Update doc

This commit is contained in:
Tatsuhiro Tsujikawa 2013-12-28 22:09:17 +09:00
parent 1c43cdbbc8
commit cc954e077f
2 changed files with 51 additions and 50 deletions

View File

@ -12,7 +12,7 @@ resource denoted by the URI. Its synopsis is like this::
$ libevent-client HTTPS_URI $ libevent-client HTTPS_URI
We use libevent in this tutorial to handle networking I/O. Please We use libevent in this tutorial to handle networking I/O. Please
note that nghttp2 iteself does not depends on libevent. note that nghttp2 itself does not depend on libevent.
First we do some setup routine for libevent and OpenSSL library in First we do some setup routine for libevent and OpenSSL library in
function ``main()`` and ``run()``, which is not so relevant to nghttp2 function ``main()`` and ``run()``, which is not so relevant to nghttp2
@ -119,8 +119,8 @@ We set 3 callbacks for the bufferevent: ``reacb``, ``writecb`` and
``eventcb``. ``eventcb``.
The ``eventcb()`` is invoked by libevent event loop when an event The ``eventcb()`` is invoked by libevent event loop when an event
(e.g., connection established, timeout, etc) happens on the underlying (e.g., connection has been established, timeout, etc) happens on the
network socket:: underlying network socket::
static void eventcb(struct bufferevent *bev, short events, void *ptr) static void eventcb(struct bufferevent *bev, short events, void *ptr)
{ {
@ -281,8 +281,8 @@ frames. The ``session_send()`` function is defined as follows::
} }
The `nghttp2_session_send()` function serializes the frame into wire The `nghttp2_session_send()` function serializes the frame into wire
format and call :member:`nghttp2_callbacks.nghttp2_send_callback` with format and call :member:`nghttp2_session_callbacks.send_callback` with
it. We set ``send_callback()`` function as it. We set ``send_callback()`` function to
:member:`nghttp2_session_callbacks.send_callback` in :member:`nghttp2_session_callbacks.send_callback` in
``initialize_nghttp2_session()`` function described earlier. It is ``initialize_nghttp2_session()`` function described earlier. It is
defined as follows:: defined as follows::
@ -332,7 +332,7 @@ conditions as well. Using these information, nghttp2 session object
will tell whether the connection should be dropped or not. More will tell whether the connection should be dropped or not. More
specifically, both `nghttp2_session_want_read()` and specifically, both `nghttp2_session_want_read()` and
`nghttp2_session_want_write()` return 0, we have no business in the `nghttp2_session_want_write()` return 0, we have no business in the
connection. But since we have using bufferevent and its deferred connection. But since we are using bufferevent and its deferred
callback option, the bufferevent output buffer may contain the pending callback option, the bufferevent output buffer may contain the pending
data when the ``writecb()`` is called. To handle this situation, we data when the ``writecb()`` is called. To handle this situation, we
also check whether the output buffer is empty or not. If these also check whether the output buffer is empty or not. If these

View File

@ -2,10 +2,10 @@ Tutorial: HTTP/2.0 server
========================= =========================
In this tutorial, we are going to write single-threaded, event-based In this tutorial, we are going to write single-threaded, event-based
HTTP/2.0 web server, which supports HTTPS. It can handle concurrent HTTP/2.0 web server, which supports HTTPS only. It can handle
multiple requests, but only GET method is supported. The complete concurrent multiple requests, but only GET method is supported. The
source code, `libevent-server.c`_, is attached at the end of this complete source code, `libevent-server.c`_, is attached at the end of
page. It also resides in examples directory in the archive or this page. It also resides in examples directory in the archive or
repository. repository.
This simple server takes 3 arguments, a port number to listen to, a This simple server takes 3 arguments, a port number to listen to, a
@ -15,17 +15,17 @@ is like this::
$ libevent-server PORT /path/to/server.key /path/to/server.crt $ libevent-server PORT /path/to/server.key /path/to/server.crt
We use libevent in this tutorial to handle networking I/O. Please We use libevent in this tutorial to handle networking I/O. Please
note that nghttp2 iteself does not depends on libevent. note that nghttp2 itself does not depend on libevent.
First we do some setup routine for libevent and OpenSSL library in First we do some setup routine for libevent and OpenSSL library in
function ``main()`` and ``run()``, which is not so relevant to nghttp2 function ``main()`` and ``run()``, which is not so relevant to nghttp2
library use. The one thing you should look at is setup NPN callback. library use. The one thing you should look at is setup NPN callback.
The NPN callback is used for the server to advertise the application The NPN callback is used for the server to advertise the application
protocols the server supports to a client. In this example program, protocols the server supports to a client. In this example program,
when creating SSL_CTX object, we stores the application protocol name when creating ``SSL_CTX`` object, we stores the application protocol
in the wire format of NPN in statically allocated buffer. This is safe name in the wire format of NPN in statically allocated buffer. This is
because we only create 1 SSL_CTX object in the entire program life safe because we only create 1 ``SSL_CTX`` object in the entire program
time:: life time::
static unsigned char next_proto_list[256]; static unsigned char next_proto_list[256];
static size_t next_proto_list_len; static size_t next_proto_list_len;
@ -55,14 +55,14 @@ time::
return ssl_ctx; return ssl_ctx;
} }
The wire format of NPN is array of length prefixed string. The exactly The wire format of NPN is a sequence of length prefixed string. The
one byte is used to specify the length of the protocol identifier. In exactly one byte is used to specify the length of each protocol
this tutorial, we advertise the HTTP/2.0 protocol the nghttp2 library identifier. In this tutorial, we advertise the HTTP/2.0 protocol the
supports. We export its identifier in nghttp2 library supports. The nghttp2 library exports its identifier
:macro:`NGHTTP2_PROTO_VERSION_ID`. The ``next_proto_cb()`` function is in :macro:`NGHTTP2_PROTO_VERSION_ID`. The ``next_proto_cb()`` function
the server-side NPN callback. In OpenSSL implementation, We just is the server-side NPN callback. In OpenSSL implementation, we just
assign the pointer to the NPN buffers we filled earlier. The NPN assign the pointer to the NPN buffers we filled earlier. The NPN
callback function is set to SSL_CTX object using callback function is set to ``SSL_CTX`` object using
``SSL_CTX_set_next_protos_advertised_cb()``. ``SSL_CTX_set_next_protos_advertised_cb()``.
We use ``app_content`` structure to store the application-wide data:: We use ``app_content`` structure to store the application-wide data::
@ -100,7 +100,8 @@ object in O(1). The first element of this list is pointed by the
``root->next`` in ``http2_session_data``. Initially, ``root->next`` ``root->next`` in ``http2_session_data``. Initially, ``root->next``
is ``NULL``. The ``handshake_leftlen`` member of is ``NULL``. The ``handshake_leftlen`` member of
``http2_session_data`` is used to track the number of bytes remaining ``http2_session_data`` is used to track the number of bytes remaining
when receiving first 24 bytes magic values from the client. We use when receiving first 24 bytes magic value
(:macro:`NGHTTP2_CLIENT_CONNECTION_HEADER`) from the client. We use
libevent's bufferevent structure to perform network I/O. Notice that libevent's bufferevent structure to perform network I/O. Notice that
bufferevent object is in ``http2_session_data`` and not in bufferevent object is in ``http2_session_data`` and not in
``http2_stream_data``. This is because ``http2_stream_data`` is just a ``http2_stream_data``. This is because ``http2_stream_data`` is just a
@ -161,8 +162,8 @@ connection is also initialized at this time. We specify 2 callbacks
for the bufferevent: ``handshake_readcb`` and ``eventcb``. for the bufferevent: ``handshake_readcb`` and ``eventcb``.
The ``eventcb()`` is invoked by libevent event loop when an event The ``eventcb()`` is invoked by libevent event loop when an event
(e.g., connection established, timeout, etc) happens on the underlying (e.g., connection has been established, timeout, etc) happens on the
network socket:: underlying network socket::
static void eventcb(struct bufferevent *bev, short events, void *ptr) static void eventcb(struct bufferevent *bev, short events, void *ptr)
{ {
@ -223,13 +224,13 @@ it::
} }
} }
Nothing special here, we just compare the magic byte string received We check that the received byte string matches
and expected one :macro:`NGHTTP2_CLIENT_CONNECTION_HEADER`. When :macro:`NGHTTP2_CLIENT_CONNECTION_HEADER`. When they match, the
whole magic byte string is received, the connection state is ready for connection state is ready for starting HTTP/2.0 communication. First
starting HTTP/2.0 communication. First we change the callback we change the callback functions for the bufferevent object. We use
functions for the bufferevent object. We use same ``eventcb`` as same ``eventcb`` as before. But we specify new ``readcb`` and
before. But we specify new ``readcb`` and ``writecb`` function to ``writecb`` function to handle HTTP/2.0 communication. We describe
handle HTTP/2.0 communication. We describe these 2 functions later. these 2 functions later.
We initialize nghttp2 session object which is done in We initialize nghttp2 session object which is done in
``initialize_nghttp2_session()``:: ``initialize_nghttp2_session()``::
@ -303,9 +304,9 @@ functions for these pending data. To process received data, we call
In this function, we feed all unprocessed, received data to nghttp2 In this function, we feed all unprocessed, received data to nghttp2
session object using `nghttp2_session_mem_recv()` function. The session object using `nghttp2_session_mem_recv()` function. The
`nghttp2_session_mem_recv()` processes the received data and may `nghttp2_session_mem_recv()` processes the received data and may
invoke nghttp2 callbacks and also queue frames. Since there may be invoke nghttp2 callbacks and also queue outgoing frames. Since there
pending frames, we call ``session_send()`` function to send those may be pending frames, we call ``session_send()`` function to send
frames. The ``session_send()`` function is defined as follows:: those frames. The ``session_send()`` function is defined as follows::
static int session_send(http2_session_data *session_data) static int session_send(http2_session_data *session_data)
{ {
@ -319,8 +320,8 @@ frames. The ``session_send()`` function is defined as follows::
} }
The `nghttp2_session_send()` function serializes the frame into wire The `nghttp2_session_send()` function serializes the frame into wire
format and call :member:`nghttp2_callbacks.nghttp2_send_callback` with format and call :member:`nghttp2_session_callbacks.send_callback` with
it. We set ``send_callback()`` function as it. We set ``send_callback()`` function to
:member:`nghttp2_session_callbacks.send_callback` in :member:`nghttp2_session_callbacks.send_callback` in
``initialize_nghttp2_session()`` function described earlier. It is ``initialize_nghttp2_session()`` function described earlier. It is
defined as follows:: defined as follows::
@ -397,7 +398,7 @@ frame and other error conditions as well. Using these information,
nghttp2 session object will tell whether the connection should be nghttp2 session object will tell whether the connection should be
dropped or not. More specifically, both `nghttp2_session_want_read()` dropped or not. More specifically, both `nghttp2_session_want_read()`
and `nghttp2_session_want_write()` return 0, we have no business in and `nghttp2_session_want_write()` return 0, we have no business in
the connection. But since we have using bufferevent and its deferred the connection. But since we are using bufferevent and its deferred
callback option, the bufferevent output buffer may contain the pending callback option, the bufferevent output buffer may contain the pending
data when the ``writecb()`` is called. To handle this situation, we data when the ``writecb()`` is called. To handle this situation, we
also check whether the output buffer is empty or not. If these also check whether the output buffer is empty or not. If these
@ -406,7 +407,7 @@ conditions are met, we drop connection.
Otherwise, we call ``session_send()`` to process pending output Otherwise, we call ``session_send()`` to process pending output
data. Remember that in ``send_callback()``, we may not write all data data. Remember that in ``send_callback()``, we may not write all data
to bufferevent to avoid excessive buffering. We continue process to bufferevent to avoid excessive buffering. We continue process
pending data if output buffer becomes empty. pending data when output buffer becomes empty.
We have already described about nghttp2 callback ``send_callback()``. We have already described about nghttp2 callback ``send_callback()``.
Let's describe remaining nghttp2 callbacks we setup in Let's describe remaining nghttp2 callbacks we setup in
@ -447,17 +448,17 @@ received from the remote peer::
return 0; return 0;
} }
We only interested HEADERS frame in this function. Since HEADERS frame We only interested in HEADERS frame in this function. Since HEADERS
has several roles in HTTP/2.0 protocol, we check that it is a request frame has several roles in HTTP/2.0 protocol, we check that it is a
HEADERS, which opens new stream. If frame is request HEADERS, then we request HEADERS, which opens new stream. If frame is request HEADERS,
create ``http2_stream_data`` object to store stream related data. We then we create ``http2_stream_data`` object to store stream related
associate created ``http2_stream_data`` object to the stream in data. We associate created ``http2_stream_data`` object to the stream
nghttp2 session object using `nghttp2_set_stream_user_data()` in order in nghttp2 session object using `nghttp2_set_stream_user_data()` in
to get the object without searching through doubly linked list. order to get the object without searching through doubly linked list.
In this example server, we want to server static file relative to the In this example server, we want to serve files relative to the current
current working directory the program was invoked. We search ``:path`` working directory the program was invoked. We search ``:path`` header
header field in request headers and keep the requested path in field in request headers and keep the requested path in
``http2_stream_data`` object. In this example program, we ignore ``http2_stream_data`` object. In this example program, we ignore
``:method`` header field and always treat the request as GET request. ``:method`` header field and always treat the request as GET request.
@ -588,7 +589,7 @@ is about to close::
} }
We destroy ``http2_stream_data`` object in this function since the We destroy ``http2_stream_data`` object in this function since the
stream is about to close and we no longer to use that object. stream is about to close and we no longer use that object.
libevent-server.c libevent-server.c