Fastapi: [BUG] Content-Type header must be allowed explicitly, docs say otherwise

Created on 6 Mar 2020  Â·  9Comments  Â·  Source: tiangolo/fastapi

Describe the bug

According to [1], Content-Type is always allowed for CORS requests. This is not true, see the test below.

[1] https://fastapi.tiangolo.com/tutorial/cors/#use-corsmiddleware

To Reproduce

Steps to reproduce the behavior with a minimum self-contained file.

Replace each part with your own scenario:

  1. Create a file test_cors.py with:


Toggle to view

import pytest
from fastapi import FastAPI
from starlette import status
from starlette.middleware.cors import CORSMiddleware
from starlette.testclient import TestClient

app = FastAPI()

app.add_middleware(CORSMiddleware)


@app.post(path='/dummy')
def dummy():
    ...


@pytest.fixture
def client():
    yield TestClient(app)


def test_content_type_is_always_allowed_for_cors_requests(client):
    # arrange
    request_headers = {
        "Origin": "https://www.google.de",
        "Access-Control-Request-Method": "POST",
        "Access-Control-Request-Headers": "Content-Type",
    }

    # act
    response = client.options('/', headers=request_headers)

    # assert
    assert response.status_code == status.HTTP_200_OK

  1. Run pytest test_cors.py

Expected behavior

The Content-Type header is whitelisted as per the documentation.

Screenshots

n/a

Environment

  • OS: macOS
  • FastAPI Version: 0.52.0
  • Python version: 3.7.6

Additional context

bug

Most helpful comment

The section:

The Accept, Accept-Language, Content-Language and Content-Type headers are always allowed for CORS requests.

It doesn't mean that something will automatically return the Allow-X headers without a middleware, it means that browsers, the ones that actually do all the CORS dance, don't require those headers to do CORS (cross-origin resource sharing). So, browsers don't even trigger an OPTIONS request before one with those headers.

I think it would be useful for you to read the docs about CORS in MDN to understand how all that works: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

All 9 comments

I noticed that the CORSMiddleware is coming straight from Starlette, so I would need to create an issue there, as well.

Did miss the allow_headers=["*"], kwargs?

Yes, I did not add this because the docs state: "The Accept, Accept-Language, Content-Language and Content-Type headers are always allowed for CORS requests."

I consider "always" to be unconditional. Am I wrong here?

For default CORS, I think you shouldn't add the code app.add_middleware(CORSMiddleware)

My understanding is that without the CORSMiddleware, no CORS is enabled at all.

The section:

The Accept, Accept-Language, Content-Language and Content-Type headers are always allowed for CORS requests.

It doesn't mean that something will automatically return the Allow-X headers without a middleware, it means that browsers, the ones that actually do all the CORS dance, don't require those headers to do CORS (cross-origin resource sharing). So, browsers don't even trigger an OPTIONS request before one with those headers.

I think it would be useful for you to read the docs about CORS in MDN to understand how all that works: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

Thanks for explaining!

Thanks @tiangolo

I wonder if it would be clearer if we change the docs to say,

The Accept, Accept-Language, Content-Language and Content-Type headers are always allowed for simple CORS requests.

I too had the misunderstanding that I would not have to explicitly specify those headers regardless of the kind of CORS request the server is expecting. I can create a PR if the doc change is OK with you.

Was this page helpful?
0 / 5 - 0 ratings