-
-
Notifications
You must be signed in to change notification settings - Fork 753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(http): enable httptools lenient data #2488
Conversation
…ndency- Set dangerous leniency for HTTP parsing to handle data received after connection close - Upgrade httptools dependency from >=0.5.0 to >=0.6.3 for improved functionality and security
Can you explain a bit what we are doing here? |
Use a relaxed approach to parsing messages. |
If we follow the discussion in #2238 and the RFC standard we should use lenient mode to parse the data.
|
As a record. Httptools v0.6.3 upgrades dependency llhttp from 8.1.1 to 9.2.1, due to the lenient mode used before llhttp v9.0, some messages could not be parsed and responded to in this upgrade. The following is a list of methods that support lenient parsing in llhttp, facilitate subsequent troubleshooting and development of more lenient methods as needed. |
Should we enable this flag tho? https://llhttp.org/ Maybe we should fix the test instead? |
message = 'GET / HTTP/1.1\r\nConnection: close\r\n\r\nInvalid\r\n\r\n' For enabling or not, I think it depends on whether the production environment receives such messages. If such messages are not generated except for malicious attacks, then we do not need to enable them.
Since h11 is now capable of handling such messages, if you want to modify it, keep the processing logic of h11 and httptools the same. |
How about leaving it up to the user to decide whether or not to use a lenient flag. 🤔 |
No. I don't think we should add a new flag. |
Do you have any good suggestions? import httptools
REQUEST_AFTER_CONNECTION_CLOSE = b"\r\n".join(
[
b"GET / HTTP/1.1",
b"Host: example1.org",
b"Connection: close",
b"",
b"",
b"GET / HTTP/1.1",
b"Host: example2.org",
b"",
b"",
]
)
class MyHandler:
def on_url(self, url: bytes) -> None:
print(f"Target: {url}")
def on_headers_complete(self) -> None:
http_version = parser.get_http_version()
method = parser.get_method()
print(f"HTTP version: {http_version}, method: {method}")
def on_header(self, name: bytes, value: bytes) -> None:
print(f"Header: {name.decode()}: {value.decode()}")
parser = httptools.HttpRequestParser(MyHandler())
# Adding this line works fine.
parser.set_dangerous_leniencies(lenient_data_after_close=True)
parser.feed_data(REQUEST_AFTER_CONNECTION_CLOSE)
import h11
conn = h11.Connection(h11.SERVER)
conn.receive_data(REQUEST_AFTER_CONNECTION_CLOSE)
print(conn.next_event()) Or we can turn this flag on by default, keeping h11 and httptools the same processing logic. |
f58bce0
to
0ebbc70
Compare
Sorry, I shouldn't have force-pushed. I should have just added the revert commits. I used your first commit here. |
except AttributeError: | ||
# httptools < 0.6.3 | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some people don't use uvicorn[standard]
because it install more than needed on production e.g. watchfiles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks.
Summary
#2486
Checklist