162 lines
7.7 KiB
ReStructuredText
162 lines
7.7 KiB
ReStructuredText
Programmers' Guide
|
|
==================
|
|
|
|
Architecture
|
|
------------
|
|
|
|
The most notable point in nghttp2 library architecture is it does not
|
|
perform any I/O. nghttp2 only performs HTTP/2 protocol stuff based on
|
|
input byte strings. It will calls callback functions set by
|
|
applications while processing input. The output of nghttp2 is just
|
|
byte string. An application is responsible to send these output to
|
|
the remote peer. The callback functions may be called while producing
|
|
output.
|
|
|
|
Not doing I/O makes embedding nghttp2 library in the existing code
|
|
base very easy. Usually, the existing applications have its own I/O
|
|
event loops. It is very hard to use nghttp2 in that situation if
|
|
nghttp2 does its own I/O. It also makes light weight language wrapper
|
|
for nghttp2 easy with the same reason. The down side is that an
|
|
application author has to write more code to write complete
|
|
application using nghttp2. This is especially true for simple "toy"
|
|
application. For the real applications, however, this is not the
|
|
case. This is because you probably want to support HTTP/1 which
|
|
nghttp2 does not provide, and to do that, you will need to write your
|
|
own HTTP/1 stack or use existing third-party library, and bind them
|
|
together with nghttp2 and I/O event loop. In this point, not
|
|
performing I/O in nghttp2 has more point than doing it.
|
|
|
|
The primary object that an application uses is :type:`nghttp2_session`
|
|
object, which is opaque struct and its details are hidden in order to
|
|
ensure the upgrading its internal architecture without breaking the
|
|
backward compatibility. An application can set callbacks to
|
|
:type:`nghttp2_session` object through the dedicated object and
|
|
functions, and it also interacts with it via many API function calls.
|
|
|
|
An application can create as many :type:`nghttp2_session` object as it
|
|
wants. But single :type:`nghttp2_session` object must be used by a
|
|
single thread at the same time. This is not so hard to enforce since
|
|
most event-based architecture applicatons use is single thread per
|
|
core, and handling one connection I/O is done by single thread.
|
|
|
|
To feed input to :type:`nghttp2_session` object, one can use
|
|
`nghttp2_session_recv()` or `nghttp2_session_mem_recv()` functions.
|
|
They behave similarly, and the difference is that
|
|
`nghttp2_session_recv()` will use :type:`nghttp2_read_callback` to get
|
|
input. On the other hand, `nghttp2_session_mem_recv()` will take
|
|
input as its parameter. If in doubt, use `nghttp2_session_mem_recv()`
|
|
since it is simpler, and could be faster since it avoids calling
|
|
callback function.
|
|
|
|
To get output from :type:`nghttp2_session` object, one can use
|
|
`nghttp2_session_send()` or `nghttp2_session_mem_send()`. The
|
|
difference between them is that the former uses
|
|
:type:`nghttp2_send_callback` to pass output to an application. On
|
|
the other hand, the latter returns the output to the caller. If in
|
|
doubt, use `nghttp2_session_mem_send()` since it is simpler. But
|
|
`nghttp2_session_send()` might be easier to use if the output buffer
|
|
an application has is fixed sized.
|
|
|
|
Includes
|
|
--------
|
|
|
|
To use the public APIs, include ``nghttp2/nghttp2.h``::
|
|
|
|
#include <nghttp2/nghttp2.h>
|
|
|
|
The header files are also available online: :doc:`nghttp2.h` and
|
|
:doc:`nghttp2ver.h`.
|
|
|
|
Remarks
|
|
-------
|
|
|
|
Do not call `nghttp2_session_send()`, `nghttp2_session_mem_send()`,
|
|
`nghttp2_session_recv()` or `nghttp2_session_mem_recv()` from the
|
|
nghttp2 callback functions directly or indirectly. It will lead to the
|
|
crash. You can submit requests or frames in the callbacks then call
|
|
these functions outside the callbacks.
|
|
|
|
`nghttp2_session_send()` and `nghttp2_session_mem_send()` send first
|
|
24 bytes of client magic string (MAGIC)
|
|
(:macro:`NGHTTP2_CLIENT_MAGIC`) on client configuration. The
|
|
applications are responsible to send SETTINGS frame as part of
|
|
connection preface using `nghttp2_submit_settings()`. Similarly,
|
|
`nghttp2_session_recv()` and `nghttp2_session_mem_recv()` consume
|
|
MAGIC on server configuration unless
|
|
`nghttp2_option_set_no_recv_client_magic()` is used with nonzero
|
|
option value.
|
|
|
|
.. _http-messaging:
|
|
|
|
HTTP Messaging
|
|
--------------
|
|
|
|
By default, nghttp2 library checks HTTP messaging rules described in
|
|
`HTTP/2 specification, section 8
|
|
<https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-8>`_.
|
|
Everything described in that section is not validated however. We
|
|
briefly describe what the library does in this area. In the following
|
|
description, without loss of generality we omit CONTINUATION frame
|
|
since they must follow HEADERS frame and are processed atomically. In
|
|
other words, they are just one big HEADERS frame. To disable these
|
|
validations, use `nghttp2_option_set_no_http_messaging()`.
|
|
|
|
For HTTP request, including those carried by PUSH_PROMISE, HTTP
|
|
message starts with one HEADERS frame containing request headers. It
|
|
is followed by zero or more DATA frames containing request body, which
|
|
is followed by zero or one HEADERS containing trailer headers. The
|
|
request headers must include ":scheme", ":method" and ":path" pseudo
|
|
header fields unless ":method" is not "CONNECT". ":authority" is
|
|
optional, but nghttp2 requires either ":authority" or "Host" header
|
|
field must be present. If ":method" is "CONNECT", the request headers
|
|
must include ":method" and ":authority" and must omit ":scheme" and
|
|
":path".
|
|
|
|
For HTTP response, HTTP message starts with zero or more HEADERS
|
|
frames containing non-final response (status code 1xx). They are
|
|
followed by one HEADERS frame containing final response headers
|
|
(non-1xx). It is followed by zero or more DATA frames containing
|
|
response body, which is followed by zero or one HEADERS containing
|
|
trailer headers. The non-final and final response headers must
|
|
contain ":status" pseudo header field containing 3 digits only.
|
|
|
|
All request and response headers must include exactly one valid value
|
|
for each pseudo header field. Additionally nghttp2 requires all
|
|
request headers must not include more than one "Host" header field.
|
|
|
|
HTTP/2 prohibits connection-specific header fields. The following
|
|
header fields must not appear: "Connection", "Keep-Alive",
|
|
"Proxy-Connection", "Transfer-Encoding" and "Upgrade". Additionally,
|
|
"TE" header field must not include any value other than "trailers".
|
|
|
|
Each header field name and value must obey the field-name and
|
|
field-value production rules described in `RFC 7230, section
|
|
3.2. <https://tools.ietf.org/html/rfc7230#section-3.2>`_.
|
|
Additionally, all field name must be lower cased. While the pseudo
|
|
header fields must satisfy these rules, we just ignore illegal regular
|
|
headers (this means that these header fields are not passed to
|
|
application callback). This is because these illegal header fields
|
|
are floating around in existing internet and resetting stream just
|
|
because of this may break many web sites. This is especially true if
|
|
we forward to or translate from HTTP/1 traffic.
|
|
|
|
For "http" or "https" URIs, ":path" pseudo header fields must start
|
|
with "/". The only exception is OPTIONS request, in that case, "*" is
|
|
allowed in ":path" pseudo header field to represent system-wide
|
|
OPTIONS request.
|
|
|
|
With the above validations, nghttp2 library guarantees that header
|
|
field name passed to `nghttp2_on_header_callback()` is not empty.
|
|
Also required pseudo headers are all present and not empty.
|
|
|
|
nghttp2 enforces "Content-Length" validation as well. All request or
|
|
response headers must not contain more than one "Content-Length"
|
|
header field. If "Content-Length" header field is present, it must be
|
|
parsed as 64 bit signed integer. The sum of data length in the
|
|
following DATA frames must match with the number in "Content-Length"
|
|
header field if it is present (this does not include padding bytes).
|
|
|
|
Any deviation results in stream error of type PROTOCOL_ERROR. If
|
|
error is found in PUSH_PROMISE frame, stream error is raised against
|
|
promised stream.
|