From de27a9bf03af1b256969e3846d431458845f91f0 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Wed, 29 Jan 2014 21:57:16 +0900 Subject: [PATCH] Update doc --- _sources/apiref.txt | 117 ++++++++---------- _sources/tutorial-client.txt | 42 ++----- _sources/tutorial-server.txt | 96 ++++++--------- apiref.html | 120 ++++++++---------- genindex.html | 20 +-- nghttp2.h.html | 132 +++++++++----------- objects.inv | Bin 2126 -> 2114 bytes searchindex.js | 2 +- tutorial-client.html | 89 +++++--------- tutorial-server.html | 232 +++++++++++++++++------------------ 10 files changed, 362 insertions(+), 488 deletions(-) diff --git a/_sources/apiref.txt b/_sources/apiref.txt index 9336000a..e7604e82 100644 --- a/_sources/apiref.txt +++ b/_sources/apiref.txt @@ -820,6 +820,16 @@ Types (structs, unions and typedefs) respectively. The header name/value pairs are emitted via :type:`nghttp2_on_header_callback`. + For HEADERS, PUSH_PROMISE and DATA frames, this callback may be + called after stream is closed (see + :type:`nghttp2_on_stream_close_callback`). The application should + check that stream is still alive using its own stream management or + :func:`nghttp2_session_get_stream_user_data()`. + + Only HEADERS and DATA frame can signal the end of incoming data. If + ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` is nonzero, the + *frame* is the last frame from the remote peer in this stream. + The implementation of this function must return 0 if it succeeds. If nonzero value is returned, it is treated as fatal error and `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` @@ -840,10 +850,6 @@ Types (structs, unions and typedefs) member of their data structure are always ``NULL`` and 0 respectively. - If this callback is called, :type:`nghttp2_on_header_callback` and - :type:`nghttp2_on_end_headers_callback` will not be called for this - frame. - The implementation of this function must return 0 if it succeeds. If nonzero is returned, it is treated as fatal error and `nghttp2_session_recv()` and `nghttp2_session_send()` functions @@ -935,21 +941,6 @@ Types (structs, unions and typedefs) `nghttp2_session_recv()` and `nghttp2_session_send()` functions immediately return :macro:`NGHTTP2_ERR_CALLBACK_FAILURE`. -.. type:: typedef int (*nghttp2_on_request_recv_callback) (nghttp2_session *session, int32_t stream_id, void *user_data) - - - Callback function invoked when the request from the remote peer is - received. In other words, the frame with END_STREAM flag set is - received. In HTTP, this means HTTP request, including request - body, is fully received. The *user_data* pointer is the third - argument passed in to the call to `nghttp2_session_client_new()` or - `nghttp2_session_server_new()`. - - The implementation of this function must return 0 if it - succeeds. If nonzero is returned, it is treated as fatal error and - `nghttp2_session_recv()` and `nghttp2_session_send()` functions - immediately return :macro:`NGHTTP2_ERR_CALLBACK_FAILURE`. - .. type:: typedef int (*nghttp2_on_unknown_frame_recv_callback) (nghttp2_session *session, const uint8_t *head, size_t headlen, const uint8_t *payload, size_t payloadlen, void *user_data) @@ -969,6 +960,27 @@ Types (structs, unions and typedefs) `nghttp2_session_recv()` and `nghttp2_session_send()` functions immediately return :macro:`NGHTTP2_ERR_CALLBACK_FAILURE`. +.. type:: typedef int (*nghttp2_on_begin_headers_callback) (nghttp2_session *session, const nghttp2_frame *frame, void *user_data) + + + Callback function invoked when the reception of header block in + HEADERS or PUSH_PROMISE is started. Each header name/value pair + will be emitted by :type:`nghttp2_on_header_callback`. + + The ``frame->hd.flags`` may not have + :macro:`NGHTTP2_FLAG_END_HEADERS` flag set, which indicates that one + or more CONTINUATION frames are involved. But the application does + not need to care about that because the header name/value pairs are + emitted transparently regardless of CONTINUATION frames. + + The implementation of this function must return 0 if it succeeds or + :macro:`NGHTTP2_ERR_CALLBACK_FAILURE`. If nonzero value other than + :macro:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned, it is treated as + if :macro:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. If + :macro:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned, + `nghttp2_session_mem_recv()` function will immediately return + :macro:`NGHTTP2_ERR_CALLBACK_FAILURE`. + .. type:: typedef int (*nghttp2_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) @@ -976,9 +988,11 @@ Types (structs, unions and typedefs) for the *frame*. When this callback is invoked, ``frame->hd.type`` is either :macro:`NGHTTP2_HEADERS` or :macro:`NGHTTP2_PUSH_PROMISE`. After all header name/value pairs are processed with this callback, - or header decompression error occurred, then - :type:`nghttp2_on_end_headers_callback` will be invoked unless - application returns nonzero value from this callback. + and no error has been detected, + :type:`nghttp2_on_frame_recv_callback` will be invoked. If there + is an error in decompression, + :type:`nghttp2_on_frame_recv_callback` for the *frame* will not be + invoked. The *name* may be ``NULL`` if the *namelen* is 0. The same thing can be said about the *value*. @@ -995,7 +1009,7 @@ Types (structs, unions and typedefs) Returning :macro:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close the stream by issuing RST_STREAM with :macro:`NGHTTP2_INTERNAL_ERROR`. In this case, - :type:`nghttp2_on_end_headers_callback` will not be invoked. + :type:`nghttp2_on_frame_recv_callback` will not be invoked. The implementation of this function must return 0 if it succeeds. It may return :macro:`NGHTTP2_ERR_PAUSE` or @@ -1007,26 +1021,6 @@ Types (structs, unions and typedefs) `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions immediately return :macro:`NGHTTP2_ERR_CALLBACK_FAILURE`. -.. type:: typedef int (*nghttp2_on_end_headers_callback) (nghttp2_session *session, const nghttp2_frame *frame, nghttp2_error_code error_code, void *user_data) - - - Callback function invoked when all header name/value pairs are - processed or after the header decompression error is detected. If - the *error_code* is :macro:`NGHTTP2_NO_ERROR`, it indicates the - header decompression succeeded. Otherwise, error prevented the - completion of the header decompression. In this case, the library - will handle the error by either transmitting RST_STREAM or GOAWAY - and terminate session. - - If the *error_code* is not :macro:`NGHTTP2_NO_ERROR`, then - :type:`nghttp2_on_request_recv_callback` will not called for this - frame if the *frame* is HEADERS. - - The implementation of this function must return 0 if it - succeeds. If nonzero value is returned, it is treated as fatal - error and `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` - functions immediately return :macro:`NGHTTP2_ERR_CALLBACK_FAILURE`. - .. type:: nghttp2_session_callbacks @@ -1065,22 +1059,18 @@ Types (structs, unions and typedefs) .. member:: nghttp2_on_stream_close_callback on_stream_close_callback Callback function invoked when the stream is closed. - .. member:: nghttp2_on_request_recv_callback on_request_recv_callback - - Callback function invoked when request from the remote peer is - received. .. member:: nghttp2_on_unknown_frame_recv_callback on_unknown_frame_recv_callback Callback function invoked when the received frame type is unknown. + .. member:: nghttp2_on_begin_headers_callback on_begin_headers_callback + + Callback function invoked when the reception of header block in + HEADERS or PUSH_PROMISE is started. .. member:: nghttp2_on_header_callback on_header_callback Callback function invoked when a header name/value pair is received. - .. member:: nghttp2_on_end_headers_callback on_end_headers_callback - - Callback function invoked when all header name/value pairs are - processed. .. type:: nghttp2_opt_set @@ -1260,9 +1250,7 @@ Functions is invoked. 2. If one DATA frame is completely received, :member:`nghttp2_session_callbacks.on_frame_recv_callback` is - invoked. If the frame is the final frame of the request, - :member:`nghttp2_session_callbacks.on_request_recv_callback` - is invoked. If the reception of the frame triggers the + invoked. If the reception of the frame triggers the closure of the stream, :member:`nghttp2_session_callbacks.on_stream_close_callback` is invoked. @@ -1271,17 +1259,20 @@ Functions 1. :member:`nghttp2_session_callbacks.recv_callback` is invoked one or more times to receive whole frame. - 2. If the received frame is valid, - :member:`nghttp2_session_callbacks.on_frame_recv_callback` is - invoked. If frame is either HEADERS or PUSH_PROMISE, + + 2. If the received frame is valid, then following actions are + taken. If the frame is either HEADERS or PUSH_PROMISE, + :member:`nghttp2_session_callbacks.on_begin_headers_callback` + is invoked. Then :member:`nghttp2_session_callbacks.on_header_callback` is invoked for each header name/value pair. After all name/value - pairs are emitted (or decompression failed), - :member:`nghttp2_session_callbacks.on_end_headers_callback` - is invoked. If the frame is the final frame of the request, - :member:`nghttp2_session_callbacks.on_request_recv_callback` - is invoked. If the reception of the frame triggers the - closure of the stream, + pairs are emitted successfully, + :member:`nghttp2_session_callbacks.on_frame_recv_callback` is + invoked. For other frames, + :member:`nghttp2_session_callbacks.on_frame_recv_callback` is + invoked. + If the reception of the frame triggers the closure of the + stream, :member:`nghttp2_session_callbacks.on_stream_close_callback` is invoked. 3. If the received frame is unpacked but is interpreted as diff --git a/_sources/tutorial-client.txt b/_sources/tutorial-client.txt index bd7aae85..2c12f943 100644 --- a/_sources/tutorial-client.txt +++ b/_sources/tutorial-client.txt @@ -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_stream_close_callback = on_stream_close_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); } @@ -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 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 ``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. 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, - const nghttp2_frame *frame, - nghttp2_error_code error_code, - void *user_data) + 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, "All headers received with error_code=%d\n", error_code); + fprintf(stderr, "All headers received\n"); } break; } return 0; } -This callback may be called prematurely because of errors (e.g., -header decompression failure) which is indicated by ``error_code``. +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. The ``on_data_chunk_recv_callback()`` function is invoked when a chunk of data is received from the remote peer:: diff --git a/_sources/tutorial-server.txt b/_sources/tutorial-server.txt index 69a5b3ab..ff5e0552 100644 --- a/_sources/tutorial-server.txt +++ b/_sources/tutorial-server.txt @@ -241,9 +241,9 @@ We initialize nghttp2 session object which is done in callbacks.send_callback = send_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_header_callback = on_header_callback; + callbacks.on_begin_headers_callback = on_begin_headers_callback; 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 ``initialize_nghttp2_setup()`` function. -The ``on_frame_recv_callback()`` function is invoked when a frame is -received from the remote peer:: +The ``on_begin_headers_callback()`` function is invoked when reception +of header block in HEADERS or PUSH_PROMISE frame is started:: - static int on_frame_recv_callback(nghttp2_session *session, - const nghttp2_frame *frame, void *user_data) + static int on_begin_headers_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; - switch(frame->hd.type) { - case NGHTTP2_HEADERS: - if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) { - 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); - break; - default: - break; + + if(frame->hd.type != NGHTTP2_HEADERS || + frame->headers.cat != NGHTTP2_HCAT_REQUEST) { + 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); 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 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()``:: +``on_begin_headers_callback()``:: static int on_header_callback(nghttp2_session *session, 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 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_frame_recv_callback()`` function is invoked when a frame is +fully received:: -The ``on_request_recv_callback()`` function is invoked when all HTTP -request, including entity body, was received:: - - static int on_request_recv_callback(nghttp2_session *session, - int32_t stream_id, void *user_data) + static int on_frame_recv_callback(nghttp2_session *session, + const nghttp2_frame *frame, void *user_data) { - int fd; http2_session_data *session_data = (http2_session_data*)user_data; http2_stream_data *stream_data; - nghttp2_nv hdrs[] = { - MAKE_NV(":status", "200") - }; - char *rel_path; - - stream_data = (http2_stream_data*)nghttp2_session_get_stream_user_data - (session, stream_id); - if(!stream_data->request_path) { - if(error_reply(session, stream_data) != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; + switch(frame->hd.type) { + case NGHTTP2_DATA: + case NGHTTP2_HEADERS: + /* Check that the client request has finished */ + if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { + stream_data = nghttp2_session_get_stream_user_data(session, + frame->hd.stream_id); + /* For DATA and HEADERS frame, this callback may be called after + on_stream_close_callback. Check that stream still alive. */ + if(!stream_data) { + return 0; + } + return on_request_recv(session, session_data, stream_data); } - return 0; - } - fprintf(stderr, "%s GET %s\n", session_data->client_addr, - 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; + break; + default: + break; } return 0; } 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 be served for some reasons (e.g., file is not found), we send 404 response, which is done in ``error_reply()``. Otherwise, we open diff --git a/apiref.html b/apiref.html index a1e0da13..38eb1f40 100644 --- a/apiref.html +++ b/apiref.html @@ -1331,6 +1331,14 @@ in to the call to NULL and 0 respectively. The header name/value pairs are emitted via nghttp2_on_header_callback.

+

For HEADERS, PUSH_PROMISE and DATA frames, this callback may be +called after stream is closed (see +nghttp2_on_stream_close_callback). The application should +check that stream is still alive using its own stream management or +nghttp2_session_get_stream_user_data().

+

Only HEADERS and DATA frame can signal the end of incoming data. If +frame->hd.flags & NGHTTP2_FLAG_END_STREAM is nonzero, the +frame is the last frame from the remote peer in this stream.

The implementation of this function must return 0 if it succeeds. If nonzero value is returned, it is treated as fatal error and nghttp2_session_recv() and nghttp2_session_mem_recv() @@ -1350,9 +1358,6 @@ third argument passed in to the call to

If frame is HEADERS or PUSH_PROMISE, the nva and nvlen member of their data structure are always NULL and 0 respectively.

-

If this callback is called, nghttp2_on_header_callback and -nghttp2_on_end_headers_callback will not be called for this -frame.

The implementation of this function must return 0 if it succeeds. If nonzero is returned, it is treated as fatal error and nghttp2_session_recv() and nghttp2_session_send() functions @@ -1444,21 +1449,6 @@ succeeds. If nonzero is returned, it is treated as fatal error and immediately return NGHTTP2_ERR_CALLBACK_FAILURE.

-
-
-typedef int (*nghttp2_on_request_recv_callback)(nghttp2_session *session, int32_t stream_id, void *user_data)
-

Callback function invoked when the request from the remote peer is -received. In other words, the frame with END_STREAM flag set is -received. In HTTP, this means HTTP request, including request -body, is fully received. The user_data pointer is the third -argument passed in to the call to nghttp2_session_client_new() or -nghttp2_session_server_new().

-

The implementation of this function must return 0 if it -succeeds. If nonzero is returned, it is treated as fatal error and -nghttp2_session_recv() and nghttp2_session_send() functions -immediately return NGHTTP2_ERR_CALLBACK_FAILURE.

-
-
typedef int (*nghttp2_on_unknown_frame_recv_callback)(nghttp2_session *session, const uint8_t *head, size_t headlen, const uint8_t *payload, size_t payloadlen, void *user_data)
@@ -1478,6 +1468,26 @@ succeeds. If nonzero is returned, it is treated as fatal error and immediately return NGHTTP2_ERR_CALLBACK_FAILURE.

+
+
+typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
+

Callback function invoked when the reception of header block in +HEADERS or PUSH_PROMISE is started. Each header name/value pair +will be emitted by nghttp2_on_header_callback.

+

The frame->hd.flags may not have +NGHTTP2_FLAG_END_HEADERS flag set, which indicates that one +or more CONTINUATION frames are involved. But the application does +not need to care about that because the header name/value pairs are +emitted transparently regardless of CONTINUATION frames.

+

The implementation of this function must return 0 if it succeeds or +NGHTTP2_ERR_CALLBACK_FAILURE. If nonzero value other than +NGHTTP2_ERR_CALLBACK_FAILURE is returned, it is treated as +if NGHTTP2_ERR_CALLBACK_FAILURE is returned. If +NGHTTP2_ERR_CALLBACK_FAILURE is returned, +nghttp2_session_mem_recv() function will immediately return +NGHTTP2_ERR_CALLBACK_FAILURE.

+
+
typedef int (*nghttp2_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)
@@ -1485,9 +1495,11 @@ typedef int (*nghttp2_on_header_callback)(< for the frame. When this callback is invoked, frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE. After all header name/value pairs are processed with this callback, -or header decompression error occurred, then -nghttp2_on_end_headers_callback will be invoked unless -application returns nonzero value from this callback.

+and no error has been detected, +nghttp2_on_frame_recv_callback will be invoked. If there +is an error in decompression, +nghttp2_on_frame_recv_callback for the frame will not be +invoked.

The name may be NULL if the namelen is 0. The same thing can be said about the value.

If the application uses nghttp2_session_mem_recv(), it can return @@ -1501,7 +1513,7 @@ region included in the input bytes.

Returning NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE will close the stream by issuing RST_STREAM with NGHTTP2_INTERNAL_ERROR. In this case, -nghttp2_on_end_headers_callback will not be invoked.

+nghttp2_on_frame_recv_callback will not be invoked.

The implementation of this function must return 0 if it succeeds. It may return NGHTTP2_ERR_PAUSE or NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE. For other critical @@ -1513,25 +1525,6 @@ the other nonzero value is returned, it is treated as immediately return NGHTTP2_ERR_CALLBACK_FAILURE.

-
-
-typedef int (*nghttp2_on_end_headers_callback)(nghttp2_session *session, const nghttp2_frame *frame, nghttp2_error_code error_code, void *user_data)
-

Callback function invoked when all header name/value pairs are -processed or after the header decompression error is detected. If -the error_code is NGHTTP2_NO_ERROR, it indicates the -header decompression succeeded. Otherwise, error prevented the -completion of the header decompression. In this case, the library -will handle the error by either transmitting RST_STREAM or GOAWAY -and terminate session.

-

If the error_code is not NGHTTP2_NO_ERROR, then -nghttp2_on_request_recv_callback will not called for this -frame if the frame is HEADERS.

-

The implementation of this function must return 0 if it -succeeds. If nonzero value is returned, it is treated as fatal -error and nghttp2_session_recv() and nghttp2_session_mem_recv() -functions immediately return NGHTTP2_ERR_CALLBACK_FAILURE.

-
-
nghttp2_session_callbacks
@@ -1596,13 +1589,6 @@ because of an error.

Callback function invoked when the stream is closed.

-
-
-nghttp2_on_request_recv_callback on_request_recv_callback
-

Callback function invoked when request from the remote peer is -received.

-
-
nghttp2_on_unknown_frame_recv_callback on_unknown_frame_recv_callback
@@ -1610,6 +1596,13 @@ received.

unknown.

+
+
+nghttp2_on_begin_headers_callback on_begin_headers_callback
+

Callback function invoked when the reception of header block in +HEADERS or PUSH_PROMISE is started.

+
+
nghttp2_on_header_callback on_header_callback
@@ -1617,13 +1610,6 @@ unknown.

received.

-
-
-nghttp2_on_end_headers_callback on_end_headers_callback
-

Callback function invoked when all header name/value pairs are -processed.

-
-
@@ -1810,9 +1796,7 @@ to receive DATA payload. For each chunk of data, is invoked.
  • If one DATA frame is completely received, nghttp2_session_callbacks.on_frame_recv_callback is -invoked. If the frame is the final frame of the request, -nghttp2_session_callbacks.on_request_recv_callback -is invoked. If the reception of the frame triggers the +invoked. If the reception of the frame triggers the closure of the stream, nghttp2_session_callbacks.on_stream_close_callback is invoked.
  • @@ -1821,17 +1805,19 @@ is invoked.
  • If the frame is the control frame:
    1. nghttp2_session_callbacks.recv_callback is invoked one or more times to receive whole frame.
    2. -
    3. If the received frame is valid, -nghttp2_session_callbacks.on_frame_recv_callback is -invoked. If frame is either HEADERS or PUSH_PROMISE, +
    4. If the received frame is valid, then following actions are +taken. If the frame is either HEADERS or PUSH_PROMISE, +nghttp2_session_callbacks.on_begin_headers_callback +is invoked. Then nghttp2_session_callbacks.on_header_callback is invoked for each header name/value pair. After all name/value -pairs are emitted (or decompression failed), -nghttp2_session_callbacks.on_end_headers_callback -is invoked. If the frame is the final frame of the request, -nghttp2_session_callbacks.on_request_recv_callback -is invoked. If the reception of the frame triggers the -closure of the stream, +pairs are emitted successfully, +nghttp2_session_callbacks.on_frame_recv_callback is +invoked. For other frames, +nghttp2_session_callbacks.on_frame_recv_callback is +invoked. +If the reception of the frame triggers the closure of the +stream, nghttp2_session_callbacks.on_stream_close_callback is invoked.
    5. If the received frame is unpacked but is interpreted as diff --git a/genindex.html b/genindex.html index 8612d03b..182375d0 100644 --- a/genindex.html +++ b/genindex.html @@ -606,18 +606,18 @@
      nghttp2_nv.valuelen (C member)
      +
  • +
    nghttp2_nv_compare_name (C function)
    -
    -
    -
    nghttp2_on_data_chunk_recv_callback (C type) +
    nghttp2_on_begin_headers_callback (C type)
    -
    nghttp2_on_end_headers_callback (C type) +
    nghttp2_on_data_chunk_recv_callback (C type)
    @@ -641,10 +641,6 @@ -
    nghttp2_on_request_recv_callback (C type) -
    - -
    nghttp2_on_stream_close_callback (C type)
    @@ -805,11 +801,11 @@ -
    nghttp2_session_callbacks.on_data_chunk_recv_callback (C member) +
    nghttp2_session_callbacks.on_begin_headers_callback (C member)
    -
    nghttp2_session_callbacks.on_end_headers_callback (C member) +
    nghttp2_session_callbacks.on_data_chunk_recv_callback (C member)
    @@ -833,10 +829,6 @@ -
    nghttp2_session_callbacks.on_request_recv_callback (C member) -
    - -
    nghttp2_session_callbacks.on_stream_close_callback (C member)
    diff --git a/nghttp2.h.html b/nghttp2.h.html index 87f9357e..859c7f89 100644 --- a/nghttp2.h.html +++ b/nghttp2.h.html @@ -1031,6 +1031,16 @@ * respectively. The header name/value pairs are emitted via * :type:`nghttp2_on_header_callback`. * + * For HEADERS, PUSH_PROMISE and DATA frames, this callback may be + * called after stream is closed (see + * :type:`nghttp2_on_stream_close_callback`). The application should + * check that stream is still alive using its own stream management or + * :func:`nghttp2_session_get_stream_user_data()`. + * + * Only HEADERS and DATA frame can signal the end of incoming data. If + * ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` is nonzero, the + * |frame| is the last frame from the remote peer in this stream. + * * The implementation of this function must return 0 if it * succeeds. If nonzero value is returned, it is treated as fatal * error and `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` @@ -1054,10 +1064,6 @@ * member of their data structure are always ``NULL`` and 0 * respectively. * - * If this callback is called, :type:`nghttp2_on_header_callback` and - * :type:`nghttp2_on_end_headers_callback` will not be called for this - * frame. - * * The implementation of this function must return 0 if it * succeeds. If nonzero is returned, it is treated as fatal error and * `nghttp2_session_recv()` and `nghttp2_session_send()` functions @@ -1171,24 +1177,6 @@ (nghttp2_session *session, int32_t stream_id, nghttp2_error_code error_code, void *user_data); -/** - * @functypedef - * - * Callback function invoked when the request from the remote peer is - * received. In other words, the frame with END_STREAM flag set is - * received. In HTTP, this means HTTP request, including request - * body, is fully received. The |user_data| pointer is the third - * argument passed in to the call to `nghttp2_session_client_new()` or - * `nghttp2_session_server_new()`. - * - * The implementation of this function must return 0 if it - * succeeds. If nonzero is returned, it is treated as fatal error and - * `nghttp2_session_recv()` and `nghttp2_session_send()` functions - * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. - */ -typedef int (*nghttp2_on_request_recv_callback) -(nghttp2_session *session, int32_t stream_id, void *user_data); - /** * @functypedef * @@ -1214,6 +1202,30 @@ const uint8_t *payload, size_t payloadlen, void *user_data); +/** + * @functypedef + * + * Callback function invoked when the reception of header block in + * HEADERS or PUSH_PROMISE is started. Each header name/value pair + * will be emitted by :type:`nghttp2_on_header_callback`. + * + * The ``frame->hd.flags`` may not have + * :enum:`NGHTTP2_FLAG_END_HEADERS` flag set, which indicates that one + * or more CONTINUATION frames are involved. But the application does + * not need to care about that because the header name/value pairs are + * emitted transparently regardless of CONTINUATION frames. + * + * The implementation of this function must return 0 if it succeeds or + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If nonzero value other than + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned, it is treated as + * if :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. If + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned, + * `nghttp2_session_mem_recv()` function will immediately return + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + */ +typedef int (*nghttp2_on_begin_headers_callback) +(nghttp2_session *session, const nghttp2_frame *frame, void *user_data); + /** * @functypedef * @@ -1221,9 +1233,11 @@ * for the |frame|. When this callback is invoked, ``frame->hd.type`` * is either :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`. * After all header name/value pairs are processed with this callback, - * or header decompression error occurred, then - * :type:`nghttp2_on_end_headers_callback` will be invoked unless - * application returns nonzero value from this callback. + * and no error has been detected, + * :type:`nghttp2_on_frame_recv_callback` will be invoked. If there + * is an error in decompression, + * :type:`nghttp2_on_frame_recv_callback` for the |frame| will not be + * invoked. * * The |name| may be ``NULL`` if the |namelen| is 0. The same thing * can be said about the |value|. @@ -1240,7 +1254,7 @@ * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close * the stream by issuing RST_STREAM with * :enum:`NGHTTP2_INTERNAL_ERROR`. In this case, - * :type:`nghttp2_on_end_headers_callback` will not be invoked. + * :type:`nghttp2_on_frame_recv_callback` will not be invoked. * * The implementation of this function must return 0 if it * succeeds. It may return :enum:`NGHTTP2_ERR_PAUSE` or @@ -1259,32 +1273,6 @@ const uint8_t *value, size_t valuelen, void *user_data); -/** - * @functypedef - * - * Callback function invoked when all header name/value pairs are - * processed or after the header decompression error is detected. If - * the |error_code| is :enum:`NGHTTP2_NO_ERROR`, it indicates the - * header decompression succeeded. Otherwise, error prevented the - * completion of the header decompression. In this case, the library - * will handle the error by either transmitting RST_STREAM or GOAWAY - * and terminate session. - * - * If the |error_code| is not :enum:`NGHTTP2_NO_ERROR`, then - * :type:`nghttp2_on_request_recv_callback` will not called for this - * frame if the |frame| is HEADERS. - * - * The implementation of this function must return 0 if it - * succeeds. If nonzero value is returned, it is treated as fatal - * error and `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` - * functions immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. - */ -typedef int (*nghttp2_on_end_headers_callback) -(nghttp2_session *session, - const nghttp2_frame *frame, - nghttp2_error_code error_code, - void *user_data); - /** * @struct * @@ -1334,25 +1322,20 @@ */ nghttp2_on_stream_close_callback on_stream_close_callback; /** - * Callback function invoked when request from the remote peer is - * received. - */ - nghttp2_on_request_recv_callback on_request_recv_callback; - /** * Callback function invoked when the received frame type is * unknown. */ nghttp2_on_unknown_frame_recv_callback on_unknown_frame_recv_callback; /** + * Callback function invoked when the reception of header block in + * HEADERS or PUSH_PROMISE is started. + */ + nghttp2_on_begin_headers_callback on_begin_headers_callback; + /** * Callback function invoked when a header name/value pair is * received. */ nghttp2_on_header_callback on_header_callback; - /** - * Callback function invoked when all header name/value pairs are - * processed. - */ - nghttp2_on_end_headers_callback on_end_headers_callback; } nghttp2_session_callbacks; /** @@ -1589,9 +1572,7 @@ * is invoked. * 2. If one DATA frame is completely received, * :member:`nghttp2_session_callbacks.on_frame_recv_callback` is - * invoked. If the frame is the final frame of the request, - * :member:`nghttp2_session_callbacks.on_request_recv_callback` - * is invoked. If the reception of the frame triggers the + * invoked. If the reception of the frame triggers the * closure of the stream, * :member:`nghttp2_session_callbacks.on_stream_close_callback` * is invoked. @@ -1600,17 +1581,20 @@ * * 1. :member:`nghttp2_session_callbacks.recv_callback` is invoked * one or more times to receive whole frame. - * 2. If the received frame is valid, - * :member:`nghttp2_session_callbacks.on_frame_recv_callback` is - * invoked. If frame is either HEADERS or PUSH_PROMISE, + * + * 2. If the received frame is valid, then following actions are + * taken. If the frame is either HEADERS or PUSH_PROMISE, + * :member:`nghttp2_session_callbacks.on_begin_headers_callback` + * is invoked. Then * :member:`nghttp2_session_callbacks.on_header_callback` is * invoked for each header name/value pair. After all name/value - * pairs are emitted (or decompression failed), - * :member:`nghttp2_session_callbacks.on_end_headers_callback` - * is invoked. If the frame is the final frame of the request, - * :member:`nghttp2_session_callbacks.on_request_recv_callback` - * is invoked. If the reception of the frame triggers the - * closure of the stream, + * pairs are emitted successfully, + * :member:`nghttp2_session_callbacks.on_frame_recv_callback` is + * invoked. For other frames, + * :member:`nghttp2_session_callbacks.on_frame_recv_callback` is + * invoked. + * If the reception of the frame triggers the closure of the + * stream, * :member:`nghttp2_session_callbacks.on_stream_close_callback` * is invoked. * 3. If the received frame is unpacked but is interpreted as diff --git a/objects.inv b/objects.inv index 6abc42c85314812bd1db39c79d58b4b20206dff5..32755a762e2a3ba9f03c737d85a30c502f91fe80 100644 GIT binary patch delta 1990 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.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; + callbacks.on_begin_headers_callback = on_begin_headers_callback; nghttp2_session_client_new(&session_data->session, &callbacks, session_data); } @@ -508,29 +508,6 @@ unnecessary to compare them, but real applications surely deal with multiple streams, and stream_user_data is very handy to identify which HEADERS we are seeing in the callback. Therefore we just show 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 -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,
    @@ -555,18 +532,16 @@ its stream ID.

    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)
    +on_frame_recv_callback function is called:

    +
    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, "All headers received with error_code=%d\n", error_code);
    +      fprintf(stderr, "All headers received\n");
         }
         break;
       }
    @@ -574,8 +549,10 @@ its stream ID.

    }
    -

    This callback may be called prematurely because of errors (e.g., -header decompression failure) which is indicated by error_code.

    +

    In this tutorial, we are just interested in the HTTP response +HEADERS. We check te frame type and its category (it should be +NGHTTP2_HCAT_RESPONSE for HTTP response HEADERS). Also check +its stream ID.

    The on_data_chunk_recv_callback() function is invoked when a chunk of data is received from the remote peer:

    static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
    @@ -859,30 +836,11 @@ here.

    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, - const nghttp2_frame *frame, void *user_data) +/* nghttp2_on_begin_headers_callback: Called when nghttp2 library gets + started to receive header block. */ +static int on_begin_headers_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) { @@ -897,6 +855,23 @@ here.

    return 0; } +/* nghttp2_on_frame_recv_callback: Called when nghttp2 library + received a complete frame 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, "All headers received\n"); + } + break; + } + return 0; +} + /* nghttp2_on_data_chunk_recv_callback: Called when DATA frame is received from the remote peer. In this implementation, if the frame is meant to the stream we initiated, print the received data in @@ -989,7 +964,7 @@ here.

    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; + callbacks.on_begin_headers_callback = on_begin_headers_callback; nghttp2_session_client_new(&session_data->session, &callbacks, session_data); } diff --git a/tutorial-server.html b/tutorial-server.html index 90ff26ac..d9cf7bcf 100644 --- a/tutorial-server.html +++ b/tutorial-server.html @@ -367,9 +367,9 @@ these 2 functions later.

    callbacks.send_callback = send_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_header_callback = on_header_callback; + callbacks.on_begin_headers_callback = on_begin_headers_callback; nghttp2_session_server_new(&session_data->session, &callbacks, session_data); }
    @@ -534,25 +534,22 @@ pending data when output buffer becomes empty.

    We have already described about nghttp2 callback send_callback(). Let’s describe remaining nghttp2 callbacks we setup in initialize_nghttp2_setup() function.

    -

    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)
    +

    The on_begin_headers_callback() function is invoked when reception +of header block in HEADERS or PUSH_PROMISE frame is started:

    +
    static int on_begin_headers_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;
    -  switch(frame->hd.type) {
    -  case NGHTTP2_HEADERS:
    -    if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
    -      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);
    -    break;
    -  default:
    -    break;
    +
    +  if(frame->hd.type != NGHTTP2_HEADERS ||
    +     frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
    +    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);
       return 0;
     }
     
    @@ -567,7 +564,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 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():

    +on_begin_headers_callback():

    static int on_header_callback(nghttp2_session *session,
                                   const nghttp2_frame *frame,
                                   const uint8_t *name, size_t namelen,
    @@ -601,59 +598,37 @@ is emitted via on_header_callback
     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:

    -
    static int on_request_recv_callback(nghttp2_session *session,
    -                                    int32_t stream_id, void *user_data)
    +

    The on_frame_recv_callback() function is invoked when a frame is +fully received:

    +
    static int on_frame_recv_callback(nghttp2_session *session,
    +                                  const nghttp2_frame *frame, void *user_data)
     {
    -  int fd;
       http2_session_data *session_data = (http2_session_data*)user_data;
       http2_stream_data *stream_data;
    -  nghttp2_nv hdrs[] = {
    -    MAKE_NV(":status", "200")
    -  };
    -  char *rel_path;
    -
    -  stream_data = (http2_stream_data*)nghttp2_session_get_stream_user_data
    -    (session, stream_id);
    -  if(!stream_data->request_path) {
    -    if(error_reply(session, stream_data) != 0) {
    -      return NGHTTP2_ERR_CALLBACK_FAILURE;
    +  switch(frame->hd.type) {
    +  case NGHTTP2_DATA:
    +  case NGHTTP2_HEADERS:
    +    /* Check that the client request has finished */
    +    if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
    +      stream_data = nghttp2_session_get_stream_user_data(session,
    +                                                         frame->hd.stream_id);
    +      /* For DATA and HEADERS frame, this callback may be called after
    +         on_stream_close_callback. Check that stream still alive. */
    +      if(!stream_data) {
    +        return 0;
    +      }
    +      return on_request_recv(session, session_data, stream_data);
         }
    -    return 0;
    -  }
    -  fprintf(stderr, "%s GET %s\n", session_data->client_addr,
    -          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;
    +    break;
    +  default:
    +    break;
       }
       return 0;
     }
     

    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 be served for some reasons (e.g., file is not found), we send 404 response, which is done in error_reply(). Otherwise, we open @@ -1056,56 +1031,6 @@ stream is about to close and we no longer use that object.

    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; - switch(frame->hd.type) { - case NGHTTP2_HEADERS: - if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) { - 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); - break; - default: - break; - } - return 0; -} - static ssize_t file_read_callback (nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length, int *eof, @@ -1174,6 +1099,53 @@ stream is about to close and we no longer use that object.

    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_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_begin_headers_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; + + if(frame->hd.type != NGHTTP2_HEADERS || + frame->headers.cat != NGHTTP2_HCAT_REQUEST) { + 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); + return 0; +} + /* Minimum check for directory traversal. Returns nonzero if it is safe. */ static int check_path(const char *path) @@ -1186,19 +1158,16 @@ stream is about to close and we no longer use that object.

    !ends_with(path, "/..") && !ends_with(path, "/."); } -static int on_request_recv_callback(nghttp2_session *session, - int32_t stream_id, void *user_data) +static int on_request_recv(nghttp2_session *session, + http2_session_data *session_data, + http2_stream_data *stream_data) { int fd; - http2_session_data *session_data = (http2_session_data*)user_data; - http2_stream_data *stream_data; nghttp2_nv hdrs[] = { MAKE_NV(":status", "200") }; char *rel_path; - stream_data = (http2_stream_data*)nghttp2_session_get_stream_user_data - (session, stream_id); if(!stream_data->request_path) { if(error_reply(session, stream_data) != 0) { return NGHTTP2_ERR_CALLBACK_FAILURE; @@ -1223,13 +1192,40 @@ stream is about to close and we no longer use that object.

    } stream_data->fd = fd; - if(send_response(session, stream_id, hdrs, ARRLEN(hdrs), fd) != 0) { + if(send_response(session, stream_data->stream_id, hdrs, + ARRLEN(hdrs), fd) != 0) { close(fd); return NGHTTP2_ERR_CALLBACK_FAILURE; } 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; + switch(frame->hd.type) { + case NGHTTP2_DATA: + case NGHTTP2_HEADERS: + /* Check that the client request has finished */ + if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { + stream_data = nghttp2_session_get_stream_user_data(session, + frame->hd.stream_id); + /* For DATA and HEADERS frame, this callback may be called after + on_stream_close_callback. Check that stream still alive. */ + if(!stream_data) { + return 0; + } + return on_request_recv(session, session_data, stream_data); + } + break; + default: + break; + } + return 0; +} + static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id, nghttp2_error_code error_code, @@ -1250,9 +1246,9 @@ stream is about to close and we no longer use that object.

    callbacks.send_callback = send_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_header_callback = on_header_callback; + callbacks.on_begin_headers_callback = on_begin_headers_callback; nghttp2_session_server_new(&session_data->session, &callbacks, session_data); }