My favorites | Sign in
Project Logo
                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import httplib

import mimetools, mimetypes

ENCODE_TEMPLATE= """--%(boundary)s
Content-Disposition: form-data; name="%(name)s"

%(value)s
""".replace('\n','\r\n')

ENCODE_TEMPLATE_FILE = """--%(boundary)s
Content-Disposition: form-data; name="%(name)s"; filename="%(filename)s"
Content-Type: %(contenttype)s

%(value)s
""".replace('\n','\r\n')

# TODO: is replace('\n', '\r\n') going to cause problems on other platforms?
# Are we better off building a list of strings and doing '\r\n'.join(body)?

def get_content_type(filename):
return mimetypes.guess_type(filename)[0] or 'application/octet-stream'

def encode_multipart_formdata(fields):
"""
Given a dictionary field parameters, returns the HTTP request body and the
content_type (which includes the boundary string), to be used with an
httplib-like call.

Normal key/value items are treated as regular parameters, but key/tuple
items are treated as files, where a value tuple is a (filename, data) tuple.

For example:

fields = {
'foo': 'bar',
'foofile': ('foofile.txt', 'contents of foofile'),
}

body, content_type = encode_multipart_formdata(fields)
"""

BOUNDARY = mimetools.choose_boundary()

body = ""

# NOTE: Every non-binary possibly-unicode variable must be casted to str()
# because if a unicode value pollutes the `body` string, then all of body
# will become unicode. Appending a binary file string to a unicode string
# will cast the binary data to unicode, which will raise an encoding
# exception. Long story short, we want to stick to plain strings.
# This is not ideal, but if anyone has a better method, I'd love to hear it.

for key, value in fields.iteritems():
if isinstance(value, tuple):
filename, value = value
body += ENCODE_TEMPLATE_FILE % {
'boundary': BOUNDARY,
'name': str(key),
'value': str(value),
'filename': str(filename),
'contenttype': str(get_content_type(filename))
}
else:
body += ENCODE_TEMPLATE % {
'boundary': BOUNDARY,
'name': str(key),
'value': str(value)
}

body += '--%s--\n\r' % BOUNDARY
content_type = 'multipart/form-data; boundary=%s' % BOUNDARY

return body, content_type
Show details Hide details

Change log

r18 by shazow on Nov 17, 2008   Diff
Added exception raise for socket timeout,
TimeoutError. Fixed yet another bug in
filepost
Go to: 
Project members, sign in to write a code review

Older revisions

r16 by shazow on Nov 17, 2008   Diff
Fixed missing new line from http
request
r14 by shazow on Nov 17, 2008   Diff
Some bugs left over from an older
version... still not passing unit
tests though
r2 by shazow on Nov 11, 2008   Diff
Should be working, not tested very
well yet.
All revisions of this file

File info

Size: 2476 bytes, 74 lines
Hosted by Google Code