Search code examples
djangodjango-rest-frameworkpython-3.5django-cors-headers

Django - Sending OPTIONS request second time will append body data to request method


The issue is when there's content inside body with OPTIONS method, the second request will always fail with message Method Not Allowed. Printed the log and showed that the method became "{"username":"test","password":"test"}POST /member/login/ HTTP/1.1" 405 111. Problem is when the server has restarted, the first OPTIONS request will pass normally. Have tried with only POST and it works fine. Only OPTIONS has this issue.

ENV details: python:3.6.5, django:2.1.3, drf:3.9.0, django-cors-headers:2.4.0

views.py(Only show the decorations cause it didn't go inside the block):

@csrf_exempt
@api_view(['POST'])
@authentication_classes([])
@permission_classes([AllowAny])
def member_login(request):
    pass

middlewares:

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Request method: OPTIONS and POST

Request header:

Content-Type: application/json
Origin: http://google.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER,Content-Type

Request body:

{"username":"superuser","password":"pass1234"}

After sending OPTIONS request for 2 times:

INFO 2018-12-25 02:26:03,585 "OPTIONS /member/login/ HTTP/1.1" 200 0
WARNING 2018-12-25 02:26:10,180 Method Not Allowed: /member/login/
WARNING 2018-12-25 02:26:10,182 "{"username":"superuser","password":"pass1234"}OPTIONS /member/login/ HTTP/1.1" 405 98

After getting error with method not allowed, cannot send any other request to the api. It will always return Method Not Allowed even it's the different method I'm using.

WARNING 2018-12-25 02:30:57,939 Method Not Allowed: /member/login/
WARNING 2018-12-25 02:30:57,940 "{"username":"superuser","password":"pass1234"}POST /member/login/ HTTP/1.1" 405 95
WARNING 2018-12-25 02:30:58,603 Method Not Allowed: /member/login/
WARNING 2018-12-25 02:30:58,603 "{"username":"superuser","password":"pass1234"}POST /member/login/ HTTP/1.1" 405 95
WARNING 2018-12-25 02:30:59,684 Method Not Allowed: /member/login/
WARNING 2018-12-25 02:30:59,685 "{"username":"superuser","password":"pass1234"}POST /member/login/ HTTP/1.1" 405 95

Tried with the older version of Django. This issue didn't happen.


Solution

  • Updating to Django>=2.1.5 will fix this. This is due to this issue: HTTP server doesn't clear previous request data in keep-alive connection

    The issue was that the implementation of WSGI server for runserver was not consuming request content when there was an OPTIONS request. And with a keep-alive connection, the remaining data got read as content for the subsequent request.