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
Serverclass.This class automatically uses the
HTTPConnectionconnection 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 HTTPRequestclass 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-ForandX-Forwarded-Protoheaders.sendfile False Optional. Whether or not to use X-Sendfileheaders. 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-Sendfileheaders. 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
HTTPSserver.When an HTTP server has been secured, the
schemeof allHTTPRequestinstances is set tohttps, otherwise it will behttp. Please note that theX-Forwarded-Protomay overrideschemeifxheadersis set toTrue.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
addressis 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
HTTPRequestbefore passing that instance to the associatedHTTPServer‘s request handler.Direct interaction with this class is typically unnecessary, only becoming useful when implementing another protocol on top of HTTP, such as
WebSocketsor performing some other action that requires direct control over the underlying socket.-
current_request¶ An instance of
HTTPRequestrepresenting the active request on the connection. If there is no active request, this will beNone.
-
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
HTTPServerhas 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
bytesrather thanstrunless otherwise stated, as network communications take place as bytes.-
remote_ip¶ The IP address of the client, represented as
bytes. If the underlyingHTTPServeris set to usexheaders, this value may be loaded from theX-Real-IporX-Forwarded-Forheaders.
-
scheme¶ The scheme through which the request was received. This will typically be
http. The scheme will be set tohttpswhen the connection the request was received across is secured. If the underlyingHTTPServeris set to usexheaders, this value may be loaded from theX-Forwarded-Protoheader.
-
protocol¶ The protocol the request was received across. This is typically either
HTTP/1.1orHTTP/1.0.
-
method¶ The HTTP request method, such as
GETorPOST.
-
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.
-
headers¶ An instance of
pants.http.utils.HTTPHeaderscontaining 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
Hostheader. If no such header exists, the value will be set to the bytes127.0.0.1.Unlike the
hostname, this value may contain a port number if the request was sent to a non-standard port.
-
get¶ A dictionary of HTTP GET variables. The variables are parsed from the
queryusingurlparse.parse_qsl()withkeep_blank_valuesset toFalse.
-
post¶ A dictionary of HTTP POST variables. For security, this variable is only populated if the
methodisPOSTorPUT.If the request’s
Content-Typeheader is set toapplication/x-www-form-urlencoded, the variables will be parsed from thebodyusingurlparse.parse_sql()withkeep_blank_valuesset toFalse.If the request’s
Content-Typeheader is set tomultipart/form-data, thebodywill be processed for both POST variables andfiles.
-
files¶ A dictionary containing files received within the request body. For security, this variable is only populated if the
methodisPOSTorPUT. At this time, Pants only knows how to receive files when the request body is formatted asmultipart/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, andcontent_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
bytesinstance containing the entire request body that has not been processed in any way.
-
connection¶ The underlying
HTTPConnectioninstance that received this request. You shouldn’t have need to use this in most situations.
An instance of
Cookie.SimpleCookierepresenting the cookies received with this request. Cookies being sent to the client with the response are stored incookies_out.
An instance of
Cookie.SimpleCookieto 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
HTTPConnectionto 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 theurl.
Return the signed cookie with the key
nameif 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.
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_outwill 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 theHTTPServerinstance is configured to send X-Sendfile headers.If
X-Sendfileis 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 aHEADrequest, 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 HTTPServerinstance 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-Typeheader based on the file extension.headers None Optional. A dictionary of HTTP headers to send with the file. Note
If you set a
Content-Typeheader with theheadersparameter, the mime type will not be used, even ifguess_mimeis True. Theheaderswill also override anyContent-Dispositionheader generated by thefilenameparameter.
-
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 200Optional. The HTTP status code to send to the client. content_type text/plainOptional. 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 inHTTP/1.1 404 Not Foundbeing sent to the client, assuming of course that the request used HTTP protocol versionHTTP/1.1.Argument Default Description code 200Optional. 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
HTTPServermust have acookie_secretset.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 2592000Optional. How long, in seconds, the cookie should last before expiring. The default value is equivalent to 30 days. Additional arguments, such as
pathandsecuremay be set by providing them as keyword arguments. TheHttpOnlyattribute 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.
-