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):
64
64
def maybe_read_from_IDLE_client (buf ):
65
65
lines = buf .maybe_extract_lines ()
66
66
if lines is None :
67
+ if buf .is_next_line_obviously_invalid_request_line ():
68
+ raise LocalProtocolError ("illegal request line" )
67
69
return None
68
70
if not lines :
69
71
raise LocalProtocolError ("no request line received" )
@@ -81,6 +83,8 @@ def maybe_read_from_IDLE_client(buf):
81
83
def maybe_read_from_SEND_RESPONSE_server (buf ):
82
84
lines = buf .maybe_extract_lines ()
83
85
if lines is None :
86
+ if buf .is_next_line_obviously_invalid_request_line ():
87
+ raise LocalProtocolError ("illegal request line" )
84
88
return None
85
89
if not lines :
86
90
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):
133
133
del lines [- 2 :]
134
134
135
135
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():
969
969
c .next_event ()
970
970
971
971
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
+
972
1004
# This used to give different headers for HEAD and GET.
973
1005
# The correct way to handle HEAD is to put whatever headers we *would* have
974
1006
# 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