Send file names in multipart/form-data requests.

Most of the values in the `files` dictionary are open file objects, which means they have a `name` attribute. Requests, though, sends the key name instead of file name. This can cause some unexpected shit if the server decides to use that information.

Note: I'm not sure whether this change will work on Python <= 2.6.


Thanks, I've been tossing that idea back and forth for a while. :cake:

---

Anyone else have any input?


In general I am quite unhappy with the multipart uploading in requests currently, especially because you cannot use it to upload humongous files since they will be read into memory. I would recommend considering rewriting part of the multipart handling and to also make it possible to override the encoding explicitly.

Regarding the filename issue however, do not use `.name` directly since this causes problems with streams that come from memory.

Better:

``` python
def guess_filename(obj):
    name = getattr(obj, 'name', None)
    if name and name[0] != '<' and name[-1] != '>':
        return name
```


@mitsuhiko hmm, are you sure that in-memory streams have a `name` attribute?

``` python
>>> from io import StringIO
>>> StringIO().name
Traceback (most recent call last):
  ...
AttributeError: '_io.StringIO' object has no attribute 'name'
```

According to http://docs.python.org/library/io.html, the `name` attribute is not a part of the API.

UPD: By the way, `<stdin>`, `<memory>`, etc. are valid filenames in ext*, hfs+, and many other file systems; you can't throw them out so easy.


A socket file descriptor has the name "<fdopen>", same goes with other things opened by file descriptor. stdin/stdout etc have '<stdin>'. Yes, StringIO does not have that attribute but many other streams have like temporary file objects opened with tempfile and many custom user streams have a different meaning assigned to `name`. In general I strongly recommend against using this attribute since it's undocumented and often used for different things.

I made this mistake in Werkzeug and am currently in the process of recovering from it. I now have an explicit API for this kind of thing.


Yeah, you're right. I don't see any way to ensure valid filenames other than to use requests with Python 3 (which has a well-defined I/O layer) then. That's quite sad.

UPD: hey, wait. If someone rewrites the `encode_multipart_formdata()` function so that it does not load the whole stream contents into the memory, how are you supposed to pass anything other than files and BytesIOs to it? Don't forget, you **must know the exact request body length** in order to send it; sockets and most user-defined streams, as well as stdin (stdout is not readable, by the way :-), don't have a defined content length. Thus the filename problem is eliminated by restricting input streams to files (which have a `name`) and BytesIOs (which don't have a `name`.) If you want to send some data from a socket, for example, you should probably first read as much data as you need and then wrap it into a BytesIO.


@mitsuhiko I have an old branch `filepost-stream` which implements a stream-whenever-possible `encode_multipart_formdata()`: http://code.google.com/p/urllib3/source/browse/urllib3/filepost.py?name=filepost-stream

It's a proof of concept and over the top in trying to cover to get the stream size in too many cases (to avoid using chunked-encoding which was rarely supported back in the day). If we get rid of the size guessing code, it should be pretty straight forward to forwardport to the latest urllib3 core.


@shazow are you sure that the situation with Transfer-Encoding: chunked got better since then? For example, I've tried to send a file to http://httpbin.org/post using chunked transfer encoding and it replied me with the 411 Length Required error. We should probably stick to specifying the Content-Length. (UPD: TE: chunked works on http://httpbin.herokuapp.com/post)

Anyway, this pull request is about sending filenames. I thought a bit more about what @mitsuhiko wrote and decided that using `getattr(v, 'name', k)` is OK in this case: even if it accidentally returns `<fdopen>` or `<stdin>` or something, sending the key name does not make much more sense (and angle brackets will get stripped by something like `werkzeug.utils.secure_filename` on the server side anyway.)


@pyos, sorry for the heroku issues. I recommend using the `httpbin.herokuapp.com`domain now. The Requests tests will be updated accordingly.