john john - 10 months ago 142
Python Question

Python SimpleHTTPServer to receive files

I am using SimpleHTTPServer's do_POST method to receive file. The script is working fine if I upload the png file using curl but whenever I use python request library to upload file, File uploads but become corrupt. Here is the SimpleHTTPServer code

#!/usr/bin/env python
# Simple HTTP Server With Upload.

import os
import posixpath
import BaseHTTPServer
import urllib
import cgi
import shutil
import mimetypes
import re
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO

class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
# Simple HTTP request handler with POST commands.

def do_POST(self):
"""Serve a POST request."""
r, info = self.deal_post_data()
print r, info, "by: ", self.client_address
f = StringIO()

if r:

length = f.tell()
self.send_header("Content-type", "text/html")
self.send_header("Content-Length", str(length))
if f:
self.copyfile(f, self.wfile)

def deal_post_data(self):
print self.headers
boundary = self.headers.plisttext.split("=")[1]
print 'Boundary %s' %boundary
remainbytes = int(self.headers['content-length'])
print "Remain Bytes %s" %remainbytes
line = self.rfile.readline()
remainbytes -= len(line)
if not boundary in line:
return (False, "Content NOT begin with boundary")
line = self.rfile.readline()
remainbytes -= len(line)
fn = re.findall(r'Content-Disposition.*name="file"; filename="(.*)"', line)
if not fn:
return (False, "Can't find out file name...")
path = self.translate_path(self.path)
fn = os.path.join(path, fn[0])
line = self.rfile.readline()
remainbytes -= len(line)
line = self.rfile.readline()
remainbytes -= len(line)
out = open(fn, 'wb')
except IOError:
return (False, "Can't create file to write, do you have permission to write?")

preline = self.rfile.readline()
remainbytes -= len(preline)
while remainbytes > 0:
line = self.rfile.readline()
remainbytes -= len(line)
if boundary in line:
preline = preline[0:-1]
if preline.endswith('\r'):
preline = preline[0:-1]
return (True, "File '%s' upload success!" % fn)
preline = line
return (False, "Unexpect Ends of data.")

def translate_path(self, path):
"""Translate a /-separated PATH to the local filename syntax.

Components that mean special things to the local file system
(e.g. drive or directory names) are ignored. (XXX They should
probably be diagnosed.)

# abandon query parameters
path = path.split('?',1)[0]
path = path.split('#',1)[0]
path = posixpath.normpath(urllib.unquote(path))
words = path.split('/')
words = filter(None, words)
path = os.getcwd()
for word in words:
drive, word = os.path.splitdrive(word)
head, word = os.path.split(word)
if word in (os.curdir, os.pardir): continue
path = os.path.join(path, word)
return path

def copyfile(self, source, outputfile):
"""Copy all data between two file objects.

The SOURCE argument is a file object open for reading
(or anything with a read() method) and the DESTINATION
argument is a file object open for writing (or
anything with a write() method).

The only reason for overriding this would be to change
the block size or perhaps to replace newlines by CRLF
-- note however that this the default server uses this
to copy binary data as well.

shutil.copyfileobj(source, outputfile)

def test(HandlerClass = SimpleHTTPRequestHandler,
ServerClass = BaseHTTPServer.HTTPServer):
BaseHTTPServer.test(HandlerClass, ServerClass)

if __name__ == '__main__':

client side code to upload a file is here


import requests

files = {'file': open('test.png', 'rb')}
r ='', files=files)
print r.request.headers

File was uploaded successfully but become corrupted.

python request header

SimpleHTTPServer response

Using curl [ curl -F 'file=@test.png' -v ], file uploaded and opened successfully.

Is there any issue in python-request code?

Answer Source

curl and request have a slightly different header, curl has an additional empty line while requests doesn't.

Replace preline = self.rfile.readline() with the following block

if line.strip():
    preline = line
    preline = self.rfile.readline()