Repository: psf/requests

Issue:
Leading slash in uri followed by column fails
Leading slash in uri followed by column fails.

## Expected Result

```python
requests.get('http://127.0.0.1:10000//v:h')
<Response [200]>
```

## Actual Result

```python
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/urllib3/util/url.py", line 425, in parse_url
    host, port = _HOST_PORT_RE.match(host_port).groups()  # type: ignore[union-attr]
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'groups'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.11/site-packages/requests/api.py", line 73, in get
    return request("get", url, params=params, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/api.py", line 59, in request
    return session.request(method=method, url=url, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/sessions.py", line 589, in request
    resp = self.send(prep, **send_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/sessions.py", line 703, in send
    r = adapter.send(request, **kwargs)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/adapters.py", line 486, in send
    resp = conn.urlopen(
           ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/urllib3/connectionpool.py", line 711, in urlopen
    parsed_url = parse_url(url)
                 ^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/urllib3/util/url.py", line 451, in parse_url
    raise LocationParseError(source_url) from e
urllib3.exceptions.LocationParseError: Failed to parse: //v:h
```

## Reproduction Steps

```python
import requests
requests.get('http://127.0.0.1:10000//v:h')

```

## System Information

    $ python -m requests.help

```json
{
  "chardet": {
    "version": null
  },
  "charset_normalizer": {
    "version": "3.3.2"
  },
  "cryptography": {
    "version": ""
  },
  "idna": {
    "version": "3.6"
  },
  "implementation": {
    "name": "CPython",
    "version": "3.11.8"
  },
  "platform": {
    "release": "5.10.209-198.812.amzn2.x86_64",
    "system": "Linux"
  },
  "pyOpenSSL": {
    "openssl_version": "",
    "version": null
  },
  "requests": {
    "version": "2.31.0"
  },
  "system_ssl": {
    "version": "300000b0"
  },
  "urllib3": {
    "version": "2.2.1"
  },
  "using_charset_normalizer": true,
  "using_pyopenssl": false
}
```

<!-- This command is only available on Requests v2.16.4 and greater. Otherwise,
please provide some basic information about your system (Python version,
operating system, &c). -->



Discussion:
I can reproduce this with

```py
import urllib3

urllib3.PoolManager().urlopen(method="GET", url="http://127.0.0.1:10000//v:h")
```

cc @sethmlarson @pquentin 
Ah I see the problem, both the PoolManager and requests are sending the path (`//v:h`) to `urlopen`: https://github.com/urllib3/urllib3/blob/d4ffa29ee1862b3d1afe584efb57d489a7659dac/src/urllib3/poolmanager.py#L444 https://github.com/psf/requests/blob/7a13c041dbef42f9f3feb14110f02626f6892e9a/src/requests/adapters.py#L487 and `urlopen` is now probably taking on too many responsibilities: https://github.com/urllib3/urllib3/blob/d4ffa29ee1862b3d1afe584efb57d489a7659dac/src/urllib3/connectionpool.py#L711-L712
Also, yes, I verified that RFC3986 allows `:` as a non-percent-encoded character in the path: https://datatracker.ietf.org/doc/html/rfc3986.html#section-3.3
And I think the problem is the `//` in the path which is tripping up the parsing as `//` is the delimiter for what should be host and port after that. So in reality nothing is wrong here. I wonder if we need some kind of pre-parsing of the URL before sending it to `urlopen` to  trim this down. Something like `re.sub('^/+', '/')` would likely fix this in both Requests and urllib3.



Patch:
diff --git a/src/requests/adapters.py b/src/requests/adapters.py
index eb240fa954..fc5606bdcb 100644
--- a/src/requests/adapters.py
+++ b/src/requests/adapters.py
@@ -390,6 +390,9 @@ def request_url(self, request, proxies):
             using_socks_proxy = proxy_scheme.startswith("socks")
 
         url = request.path_url
+        if url.startswith("//"):  # Don't confuse urllib3
+            url = f"/{url.lstrip('/')}"
+
         if is_proxied_http_request and not using_socks_proxy:
             url = urldefragauth(request.url)
 


Test patch:
diff --git a/tests/test_adapters.py b/tests/test_adapters.py
new file mode 100644
index 0000000000..6c55d5a130
--- /dev/null
+++ b/tests/test_adapters.py
@@ -0,0 +1,8 @@
+import requests.adapters
+
+
+def test_request_url_trims_leading_path_separators():
+    """See also https://github.com/psf/requests/issues/6643."""
+    a = requests.adapters.HTTPAdapter()
+    p = requests.Request(method="GET", url="http://127.0.0.1:10000//v:h").prepare()
+    assert "/v:h" == a.request_url(p, {})