Python-spdylay is the Python extension module of Spdylay SPDY C library.
To generate C source code from spdylay.pyx, run cython:
$ cython spdylay.pyx
To build extension, run setup.py:
$ python setup.py build_ext
This is the class to hold the resources needed for a SPDY session. Sending and receiving SPDY frames are done using the methods of this class.
The side specifies server or client. Use one of the following:
Indicates client.
Indicates server.
The version specifies SPDY protocol version. Use of the following:
Indicates SPDY/2.
Indicates SPDY/3.
The user_data specifies opaque object tied to this object. It can be accessed through user_data attribute.
The recv_cb specifies callback function (callable) invoked when the object wants to receive data from the remote peer. The signature of this callback is:
The session is the Session object invoking the callback. The implementation of this function must read at most length bytes of bytestring and return it. If it cannot read any single byte without blocking, it must return empty bytestring or None. If it gets EOF before it reads any single byte, it must raise EOFError. For other errors, it must raise CallbackFailureError.
The send_cb specifies callback function (callable) invoked when session wants to send data to the remote peer. The signature of this callback is:
The session is the Session object invoking the callback. The data is the bytestring to send. The implementation of this function will send all or part of data. It must return the number of bytes sent if it succeeds. If it cannot send any single byte without blocking, it must return 0 or None. For other errors, it must return CallbackFailureError.
The on_ctrl_recv_cb specifies callback function (callable) invoked when a control frame is received.
The session is the Session object invoking the callback. The frame is the received control frame. frame.frame_type tells the type of frame. See Frame Types for the details. Once the frame type is identified, access attribute of the frame to get information.
The on_invalid_ctrl_recv_cb specifies callback function (callable) invoked when an invalid control frame is received.
The session is the Session object invoking the callback. The frame is the received control frame. frame.frame_type tells the type of frame. See Frame Types for the details. Once the frame type is identified, access attribute of the frame to get information. The status_code is one of the Stream Status Codes and indicates the error. When this callback function is invoked, either RST_STREAM or GOAWAY will be sent.
The on_data_chunk_recv_cb specifies callback function (callable) invoked when a chunk of data in DATA frame is received.
The session is the Session object invoking the callback. The stream_id is the stream ID this DATA frame belongs to. The flags is the flags of DATA frame which this data chunk is contained. (flags & DATA_FLAG_FIN) != 0 does not necessarily mean this chunk of data is the last one in the stream. You should use on_data_recv_cb() to know all data frames are received. The data is the bytestring of received data.
The on_data_recv_cb specifies callback function (callable) invoked when DATA frame is received.
The actual data it contains are received by on_data_chunk_recv_cb().
The before_ctrl_send_cb specifies callback function (callable) invoked before the control frame is sent.
The session is the Session object invoking the callback. The frame is the control frame to be sent. frame.frame_type tells the type of frame. See Frame Types for the details. Once the frame type is identified, access attribute of the frame to get information.
The on_ctrl_send_cb specifies callback function (callable) invoked after the control frame is sent.
The session is the Session object invoking the callback. The frame is the control frame to be sent. frame.frame_type tells the type of frame. See Frame Types for the details. Once the frame type is identified, access attribute of the frame to get information.
The on_ctrl_not_send_cb specifies callback function (callable) after the control frame is not sent because of the error.
The session is the Session object invoking the callback. The frame is the received control frame. frame.frame_type tells the type of frame. See Frame Types for the details. Once the frame type is identified, access attribute of the frame to get information. The error_code is one of the Error Codes and indicates the error.
The on_data_send_cb specifies callback function (callable) invoked after DATA frame is sent.
The on_stream_close_cb specifies callback function (callable) invoked when the stream is closed.
The session is the Session object invoking the callback. The stream_id indicates the stream ID. The reason of closure is indicated by the status_code. See Stream Status Codes for the details. The stream_user_data, which was specified in submit_request() or submit_syn_stream(), is still available in this function.
The on_request_recv_cb specifies callback function (callable) invoked when the request from the remote peer is received. In other words, the frame with FIN flag set is received. In HTTP, this means HTTP request, including request body, is fully received.
The session is the Session object invoking the callback. The stream_id indicates the stream ID.
The on_ctrl_recv_parse_error_cb specifies callback function (callable) invoked when the received control frame octets could not be parsed correctly.
The type indicates the type of received control frame. The head is the bytestring of control frame header. The payload is the bytestring of data portion of the received frame. The error_code is one of the error code defined in Error Codes and indicates the error.
The on_unknown_ctrl_recv_cb specifies callback function (callable) invoked when the received control frame type is unknown.
The head is the bytestring of control frame header. The payload is the bytestring of data portion of the received frame.
The InvalidArgumentError will be raised if the given argument is invalid. The UnsupportedVersionError will be raised if the version is not supported. The ZlibError will be raised if initialization of zlib failed.
The object passed in the constructor as user_data argument. This attribute is read-only.
Sends pending frames to the remote peer. This method retrieves the highest prioritized frame from the outbound queue and sends it to the remote peer. It does this as many as possible until the user callback send_cb() returns 0 or None or the outbound queue becomes empty. This method calls several callback functions which are passed when initializing the session. See spdylay_session_send() about the callback functions invoked from this method.
The CallbackFailureError will be raised if the callback function failed.
Receives frames from the remote peer. This method receives as many frames as possible until the user callback recv_cb() returns empty bytestring or None. This function calls several callback functions which are passed when initializing the session. See spdylay_session_recv() about the callback functions invoked from this method. If data is None, this method will invoke recv_cb() callback function to receive incoming data. If data is not None, it must be a bytestring and this method uses it as the incoming data and does not call recv_cb() callback function.
The EOFError will be raised if the remote peer did shutdown on the connection. The CallbackFailureError will be raised if the callback function failed.
Puts back previously deferred DATA frame in the stream stream_id to the outbound queue.
This method returns True if it succeeds, or False. This method will fail if the stream does not exist or no deferred data exist.
Returns True if session wants to receive data from the remote peer.
If both want_read() and want_write() return False, the application should drop the connection.
Returns True if session wants to send data to the remote peer.
If both want_read() and want_write() return False, the application should drop the connection.
Returns stream_user_data for the stream stream_id. The stream_user_data is provided by submit_request() or submit_syn_stream(). If the stream is initiated by the remote endpoint, stream_user_data is always None. If the stream is initiated by the local endpoint and None is given in submit_request() or submit_syn_stream(), then this function returns None. If the stream does not exist, this function returns None.
Returns the number of frames in the outbound queue. This does not include the deferred DATA frames.
Returns lowest priority value for the session.
Submits GOAWAY frame. The status code status_code is ignored if the protocol version is PROTO_SPDY2.
This method should be called when the connection should be terminated after sending GOAWAY. If the remaining streams should be processed after GOAWAY, use submit_goaway() instead.
Submits SYN_STREAM frame and optionally one or more DATA frames.
The pri is priority of this request. 0 is the highest priority value. Use get_pri_lowest() to know the lowest priority value for this session.
The nv is a list containing the name/value pairs. The each element is a pair of unicode strings: name and value (e.g., (u'host', u'localhost')).
The nv must include following name/value pairs:
If the session is initialized with the version PROTO_SPDY2, the above names are translated to method, scheme, url, version and host respectively.
The names in nv will be lower-cased when they are sent.
If data_prd is not None, it provides data which will be sent in subsequent DATA frames. In this case, a method that allows request message bodies (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9) must be specified with :method key in nv (e.g. POST). The type of data_prd is expected to be DataProvider. If data_prd is None, SYN_STREAM have FLAG_FIN set.
Note
This method does not increase reference count of data_prd, so the application must hold the reference to it until the stream is closed.
The stream_user_data is data associated to the stream opened by this request and can be an arbitrary object, which can be retrieved later by get_stream_user_data().
Since the library reorders the frames and tries to send the highest prioritized one first and the SPDY specification requires the stream ID must be strictly increasing, the stream ID of this request cannot be known until it is about to sent. To know the stream ID of the request, the application can use before_ctrl_send_cb(). This callback is called just before the frame is sent. For SYN_STREAM frame, the argument frame has the stream ID assigned. Also since the stream is already opened, get_stream_user_data() can be used to get stream_user_data to identify which SYN_STREAM we are processing.
The InvalidArgumentError will be raised if the pri is invalid; or the nv includes empty name or None value.
Submits SYN_REPLY frame and optionally one or more DATA frames against the stream stream_id.
The nv is a list containing the name/value pairs. The each element is a pair of unicode strings: name and value (e.g., (u'host', u'localhost')).
The nv must include following name/value pairs:
If the session is initialized with the version PROTO_SPDY2, the above names are translated to status and version respectively.
The names in nv will be lower-cased when they are sent.
If data_prd is not None, it provides data which will be sent in subsequent DATA frames. The type of data_prd is expected to be DataProvider. If data_prd is None, SYN_REPLY have FLAG_FIN set.
Note
This method does not increase reference count of data_prd, so the application must hold the reference to it until the stream is closed.
The InvalidArgumentError will be raised if the nv includes empty name or None value.
Submits SYN_STREAM frame. The flags is bitwise OR of the following values:
If flags includes CTRL_FLAG_FIN, this frame has FLAG_FIN flag set.
The assoc_stream_id is used for server-push. Specify 0 if this stream is not server-push. If session is initialized for client use, assoc_stream_id is ignored.
The pri is priority of this request. 0 is the highest priority value. Use get_pri_lowest() to know the lowest priority value for this session.
The nv is a list containing the name/value pairs. The each element is a pair of unicode strings: name and value (e.g., (u'host', u'localhost')).
The names in nv will be lower-cased when they are sent.
The stream_user_data is data associated to the stream opened by this request and can be an arbitrary object, which can be retrieved later by get_stream_user_data().
This function is low-level in a sense that the application code can specify flags and the Associated-To-Stream-ID directly. For usual HTTP request, submit_request() is useful.
The InvalidArgumentError will be raised if the pri is invalid; or the assoc_stream_id is invalid; or the nv includes empty name or None value.
Submits SYN_REPLY frame. The flags is bitwise OR of the following values:
If flags includes CTRL_FLAG_FIN, this frame has FLAG_FIN flag set.
The stream which this frame belongs to is given in the stream_id. The nv is the name/value pairs in this frame.
The nv is a list containing the name/value pairs. The each element is a pair of unicode strings: name and value (e.g., (u'host', u'localhost')).
The names in nv will be lower-cased when they are sent.
The InvalidArgumentError will be raised if the nv includes empty name or None value.
Submits HEADERS frame. The flags is bitwise OR of the following values:
If flags includes CTRL_FLAG_FIN, this frame has FLAG_FIN flag set.
The stream which this frame belongs to is given in the stream_id. The nv is the name/value pairs in this frame.
The nv is a list containing the name/value pairs. The each element is a pair of unicode strings: name and value (e.g., (u'host', u'localhost')).
The names in nv will be lower-cased when they are sent.
The InvalidArgumentError will be raised if the nv includes empty name or None value.
Submits one or more DATA frames to the stream stream_id. The data to be sent are provided by data_prd. The type of data_prd is expected to be DataProvider. If flags contains DATA_FLAG_FIN, the last DATA frame has FLAG_FIN set.
Note
This method does not increase reference count of data_prd, so the application must hold the reference to it until the stream is closed.
Submits RST_STREAM frame to cancel/reject the stream stream_id with the status code status_code. See Stream Status Codes for available status codes.
Submits PING frame.
Submits GOAWAY frame. The status code status_code is ignored if the protocol version is PROTO_SPDY2. See GOAWAY Status Codes for available status codes.
Stores local settings and submits SETTINGS frame. The flags is bitwise OR of the values described in SETTINGS Frame Flags.
The iv is a list of tuple (settings_id, flag, value). For settings_id, see SETTINGS IDs. For flag, see SETTINGS ID Flags.
The InvalidArgumentError will be raised if the iv contains duplicate settings ID or invalid value.
Submits WINDOW_UPDATE frame. The effective range of the delta_window_size is [1, (1 << 31)-1], inclusive. But the application must be responsible to keep the resulting window size <= (1 << 31)-1.
The InvalidArgumentError will be raised if the delta_window_size is 0 or negative. The StreamClosedError will be raised if the stream is already closed or does not exist.
Returns SPDY version strings which can be directly passed to ssl.SSLContext.set_npn_protocols(). Please note that the returned list only includes SPDY version strings this library supports. If the application intends to support other fallback protocols (e.g., http/1.1), the application should add them to the returned list.
Returns SPDY version which spdylay library supports from the given protocol name. The proto is the unicode string to the protocol name. Currently, spdy/2 and spdy/3 are supported. The returned nonzero SPDY version can be passed as the version argument in Session constructor.
This function returns nonzero SPDY version if it succeeds, or 0.
This class represents the data source and the way to read a chunk of data from it. The source is expected to be the data source to read, but the application can freely pass any object including None. The read_cb is the callback function invoked when the library needs to read data. The data read will be sent as DATA frame.
The session is the Session object. The stream_id is the stream to send data. The source is the object passed as a source in DataProvider constructor. The implementation of this callback must read at most length bytes of data and return it as bytestring. When all data is read, assign READ_EOF to read_ctrl.flags. If the application wants to postpone DATA frames, (e.g., asynchronous I/O, or reading data blocks for long time), it is achieved by returning ERR_DEFERRED without reading any data in this invocation. The library removes DATA frame from the outgoing queue temporarily. To move back deferred DATA frame to outgoing queue, call Session.resume_data(). In case of error, there are 2 choices. Raising TemporalCallbackFailureError will close the stream by issuing RST_STREAM with INTERNAL_ERROR. Raising CallbackFailureError will signal the entire session failure.
The base class of SPDY control frames.
Version
Frame type. See Frame Types.
Flags. See Control Frame Flags.
Frame payload length
The following frame classes inherit CtrlFrame class.
Following error codes indicate fatal error.
Note that this was deprecated in SPDY/3.
This first appeared in SPDY/3.
This first appeared in SPDY/3.
Indicates no flags set.
This is not a valid status code for RST_STREAM. Don’t use this in Session.submit_rst_stream().
Following status codes were introduced in SPDY/3.
This module offers a simple SPDY client implementation. The function urlfetch() fetches given URLs. For each URL, StreamHandlerClass is instantiated and its methods are called when certain event occurs. The StreamHandlerClass must be a subclass of BaseSPDYStreamHandler.
Opens URL and handles the response from the servers.
The url_or_urls is either one URL string or list of URL string. For each URL, StreamHandlerClass is instantiated and it handles the request to and response from the server. If successive URLs in url_or_urls list have same origin, they are processed in one SPDY session.
This class handles one URL retrieval, which corresponds one SPDY stream. The url is the URL to fetch. The fetcher is a driver object to call methods of this object. For now it is opaque object. This class is intended to be subclassed by the application to add specific behavior.
BaseSPDYStreamHandler has the following instance variables:
The URL for this stream.
The stream ID for this stream.
BaseSPDYStreamHandler has the following methods:
Called when name/value pairs (headers) nv is received. This method may be overridden by subclasses. The default implementation does nothing.
Called when data is received. This method may be overridden by subclass. The default implementation does nothing.
Called when this stream is closed. The status_code indicates the reason of the closure. See Stream Status Codes. This method may be overridden by subclass. The default implementation does nothing.
The example follows:
#!/usr/bin/env python
# The example SPDY client. You need Python 3.3 or later because we
# use TLS NPN.
#
# Usage: spdyclient.py URL...
#
import sys
import spdylay
class MyStreamHandler(spdylay.BaseSPDYStreamHandler):
def on_header(self, nv):
sys.stdout.write('Stream#{}\n'.format(self.stream_id))
for k, v in nv:
sys.stdout.write('{}: {}\n'.format(k, v))
def on_data(self, data):
sys.stdout.write('Stream#{}\n'.format(self.stream_id))
sys.stdout.buffer.write(data)
def on_close(self, status_code):
sys.stdout.write('Stream#{} closed\n'.format(self.stream_id))
if __name__ == '__main__':
uris = sys.argv[1:]
spdylay.urlfetch(uris, MyStreamHandler)
This module offers a simple SPDY server implementation to ready for use with little additional code.
The ThreadedSPDYServer is a socketserver.TCPServer subclass. As the name of the class suggests, it is multi threaded. It only supports SPDY connection and does not fallback to HTTP/1.1. Since it uses TLS NPN extension, Python 3.3.0 or later is required.
This class builds on TCPServer class by passing server_address and RequestHandlerCalss. The request is handled by the instance of RequestHandlerCalss.
The ThreadedSPDYServer requires a RequestHandlerCalss on instantiation, which must be a subclass of BaseSPDYRequestHandler.
Most texts are copied (and modified) from http.server documentation.
This class is used to handle the SPDY requests (streams) that arrive at the server. By itself, it cannot respond to any actual SPDY requests; it must be subclassed to handle each request method (e.g. GET or POST). BaseSPDYRequestHandler provides a number of class and instance variables, and methods for use by subclasses.
The handler will gather headers (name/value pairs in SPDY terms) and read POST data (if any), then call a method specific to the request type. The method name is constructed from the request. For example, for the request method SPAM, the do_SPAM() method will be called with no arguments. All of the relevant information is stored in instance variables of the handler. Subclasses should not need to override or extend the __init__() method.
Note
Currently, this implementation accepts request body only if method is POST and the request body will be stored in memory.
BaseSPDYRequestHandler has the following instance variables:
Contains a tuple of the form (host, port) referring to the client’s address.
Contains the server instance.
Contains the command (request type, method). For example, GET.
Contains the request path.
Contains the version string from the request. For example, HTTP/1.1.
Contains the request headers. Each name/value pair is a tuple of the form (name, value).
Contains an input stream, positioned at the start of the optional input data. If there is no optional input data, it may be None.
Contains the output stream for writing a response back to the client.
BaseSPDYRequestHandler has the following class variables:
Specifies the server software version.
Contains the Python system version.
A BaseSPDYRequestHandler instance has the following methods:
Interacts client exchanging SPDY frames. When a request is completely received, it calls appropriate do_*() method. This method will handle multiple requests (streams) until SPDY session is over.
Send a complete error reply to the client The numeric code specifies the HTTP error code, with message as optional, more specific text. A complete set of headers is sent, followed by HTML text.
Adds a response code and, optionally, short message. This will be formatted as ‘:status’ response header field.
Adds the HTTP header. The keyword and value must be unicode strings and not None.
The example of BaseSPDYRequestHandler and ThreadedSPDYServer follows:
#!/usr/bin/env python
# The example SPDY server. Python 3.3 or later is required because TLS
# NPN is used in spdylay.ThreadedSPDYServer. Put private key and
# certificate file in the current working directory.
import spdylay
# private key file
KEY_FILE='server.key'
# certificate file
CERT_FILE='server.crt'
class MySPDYRequestHandler(spdylay.BaseSPDYRequestHandler):
def do_GET(self):
if self.path == '/notfound':
# Example code to return error
self.send_error(404)
return
self.send_response(200)
self.send_header('content-type', 'text/html; charset=UTF-8')
content = '''\
<html>
<head><title>SPDY FTW</title></head>
<body>
<h1>SPDY FTW</h1>
<p>The age of HTTP/1.1 is over. The time of SPDY has come.</p>
</body>
</html>'''.encode('UTF-8')
self.wfile.write(content)
if __name__ == "__main__":
HOST, PORT = "localhost", 3000
server = spdylay.ThreadedSPDYServer((HOST, PORT),
MySPDYRequestHandler,
cert_file=CERT_FILE,
key_file=KEY_FILE)
server.start()