Azure / azure-functions-python-worker

Python worker for Azure Functions.
http://aka.ms/azurefunctions
MIT License
331 stars 100 forks source link

[BUG] latin-1 encoding of route_params in AsgiMiddleware #1437

Closed fredrike closed 2 months ago

fredrike commented 4 months ago

There is encoding issues when using AsgiMiddleware toghether with FastApi. Swedish characters like åäö are not handeled correctly.

The issue might come from this line: https://github.com/Azure/azure-functions-python-library/blob/e1d3ebbad3eb3a17a41839ba7b866e56096febf6/azure/functions/_http_wsgi.py#L33

See mwe at Source section.

Investigative information

Please provide the following:

Repro steps

Provide the steps required to reproduce the problem:
  1. Run the function app with code from source #section
    • func start -p 8000
  2. Post a GET request to http://localhost:8000/hello/Pippi%20L%C3%A5ngstrump (Pippi Långstrump is Pippi Longstocking in swedish)

Expected behavior

Provide a description of the expected behavior.

The response should be:

{
  "name": "Pippi Långstrump",
  "encoded name": "Pippi Långstrump"
}

Actual behavior

Provide a description of the actual behavior observed.
{
  "name": "Pippi LÃ¥ngstrump",
  "encoded name": "Pippi Långstrump"
}

Do note that the following is seen in the func log:

$ func start -p 8000
Found Python version 3.10.12 (python3).

Azure Functions Core Tools
Core Tools Version:       4.0.5455 Commit hash: N/A  (64-bit)
Function Runtime Version: 4.27.5.21554

[2024-02-28T11:27:27.886Z] Customer packages not in sys path. This should never happen! 
[2024-02-28T11:27:28.430Z] Worker process started and initialized.

Functions:

        backend-api:  http://localhost:8000/{*route}

For detailed output, run func with --verbose flag.
[2024-02-28T11:27:30.308Z] Executing 'Functions.backend-api' (Reason='This function was programmatically called via the host APIs.', Id=4151d47b-9d32-4d64-afd3-0deabf68f9ed)
[2024-02-28T11:27:30.345Z] http://localhost:8000/hello/Pippi%20L%C3%A5ngstrump {'route': 'hello/Pippi Långstrump'}
[2024-02-28T11:27:30.345Z] Pippi LÃ¥ngstrump Pippi Långstrump
[2024-02-28T11:27:30.388Z] Executed 'Functions.backend-api' (Succeeded, Id=4151d47b-9d32-4d64-afd3-0deabf68f9ed, Duration=97ms)
[2024-02-28T11:27:32.598Z] Host lock lease acquired by instance ID '000000000000000000000000B7E20425'.

So the encoding is right in line 26 (print(req.url, req.route_params) -> [2024-02-28T11:27:30.345Z] http://localhost:8000/hello/Pippi%20L%C3%A5ngstrump {'route': 'hello/Pippi Långstrump'}) but something happens when the parameter is sent to FastAPI (line 11 print(name, name.encode("latin-1").decode("utf-8")) -> [2024-02-28T11:27:30.345Z] Pippi LÃ¥ngstrump Pippi Långstrump ). The expected behavior is seen when FastAPI is invoked with uvicorn.

Known workarounds

Provide a description of any known workarounds.

See line 14 name.encode("latin-1").decode("utf-8") so there is an encoding from bytes to latin-1 somewhere in your code, Python3 is UTF-8.

Contents of the requirements.txt file:

Provide the requirements.txt file to help us find out module related issues.
annotated-types==0.6.0
anyio==4.3.0
azure-functions==1.18.0
exceptiongroup==1.2.0
fastapi==0.109.0
idna==3.6
pydantic==2.6.3
pydantic_core==2.16.3
sniffio==1.3.1
starlette==0.35.1
typing_extensions==4.10.0

Related information

Provide any related information
Source ```python # function_app.py """Main app""" import azure.functions as func from fastapi import FastAPI fast_app = FastAPI() @fast_app.get("/hello/{name}") async def get_name(name: str): print(name, name.encode("latin-1").decode("utf-8")) return { "name": name, "encoded name": name.encode("latin-1").decode("utf-8"), } app = func.FunctionApp() # Azure Functions v2 HTTP trigger decorator @app.function_name("backend-api") @app.route(route="{*route}", auth_level="anonymous") async def backend_api(req: func.HttpRequest) -> func.HttpResponse: """Initiate backend_api as AsgiMiddleware""" print(req.url, req.route_params) return await func.AsgiMiddleware(fast_app).handle_async(req) # pragma: no cover ``` `requirements.txt` ```txt annotated-types==0.6.0 anyio==4.3.0 azure-functions==1.18.0 exceptiongroup==1.2.0 fastapi==0.109.0 idna==3.6 pydantic==2.6.3 pydantic_core==2.16.3 sniffio==1.3.1 starlette==0.35.1 typing_extensions==4.10.0 ``` `host.json` ```json { "version": "2.0", "extensions": { "http": { "routePrefix": "" } } } ```
YunchuWang commented 3 months ago

thanks for reporting this issue! We will include the fix in next python function library release.

YunchuWang commented 2 months ago

merged, going into next azure function runtime release