+++ /dev/null
-import random
-from cStringIO import StringIO
-
-
-class Upload(object):
-
- """
- Base class for upload objects. This class should always be subclassed
- by upload classes and its constructor always be called.
-
- Upload classes are file like object/iterators that have additional
- variables length and content_type.
- """
-
- BLOCK_SIZE = 8192
-
- def __init__(self, length, content_type):
- self.length = length
- self.content_type = content_type
-
- def __iter__(self):
- return self
-
- def next(self):
- data = self.read(self.BLOCK_SIZE)
- if data == '':
- raise StopIteration
- return data
-
- @staticmethod
- def encode(s):
- if type(s) is str:
- return s
- elif type(s) is unicode:
- return s.encode('utf-8')
- else:
- return s
-
-
-class UploadRawData(Upload):
-
- """
- This upload class is simply a wrapper around StringIO
- """
-
- def __init__(self, data, content_type='application/x-www-form-urlencoded'):
- self.fstr = StringIO(data)
- Upload.__init__(self, len(data), content_type)
-
- def read(self, length=-1):
- return self.fstr.read(length)
-
-
-class UploadDict(UploadRawData):
-
- """
- This class creates an x-www-form-urlencoded representation of a dict
- and then passes it through its parent UploadRawData
- """
-
- def __init__(self, data):
- postdata = '&'.join('%s=%s' % (self.encode(i), self.encode(data[i])) for i in data)
- UploadRawData.__init__(self, postdata)
-
-
-class UploadFile(Upload):
-
- """
- This class accepts a file with information and a postdata dictionary
- and creates a multipart/form-data representation from it.
- """
- STAGE_FILEHEADER = 0
- STAGE_FILE = 1
- STAGE_POSTDATA = 2
- STAGE_FOOTER = 3
- STAGE_DONE = 4
-
- def __init__(self, filefield, filename, filelength, file, data):
- self.stage = self.STAGE_FILEHEADER
- self.boundary = self.generate_boundary()
- self.postdata = self.generate_multipart_from_dict(data)
- self.footer = '\r\n--%s--\r\n' % self.boundary
- self.fileheader = ('--%s\r\n' % self.boundary +
- 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' %
- (self.encode(filefield), self.encode(filename)) +
- 'Content-Type: application/octet-stream\r\n\r\n')
- self.file = file
- self.length_left = filelength
- self.str_data = None
-
- Upload.__init__(self, len(self.fileheader) + filelength + len(self.postdata) + len(self.footer) + 2,
- 'multipart/form-data; boundary=' + self.boundary)
-
- def read(self, length):
- if self.stage == self.STAGE_DONE:
- return ''
- elif self.stage != self.STAGE_FILE:
- if self.str_data is None:
- if self.stage == self.STAGE_FILEHEADER:
- self.str_data = StringIO(self.fileheader)
- elif self.stage == self.STAGE_POSTDATA:
- self.str_data = StringIO(self.postdata)
- elif self.stage == self.STAGE_FOOTER:
- self.str_data = StringIO(self.footer)
- data = self.str_data.read(length)
- else:
- if self.length_left:
- if length > self.length_left:
- length = self.length_left
- data = self.file.read(length)
- self.length_left -= len(data)
- else:
- self.stage += 1
- return '\r\n'
-
- if data == '':
- self.stage += 1
- self.str_data = None
- return self.read(length)
- return data
-
- @staticmethod
- def generate_boundary():
- return '----%s----' % ''.join((random.choice(
- 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
- for i in xrange(32)))
-
- def generate_multipart_from_dict(self, data):
- postdata = []
- for i in data:
- postdata.append('--' + self.boundary)
- postdata.append('Content-Disposition: form-data; name="%s"' % self.encode(i))
- postdata.append('')
- postdata.append(self.encode(data[i]))
- return '\r\n'.join(postdata)