diff --git a/apiclient/http.py b/apiclient/http.py index 333461e..8ea5c73 100644 --- a/apiclient/http.py +++ b/apiclient/http.py @@ -251,7 +251,9 @@ class HttpRequest(object): # Pull the multipart boundary out of the content-type header. major, minor, params = mimeparse.parse_mime_type( headers.get('content-type', 'application/json')) - self.multipart_boundary = params.get('boundary', '').strip('"') + + # Terminating multipart boundary get a trailing '--' appended. + self.multipart_boundary = params.get('boundary', '').strip('"') + '--' # If this was a multipart resumable, the size of the non-media part. self.multipart_size = 0 diff --git a/oauth2client/client.py b/oauth2client/client.py index 3440c23..07df411 100644 --- a/oauth2client/client.py +++ b/oauth2client/client.py @@ -754,6 +754,8 @@ if HAS_OPENSSL: def _urlsafe_b64decode(b64string): + # Guard against unicode strings, which base64 can't handle. + b64string = b64string.encode('ascii') padded = b64string + '=' * (4 - len(b64string) % 4) return base64.urlsafe_b64decode(padded) diff --git a/oauth2client/crypt.py b/oauth2client/crypt.py index 523c921..323345a 100644 --- a/oauth2client/crypt.py +++ b/oauth2client/crypt.py @@ -137,6 +137,8 @@ def _urlsafe_b64encode(raw_bytes): def _urlsafe_b64decode(b64string): + # Guard against unicode strings, which base64 can't handle. + b64string = b64string.encode('ascii') padded = b64string + '=' * (4 - len(b64string) % 4) return base64.urlsafe_b64decode(padded) diff --git a/tests/test_discovery.py b/tests/test_discovery.py index 2995633..9e47e8f 100644 --- a/tests/test_discovery.py +++ b/tests/test_discovery.py @@ -389,7 +389,7 @@ class Discovery(unittest.TestCase): self.assertEquals('image/png', request.resumable.mimetype()) - self.assertEquals(request.multipart_boundary, '') + self.assertEquals(request.multipart_boundary, '--') self.assertEquals(request.body, None) self.assertEquals(request.resumable_uri, None) diff --git a/tests/test_http.py b/tests/test_http.py index f502bac..b7054dc 100644 --- a/tests/test_http.py +++ b/tests/test_http.py @@ -109,7 +109,7 @@ class TestUserAgent(unittest.TestCase): self.assertEquals(new_req.body, '{}') self.assertEquals(new_req.http, http) self.assertEquals(new_req.resumable.to_json(), media_upload.to_json()) - self.assertEquals(new_req.multipart_boundary, '---flubber') + self.assertEquals(new_req.multipart_boundary, '---flubber--') EXPECTED = """POST /someapi/v1/collection/?foo=bar HTTP/1.1 Content-Type: application/json diff --git a/tests/test_oauth2client.py b/tests/test_oauth2client.py index 9acc9cf..8286eed 100644 --- a/tests/test_oauth2client.py +++ b/tests/test_oauth2client.py @@ -280,7 +280,8 @@ class OAuth2WebServerFlowTest(unittest.TestCase): def test_exchange_id_token_fail(self): body = {'foo': 'bar'} payload = base64.urlsafe_b64encode(simplejson.dumps(body)).strip('=') - jwt = 'stuff.' + payload + '.signature' + jwt = (base64.urlsafe_b64encode('stuff')+ '.' + payload + '.' + + base64.urlsafe_b64encode('signature')) http = HttpMockSequence([ ({'status': '200'}, """{ "access_token":"SlAV32hkKG",