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>
|
Xie Shi <xieshi@douban.com>
|
||||||
Yue Du <ifduyue@gmail.com>
|
Yue Du <ifduyue@gmail.com>
|
||||||
zakdances <zakdances@gmail.com>
|
zakdances <zakdances@gmail.com>
|
||||||
|
Emile Fugulin <emilefugulin@hotmail.com>
|
||||||
|
|||||||
@ -2010,3 +2010,20 @@ class PasteGlobalConf(Setting):
|
|||||||
|
|
||||||
.. versionadded:: 19.7
|
.. 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:
|
if curr.find(":") < 0:
|
||||||
raise InvalidHeader(curr.strip())
|
raise InvalidHeader(curr.strip())
|
||||||
name, value = curr.split(":", 1)
|
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):
|
if HEADER_RE.search(name):
|
||||||
raise InvalidHeaderName(name)
|
raise InvalidHeaderName(name)
|
||||||
|
|
||||||
@ -128,9 +131,12 @@ class Message(object):
|
|||||||
content_length = None
|
content_length = None
|
||||||
for (name, value) in self.headers:
|
for (name, value) in self.headers:
|
||||||
if name == "CONTENT-LENGTH":
|
if name == "CONTENT-LENGTH":
|
||||||
|
if content_length is not None:
|
||||||
|
raise InvalidHeader("CONTENT-LENGTH", req=self)
|
||||||
content_length = value
|
content_length = value
|
||||||
elif name == "TRANSFER-ENCODING":
|
elif name == "TRANSFER-ENCODING":
|
||||||
chunked = value.lower() == "chunked"
|
if value.lower() == "chunked":
|
||||||
|
chunked = True
|
||||||
elif name == "SEC-WEBSOCKET-KEY1":
|
elif name == "SEC-WEBSOCKET-KEY1":
|
||||||
content_length = 8
|
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