resolved RESOLVED PASS · 18 tool calls · 92 s · psf/requests
Trim excess leading path separators A URL with excess leading / (path-separator)s would cause urllib3 to attempt to reparse the request-uri as a full URI with a host and port. This bypasses that logic in ConnectionPool.urlopen by replacing these leading /s with just a single /. Closes #6643
| # | Tool | Arguments | Result |
|---|---|---|---|
| 1 | run_command | {
"command": "grep -rn \"urlopen\" src/requests | head -20"
} | {"status": "ok", "stdout": "src/requests/adapters.py:485: resp = conn.urlopen(\n", "exit_code": 0}full{"status": "ok", "stdout": "src/requests/adapters.py:485: resp = conn.urlopen(\n", "exit_code": 0} |
| 2 | read_file | {
"filepath": "src/requests/adapters.py",
"start_line": 450,
"end_line": 500
} | {"status": "ok", "filepath": "src/requests/adapters.py", "content": " \"\"\"\n\n try:\n conn = self.get_connection(request.url, proxies)\n except LocationValueEfull{"status": "ok", "filepath": "src/requests/adapters.py", "content": " \"\"\"\n\n try:\n conn = self.get_connection(request.url, proxies)\n except LocationValueError as e:\n raise InvalidURL(e, request=request)\n\n self.cert_verify(conn, request.url, verify, cert)\n url = self.request_url(request, proxies)\n self.add_headers(\n request,\n stream=stream,\n timeout=timeout,\n verify=verify,\n cert=cert,\n proxies=proxies,\n )\n\n chunked = not (request.body is None or \"Content-Length\" in request.headers)\n\n if isinstance(timeout, tuple):\n try:\n connect, read = timeout\n timeout = TimeoutSauce(connect=connect, read=read)\n except ValueError:\n raise ValueError(\n f\"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, \"\n f\"or a single float to set both timeouts to the same value.\"\n )\n elif isinstance(timeout, TimeoutSauce):\n pass\n else:\n timeout = TimeoutSauce(connect=timeout, read=timeout)\n\n try:\n resp = conn.urlopen(\n method=request.method,\n url=url,\n body=request.body,\n headers=request.headers,\n redirect=False,\n assert_same_host=False,\n preload_content=False,\n decode_content=False,\n retries=self.max_retries,\n timeout=timeout,\n chunked=chunked,\n )\n\n except (ProtocolError, OSError) as err:\n raise ConnectionError(err, request=request)\n", "start_line": 450, "end_line": 500, "total_lines": 537, "is_truncated": false} |
| 3 | read_file | {
"end_line": 460,
"filepath": "src/requests/adapters.py",
"start_line": 440
} | {"status": "ok", "filepath": "src/requests/adapters.py", "content": " :param timeout: (optional) How long to wait for the server to send\n data before giving upfull{"status": "ok", "filepath": "src/requests/adapters.py", "content": " :param timeout: (optional) How long to wait for the server to send\n data before giving up, as a float, or a :ref:`(connect timeout,\n read timeout) <timeouts>` tuple.\n :type timeout: float or tuple or urllib3 Timeout object\n :param verify: (optional) Either a boolean, in which case it controls whether\n we verify the server's TLS certificate, or a string, in which case it\n must be a path to a CA bundle to use\n :param cert: (optional) Any user-provided SSL certificate to be trusted.\n :param proxies: (optional) The proxies dictionary to apply to the request.\n :rtype: requests.Response\n \"\"\"\n\n try:\n conn = self.get_connection(request.url, proxies)\n except LocationValueError as e:\n raise InvalidURL(e, request=request)\n\n self.cert_verify(conn, request.url, verify, cert)\n url = self.request_url(request, proxies)\n self.add_headers(\n request,\n", "start_line": 440, "end_line": 460, "total_lines": 537, "is_truncated": false} |
| 4 | read_file | {
"end_line": 440,
"filepath": "src/requests/adapters.py",
"start_line": 300
} | {"status": "ok", "filepath": "src/requests/adapters.py", "content": " :param resp: The urllib3 response object.\n :rtype: requests.Response\n \"\"\"\n response full{"status": "ok", "filepath": "src/requests/adapters.py", "content": " :param resp: The urllib3 response object.\n :rtype: requests.Response\n \"\"\"\n response = Response()\n\n # Fallback to None if there's no status_code, for whatever reason.\n response.status_code = getattr(resp, \"status\", None)\n\n # Make headers case-insensitive.\n response.headers = CaseInsensitiveDict(getattr(resp, \"headers\", {}))\n\n # Set encoding.\n response.encoding = get_encoding_from_headers(response.headers)\n response.raw = resp\n response.reason = response.raw.reason\n\n if isinstance(req.url, bytes):\n response.url = req.url.decode(\"utf-8\")\n else:\n response.url = req.url\n\n # Add new cookies from the server.\n extract_cookies_to_jar(response.cookies, req, resp)\n\n # Give the Response some context.\n response.request = req\n response.connection = self\n\n return response\n\n def get_connection(self, url, proxies=None):\n \"\"\"Returns a urllib3 connection for the given URL. This should not be\n called from user code, and is only exposed for use when subclassing the\n :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.\n\n :param url: The URL to connect to.\n :param proxies: (optional) A Requests-style dictionary of proxies used on this request.\n :rtype: urllib3.ConnectionPool\n \"\"\"\n proxy = select_proxy(url, proxies)\n\n if proxy:\n proxy = prepend_scheme_if_needed(proxy, \"http\")\n proxy_url = parse_url(proxy)\n if not proxy_url.host:\n raise InvalidProxyURL(\n \"Please check proxy URL. It is malformed \"\n \"and could be missing the host.\"\n )\n proxy_manager = self.proxy_manager_for(proxy)\n conn = proxy_manager.connec |
| 5 | read_file | {
"end_line": 380,
"filepath": "src/requests/adapters.py",
"start_line": 360
} | {"status": "ok", "filepath": "src/requests/adapters.py", "content": " \"\"\"Disposes of any internal state.\n\n Currently, this closes the PoolManager and any afull{"status": "ok", "filepath": "src/requests/adapters.py", "content": " \"\"\"Disposes of any internal state.\n\n Currently, this closes the PoolManager and any active ProxyManager,\n which closes any pooled connections.\n \"\"\"\n self.poolmanager.clear()\n for proxy in self.proxy_manager.values():\n proxy.clear()\n\n def request_url(self, request, proxies):\n \"\"\"Obtain the url to use when making the final request.\n\n If the message is being sent through a HTTP proxy, the full URL has to\n be used. Otherwise, we should only use the path portion of the URL.\n\n This should not be called from user code, and is only exposed for use\n when subclassing the\n :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.\n\n :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.\n :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs.\n", "start_line": 360, "end_line": 380, "total_lines": 537, "is_truncated": false} |
| 6 | read_file | {
"end_line": 400,
"filepath": "src/requests/adapters.py",
"start_line": 381
} | {"status": "ok", "filepath": "src/requests/adapters.py", "content": " :rtype: str\n \"\"\"\n proxy = select_proxy(request.url, proxies)\n scheme = urlparse(requfull{"status": "ok", "filepath": "src/requests/adapters.py", "content": " :rtype: str\n \"\"\"\n proxy = select_proxy(request.url, proxies)\n scheme = urlparse(request.url).scheme\n\n is_proxied_http_request = proxy and scheme != \"https\"\n using_socks_proxy = False\n if proxy:\n proxy_scheme = urlparse(proxy).scheme.lower()\n using_socks_proxy = proxy_scheme.startswith(\"socks\")\n\n url = request.path_url\n if is_proxied_http_request and not using_socks_proxy:\n url = urldefragauth(request.url)\n\n return url\n\n def add_headers(self, request, **kwargs):\n \"\"\"Add any headers needed by the connection. As of v2.0 this does\n nothing by default, but is left for overriding by users that subclass\n", "start_line": 381, "end_line": 400, "total_lines": 537, "is_truncated": false} |
| 7 | run_command | {
"command": "grep -rn \"path_url\" src/requests | head -20"
} | {"status": "ok", "stdout": "src/requests/models.py:86: def path_url(self):\nsrc/requests/adapters.py:392: url = request.path_url\n", "exit_code": 0}full{"status": "ok", "stdout": "src/requests/models.py:86: def path_url(self):\nsrc/requests/adapters.py:392: url = request.path_url\n", "exit_code": 0} |
| 8 | read_file | {
"end_line": 100,
"filepath": "src/requests/models.py",
"start_line": 70
} | {"status": "ok", "filepath": "src/requests/models.py", "content": "#: processable redirect.\nREDIRECT_STATI = (\n codes.moved, # 301\n codes.found, # 302\n codefull{"status": "ok", "filepath": "src/requests/models.py", "content": "#: processable redirect.\nREDIRECT_STATI = (\n codes.moved, # 301\n codes.found, # 302\n codes.other, # 303\n codes.temporary_redirect, # 307\n codes.permanent_redirect, # 308\n)\n\nDEFAULT_REDIRECT_LIMIT = 30\nCONTENT_CHUNK_SIZE = 10 * 1024\nITER_CHUNK_SIZE = 512\n\n\nclass RequestEncodingMixin:\n @property\n def path_url(self):\n \"\"\"Build the path URL to use.\"\"\"\n\n url = []\n\n p = urlsplit(self.url)\n\n path = p.path\n if not path:\n path = \"/\"\n\n url.append(path)\n\n query = p.query\n if query:\n", "start_line": 70, "end_line": 100, "total_lines": 1032, "is_truncated": false} |
| 9 | read_file | {
"end_line": 120,
"filepath": "src/requests/models.py",
"start_line": 101
} | {"status": "ok", "filepath": "src/requests/models.py", "content": " url.append(\"?\")\n url.append(query)\n\n return \"\".join(url)\n\n @staticmethod\n def _encfull{"status": "ok", "filepath": "src/requests/models.py", "content": " url.append(\"?\")\n url.append(query)\n\n return \"\".join(url)\n\n @staticmethod\n def _encode_params(data):\n \"\"\"Encode parameters in a piece of data.\n\n Will successfully encode parameters when passed as a dict or a list of\n 2-tuples. Order is retained if data is a list of 2-tuples but arbitrary\n if parameters are supplied as a dict.\n \"\"\"\n\n if isinstance(data, (str, bytes)):\n return data\n elif hasattr(data, \"read\"):\n return data\n elif hasattr(data, \"__iter__\"):\n result = []\n", "start_line": 101, "end_line": 120, "total_lines": 1032, "is_truncated": false} |
| 10 | run_command | {
"command": "cat > /tmp/repro.py <<'EOF'\nfrom requests.models import RequestEncodingMixin\nfrom urllib.parse import urlsplit\n\nclass MockRequest(RequestEncodingMixin):\n def __init__(self, url):\n self.url = url\n\ndef test_path_url():\n # Normal path\n req1 = MockRequest(\"http://example.com/foo\")\n print(f\"req1: {req1.path_url}\")\n assert req1.path_url == \"/foo\"\n\n # Path with multiple leading slashes\n req2 = MockRequest(\"http://example.com///foo\")\n print(f\"req2: {req2.path_url}\")\n # Current behavior likely returns \"///foo\"\n # Expected behavior based on issue description: \"/foo\"\n \n # Path with just multiple slashes\n req3 = MockRequest(\"http://example.com////\")\n print(f\"req3: {req3.path_url}\")\n # Expected behavior: \"/\"\n\nif __name__ == \"__main__\":\n test_path_url()\nEOF\npython3 /tmp/repro.py"
} | {"status": "ok", "stdout": "req1: /foo\nreq2: ///foo\nreq3: ////\n", "exit_code": 0}full{"status": "ok", "stdout": "req1: /foo\nreq2: ///foo\nreq3: ////\n", "exit_code": 0} |
| 11 | edit_file | {
"filepath": "src/requests/models.py",
"new_string": " path = p.path\n if not path:\n path = \\\"/\\\"\n elif path.startswith(\\\"//\\\"):\n path = \\\"/\\\" + path.lstrip(\\\"/\\\")\n\n url.append(path)",
"old_string": " path = p.path\n if not path:\n path = \\\"/\\\"\n\n url.append(path)"
} | {"status": "error", "error_type": "FileEditError", "error_message": "old_string not found in file (tried exact, flexible and regex matching)"}full{"status": "error", "error_type": "FileEditError", "error_message": "old_string not found in file (tried exact, flexible and regex matching)"} |
| 12 | read_file | {
"end_line": 100,
"filepath": "src/requests/models.py",
"start_line": 80
} | {"status": "ok", "filepath": "src/requests/models.py", "content": "CONTENT_CHUNK_SIZE = 10 * 1024\nITER_CHUNK_SIZE = 512\n\n\nclass RequestEncodingMixin:\n @profull{"status": "ok", "filepath": "src/requests/models.py", "content": "CONTENT_CHUNK_SIZE = 10 * 1024\nITER_CHUNK_SIZE = 512\n\n\nclass RequestEncodingMixin:\n @property\n def path_url(self):\n \"\"\"Build the path URL to use.\"\"\"\n\n url = []\n\n p = urlsplit(self.url)\n\n path = p.path\n if not path:\n path = \"/\"\n\n url.append(path)\n\n query = p.query\n if query:\n", "start_line": 80, "end_line": 100, "total_lines": 1032, "is_truncated": false} |
| 13 | edit_file | {
"filepath": "src/requests/models.py",
"new_string": " path = p.path\n if not path:\n path = \\\"/\\\"\n elif path.startswith(\\\"//\\\"):\n path = \\\"/\\\" + path.lstrip(\\\"/\\\")\n\n url.append(path)",
"old_string": " path = p.path\n if not path:\n path = \\\"/\\\"\n\n url.append(path)"
} | {"status": "error", "error_type": "FileEditError", "error_message": "old_string not found in file (tried exact, flexible and regex matching)"}full{"status": "error", "error_type": "FileEditError", "error_message": "old_string not found in file (tried exact, flexible and regex matching)"} |
| 14 | read_file | {
"end_line": 95,
"filepath": "src/requests/models.py",
"start_line": 85
} | {"status": "ok", "filepath": "src/requests/models.py", "content": " @property\n def path_url(self):\n \"\"\"Build the path URL to use.\"\"\"\n\n url = []\n\n p full{"status": "ok", "filepath": "src/requests/models.py", "content": " @property\n def path_url(self):\n \"\"\"Build the path URL to use.\"\"\"\n\n url = []\n\n p = urlsplit(self.url)\n\n path = p.path\n if not path:\n path = \"/\"\n", "start_line": 85, "end_line": 95, "total_lines": 1032, "is_truncated": false} |
| 15 | edit_file | {
"filepath": "src/requests/models.py",
"new_string": " path = p.path\n if not path:\n path = \\\"/\\\"\n elif path.startswith(\\\"//\\\"):\n path = \\\"/\\\" + path.lstrip(\\\"/\\\")\n\n url.append(path)",
"old_string": " path = p.path\n if not path:\n path = \\\"/\\\"\n\n url.append(path)"
} | {"status": "error", "error_type": "FileEditError", "error_message": "old_string not found in file (tried exact, flexible and regex matching)"}full{"status": "error", "error_type": "FileEditError", "error_message": "old_string not found in file (tried exact, flexible and regex matching)"} |
| 16 | read_file | {
"end_line": 105,
"filepath": "src/requests/models.py",
"start_line": 85
} | {"status": "ok", "filepath": "src/requests/models.py", "content": " @property\n def path_url(self):\n \"\"\"Build the path URL to use.\"\"\"\n\n url = []\n\n p full{"status": "ok", "filepath": "src/requests/models.py", "content": " @property\n def path_url(self):\n \"\"\"Build the path URL to use.\"\"\"\n\n url = []\n\n p = urlsplit(self.url)\n\n path = p.path\n if not path:\n path = \"/\"\n\n url.append(path)\n\n query = p.query\n if query:\n url.append(\"?\")\n url.append(query)\n\n return \"\".join(url)\n\n", "start_line": 85, "end_line": 105, "total_lines": 1032, "is_truncated": false} |
| 17 | edit_file | {
"filepath": "src/requests/models.py",
"new_string": " path = p.path\n if not path:\n path = \"/\"\n elif path.startswith(\"//\"):\n path = \"/\" + path.lstrip(\"/\")\n\n url.append(path)",
"old_string": " path = p.path\n if not path:\n path = \"/\"\n\n url.append(path)"
} | {"status": "ok", "filepath": "src/requests/models.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/src/requests/models.py\n+++ b/src/requests/models.pfull{"status": "ok", "filepath": "src/requests/models.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/src/requests/models.py\n+++ b/src/requests/models.py\n@@ -93,6 +93,8 @@\n path = p.path\n if not path:\n path = \"/\"\n+ elif path.startswith(\"//\"):\n+ path = \"/\" + path.lstrip(\"/\")\n \n url.append(path)\n \n", "is_truncated": false} |
| 18 | run_command | {
"command": "python3 /tmp/repro.py"
} | {"status": "ok", "stdout": "req1: /foo\nreq2: /foo\nreq3: /\n", "exit_code": 0}full{"status": "ok", "stdout": "req1: /foo\nreq2: /foo\nreq3: /\n", "exit_code": 0} |
| 19 | submit_patch | [] | {"status": "ok", "patch_size": 376, "files_changed": 1}full{"status": "ok", "patch_size": 376, "files_changed": 1} |
diff --git a/src/requests/models.py b/src/requests/models.py
index 44556394..618b4b30 100644
--- a/src/requests/models.py
+++ b/src/requests/models.py
@@ -93,6 +93,8 @@ class RequestEncodingMixin:
path = p.path
if not path:
path = "/"
+ elif path.startswith("//"):
+ path = "/" + path.lstrip("/")
url.append(path)
. [100%]
=============================== warnings summary ===============================
../../../../../../kaggle/tmp/envs/requests/lib/python3.13/site-packages/_pytest/config/__init__.py:1464
/kaggle/tmp/envs/requests/lib/python3.13/site-packages/_pytest/config/__init__.py:1464: PytestConfigWarning: Unknown config option: timeout
self._warn_or_fail_if_strict(f"Unknown config option: {key}\n")
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
1 passed, 1 warning in 0.01s
[2026-09-24 11:07:32,259] WARNING in core: flasgger is not installed; serving the static landing page at / and skipping the Swagger UI and /spec.json.