HTTP Client

There are two levels of HTTP client in SuPPort: One which roughly maps to Python’s builtin httplib module, and another that maps to urllib2.

Drop-in HTTP client: gurllib2

This module has all the same members as the standard urllib2 library, except that a few have been overridden with alternatives that use SuPPort for logging and connection management. It can be used as a drop-in replacement in most applications that use urllib2. It is built on http_client, detailed further down.

class support.gurllib2.GHTTPHandler(debuglevel=0)
http_open(req)
http_request(request)
class support.gurllib2.GHTTPSHandler(debuglevel=0)
https_open(req)
https_request(request)
class support.gurllib2.LogAwareHandler(debuglevel=0)[source]
LOG_LEVEL = 'info'
TRANSACTION_TYPE = 'API'
do_open(conn_type, req)[source]
get_log_kwargs(request)[source]
post_request(log_record, request, response)[source]
pre_request(log_record, request)[source]
support.gurllib2.build_opener(*args, **kwargs)[source]
support.gurllib2.install_opener(opener)[source]
support.gurllib2.urlopen(url, data=None, timeout=<object object>)[source]

Low-level HTTP client: http_client

http_client is a simple HTTP client that builds on httplib and gevent, using SuPPort for connection management and logging.

A simple HTTP client which mixes httplib with gevent and PayPal protecteds.

It provides convenience functions for the standard set of HTTP methods:

>>> http_client.get('http://example.com/foo') 

which are just shortcuts for the corresponding request() call:

>>> http_client.request("get", "http://example.com/foo") 

If you don’t intend to read the response’s body, you should use a context manager:

>>> with http_client.get('http://www.example.com') as response: 
...    assert response.status == 200

This will release the underlying socket back to the socket pool.

class support.http_client.Request(method, url, headers, body)[source]

A simple wrapper for HTTP Requests

method

The method used for this request (e.g., POST, GET).

url

The requested URL.

headers

The request headers (a list of two-item tuples)

body

The body if present, otherwise None.

class support.http_client.Response(request, status, headers, http_response)[source]

A simple wrapper for HTTP responses.

request

the Request object that lead to this response

status

the numeric status code for this Response

headers

an HTTPMessage object containing this response’s headers. You can treat this as a dictionary: for example, you can get the value for the Host header with msg['Host']. You should, however, be careful with duplicate headers.

Consider the following headers:

>>> headers = '\r\n'.join(['X-First-Header: First, Value',
...                       'X-First-Header: Second, Value',
...                       'X-Second-Header: Final, Value',
...                       ''])

Note that the header X-First-Header appears twice.

>>> from StringIO import StringIO
>>> from httplib import HTTPMessage
>>> msg = HTTPMessage(StringIO(headers))
>>> msg['X-First-Header']
'First, Value, Second, Value'

HTTPMessage has concatenated the two values we provided for X-First-Header (First, Value and Second, Value) with a comma. Unfortunately both of these values contain a comma. That means a simple str.split() can’t Recover the original values:

>>> msg['X-First-Header'].split(', ')
['First', 'Value', 'Second', 'Value']

The same behavior occurs with HTTPMessage.items():

>>> msg.items() 
[('x-second-header', 'Final, Value'),
 ('x-first-header', 'First, Value, Second, Value')]

To correctly recover values from duplicated header fields, use HTTPMessage.getheaders():

>>> msg.getheaders('X-First-Header')
['First, Value', 'Second, Value']
http_response

the underlying HTTPResponse object for this response.

body

the body of the request, if applicable.

Since this value is lazily loaded, if you never access it the response’s body will never be downloaded. Once loaded it’s stored locally, so repeated accesses won’t trigger repeated network calls.

close()[source]

Release the underlying socket back to the connection pool. This will be automatically called by :attribute:`~Response.body` after the body has been read. You should arrange to have this called (

support.http_client.request(method, url, body=None, headers=None, literal=False, use_protected=False, timeout=<object object>)[source]

A function to issue HTTP requests.

Parameters:
  • method – the HTTP method for this request. Case insensitive.
  • url – the URL to request. Must include a protocol (e.g. http, https).
  • body (a string or file-like object (i.e, an object that has a read method). It could also be a dict, in which case it is stringified, and the header set to application/json) – the body of the request, if applicable
  • headers (dict) – A dictionary of request headers
  • literal – if true, instruct HTTPConnection not to set the Host or Accept-Encoding headers automatically. Useful for testing
  • use_protected – if true, use the appropriate protected for this call.
  • timeout – connection timeout for this request.
Returns:

a Response object.

An example, calling up google with a custom host header:

>>> request('get',
...         'http://google.com',
...         headers={'Host': 'www.google.com'},
...         literal=True)
<http_client.Response (200) GET http://google.com>
support.http_client.urllib2_request(u2req, timeout=None)[source]

Translate a urllib2.Request to something we can pass to our request() function, and translate our Response to a urllib2.addinfourl object