pants.http.server

pants.http.server implements a lean HTTP server on top of Pants with support for most of HTTP/1.1, including persistent connections. The HTTP server supports secure connections, efficient transfer of files, and proxy headers. Utilizing the power of Pants, it becomes easy to implement other protocols on top of HTTP such as WebSockets.

The Server

HTTPServer is a subclass of pants.server.Server that implements the HTTP/1.1 protocol via the class HTTPConnection. Rather than specifying a custom ConnectionClass, you implement your behavior with a request_handler. There will be more on request handlers below. For now, a brief example:

from pants.http import HTTPServer
from pants import Engine

def my_handler(request):
    request.send_response("Hello World.")

server = HTTPServer(my_handler)
server.listen()
Engine.instance().start()

In addition to specifying the request handler, there are a few other ways to configure HTTPServer.

Using HTTPServer Behind a Proxy

HTTPServer has support for a few special HTTP headers that can be set by proxy servers (notably X-Forwarded-For and X-Forwarded-Proto) and it can use X-Sendfile headers when sending files to allow the proxy server to take care of static file transmission.

When creating your HTTPServer instance, set xheaders to True to allow the server to automatically use the headers X-Real-IP, X-Forwarded-For, and X-Forwarded-Proto if they exist to set the HTTPRequest‘s remote_ip and scheme.

Sendfile is a bit more complex, with three separate variables for configuration. To enable the X-Sendfile header, set sendfile to True when creating your HTTPServer instance. Alternatively, you may set it to a string to have Pants use a string other than X-Sendfile for the header’s name.

HTTPServer’s sendfile_prefix allows you to set a prefix for the path written to the X-Sendfile header. This is useful when using Pants behind nginx.

HTTPServer’s file_root allows you to specify a root directory from which static files should be located. This root path will be stripped from the file paths before they’re written to the X-Sendfile header. If file_root is not set, the current working directory (as of the time HTTPRequest.send_file() is called) will be used.

def my_handler(request):
    request.send_file('/srv/files/example.jpg')

server = HTTPServer(my_handler, sendfile=True, sendfile_prefix='/_static/',
                    file_root='/srv/files')
server.listen()

The above code would result in an HTTP response similar to:

HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 0
X-Sendfile: /_static/example.jpg

Your proxy server would then be required to detect the X-Sendfile header in that response and insert the appropriate content and headers.

Note

The sendfile API is quite rough at this point, and is most likely going to be changed in future versions. It is possible to manually set the appropriate headers to handle sending files yourself if you require more control over the process.

Request Handlers

A request handler is a callable Python object, typically either a function or a class instance with a defined __call__ method. Request handlers are passed an instance of HTTPRequest representing the current request.

HTTPRequest instances contain all of the information that was sent with an incoming request. The instances also have numerous methods for building responses.

Note

It is not required to finish responding to a request within the request handler.

Please see the documentation for the HTTPRequest class below for more information on what you can do.

HTTPServer

class pants.http.server.HTTPServer(request_handler, max_request=10485760, keep_alive=True, cookie_secret=None, xheaders=False, sendfile=False, sendfile_prefix=None, file_root=None, **kwargs)[source]

An HTTP server, extending the default Server class.

This class automatically uses the HTTPConnection connection class. Rather than through specifying a connection class, its behavior is customized by providing a request handler function that is called whenever a valid request is received.

A server’s behavior is defined almost entirely by its request handler, and will not send any response by itself unless the received HTTP request is not valid or larger than the specified limit (which defaults to 10 MiB, or 10,485,760 bytes).

Argument Default Description
request_handler   A callable that accepts a single argument. That argument is an instance of the HTTPRequest class representing the current request.
max_request 10 MiB Optional. The maximum allowed length, in bytes, of an HTTP request body. This should be kept small, as the entire request body will be held in memory.
keep_alive True Optional. Whether or not multiple requests are allowed over a single connection.
cookie_secret None Optional. A string to use when signing secure cookies.
xheaders False Optional. Whether or not to use X-Forwarded-For and X-Forwarded-Proto headers.
sendfile False Optional. Whether or not to use X-Sendfile headers. If this is set to a string, that string will be used as the header name.
sendfile_prefix None Optional. A string to prefix paths with for use in the X-Sendfile headers. Useful for nginx.
file_root None Optional. The root path to send files from using send_file().
startSSL(ssl_options={})

Enable SSL on the server, creating an HTTPS server.

When an HTTP server has been secured, the scheme of all HTTPRequest instances is set to https, otherwise it will be http. Please note that the X-Forwarded-Proto may override scheme if xheaders is set to True.

See also

See pants.server.Server.startSSL() for more information on how SSL is implemented within Pants.

listen(address=None, backlog=1024, slave=True)[source]

Begins listening for connections to the HTTP server.

The given address is resolved, the server is bound to the address, and it then begins listening for connections. If an address isn’t specified, the server will listen on either port 80 or port 443 by default. Port 443 is selected if SSL has been enabled prior to the call to listen, otherwise port 80 will be used.

See also

See pants.server.Server.listen() for more information on listening servers.

HTTPConnection

class pants.http.server.HTTPConnection(*args, **kwargs)[source]

This class implements the HTTP protocol on top of Pants. It specifically processes incoming HTTP requests and constructs an instance of HTTPRequest before passing that instance to the associated HTTPServer‘s request handler.

Direct interaction with this class is typically unnecessary, only becoming useful when implementing another protocol on top of HTTP, such as WebSockets or performing some other action that requires direct control over the underlying socket.

current_request

An instance of HTTPRequest representing the active request on the connection. If there is no active request, this will be None.

finish()[source]

This method should be called when the response to the current request has been completed, in preparation for either closing the connection or attempting to read a new request from the connection.

This method is called automatically when you use the method HTTPRequest.finish().

HTTPRequest

class pants.http.server.HTTPRequest(connection, method, url, protocol, headers=None, scheme='http')[source]

Instances of this class represent single HTTP requests that an HTTPServer has received. Such instances contain all the information needed to respond to the request, as well as the functions used to build the appropriate response.

HTTPRequest uses bytes rather than str unless otherwise stated, as network communications take place as bytes.

remote_ip

The IP address of the client, represented as bytes. If the underlying HTTPServer is set to use xheaders, this value may be loaded from the X-Real-Ip or X-Forwarded-For headers.

scheme

The scheme through which the request was received. This will typically be http. The scheme will be set to https when the connection the request was received across is secured. If the underlying HTTPServer is set to use xheaders, this value may be loaded from the X-Forwarded-Proto header.

protocol

The protocol the request was received across. This is typically either HTTP/1.1 or HTTP/1.0.

method

The HTTP request method, such as GET or POST.

url

The URL that has been requested.

path

The path segment of the url. Note that Pants does not separate the path and parameters segments automatically to save time on each request as the parameters segment is not often utilized.

query

The query segment of the url.

fragment

The fragment segment of the url.

headers

An instance of pants.http.utils.HTTPHeaders containing the headers that were received with the request. HTTPHeaders is effectively a case-insensitive dictionary that normalizes header cases upon iteration.

host

The host that the request was directed to. This is, effectively, the value of the request’s Host header. If no such header exists, the value will be set to the bytes 127.0.0.1.

Unlike the hostname, this value may contain a port number if the request was sent to a non-standard port.

hostname

The hostname segment of the host. This value will always be lower-case.

get

A dictionary of HTTP GET variables. The variables are parsed from the query using urlparse.parse_qsl() with keep_blank_values set to False.

post

A dictionary of HTTP POST variables. For security, this variable is only populated if the method is POST or PUT.

If the request’s Content-Type header is set to application/x-www-form-urlencoded, the variables will be parsed from the body using urlparse.parse_sql() with keep_blank_values set to False.

If the request’s Content-Type header is set to multipart/form-data, the body will be processed for both POST variables and files.

files

A dictionary containing files received within the request body. For security, this variable is only populated if the method is POST or PUT. At this time, Pants only knows how to receive files when the request body is formatted as multipart/form-data.

The form data variable names will be used for the dictionary keys. Each key will contain a list with one or more dictionaries representing the received files. A file’s dictionary has the keys: filename, body, and content_type.

You might receive a file using:

def my_handler(request):
    contents = request.files['my_field'][0]['body']

Note

Pants does a poor job of handling files at this time, keeping them entirely in memory while a request is being handled. It is recommended to use a proxy server with some way to receive files when writing applications.

In the future, the Pants HTTP server will be modified so that large request bodies and received files are stored to disk as temporary files as they’re received to reduce memory utilization.

body

A bytes instance containing the entire request body that has not been processed in any way.

connection

The underlying HTTPConnection instance that received this request. You shouldn’t have need to use this in most situations.

cookies

An instance of Cookie.SimpleCookie representing the cookies received with this request. Cookies being sent to the client with the response are stored in cookies_out.

cookies_out

An instance of Cookie.SimpleCookie to populate with cookies that should be sent with the response.

finish()[source]

This function should be called when the response has been completed, allowing the associated HTTPConnection to either close the connection to the client or begin listening for a new request.

Failing to call this function will drastically reduce the performance of the HTTP server, if it will work at all.

full_url

The full url for this request. This is created by combining the scheme, host, and the url.

Return the signed cookie with the key name if it exists and has a valid signature. Otherwise, return None.

is_secure

Whether or not the request was received via HTTPS.

send(data)[source]

Write data to the client.

Argument Description
data A string of data to be sent to the client.
send_cookies(keys=None, end_headers=False)[source]

Write any cookies associated with the request to the client. If any keys are specified, only the cookies with the specified keys will be transmitted. Otherwise, all cookies in cookies_out will be written to the client.

This function is usually called automatically by send_headers.

Argument Default Description
keys None Optional. A list of cookie names to send.
end_headers False Optional. If this is set to True, a double CRLF sequence will be written at the end of the cookie headers, signifying the end of the HTTP headers segment and the beginning of the response.
send_file(path, filename=None, guess_mime=True, headers=None)[source]

Send a file to the client, given the path to that file. This method makes use of X-Sendfile, if the HTTPServer instance is configured to send X-Sendfile headers.

If X-Sendfile is not available, Pants will make full use of caching headers, Ranges, and the sendfile system call to improve file transfer performance. Additionally, if the client had made a HEAD request, the contents of the file will not be transferred.

Note

The request is finished automatically by this method.

Argument Default Description
path   The path to the file to send. If this is a relative path, and the HTTPServer instance has no root path for Sendfile set, the path will be assumed relative to the current working directory.
filename None Optional. If this is set, the file will be sent as a download with the given filename as the default name to save it with.
guess_mime True Optional. If this is set to True, Pants will attempt to set the Content-Type header based on the file extension.
headers None Optional. A dictionary of HTTP headers to send with the file.

Note

If you set a Content-Type header with the headers parameter, the mime type will not be used, even if guess_mime is True. The headers will also override any Content-Disposition header generated by the filename parameter.

send_headers(headers, end_headers=True, cookies=True)[source]

Write a dictionary of HTTP headers to the client.

Argument Default Description
headers   A dictionary of HTTP headers.
end_headers True Optional. If this is set to True, a double CRLF sequence will be written at the end of the cookie headers, signifying the end of the HTTP headers segment and the beginning of the response.
cookies True Optional. If this is set to True, HTTP cookies will be sent along with the headers.
send_response(content, code=200, content_type='text/plain')[source]

Write a very simple response, in one easy function. This function is for convenience, and allows you to send a basic response in one line.

Basically, rather than:

def request_handler(request):
    output = "Hello, World!"

    request.send_status(200)
    request.send_headers({
        'Content-Type': 'text/plain',
        'Content-Length': len(output)
        })
    request.send(output)
    request.finish()

You can simply:

def request_handler(request):
    request.send_response("Hello, World!")
Argument Default Description
content   A string of content to send to the client.
code 200 Optional. The HTTP status code to send to the client.
content_type text/plain Optional. The Content-Type header to send.
send_status(code=200)[source]

Write an HTTP status line (the very first line of any response) to the client, using the same HTTP protocol version as the request. If one is available, a human readable status message will be appended after the provided code.

For example, request.send_status(404) would result in HTTP/1.1 404 Not Found being sent to the client, assuming of course that the request used HTTP protocol version HTTP/1.1.

Argument Default Description
code 200 Optional. The HTTP status code to send to the client.

Set a timestamp on a cookie and sign it, ensuring that it can’t be altered by the client. To use this, the HTTPServer must have a cookie_secret set.

Cookies set with this function may be read with get_secure_cookie().

If the provided value is a dictionary, list, or tuple the value will be serialized into JSON and encoded as UTF-8. Unicode strings will also be encoded as UTF-8. Byte strings will be passed as is. All other types will result in a TypeError.

Argument Default Description
name   The name of the cookie to set.
value   The value of the cookie.
expires 2592000 Optional. How long, in seconds, the cookie should last before expiring. The default value is equivalent to 30 days.

Additional arguments, such as path and secure may be set by providing them as keyword arguments. The HttpOnly attribute will be set by default on secure cookies..

time

The amount of time that has elapsed since the request was received. If the request has been finished already, this will be the total time that elapsed over the duration of the request.