/usr/share/parley/plugins/mwclient/upload.py is in parley-data 4:15.12.3-0ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | 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)
|