doc, examples: Update tutorial and examples
This commit is contained in:
parent
e960c56aad
commit
0b14319675
|
@ -163,11 +163,13 @@ finished successfully. We first initialize nghttp2 session object in
|
|||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
||||
callbacks.on_header_callback = on_header_callback;
|
||||
callbacks.on_end_headers_callback = on_end_headers_callback;
|
||||
nghttp2_session_client_new(&session_data->session, &callbacks, session_data);
|
||||
}
|
||||
|
||||
Since we are creating client, we use `nghttp2_session_client_new()` to
|
||||
initialize nghttp2 session object. We setup 5 callbacks for the
|
||||
initialize nghttp2 session object. We setup 7 callbacks for the
|
||||
nghttp2 session. We'll explain these callbacks later.
|
||||
|
||||
The `delete_http2_session_data()` destroys ``session_data`` and frees
|
||||
|
@ -395,9 +397,8 @@ received from the remote peer::
|
|||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session_data->stream_data->stream_id == frame->hd.stream_id) {
|
||||
/* Print response headers for the initiated request. */
|
||||
fprintf(stderr, "Response headers:\n");
|
||||
print_headers(stderr, frame->headers.nva, frame->headers.nvlen);
|
||||
fprintf(stderr, "Response headers for stream ID=%d:\n",
|
||||
frame->hd.stream_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -409,6 +410,53 @@ HEADERS. We check te frame type and its category (it should be
|
|||
:macro:`NGHTTP2_HCAT_RESPONSE` for HTTP response HEADERS). Also check
|
||||
its stream ID.
|
||||
|
||||
Each request header name/value pair is emitted via
|
||||
``on_header_callback`` function::
|
||||
|
||||
static int on_header_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session_data->stream_data->stream_id == frame->hd.stream_id) {
|
||||
/* Print response headers for the initiated request. */
|
||||
print_header(stderr, name, namelen, value, valuelen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
In this turotial, we just print the name/value pair.
|
||||
|
||||
After all name/value pairs are emitted for a frame,
|
||||
``on_end_headers_callback`` function is called::
|
||||
|
||||
static int on_end_headers_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
nghttp2_error_code error_code,
|
||||
void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session_data->stream_data->stream_id == frame->hd.stream_id) {
|
||||
fprintf(stderr, "All headers received with error_code=%d\n", error_code);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
This callback may be called prematurely because of errors (e.g.,
|
||||
header decompression failure) which is indicated by ``error_code``.
|
||||
|
||||
The ``on_data_chunk_recv_callback()`` function is invoked when a chunk
|
||||
of data is received from the remote peer::
|
||||
|
||||
|
|
|
@ -243,11 +243,12 @@ We initialize nghttp2 session object which is done in
|
|||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||
callbacks.on_request_recv_callback = on_request_recv_callback;
|
||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
||||
callbacks.on_header_callback = on_header_callback;
|
||||
nghttp2_session_server_new(&session_data->session, &callbacks, session_data);
|
||||
}
|
||||
|
||||
Since we are creating server, nghttp2 session object is created using
|
||||
`nghttp2_session_server_new()` function. We registers 4 callbacks to
|
||||
`nghttp2_session_server_new()` function. We registers 5 callbacks to
|
||||
nghttp2 session object. We'll talk about these callbacks later.
|
||||
|
||||
After initialization of nghttp2 session object, we are going to send
|
||||
|
@ -421,8 +422,6 @@ received from the remote peer::
|
|||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
http2_stream_data *stream_data;
|
||||
size_t i;
|
||||
const char PATH[] = ":path";
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
|
@ -431,16 +430,6 @@ received from the remote peer::
|
|||
stream_data = create_http2_stream_data(session_data, frame->hd.stream_id);
|
||||
nghttp2_session_set_stream_user_data(session, frame->hd.stream_id,
|
||||
stream_data);
|
||||
for(i = 0; i < frame->headers.nvlen; ++i) {
|
||||
nghttp2_nv *nv = &frame->headers.nva[i];
|
||||
if(nv->namelen == sizeof(PATH) - 1 &&
|
||||
memcmp(PATH, nv->name, nv->namelen) == 0) {
|
||||
size_t j;
|
||||
for(j = 0; j < nv->valuelen && nv->value[j] != '?'; ++j);
|
||||
stream_data->request_path = percent_decode(nv->value, j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -457,13 +446,47 @@ in nghttp2 session object using `nghttp2_set_stream_user_data()` in
|
|||
order to get the object without searching through doubly linked list.
|
||||
|
||||
In this example server, we want to serve files relative to the current
|
||||
working directory the program was invoked. We search ``:path`` header
|
||||
field in request headers and keep the requested path in
|
||||
``http2_stream_data`` object. In this example program, we ignore
|
||||
``:method`` header field and always treat the request as GET request.
|
||||
working directory the program was invoked. Each header name/value pair
|
||||
is emitted via ``on_header_callback`` function, which is called after
|
||||
``on_frame_recv_callback()``::
|
||||
|
||||
It is ok for the server to start sending response in this callback. In
|
||||
this example, we defer it to ``on_request_recv_callback()`` function.
|
||||
static int on_header_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
void *user_data)
|
||||
{
|
||||
http2_stream_data *stream_data;
|
||||
const char PATH[] = ":path";
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
break;
|
||||
}
|
||||
stream_data = nghttp2_session_get_stream_user_data(session,
|
||||
frame->hd.stream_id);
|
||||
if(stream_data->request_path) {
|
||||
break;
|
||||
}
|
||||
if(namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
|
||||
size_t j;
|
||||
for(j = 0; j < valuelen && value[j] != '?'; ++j);
|
||||
stream_data->request_path = percent_decode(value, j);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
We search ``:path`` header field in request headers and keep the
|
||||
requested path in ``http2_stream_data`` object. In this example
|
||||
program, we ignore ``:method`` header field and always treat the
|
||||
request as GET request.
|
||||
|
||||
It is ok for the server to start sending response in this callback (or
|
||||
in `nghttp2_on_end_headers_callback()`, which is not used in this
|
||||
tutorial). In this example, we defer it to
|
||||
``on_request_recv_callback()`` function.
|
||||
|
||||
The ``on_request_recv_callback()`` function is invoked when all HTTP
|
||||
request, including entity body, was received::
|
||||
|
|
|
@ -151,6 +151,16 @@ static void delete_http2_session_data(http2_session_data *session_data)
|
|||
free(session_data);
|
||||
}
|
||||
|
||||
static void print_header(FILE *f,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen)
|
||||
{
|
||||
fwrite(name, namelen, 1, f);
|
||||
fprintf(f, ": ");
|
||||
fwrite(value, valuelen, 1, f);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
/* Print HTTP headers to |f|. Please note that this function does not
|
||||
take into account that header name and value are sequence of
|
||||
octets, therefore they may contain non-printable characters. */
|
||||
|
@ -158,12 +168,11 @@ static void print_headers(FILE *f, nghttp2_nv *nva, size_t nvlen)
|
|||
{
|
||||
size_t i;
|
||||
for(i = 0; i < nvlen; ++i) {
|
||||
fwrite(nva[i].name, nva[i].namelen, 1, stderr);
|
||||
fprintf(stderr, ": ");
|
||||
fwrite(nva[i].value, nva[i].valuelen, 1, stderr);
|
||||
fprintf(stderr, "\n");
|
||||
print_header(f,
|
||||
nva[i].name, nva[i].namelen,
|
||||
nva[i].value, nva[i].valuelen);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
/* nghttp2_send_callback. Here we transmit the |data|, |length| bytes,
|
||||
|
@ -201,6 +210,47 @@ static int before_frame_send_callback
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* nghttp2_on_header_callback: Called when nghttp2 library emits
|
||||
single header name/value pair. */
|
||||
static int on_header_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session_data->stream_data->stream_id == frame->hd.stream_id) {
|
||||
/* Print response headers for the initiated request. */
|
||||
print_header(stderr, name, namelen, value, valuelen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* nghttp2_on_end_headers_callback: Called when nghttp2 library emits
|
||||
all header name/value pairs, or may be called prematurely because
|
||||
of errors which is indicated by |error_code|. */
|
||||
static int on_end_headers_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
nghttp2_error_code error_code,
|
||||
void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session_data->stream_data->stream_id == frame->hd.stream_id) {
|
||||
fprintf(stderr, "All headers received with error_code=%d\n", error_code);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* nghttp2_on_frame_recv_callback: Called when nghttp2 library
|
||||
received a frame from the remote peer. */
|
||||
static int on_frame_recv_callback(nghttp2_session *session,
|
||||
|
@ -211,9 +261,8 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
|||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session_data->stream_data->stream_id == frame->hd.stream_id) {
|
||||
/* Print response headers for the initiated request. */
|
||||
fprintf(stderr, "Response headers:\n");
|
||||
print_headers(stderr, frame->headers.nva, frame->headers.nvlen);
|
||||
fprintf(stderr, "Response headers for stream ID=%d:\n",
|
||||
frame->hd.stream_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -311,6 +360,8 @@ static void initialize_nghttp2_session(http2_session_data *session_data)
|
|||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
||||
callbacks.on_header_callback = on_header_callback;
|
||||
callbacks.on_end_headers_callback = on_end_headers_callback;
|
||||
nghttp2_session_client_new(&session_data->session, &callbacks, session_data);
|
||||
}
|
||||
|
||||
|
|
|
@ -325,13 +325,41 @@ static char* percent_decode(const uint8_t *value, size_t valuelen)
|
|||
return res;
|
||||
}
|
||||
|
||||
/* nghttp2_on_header_callback: Called when nghttp2 library emits
|
||||
single header name/value pair. */
|
||||
static int on_header_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
void *user_data)
|
||||
{
|
||||
http2_stream_data *stream_data;
|
||||
const char PATH[] = ":path";
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
break;
|
||||
}
|
||||
stream_data = nghttp2_session_get_stream_user_data(session,
|
||||
frame->hd.stream_id);
|
||||
if(stream_data->request_path) {
|
||||
break;
|
||||
}
|
||||
if(namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
|
||||
size_t j;
|
||||
for(j = 0; j < valuelen && value[j] != '?'; ++j);
|
||||
stream_data->request_path = percent_decode(value, j);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_frame_recv_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame, void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
http2_stream_data *stream_data;
|
||||
size_t i;
|
||||
const char PATH[] = ":path";
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
|
@ -340,16 +368,6 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
|||
stream_data = create_http2_stream_data(session_data, frame->hd.stream_id);
|
||||
nghttp2_session_set_stream_user_data(session, frame->hd.stream_id,
|
||||
stream_data);
|
||||
for(i = 0; i < frame->headers.nvlen; ++i) {
|
||||
nghttp2_nv *nv = &frame->headers.nva[i];
|
||||
if(nv->namelen == sizeof(PATH) - 1 &&
|
||||
memcmp(PATH, nv->name, nv->namelen) == 0) {
|
||||
size_t j;
|
||||
for(j = 0; j < nv->valuelen && nv->value[j] != '?'; ++j);
|
||||
stream_data->request_path = percent_decode(nv->value, j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -503,6 +521,7 @@ static void initialize_nghttp2_session(http2_session_data *session_data)
|
|||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||
callbacks.on_request_recv_callback = on_request_recv_callback;
|
||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
||||
callbacks.on_header_callback = on_header_callback;
|
||||
nghttp2_session_server_new(&session_data->session, &callbacks, session_data);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue