sanic-org / sanic-routing

Internal handler routing for Sanic beginning with v21.3.
https://sanicframework.org/
MIT License
13 stars 11 forks source link

"unquote=True" breaks int path parameters #73

Closed xmcp closed 1 year ago

xmcp commented 1 year ago

Is there an existing issue for this?

Describe the bug

Routes that both set unquote=True and have int path parameters will cause a bug in the Sanic router, resulting in 500 errors when visited.

Code snippet

Run this code:

from sanic import Sanic
from sanic.response import text

app = Sanic('app')

@app.route("/test/<x:int>", unquote=True)
async def handler(request, x: int):
    return text(f'hi {x}')

if __name__=='__main__':
    app.run(port=4321, debug=True)

Then visit /test/1.

Sanic raises a 500 error:

[2023-07-17 03:41:24 +0800] [52892] [ERROR] Exception occurred while handling uri: 'http://127.0.0.1:4321/test/1'
Traceback (most recent call last):
  File "C:\Users\xmcp\AppData\Roaming\Python\Python310\site-packages\sanic\app.py", line 904, in handle_request
    route, handler, kwargs = self.router.get(
  File "C:\Users\xmcp\AppData\Roaming\Python\Python310\site-packages\sanic\router.py", line 64, in get
    return self._get(path, method, host)
  File "C:\Users\xmcp\AppData\Roaming\Python\Python310\site-packages\sanic\router.py", line 36, in _get
    return self.resolve(
  File "C:\Users\xmcp\AppData\Roaming\Python\Python310\site-packages\sanic_routing\router.py", line 82, in resolve
    route, param_basket = self.find_route(
  File "", line 22, in find_route
  File "C:\Program Files\Python310\lib\urllib\parse.py", line 656, in unquote
    if '%' not in string:
TypeError: argument of type 'int' is not iterable
[2023-07-17 03:41:24 +0800] - (sanic.access)[INFO][127.0.0.1:50831]: GET http://127.0.0.1:4321/test/1  500 2402

Expected Behavior

It should return hi 1 without a 500 error.

How do you run Sanic?

As a script (app.run or Sanic.serve)

Operating System

Windows

Sanic Version

Sanic 22.12.0; Routing 22.8.0

Additional context

self.find_route_src in the sanic router says something like that:

if num == 4:  # CHECK 1
    try:
        basket['__matches__'][3] = int(parts[3])
    except ValueError:
        pass
    else:
        basket['__matches__'][3] = unquote(basket['__matches__'][3])

You can see that Sanic converts the request arg into an integer and then tries to unquote it.

ahopkins commented 1 year ago

Nice catch. Thank you for reporting.