Forcing path_url to be of type str in Python2

This is important when posting files/binary data in Python2.
Since urlsplit will produce unicode parts, the path_url will also be unicode, and thus the sent body will be converted to unicode during concatenation by urllib, producing a UnicodeDecodeError when sending binary data.
Forcing the path_url to be a native string in Python2 resolves this.

No test cases yet.


Additionally, in lines 392 and 396, the `str` primitive is used to convert the _content_ of the 'Content-Length' header to unicode (in Python2). This does not seem to matter for concatenation, though, it just looks interesting when you inspect your headers and get

```
'Content-Length': u'2246'
```


> Additionally, in lines 392 and 396, (...)

Good catch. Issue #1113 is related. There's also `self.headers['Content-Length'] = '0'` which is wrong as in Python 3 this will be unicode string too.


@shezi would you like to make the changes you and @piotr-dobrogost mentioned and push to the same branch? This sounds like a good pull IMO.


I have added the requested changes, but I'm not sure I understand you, @piotr-dogrobost. Using `builtin_str` will still be of type `str` in Python 3, so will be a unicode object. Do you think we should convert to `bytes` here (causing `str` in Python 2 and `bytes` in Python 3)?


@shezi
You raise a valid point. If we use `builtin_str` then we could left the `0` string literal as is, indeed. As to using `bytes` in Python 3 I believe we should set a boundary after which all headers are bytes - see my comment at https://github.com/kennethreitz/requests/pull/1116#issuecomment-12621940 However this hasn't been decided, yet.


@piotr-dobrogost That's what I had thought. However, I turned the string literal into a conversion to mark it for future edits: if at one point the decision is made to convert to `bytes` here, it should be more clear that all three calls must be converted.

(sorry for using the wrong name above!)


We need to be very careful about changing these things. 

What's broken about the current implementation?


This actually codes around a peculiarity in `requests-oauthlib`, where the URL is converted to unicode. I'll write a patch for that as well, so you can decide if that one sounds better.

The full test case is this:

```
# python 2.7.3
import requests # 1.1.0
from requests_oauthlib import OAuth1 # >= 0.3.4
files = {'file': 'byte string with lots of non-ascii-characters in it: ' + ''.join(chr(x) for x in xrange(256))}
oauth = OAuth1('key')
r = requests.put('http://example.com/', auth=oauth, files=files)
```

Gives me this:

```
Traceback (most recent call last):
  File "try.py", line 8, in <module>
    r = requests.put('http://example.com/', auth=oauth, files=files)
  File "/Users/spielmann/prog/tmp/requests/env/lib/python2.7/site-packages/requests/api.py", line 98, in put
    return request('put', url, data=data, **kwargs)
  File "/Users/spielmann/prog/tmp/requests/env/lib/python2.7/site-packages/requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "/Users/spielmann/prog/tmp/requests/env/lib/python2.7/site-packages/requests/sessions.py", line 279, in request
    resp = self.send(prep, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies)
  File "/Users/spielmann/prog/tmp/requests/env/lib/python2.7/site-packages/requests/sessions.py", line 374, in send
    r = adapter.send(request, **kwargs)
  File "/Users/spielmann/prog/tmp/requests/env/lib/python2.7/site-packages/requests/adapters.py", line 174, in send
    timeout=timeout
  File "/Users/spielmann/prog/tmp/requests/env/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 422, in urlopen
    body=body, headers=headers)
  File "/Users/spielmann/prog/tmp/requests/env/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 274, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 955, in request
    self._send_request(method, url, body, headers)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 989, in _send_request
    self.endheaders(body)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 951, in endheaders
    self._send_output(message_body)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 809, in _send_output
    msg += message_body
UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 321: ordinal not in range(128)
```

I've tracked the reason to this back to the `urlsplit` that produces a unicode URL, even though IMHO URLs should not be unicode.


> thus the sent body will be converted to unicode during concatenation by urllib, producing a UnicodeDecodeError when sending binary data

@shezi
How come is path concatenated with the body? Can you point us to the exact place where it happens?


The path is concatenated with the body because a HTTP request contains the path in its data. At some stage your request has to end up looking like:

POST /index.html
Headers
Body

or similar.


I know but there are headers there between the path and a body :) That's why I'm asking.


You can see that here:

```
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 809, in _send_output
msg += message_body
```

That's the last line of the error stack from above. As @Lukasa pointed out, in the end the whole request has to be serialized as a string. It doesn't matter that there are headers in between, because if you do `unicode + str` the result will be `unicode`. So as long as there is at least one `unicode` element before the message body, the message body will have to be converted to `unicode` too. Basically, a single `unicode` element in URL, fragment, query string, headers or body "infects" all other elements.

In any case, the specific problem I had can be solved in a client library, so that's what I did and submitted a pull request there.


@shezi
Thanks for explanation and sorry I didn't notice this myself in the stacktrace.
What about Python 3?


@piotr-dobrogost No worries, it took me some time, too, to figure it out. =) I haven't tried it in Python3.