1

How can I POST parameters with a file object to a URL using httplib in python web services.

Am using the following scripts:

import httplib
import urllib
params = urllib.urlencode({"@str1":"string1", "@str2":"string2", "@file":"/local/path/to/file/in/client/machine", "@action":"action.php" })
headers = {"Content-type":"application/pdf , text/*" }
conn = httplib.HTTPConnection("192.168.2.17")
conn.request("POST", "/SomeName/action.php", params, headers)
response = conn.getresponse()
print response.status, response.reason
data = response.read()
data
conn.close()

And I have the following output:

200
OK
<html>.....some html code </html>

I wrote some php code for save those string and the file in DB My problem is that, Am only getting the file path as a sting but not my file. May be I have to send the file object like,

file_obj = open("filename.txt","r")
conn.request("POST", "/SomeName/action.php", file_obj, headers)

But I want to send both strings and file. Any suggestions to solve this?

EDIT I change my code as follows: When i send a pdf file, by directly using httplib, to my server the file saves as BIN file.

def document_management_service(self,str_loc_file_path,*args):
    locfile = open(str_loc_file_path,'rb').read()
    host = "some.hostname.com"
    selector = "/api/?task=create"
    fields = [('docName','INVOICE'),('docNumber','DOC/3'),('cusName','name'),('cusNumber','C124'),('category','INVOICE'),('data','TIJO MRS,SOME/DATA/CONTENT,Blahblah,2584.00,blahblah'),('action','create')]
    files = [('strfile','File.pdf',locfile)]
    response = self.post_multipart(host, selector, fields, files)
    print response
    pass

def post_multipart(self,host, selector, fields, files):
    content_type, body = self.encode_multipart_formdata(fields, files)
    h = httplib.HTTP(host)
    h.set_debuglevel(1)
    h.putrequest('POST', selector)
    h.putheader('content-type', content_type)
    h.putheader('content-length', str(len(body)))
    h.putheader('Host', host)
    h.endheaders()
    h.send(body)
    errcode, errmsg, headers= h.getreply()
    return h.file.read()

def encode_multipart_formdata(self, fields, files):
    LIMIT = '----------lImIt_of_THE_fIle_eW_$'
    CRLF = '\r\n'
    L = []
    for (key, value) in fields:
        L.append('--' + LIMIT)
        L.append('Content-Disposition: form-data; name="%s"' % key)
        L.append('')
        L.append(value)
    for (key, filename, value) in files:
        L.append('--' + LIMIT)
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
        L.append('Content-Type: %s' % self.get_content_type(filename))
        L.append('')
        L.append(value)
    L.append('--' + LIMIT + '--')
    L.append('')
    body = CRLF.join(L)
    content_type = 'multipart/form-data; boundary=%s' % LIMIT
    return content_type, body

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

I have debug the request which shows as:

[('content-length', '4191'), ('accept-ranges', 'bytes'), ('server', 'Apache/2.2.12 (Ubuntu)'), ('last-modified', 'Tue, 23 Oct 2012 04:46:36 GMT'), ('etag', 'W/"567dd-105f-4ccb2a7a9a500"'), ('date', 'Tue, 23 Oct 2012 04:46:36 GMT'), ('content-type', 'application/pdf')]
multipart/form-data; boundary=----------lImIt_of_THE_fIle_eW_$

And I didn't try requests,Coz I would like to solve this with httplib(without any external lib)

2 Answers 2

2

To post parameters and a file in a body you could use multipart/form-data content type:

#!/usr/bin/env python
import requests # $ pip install requests

file = 'file content as a file object or string'
r = requests.post('http://example.com/SomeName/action.php',
                  files={'file': ('filename.txt', file)},
                  data={'str1': 'string1', 'str2': 'string2'})
print(r.text) # response

requests.post sends to the server something like-this:

POST /SomeName/action.php HTTP/1.1
Host: example.com
Content-Length: 449
Content-Type: multipart/form-data; boundary=f27f8ef67cac403aaaf433f83742bd64
Accept-Encoding: identity, deflate, compress, gzip
Accept: */*

--f27f8ef67cac403aaaf433f83742bd64
Content-Disposition: form-data; name="str2"
Content-Type: text/plain

string2
--f27f8ef67cac403aaaf433f83742bd64
Content-Disposition: form-data; name="str1"
Content-Type: text/plain

string1
--f27f8ef67cac403aaaf433f83742bd64
Content-Disposition: form-data; name="file"; filename="filename.txt"
Content-Type: text/plain

file content as a file object or string
--f27f8ef67cac403aaaf433f83742bd64--

To reproduce it with httplib see POST form-data with Python example.

A simpler solution if your parameters do not contain much data is to pass them in the url query part and leave the body to contain only the file:

#!/usr/bin/env python
import urllib
import requests # $ pip install requests

params = {'str1': 'string1', 'str2': 'string2', 'filename': 'filename.txt'}
file = 'file content as a file object or string, etc'    
url = 'http://example.com/SomeName/action.php?' + urllib.urlencode(params)
r = requests.post(url, data=file, headers={'Content-Type': 'text/plain'})
print(r.text) # response

It corresponds to the following HTTP request:

POST /SomeName/action.php?str2=string2&str1=string1&filename=filename.txt HTTP/1.1
Host: example.com
Content-Length: 39
Content-Type: text/plain
Accept-Encoding: identity, deflate, compress, gzip
Accept: */*

file content as a file object or string

It should be easier to translate to httplib if you need it.

Sign up to request clarification or add additional context in comments.

8 Comments

# sebastian. I reproduced the code with above link (for httplib[link]stackoverflow.com/questions/680305/…). But when am sending a PDF file it reaches as a BIN file at server side.
I have used the recipe to post multipart using httplib directly [link] stackoverflow.com/questions/680305/…. But that script showed a Not Found response for my request. Then i add a line h.putheader('Host', host) just before the h.endheaders() statement, Now It works for me. But my file it saves as a BIN file at server side
@SKT: just modify get_content_type(filename) function to return whatever you like.
.. in particular application/pdf
@SKT: update your question or create a new one to include a minimal complete code example that reproduces your problem and the description of what you expect to happen, what happens instead. What happens if you use a browser as a client (with a real html form). How does the content that the browser sends differ from your client? Have you tried the requests-based client?
|
0

The following code can also solve the problem with transfering file with other meta data using httplib (with out any external libraries):

def document_management_service_success(self,str_loc_file_path,*args):
    locfile = open(str_loc_file_path,'rb').read()
    str_loc_file = locfile.split('#end_pymotw_header')
    initial_data = str_loc_file[0]
    encoded_data = ''.join("{0:08b}".format(ord(c)) for c in initial_data)
    params = urllib.urlencode({'docName':'INVOICE', 'docNumber':'RF/2', 'cusName':'Tijo john', 'cusNumber':'C124', 'category':'INVOICE', 'data':encoded_data})
    headers = {"Accept": "Text/*","Content-Disposition":"form-data" ,"Content-Type": "application/x-www-form-urlencoded, application/pdf, form-data"}
    conn = httplib.HTTPConnection("efiling.nucoreindia.com")
    conn.connect()
    conn.set_debuglevel(1)
    conn.request("POST", "/api/?task=create", params, headers)
    response = conn.getresponse()
    print "Server Response status is"+str(response.status)+"and Reason is,"+str(response.reason)
    print response.getheaders()
    print response.read()
    pass

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.