Usage

Default

To allow upload files to ../uploads directory for all clients via /uploads URL,

from pathlib import Path

from aiohttp import web
from aiohttp_tus import setup_tus


app = setup_tus(
    web.Application(),
    upload_path=Path(__file__).parent.parent / "uploads",
)

Understanding tus.io Chunk Size

By default, Uppy and some other tus.io clients do not setup chunk size and tries to upload as large chunk, as possible. However as aiohttp.web.Application setting up client_max_size on app initialization you might need to configure server to receive larger chunks as well as setup tus.io client to use respected chunk sizes.

Examples below shown on how to config different parts to upload files with chunk size of 4MB (4_000_000 bytes)

aiohttp.web configuration

from aiohttp import web
from aiohttp_tus import setup_tus

app = web.Application(client_max_size=4_000_000)

nginx configuration

location ~ ^/uploads.*$ {
    client_max_body_size 4M;
    proxy_pass http://localhost:8080;
}

tus.py configuration

tus-upload --chunk-size=4000000 \
    /path/to/large-file http://localhost:8080/uploads

uppy.io Configuration

uppy.use(Uppy.Tus, {
    endpoint: "http://localhost:8080/uploads",
    chunkSize: 3999999
})

Important

To make Uppy.Tus plugin work you need to specify chunk size at least 1 byte smaller than client_max_size. If you’ll provide chunk size equals to client max size upload will not work properly.

CORS Headers

At a moment (May 17 2020), aiohttp-tus supports setting up CORS Headers for aiohttp.web application only via cors_middleware from aiohttp-middlewares package.

As aiohttp-tus registers OPTIONS handlers it doesn’t work with aiohttp-cors library cause of known issue aio-libs/aiohttp-cors#241. (Full discussion)

To enable CORS Headers for your aiohttp.web application, which is using aiohttp-tus, you need to,

  1. Install aiohttp-middlewares

  2. In your app.py,

    from pathlib import Path
    
    from aiohttp import web
    from aiohttp_middlewares import cors_middleware
    from aiohttp_tus import setup_tus
    
    
    # Allow CORS Headers for requests from http://localhost:3000
    app = web.Application(
        middlewares=(
            cors_middleware(origins=("http://localhost:3000",)),
        )
    )
    setup_tus(
        app, upload_path=Path(__file__).parent.parent / "uploads",
    )
    

Reverse proxy and HTTPS

When aiohttp web application with aiohttp-tus deployed under the reverse proxy (such as nginx), with HTTPS support you need to setup https_middleware from aiohttp-middlewares package to ensure that aiohttp.web.Request instance has proper schema.

To use HTTPS middleware you need to,

  1. Install aiohttp-middlewares

  2. In app.py,

    from pathlib import Path
    
    from aiohttp import web
    from aiohttp_middlewares import https_middleware
    from aiohttp_tus import setup_tus
    
    app = web.Application(middlewares=(https_middleware(),))
    setup_tus(
        app, upload_path=Path(__file__).parent.parent / "uploads"
    )
    

User Uploads

To allow upload files to /files/{username} directory only for authenticated users via /users/{username}/uploads URL,

from aiohttp_tus.annotations import Handler


def upload_user_required(handler: Handler) -> Handler:
    async def decorator(request: web.Request) -> web.Response:
        # Change ``is_user_authenticated`` call to actual call,
        # checking whether user authetnicated for given request
        # or not
        if not is_user_authenticated(request):
            raise web.HTTPForbidden()
        return await handler(request)

    return decorator


app = setup_tus(
    web.Application(),
    upload_path=Path("/files") / r"{username}",
    upload_url=r"/users/{username}/uploads",
    decorator=upload_user_required,
)

On Upload Done Callback

There is a possibility to run any coroutine after upload is done. Example below, illustrates how to achieve that,

from aiohttp_tus.data import Resource


async def notify_on_upload(
    request: web.Request, resource: Resource, file_path: Path,
) -> None:
    redis = request.config_dict["redis"]
    await redis.rpush("uploaded_files", resource.file_name)


app = setup_tus(
    web.Application(),
    upload_path=Path(__file__).parent.parent / "uploads",
    on_upload_done=notify_on_upload,
)

Mutliple TUS upload URLs

It is possible to setup multiple TUS upload URLs. Example below illustrates, how to achieve anonymous & authenticated uploads in same time for one aiohttp.web.Application instance.

app = web.Application()
base_upload_path = Path(__file__).parent.parent / "uploads"

# Anonymous users uploads
setup_tus(app, upload_path=base_upload_path / "anonymous")

# Authenticated users uploads
setup_tus(
    app,
    upload_path=base_upload_path / r"{username}",
    upload_url=r"/users/{username}/uploads",
    decorator=upload_user_required,
)

Upload resource name

In most cases there is no need to specify aiohttp.web.Resource name for upload resource, but when it is necessary, it is possible to specify custom upload_resource_name and lately use it for URL reversing.

Example below illustrates how to achieve it,

In app.py,

setup_tus(
    web.Application(),
    upload_path=(
        Path(__file__).parent.parent / "uploads" / r"{username}"
    ),
    upload_url="/user/{username}/uploads",
    upload_resource_name="user_upload",
)

In views.py,

async def user_profile(request: web.Request) -> web.Response:
    upload_url = request.app.router["uploads"].url_for(
        username=request.match_info["username"]
    )
    return aiohttp_jinja2.render(
        "users/profile.html",
        request,
        {"upload_url": upload_url},
    )