diff --git a/scapy/layers/http.py b/scapy/layers/http.py index ac3496fcb24..d4293071fe8 100644 --- a/scapy/layers/http.py +++ b/scapy/layers/http.py @@ -57,6 +57,7 @@ import subprocess from enum import Enum +from urllib.parse import urlsplit from scapy.compat import plain_str, bytes_encode @@ -897,26 +898,33 @@ def request( e.g. Method="POST" """ # Parse request url - m = re.match(r"(https?)://([^/:]+)(?:\:(\d+))?(/.*)?", url) - if not m: + try: + parsed = urlsplit(url) + transport = parsed.scheme + host = parsed.hostname + port = parsed.port + except ValueError: + raise ValueError("Bad URL !") from None + if transport not in ["http", "https"] or not host: raise ValueError("Bad URL !") - transport, host, port, path = m.groups() if transport == "https": tls = True else: tls = False - path = path or "/" - port = port and int(port) + path = parsed.path or "/" + if parsed.query: + path += "?" + parsed.query + if port is None: + port = 443 if tls else 80 # Connect (or reuse) socket self._connect_or_reuse(host, port=port, tls=tls, timeout=timeout) # Build request + host_hdr = "[%s]" % host if ":" in host else host if (tls and port != 443) or (not tls and port != 80): - host_hdr = "%s:%d" % (host, port) - else: - host_hdr = host + host_hdr = "%s:%d" % (host_hdr, port) headers.setdefault("Host", host_hdr) headers.setdefault("Path", path) diff --git a/test/scapy/layers/http.uts b/test/scapy/layers/http.uts index 1b132a5a614..9e681529f5b 100644 --- a/test/scapy/layers/http.uts +++ b/test/scapy/layers/http.uts @@ -363,6 +363,28 @@ with run_httpserver(mech=HTTP_AUTH_MECHS.NTLM, ssp=NTLMSSP(IDENTITIES={"user": M assert resp.Status_Code == b"401" += HTTP - HTTP_Client follows standard URL authority parsing +~ http-client + +from scapy.layers.http import HTTP_Client, HTTPResponse + +class URLParsingClient(HTTP_Client): + def _connect_or_reuse(self, host, port=None, tls=False, timeout=5): + self.connected = (host, port, tls) + def sr1(self, req, **kwargs): + self.sent_request = req + return HTTPResponse(Status_Code=b"200") + +client = URLParsingClient(verb=False) +resp = client.request( + "http://127.0.0.1:8081@allowed.example:8080/resource?item=1#fragment" +) + +assert resp.Status_Code == b"200" +assert client.connected == ("allowed.example", 8080, False) +assert client.sent_request.Host == b"allowed.example:8080" +assert client.sent_request.Path == b"/resource?item=1" + = HTTP - HTTP_client asks HTTP_server with NTLMSSP ~ http-client