Skip to content

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

Closed
Azure/azure-functions-python-library
#208
@fredrike

Description

@fredrike

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:
  • Timestamp: 2024-02-28T11:27:27.886Z
  • Function App name: N/A
  • Function name(s) (as appropriate): backend-api
  • Core Tools version: 4.0.5455

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
# 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

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

{
  "version": "2.0",
  "extensions": {
    "http": {
      "routePrefix": ""
    }
  }
}

Metadata

Metadata

Assignees

Labels

pending-releaseFixed but pending docker image, runtime or core tools release.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions