aws / chalice

Python Serverless Microframework for AWS
Apache License 2.0
10.67k stars 1.01k forks source link

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

Open mangled-data opened 1 year ago

mangled-data commented 1 year ago

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 commented 1 year ago

It happens because here

https://github.com/aws/chalice/blob/79838b02dc330cfe549823899d2662ded0538015/chalice/app.py#L1832-L1839

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

bbuechler commented 1 month ago

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.