summaryrefslogtreecommitdiff
path: root/python2
diff options
context:
space:
mode:
authorJoe Gregorio <jcgregorio@google.com>2011-05-25 13:51:10 -0400
committerJoe Gregorio <jcgregorio@google.com>2011-05-25 13:51:10 -0400
commit788543e3e07fa8527b58cce6f719b1e3cdaa7310 (patch)
treed54dc0178495c03292d6ecf71be0b4ef16d35e20 /python2
parentbd68208f93806704374711623f8715a0356d048a (diff)
downloadhttplib2-788543e3e07fa8527b58cce6f719b1e3cdaa7310.tar.gz
Uses a custom httplib shim on App Engine to wrap urlfetch, as opposed
to using the standard httplib, which allows setting timeouts and checking certificates. Reviewed in http://codereview.appspot.com/4520043/
Diffstat (limited to 'python2')
-rw-r--r--python2/httplib2/__init__.py88
1 files changed, 87 insertions, 1 deletions
diff --git a/python2/httplib2/__init__.py b/python2/httplib2/__init__.py
index 1e6a5c0..f16882f 100644
--- a/python2/httplib2/__init__.py
+++ b/python2/httplib2/__init__.py
@@ -813,6 +813,92 @@ class HTTPSConnectionWithTimeout(httplib.HTTPSConnection):
if not self.sock:
raise socket.error, msg
+SCHEME_TO_CONNECTION = {
+ 'http': HTTPConnectionWithTimeout,
+ 'https': HTTPSConnectionWithTimeout
+ }
+
+# Use a different connection object for Google App Engine
+try:
+ from google.appengine.api.urlfetch import fetch
+ from google.appengine.api.urlfetch import InvalidURLError
+ from google.appengine.api.urlfetch import DownloadError
+ from google.appengine.api.urlfetch import ResponseTooLargeError
+ import logging
+
+
+ class ResponseDict(dict):
+ """Is a dictionary that also has a read() method, so
+ that it can pass itself off as an httlib.HTTPResponse()."""
+ def read(self):
+ pass
+
+
+ class AppEngineHttpConnection(object):
+ """Emulates an httplib.HTTPConnection object, but actually uses the Google
+ App Engine urlfetch library. This allows the timeout to be properly used on
+ Google App Engine, and avoids using httplib, which on Google App Engine is
+ just another wrapper around urlfetch.
+ """
+ def __init__(self, host, port=None, key_file=None, cert_file=None,
+ strict=None, timeout=None, proxy_info=None):
+ self.host = host
+ self.port = port
+ self.timeout = timeout
+ if key_file or cert_file or proxy_info:
+ raise NotSupportedOnThisPlatform()
+ self.response = None
+ self.scheme = 'http'
+
+ def request(self, method, url, body, headers):
+ # Calculate the absolute URI, which fetch requires
+ netloc = self.host
+ if self.port:
+ netloc = '%s:%s' % (self.host, self.port)
+ absolute_uri = '%s://%s%s' % (self.scheme, netloc, url)
+ try:
+ response = fetch(absolute_uri, payload=body, method=method, headers=headers,
+ allow_truncated=False, follow_redirects=False,
+ deadline=self.timeout, validate_certificate=True)
+ self.response = ResponseDict(response.headers)
+ self.response['status'] = response.status_code
+ setattr(self.response, 'read', lambda : response.content)
+
+ # Make sure the exceptions raised match the exceptions expected.
+ except InvalidURLError:
+ raise socket.gaierror('')
+ except (DownloadError, ResponseTooLargeError, SSLCertificateError):
+ raise httplib.HTTPException()
+
+ def getresponse(self):
+ return self.response
+
+ def set_debuglevel(self, level):
+ pass
+
+ def connect(self):
+ pass
+
+ def close(self):
+ pass
+
+
+ class AppEngineHttpsConnection(object):
+ """Same as AppEngineHttpConnection, but for HTTPS URIs."""
+ def __init__(self, host, port=None, key_file=None, cert_file=None,
+ strict=None, timeout=None, proxy_info=None):
+ AppEngineHttpConnection.__init__(self, host, port, key_file, cert_file,
+ strict, timeout, proxy_info)
+ self.scheme = 'https'
+
+ # Update the connection classes to use the Googel App Engine specific ones.
+ SCHEME_TO_CONNECTION = {
+ 'http': AppEngineHttpConnection,
+ 'https': AppEngineHttpsConnection
+ }
+
+except ImportError:
+ pass
class Http(object):
@@ -1077,7 +1163,7 @@ a string that contains the response entity body.
conn = self.connections[conn_key]
else:
if not connection_type:
- connection_type = (scheme == 'https') and HTTPSConnectionWithTimeout or HTTPConnectionWithTimeout
+ connection_type = SCHEME_TO_CONNECTION[scheme]
certs = list(self.certificates.iter(authority))
if scheme == 'https' and certs:
conn = self.connections[conn_key] = connection_type(authority, key_file=certs[0][0],