Broken parsing of authenticated URI for Proxy

Opening issue (appears to be related to issue https://github.com/kennethreitz/requests/issues/1856) as this issue is still breaking for me.

When I run the following it breaks:

``` py
>>> import requests
>>> url = "http://sitereview.bluecoat.com/rest/categorization"
>>> data = {'url':'google.com'}
>>> proxy = { "http": "http://test.username:testp@ssword#@proxy.url.com:8080"}
>>> header = {'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:33.0) Gecko/20100101 Firefox/33.0'}
>>> request = requests.post(url, proxies=proxy, headers=header, data=data)
```

The error it is giving is as follows:

```
requests.exceptions.ConnectionError: HTTPConnectionPool(host='ssword', port=80): Max retries exceeded with url: http://sitereview.bluecoat.com/rest/categorization (Caused by ProxyError('Cannot connect to proxy.', gaierror(-2, 'Name or service not known')))
```

If I change the password over to testp@ssword instead of `testp@ssword#` it works just fine.

It may be that I am rather new but I would appreciate any help or insight you can provide.


What version of requests are you using?


I am using version 2.5.1. I also tried it with the latest version in the pip repo's which I believe is version 2.7 Same issue on both versions.


So it's definitely the case that requests doesn't handle this well. In the short term, try encoding the fragment to `%23`. Longer term, we should work out how we can make this work correctly.


Alright so I was able to get this clean by adding the following to the password before it is put inside the proxies variable that gets passed to request:

clean_pass = urllib.quote_plus(password)

I found that quote_plus worked more effectively than urlencode as urlencode was throwing errors on the password with the error of "TypeError: not a valid non-string sequence or mapping object". 

Just know that quote_plus worked for me. It may give you folks a better possible solution (who knows).


So, I don't think there is a "good way" to handle this. Looking at the [User Info portion of RFC 3986](https://tools.ietf.org/html/rfc3986#section-3.2.1), you'll see that the user info is composed of:

```
   unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
   pct-encoded   = "%" HEXDIG HEXDIG
   sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
                 / "*" / "+" / "," / ";" / "="
```

And `:`. That means `@` and `#` are not valid characters unless they're percent-encoded, i.e., the user calls `urllib.quote_plus` on that information. The fact that we happen to parse the URI in such a way that is forgiving towards users with `@`s in their userinfo is nice but technically incorrect based on the specification. I don't think we have an obligation to further violate the spec to allow for `#` in user-info as well.


@sigmavirus24 

While I don't disagree with you it may be a good idea to update the documentation to state that the quote_plus (or equivalent) is required if passwords are going to contain those characters. This may be the simplest way to resolve this issue. That way future users don't get confused.


Hmm, documenting our way our of this is really sad. I feel like we should be able to do something better than that, although I cannot for the life of me work out what that should be at the moment.


As far as a possible solution on your end the only thing I was able to come up was to break apart the string before it is parsed in the get_auth_from_url(url) function of the utils.py and encode the password function somewhere before the parsed = urlparse(url) was being called. It appears from my testing that that is where it is being broken.

Just tossing out any options I can think of (even if they are hacky).