Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why doesn't {proxy+} work as catchall ? #2072

Open
mangled-data opened this issue Sep 9, 2023 · 2 comments
Open

Why doesn't {proxy+} work as catchall ? #2072

mangled-data opened this issue Sep 9, 2023 · 2 comments

Comments

@mangled-data
Copy link

mangled-data commented Sep 9, 2023


app = Chalice(app_name='chalice-proxy-example')

@app.route('/')
def index():
    return {"message": "Welcome to the root endpoint!"}

@app.route('/resource/{proxy+}', methods=['GET', 'POST'])
def resource_proxy(proxy):
    # proxy contains the path information. 
    # For instance, if you access /resource/a/b/c, proxy will be "a/b/c"
    return {
        "message": "You've accessed the proxy endpoint.",
        "path": proxy
    }


I have tried all combinations and I can't figure out why a generic catch all work. I probably miss something super basic, but at a point where I may have to move to something else. This is such a super great framework, if I could get a reverse proxy type setup working! Can anyone help please ?

$ curl http://127.0.0.1:8000/
{"message":"Welcome to the root endpoint!"}

$ curl http://127.0.0.1:8000/1
{"message": "Missing Authentication Token"}

On chalice, I see 127.0.0.1 - - [09/Sep/2023 15:02:09] "GET /1 HTTP/1.1" 403 -
@pkit
Copy link

pkit commented Sep 15, 2023

It happens because here

chalice/chalice/app.py

Lines 1832 to 1839 in 79838b0

def _main_rest_api_handler(self, event: Any, context: Any) -> Response:
resource_path = event.get('requestContext', {}).get('resourcePath')
if resource_path is None:
return error_response(error_code='InternalServerError',
message='Unknown request.',
http_status_code=500)
http_method = event['requestContext']['httpMethod']
if http_method not in self.routes[resource_path]:

resource_path is ..../{proxy*} and not .../{proxy+} which fails to get the key from dict...

@bbuechler
Copy link

Your route @app.route('/resource/{proxy+}', methods=['GET', 'POST']) is specifying the proxy+ glob after /resource/, but you're curl reqs (at least in your example) are not hitting /resource/..../ URIs.

I would expect curl http://127.0.0.1:8000/resource/1 to return what you expect.

@app.route('/resource/{proxy+}', methods=['GET', 'POST'])
def resource_proxy():
    # proxy contains the path information. 
    # For instance, if you access /resource/a/b/c, proxy will be "a/b/c"
    return {
        "message": "You've accessed the proxy endpoint.",
        "path": app.current_request.uri_params.get("proxy+")
    }

and...

curl http://127.0.0.1:8000/resource/1
127.0.0.1 - - [18/Sep/2024 15:15:01] "GET /resource/1 HTTP/1.1" 200 -
{"message":"You've accessed the proxy endpoint.","path":"1"}

Also: The greedy {proxy+} does not (I do not believe) feed a proxy variable to the resource_proxy() handler function like a non-greedy {proxy} would. That results in this error:

TypeError: resource_proxy() missing 1 required positional argument: 'proxy'

If you don't care about nested paths (eg resource/1/2/3), you can use the non-greedy {proxy} argument:

@app.route('/resource/{proxy}', methods=['GET', 'POST'])
def resource_proxy(proxy):
    return {
        "message": "You've accessed the proxy endpoint.",
        "non_greedy_path": proxy
    }

which does the trick:

% curl http://127.0.0.1:8000/resource/1
127.0.0.1 - - [18/Sep/2024 15:28:22] "GET /resource/1 HTTP/1.1" 200 -
{"message":"You've accessed the proxy endpoint.","non_greedy_path":"1"}

Frustratingly, and why I'm here in the chalice github right now and found your ticket, and perhaps maybe at the core of your problem, is that at least with chalice 1.31.2, the {proxy+} glob seems to be broken in the local development server, even though it works properly in AWS. When I try to use nested URLs with this code:

@app.route('/resource/{proxy+}', methods=['GET', 'POST'])
def resource_proxy():
    return {
        "message": "You've accessed the proxy endpoint.",
        "path": app.current_request.uri_params.get("proxy+")
    }

This happens:

curl http://127.0.0.1:8000/resource/good
127.0.0.1 - - [18/Sep/2024 15:34:52] "GET /resource/good HTTP/1.1" 200 -
{"message":"You've accessed the proxy endpoint.","path":"good"}

curl http://127.0.0.1:8000/resource/still_good/            
127.0.0.1 - - [18/Sep/2024 15:36:40] "GET /resource/still_good/ HTTP/1.1" 200 -
{"message":"You've accessed the proxy endpoint.","path":"still_good"}

curl http://127.0.0.1:8000/resource/should_work/but_doesnt
127.0.0.1 - - [18/Sep/2024 15:35:07] "GET /resource/should_work/but_doesnt HTTP/1.1" 403 -
{"message": "Missing Authentication Token"}

curl http://127.0.0.1:8000/resource/should_work/but_doesnt/
127.0.0.1 - - [18/Sep/2024 15:35:10] "GET /resource/should_work/but_doesnt/ HTTP/1.1" 403 -
{"message": "Missing Authentication Token"}

Again, when deployed to AWS, this works perfectly fine. However, in the chalice local server, it won't route.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants