mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
commit
c5be1bae5c
1
THANKS
1
THANKS
@ -178,3 +178,4 @@ WooParadog <guohaochuan@gmail.com>
|
||||
Xie Shi <xieshi@douban.com>
|
||||
Yue Du <ifduyue@gmail.com>
|
||||
zakdances <zakdances@gmail.com>
|
||||
Emile Fugulin <emilefugulin@hotmail.com>
|
||||
|
||||
@ -2010,3 +2010,20 @@ class PasteGlobalConf(Setting):
|
||||
|
||||
.. versionadded:: 19.7
|
||||
"""
|
||||
|
||||
|
||||
class StripHeaderSpaces(Setting):
|
||||
name = "strip_header_spaces"
|
||||
section = "Server Mechanics"
|
||||
cli = ["--strip-header-spaces"]
|
||||
validator = validate_bool
|
||||
action = "store_true"
|
||||
default = False
|
||||
desc = """\
|
||||
Strip spaces present between the header name and the the ``:``.
|
||||
|
||||
This is known to induce vulnerabilities and is not compliant with the HTTP/1.1 standard.
|
||||
See https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn.
|
||||
|
||||
Use with care and only if necessary.
|
||||
"""
|
||||
|
||||
@ -90,7 +90,10 @@ class Message(object):
|
||||
if curr.find(":") < 0:
|
||||
raise InvalidHeader(curr.strip())
|
||||
name, value = curr.split(":", 1)
|
||||
name = name.rstrip(" \t").upper()
|
||||
if self.cfg.strip_header_spaces:
|
||||
name = name.rstrip(" \t").upper()
|
||||
else:
|
||||
name = name.upper()
|
||||
if HEADER_RE.search(name):
|
||||
raise InvalidHeaderName(name)
|
||||
|
||||
@ -128,9 +131,12 @@ class Message(object):
|
||||
content_length = None
|
||||
for (name, value) in self.headers:
|
||||
if name == "CONTENT-LENGTH":
|
||||
if content_length is not None:
|
||||
raise InvalidHeader("CONTENT-LENGTH", req=self)
|
||||
content_length = value
|
||||
elif name == "TRANSFER-ENCODING":
|
||||
chunked = value.lower() == "chunked"
|
||||
if value.lower() == "chunked":
|
||||
chunked = True
|
||||
elif name == "SEC-WEBSOCKET-KEY1":
|
||||
content_length = 8
|
||||
|
||||
|
||||
4
tests/requests/invalid/020.http
Normal file
4
tests/requests/invalid/020.http
Normal file
@ -0,0 +1,4 @@
|
||||
GET /stuff/here?foo=bar HTTP/1.1\r\n
|
||||
Content-Length : 3\r\n
|
||||
\r\n
|
||||
xyz
|
||||
5
tests/requests/invalid/020.py
Normal file
5
tests/requests/invalid/020.py
Normal file
@ -0,0 +1,5 @@
|
||||
from gunicorn.config import Config
|
||||
from gunicorn.http.errors import InvalidHeaderName
|
||||
|
||||
cfg = Config()
|
||||
request = InvalidHeaderName
|
||||
5
tests/requests/invalid/021.http
Normal file
5
tests/requests/invalid/021.http
Normal file
@ -0,0 +1,5 @@
|
||||
GET /stuff/here?foo=bar HTTP/1.1\r\n
|
||||
Content-Length: 3\r\n
|
||||
Content-Length: 2\r\n
|
||||
\r\n
|
||||
xyz
|
||||
5
tests/requests/invalid/021.py
Normal file
5
tests/requests/invalid/021.py
Normal file
@ -0,0 +1,5 @@
|
||||
from gunicorn.config import Config
|
||||
from gunicorn.http.errors import InvalidHeader
|
||||
|
||||
cfg = Config()
|
||||
request = InvalidHeader
|
||||
4
tests/requests/valid/028.http
Normal file
4
tests/requests/valid/028.http
Normal file
@ -0,0 +1,4 @@
|
||||
GET /stuff/here?foo=bar HTTP/1.1\r\n
|
||||
Content-Length : 3\r\n
|
||||
\r\n
|
||||
xyz
|
||||
14
tests/requests/valid/028.py
Normal file
14
tests/requests/valid/028.py
Normal file
@ -0,0 +1,14 @@
|
||||
from gunicorn.config import Config
|
||||
|
||||
cfg = Config()
|
||||
cfg.set("strip_header_spaces", True)
|
||||
|
||||
request = {
|
||||
"method": "GET",
|
||||
"uri": uri("/stuff/here?foo=bar"),
|
||||
"version": (1, 1),
|
||||
"headers": [
|
||||
("CONTENT-LENGTH", "3"),
|
||||
],
|
||||
"body": b"xyz"
|
||||
}
|
||||
7
tests/requests/valid/029.http
Normal file
7
tests/requests/valid/029.http
Normal file
@ -0,0 +1,7 @@
|
||||
GET /stuff/here?foo=bar HTTP/1.1\r\n
|
||||
Transfer-Encoding: chunked\r\n
|
||||
Transfer-Encoding: identity\r\n
|
||||
\r\n
|
||||
5\r\n
|
||||
hello\r\n
|
||||
000\r\n
|
||||
14
tests/requests/valid/029.py
Normal file
14
tests/requests/valid/029.py
Normal file
@ -0,0 +1,14 @@
|
||||
from gunicorn.config import Config
|
||||
|
||||
cfg = Config()
|
||||
|
||||
request = {
|
||||
"method": "GET",
|
||||
"uri": uri("/stuff/here?foo=bar"),
|
||||
"version": (1, 1),
|
||||
"headers": [
|
||||
('TRANSFER-ENCODING', 'chunked'),
|
||||
('TRANSFER-ENCODING', 'identity')
|
||||
],
|
||||
"body": b"hello"
|
||||
}
|
||||
7
tests/requests/valid/030.http
Normal file
7
tests/requests/valid/030.http
Normal file
@ -0,0 +1,7 @@
|
||||
GET /stuff/here?foo=bar HTTP/1.1\r\n
|
||||
Transfer-Encoding: identity\r\n
|
||||
Transfer-Encoding: chunked\r\n
|
||||
\r\n
|
||||
5\r\n
|
||||
hello\r\n
|
||||
000\r\n
|
||||
14
tests/requests/valid/030.py
Normal file
14
tests/requests/valid/030.py
Normal file
@ -0,0 +1,14 @@
|
||||
from gunicorn.config import Config
|
||||
|
||||
cfg = Config()
|
||||
|
||||
request = {
|
||||
"method": "GET",
|
||||
"uri": uri("/stuff/here?foo=bar"),
|
||||
"version": (1, 1),
|
||||
"headers": [
|
||||
('TRANSFER-ENCODING', 'identity'),
|
||||
('TRANSFER-ENCODING', 'chunked')
|
||||
],
|
||||
"body": b"hello"
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user