-
Notifications
You must be signed in to change notification settings - Fork 69
Description
Bug
When a HttpResponse has multiple headers with the same name, only one header is returned.
Django uses multiple response cookies (e.g. 'csrf' and 'messages').
Multiple Set-Cookie headers can be returned. Set-Cookie is the name (the key) of the Http Response Header.
Context
A Django app running in an Azure Function
package
Name: azure-functions
Version: 1.8.0
Summary: Azure Functions for Python
Home-page: UNKNOWN
Author: Microsoft Corporation
Author-email: [email protected]
Version
Azure function runtime version = ~4
Reproduction
- Create a http response with two Set-Cookie headers
This header has been captured from the app running without the Azure wsgi middleware.
HTTP/1.1 200 OK
Date: Sun, 16 Jan 2022 09:00:59 GMT
Server: WSGIServer/0.2 CPython/3.9.9
Content-Type: text/html; charset=utf-8
X-Frame-Options: DENY
Vary: Cookie
Content-Length: 5206
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Set-Cookie: messages=""; expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; Max-Age=0; Path=/; SameSite=Lax
Set-Cookie: csrftoken=L6coOZOclDhAg2X7geBKbhvJSHPxz9AbgOkoVqNAIsgVe8oxTEPTSPbc2VPSyjwq; expires=Sun, 15 Jan 2023 09:00:59 GMT; Max-Age=31449600; Path=/; SameSite=Lax
-
Run without azure.functions.WsgiMiddleware
Two Set-Cookies headers are returned (as depicted above) -
Run with azure.functions.WsgiMiddleware.handle
import azure.functions as func
def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
http_response = func.WsgiMiddleware(application).handle(req, context)
return http_response
Only one header with the name "Set-Cookie" is returned.
Local and remote
This behaviour has been reproduced both locally (while debugging) as on an Azure Function container (icarus-int)
Root cause
Python package 'azure-functions'
azure\functions_http.py
class HttpResponseHeaders(BaseHeaders, collections.abc.MutableMapping):
def __setitem__(self, key: str, value: str):
self.__http_headers__[key.lower()] = value
def __delitem__(self, key: str):
del self.__http_headers__[key.lower()]
The headers are stored as a dictionary. All keys in a dictionary are unique.
References
https://www.rfc-editor.org/rfc/rfc6265#page-6
Section 3
"Origin servers SHOULD NOT fold multiple Set-Cookie header fields into
a single header field. The usual mechanism for folding HTTP headers
fields (i.e., as defined in [RFC2616]) might change the semantics of
the Set-Cookie header field because the %x2C (",") character is used
by Set-Cookie in a way that conflicts with such folding."
https://www.rfc-editor.org/rfc/rfc6265#section-4.1
"Servers SHOULD NOT include more than one Set-Cookie header field in
the same response with the same cookie-name. (See Section 5.2 for
how user agents handle this case.)"
This means that multiple Set-Cookie headers with different cookie-names are allowed.