Better content-type detection and unicode fix
authorIb Lundgren <ib.lundgren@gmail.com>
Tue, 15 May 2012 15:20:01 +0000 (17:20 +0200)
committerIb Lundgren <ib.lundgren@gmail.com>
Tue, 15 May 2012 15:20:01 +0000 (17:20 +0200)
requests/auth.py

index a20c545cac39ef5d7e85e561d713b89ca172c39a..c9a1a02f4296396cd08ed81c8d2c4ad2d0439bdc 100644 (file)
@@ -60,14 +60,51 @@ class OAuth1(AuthBase):
             signature_type, rsa_key, verifier)
 
     def __call__(self, r):
+        """Add OAuth parameters to the request.
+
+        Parameters may be included from the body if the content-type is
+        urlencoded, if no content type is set an educated guess is made.
+        """
         contenttype = r.headers.get('Content-Type', None)
-        decoded_body = extract_params(r.data)
+        # extract_params will not give params unless the body is a properly
+        # formatted string, a dictionary or a list of 2-tuples.
+        decoded_body = extract_params(r.data)     
         if contenttype == None and decoded_body != None:
-            r.headers['Content-Type'] = 'application/x-www-form-urlencoded'
-
-        r.url, r.headers, r.data = self.client.sign(
-            unicode(r.url), unicode(r.method), r.data, r.headers)
-        return r
+            # extract_params can only check the present r.data and does not know
+            # of r.files, thus an extra check is performed. We know that 
+            # if files are present the request will not have 
+            # Content-type: x-www-form-urlencoded. We guess it will have
+            # a mimetype of multipart/form-encoded and if this is not the case
+            # we assume the correct header will be set later.
+            if r.files:
+                # Omit body data in the signing and since it will always
+                # be empty (cant add paras to body if multipart) and we wish
+                # to preserve body. 
+                r.headers['Content-Type'] = 'multipart/form-encoded'
+                r.url, r.headers, _ = self.client.sign(
+                    unicode(r.url), unicode(r.method), None, r.headers)
+            else:
+                # Normal signing
+                r.headers['Content-Type'] = 'application/x-www-form-urlencoded'
+                r.url, r.headers, r.data = self.client.sign(
+                    unicode(r.url), unicode(r.method), r.data, r.headers)
+
+            # Having the authorization header, key or value, in unicode will
+            # result in UnicodeDecodeErrors when the request is concatenated
+            # by httplib. This can easily be seen when attaching files.
+            # Note that simply encoding the value is not enough since Python
+            # saves the type of first key set. Thus we remove and re-add.
+            # >>> d = {u'a':u'foo'}
+            # >>> d['a'] = 'foo'
+            # >>> d
+            # { u'a' : 'foo' }
+            if u'Authorization' in r.headers:
+                auth_header = r.headers[u'Authorization'].encode('utf-8')
+                del r.headers[u'Authorization']
+                r.headers['Authorization'] = auth_header
+                print r.headers
+
+            return r
 
 
 class HTTPBasicAuth(AuthBase):