Special Character in Proxy Authentication

I have problem with special characters in proxy authentication:(  @ in password field)

proxies = {
  "http": "http://username:pass@example.com@proxy.example.com:3128/"
}

```

```

  File "/usr/lib/python2.6/site-packages/requests/sessions.py", line 347, in get
    return self.request('GET', url, *_kwargs)
  File "/usr/lib/python2.6/site-packages/requests/sessions.py", line 335, in request
    resp = self.send(prep, *_send_kwargs)
  File "/usr/lib/python2.6/site-packages/requests/sessions.py", line 438, in send
    r = adapter.send(request, **kwargs)
  File "/usr/lib/python2.6/site-packages/requests/adapters.py", line 327, in send
    raise ConnectionError(e)

```
```


Looking at the code it doesn't seem to me that there's a problem here. Can you get Wireshark/tcpdump trace for this?


Oh, Sorry. complete Error:

  File "test.py", line 14, in <module>
    main()
  File "test.py", line 12, in main
    r = session.get(URL, proxies=proxies)
  File "/usr/lib/python2.6/site-packages/requests/sessions.py", line 347, in get
    return self.request('GET', url, *_kwargs)
  File "/usr/lib/python2.6/site-packages/requests/sessions.py", line 335, in request
    resp = self.send(prep, *_send_kwargs)
  File "/usr/lib/python2.6/site-packages/requests/sessions.py", line 438, in send
    r = adapter.send(request, **kwargs)
  File "/usr/lib/python2.6/site-packages/requests/adapters.py", line 327, in send
    raise ConnectionError(e)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='example.com@proxy.example.com', port=3128): Max retries exceeded with url: http://www.curlmyip.com/ (Caused by <class 'socket.gaierror'>: [Errno -2] Name or service not known)

My Code:

```
import requests
import sys

URL = "http://www.curlmyip.com"

proxies = {
  "http": "http://username:pass@example.com@proxy.example.com:3128/"
}

def main():
    session = requests.session()
    r = session.get(URL, proxies=proxies)
if __name__ == '__main__':
    main()
```

Complete Error in python2.7:

  File "test.py", line 14, in <module>
    main()
  File "test.py", line 12, in main
    r = session.get(URL, proxies=proxies)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 369, in get
    return self.request('GET', url, *_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 357, in request
    resp = self.send(prep, *_send_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 460, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 319, in send
    timeout=timeout
  File "/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/connectionpool.py", line 583, in urlopen
    'Socket error: %s.' % e)
requests.packages.urllib3.exceptions.ProxyError: Cannot connect to proxy. Socket error: [Errno 2] No such file or directory.

I think there is a problem in detecting host name:


Ah, yes, ok. The problem is that we pass the full URL to `proxy_from_url`. This ends up calling `urllib3.util.parse_url` which is a bit stupid when it comes to splitting the path.

@shazow Do you want to make `proxy_from_url` better, or do you want Requests to try to sanitise the URL it sends to you?


That's totally a urllib3 bug. Fixed in https://github.com/shazow/urllib3/commit/b76248c95d34aa6ffc6a2cb4fb20d4da98ad2697, thanks for catching it!


> This ends up calling `urllib3.util.parse_url` which is a bit stupid when it comes to splitting the path.

Perhaps falsely, but I'm quite proud of urllib3's url parsing. :P It's much less hacky than urlparse (no surprise runtime parse exceptions when you access properties), and actually well-documented, easy to follow (super linear, not fragmented), and predictable performance. Ugh, just looking at urlparse's source again is making my blood pressure rise. :P

Anyways, I hope to make to make `urllib3.util.parse_url` fully spec compliant, if it's not already. Possibly make it into its own lib. If there are any other problems, I'm eager to fix them! :)


Sounds good! If I get time I'll see if I can improve it. 


Are you sure plain `@` is allowed in the password field?

[RFC 1738 Section 3.1](https://tools.ietf.org/html/rfc1738#section-3.1) (Former URL RFC):

```
The user name (and password), if present, are followed by a
commercial at-sign "@". Within the user and password field, any ":",
"@", or "/" must be encoded.
```

[RFC 3986 Appendix A](https://tools.ietf.org/html/rfc3986#appendix-A) (Current URL RFC):
`userinfo` is username and password combined.

```
userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
# [..]
unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
reserved      = gen-delims / sub-delims
gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
              / "*" / "+" / "," / ";" / "="
```


everything in ":" syntax should be urlencoded. Normal requests auth flow does this automatically.


@t-8ch It's very possible that it's not allowed unencoded, I didn't check, I just checked if urlparse would split it.


Scumbag urlparse, ruining other libraries from the grave. :P 

@t-8ch Worth removing what I just added? Seems harmless. (/me imagines urlparse authors saying this a decade ago.) 


@shazow Doesn't seem to hurt.

Using `str.rsplit` would be easier on the eyes though :smiley:

``` py
# Last '@' denotes end of auth part
auth, url = url.rsplit('@', 1)
```


@t-8ch Ugh I literally spent 5 minutes yesterday looking for that method, and gave up. Thank you. :) My venture into golangland has ruined my pyfu. Fixed in https://github.com/shazow/urllib3/commit/9552344989bfd8c06214692e612aac9a9fc83abc


Sweet, so we just need to bring in a new urllib3. =)


:+1:


New urllib3 brought in, fixed in 2.1.0.