XZise has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/174129

Change subject: [FIX] Upload: Convert unicode to ASCII
......................................................................

[FIX] Upload: Convert unicode to ASCII

If using MIME the header must be ASCII, but when the file name is using
non-ASCII letters those will be directly added and the server can't
interpret them. The server returns with a rather confusing message:

  missingparam: One of the parameters filekey, file, url, statuskey is
  required

This patch is encoding the parameters which aren't compatible with ASCII
with the site's encoding and then using urllib(.parse).quote to convert
them into ASCII strings.

Change-Id: Ifb0eb96051c6f4f29676ef2d5a7d4658302ddf5c
---
M pywikibot/data/api.py
M tests/dry_api_tests.py
2 files changed, 20 insertions(+), 10 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/pywikibot/core 
refs/changes/29/174129/1

diff --git a/pywikibot/data/api.py b/pywikibot/data/api.py
index 8aa97b4..a5a52df 100644
--- a/pywikibot/data/api.py
+++ b/pywikibot/data/api.py
@@ -39,7 +39,7 @@
     # unless the fix is not backported to py3.x versions that should
     # instead support PWB.
     basestring = (str, )
-    from urllib.parse import urlencode, unquote
+    from urllib.parse import urlencode, quote, unquote
     unicode = str
 
     from io import BytesIO
@@ -75,7 +75,7 @@
 
     MIMEMultipart = CTEBinaryMIMEMultipart
 else:
-    from urllib import urlencode, unquote
+    from urllib import urlencode, quote, unquote
     from email.mime.multipart import MIMEMultipart
 
 _logger = "data.api"
@@ -803,7 +803,8 @@
         return message == ERR_MSG
 
     @staticmethod
-    def _generate_MIME_part(key, content, keytype=None, headers=None):
+    def _generate_MIME_part(encoding, key, content, keytype=None,
+                            headers=None):
         if not keytype:
             try:
                 content.encode("ascii")
@@ -813,7 +814,15 @@
         submsg = MIMENonMultipart(*keytype)
         content_headers = {'name': key}
         if headers:
-            content_headers.update(headers)
+            for header_key, header_value in headers.items():
+                try:
+                    header_value.encode('ascii')
+                except UnicodeError:
+                    header_value = header_value.encode(encoding)
+                except AttributeError:
+                    pass  # header_value is already a bytes object
+                header_value = quote(header_value)
+                content_headers[header_key] = header_value
         submsg.add_header("Content-disposition", "form-data",
                           **content_headers)
 
@@ -824,7 +833,7 @@
         return submsg
 
     @staticmethod
-    def _build_mime_request(params, mime_params):
+    def _build_mime_request(params, mime_params, encoding):
         """Construct a MIME multipart form post.
 
         @param params: HTTP request params
@@ -837,10 +846,10 @@
         # construct a MIME message containing all API key/values
         container = MIMEMultipart(_subtype='form-data')
         for key, value in params.items():
-            submsg = Request._generate_MIME_part(key, value)
+            submsg = Request._generate_MIME_part(encoding, key, value)
             container.attach(submsg)
         for key, value in mime_params.items():
-            submsg = Request._generate_MIME_part(key, *value)
+            submsg = Request._generate_MIME_part(encoding, key, *value)
             container.attach(submsg)
 
         # strip the headers to get the HTTP message body
@@ -919,7 +928,8 @@
             try:
                 if self.mime:
                     (headers, body) = Request._build_mime_request(
-                        self._encoded_items(), self.mime_params)
+                        self._encoded_items(), self.mime_params,
+                        self.site.encoding())
                     use_get = False  # MIME requests require HTTP POST
                 else:
                     headers = {'Content-Type': 
'application/x-www-form-urlencoded'}
diff --git a/tests/dry_api_tests.py b/tests/dry_api_tests.py
index 3b3afe4..a63fd3f 100644
--- a/tests/dry_api_tests.py
+++ b/tests/dry_api_tests.py
@@ -192,7 +192,7 @@
         with open(local_filename, 'rb') as f:
             file_content = f.read()
         submsg = Request._generate_MIME_part(
-            'file', file_content, ('image', 'png'),
+            'utf8', 'file', file_content, ('image', 'png'),
             {'filename': local_filename})
         self.assertEqual(file_content, submsg.get_payload(decode=True))
 
@@ -203,7 +203,7 @@
         body = Request._build_mime_request({}, {
             'file': (file_content, ('image', 'png'),
                      {'filename': local_filename})
-        })[1]
+        }, 'utf8')[1]
         self.assertNotEqual(body.find(file_content), -1)
 
 

-- 
To view, visit https://gerrit.wikimedia.org/r/174129
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifb0eb96051c6f4f29676ef2d5a7d4658302ddf5c
Gerrit-PatchSet: 1
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: XZise <commodorefabia...@gmx.de>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to