Replies: 5 comments 2 replies
-
Yeah, I think this StackOverflow answer has good info pointing to the W3C recommendations which would be sort of the authority (I don't think the URL RFC have something specific about that). So I think that should be the behavior. Nevertheless, this is actually handled in Starlette directly, not in FastAPI. But it would be a valid Starlette bug/feature request. |
Beta Was this translation helpful? Give feedback.
-
Well, we can actually achieve that by creating a custom route, from fastapi import FastAPI, Body, APIRouter, Request, Response
from typing import Callable
from fastapi.routing import APIRoute
from pydantic import BaseModel
import json
from pprint import pprint as print
class CustomRoute(APIRoute):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
def get_route_handler(self) -> Callable:
original_route_handler = super().get_route_handler()
async def custom_route_handler(request: Request) -> Response:
old_scope = request.scope["raw_path"].decode("utf-8")
new_scope = old_scope.replace("%2F", "/").encode("utf-8")
request.scope["raw_path"] = new_scope
response = await original_route_handler(request)
return response
return custom_route_handler
app = FastAPI()
router = APIRouter(route_class=CustomRoute)
class TestModel(BaseModel):
name: str
@router.post("/{some}/{other_path}")
async def dummy(some: str, other_path: str):
return {
"some": some,
"other_path": other_path,
}
app.include_router(router) This changes the curl -X POST "http://127.0.0.1:8000/asdf%2Fasdf" -H "accept: application/json" -d ""
{"some":"asdf","other_path":"asdf"} |
Beta Was this translation helpful? Give feedback.
-
The answer posted by @app.post("/{path}")
def post_method(path: str):
return "ok" You are not able to call it with:
I've put logging statements in the The reason the code above works is because the |
Beta Was this translation helpful? Give feedback.
-
I ran into the same issue and it took me a while to find out what was happening. "/{path:path}" works to some extend, but then it's no longer possible to match something like /hahahaha%2Fahhaa/name. Like some other frameworks, FastAPI(or Starlette) seems to decode the URL before matching routes, which I think is strictly speaking a bug. If a clients wants hahahaha%2Fahhaa to be interpreted as hahahaha/ahhaa, it wouldn't escape it. The RFC's seem to agree with that interpretation. Is there a corresponding issue at https://github.com/encode/starlette? Would FastAPI consider a setting to disable this behaviour? |
Beta Was this translation helpful? Give feedback.
-
I was able to get this working with the following workaround: import re
from typing import Tuple
from urllib.parse import quote_plus, unquote_plus
from fastapi import APIRouter, FastAPI
from fastapi.routing import APIRoute
from fastapi.testclient import TestClient
from starlette.routing import Match
from starlette.types import Scope
class RawPathRoute(APIRoute):
def matches(self, scope: Scope) -> Tuple[Match, Scope]:
raw_path: str | None = None
if "raw_path" in scope and scope["raw_path"] is not None:
raw_path = scope["raw_path"].decode("utf-8")
elif "aws.event" in scope and "path" in scope["aws.event"]:
raw_path = scope["aws.event"]["path"]
if raw_path is None:
raise HTTPException(status_code=500, detail="Internal routing error")
new_path = re.sub(r"\?.*", "", raw_path)
scope["path"] = new_path
return super().matches(scope)
router = APIRouter(prefix="/mypath", route_class=RawPathRoute)
@router.get("/{path1}/{path2}")
def mypath(path1: str, path2: str):
print(f"Paths: {unquote_plus(path1)} and {unquote_plus(path2)}")
app = FastAPI()
app.include_router(router)
client = TestClient(app)
def test_example():
path1 = "some/path/here"
path2 = "another/path/here"
response = client.get(f"/mypath/{quote_plus(path1)}/{quote_plus(path2)}")
assert response.status_code == 200 Then running it in pytest we can see the paths come in separately and decoded:
|
Beta Was this translation helpful? Give feedback.
-
First check
Description
This is more a question/feature request. Currently, we are not able to withstand forward slashes in the
Path
. Do we want to have that available?Minimal example
Having those two endpoints:
I want to be able to access the first endpoint with the following request:
curl -X POST "http://localhost:8000/hahahaha%2Fahhaa" -H "accept: application/json" -d ""
The
%2F
is known way to escape forward slashes.Additional context
This issue was brought by @hang15 on our gitter and on StackOverflow.
Beta Was this translation helpful? Give feedback.
All reactions