Update tutorial

This commit is contained in:
Tatsuhiro Tsujikawa 2014-01-29 21:49:50 +09:00
parent 652228a9d2
commit 03a94ecca7
2 changed files with 44 additions and 94 deletions

View File

@ -164,7 +164,7 @@ finished successfully. We first initialize nghttp2 session object in
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback; callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
callbacks.on_stream_close_callback = on_stream_close_callback; callbacks.on_stream_close_callback = on_stream_close_callback;
callbacks.on_header_callback = on_header_callback; callbacks.on_header_callback = on_header_callback;
callbacks.on_end_headers_callback = on_end_headers_callback; callbacks.on_begin_headers_callback = on_begin_headers_callback;
nghttp2_session_client_new(&session_data->session, &callbacks, session_data); nghttp2_session_client_new(&session_data->session, &callbacks, session_data);
} }
@ -386,30 +386,6 @@ multiple streams, and *stream_user_data* is very handy to identify
which HEADERS we are seeing in the callback. Therefore we just show which HEADERS we are seeing in the callback. Therefore we just show
how to use it here. how to use it here.
The ``on_frame_recv_callback()`` function is invoked when a frame is
received from the remote peer::
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;
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, "Response headers for stream ID=%d:\n",
frame->hd.stream_id);
}
break;
}
return 0;
}
In this tutorial, we are just interested in the HTTP response
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 Each request header name/value pair is emitted via
``on_header_callback`` function:: ``on_header_callback`` function::
@ -435,27 +411,27 @@ Each request header name/value pair is emitted via
In this turotial, we just print the name/value pair. In this turotial, we just print the name/value pair.
After all name/value pairs are emitted for a frame, After all name/value pairs are emitted for a frame,
``on_end_headers_callback`` function is called:: ``on_frame_recv_callback`` function is called::
static int on_end_headers_callback(nghttp2_session *session, static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, const nghttp2_frame *frame, void *user_data)
nghttp2_error_code error_code,
void *user_data)
{ {
http2_session_data *session_data = (http2_session_data*)user_data; http2_session_data *session_data = (http2_session_data*)user_data;
switch(frame->hd.type) { switch(frame->hd.type) {
case NGHTTP2_HEADERS: case NGHTTP2_HEADERS:
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE && if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) { session_data->stream_data->stream_id == frame->hd.stream_id) {
fprintf(stderr, "All headers received with error_code=%d\n", error_code); fprintf(stderr, "All headers received\n");
} }
break; break;
} }
return 0; return 0;
} }
This callback may be called prematurely because of errors (e.g., In this tutorial, we are just interested in the HTTP response
header decompression failure) which is indicated by ``error_code``. 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.
The ``on_data_chunk_recv_callback()`` function is invoked when a chunk The ``on_data_chunk_recv_callback()`` function is invoked when a chunk
of data is received from the remote peer:: of data is received from the remote peer::

View File

@ -241,9 +241,9 @@ We initialize nghttp2 session object which is done in
callbacks.send_callback = send_callback; callbacks.send_callback = send_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback; 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_stream_close_callback = on_stream_close_callback;
callbacks.on_header_callback = on_header_callback; callbacks.on_header_callback = on_header_callback;
callbacks.on_begin_headers_callback = on_begin_headers_callback;
nghttp2_session_server_new(&session_data->session, &callbacks, session_data); nghttp2_session_server_new(&session_data->session, &callbacks, session_data);
} }
@ -414,26 +414,23 @@ 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
``initialize_nghttp2_setup()`` function. ``initialize_nghttp2_setup()`` function.
The ``on_frame_recv_callback()`` function is invoked when a frame is The ``on_begin_headers_callback()`` function is invoked when reception
received from the remote peer:: of header block in HEADERS or PUSH_PROMISE frame is started::
static int on_frame_recv_callback(nghttp2_session *session, static int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data) const nghttp2_frame *frame,
void *user_data)
{ {
http2_session_data *session_data = (http2_session_data*)user_data; http2_session_data *session_data = (http2_session_data*)user_data;
http2_stream_data *stream_data; http2_stream_data *stream_data;
switch(frame->hd.type) {
case NGHTTP2_HEADERS: if(frame->hd.type != NGHTTP2_HEADERS ||
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) { frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
break; return 0;
}
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);
break;
default:
break;
} }
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);
return 0; return 0;
} }
@ -448,7 +445,7 @@ order to get the object without searching through doubly linked list.
In this example server, we want to serve files relative to the current In this example server, we want to serve files relative to the current
working directory the program was invoked. Each header name/value pair working directory the program was invoked. Each header name/value pair
is emitted via ``on_header_callback`` function, which is called after is emitted via ``on_header_callback`` function, which is called after
``on_frame_recv_callback()``:: ``on_begin_headers_callback()``::
static int on_header_callback(nghttp2_session *session, static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame, const nghttp2_frame *frame,
@ -483,60 +480,37 @@ requested path in ``http2_stream_data`` object. In this example
program, we ignore ``:method`` header field and always treat the program, we ignore ``:method`` header field and always treat the
request as GET request. request as GET request.
It is ok for the server to start sending response in this callback (or The ``on_frame_recv_callback()`` function is invoked when a frame is
in `nghttp2_on_end_headers_callback()`, which is not used in this fully received::
tutorial). In this example, we defer it to
``on_request_recv_callback()`` function.
The ``on_request_recv_callback()`` function is invoked when all HTTP static int on_frame_recv_callback(nghttp2_session *session,
request, including entity body, was received:: const nghttp2_frame *frame, void *user_data)
static int on_request_recv_callback(nghttp2_session *session,
int32_t stream_id, void *user_data)
{ {
int fd;
http2_session_data *session_data = (http2_session_data*)user_data; http2_session_data *session_data = (http2_session_data*)user_data;
http2_stream_data *stream_data; http2_stream_data *stream_data;
nghttp2_nv hdrs[] = { switch(frame->hd.type) {
MAKE_NV(":status", "200") case NGHTTP2_DATA:
}; case NGHTTP2_HEADERS:
char *rel_path; /* Check that the client request has finished */
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream_data = (http2_stream_data*)nghttp2_session_get_stream_user_data stream_data = nghttp2_session_get_stream_user_data(session,
(session, stream_id); frame->hd.stream_id);
if(!stream_data->request_path) { /* For DATA and HEADERS frame, this callback may be called after
if(error_reply(session, stream_data) != 0) { on_stream_close_callback. Check that stream still alive. */
return NGHTTP2_ERR_CALLBACK_FAILURE; if(!stream_data) {
return 0;
}
return on_request_recv(session, session_data, stream_data);
} }
return 0; break;
} default:
fprintf(stderr, "%s GET %s\n", session_data->client_addr, break;
stream_data->request_path);
if(!check_path(stream_data->request_path)) {
if(error_reply(session, stream_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
for(rel_path = stream_data->request_path; *rel_path == '/'; ++rel_path);
fd = open(rel_path, O_RDONLY);
if(fd == -1) {
if(error_reply(session, stream_data) != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
stream_data->fd = fd;
if(send_response(session, stream_id, hdrs, ARRLEN(hdrs), fd) != 0) {
close(fd);
return NGHTTP2_ERR_CALLBACK_FAILURE;
} }
return 0; return 0;
} }
First we retrieve ``http2_stream_data`` object associated to the First we retrieve ``http2_stream_data`` object associated to the
stream in ``on_frame_recv_callback()``. It is done using stream in ``on_begin_headers_callback()``. It is done using
`nghttp2_session_get_stream_user_data()`. If the requested path cannot `nghttp2_session_get_stream_user_data()`. If the requested path cannot
be served for some reasons (e.g., file is not found), we send 404 be served for some reasons (e.g., file is not found), we send 404
response, which is done in ``error_reply()``. Otherwise, we open response, which is done in ``error_reply()``. Otherwise, we open