1--- MultipartPostHandler.py 2017-05-18 12:42:04.369440354 +0200
2+++ MultipartPostHandler.py 2017-05-30 18:27:15.085714022 +0200
3@@ -51,15 +51,15 @@
4 opener.open("http://wwww.bobsite.com/upload/", params)
5 """
6
7-import urllib.request, urllib.parse, urllib.error
8-import urllib.request, urllib.error, urllib.parse
9-import mimetools, mimetypes
10-import os, stat
11-from io import StringIO
12-
13-class Callable:
14- def __init__(self, anycallable):
15- self.__call__ = anycallable
16+import os
17+import io
18+import stat
19+import urllib.error
20+import urllib.parse
21+import urllib.request
22+from email.generator import _make_boundary
23+
24+import mimetypes
25
26 # Controls how sequences are uncoded. If true, elements may be given multiple values by
27 # assigning a sequence.
28@@ -69,13 +69,13 @@
29 handler_order = urllib.request.HTTPHandler.handler_order - 10 # needs to run first
30
31 def http_request(self, request):
32- data = request.get_data()
33+ data = request.data
34 if data is not None and type(data) != str:
35 v_files = []
36 v_vars = []
37 try:
38 for(key, value) in list(data.items()):
39- if type(value) == file:
40+ if isinstance(value, io.IOBase):
41 v_files.append((key, value))
42 else:
43 v_vars.append((key, value))
44@@ -93,35 +93,44 @@
45 print("Replacing %s with %s" % (request.get_header('content-type'), 'multipart/form-data'))
46 request.add_unredirected_header('Content-Type', contenttype)
47
48- request.add_data(data)
49+ if isinstance(data, str):
50+ request.data = data.encode()
51+
52+ else:
53+ request.data = data
54 return request
55
56- def multipart_encode(vars, files, boundary = None, buffer = None):
57+ def multipart_encode(self, vars, files, boundary = None, buffer = None):
58 if boundary is None:
59- boundary = mimetools.choose_boundary()
60+ boundary = _make_boundary()
61 if buffer is None:
62- buffer = StringIO()
63+ buffer = io.BytesIO()
64 for(key, value) in vars:
65- buffer.write('--%s\r\n' % boundary)
66- buffer.write('Content-Disposition: form-data; name="%s"' % key)
67+ buffer.write(b'--%s\r\n' % boundary.encode())
68+ buffer.write(b'Content-Disposition: form-data; name="%s"' % key.encode())
69 if value is None:
70- value = ""
71+ value = b""
72+ else:
73+ value = value.encode()
74 # if type(value) is not str, we need str(value) to not error with cannot concatenate 'str'
75 # and 'dict' or 'tuple' or somethingelse objects
76- buffer.write('\r\n\r\n' + str(value) + '\r\n')
77+ buffer.write(b'\r\n\r\n' + value + b'\r\n')
78 for(key, fd) in files:
79 file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
80 filename = fd.name.split('/')[-1]
81 contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
82- buffer.write('--%s\r\n' % boundary)
83- buffer.write('Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename))
84- buffer.write('Content-Type: %s\r\n' % contenttype)
85- buffer.write('Content-Length: %s\r\n' % file_size)
86+ buffer.write(b'--%s\r\n' % boundary.encode())
87+ buffer.write(b'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key.encode(), filename.encode()))
88+ buffer.write(b'Content-Type: %s\r\n' % contenttype.encode())
89+ # do not send Content-Length header as it makes UCM corrupt the file
90+ # buffer.write(b'Content-Length: %s\r\n' % str(file_size).encode())
91 fd.seek(0)
92- buffer.write('\r\n' + fd.read() + '\r\n')
93- buffer.write('--' + boundary + '--\r\n')
94+ content = fd.read()
95+ if isinstance(content, str):
96+ content = content.encode()
97+ buffer.write(b'\r\n' + content + b'\r\n')
98+ buffer.write(b'--' + boundary.encode() + b'--\r\n')
99 buffer = buffer.getvalue()
100 return boundary, buffer
101- multipart_encode = Callable(multipart_encode)
102
103 https_request = http_request