Skip to content

Commit b83e8bb

Browse files
committed
Merge remote branch 'zooko/pending' into pending
2 parents 77cb11f + b2fca15 commit b83e8bb

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

oauth2/__init__.py

+17-4
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,22 @@ def build_xoauth_string(url, consumer, token=None):
8888
return "%s %s %s" % ("GET", url, ','.join(params))
8989

9090

91+
def to_unicode(s):
92+
""" Convert to unicode, raise exception with instructive error
93+
message if s is not unicode or ascii. """
94+
if not isinstance(s, unicode):
95+
if not isinstance(s, str):
96+
raise TypeError('You are required to pass either unicode or string here, not: %r (%s)' % (type(s), s))
97+
try:
98+
s = s.decode('ascii')
99+
except UnicodeDecodeError, le:
100+
raise TypeError('You are required to pass either a unicode object or an ascii string here. You passed a Python string object which contained non-ascii: %r. The UnicodeDecodeError that resulted from attempting to interpret it as ascii was: %s' % (s, le,))
101+
return s
102+
91103
def escape(s):
92104
"""Escape a URL including any /."""
93-
return urllib.quote(s, safe='~')
94-
105+
s = to_unicode(s)
106+
return urllib.quote(s.encode('utf-8'), safe='~')
95107

96108
def generate_timestamp():
97109
"""Get seconds since epoch (UTC)."""
@@ -276,8 +288,9 @@ class Request(dict):
276288
version = OAUTH_VERSION
277289

278290
def __init__(self, method=HTTP_METHOD, url=None, parameters=None):
291+
if url is not None:
292+
self.url = to_unicode(url)
279293
self.method = method
280-
self.url = url
281294
if parameters is not None:
282295
self.update(parameters)
283296

@@ -717,7 +730,7 @@ class SignatureMethod_HMAC_SHA1(SignatureMethod):
717730
name = 'HMAC-SHA1'
718731

719732
def signing_base(self, request, consumer, token):
720-
if request.normalized_url is None:
733+
if not hasattr(request, 'normalized_url') or request.normalized_url is None:
721734
raise ValueError("Base URL for request is not set.")
722735

723736
sig = (

tests/test_oauth.py

+20-2
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ def test_setter(self):
253253
url = "http://example.com"
254254
method = "GET"
255255
req = oauth.Request(method)
256-
self.assertTrue(req.url is None)
257-
self.assertTrue(req.normalized_url is None)
256+
self.assertTrue(not hasattr(req, 'url') or req.url is None)
257+
self.assertTrue(not hasattr(req, 'normalized_url') or req.normalized_url is None)
258258

259259
def test_deleter(self):
260260
url = "http://example.com"
@@ -558,6 +558,24 @@ def test_get_normalized_string_escapes_spaces_properly(self):
558558
expected = urllib.urlencode(sorted(params.items())).replace('+', '%20')
559559
self.assertEqual(expected, res)
560560

561+
def test_request_nonascii_bytes(self):
562+
# If someone has a sequence of bytes which is not ascii, we'll
563+
# raise an exception as early as possible.
564+
url = "http://sp.example.com/\x92"
565+
566+
params = {
567+
'oauth_version': "1.0",
568+
'oauth_nonce': "4572616e48616d6d65724c61686176",
569+
'oauth_timestamp': "137131200"
570+
}
571+
572+
tok = oauth.Token(key="tok-test-key", secret="tok-test-secret")
573+
con = oauth.Consumer(key="con-test-key", secret="con-test-secret")
574+
575+
params['oauth_token'] = tok.key
576+
params['oauth_consumer_key'] = con.key
577+
self.assertRaises(TypeError, oauth.Request, method="GET", url=url, parameters=params)
578+
561579
def test_sign_request(self):
562580
url = "http://sp.example.com/"
563581

0 commit comments

Comments
 (0)