Fix the final boundary in resumable multipart media uploads.

Reviewed in http://codereview.appspot.com/5450107/.
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 @@
     # 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 @@
 
 
 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_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 @@
 
     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 @@
     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 @@
   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",