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
andX-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 allHTTPRequest
instances is set tohttps
, otherwise it will behttp
. Please note that theX-Forwarded-Proto
may overridescheme
ifxheaders
is 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
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 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
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 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
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 thanstr
unless otherwise stated, as network communications take place as bytes.-
remote_ip
¶ The IP address of the client, represented as
bytes
. If the underlyingHTTPServer
is set to usexheaders
, this value may be loaded from theX-Real-Ip
orX-Forwarded-For
headers.
-
scheme
¶ The scheme through which the request was received. This will typically be
http
. The scheme will be set tohttps
when the connection the request was received across is secured. If the underlyingHTTPServer
is set to usexheaders
, this value may be loaded from theX-Forwarded-Proto
header.
-
protocol
¶ The protocol the request was received across. This is typically either
HTTP/1.1
orHTTP/1.0
.
-
method
¶ The HTTP request method, such as
GET
orPOST
.
-
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.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 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
query
usingurlparse.parse_qsl()
withkeep_blank_values
set toFalse
.
-
post
¶ A dictionary of HTTP POST variables. For security, this variable is only populated if the
method
isPOST
orPUT
.If the request’s
Content-Type
header is set toapplication/x-www-form-urlencoded
, the variables will be parsed from thebody
usingurlparse.parse_sql()
withkeep_blank_values
set toFalse
.If the request’s
Content-Type
header is set tomultipart/form-data
, thebody
will 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
method
isPOST
orPUT
. 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
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.
An instance of
Cookie.SimpleCookie
representing the cookies received with this request. Cookies being sent to the client with the response are stored incookies_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 theurl
.
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.
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 theHTTPServer
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 aHEAD
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 theheaders
parameter, the mime type will not be used, even ifguess_mime
is True. Theheaders
will also override anyContent-Disposition
header generated by thefilename
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 inHTTP/1.1 404 Not Found
being sent to the client, assuming of course that the request used HTTP protocol versionHTTP/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 acookie_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
andsecure
may be set by providing them as keyword arguments. TheHttpOnly
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.
-