diff --git a/requests/auth.py b/requests/auth.py index a20c545c..c9a1a02f 100644 --- a/requests/auth.py +++ b/requests/auth.py @@ -60,14 +60,51 @@ class OAuth1(AuthBase): signature_type, rsa_key, verifier) def __call__(self, r): - contenttype = r.headers.get('Content-Type', None) - decoded_body = extract_params(r.data) - if contenttype == None and decoded_body != None: - r.headers['Content-Type'] = 'application/x-www-form-urlencoded' + """Add OAuth parameters to the request. - r.url, r.headers, r.data = self.client.sign( - unicode(r.url), unicode(r.method), r.data, r.headers) - return r + 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) + # 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: + # 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):