pax_global_header 0000666 0000000 0000000 00000000064 15074714634 0014525 g ustar 00root root 0000000 0000000 52 comment=3850ad6520cafb290bd4174fa9c4ca5d33440c82
uvicorn-0.38.0/ 0000775 0000000 0000000 00000000000 15074714634 0013302 5 ustar 00root root 0000000 0000000 uvicorn-0.38.0/.github/ 0000775 0000000 0000000 00000000000 15074714634 0014642 5 ustar 00root root 0000000 0000000 uvicorn-0.38.0/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 15074714634 0017025 5 ustar 00root root 0000000 0000000 uvicorn-0.38.0/.github/ISSUE_TEMPLATE/1-issue.yml 0000664 0000000 0000000 00000003623 15074714634 0021042 0 ustar 00root root 0000000 0000000 name: Issue
description: Report a bug or unexpected behavior. π
body:
- type: markdown
attributes:
value: Thank you for contributing to Uvicorn! β
- type: checkboxes
id: checks
attributes:
label: Initial Checks
description: Just making sure you open a discussion first. π
options:
- label: I confirm this was discussed, and the maintainers suggest I open an issue.
required: true
- label: I'm aware that if I created this issue without a discussion, it may be closed without a response.
required: true
- type: textarea
id: discussion
attributes:
label: Discussion Link
description: |
Please link to the discussion that led to this issue.
If you haven't discussed this issue yet, please do so before opening an issue.
render: Text
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: |
Please explain what you're seeing and what you would expect to see.
Please provide as much detail as possible to make understanding and solving your problem as quick as possible. π
validations:
required: true
- type: textarea
id: example
attributes:
label: Example Code
description: >
If applicable, please add a self-contained,
[minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example)
demonstrating the bug.
render: Python
- type: textarea
id: version
attributes:
label: Python, Uvicorn & OS Version
description: |
Which version of Python & Uvicorn are you using, and which Operating System?
Please run the following command and copy the output below:
```bash
python -m uvicorn --version
```
render: Text
validations:
required: true
uvicorn-0.38.0/.github/ISSUE_TEMPLATE/config.yml 0000664 0000000 0000000 00000000676 15074714634 0021026 0 ustar 00root root 0000000 0000000 # Ref: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
blank_issues_enabled: false
contact_links:
- name: Discussions
url: https://github.com/Kludex/uvicorn/discussions
about: The "Discussions" forum is where you want to start. π
- name: Chat
url: https://discord.com/invite/SWU73HffbV
about: Our community Discord server. π¬
uvicorn-0.38.0/.github/PULL_REQUEST_TEMPLATE.md 0000664 0000000 0000000 00000001041 15074714634 0020437 0 ustar 00root root 0000000 0000000
# Summary
# Checklist
- [ ] I understand that this PR may be closed in case there was no previous discussion. (This doesn't apply to typos!)
- [ ] I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
- [ ] I've updated the documentation accordingly.
uvicorn-0.38.0/.github/dependabot.yml 0000664 0000000 0000000 00000000421 15074714634 0017467 0 ustar 00root root 0000000 0000000 version: 2
updates:
- package-ecosystem: "uv"
directory: "/"
schedule:
interval: "monthly"
groups:
python-packages:
patterns:
- "*"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: monthly
uvicorn-0.38.0/.github/workflows/ 0000775 0000000 0000000 00000000000 15074714634 0016677 5 ustar 00root root 0000000 0000000 uvicorn-0.38.0/.github/workflows/main.yml 0000664 0000000 0000000 00000003002 15074714634 0020341 0 ustar 00root root 0000000 0000000 ---
name: Test Suite
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
jobs:
tests:
name: "Python ${{ matrix.python-version }} ${{ matrix.os }}"
runs-on: "${{ matrix.os }}"
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"]
os: [windows-latest, ubuntu-latest, macos-latest]
steps:
- uses: "actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8" # v5.0.0
- name: Install uv
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
python-version: ${{ matrix.python-version }}
enable-cache: ${{ matrix.os != 'windows-latest' }}
- name: Install dependencies
run: scripts/install
shell: bash
- name: Run linting checks
run: scripts/check
if: "${{ matrix.os == 'ubuntu-latest'}}"
- name: "Build package & docs"
run: scripts/build
shell: bash
- name: "Run tests"
run: scripts/test
shell: bash
- name: "Enforce coverage"
run: scripts/coverage
shell: bash
# https://github.com/marketplace/actions/alls-green#why
check:
if: always()
needs: [tests]
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
with:
jobs: ${{ toJSON(needs) }}
uvicorn-0.38.0/.github/workflows/publish.yml 0000664 0000000 0000000 00000006144 15074714634 0021075 0 ustar 00root root 0000000 0000000 name: Publish
on:
push:
tags:
- '*'
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Install uv
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
python-version: "3.11"
enable-cache: true
- name: Install dependencies
run: scripts/install
- name: Build package & docs
run: scripts/build
- name: Upload package distributions
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: package-distributions
path: dist/
- name: Upload documentation
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: documentation
path: site/
pypi-publish:
runs-on: ubuntu-latest
needs: build
if: success() && startsWith(github.ref, 'refs/tags/')
permissions:
id-token: write
environment:
name: pypi
url: https://pypi.org/project/uvicorn
steps:
- name: Download artifacts
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: package-distributions
path: dist/
- name: Publish distribution π¦ to PyPI
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
docs-publish:
runs-on: ubuntu-latest
needs: build
permissions:
contents: write
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Download artifacts
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: documentation
path: site/
- name: Configure Git Credentials
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
- name: Install uv
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
python-version: "3.12"
enable-cache: true
- name: Install dependencies
run: scripts/install
- name: Publish documentation π to GitHub Pages
run: uv run mkdocs gh-deploy --force
docs-cloudflare:
runs-on: ubuntu-latest
needs: build
environment:
name: cloudflare
url: https://uvicorn.dev
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Download artifacts
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: documentation
path: site/
- uses: cloudflare/wrangler-action@da0e0dfe58b7a431659754fdf3f186c529afbe65 # v3.14.1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: >
pages deploy ./site
--project-name uvicorn
--commit-hash ${{ github.sha }}
--branch main
uvicorn-0.38.0/.gitignore 0000664 0000000 0000000 00000000144 15074714634 0015271 0 ustar 00root root 0000000 0000000 .cache
.coverage
.coverage.*
.mypy_cache/
__pycache__/
uvicorn.egg-info/
venv/
htmlcov/
site/
dist/
uvicorn-0.38.0/CHANGELOG.md 0000777 0000000 0000000 00000000000 15074714634 0021126 2docs/release-notes.md ustar 00root root 0000000 0000000 uvicorn-0.38.0/CITATION.cff 0000664 0000000 0000000 00000001164 15074714634 0015176 0 ustar 00root root 0000000 0000000 # This CITATION.cff file was generated with cffinit.
# Visit https://bit.ly/cffinit to generate yours today!
cff-version: 1.2.0
title: Uvicorn
message: >-
If you use this software, please cite it using the
metadata from this file.
type: software
authors:
- given-names: Marcelo
family-names: Trylesinski
email: marcelotryle@gmail.com
- given-names: Tom
family-names: Christie
email: tom@tomchristie.com
repository-code: "https://github.com/Kludex/uvicorn"
url: "https://uvicorn.dev/"
abstract: Uvicorn is an ASGI web server implementation for Python.
keywords:
- asgi
- server
license: BSD-3-Clause
uvicorn-0.38.0/LICENSE.md 0000664 0000000 0000000 00000002766 15074714634 0014721 0 ustar 00root root 0000000 0000000 Copyright Β© 2017-present, [Encode OSS Ltd](https://www.encode.io/).
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
uvicorn-0.38.0/README.md 0000664 0000000 0000000 00000011437 15074714634 0014567 0 ustar 00root root 0000000 0000000
An ASGI web server, for Python.
---
[](https://github.com/Kludex/uvicorn/actions)
[](https://pypi.python.org/pypi/uvicorn)
[](https://pypi.org/project/uvicorn)
[](https://discord.gg/RxKUF5JuHs)
---
**Documentation**: [https://uvicorn.dev](https://uvicorn.dev)
**Source Code**: [https://www.github.com/Kludex/uvicorn](https://www.github.com/Kludex/uvicorn)
---
Uvicorn is an ASGI web server implementation for Python.
Until recently Python has lacked a minimal low-level server/application interface for
async frameworks. The [ASGI specification][asgi] fills this gap, and means we're now able to
start building a common set of tooling usable across all async frameworks.
Uvicorn supports HTTP/1.1 and WebSockets.
## Quickstart
Install using `pip`:
```shell
$ pip install uvicorn
```
This will install uvicorn with minimal (pure Python) dependencies.
```shell
$ pip install 'uvicorn[standard]'
```
This will install uvicorn with "Cython-based" dependencies (where possible) and other "optional extras".
In this context, "Cython-based" means the following:
- the event loop `uvloop` will be installed and used if possible.
- the http protocol will be handled by `httptools` if possible.
Moreover, "optional extras" means that:
- the websocket protocol will be handled by `websockets` (should you want to use `wsproto` you'd need to install it manually) if possible.
- the `--reload` flag in development mode will use `watchfiles`.
- windows users will have `colorama` installed for the colored logs.
- `python-dotenv` will be installed should you want to use the `--env-file` option.
- `PyYAML` will be installed to allow you to provide a `.yaml` file to `--log-config`, if desired.
Create an application, in `example.py`:
```python
async def app(scope, receive, send):
assert scope['type'] == 'http'
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
(b'content-type', b'text/plain'),
],
})
await send({
'type': 'http.response.body',
'body': b'Hello, world!',
})
```
Run the server:
```shell
$ uvicorn example:app
```
---
## Why ASGI?
Most well established Python Web frameworks started out as WSGI-based frameworks.
WSGI applications are a single, synchronous callable that takes a request and returns a response.
This doesnβt allow for long-lived connections, like you get with long-poll HTTP or WebSocket connections,
which WSGI doesn't support well.
Having an async concurrency model also allows for options such as lightweight background tasks,
and can be less of a limiting factor for endpoints that have long periods being blocked on network
I/O such as dealing with slow HTTP requests.
---
## Alternative ASGI servers
A strength of the ASGI protocol is that it decouples the server implementation
from the application framework. This allows for an ecosystem of interoperating
webservers and application frameworks.
### Daphne
The first ASGI server implementation, originally developed to power Django Channels, is [the Daphne webserver][daphne].
It is run widely in production, and supports HTTP/1.1, HTTP/2, and WebSockets.
Any of the example applications given here can equally well be run using `daphne` instead.
```
$ pip install daphne
$ daphne app:App
```
### Hypercorn
[Hypercorn][hypercorn] was initially part of the Quart web framework, before
being separated out into a standalone ASGI server.
Hypercorn supports HTTP/1.1, HTTP/2, and WebSockets.
It also supports [the excellent `trio` async framework][trio], as an alternative to `asyncio`.
```
$ pip install hypercorn
$ hypercorn app:App
```
### Mangum
[Mangum][mangum] is an adapter for using ASGI applications with AWS Lambda & API Gateway.
### Granian
[Granian][granian] is an ASGI compatible Rust HTTP server which supports HTTP/2, TLS and WebSockets.
---
Uvicorn is BSD licensed code.
Designed & crafted with care.
— π¦ —
[asgi]: https://asgi.readthedocs.io/en/latest/
[daphne]: https://github.com/django/daphne
[hypercorn]: https://github.com/pgjones/hypercorn
[trio]: https://trio.readthedocs.io
[mangum]: https://github.com/jordaneremieff/mangum
[granian]: https://github.com/emmett-framework/granian
uvicorn-0.38.0/docs/ 0000775 0000000 0000000 00000000000 15074714634 0014232 5 ustar 00root root 0000000 0000000 uvicorn-0.38.0/docs/CNAME 0000664 0000000 0000000 00000000020 15074714634 0014770 0 ustar 00root root 0000000 0000000 www.uvicorn.org
uvicorn-0.38.0/docs/concepts/ 0000775 0000000 0000000 00000000000 15074714634 0016050 5 ustar 00root root 0000000 0000000 uvicorn-0.38.0/docs/concepts/asgi.md 0000664 0000000 0000000 00000017730 15074714634 0017325 0 ustar 00root root 0000000 0000000 ## ASGI
**Uvicorn** uses the [ASGI specification](https://asgi.readthedocs.io/en/latest/) for interacting with an application.
The application should expose an async callable which takes three arguments:
* `scope` - A dictionary containing information about the incoming connection.
* `receive` - A channel on which to receive incoming messages from the server.
* `send` - A channel on which to send outgoing messages to the server.
Two common patterns you might use are either function-based applications:
```python
async def app(scope, receive, send):
assert scope['type'] == 'http'
...
```
Or instance-based applications:
```python
class App:
async def __call__(self, scope, receive, send):
assert scope['type'] == 'http'
...
app = App()
```
It's good practice for applications to raise an exception on scope types
that they do not handle.
The content of the `scope` argument, and the messages expected by `receive` and `send` depend on the protocol being used.
The format for HTTP messages is described in the [ASGI HTTP Message format](https://asgi.readthedocs.io/en/latest/specs/www.html).
### HTTP Scope
An incoming HTTP request might have a connection `scope` like this:
```python
{
'type': 'http',
'scheme': 'http',
'root_path': '',
'server': ('127.0.0.1', 8000),
'http_version': '1.1',
'method': 'GET',
'path': '/',
'headers': [
(b'host', b'127.0.0.1:8000'),
(b'user-agent', b'curl/7.51.0'),
(b'accept', b'*/*')
]
}
```
### HTTP Messages
The instance coroutine communicates back to the server by sending messages to the `send` coroutine.
```python
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
[b'content-type', b'text/plain'],
]
})
await send({
'type': 'http.response.body',
'body': b'Hello, world!',
})
```
### Requests & responses
Here's an example that displays the method and path used in the incoming request:
```python
async def app(scope, receive, send):
"""
Echo the method and path back in an HTTP response.
"""
assert scope['type'] == 'http'
body = f'Received {scope["method"]} request to {scope["path"]}'
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
[b'content-type', b'text/plain'],
]
})
await send({
'type': 'http.response.body',
'body': body.encode('utf-8'),
})
```
### Reading the request body
You can stream the request body without blocking the asyncio task pool,
by fetching messages from the `receive` coroutine.
```python
async def read_body(receive):
"""
Read and return the entire body from an incoming ASGI message.
"""
body = b''
more_body = True
while more_body:
message = await receive()
body += message.get('body', b'')
more_body = message.get('more_body', False)
return body
async def app(scope, receive, send):
"""
Echo the request body back in an HTTP response.
"""
body = await read_body(receive)
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
(b'content-type', b'text/plain'),
(b'content-length', str(len(body)).encode())
]
})
await send({
'type': 'http.response.body',
'body': body,
})
```
### Streaming responses
You can stream responses by sending multiple `http.response.body` messages to
the `send` coroutine.
```python
import asyncio
async def app(scope, receive, send):
"""
Send a slowly streaming HTTP response back to the client.
"""
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
[b'content-type', b'text/plain'],
]
})
for chunk in [b'Hello', b', ', b'world!']:
await send({
'type': 'http.response.body',
'body': chunk,
'more_body': True
})
await asyncio.sleep(1)
await send({
'type': 'http.response.body',
'body': b'',
})
```
---
## Why ASGI?
Most well established Python Web frameworks started out as WSGI-based frameworks.
WSGI applications are a single, synchronous callable that takes a request and returns a response.
This doesnβt allow for long-lived connections, like you get with long-poll HTTP or WebSocket connections,
which WSGI doesn't support well.
Having an async concurrency model also allows for options such as lightweight background tasks,
and can be less of a limiting factor for endpoints that have long periods being blocked on network
I/O such as dealing with slow HTTP requests.
---
## Alternative ASGI servers
A strength of the ASGI protocol is that it decouples the server implementation
from the application framework. This allows for an ecosystem of interoperating
webservers and application frameworks.
### Daphne
The first ASGI server implementation, originally developed to power Django Channels, is
[the Daphne webserver](https://github.com/django/daphne).
It is run widely in production, and supports HTTP/1.1, HTTP/2, and WebSockets.
Any of the example applications given here can equally well be run using `daphne` instead.
```shell
pip install daphne
daphne app:App
```
### Hypercorn
[Hypercorn](https://github.com/pgjones/hypercorn) was initially part of the Quart web framework,
before being separated out into a standalone ASGI server.
Hypercorn supports HTTP/1.1, HTTP/2, HTTP/3 and WebSockets.
```shell
pip install hypercorn
hypercorn app:App
```
---
## ASGI frameworks
You can use Uvicorn, Daphne, or Hypercorn to run any ASGI framework.
For small services you can also write ASGI applications directly.
### Starlette
[Starlette](https://github.com/Kludex/starlette) is a lightweight ASGI framework/toolkit.
It is ideal for building high performance asyncio services, and supports both HTTP and WebSockets.
### Django Channels
The ASGI specification was originally designed for use with [Django Channels](https://channels.readthedocs.io/en/latest/).
Channels is a little different to other ASGI frameworks in that it provides
an asynchronous frontend onto a threaded-framework backend. It allows Django
to support WebSockets, background tasks, and long-running connections,
with application code still running in a standard threaded context.
### Quart
[Quart](https://pgjones.gitlab.io/quart/) is a Flask-like ASGI web framework.
### FastAPI
[**FastAPI**](https://github.com/tiangolo/fastapi) is an API framework based on **Starlette** and **Pydantic**, heavily inspired by previous server versions of **APIStar**.
You write your API function parameters with Python 3.6+ type declarations and get automatic data conversion, data validation, OpenAPI schemas (with JSON Schemas) and interactive API documentation UIs.
### BlackSheep
[BlackSheep](https://www.neoteroi.dev/blacksheep/) is a web framework based on ASGI, inspired by Flask and ASP.NET Core.
Its most distinctive features are built-in support for dependency injection, automatic binding of parameters by request handler's type annotations, and automatic generation of OpenAPI documentation and Swagger UI.
### Falcon
[Falcon](https://falconframework.org) is a minimalist REST and app backend framework for Python, with a focus on reliability, correctness, and performance at scale.
### Muffin
[Muffin](https://github.com/klen/muffin) is a fast, lightweight and asynchronous ASGI web-framework for Python 3.
### Litestar
[Litestar](https://litestar.dev) is a powerful, lightweight and flexible ASGI framework.
It includes everything that's needed to build modern APIs - from data serialization and validation to websockets, ORM integration, session management, authentication and more.
### Panther
[Panther](https://PantherPy.github.io/) is a fast & friendly web framework for building async APIs with Python 3.10+.
It has built-in Document-oriented Database, Caching System, Authentication and Permission Classes, Visual API Monitoring and also supports Websocket, Throttling, Middlewares.
uvicorn-0.38.0/docs/concepts/event-loop.md 0000664 0000000 0000000 00000005014 15074714634 0020462 0 ustar 00root root 0000000 0000000 # Event Loop
Uvicorn provides two event loop implementations that you can choose from using the [`--loop`](../settings.md#implementation) option:
```bash
uvicorn main:app --loop
```
By default, Uvicorn uses `--loop auto`, which automatically selects:
1. **uvloop** - If [uvloop](https://github.com/MagicStack/uvloop) is installed, Uvicorn will use it for maximum performance
2. **asyncio** - If uvloop is not available, Uvicorn falls back to Python's built-in asyncio event loop
Since `uvloop` is not compatible with Windows or PyPy, it is not available on these platforms.
On Windows, the asyncio implementation uses [`ProactorEventLoop`][asyncio.ProactorEventLoop] if running with multiple workers,
otherwise it uses the standard [`SelectorEventLoop`][asyncio.SelectorEventLoop] for better performance.
??? info "Why does `SelectorEventLoop` not work with multiple processes on Windows?"
If you want to know more about it, you can read the issue [#cpython/122240](https://github.com/python/cpython/issues/122240).
## Custom Event Loop
You can use custom event loop implementations by specifying a module path and function name using the colon notation:
```bash
uvicorn main:app --loop :
```
The function should return a callable that creates a new event loop instance.
### rloop
[rloop](https://github.com/gi0baro/rloop) is an experimental AsyncIO event loop implemented in Rust on top of the [mio](https://github.com/tokio-rs/mio) crate. It aims to provide high performance through Rust's systems programming capabilities.
You can install it with:
=== "pip"
```bash
pip install rloop
```
=== "uv"
```bash
uv add rloop
```
You can run `uvicorn` with `rloop` with the following command:
```bash
uvicorn main:app --loop rloop:new_event_loop
```
!!! warning "Experimental"
rloop is currently **experimental** and **not suited for production usage**. It is only available on **Unix systems**.
### Winloop
[Winloop](https://github.com/Vizonex/Winloop) is an alternative library that brings uvloop-like performance to Windows. Since uvloop is based on libuv and doesn't support Windows, Winloop provides a Windows-compatible implementation with significant performance improvements over the standard Windows event loop policies.
You can install it with:
=== "pip"
```bash
pip install winloop
```
=== "uv"
```bash
uv add winloop
```
You can run `uvicorn` with `Winloop` with the following command:
```bash
uvicorn main:app --loop winloop:new_event_loop
```
uvicorn-0.38.0/docs/concepts/lifespan.md 0000664 0000000 0000000 00000010234 15074714634 0020173 0 ustar 00root root 0000000 0000000 Since Uvicorn is an ASGI server, it supports the
[ASGI lifespan protocol](https://asgi.readthedocs.io/en/latest/specs/lifespan.html).
This allows you to run **startup** and **shutdown** events for your application.
The lifespan protocol is useful for initializing resources that need to be available throughout
the lifetime of the application, such as database connections, caches, or other services.
Keep in mind that the lifespan is executed **only once per application instance**. If you have
multiple workers, each worker will execute the lifespan independently.
## Lifespan Architecture
The lifespan protocol runs as a sibling task alongside your main application, allowing both to execute concurrently.
Let's see how Uvicorn handles the lifespan and main application tasks:
```mermaid
sequenceDiagram
participant Server as Uvicorn Server
participant LifespanTask as Lifespan Task
participant AppTask as Application Task
participant UserApp as User Application
Note over Server: β
Server starts
Server->>+LifespanTask: spawn_task(lifespan_handler)
LifespanTask->>UserApp: {"type": "lifespan.startup"}
Note over UserApp: Initialize databases, caches, etc.
UserApp-->>LifespanTask: {"type": "lifespan.startup.complete"}
LifespanTask->>Server: β
Startup complete
Server->>+AppTask: spawn_task(application_handler)
Note over AppTask: β
Ready for requests
rect rgb(240, 248, 255)
Note over LifespanTask, AppTask: Both tasks running concurrently
par Lifespan maintains state
LifespanTask->>LifespanTask: Keep lifespan connection alive
and Application serves requests
AppTask->>UserApp: HTTP/WebSocket requests
UserApp-->>AppTask: Responses
end
end
Note over Server: Shutdown signal received
Server->>AppTask: Stop accepting new connections
AppTask->>AppTask: Complete pending requests
LifespanTask->>UserApp: {"type": "lifespan.shutdown"}
Note over UserApp: Cleanup databases, caches, etc.
UserApp-->>LifespanTask: {"type": "lifespan.shutdown.complete"}
LifespanTask->>-Server: Lifespan task complete
AppTask->>-Server: Application task complete
Note over Server: β
Server stopped
```
Having the lifespan task run as a sibling task is a deliberate design choice. It could have been implemented as a parent task that spawns the
application task. This decision has the implication that if you create a [`ContextVar`][contextvars.ContextVar]
in the lifespan task, it will not be available in the application task.
## Usage
Let's see an example of a minimal (but complete) ASGI application that implements the lifespan protocol:
```python title="ASGI application with lifespan" hl_lines="3-11"
async def app(scope, receive, send):
if scope['type'] == 'lifespan':
while True:
message = await receive()
if message['type'] == 'lifespan.startup':
print("Application is starting up...")
await send({'type': 'lifespan.startup.complete'})
elif message['type'] == 'lifespan.shutdown':
print("Application is shutting down...")
await send({'type': 'lifespan.shutdown.complete'})
return
elif scope['type'] == 'http':
await send({
'type': 'http.response.start',
'status': 200,
'headers': [(b'content-type', b'text/plain')],
})
await send({'type': 'http.response.body', 'body': b'Hello, World!'})
else:
raise RuntimeError("This server doesn't support WebSocket.")
```
You can run the above application with `uvicorn main:app`. Then you'll see the print statements when the
application starts. You can also try to send some HTTP requests to it, and it will respond with "Hello, World!".
And if you stop the server (`CTRL + C`), it will print `"Application is shutting down..."`.
## Disabling Lifespan
If you want to disable the lifespan protocol, you can do so by setting the `lifespan` option to `off` when running Uvicorn:
```bash
uvicorn main:app --lifespan off
```
By default, Uvicorn will automatically enable the lifespan protocol if the application supports it.
uvicorn-0.38.0/docs/concepts/websockets.md 0000664 0000000 0000000 00000010234 15074714634 0020543 0 ustar 00root root 0000000 0000000 **Uvicorn** supports the WebSocket protocol as defined in [RFC 6455](https://datatracker.ietf.org/doc/html/rfc6455).
## Upgrade Process
The WebSocket protocol starts as an HTTP connection that gets "upgraded" to a WebSocket connection
through a handshake process. Here's how it works:
```mermaid
sequenceDiagram
participant Client
participant Server
participant ASGI App
Note over Client,ASGI App: WebSocket Handshake Process
Client->>Server: HTTP GET Request
Note right of Client: Headers:
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: [key]
Sec-WebSocket-Version: 13
Server->>ASGI App: websocket.connect event
Note right of Server: Scope type: "websocket"
alt Connection Accepted
ASGI App->>Server: {"type": "websocket.accept"}
Server->>Client: HTTP 101 Switching Protocols
Note right of Server: Headers:
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: [hash]
Note over Client,ASGI App: WebSocket Connection Established
loop Message Exchange
Client->>Server: WebSocket Frame
Server->>ASGI App: websocket.receive event
ASGI App->>Server: {"type": "websocket.send", "text": "..."}
Server->>Client: WebSocket Frame
end
alt Client Closes
Client->>Server: Close Frame
Server->>ASGI App: websocket.disconnect event
else Server Closes
ASGI App->>Server: {"type": "websocket.close"}
Server->>Client: Close Frame
end
else Connection Rejected
ASGI App->>Server: {"type": "websocket.http.response.start", "status": 403}
Server->>Client: HTTP 403 Forbidden
end
```
1. **Initial HTTP Request**: The client sends a regular HTTP GET request with special headers indicating it wants to upgrade to WebSocket:
- `Upgrade: websocket`
- `Connection: Upgrade`
- `Sec-WebSocket-Key`: A base64-encoded random key
- `Sec-WebSocket-Version: 13`
2. **Server Processing**: Uvicorn receives the request and creates a WebSocket scope, sending a `websocket.connect` event to the ASGI application.
3. **Application Decision**: The ASGI app decides whether to accept or reject the connection based on authentication, authorization, or other logic.
4. **Handshake Completion**: If accepted, the server responds with HTTP 101 status and the computed `Sec-WebSocket-Accept` header.
5. **Full-Duplex Communication**: Once upgraded, both client and server can send messages at any time using WebSocket frames.
6. **Connection Termination**: Either side can initiate closing the connection with a close frame.
## ASGI WebSocket Events
**Uvicorn** translates WebSocket protocol messages into ASGI events:
- `websocket.connect`: Sent when a client requests a WebSocket upgrade
- `websocket.receive`: Sent when a message is received from the client
- `websocket.disconnect`: Sent when the connection is closed
The ASGI app can respond with:
- `websocket.accept`: Accept the connection upgrade with an optional subprotocol
- `websocket.send`: Send a message to the client
- `websocket.close`: Close the connection with an optional status code
You can read more about it on the [ASGI documentation](https://asgi.readthedocs.io/en/latest/specs/www.html#websocket).
## Protocol Implementations
**Uvicorn** has three implementations of the WebSocket protocol.
### WSProto Protocol
This implementation was the first implemented. It uses the
[`wsproto`](https://python-hyper.org/projects/wsproto/en/stable/) package underneath.
You can choose this protocol by setting the `--ws` option to `wsproto`.
### WebSocket Protocol
This implementation uses the [`websockets`](https://websockets.readthedocs.io/) package as dependency.
By default, if you have `websockets` installed, Uvicorn will use this protocol.
### WebSockets SansIO Protocol
Since `websockets` deprecated the API Uvicorn uses to run the previous protocol, we had to create this new
protocol that uses the `websockets` SansIO API.
You can choose this protocol by setting the `--ws` option to `websockets-sansio`.
!!! note
The SansIO implementation was released in Uvicorn version 0.35.0 in June 2025.
uvicorn-0.38.0/docs/contributing.md 0000664 0000000 0000000 00000013356 15074714634 0017273 0 ustar 00root root 0000000 0000000 # Contributing
Thank you for being interested in contributing to Uvicorn.
There are many ways you can contribute to the project:
- Using Uvicorn on your stack and [reporting bugs/issues you find](https://github.com/Kludex/uvicorn/issues/new)
- [Implementing new features and fixing bugs](https://github.com/Kludex/uvicorn/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
- [Review Pull Requests of others](https://github.com/Kludex/uvicorn/pulls)
- Write documentation
- Participate in discussions
## Reporting Bugs, Issues or Feature Requests
Found something that Uvicorn should support?
Stumbled upon some unexpected behaviour?
Need a missing functionality?
Contributions should generally start out from a previous discussion.
You can reach out someone at the [community chat](https://discord.com/invite/SWU73HffbV)
or at the [github discussions tab](https://github.com/Kludex/uvicorn/discussions).
When creating a new topic in the discussions tab, possible bugs may be raised
as a "Potential Issue" discussion, feature requests may be raised as an
"Ideas" discussion. We can then determine if the discussion needs
to be escalated into an "Issue" or not, or if we'd consider a pull request.
Try to be more descriptive as you can and in case of a bug report,
provide as much information as possible like:
- OS platform
- Python version
- Installed dependencies and versions (`python -m pip freeze`)
- Code snippet
- Error traceback
You should always try to reduce any examples to the *simplest possible case*
that demonstrates the issue.
Some possibly useful tips for narrowing down potential issues...
- Does the issue exist with a specific supervisor like `Multiprocess` or more than one?
- Does the issue exist on asgi, or wsgi, or both?
- Are you running Uvicorn in conjunction with Gunicorn, others, or standalone?
## Development
To start developing Uvicorn create a **fork** of the
[Uvicorn repository](https://github.com/Kludex/uvicorn) on GitHub.
Then clone your fork with the following command replacing `YOUR-USERNAME` with
your GitHub username:
```shell
$ git clone https://github.com/YOUR-USERNAME/uvicorn
```
You can now install the project and its dependencies using:
```shell
$ cd uvicorn
$ scripts/install
```
## Testing and Linting
We use custom shell scripts to automate testing, linting,
and documentation building workflow.
To run the tests, use:
```shell
$ scripts/test
```
Any additional arguments will be passed to `pytest`. See the [pytest documentation](https://docs.pytest.org/en/latest/how-to/usage.html) for more information.
For example, to run a single test script:
```shell
$ scripts/test tests/test_cli.py
```
To run the code auto-formatting:
```shell
$ scripts/lint
```
Lastly, to run code checks separately (they are also run as part of `scripts/test`), run:
```shell
$ scripts/check
```
## Documenting
Documentation pages are located under the `docs/` folder.
To run the documentation site locally (useful for previewing changes), use:
```shell
$ scripts/docs serve
```
## Resolving Build / CI Failures
Once you've submitted your pull request, the test suite will
automatically run, and the results will show up in GitHub.
If the test suite fails, you'll want to click through to the
"Details" link, and try to identify why the test suite failed.
Here are some common ways the test suite can fail:
### Check Job Failed
This job failing means there is either a code formatting issue or type-annotation issue.
You can look at the job output to figure out why it's failed or within a shell run:
```shell
$ scripts/check
```
It may be worth it to run `$ scripts/lint` to attempt auto-formatting the code
and if that job succeeds commit the changes.
### Docs Job Failed
This job failing means the documentation failed to build. This can happen for
a variety of reasons like invalid markdown or missing configuration within `mkdocs.yml`.
### Python 3.X Job Failed
This job failing means the unit tests failed or not all code paths are covered by unit tests.
If tests are failing you will see this message under the coverage report:
`=== 1 failed, 354 passed, 1 skipped, 1 xfailed in 37.08s ===`
If tests succeed but coverage doesn't reach 100%, you will see this
message under the coverage report:
`Coverage failure: total of 98 is less than fail-under=100`
## Releasing
*This section is targeted at Uvicorn maintainers.*
Before releasing a new version, create a pull request that includes:
- **An update to the changelog**:
- We follow the format from [keepachangelog](https://keepachangelog.com/en/1.0.0/).
- [Compare](https://github.com/Kludex/uvicorn/compare/) `main` with the tag of the latest release, and list all entries that are of interest to our users:
- Things that **must** go in the changelog: added, changed, deprecated or removed features, and bug fixes.
- Things that **should not** go in the changelog: changes to documentation, tests or tooling.
- Try sorting entries in descending order of impact / importance.
- Keep it concise and to-the-point. π―
- **A version bump**: see `__init__.py`.
For an example, see [#1006](https://github.com/Kludex/uvicorn/pull/1107).
Once the release PR is merged, create a
[new release](https://github.com/Kludex/uvicorn/releases/new) including:
- Tag version like `0.13.3`.
- Release title `Version 0.13.3`
- Description copied from the changelog.
Once created this release will be automatically uploaded to PyPI.
uvicorn-0.38.0/docs/deployment/ 0000775 0000000 0000000 00000000000 15074714634 0016412 5 ustar 00root root 0000000 0000000 uvicorn-0.38.0/docs/deployment/docker.md 0000664 0000000 0000000 00000010645 15074714634 0020211 0 ustar 00root root 0000000 0000000 # Dockerfile
**Docker** is a popular choice for modern application deployment. However, creating a good Dockerfile from scratch can be challenging. This guide provides a **solid foundation** that works well for most Python projects.
While the example below won't fit every use case, it offers an excellent starting point that you can adapt to your specific needs.
## Quickstart
For this example, we'll need to install [`docker`](https://docs.docker.com/get-docker/),
[docker-compose](https://docs.docker.com/compose/install/) and
[`uv`](https://docs.astral.sh/uv/getting-started/installation/).
Then, let's create a new project with `uv`:
```bash
uv init app
```
This will create a new project with a basic structure:
```bash
app/
βββ main.py
βββ pyproject.toml
βββ README.md
```
On `main.py`, let's create a simple ASGI application:
```python title="main.py"
async def app(scope, receive, send):
body = "Hello, world!"
await send(
{
"type": "http.response.start",
"status": 200,
"headers": [
[b"content-type", b"text/plain"],
[b"content-length", len(body)],
],
}
)
await send(
{
"type": "http.response.body",
"body": body.encode("utf-8"),
}
)
```
We need to include `uvicorn` in the dependencies:
```bash
uv add uvicorn
```
This will also create a `uv.lock` file. :sunglasses:
??? tip "What is `uv.lock`?"
`uv.lock` is a `uv` specific lockfile. A lockfile is a file that contains the exact versions of the dependencies
that were installed when the `uv.lock` file was created.
This allows for deterministic builds and consistent deployments.
Just to make sure everything is working, let's run the application:
```bash
uv run uvicorn main:app
```
You should see the following output:
```bash
INFO: Started server process [62727]
INFO: Waiting for application startup.
INFO: ASGI 'lifespan' protocol appears unsupported.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
## Dockerfile
We'll create a **cache-aware Dockerfile** that optimizes build times. The key strategy is to install dependencies first, then copy the project files. This approach leverages Docker's caching mechanism to significantly speed up rebuilds.
```dockerfile title="Dockerfile"
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# Change the working directory to the `app` directory
WORKDIR /app
# Install dependencies
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --frozen --no-install-project
# Copy the project into the image
ADD . /app
# Sync the project
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen
# Run with uvicorn
CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```
A common question is **"how many workers should I run?"**. The image above uses a single Uvicorn worker.
The recommended approach is to let your orchestration system manage the number of deployed containers rather than
relying on the process manager inside the container.
You can read more about this in the
[Decouple applications](https://docs.docker.com/build/building/best-practices/#decouple-applications) section
of the Docker documentation.
!!! warning "For production, create a non-root user!"
When running in production, you should create a non-root user and run the container as that user.
To make sure it works, let's build the image and run it:
```bash
docker build -t my-app .
docker run -p 8000:8000 my-app
```
For more information on using uv with Docker, refer to the
[official uv Docker integration guide](https://docs.astral.sh/uv/guides/integration/docker/).
## Docker Compose
When running in development, it's often useful to have a way to hot-reload the application when code changes.
Let's create a `docker-compose.yml` file to run the application:
```yaml title="docker-compose.yml"
services:
backend:
build: .
ports:
- "8000:8000"
environment:
- UVICORN_RELOAD=true
volumes:
- .:/app
tty: true
```
You can run the application with `docker compose up` and it will automatically rebuild the image when code changes.
Now you have a fully working development environment! :tada:
uvicorn-0.38.0/docs/deployment/index.md 0000664 0000000 0000000 00000026406 15074714634 0020053 0 ustar 00root root 0000000 0000000 Server deployment is a complex area, that will depend on what kind of service you're deploying Uvicorn onto.
As a general rule, you probably want to:
* Run `uvicorn --reload` from the command line for local development.
* Run `gunicorn -k uvicorn.workers.UvicornWorker` for production.
* Additionally run behind Nginx for self-hosted deployments.
* Finally, run everything behind a CDN for caching support, and serious DDOS protection.
## Running from the command line
Typically you'll run `uvicorn` from the command line.
```bash
$ uvicorn main:app --reload --port 5000
```
The ASGI application should be specified in the form `path.to.module:instance.path`.
When running locally, use `--reload` to turn on auto-reloading.
The `--reload` and `--workers` arguments are **mutually exclusive**.
To see the complete set of available options, use `uvicorn --help`:
```bash
{{ uvicorn_help }}
```
See the [settings documentation](../settings.md) for more details on the supported options for running uvicorn.
## Running programmatically
To run directly from within a Python program, you should use `uvicorn.run(app, **config)`. For example:
```py title="main.py"
import uvicorn
class App:
...
app = App()
if __name__ == "__main__":
uvicorn.run("main:app", host="127.0.0.1", port=5000, log_level="info")
```
The set of configuration options is the same as for the command line tool.
Note that the application instance itself *can* be passed instead of the app
import string.
```python
uvicorn.run(app, host="127.0.0.1", port=5000, log_level="info")
```
However, this style only works if you are not using multiprocessing (`workers=NUM`)
or reloading (`reload=True`), so we recommend using the import string style.
Also note that in this case, you should put `uvicorn.run` into `if __name__ == '__main__'` clause in the main module.
!!! note
The `reload` and `workers` parameters are **mutually exclusive**.
## Using a process manager
Running Uvicorn using a process manager ensures that you can run multiple processes in a resilient manner, and allows you to perform server upgrades without dropping requests.
A process manager will handle the socket setup, start-up multiple server processes, monitor process aliveness, and listen for signals to provide for processes restarts, shutdowns, or dialing up and down the number of running processes.
### Built-in
Uvicorn includes a `--workers` option that allows you to run multiple worker processes.
```bash
$ uvicorn main:app --workers 4
```
Unlike gunicorn, uvicorn does not use pre-fork, but uses [`spawn`](https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods), which allows uvicorn's multiprocess manager to still work well on Windows.
The default process manager monitors the status of child processes and automatically restarts child processes that die unexpectedly. Not only that, it will also monitor the status of the child process through the pipeline. When the child process is accidentally stuck, the corresponding child process will be killed through an unstoppable system signal or interface.
You can also manage child processes by sending specific signals to the main process. (Not supported on Windows.)
- `SIGHUP`: Work processeses are graceful restarted one after another. If you update the code, the new worker process will use the new code.
- `SIGTTIN`: Increase the number of worker processes by one.
- `SIGTTOU`: Decrease the number of worker processes by one.
### Gunicorn
!!! warning
The `uvicorn.workers` module is deprecated and will be removed in a future release.
You should use the [`uvicorn-worker`](https://github.com/Kludex/uvicorn-worker) package instead.
```bash
python -m pip install uvicorn-worker
```
Gunicorn is probably the simplest way to run and manage Uvicorn in a production setting. Uvicorn includes a gunicorn worker class that means you can get set up with very little configuration.
The following will start Gunicorn with four worker processes:
`gunicorn -w 4 -k uvicorn.workers.UvicornWorker`
The `UvicornWorker` implementation uses the `uvloop` and `httptools` implementations. To run under PyPy you'll want to use pure-python implementation instead. You can do this by using the `UvicornH11Worker` class.
`gunicorn -w 4 -k uvicorn.workers.UvicornH11Worker`
Gunicorn provides a different set of configuration options to Uvicorn, so some options such as `--limit-concurrency` are not yet supported when running with Gunicorn.
If you need to pass uvicorn's config arguments to gunicorn workers then you'll have to subclass `UvicornWorker`:
```python
from uvicorn.workers import UvicornWorker
class MyUvicornWorker(UvicornWorker):
CONFIG_KWARGS = {"loop": "asyncio", "http": "h11", "lifespan": "off"}
```
### Supervisor
To use `supervisor` as a process manager you should either:
* Hand over the socket to uvicorn using its file descriptor, which supervisor always makes available as `0`, and which must be set in the `fcgi-program` section.
* Or use a UNIX domain socket for each `uvicorn` process.
A simple supervisor configuration might look something like this:
```ini title="supervisord.conf"
[supervisord]
[fcgi-program:uvicorn]
socket=tcp://localhost:8000
command=venv/bin/uvicorn --fd 0 main:App
numprocs=4
process_name=uvicorn-%(process_num)d
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
```
Then run with `supervisord -n`.
## Running behind Nginx
Using Nginx as a proxy in front of your Uvicorn processes may not be necessary, but is recommended for additional resilience. Nginx can deal with serving your static media and buffering slow requests, leaving your application servers free from load as much as possible.
In managed environments such as `Heroku`, you won't typically need to configure Nginx, as your server processes will already be running behind load balancing proxies.
The recommended configuration for proxying from Nginx is to use a UNIX domain socket between Nginx and whatever the process manager that is being used to run Uvicorn. If using Uvicorn directly you can bind it to a UNIX domain socket using `uvicorn --uds /path/to/socket.sock <...>`.
When running your application behind one or more proxies you will want to make sure that each proxy sets appropriate headers to ensure that your application can properly determine the client address of the incoming connection, and if the connection was over `http` or `https`. For more information see [Proxies and Forwarded Headers](#proxies-and-forwarded-headers) below.
Here's how a simple Nginx configuration might look. This example includes setting proxy headers, and using a UNIX domain socket to communicate with the application server.
It also includes some basic configuration to forward websocket connections.
For more info on this, check [Nginx recommendations](https://nginx.org/en/docs/http/websocket.html).
```conf
http {
server {
listen 80;
client_max_body_size 4G;
server_name example.com;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://uvicorn;
}
location /static {
# path for static files
root /path/to/app/static;
}
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream uvicorn {
server unix:/tmp/uvicorn.sock;
}
}
```
Uvicorn's `--proxy-headers` behavior may not be sufficient for more complex proxy configurations that use different combinations of headers, or where the application is running behind more than one intermediary proxying service.
In those cases, you might want to use an ASGI middleware to set the `client` and `scheme` dependant on the request headers.
## Running behind a CDN
Running behind a content delivery network, such as Cloudflare or Cloud Front, provides a serious layer of protection against DDoS attacks. Your service will be running behind huge clusters of proxies and load balancers that are designed for handling huge amounts of traffic, and have capabilities for detecting and closing off connections from DDoS attacks.
Proper usage of cache control headers can mean that a CDN is able to serve large amounts of data without always having to forward the request on to your server.
Content Delivery Networks can also be a low-effort way to provide HTTPS termination.
## Running with HTTPS
To run uvicorn with https, a certificate and a private key are required.
The recommended way to get them is using [Let's Encrypt](https://letsencrypt.org/).
For local development with https, it's possible to use [mkcert](https://github.com/FiloSottile/mkcert)
to generate a valid certificate and private key.
```bash
$ uvicorn main:app --port 5000 --ssl-keyfile=./key.pem --ssl-certfile=./cert.pem
```
### Running gunicorn worker
It's also possible to use certificates with uvicorn's worker for gunicorn.
```bash
$ gunicorn --keyfile=./key.pem --certfile=./cert.pem -k uvicorn.workers.UvicornWorker main:app
```
## Proxies and Forwarded Headers
When running an application behind one or more proxies, certain information about the request is lost.
To avoid this most proxies will add headers containing this information for downstream servers to read.
Uvicorn currently supports the following headers:
- `X-Forwarded-For` ([MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For))
- `X-Forwarded-Proto`([MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto))
Uvicorn can use these headers to correctly set the client and protocol in the request.
However as anyone can set these headers you must configure which "clients" you will trust to have set them correctly.
Uvicorn can be configured to trust IP Addresses (e.g. `127.0.0.1`), IP Networks (e.g. `10.100.0.0/16`),
or Literals (e.g. `/path/to/socket.sock`). When running from CLI these are configured using `--forwarded-allow-ips`.
!!! Warning "Only trust clients you can actually trust!"
Incorrectly trusting other clients can lead to malicious actors spoofing their apparent client address to your application.
For more information, check [`ProxyHeadersMiddleware`](https://github.com/Kludex/uvicorn/blob/main/uvicorn/middleware/proxy_headers.py).
### Client Port
Currently if the `ProxyHeadersMiddleware` is able to retrieve a trusted client value then the client's port will be set to `0`.
This is because port information is lost when using these headers.
### UNIX Domain Sockets (UDS)
Although it is common for UNIX Domain Sockets to be used for communicating between various HTTP servers, they can mess with some of the expected received values as they will be various non-address strings or missing values.
For example:
- when NGINX itself is running behind a UDS it will add the literal `unix:` as the client in the `X-Forwarded-For` header.
- When Uvicorn is running behind a UDS the initial client will be `None`.
### Trust Everything
Rather than specifying what to trust, you can instruct Uvicorn to trust all clients using the literal `"*"`.
You should only set this when you know you can trust all values within the forwarded headers (e.g. because
your proxies remove the existing headers before setting their own).
uvicorn-0.38.0/docs/img/ 0000775 0000000 0000000 00000000000 15074714634 0015006 5 ustar 00root root 0000000 0000000 uvicorn-0.38.0/docs/img/gh-actions-fail-check.png 0000664 0000000 0000000 00000401472 15074714634 0021544 0 ustar 00root root 0000000 0000000 PNG
IHDR o ³±= sBIT|d tEXtSoftware gnome-screenshotοΏ> IDATxμέwXυΗρη9μ=Dΐ= *ξ{δΘZeeυνΧ2ΫefεΧΚ¬ΤJΝ,·{ο4s8’2=Ξωύ$A@)ωΪλq]\ηΎοΟΈο£(―σΉί·Αl6RΕx·' """"""""""7Sx+"""""""""R
)Ό)
ήB
oEDDDDDDDDDJ!
·""""""""""₯Β[RHαH)€πVDDDDDDDDD€².NΜa1νΨ
9<σ
p! _uprΒΰη±k'~~%1Θ=Ο`6Ν·Υ29Σeδ¬]g kεδUΎ}δΆω·ΈπΦΌcΩ|))·7ͺ7ΦOΔΠΊεν΅ΉΗ;ΌΝφ-¦%KKdp«GΡ*\|+ΌΝωδ3LkΧθ¬ρΗK΄OuΖ’3νn
ujσΛBrfX’ύό―³.ΚAζ»0-YvΛcAυ0vν1(|}rΫ
cΐ΄v=ζ°Γy―Sσο `ϊρ'~~ͺ+"""""""""rMαeΙztxΑ'σφΖϊΥ0ΤΊe7ζΠ0r¦}9βtΰΦΒΗ9?yβΗOF0wώΒOαεη">!³ζΡ£kPδ~nΧΎa|ςω7΄iΩQO=vΗύ½ώξGD=ΟογγνU3Μ+5-Η}OwΎϊl\χ/"""""""""%«Π² 9άͺWΓζλ/
nυ°ώd"ΖΆmon.Δ«|Βo«ΧsβTΤΕ§¬ξnΤ
πΓΫ«δΟό8;9R+ΐrΎή%_Κ©ΰMCΡh€V~Υ«ό-ύHΙ*tεmVΏω·ήήΨ|ύ%8;oΔδd²~ββnήηδΝEκζεθ±}λόͺorOJLLbκΩGΑ«ΟJ΅*ΤφμΉ(¦ΝCtΜ0ΐΠΑθΤu‘ν―\ΗΪ[ΙΞΙ‘iΓ
ΡΘώCωzζ<Η^MNα§_`4ήόΙγΟΎΒ'γήΒΣΓ½h'+""""""""χΌ[.σ4ΈκΦϊΥά8;cύκKdΏϊϊΝϋRR0cπσ»eΧK Όύα'<3βQ²²²-eμίίΛ₯Λρ<σΔ£΄nΑδ©3Ψ³ο ν[πΜήΤηΟζjr2φοΕΚ΅±²²’sϋ`ΥaΖμΓί―*£|w·Κ&dff1wώB―OYξοή6-ΊΖ² VVF{εm*U(OΧNmωmυzSRiΦΈ#> QΡ±Μ=sηchΩ¬W&³gίAΖΏ;κU+η9ΏόΚ&9z_ΚΩσQ888P·v
κ»» k7laΥϊΝ\Ί»+7a`Ώϋ±2ωmυ~όe1ύ{ucP^ LύvΫvνεF€a©iiΜωy1‘AέΐZd ₯ΒΖ/iίύHZ5σ(ΆνΪΛ%ΏρΪΟ©ν[ρ―^qοΌoΈ?bύζmΌΖK8;91aςTΦmάJ·Ξνiά ΣΏψΨrμ½ϋΩ΅χ@ϋΉedΪΉ+ίν zE*PCύ AυςsνϊBΫ<JΚππΐΎΤ]3Ο~;;[?2EΛWy½ϋαμδΔϋέ²οΕΏ¦―W&³pΩJή) 6669z
KWδΫξΕΏ²fΓάέ\iΩ¬1 ILύvΏq’Hϋσs!^«+iiιlΪΊMΫrίΜL&ώχ+ώ8~*+°ΠaBzνKLΊΒ€)_sζάyZ4mDy_oΆο
ασ―Ώ`‘Γ|χγ|222iΣ²)666,ύm
K―*ς¦|Ν¦;©V΅2ukr Ο¦N';;»Πρ+1ι
gΞΡ«GF#νZ·Θά?ΑθwΖσΒkο2ζ½ =ΐω¨FώηuΆξΨΓφέ!<σo0ς?―[ήτΎω#/~^{υ·[ϊά³ο ΫΆ¦§vvΆάί3»Cή4·ΜΜ,ζ-\ΞΓϋXΆ=~σ>/½ρΌs{ΫWήGδ»έΨ΅σlμΪ°ΓEσF΅pqq²|_ΖΣγ¦c7’i£ϊeβδ―0Ν<ς`?\
Y-όκ# ͺ[/Ώύν»BhΦΈ!yζq=ΖΈI_p>:&ίvα thΫmZrόdSφ:LvNNφη'''Ι½CY―2,XΊEΛVqϊ΄fΛφέΔ]ΌLΣΖυyωΉ§HLLβΩί*μY!#3ͺU*1 OΌΚx2oαrrrr0ΝωΥ©ΝϊΖΚ΅qu)Ϊjλ§NσΗρSΦ
ΰΥF0eΪwμΪ»=ϋβζκzΛρ
CΟΰΜΉ(|}Κ2kξΑ»ld ω§Οϊ~χw£u&,[±Ή2ζ₯QT¬Po¦L`Κ΄ο¬@mςτ;oΑ2223ψτ£wHMMeΜ{ρ«V
jU*s!/ηγMLμ
ζΆeΗnόͺαλσg}δoΏGφ₯iγϊlΨΌ΄ττ"ηυ?ωy OφνY€~DDDDDDDD€τ»εΚ[s>α*1θφWέ^gπ«Κ4άaΔήΞ€+W©ΰGϋΰ
Ά πΟλξ{λ~Mάyz\{m2ε_"ΈAύ: Μύ3O>?ΥΆX«υλΦ.ώό/ηCY―2 TBfeeXVΥΙmοξξ1FΰW
g''"ΟγωWία΅·ΗΠ§gWAυ1lήΎ'―¦ΟΖΫΛNνΤυϋθ±<4|
Ε½ϋ―ν-tόβJII%ότYκΤΑ> IΓϊLώrΧK:OxοuZ5o@ν\»T€~χ:Lm±2qqv¦Uσ&μ?@ff&ΆΆ6Μ5·ΖNΒΦΦτ<νΝf3+Φl€η}-Ϋpρe4Κύ{Τ6Έ
ΆΨ·'ς hάά{nΉςΆ@Ύ>w G{Ό½ΚΠΌIC ΊwiΟΌ
ΛHHLΒΣΓ‘¬Z·23³0φη!%%/ΏύΑR«6;'fκ`ggGffujΧΐΧΗΜΜ,μνμς΄<ΙdΚS89%G{KHmcmmΡΟw@ΝfΛ
\·""""""""χ¦ΫoGΜσρτΰdψiΦmΪFΧmK|μμl/_
#ΜΗ³fΓ~»ΓGs_§v·ά_Px{+εΛεθG~?F6-INIαΔ©ΣEnzψ(ΗOSΏ^ztνΘ+Wyχ£ΟγΜΉ(N9GBB"χunΗCzyζcήΘ£Η°±Ιύ£δε'―Z ¨XΎ27i»ΒtΧή>»k‘γϋW―Z¬λαγ]ΤΤJ.XYYΔWΣg3ρ7(_Ξc'N1mζ"υλαξΖ³OΝw>ε}}8w>ΚςΐΆ]{χS±BΉ<Η=BΓ :yΆ99:akZz:YΕ:ίΓZ·""""""""χ¦[·zσφΨwΎϊ6Ϊ 1Kΐ½ϋ9φ;Κϋς£FπΪΫγ·pΝΥΗέέDΖΈΞΪΪύsζ\?FΕ
ε8ςGnΘXΣΏΠύ·£}pK,_Ν=ϋHNM%:ζΩΩΩEnΕβ_W³~σv7¨GFf&±.ββμLΕ
εΨ±{«ΦmbχΎΤ©U¨XΜf3΅Ν·ZJ εqpιrIWZϊχ«V
Ϊ5ύ =|ΙSgΰθθΐΦ{pqq¦OΟ;qκγW9_oΚzaνΖtνΨ5λ·PήΧ7W"ΟΗΪΪο²e0Llέ±ττΒ;4
bΝϊ-ψ=YΙΔOΡ’iCόͺΡ²Y#&OAΗvqrtdΕthΫ*OϋΘ3ηhXΏnmξnxΈ»r f°~ΣvΛJεβPh+"""""""ro»ebdπΟΏ΄),μ.¨Ζ,Τ4fύ΄ϋχ’bωr΄mΥ΄΄tΎ»ΰϋΟΟ+/€UσΖD_cΣΦdeeΣΏwwξοΦΉHϋΛέΝ7^yκU+sςΤikΠτΪνόEΡ΄Q}|l0ξξnμΪ{CaG ¬U1/ΒήΞφαώnΙΞΞfσΆ]DEΗ¦U3F
@
κ<ΨΏ.Ξ\»D¦
iqdε6qόd8{χ’QύΊΌχϊΈ8;:ώνxρΩ'ΨΆs/#{{χρΒΣP₯R5¨Ηχ&ςΡgS nΥ;;;ΎψζBϋμί»;VVVόgτ{ΌτΖdgg[J ψU£WχΞΌχΡd^zγjψW§γ_ΒΫΛ xόεΓΑΐSΓζΗ_σμKoΰββ©₯=DDDDDDDDδίΑ`ΎΕr¦}iΙ²ΥΓϊw4pφ+£σ} ±_¬yG}ΔΔΖ{!²^e,+U_σΡ±ψzςψ_],"""""""""¬[M0εήΓc
ΓP?θΆ5εά^S
w.*ΟΎ»CμOtμ’c/PΓΏ[{ΐ-Wήd
qq77τ«υ€ ΰμ\ΌΙ~υuΜα7οσφΖζΗΧίΏΨΊMΫX³~q.αδθH½:΅xx@
·"""""""""χBΓΫΩ?bϊρ§ό7ΐ½Up<ΥΠ!EλKDDDDDDDDDδVθ#ξϊχGΗ|χΓ#Θzζ9Μ‘
?ΐΜ{lΑ-ήήΉcHα+oΜ;vύώΨ[wTcΧ.όͺaπσΛmvsμLKΪ^cύξΫZ·,ΖΤEDDDDDDDDDξ]E
or¦}οΓΛJ±_¬ω·τ-"""""""""ςΏ¨Π² ΧY=3cN%?.άόEWή^W+p΅βVDDDDDDDDD$ΕoαZ
άIBjκνκθυ«/«ΖHn+Ό 9ΕK1-^ZτΧΡcΎXυοΞΞ·5¬ΘΏΑν·70cZ»sx$'c8»ΓΡΏΏκ΄VDDDDDDDDD€J$ΌeΌΫ)Ό)
ήB
oEDDDDDDDDDJ!
·""""""""""₯Β[RHαH)€πVDDDDDDDDD€Rx+"""""""""R
)Ό)
ήB
oEDDDDDDDDDJ!
·""""""""""₯Β[RHαH)dzμτέH©7 Ώ»=ω±_«Ϊέό
Κ&B
oEDDDDDDDDDJ!
·""""""""""₯Β[RHαH)€πVDDDDDDDDD€Rx+"""""""""R
)Ό)
ήB
oEDDDDDDDDDJ!
·""""""""""₯Β[RHαH)€πVDDDDDDDDD€Rx+"""""""""R
)Ό)
ήB
oEDDDDDDDDDJ!
·""""""""""₯Β[RΘϊnO@DDrΝ;:΅σlΛΘΘδάΉs,ZΌyΏΜΗd2ΉΏΰΦ°±±απα#\Ί|[7βββΒώο6mήR’σ/www^όΟs΄m£#gΞeξΌYΆό·[Άλί·?HεJΉxιkΧm`ΖΜοIMM½£ωΌφΚKyd0λΦoΰεW_Ώ£Ύ#ΏχθNόχ³ItμΠηΞγγO>+R''G5m
ΐΦmΫΙΙΙΉγyό}ό(Ό³yϋnfΟ[HjjZ±Ϊ9::0tπ Ϊ·ψfφΏΛΞΞ?FΏφ2φΜψξ"·αϋΈ»»ίυ φ―¬¬¬ώΝWΤ¬@FF&©©)ΤͺU±οΏΡΕKεΫnθ£πΚK/pωr<*VdΔγΓπ«^όί+δ)πωϊϊ2eς' ΄jΣδδδΎEDDDDlνμ°±±ΕΚΚκnOEώ&₯:ΌνέAώ8vΌΐύΗ₯ί^·έΏΙdΒl£ΡΑ`Θχ°#ΏσΕΤ―ωύθ$_M¦B
ςτμ~OCΖ7a?ΜΛψ±ο2π~ΝfL&3ͺ\!χY?- jεΦͺQ¬vG`φΌ
Ε
oSΣ°2Zagg[άizK.ηύ±γ0+ηΛρc ͺW‘>R¬πΆ΄jΦ΄ 5kΐΐΗΖΡ΅KgϊτιU`xϋπCπώΨq,ZΌ*U*³πythίrΎΎΔΔΖώ§!"""""rΧFΪώκδ°vν4iΤ&βκβ@Κ,ΫΚρΈ£ώίϋ΅κ5βΧ«ςέ:ςCΑζ-Ϋ°³³ΓίΏ:§#ςε4^{γ"S©b4jW2 ¬\½Zυρφ{ήΡόEJ΄΄tkΥ``ίΕϊ
¬U£Ψ«u§ΝCΘΠ<Ϋα‘α£ς|=ύβ<ΕΩlΒd2ΓωσQΜύι ·Τ««+S&BΨΑ¦σUvΛ, μ`
BΨΑάέέ2ω^{ε₯<ΗΪΫΫσαο²eγZΦϊaCά4Ξ:2λϋμάΆΥ+σι€ TͺXΡ²ΏIγFαΰΎέψϋϋρέoΨ΅}Λ,ΰΎ9Υ+³nυ
ήzc4vvvύόLΨΑθoΩΦνΎ.aγϊΥmΧϋoά'gλ¦u¬[½{£ΡmΎο»[Ύs{λΝΧo:’4p ζΟcΟΞlέΌίN£iΖ ΄jΥ%±»sΫ&:΄oW2|4n,kVύΚΞmψϊ«/hP?(OίuλΦαλ©³uΣ:vnΫΔOs~ Gχn
φ-"""""wFΑνΏG©^y;qάοxj[·ο`δ3π~Θψ+V&--ώ}{1qόX ’’’ιΥ«Χ¬γr|