File tree Expand file tree Collapse file tree 4 files changed +54
-0
lines changed
Expand file tree Collapse file tree 4 files changed +54
-0
lines changed Original file line number Diff line number Diff line change @@ -64,6 +64,8 @@ def _decode_header_lines(lines):
6464def maybe_read_from_IDLE_client (buf ):
6565 lines = buf .maybe_extract_lines ()
6666 if lines is None :
67+ if buf .is_next_line_obviously_invalid_request_line ():
68+ raise LocalProtocolError ("illegal request line" )
6769 return None
6870 if not lines :
6971 raise LocalProtocolError ("no request line received" )
@@ -81,6 +83,8 @@ def maybe_read_from_IDLE_client(buf):
8183def maybe_read_from_SEND_RESPONSE_server (buf ):
8284 lines = buf .maybe_extract_lines ()
8385 if lines is None :
86+ if buf .is_next_line_obviously_invalid_request_line ():
87+ raise LocalProtocolError ("illegal request line" )
8488 return None
8589 if not lines :
8690 raise LocalProtocolError ("no response line received" )
Original file line number Diff line number Diff line change @@ -133,3 +133,20 @@ def maybe_extract_lines(self):
133133 del lines [- 2 :]
134134
135135 return lines
136+
137+ # In theory we should wait until `\r\n` before starting to validate
138+ # incoming data. However it's interesting to detect (very) invalid data
139+ # early given they might not even contain `\r\n` at all (hence only
140+ # timeout will get rid of them).
141+ # This is not a 100% effective detection but more of a cheap sanity check
142+ # allowing for early abort in some useful cases.
143+ # This is especially interesting when peer is messing up with HTTPS and
144+ # sent us a TLS stream where we were expecting plain HTTP given all
145+ # versions of TLS so far start handshake with a 0x16 message type code.
146+ def is_next_line_obviously_invalid_request_line (self ):
147+ try :
148+ # HTTP header line must not contain non-printable characters
149+ # and should not start with a space
150+ return self ._data [0 ] < 0x21
151+ except IndexError :
152+ return False
Original file line number Diff line number Diff line change @@ -969,6 +969,38 @@ def test_empty_response():
969969 c .next_event ()
970970
971971
972+ @pytest .mark .parametrize (
973+ "data" ,
974+ [
975+ b"\x00 " ,
976+ b"\x20 " ,
977+ b"\x16 \x03 \x01 \x00 \xa5 " , # Typical start of a TLS Client Hello
978+ ],
979+ )
980+ def test_early_detection_of_invalid_request (data ):
981+ c = Connection (SERVER )
982+ # Early detection should occur before even receiving a `\r\n`
983+ c .receive_data (data )
984+ with pytest .raises (RemoteProtocolError ):
985+ c .next_event ()
986+
987+
988+ @pytest .mark .parametrize (
989+ "data" ,
990+ [
991+ b"\x00 " ,
992+ b"\x20 " ,
993+ b"\x16 \x03 \x03 \x00 \x31 " , # Typical start of a TLS Server Hello
994+ ],
995+ )
996+ def test_early_detection_of_invalid_response (data ):
997+ c = Connection (CLIENT )
998+ # Early detection should occur before even receiving a `\r\n`
999+ c .receive_data (data )
1000+ with pytest .raises (RemoteProtocolError ):
1001+ c .next_event ()
1002+
1003+
9721004# This used to give different headers for HEAD and GET.
9731005# The correct way to handle HEAD is to put whatever headers we *would* have
9741006# put if it were a GET -- even though we know that for HEAD, those headers
Original file line number Diff line number Diff line change 1+ Add early detection of invalid http data when request line starts with binary
You can’t perform that action at this time.
0 commit comments