Change GET to POST if URI is too long. Fixes issue #96.
Reviewed in http://codereview.appspot.com/6454092/.
diff --git a/apiclient/http.py b/apiclient/http.py
index 3c38bc9..753dd09 100644
--- a/apiclient/http.py
+++ b/apiclient/http.py
@@ -48,6 +48,8 @@
DEFAULT_CHUNK_SIZE = 512*1024
+MAX_URI_LENGTH = 4000
+
class MediaUploadProgress(object):
"""Status of a resumable upload."""
@@ -646,6 +648,19 @@
else:
if 'content-length' not in self.headers:
self.headers['content-length'] = str(self.body_size)
+ # If the request URI is too long then turn it into a POST request.
+ if len(self.uri) > MAX_URI_LENGTH and self.method == 'GET':
+ self.method = 'POST'
+ self.headers['x-http-method-override'] = 'GET'
+ self.headers['content-type'] = 'application/x-www-form-urlencoded'
+ parsed = urlparse.urlparse(self.uri)
+ self.uri = urlparse.urlunparse(
+ (parsed.scheme, parsed.netloc, parsed.path, parsed.params, None,
+ None)
+ )
+ self.body = parsed.query
+ self.headers['content-length'] = str(len(self.body))
+
resp, content = http.request(self.uri, self.method,
body=self.body,
headers=self.headers)
diff --git a/tests/test_http.py b/tests/test_http.py
index d067afe..9387e3a 100644
--- a/tests/test_http.py
+++ b/tests/test_http.py
@@ -25,6 +25,7 @@
import httplib2
import os
import unittest
+import urllib
import StringIO
from apiclient.discovery import build
@@ -40,6 +41,7 @@
from apiclient.http import MediaIoBaseUpload
from apiclient.http import MediaIoBaseDownload
from apiclient.http import set_user_agent
+from apiclient.http import MAX_URI_LENGTH
from apiclient.model import JsonModel
from oauth2client.client import Credentials
@@ -724,5 +726,44 @@
'"Access Not Configured">')
self.assertEqual(expected, str(callbacks.exceptions['2']))
+class TestRequestUriTooLong(unittest.TestCase):
+
+ def test_turn_get_into_post(self):
+
+ def _postproc(resp, content):
+ return content
+
+ http = HttpMockSequence([
+ ({'status': '200'},
+ 'echo_request_body'),
+ ({'status': '200'},
+ 'echo_request_headers'),
+ ])
+
+ # Send a long query parameter.
+ query = {
+ 'q': 'a' * MAX_URI_LENGTH + '?&'
+ }
+ req = HttpRequest(
+ http,
+ _postproc,
+ 'http://example.com?' + urllib.urlencode(query),
+ method='GET',
+ body=None,
+ headers={},
+ methodId='foo',
+ resumable=None)
+
+ # Query parameters should be sent in the body.
+ response = req.execute()
+ self.assertEqual('q=' + 'a' * MAX_URI_LENGTH + '%3F%26', response)
+
+ # Extra headers should be set.
+ response = req.execute()
+ self.assertEqual('GET', response['x-http-method-override'])
+ self.assertEqual(str(MAX_URI_LENGTH + 8), response['content-length'])
+ self.assertEqual(
+ 'application/x-www-form-urlencoded', response['content-type'])
+
if __name__ == '__main__':
unittest.main()