Python API Reference
====================

.. py:module:: nghttp2

nghttp2 offers some high level Python API to C library.  The bindings
currently provide HPACK compressor and decompressor classes and HTTP/2
server class.

The extension module is called ``nghttp2``.

``make`` will build the bindings.  The target Python version is
determined by configure script.  If the detected Python version is not
what you expect, specify a path to Python executable in ``PYTHON``
variable as an argument to configure script (e.g., ``./configure
PYTHON=/usr/bin/python3.4``).

HPACK API
---------

.. py:class:: HDDeflater(hd_table_bufsize_max=DEFLATE_MAX_HEADER_TABLE_SIZE)

   This class is used to perform header compression.  The
   *hd_table_bufsize_max* limits the usage of header table in the
   given amount of bytes.  The default value is
   :py:data:`DEFLATE_MAX_HEADER_TABLE_SIZE`.  This is necessary
   because the deflater and inflater share the same amount of header
   table and the inflater decides that number.  The deflater may not
   want to use all header table size because of limited memory
   availability.  In that case, *hd_table_bufsize_max* can be used to
   cap the upper limit of table size whatever the header table size is
   chosen by the inflater.

   .. py:method:: deflate(headers)

      Deflates the *headers*. The *headers* must be sequence of tuple
      of name/value pair, which are byte strings (not unicode string).

      This method returns the deflated header block in byte string.
      Raises the exception if any error occurs.

   .. py:method:: set_no_refset(no_refset)

      Tells the deflater not to use reference set if *no_refset* is
      evaluated to ``True``.  If that happens, on each subsequent
      invocation of :py:meth:`deflate()`, deflater will clear up
      refersent set.

   .. py:method:: change_table_size(hd_table_bufsize_max)

      Changes header table size to *hd_table_bufsize_max* byte.  if
      *hd_table_bufsize_max* is strictly larger than
      ``hd_table_bufsize_max`` given in constructor,
      ``hd_table_bufsize_max`` is used as header table size instead.

      Raises the exception if any error occurs.

   .. py:method:: get_hd_table()

      Returns copy of current dynamic header table.

The following example shows how to deflate header name/value pairs:

.. code-block:: python

   import binascii, nghttp2

   deflater = nghttp2.HDDeflater()

   res = deflater.deflate([(b'foo', b'bar'),
                           (b'baz', b'buz')])

   print(binascii.b2a_hex(res))


.. py:class:: HDInflater()

   This class is used to perform header decompression.

   .. py:method:: inflate(data)

      Inflates the deflated header block *data*. The *data* must be
      byte string.

      Raises the exception if any error occurs.

   .. py:method:: change_table_size(hd_table_bufsize_max)

      Changes header table size to *hd_table_bufsize_max* byte.

      Raises the exception if any error occurs.

   .. py:method:: get_hd_table()

      Returns copy of current dynamic header table.

The following example shows how to inflate deflated header block:

.. code-block:: python

   deflater = nghttp2.HDDeflater()

   data = deflater.deflate([(b'foo', b'bar'),
                            (b'baz', b'buz')])

   inflater = nghttp2.HDInflater()

   hdrs = inflater.inflate(data)

   print(hdrs)


.. py:function:: print_hd_table(hdtable)

   Convenient function to print *hdtable* to the standard output.  The
   *hdtable* is the one retrieved by
   :py:meth:`HDDeflater.get_hd_table()` or
   :py:meth:`HDInflater.get_hd_table()`.  This function does not work
   if header name/value cannot be decoded using UTF-8 encoding.

   In output, ``s=N`` means the entry occupies ``N`` bytes in header
   table.  If ``r=y``, then the entry is in the reference set.

.. py:data:: DEFAULT_HEADER_TABLE_SIZE

   The default header table size, which is 4096 as per HTTP/2
   specification.

.. py:data:: DEFLATE_MAX_HEADER_TABLE_SIZE

   The default header table size for deflater.  The initial value
   is 4096.

HTTP/2 servers
--------------

.. note::

   We use :py:mod:`asyncio` for HTTP/2 server classes.  Therefore,
   Python 3.4 or later is required to use these objects.  To
   explicitly configure nghttp2 build to use Python 3.4, specify the
   ``PYTHON`` variable to the path to Python 3.4 executable when
   invoking configure script like this::

       $ ./configure PYTHON=/usr/bin/python3.4

.. py:class:: HTTP2Server(address, RequestHandlerClass, ssl=None)

   This class builds on top of the :py:mod:`asyncio` event loop.  On
   construction, *RequestHandlerClass* must be given, which must be a
   subclass of :py:class:`BaseRequestHandler` class.

   The *address* must be a tuple of hostname/IP address and port to
   bind.  If hostname/IP address is ``None``, all interfaces are
   assumed.

   To enable SSL/TLS, specify instance of :py:class:`ssl.SSLContext`
   in *ssl*.  Before passing *ssl* to
   :py:func:`BaseEventLoop.create_server`, ALPN protocol identifiers
   are set using :py:meth:`ssl.SSLContext.set_npn_protocols`.

   To disable SSL/TLS, omit *ssl* or specify ``None``.

   .. py:method:: serve_forever()

      Runs server and processes incoming requests forever.

.. py:class:: BaseRequestHandler(http2, stream_id)

   The class is used to handle the single HTTP/2 stream.  By default,
   it does not nothing.  It must be subclassed to handle each event
   callback method.

   The first callback method invoked is :py:meth:`on_headers()`. It is
   called when HEADERS frame, which includes request header fields, is
   arrived.

   If request has request body, :py:meth:`on_data()` is invoked for
   each chunk of received data chunk.

   When whole request is received, :py:meth:`on_request_done()` is
   invoked.

   When stream is closed, :py:meth:`on_close()` is called.

   The application can send response using :py:meth:`send_response()`
   method.  It can be used in :py:meth:`on_headers()`,
   :py:meth:`on_data()` or :py:meth:`on_request_done()`.

   The application can push resource using :py:meth:`push()` method.
   It must be used before :py:meth:`send_response()` call.

   A :py:class:`BaseRequestHandler` has the following instance
   variables:

   .. py:attribute:: client_address

      Contains a tuple of the form ``(host, port)`` referring to the
      client's address.

   .. py:attribute:: stream_id

      Stream ID of this stream

   .. py:attribute:: scheme

      Scheme of the request URI.  This is a value of ``:scheme``
      header field.

   .. py:attribute:: method

      Method of this stream.  This is a value of ``:method`` header
      field.

   .. py:attribute:: host

      This is a value of ``:authority`` or ``host`` header field.

   .. py:attribute:: path

      This is a value of ``:path`` header field.

   A :py:class:`BaseRequestHandler` has the following methods:

   .. py:method:: on_headers()

      Called when request HEADERS is arrived.  By default, this method
      does nothing.

   .. py:method:: on_data(data)

      Called when a chunk of request body *data* is arrived.  This
      method will be called multiple times until all data are
      received.  By default, this method does nothing.

   .. py:method:: on_request_done()

      Called when whole request was received.  By default, this method
      does nothing.

   .. py:method:: on_close(error_code)

      Called when stream is about to close.  The *error_code*
      indicates the reason of closure.  If it is ``0``, the stream is
      going to close without error.

   .. py:method:: send_response(status=200, headers=None, body=None)

      Send response.  The *status* is HTTP status code.  The *headers*
      is additional response headers.  The *:status* header field will
      be appended by the library.  The *body* is the response body.
      It could be ``None`` if response body is empty. Or it must be
      instance of either ``str``, ``bytes`` or :py:class:`io.IOBase`.
      If instance of ``str`` is specified, it will be encoded using
      UTF-8.

      The *headers* is a list of tuple of the form ``(name,
      value)``. The ``name`` and ``value`` can be either byte string
      or unicode string.  In the latter case, they will be encoded
      using UTF-8.

      Raises the exception if any error occurs.

   .. py:method:: push(path, method='GET', request_headers=None, status=200, headers=None, body=None)

      Push a specified resource.  The *path* is a path portion of
      request URI for this resource.  The *method* is a method to
      access this resource.  The *request_headers* is additional
      request headers to access this resource.  The ``:scheme``,
      ``:method``, ``:authority`` and ``:path`` are appended by the
      library.  The ``:scheme`` and ``:authority`` are inherited from
      request header fields of the associated stream.

      The *status* is HTTP status code.  The *headers* is additional
      response headers.  The ``:status`` header field is appended by
      the library.  The *body* is the response body.  It could be
      ``None`` if response body is empty.  Or it must be instance of
      either ``str``, ``bytes`` or ``io.IOBase``.  If instance of
      ``str`` is specified, it is encoded using UTF-8.

      The headers and request_headers are a list of tuple of the form
      ``(name, value)``. The ``name`` and ``value`` can be either byte
      string or unicode string.  In the latter case, they will be
      encoded using UTF-8.

      Returns an instance of ``RequestHandlerClass`` specified in
      :py:class:`HTTP2Server` constructor for the pushed resource.

      Raises the exception if any error occurs.

The following example illustrates :py:class:`HTTP2Server` and
:py:class:`BaseRequestHandler` usage:

.. code-block:: python

    #!/usr/bin/env python

    import io, ssl
    import nghttp2

    class Handler(nghttp2.BaseRequestHandler):

        def on_headers(self):
            self.push(path='/css/style.css',
                      request_headers = [('content-type', 'text/css')],
                      status=200,
                      body='body{margin:0;}')

            self.send_response(status=200,
                               headers = [('content-type', 'text/plain')],
                               body=io.BytesIO(b'nghttp2-python FTW'))

    ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
    ctx.options = ssl.OP_ALL | ssl.OP_NO_SSLv2
    ctx.load_cert_chain('server.crt', 'server.key')

    # give None to ssl to make the server non-SSL/TLS
    server = nghttp2.HTTP2Server(('127.0.0.1', 8443), Handler, ssl=ctx)
    server.serve_forever()