@@ -984,20 +984,15 @@ def putrequest(self, method, url, skip_host=False,
984984 else :
985985 raise CannotSendRequest (self .__state )
986986
987- # Save the method we use, we need it later in the response phase
987+ # Save the method for use later in the response phase
988988 self ._method = method
989- if not url :
990- url = '/'
991- # Prevent CVE-2019-9740.
992- match = _contains_disallowed_url_pchar_re .search (url )
993- if match :
994- raise InvalidURL ("URL can't contain control characters. {!r} "
995- "(found at least {!r})" .format (url ,
996- match .group ()))
989+
990+ url = url or '/'
991+ self ._validate_path (url )
992+
997993 request = '%s %s %s' % (method , url , self ._http_vsn_str )
998994
999- # Non-ASCII characters should have been eliminated earlier
1000- self ._output (request .encode ('ascii' ))
995+ self ._output (self ._encode_request (request ))
1001996
1002997 if self ._http_vsn == 11 :
1003998 # Issue some standard headers for better HTTP/1.1 compliance
@@ -1075,6 +1070,21 @@ def putrequest(self, method, url, skip_host=False,
10751070 # For HTTP/1.0, the server will assume "not chunked"
10761071 pass
10771072
1073+ def _encode_request (self , request ):
1074+ # ASCII also helps prevent CVE-2019-9740.
1075+ return request .encode ('ascii' )
1076+
1077+ def _validate_path (self , url ):
1078+ """Validate a url for putrequest."""
1079+ # Prevent CVE-2019-9740.
1080+ match = _contains_disallowed_url_pchar_re .search (url )
1081+ if match :
1082+ msg = (
1083+ "URL can't contain control characters. {url!r} "
1084+ "(found at least {matched!r})"
1085+ ).format (matched = match .group (), ** locals ())
1086+ raise InvalidURL (msg )
1087+
10781088 def putheader (self , header , * values ):
10791089 """Send a request header line to the server.
10801090
0 commit comments