Update tutorial
This commit is contained in:
parent
652228a9d2
commit
03a94ecca7
|
@ -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::
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue