Created
February 10, 2012 22:01
-
-
Save paulosman/1793321 to your computer and use it in GitHub Desktop.
Problem posting multipart form data to Rails app.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Rails 3.0.3 Controller. Just return the parameters as a string. | |
class HomeController < ApplicationController | |
protect_from_forgery :except => :upload | |
def upload | |
render :text => params.to_s | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import requests | |
files = dict(avatar=open('avatar.jpg', 'rb')) | |
data = dict(name='A picture') | |
r = requests.post('http://localhost:4567/upload', data=data, files=files) | |
print r.text |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This one monkey patches encode_multipart_formdata to omit the Content-Type header from non-binary parts. | |
# See below for output from test.py and this one. | |
import requests | |
import codecs | |
try: | |
from mimetools import choose_boundary | |
except ImportError: | |
from requests.packages.urllib3.packages.mimetools_choose_boundary import choose_boundary | |
from io import BytesIO | |
from requests.packages.urllib3.packages import six | |
from requests.packages.urllib3.packages.six import b | |
from requests.packages.urllib3.filepost import get_content_type | |
writer = codecs.lookup('utf-8')[3] | |
def encode_multipart_formdata(fields, boundary=None): | |
"""Stop rails from doing stupid things by omitting the Content-Type header on non-binary parts.""" | |
body = BytesIO() | |
if boundary is None: | |
boundary = choose_boundary() | |
for fieldname, value in six.iteritems(fields): | |
body.write(b('--%s\r\n' % (boundary))) | |
if isinstance(value, tuple): | |
filename, data = value | |
writer(body).write('Content-Disposition: form-data; name="%s"; ' | |
'filename="%s"\r\n' % (fieldname, filename)) | |
body.write(b('Content-Type: %s\r\n\r\n' % | |
(get_content_type(filename)))) | |
else: | |
data = value | |
writer(body).write( | |
'Content-Disposition: form-data; name="%s"\r\n\r\n' % ( | |
fieldname)) | |
if isinstance(data, int): | |
data = str(data) # Backwards compatibility | |
if isinstance(data, six.text_type): | |
writer(body).write(data) | |
else: | |
body.write(data) | |
body.write(b'\r\n') | |
body.write(b('--%s--\r\n' % (boundary))) | |
content_type = b('multipart/form-data; boundary=%s' % boundary) | |
return body.getvalue(), content_type | |
requests.models.encode_multipart_formdata = encode_multipart_formdata | |
files = dict(avatar=open('avatar.jpg', 'rb')) | |
data = dict(name='A picture') | |
r = requests.post('http://localhost:4567/upload', data=data, files=files) | |
print r.text |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# running it with a recent version of requests / urllib3. Notice that Rails is parsing the non-binary part incorrectly | |
$ python test.py | |
{"name"=>#<ActionDispatch::Http::UploadedFile:0x007ff6b30d2670 @original_filename=nil, @content_type="text/plain", @headers="Content-Disposition: form-data; name=\"name\"\r\nContent-Type: text/plain\r\n", @tempfile=#<File:/var/folders/nb/httvyh1d7616jz77m4k1lxp40000gn/T/RackMultipart20120210-20637-6xlzo8>>, "avatar"=>#<ActionDispatch::Http::UploadedFile:0x007ff6b30d2530 @original_filename="avatar.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"avatar\"; filename=\"avatar.jpg\"\r\nContent-Type: image/jpeg\r\n", @tempfile=#<File:/var/folders/nb/httvyh1d7616jz77m4k1lxp40000gn/T/RackMultipart20120210-20637-4vziee>>, "action"=>"upload", "controller"=>"home"} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# running another version with urllib3.filepost.encode_multipart_formdata monkey patched to *not* set a Content-Type header for non-binary parts of the form data (basically just removed https://github.com/shazow/urllib3/blob/master/urllib3/filepost.py#L58 and added the terminal '\r\n' to L57). | |
$ python test2.py | |
{"name"=>"A picture", "avatar"=>#<ActionDispatch::Http::UploadedFile:0x007ff6b54884c0 @original_filename="avatar.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"avatar\"; filename=\"avatar.jpg\"\r\nContent-Type: image/jpeg\r\n", @tempfile=#<File:/var/folders/nb/httvyh1d7616jz77m4k1lxp40000gn/T/RackMultipart20120210-20637-rh1v7e>>, "action"=>"upload", "controller"=>"home"} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment