From dabe39dd1d19c43dd6b57ef342af00239856b74e Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 21 Aug 2012 01:10:10 +0900 Subject: [PATCH] python: add Spdylay Python extension API doc --- doc/index.rst | 1 + doc/python.rst | 363 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 364 insertions(+) create mode 100644 doc/python.rst diff --git a/doc/index.rst b/doc/index.rst index 452ab5e5..b8ff02d0 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -30,6 +30,7 @@ Contents: package_README apiref + python Resources --------- diff --git a/doc/python.rst b/doc/python.rst new file mode 100644 index 00000000..9c51c0db --- /dev/null +++ b/doc/python.rst @@ -0,0 +1,363 @@ +Spdylay Python Extension +======================== + +.. py:module:: spdylay + +This is the Python extension of Spdylay library. The wrapping is made +using Cython. The extension provides mostly same APIs as original C +API. The API is still callback-centric. We use exceptions instead of +error code where they are appropriate. + +Build +----- + +To generate C source code from ``spdylay.pyx``, run ``cython``:: + + $ cython spdylay.pyx + +To build extension, run ``setup.py``:: + + $ python setup.py build_ext + +Session objects +--------------- + +.. py:class:: Session(side, version, send_cb=None, recv_cb=None, on_ctrl_recv_cb=None, on_data_chunk_recv_cb=None, on_stream_close_cb=None, on_request_recv_cb=None, user_data=None) + + 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: + + .. py:data:: CLIENT + + Indicates client. + + .. py:data:: SERVER + + Indicates server. + + The *version* specifies SPDY protocol version. Use of the following: + + .. py:data:: PROTO_SPDY2 + + Indicates SPDY/2. + + .. py:data:: PROTO_SPDY3 + + Indicates SPDY/3. + + The *user_data* specifies opaque object tied to this object. It + can be accessed through :py:attr:`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: + + .. py:function:: recv_cb(session, length) + + The *session* is the :py:class:`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 :py:class:`EOFError`. For other + errors, it must raise :py:class:`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: + + .. py:function:: send_cb(session, data) + + The *session* is the :py:class:`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 + :py:class:`CallbackFailureError`. + + The *on_ctrl_recv_cb* specifies callback function (callable) + invoked when a control frame is received. + + .. py:function:: on_ctrl_recv_cb(session, frame) + + The *session* is the :py:class:`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_data_chunk_recv_cb* specifies callback function (callable) + invoked when a chunk of data in DATA frame is received. + + .. py:function:: on_data_chunk_recv_cb(session, flags, stream_id, data) + + The *session* is the :py:class:`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 :py:func:`on_data_recv_cb` to know all + data frames are received. The *data* is the bytestring of + received data. + + The *on_stream_close_cb* specifies callback function (callable) + invoked when the stream is closed. + + .. py:function:: on_stream_close_cb(session, stream_id, status_code) + + The *session* is the :py:class:`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 :py:meth:`submit_request()` or + :py:meth:`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. + + .. py:function:: on_request_recv_cb(session, stream_id) + + The *session* is the :py:class:`Session` object invoking the + callback. The *stream_id* indicates the stream ID. + +.. py:attribute:: Session.user_data + + The object passed in the constructor as *user_data* argument. + This attribute is read-only. + +.. py:method:: Session.send() + + 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 :py:func:`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 + :func:`spdylay_session_send` about the callback functions invoked + from this method. + +.. py:method:: Session.recv(data=None) + + Receives frames from the remote peer. This method receives as + many frames as possible until the user callback :py:func:`recv_cb` + returns empty bytestring or ``None``. This function calls several + callback functions which are passed when initializing the session. + See :func:`spdylay_session_recv` about the callback functions + invoked from this method. If data is ``None``, this method will + invoke :py:func:`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 + :py:func:`recv_cb` callback function. + +.. py:method:: Session.resume_data(stream_id) + + Puts back previously deferred DATA frame in the stream *stream_id* + to the outbound queue. + + The :py:class:`InvalidArgumentError` will be raised if the stream + does not exist or no deferred data exist. + +.. py:method:: Session.want_read() + + Returns ``True`` if session wants to receive data from the + remote peer. + + If both :py:meth:`want_read()` and :py:meth:`want_write()` return + ``False``, the application should drop the connection. + +.. py:method:: Session.want_write() + + Returns ``True`` if session wants to send data to the remote peer. + + If both :py:meth:`want_read()` and :py:meth:`want_write()` return + ``False``, the application should drop the connection. + +.. py:method:: Session.get_stream_user_data(stream_id) + + Returns stream_user_data for the stream *stream_id*. The + stream_user_data is provided by :py:meth:`submit_request()` or + :py:meth:`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 + :py:meth:`submit_request()` or :py:meth:`submit_syn_stream()`, + then this function returns ``None``. If the stream does not exist, + this function returns ``None``. + +.. py:method:: Session.get_outbound_queue_size() + + Returns the number of frames in the outbound queue. This does not + include the deferred DATA frames. + +.. py:method:: Session.get_pri_lowest() + + Returns lowest priority value for the session. + +.. py:method:: Session.fail_session(status_code) + + Submits GOAWAY frame. The status code *status_code* is ignored if + the protocol version is :py:const:`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 :py:meth:`submit_goaway()` instead. + +.. py:method:: Session.submit_request(pri, nv, data_prd=None, stream_user_data=None) + + 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 :py:meth:`get_pri_lowest()` to know the lowest + priority value for this session. + + The *nv* contains the name/value pairs. For ``i >= 0``, + ``nv[2 * i]`` contains a bytestring indicating name and + ``nv[2 * i + 1]`` contains a bytestring indicating value. + + The *nv* must include following name/value pairs: + + ``:method`` + HTTP method (e.g., ``GET``, ``POST``, ``HEAD``, etc) + ``:scheme`` + URI scheme (e.g., ``https``) + ``:path`` + Absolute path and parameters of this request (e.g., ``/foo``, + ``/foo;bar;haz?h=j&y=123``) + ``:version`` + HTTP version (e.g., ``HTTP/1.1``) + ``:host`` + The hostport portion of the URI for this request (e.g., + ``example.org:443``). This is the same as the HTTP “Host” + header field. + + If the session is initialized with the version + :py:const:`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 :py:class:`DataProvider`. This + method does not increase reference count of *data_prd*, so the + application must hold the reference to it until the stream is + closed. If *data_prd* is ``None``, SYN_STREAM have FLAG_FIN set. + + 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 :py:meth:`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 + :py:func:`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, :py:meth:`get_stream_user_data()` can be used to get + stream_user_data to identify which SYN_STREAM we are processing. + + The :py:class:`InvalidArgumentError` will be raised if the *pri* + is invalid. + +.. py:method:: Session.submit_response(stream_id, nv, data_prd=None) + + Submits SYN_REPLY frame and optionally one or more DATA frames + against the stream *stream_id*. + + The *nv* contains the name/value pairs. For ``i >= 0``, + ``nv[2 * i]`` contains a bytestring indicating name and + ``nv[2 * i + 1]`` contains a bytestring indicating value. + + The *nv* must include following name/value pairs: + + ``:status`` + HTTP status code (e.g., ``200`` or ``200 OK``) + ``:version`` + HTTP response version (e.g., ``HTTP/1.1``) + + If the session is initialized with the version + :py:const:`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 :py:class:`DataProvider`. This method does not increase + reference count of *data_prd*, so the application must hold the + reference to it until the stream is closed. If *data_prd* is + ``None``, SYN_REPLY have FLAG_FIN set. + +.. py:method:: Session.submit_request() + +Frame Types +----------- + +.. py:data:: SYN_STREAM + +.. py:data:: SYN_REPLY + +.. py:data:: RST_STREAM + +.. py:data:: SETTINGS + +.. py:data:: NOOP + + Note that this was deprecated in SPDY/3. + +.. py:data:: PING + +.. py:data:: GOAWAY + +.. py:data:: HEADERS + +.. py:data:: WINDOW_UPDATE + + This first appeared in SPDY/3. + +.. py:data:: CREDENTIAL + + This first appeared in SPDY/3. + +Stream Status Codes +------------------- + +.. py:data:: OK + +.. py:data:: PROTOCOL_ERROR + +.. py:data:: INVALID_STREAM + +.. py:data:: REFUSED_STREAM + +.. py:data:: UNSUPPORTED_VERSION + +.. py:data:: CANCEL + +.. py:data:: INTERNAL_ERROR + +.. py:data:: FLOW_CONTROL_ERROR + +Following status codes were introduced in SPDY/3. + +.. py:data:: STREAM_IN_USE + +.. py:data:: STREAM_ALREADY_CLOSED + +.. py:data:: INVALID_CREDENTIALS + +.. py:data:: FRAME_TOO_LARGE