Retry rate limits on chunk uploading
diff --git a/googleapiclient/http.py b/googleapiclient/http.py
index d22313f..1e168c1 100644
--- a/googleapiclient/http.py
+++ b/googleapiclient/http.py
@@ -639,7 +639,7 @@
     """Get the next chunk of the download.
 
     Args:
-      num_retries: Integer, number of times to retry 500's with randomized
+      num_retries: Integer, number of times to retry with randomized
             exponential backoff. If all retries fail, the raised HttpError
             represents the last request. If zero (default), we attempt the
             request only once.
@@ -782,7 +782,7 @@
     Args:
       http: httplib2.Http, an http object to be used in place of the
             one the HttpRequest request object was constructed with.
-      num_retries: Integer, number of times to retry 500's with randomized
+      num_retries: Integer, number of times to retry with randomized
             exponential backoff. If all retries fail, the raised HttpError
             represents the last request. If zero (default), we attempt the
             request only once.
@@ -870,7 +870,7 @@
     Args:
       http: httplib2.Http, an http object to be used in place of the
             one the HttpRequest request object was constructed with.
-      num_retries: Integer, number of times to retry 500's with randomized
+      num_retries: Integer, number of times to retry with randomized
             exponential backoff. If all retries fail, the raised HttpError
             represents the last request. If zero (default), we attempt the
             request only once.
@@ -965,7 +965,7 @@
       except:
         self._in_error_state = True
         raise
-      if resp.status < 500:
+      if not _should_retry_response(resp.status, content):
         break
 
     return self._process_response(resp, content)
diff --git a/tests/test_http.py b/tests/test_http.py
index 1cca7c6..865d847 100644
--- a/tests/test_http.py
+++ b/tests/test_http.py
@@ -341,16 +341,16 @@
     upload = MediaIoBaseUpload(
         fd=fd, mimetype='image/png', chunksize=500, resumable=True)
 
-    # Simulate 5XXs for both the request that creates the resumable upload and
-    # the upload itself.
+    # Simulate errors for both the request that creates the resumable upload
+    # and the upload itself.
     http = HttpMockSequence([
       ({'status': '500'}, ''),
       ({'status': '500'}, ''),
       ({'status': '503'}, ''),
       ({'status': '200', 'location': 'location'}, ''),
-      ({'status': '500'}, ''),
-      ({'status': '500'}, ''),
-      ({'status': '503'}, ''),
+      ({'status': '403'}, USER_RATE_LIMIT_EXCEEDED_RESPONSE),
+      ({'status': '403'}, RATE_LIMIT_EXCEEDED_RESPONSE),
+      ({'status': '429'}, ''),
       ({'status': '200'}, '{}'),
     ])
 
@@ -372,6 +372,34 @@
     request.execute(num_retries=3)
     self.assertEqual([20, 40, 80, 20, 40, 80], sleeptimes)
 
+  def test_media_io_base_next_chunk_no_retry_403_not_configured(self):
+    fd = BytesIO(b"i am png")
+    upload = MediaIoBaseUpload(
+        fd=fd, mimetype='image/png', chunksize=500, resumable=True)
+
+    http = HttpMockSequence([
+        ({'status': '403'}, NOT_CONFIGURED_RESPONSE),
+        ({'status': '200'}, '{}')
+        ])
+
+    model = JsonModel()
+    uri = u'https://www.googleapis.com/someapi/v1/upload/?foo=bar'
+    method = u'POST'
+    request = HttpRequest(
+        http,
+        model.response,
+        uri,
+        method=method,
+        headers={},
+        resumable=upload)
+
+    request._rand = lambda: 1.0
+    request._sleep =  mock.MagicMock()
+
+    with self.assertRaises(HttpError):
+      request.execute(num_retries=3)
+    request._sleep.assert_not_called()
+
 
 class TestMediaIoBaseDownload(unittest.TestCase):