Replace on_end_headers_callback with on_begin_headers_callback
Previously, there is inconsistency when on_frame_recv_callback is called between HEADERS/PUSH_PROMISE and the other frames. For former case, it is called before header block, in latter case, it is called after whole frame is received. To make it consistent, we call on_frame_recv_callback for HEADERS/PUSH_PROMISE after its frame is fully received. Since on_frame_recv_callback can signal the end of header block, we replaced on_end_headers_callback with on_begin_headers_callback, which is called when the reception of the header block is started.
This commit is contained in:
parent
ff475104ab
commit
e186e01933
|
@ -231,30 +231,11 @@ static int on_header_callback(nghttp2_session *session,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* nghttp2_on_end_headers_callback: Called when nghttp2 library emits
|
/* nghttp2_on_begin_headers_callback: Called when nghttp2 library gets
|
||||||
all header name/value pairs, or may be called prematurely because
|
started to receive header block. */
|
||||||
of errors which is indicated by |error_code|. */
|
static int on_begin_headers_callback(nghttp2_session *session,
|
||||||
static int on_end_headers_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;
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
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) {
|
||||||
|
@ -269,6 +250,23 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
||||||
return 0;
|
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
|
/* nghttp2_on_data_chunk_recv_callback: Called when DATA frame is
|
||||||
received from the remote peer. In this implementation, if the frame
|
received from the remote peer. In this implementation, if the frame
|
||||||
is meant to the stream we initiated, print the received data in
|
is meant to the stream we initiated, print the received data in
|
||||||
|
@ -361,7 +359,7 @@ static void initialize_nghttp2_session(http2_session_data *session_data)
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -325,56 +325,6 @@ static char* percent_decode(const uint8_t *value, size_t valuelen)
|
||||||
return res;
|
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
|
static ssize_t file_read_callback
|
||||||
(nghttp2_session *session, int32_t stream_id,
|
(nghttp2_session *session, int32_t stream_id,
|
||||||
uint8_t *buf, size_t length, int *eof,
|
uint8_t *buf, size_t length, int *eof,
|
||||||
|
@ -443,6 +393,53 @@ static int error_reply(nghttp2_session *session,
|
||||||
return 0;
|
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
|
/* Minimum check for directory traversal. Returns nonzero if it is
|
||||||
safe. */
|
safe. */
|
||||||
static int check_path(const char *path)
|
static int check_path(const char *path)
|
||||||
|
@ -455,19 +452,16 @@ static int check_path(const char *path)
|
||||||
!ends_with(path, "/..") && !ends_with(path, "/.");
|
!ends_with(path, "/..") && !ends_with(path, "/.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_request_recv_callback(nghttp2_session *session,
|
static int on_request_recv(nghttp2_session *session,
|
||||||
int32_t stream_id, void *user_data)
|
http2_session_data *session_data,
|
||||||
|
http2_stream_data *stream_data)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
|
||||||
http2_stream_data *stream_data;
|
|
||||||
nghttp2_nv hdrs[] = {
|
nghttp2_nv hdrs[] = {
|
||||||
MAKE_NV(":status", "200")
|
MAKE_NV(":status", "200")
|
||||||
};
|
};
|
||||||
char *rel_path;
|
char *rel_path;
|
||||||
|
|
||||||
stream_data = (http2_stream_data*)nghttp2_session_get_stream_user_data
|
|
||||||
(session, stream_id);
|
|
||||||
if(!stream_data->request_path) {
|
if(!stream_data->request_path) {
|
||||||
if(error_reply(session, stream_data) != 0) {
|
if(error_reply(session, stream_data) != 0) {
|
||||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||||
|
@ -492,13 +486,40 @@ static int on_request_recv_callback(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
stream_data->fd = fd;
|
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);
|
close(fd);
|
||||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||||
}
|
}
|
||||||
return 0;
|
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,
|
static int on_stream_close_callback(nghttp2_session *session,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
nghttp2_error_code error_code,
|
nghttp2_error_code error_code,
|
||||||
|
@ -519,9 +540,9 @@ static void initialize_nghttp2_session(http2_session_data *session_data)
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -916,10 +916,6 @@ typedef int (*nghttp2_on_frame_recv_callback)
|
||||||
* member of their data structure are always ``NULL`` and 0
|
* member of their data structure are always ``NULL`` and 0
|
||||||
* respectively.
|
* 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
|
* The implementation of this function must return 0 if it
|
||||||
* succeeds. If nonzero is returned, it is treated as fatal error and
|
* succeeds. If nonzero is returned, it is treated as fatal error and
|
||||||
* `nghttp2_session_recv()` and `nghttp2_session_send()` functions
|
* `nghttp2_session_recv()` and `nghttp2_session_send()` functions
|
||||||
|
@ -1076,6 +1072,30 @@ typedef int (*nghttp2_on_unknown_frame_recv_callback)
|
||||||
const uint8_t *payload, size_t payloadlen,
|
const uint8_t *payload, size_t payloadlen,
|
||||||
void *user_data);
|
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
|
* @functypedef
|
||||||
*
|
*
|
||||||
|
@ -1083,9 +1103,11 @@ typedef int (*nghttp2_on_unknown_frame_recv_callback)
|
||||||
* for the |frame|. When this callback is invoked, ``frame->hd.type``
|
* for the |frame|. When this callback is invoked, ``frame->hd.type``
|
||||||
* is either :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`.
|
* is either :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`.
|
||||||
* After all header name/value pairs are processed with this callback,
|
* After all header name/value pairs are processed with this callback,
|
||||||
* or header decompression error occurred, then
|
* and no error has been detected,
|
||||||
* :type:`nghttp2_on_end_headers_callback` will be invoked unless
|
* :type:`nghttp2_on_frame_recv_callback` will be invoked. If there
|
||||||
* application returns nonzero value from this callback.
|
* 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
|
* The |name| may be ``NULL`` if the |namelen| is 0. The same thing
|
||||||
* can be said about the |value|.
|
* can be said about the |value|.
|
||||||
|
@ -1102,7 +1124,7 @@ typedef int (*nghttp2_on_unknown_frame_recv_callback)
|
||||||
* Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close
|
* Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close
|
||||||
* the stream by issuing RST_STREAM with
|
* the stream by issuing RST_STREAM with
|
||||||
* :enum:`NGHTTP2_INTERNAL_ERROR`. In this case,
|
* :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
|
* The implementation of this function must return 0 if it
|
||||||
* succeeds. It may return :enum:`NGHTTP2_ERR_PAUSE` or
|
* succeeds. It may return :enum:`NGHTTP2_ERR_PAUSE` or
|
||||||
|
@ -1121,32 +1143,6 @@ typedef int (*nghttp2_on_header_callback)
|
||||||
const uint8_t *value, size_t valuelen,
|
const uint8_t *value, size_t valuelen,
|
||||||
void *user_data);
|
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
|
* @struct
|
||||||
*
|
*
|
||||||
|
@ -1205,16 +1201,16 @@ typedef struct {
|
||||||
* unknown.
|
* unknown.
|
||||||
*/
|
*/
|
||||||
nghttp2_on_unknown_frame_recv_callback on_unknown_frame_recv_callback;
|
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
|
* Callback function invoked when a header name/value pair is
|
||||||
* received.
|
* received.
|
||||||
*/
|
*/
|
||||||
nghttp2_on_header_callback on_header_callback;
|
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;
|
} nghttp2_session_callbacks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1462,14 +1458,19 @@ int nghttp2_session_send(nghttp2_session *session);
|
||||||
*
|
*
|
||||||
* 1. :member:`nghttp2_session_callbacks.recv_callback` is invoked
|
* 1. :member:`nghttp2_session_callbacks.recv_callback` is invoked
|
||||||
* one or more times to receive whole frame.
|
* one or more times to receive whole frame.
|
||||||
* 2. If the received frame is valid,
|
*
|
||||||
* :member:`nghttp2_session_callbacks.on_frame_recv_callback` is
|
* 2. If the received frame is valid, then following actions are
|
||||||
* invoked. If frame is either HEADERS or PUSH_PROMISE,
|
* 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
|
* :member:`nghttp2_session_callbacks.on_header_callback` is
|
||||||
* invoked for each header name/value pair. After all name/value
|
* invoked for each header name/value pair. After all name/value
|
||||||
* pairs are emitted (or decompression failed),
|
* pairs are emitted successfully,
|
||||||
* :member:`nghttp2_session_callbacks.on_end_headers_callback`
|
* :member:`nghttp2_session_callbacks.on_frame_recv_callback` is
|
||||||
* is invoked. If the frame is the final frame of the request,
|
* invoked. For other frames,
|
||||||
|
* :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`
|
* :member:`nghttp2_session_callbacks.on_request_recv_callback`
|
||||||
* is invoked. If the reception of the frame triggers the
|
* is invoked. If the reception of the frame triggers the
|
||||||
* closure of the stream,
|
* closure of the stream,
|
||||||
|
|
|
@ -1851,6 +1851,22 @@ static int nghttp2_session_call_on_frame_received
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int session_call_on_begin_headers(nghttp2_session *session,
|
||||||
|
nghttp2_frame *frame)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
DEBUGF(fprintf(stderr, "Call on_begin_headers callback stream_id=%d\n",
|
||||||
|
frame->hd.stream_id));
|
||||||
|
if(session->callbacks.on_begin_headers_callback) {
|
||||||
|
rv = session->callbacks.on_begin_headers_callback(session, frame,
|
||||||
|
session->user_data);
|
||||||
|
if(rv != 0) {
|
||||||
|
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int session_call_on_header(nghttp2_session *session,
|
static int session_call_on_header(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame,
|
const nghttp2_frame *frame,
|
||||||
const nghttp2_nv *nv)
|
const nghttp2_nv *nv)
|
||||||
|
@ -1872,22 +1888,6 @@ static int session_call_on_header(nghttp2_session *session,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int session_call_on_end_headers
|
|
||||||
(nghttp2_session *session, nghttp2_frame *frame, nghttp2_error_code error_code)
|
|
||||||
{
|
|
||||||
int rv;
|
|
||||||
DEBUGF(fprintf(stderr, "Call on_end_headers callback stream_id=%d\n",
|
|
||||||
frame->hd.stream_id));
|
|
||||||
if(session->callbacks.on_end_headers_callback) {
|
|
||||||
rv = session->callbacks.on_end_headers_callback(session, frame, error_code,
|
|
||||||
session->user_data);
|
|
||||||
if(rv != 0) {
|
|
||||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks whether received stream_id is valid.
|
* Checks whether received stream_id is valid.
|
||||||
* This function returns 1 if it succeeds, or 0.
|
* This function returns 1 if it succeeds, or 0.
|
||||||
|
@ -1931,12 +1931,12 @@ static int nghttp2_session_validate_request_headers(nghttp2_session *session,
|
||||||
* bytes. If this function returns NGHTTP2_ERR_PAUSE, the caller must
|
* bytes. If this function returns NGHTTP2_ERR_PAUSE, the caller must
|
||||||
* call this function again, until it returns 0 or one of negative
|
* call this function again, until it returns 0 or one of negative
|
||||||
* error code. If |call_header_cb| is zero, the on_header_callback
|
* error code. If |call_header_cb| is zero, the on_header_callback
|
||||||
* and on_end_headers_callback are not invoked and the function never
|
* are not invoked and the function never return NGHTTP2_ERR_PAUSE. If
|
||||||
* return NGHTTP2_ERR_PAUSE. If the given |in| is the last chunk of
|
* the given |in| is the last chunk of header block, the |final| must
|
||||||
* header block, the |final| must be nonzero. If header block is
|
* be nonzero. If header block is successfully processed (which is
|
||||||
* successfully processed (which is indicated by the return value 0,
|
* indicated by the return value 0, NGHTTP2_ERR_PAUSE or
|
||||||
* NGHTTP2_ERR_PAUSE or NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE), the
|
* NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE), the number of processed
|
||||||
* number of processed input bytes is assigned to the |*readlen_ptr|.
|
* input bytes is assigned to the |*readlen_ptr|.
|
||||||
*
|
*
|
||||||
* This function return 0 if it succeeds, or one of the negative error
|
* This function return 0 if it succeeds, or one of the negative error
|
||||||
* codes:
|
* codes:
|
||||||
|
@ -1973,13 +1973,6 @@ static ssize_t inflate_header_block(nghttp2_session *session,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
if(rv < 0) {
|
if(rv < 0) {
|
||||||
if(call_header_cb) {
|
|
||||||
rv = session_call_on_end_headers(session, frame,
|
|
||||||
NGHTTP2_COMPRESSION_ERROR);
|
|
||||||
if(rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rv = nghttp2_session_terminate_session(session,
|
rv = nghttp2_session_terminate_session(session,
|
||||||
NGHTTP2_COMPRESSION_ERROR);
|
NGHTTP2_COMPRESSION_ERROR);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
|
@ -2000,14 +1993,9 @@ static ssize_t inflate_header_block(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
|
if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
|
||||||
nghttp2_hd_inflate_end_headers(&session->hd_inflater);
|
nghttp2_hd_inflate_end_headers(&session->hd_inflater);
|
||||||
if(call_header_cb) {
|
|
||||||
rv = session_call_on_end_headers(session, frame, NGHTTP2_NO_ERROR);
|
|
||||||
if(rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
} else if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) {
|
}
|
||||||
|
if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2107,15 +2095,11 @@ static int nghttp2_session_inflate_handle_invalid_connection
|
||||||
* Out of memory.
|
* Out of memory.
|
||||||
*/
|
*/
|
||||||
int nghttp2_session_end_request_headers_received(nghttp2_session *session,
|
int nghttp2_session_end_request_headers_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame)
|
nghttp2_frame *frame,
|
||||||
|
nghttp2_stream *stream)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||||
nghttp2_stream *stream;
|
|
||||||
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
|
||||||
if(!stream) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
||||||
rv = nghttp2_session_call_on_request_recv(session, frame->hd.stream_id);
|
rv = nghttp2_session_call_on_request_recv(session, frame->hd.stream_id);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
|
@ -2140,17 +2124,13 @@ int nghttp2_session_end_request_headers_received(nghttp2_session *session,
|
||||||
* Out of memory.
|
* Out of memory.
|
||||||
*/
|
*/
|
||||||
int nghttp2_session_end_response_headers_received(nghttp2_session *session,
|
int nghttp2_session_end_response_headers_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame)
|
nghttp2_frame *frame,
|
||||||
|
nghttp2_stream *stream)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||||
/* This is the last frame of this stream, so disallow
|
/* This is the last frame of this stream, so disallow
|
||||||
further receptions. */
|
further receptions. */
|
||||||
nghttp2_stream *stream;
|
|
||||||
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
|
||||||
if(!stream) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
||||||
rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream);
|
rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream);
|
||||||
if(nghttp2_is_fatal(rv)) {
|
if(nghttp2_is_fatal(rv)) {
|
||||||
|
@ -2174,11 +2154,11 @@ int nghttp2_session_end_response_headers_received(nghttp2_session *session,
|
||||||
* Out of memory.
|
* Out of memory.
|
||||||
*/
|
*/
|
||||||
int nghttp2_session_end_headers_received(nghttp2_session *session,
|
int nghttp2_session_end_headers_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame)
|
nghttp2_frame *frame,
|
||||||
|
nghttp2_stream *stream)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||||
nghttp2_stream *stream;
|
|
||||||
if(!nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) {
|
if(!nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) {
|
||||||
rv = nghttp2_session_call_on_request_recv(session,
|
rv = nghttp2_session_call_on_request_recv(session,
|
||||||
frame->hd.stream_id);
|
frame->hd.stream_id);
|
||||||
|
@ -2186,10 +2166,6 @@ int nghttp2_session_end_headers_received(nghttp2_session *session,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
|
||||||
if(!stream) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
||||||
rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream);
|
rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream);
|
||||||
if(nghttp2_is_fatal(rv)) {
|
if(nghttp2_is_fatal(rv)) {
|
||||||
|
@ -2199,17 +2175,35 @@ int nghttp2_session_end_headers_received(nghttp2_session *session,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int session_post_process_headers_frame(nghttp2_session *session)
|
static int session_after_header_block_received(nghttp2_session *session)
|
||||||
{
|
{
|
||||||
|
int rv;
|
||||||
nghttp2_frame *frame = &session->iframe.frame;
|
nghttp2_frame *frame = &session->iframe.frame;
|
||||||
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
|
/* We call on_frame_recv_callback regardless of the existence of
|
||||||
|
stream */
|
||||||
|
rv = nghttp2_session_call_on_frame_received(session, frame);
|
||||||
|
if(nghttp2_is_fatal(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
if(frame->hd.type != NGHTTP2_HEADERS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
||||||
|
if(!stream) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
switch(frame->headers.cat) {
|
switch(frame->headers.cat) {
|
||||||
case NGHTTP2_HCAT_REQUEST:
|
case NGHTTP2_HCAT_REQUEST:
|
||||||
return nghttp2_session_end_request_headers_received(session, frame);
|
return nghttp2_session_end_request_headers_received
|
||||||
|
(session, frame, stream);
|
||||||
case NGHTTP2_HCAT_RESPONSE:
|
case NGHTTP2_HCAT_RESPONSE:
|
||||||
case NGHTTP2_HCAT_PUSH_RESPONSE:
|
case NGHTTP2_HCAT_PUSH_RESPONSE:
|
||||||
return nghttp2_session_end_response_headers_received(session, frame);
|
return nghttp2_session_end_response_headers_received
|
||||||
|
(session, frame, stream);
|
||||||
case NGHTTP2_HCAT_HEADERS:
|
case NGHTTP2_HCAT_HEADERS:
|
||||||
return nghttp2_session_end_headers_received(session, frame);
|
return nghttp2_session_end_headers_received(session, frame, stream);
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
@ -2256,7 +2250,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
|
||||||
return NGHTTP2_ERR_NOMEM;
|
return NGHTTP2_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
session->last_proc_stream_id = session->last_recv_stream_id;
|
session->last_proc_stream_id = session->last_recv_stream_id;
|
||||||
rv = nghttp2_session_call_on_frame_received(session, frame);
|
rv = session_call_on_begin_headers(session, frame);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -2287,7 +2281,7 @@ int nghttp2_session_on_response_headers_received(nghttp2_session *session,
|
||||||
(session, frame, NGHTTP2_STREAM_CLOSED);
|
(session, frame, NGHTTP2_STREAM_CLOSED);
|
||||||
}
|
}
|
||||||
stream->state = NGHTTP2_STREAM_OPENED;
|
stream->state = NGHTTP2_STREAM_OPENED;
|
||||||
rv = nghttp2_session_call_on_frame_received(session, frame);
|
rv = session_call_on_begin_headers(session, frame);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -2314,7 +2308,7 @@ int nghttp2_session_on_push_response_headers_received(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
nghttp2_stream_promise_fulfilled(stream);
|
nghttp2_stream_promise_fulfilled(stream);
|
||||||
++session->num_incoming_streams;
|
++session->num_incoming_streams;
|
||||||
rv = nghttp2_session_call_on_frame_received(session, frame);
|
rv = session_call_on_begin_headers(session, frame);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -2350,7 +2344,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
if(nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) {
|
if(nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) {
|
||||||
if(stream->state == NGHTTP2_STREAM_OPENED) {
|
if(stream->state == NGHTTP2_STREAM_OPENED) {
|
||||||
r = nghttp2_session_call_on_frame_received(session, frame);
|
r = session_call_on_begin_headers(session, frame);
|
||||||
if(r != 0) {
|
if(r != 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -2370,7 +2364,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
|
||||||
NGHTTP2_STREAM_CLOSING, we discard the frame. This is a race
|
NGHTTP2_STREAM_CLOSING, we discard the frame. This is a race
|
||||||
condition. */
|
condition. */
|
||||||
if(stream->state != NGHTTP2_STREAM_CLOSING) {
|
if(stream->state != NGHTTP2_STREAM_CLOSING) {
|
||||||
r = nghttp2_session_call_on_frame_received(session, frame);
|
r = session_call_on_begin_headers(session, frame);
|
||||||
if(r != 0) {
|
if(r != 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -2945,7 +2939,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||||
return NGHTTP2_ERR_NOMEM;
|
return NGHTTP2_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
session->last_proc_stream_id = session->last_recv_stream_id;
|
session->last_proc_stream_id = session->last_recv_stream_id;
|
||||||
rv = nghttp2_session_call_on_frame_received(session, frame);
|
rv = session_call_on_begin_headers(session, frame);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3650,8 +3644,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
if(rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
if(rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||||
/* The application says no more headers. We decompress the
|
/* The application says no more headers. We decompress the
|
||||||
rest of the header block but not invoke
|
rest of the header block but not invoke on_header_callback
|
||||||
on_header_callback and on_end_headers_callback. */
|
and on_frame_recv_callback. */
|
||||||
rv = nghttp2_session_add_rst_stream(session,
|
rv = nghttp2_session_add_rst_stream(session,
|
||||||
iframe->frame.hd.stream_id,
|
iframe->frame.hd.stream_id,
|
||||||
NGHTTP2_INTERNAL_ERROR);
|
NGHTTP2_INTERNAL_ERROR);
|
||||||
|
@ -3674,7 +3668,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) {
|
if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) {
|
||||||
rv = session_post_process_headers_frame(session);
|
rv = session_after_header_block_received(session);
|
||||||
if(nghttp2_is_fatal(rv)) {
|
if(nghttp2_is_fatal(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3785,13 +3779,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
if(nghttp2_is_fatal(rv)) {
|
if(nghttp2_is_fatal(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = session_call_on_end_headers(session, &iframe->frame,
|
|
||||||
NGHTTP2_PROTOCOL_ERROR);
|
|
||||||
|
|
||||||
if(nghttp2_is_fatal(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
/* Mark inflater bad so that we won't perform further decoding */
|
/* Mark inflater bad so that we won't perform further decoding */
|
||||||
session->hd_inflater.ctx.bad = 1;
|
session->hd_inflater.ctx.bad = 1;
|
||||||
busy = 1;
|
busy = 1;
|
||||||
|
|
|
@ -359,13 +359,16 @@ int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session,
|
||||||
|
|
||||||
|
|
||||||
int nghttp2_session_end_request_headers_received(nghttp2_session *session,
|
int nghttp2_session_end_request_headers_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame,
|
||||||
|
nghttp2_stream *stream);
|
||||||
|
|
||||||
int nghttp2_session_end_response_headers_received(nghttp2_session *session,
|
int nghttp2_session_end_response_headers_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame,
|
||||||
|
nghttp2_stream *stream);
|
||||||
|
|
||||||
int nghttp2_session_end_headers_received(nghttp2_session *session,
|
int nghttp2_session_end_headers_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame,
|
||||||
|
nghttp2_stream *stream);
|
||||||
|
|
||||||
int nghttp2_session_on_request_headers_received(nghttp2_session *session,
|
int nghttp2_session_on_request_headers_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
|
|
@ -65,7 +65,6 @@ const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION;
|
||||||
|
|
||||||
Config::Config()
|
Config::Config()
|
||||||
: data_ptr(nullptr),
|
: data_ptr(nullptr),
|
||||||
on_request_recv_callback(nullptr),
|
|
||||||
output_upper_thres(1024*1024),
|
output_upper_thres(1024*1024),
|
||||||
header_table_size(-1),
|
header_table_size(-1),
|
||||||
port(0),
|
port(0),
|
||||||
|
@ -801,45 +800,17 @@ int on_header_callback(nghttp2_session *session,
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int on_end_headers_callback(nghttp2_session *session,
|
int on_begin_headers_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame,
|
const nghttp2_frame *frame,
|
||||||
nghttp2_error_code error_code,
|
void *user_data)
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
if(error_code != NGHTTP2_NO_ERROR) {
|
auto hd = static_cast<Http2Handler*>(user_data);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(frame->hd.type != NGHTTP2_HEADERS ||
|
if(frame->hd.type != NGHTTP2_HEADERS ||
|
||||||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
auto hd = static_cast<Http2Handler*>(user_data);
|
auto stream = util::make_unique<Request>(frame->hd.stream_id);
|
||||||
auto stream = hd->get_stream(frame->hd.stream_id);
|
hd->add_stream(frame->hd.stream_id, std::move(stream));
|
||||||
if(!stream) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
http2::normalize_headers(stream->headers);
|
|
||||||
if(!http2::check_http2_headers(stream->headers)) {
|
|
||||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
|
|
||||||
NGHTTP2_PROTOCOL_ERROR);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for(size_t i = 0; REQUIRED_HEADERS[i]; ++i) {
|
|
||||||
if(!http2::get_unique_header(stream->headers, REQUIRED_HEADERS[i])) {
|
|
||||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
|
||||||
frame->hd.stream_id, NGHTTP2_PROTOCOL_ERROR);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// intermediary translating from HTTP/1 request to HTTP/2 may
|
|
||||||
// not produce :authority header field. In this case, it should
|
|
||||||
// provide host HTTP/1.1 header field.
|
|
||||||
if(!http2::get_unique_header(stream->headers, ":authority") &&
|
|
||||||
!http2::get_unique_header(stream->headers, "host")) {
|
|
||||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
|
|
||||||
NGHTTP2_PROTOCOL_ERROR);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -856,12 +827,49 @@ int hd_on_frame_recv_callback
|
||||||
switch(frame->hd.type) {
|
switch(frame->hd.type) {
|
||||||
case NGHTTP2_DATA:
|
case NGHTTP2_DATA:
|
||||||
// TODO Handle POST
|
// TODO Handle POST
|
||||||
|
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||||
|
auto stream = hd->get_stream(frame->hd.stream_id);
|
||||||
|
if(!stream) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
prepare_response(stream, hd);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_HEADERS:
|
case NGHTTP2_HEADERS:
|
||||||
switch(frame->headers.cat) {
|
switch(frame->headers.cat) {
|
||||||
case NGHTTP2_HCAT_REQUEST: {
|
case NGHTTP2_HCAT_REQUEST: {
|
||||||
auto req = util::make_unique<Request>(frame->hd.stream_id);
|
auto stream = hd->get_stream(frame->hd.stream_id);
|
||||||
hd->add_stream(frame->hd.stream_id, std::move(req));
|
if(!stream) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
http2::normalize_headers(stream->headers);
|
||||||
|
if(!http2::check_http2_headers(stream->headers)) {
|
||||||
|
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||||
|
frame->hd.stream_id,
|
||||||
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for(size_t i = 0; REQUIRED_HEADERS[i]; ++i) {
|
||||||
|
if(!http2::get_unique_header(stream->headers, REQUIRED_HEADERS[i])) {
|
||||||
|
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||||
|
frame->hd.stream_id,
|
||||||
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// intermediary translating from HTTP/1 request to HTTP/2 may
|
||||||
|
// not produce :authority header field. In this case, it should
|
||||||
|
// provide host HTTP/1.1 header field.
|
||||||
|
if(!http2::get_unique_header(stream->headers, ":authority") &&
|
||||||
|
!http2::get_unique_header(stream->headers, "host")) {
|
||||||
|
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||||
|
frame->hd.stream_id,
|
||||||
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||||
|
prepare_response(stream, hd);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -885,17 +893,6 @@ int hd_on_frame_recv_callback
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int htdocs_on_request_recv_callback
|
|
||||||
(nghttp2_session *session, int32_t stream_id, void *user_data)
|
|
||||||
{
|
|
||||||
auto hd = static_cast<Http2Handler*>(user_data);
|
|
||||||
auto stream = hd->get_stream(stream_id);
|
|
||||||
if(stream) {
|
|
||||||
prepare_response(stream, hd);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int hd_before_frame_send_callback
|
int hd_before_frame_send_callback
|
||||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||||
|
@ -977,9 +974,8 @@ void fill_callback(nghttp2_session_callbacks& callbacks, const Config *config)
|
||||||
verbose_on_unknown_frame_recv_callback;
|
verbose_on_unknown_frame_recv_callback;
|
||||||
}
|
}
|
||||||
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||||
callbacks.on_request_recv_callback = config->on_request_recv_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;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,6 @@ struct Config {
|
||||||
std::string private_key_file;
|
std::string private_key_file;
|
||||||
std::string cert_file;
|
std::string cert_file;
|
||||||
void *data_ptr;
|
void *data_ptr;
|
||||||
nghttp2_on_request_recv_callback on_request_recv_callback;
|
|
||||||
size_t output_upper_thres;
|
size_t output_upper_thres;
|
||||||
ssize_t header_table_size;
|
ssize_t header_table_size;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
|
@ -144,9 +143,6 @@ private:
|
||||||
const Config *config_;
|
const Config *config_;
|
||||||
};
|
};
|
||||||
|
|
||||||
int htdocs_on_request_recv_callback
|
|
||||||
(nghttp2_session *session, int32_t stream_id, void *user_data);
|
|
||||||
|
|
||||||
ssize_t file_read_callback
|
ssize_t file_read_callback
|
||||||
(nghttp2_session *session, int32_t stream_id,
|
(nghttp2_session *session, int32_t stream_id,
|
||||||
uint8_t *buf, size_t length, int *eof,
|
uint8_t *buf, size_t length, int *eof,
|
||||||
|
|
|
@ -1176,30 +1176,6 @@ int on_header_callback(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
|
||||||
int on_end_headers_callback(nghttp2_session *session,
|
|
||||||
const nghttp2_frame *frame,
|
|
||||||
nghttp2_error_code error_code,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
if(error_code != NGHTTP2_NO_ERROR) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(frame->hd.type != NGHTTP2_HEADERS ||
|
|
||||||
frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
auto req = (Request*)nghttp2_session_get_stream_user_data
|
|
||||||
(session, frame->hd.stream_id);
|
|
||||||
if(!req) {
|
|
||||||
// Server-pushed stream does not have stream user data
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
check_response_header(session, req);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int on_frame_recv_callback2
|
int on_frame_recv_callback2
|
||||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||||
|
@ -1212,9 +1188,9 @@ int on_frame_recv_callback2
|
||||||
// req is nullptr.
|
// req is nullptr.
|
||||||
if(req) {
|
if(req) {
|
||||||
req->record_response_time();
|
req->record_response_time();
|
||||||
|
check_response_header(session, req);
|
||||||
}
|
}
|
||||||
}
|
} else if(frame->hd.type == NGHTTP2_SETTINGS &&
|
||||||
if(frame->hd.type == NGHTTP2_SETTINGS &&
|
|
||||||
(frame->hd.flags & NGHTTP2_FLAG_ACK)) {
|
(frame->hd.flags & NGHTTP2_FLAG_ACK)) {
|
||||||
auto client = get_session(user_data);
|
auto client = get_session(user_data);
|
||||||
if(client->settings_timerev) {
|
if(client->settings_timerev) {
|
||||||
|
@ -1603,7 +1579,6 @@ int run(char **uris, int n)
|
||||||
}
|
}
|
||||||
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||||
callbacks.on_header_callback = on_header_callback;
|
callbacks.on_header_callback = on_header_callback;
|
||||||
callbacks.on_end_headers_callback = on_end_headers_callback;
|
|
||||||
|
|
||||||
std::string prev_scheme;
|
std::string prev_scheme;
|
||||||
std::string prev_host;
|
std::string prev_host;
|
||||||
|
|
|
@ -236,7 +236,6 @@ int main(int argc, char **argv)
|
||||||
SSL_load_error_strings();
|
SSL_load_error_strings();
|
||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
reset_timer();
|
reset_timer();
|
||||||
config.on_request_recv_callback = htdocs_on_request_recv_callback;
|
|
||||||
|
|
||||||
HttpServer server(&config);
|
HttpServer server(&config);
|
||||||
server.run();
|
server.run();
|
||||||
|
|
|
@ -833,20 +833,44 @@ int on_header_callback(nghttp2_session *session,
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int on_end_headers_callback(nghttp2_session *session,
|
int on_begin_headers_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame,
|
const nghttp2_frame *frame,
|
||||||
nghttp2_error_code error_code,
|
void *user_data)
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
if(error_code != NGHTTP2_NO_ERROR) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(frame->hd.type != NGHTTP2_HEADERS ||
|
|
||||||
frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int rv;
|
|
||||||
auto http2session = static_cast<Http2Session*>(user_data);
|
auto http2session = static_cast<Http2Session*>(user_data);
|
||||||
|
if(frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
|
||||||
|
// server sends request HEADERS
|
||||||
|
http2session->submit_rst_stream(frame->hd.stream_id,
|
||||||
|
NGHTTP2_REFUSED_STREAM);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto sd = static_cast<StreamData*>
|
||||||
|
(nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
|
||||||
|
if(!sd || !sd->dconn) {
|
||||||
|
http2session->submit_rst_stream(frame->hd.stream_id,
|
||||||
|
NGHTTP2_INTERNAL_ERROR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto downstream = sd->dconn->get_downstream();
|
||||||
|
if(!downstream ||
|
||||||
|
downstream->get_downstream_stream_id() != frame->hd.stream_id) {
|
||||||
|
http2session->submit_rst_stream(frame->hd.stream_id,
|
||||||
|
NGHTTP2_INTERNAL_ERROR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int on_response_headers(Http2Session *http2session,
|
||||||
|
nghttp2_session *session,
|
||||||
|
const nghttp2_frame *frame)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
auto sd = static_cast<StreamData*>
|
auto sd = static_cast<StreamData*>
|
||||||
(nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
|
(nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
|
||||||
if(!sd || !sd->dconn) {
|
if(!sd || !sd->dconn) {
|
||||||
|
@ -952,32 +976,8 @@ int on_frame_recv_callback
|
||||||
{
|
{
|
||||||
auto http2session = static_cast<Http2Session*>(user_data);
|
auto http2session = static_cast<Http2Session*>(user_data);
|
||||||
switch(frame->hd.type) {
|
switch(frame->hd.type) {
|
||||||
case NGHTTP2_HEADERS: {
|
case NGHTTP2_HEADERS:
|
||||||
if(frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
|
return on_response_headers(http2session, session, frame);
|
||||||
// server sends request HEADERS
|
|
||||||
http2session->submit_rst_stream(frame->hd.stream_id,
|
|
||||||
NGHTTP2_REFUSED_STREAM);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto sd = static_cast<StreamData*>
|
|
||||||
(nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
|
|
||||||
if(!sd || !sd->dconn) {
|
|
||||||
http2session->submit_rst_stream(frame->hd.stream_id,
|
|
||||||
NGHTTP2_INTERNAL_ERROR);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto downstream = sd->dconn->get_downstream();
|
|
||||||
if(!downstream ||
|
|
||||||
downstream->get_downstream_stream_id() != frame->hd.stream_id) {
|
|
||||||
http2session->submit_rst_stream(frame->hd.stream_id,
|
|
||||||
NGHTTP2_INTERNAL_ERROR);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NGHTTP2_RST_STREAM: {
|
case NGHTTP2_RST_STREAM: {
|
||||||
auto sd = static_cast<StreamData*>
|
auto sd = static_cast<StreamData*>
|
||||||
(nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
|
(nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
|
||||||
|
@ -1192,7 +1192,7 @@ int Http2Session::on_connect()
|
||||||
callbacks.on_frame_not_send_callback = on_frame_not_send_callback;
|
callbacks.on_frame_not_send_callback = on_frame_not_send_callback;
|
||||||
callbacks.on_unknown_frame_recv_callback = on_unknown_frame_recv_callback;
|
callbacks.on_unknown_frame_recv_callback = on_unknown_frame_recv_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_opt_set opt_set;
|
nghttp2_opt_set opt_set;
|
||||||
opt_set.no_auto_stream_window_update = 1;
|
opt_set.no_auto_stream_window_update = 1;
|
||||||
|
|
|
@ -230,20 +230,35 @@ int on_header_callback(nghttp2_session *session,
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int on_end_headers_callback(nghttp2_session *session,
|
int on_begin_headers_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame,
|
const nghttp2_frame *frame,
|
||||||
nghttp2_error_code error_code,
|
void *user_data)
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
if(error_code != NGHTTP2_NO_ERROR) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(frame->hd.type != NGHTTP2_HEADERS ||
|
|
||||||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int rv;
|
|
||||||
auto upstream = static_cast<Http2Upstream*>(user_data);
|
auto upstream = static_cast<Http2Upstream*>(user_data);
|
||||||
|
|
||||||
|
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
ULOG(INFO, upstream) << "Received upstream request HEADERS stream_id="
|
||||||
|
<< frame->hd.stream_id;
|
||||||
|
}
|
||||||
|
auto downstream = new Downstream(upstream,
|
||||||
|
frame->hd.stream_id,
|
||||||
|
frame->headers.pri);
|
||||||
|
upstream->add_downstream(downstream);
|
||||||
|
downstream->init_response_body_buf();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int on_request_headers(Http2Upstream *upstream,
|
||||||
|
nghttp2_session *session,
|
||||||
|
const nghttp2_frame *frame)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
auto downstream = upstream->find_downstream(frame->hd.stream_id);
|
auto downstream = upstream->find_downstream(frame->hd.stream_id);
|
||||||
if(!downstream) {
|
if(!downstream) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -357,21 +372,8 @@ int on_frame_recv_callback
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NGHTTP2_HEADERS: {
|
case NGHTTP2_HEADERS:
|
||||||
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
return on_request_headers(upstream, session, frame);
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(LOG_ENABLED(INFO)) {
|
|
||||||
ULOG(INFO, upstream) << "Received upstream request HEADERS stream_id="
|
|
||||||
<< frame->hd.stream_id;
|
|
||||||
}
|
|
||||||
auto downstream = new Downstream(upstream,
|
|
||||||
frame->hd.stream_id,
|
|
||||||
frame->headers.pri);
|
|
||||||
upstream->add_downstream(downstream);
|
|
||||||
downstream->init_response_body_buf();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NGHTTP2_PRIORITY: {
|
case NGHTTP2_PRIORITY: {
|
||||||
auto downstream = upstream->find_downstream(frame->hd.stream_id);
|
auto downstream = upstream->find_downstream(frame->hd.stream_id);
|
||||||
if(!downstream) {
|
if(!downstream) {
|
||||||
|
@ -505,7 +507,7 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
|
||||||
callbacks.on_frame_not_send_callback = on_frame_not_send_callback;
|
callbacks.on_frame_not_send_callback = on_frame_not_send_callback;
|
||||||
callbacks.on_unknown_frame_recv_callback = on_unknown_frame_recv_callback;
|
callbacks.on_unknown_frame_recv_callback = on_unknown_frame_recv_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_opt_set opt_set;
|
nghttp2_opt_set opt_set;
|
||||||
opt_set.no_auto_stream_window_update = 1;
|
opt_set.no_auto_stream_window_update = 1;
|
||||||
|
|
|
@ -69,7 +69,7 @@ typedef struct {
|
||||||
const nghttp2_frame *frame;
|
const nghttp2_frame *frame;
|
||||||
size_t fixed_sendlen;
|
size_t fixed_sendlen;
|
||||||
int header_cb_called;
|
int header_cb_called;
|
||||||
int end_headers_cb_called;
|
int begin_headers_cb_called;
|
||||||
nghttp2_nv nv;
|
nghttp2_nv nv;
|
||||||
} my_user_data;
|
} my_user_data;
|
||||||
|
|
||||||
|
@ -298,13 +298,12 @@ static int pause_on_header_callback(nghttp2_session *session,
|
||||||
return NGHTTP2_ERR_PAUSE;
|
return NGHTTP2_ERR_PAUSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_end_headers_callback(nghttp2_session *session,
|
static int on_begin_headers_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame,
|
const nghttp2_frame *frame,
|
||||||
nghttp2_error_code error_code,
|
void *user_data)
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
my_user_data *ud = (my_user_data*)user_data;
|
my_user_data *ud = (my_user_data*)user_data;
|
||||||
++ud->end_headers_cb_called;
|
++ud->begin_headers_cb_called;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -674,7 +673,7 @@ void test_nghttp2_session_recv_continuation(void)
|
||||||
|
|
||||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
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_server_new(&session, &callbacks, &ud);
|
nghttp2_session_server_new(&session, &callbacks, &ud);
|
||||||
|
|
||||||
|
@ -753,11 +752,11 @@ void test_nghttp2_session_recv_continuation(void)
|
||||||
memcpy(data + datalen, framedata, framedatalen);
|
memcpy(data + datalen, framedata, framedatalen);
|
||||||
datalen += framedatalen;
|
datalen += framedatalen;
|
||||||
|
|
||||||
ud.end_headers_cb_called = 0;
|
ud.begin_headers_cb_called = 0;
|
||||||
rv = nghttp2_session_mem_recv(session, data, datalen);
|
rv = nghttp2_session_mem_recv(session, data, datalen);
|
||||||
CU_ASSERT((ssize_t)datalen == rv);
|
CU_ASSERT((ssize_t)datalen == rv);
|
||||||
|
|
||||||
CU_ASSERT(1 == ud.end_headers_cb_called);
|
CU_ASSERT(1 == ud.begin_headers_cb_called);
|
||||||
CU_ASSERT(NGHTTP2_GOAWAY ==
|
CU_ASSERT(NGHTTP2_GOAWAY ==
|
||||||
OB_CTRL_TYPE(nghttp2_session_get_next_ob_item(session)));
|
OB_CTRL_TYPE(nghttp2_session_get_next_ob_item(session)));
|
||||||
|
|
||||||
|
@ -798,7 +797,7 @@ void test_nghttp2_session_continue(void)
|
||||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||||
callbacks.on_data_chunk_recv_callback = pause_on_data_chunk_recv_callback;
|
callbacks.on_data_chunk_recv_callback = pause_on_data_chunk_recv_callback;
|
||||||
callbacks.on_header_callback = pause_on_header_callback;
|
callbacks.on_header_callback = pause_on_header_callback;
|
||||||
callbacks.on_end_headers_callback = on_end_headers_callback;
|
callbacks.on_begin_headers_callback = on_begin_headers_callback;
|
||||||
|
|
||||||
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
||||||
|
|
||||||
|
@ -827,8 +826,8 @@ void test_nghttp2_session_continue(void)
|
||||||
buflen = framelen1 + framelen2;
|
buflen = framelen1 + framelen2;
|
||||||
|
|
||||||
/* Receive 1st HEADERS and pause */
|
/* Receive 1st HEADERS and pause */
|
||||||
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.header_cb_called = 0;
|
user_data.header_cb_called = 0;
|
||||||
user_data.end_headers_cb_called = 0;
|
|
||||||
rv = nghttp2_session_mem_recv(session, bufp, buflen);
|
rv = nghttp2_session_mem_recv(session, bufp, buflen);
|
||||||
|
|
||||||
bufp += rv;
|
bufp += rv;
|
||||||
|
@ -839,27 +838,27 @@ void test_nghttp2_session_continue(void)
|
||||||
CU_ASSERT((size_t)framelen1 - NGHTTP2_FRAME_HEAD_LENGTH ==
|
CU_ASSERT((size_t)framelen1 - NGHTTP2_FRAME_HEAD_LENGTH ==
|
||||||
recv_frame->hd.length);
|
recv_frame->hd.length);
|
||||||
|
|
||||||
|
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(1 == user_data.header_cb_called);
|
CU_ASSERT(1 == user_data.header_cb_called);
|
||||||
CU_ASSERT(0 == user_data.end_headers_cb_called);
|
|
||||||
|
|
||||||
CU_ASSERT(nghttp2_nv_equal(&nv1[0], &user_data.nv));
|
CU_ASSERT(nghttp2_nv_equal(&nv1[0], &user_data.nv));
|
||||||
|
|
||||||
/* get 2nd header field */
|
/* get 2nd header field */
|
||||||
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.header_cb_called = 0;
|
user_data.header_cb_called = 0;
|
||||||
user_data.end_headers_cb_called = 0;
|
|
||||||
rv = nghttp2_session_mem_recv(session, bufp, buflen);
|
rv = nghttp2_session_mem_recv(session, bufp, buflen);
|
||||||
|
|
||||||
bufp += rv;
|
bufp += rv;
|
||||||
buflen -= rv;
|
buflen -= rv;
|
||||||
|
|
||||||
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(1 == user_data.header_cb_called);
|
CU_ASSERT(1 == user_data.header_cb_called);
|
||||||
CU_ASSERT(0 == user_data.end_headers_cb_called);
|
|
||||||
|
|
||||||
CU_ASSERT(nghttp2_nv_equal(&nv1[1], &user_data.nv));
|
CU_ASSERT(nghttp2_nv_equal(&nv1[1], &user_data.nv));
|
||||||
|
|
||||||
/* will call end_headers_callback and receive 2nd HEADERS and pause */
|
/* will call end_headers_callback and receive 2nd HEADERS and pause */
|
||||||
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.header_cb_called = 0;
|
user_data.header_cb_called = 0;
|
||||||
user_data.end_headers_cb_called = 0;
|
|
||||||
rv = nghttp2_session_mem_recv(session, bufp, buflen);
|
rv = nghttp2_session_mem_recv(session, bufp, buflen);
|
||||||
|
|
||||||
bufp += rv;
|
bufp += rv;
|
||||||
|
@ -870,34 +869,36 @@ void test_nghttp2_session_continue(void)
|
||||||
CU_ASSERT((size_t)framelen2 - NGHTTP2_FRAME_HEAD_LENGTH ==
|
CU_ASSERT((size_t)framelen2 - NGHTTP2_FRAME_HEAD_LENGTH ==
|
||||||
recv_frame->hd.length);
|
recv_frame->hd.length);
|
||||||
|
|
||||||
|
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(1 == user_data.header_cb_called);
|
CU_ASSERT(1 == user_data.header_cb_called);
|
||||||
CU_ASSERT(1 == user_data.end_headers_cb_called);
|
|
||||||
|
|
||||||
CU_ASSERT(nghttp2_nv_equal(&nv2[0], &user_data.nv));
|
CU_ASSERT(nghttp2_nv_equal(&nv2[0], &user_data.nv));
|
||||||
|
|
||||||
/* get 2nd header field */
|
/* get 2nd header field */
|
||||||
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.header_cb_called = 0;
|
user_data.header_cb_called = 0;
|
||||||
user_data.end_headers_cb_called = 0;
|
|
||||||
rv = nghttp2_session_mem_recv(session, bufp, buflen);
|
rv = nghttp2_session_mem_recv(session, bufp, buflen);
|
||||||
|
|
||||||
bufp += rv;
|
bufp += rv;
|
||||||
buflen -= rv;
|
buflen -= rv;
|
||||||
|
|
||||||
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(1 == user_data.header_cb_called);
|
CU_ASSERT(1 == user_data.header_cb_called);
|
||||||
CU_ASSERT(0 == user_data.end_headers_cb_called);
|
|
||||||
|
|
||||||
CU_ASSERT(nghttp2_nv_equal(&nv2[1], &user_data.nv));
|
CU_ASSERT(nghttp2_nv_equal(&nv2[1], &user_data.nv));
|
||||||
|
|
||||||
/* No input data, just call on_end_headers_callback */
|
/* No input data, frame_recv_callback is called */
|
||||||
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.header_cb_called = 0;
|
user_data.header_cb_called = 0;
|
||||||
user_data.end_headers_cb_called = 0;
|
user_data.frame_recv_cb_called = 0;
|
||||||
rv = nghttp2_session_mem_recv(session, bufp, buflen);
|
rv = nghttp2_session_mem_recv(session, bufp, buflen);
|
||||||
|
|
||||||
bufp += rv;
|
bufp += rv;
|
||||||
buflen -= rv;
|
buflen -= rv;
|
||||||
|
|
||||||
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(0 == user_data.header_cb_called);
|
CU_ASSERT(0 == user_data.header_cb_called);
|
||||||
CU_ASSERT(1 == user_data.end_headers_cb_called);
|
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
||||||
|
|
||||||
/* Receive DATA */
|
/* Receive DATA */
|
||||||
data_hd.length = 16;
|
data_hd.length = 16;
|
||||||
|
@ -989,10 +990,8 @@ void test_nghttp2_session_on_request_headers_received(void)
|
||||||
size_t nvlen;
|
size_t nvlen;
|
||||||
|
|
||||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
callbacks.on_begin_headers_callback = on_begin_headers_callback;
|
||||||
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
||||||
user_data.frame_recv_cb_called = 0;
|
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
|
||||||
|
|
||||||
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
||||||
memset(session->iframe.buf, 0, 4);
|
memset(session->iframe.buf, 0, 4);
|
||||||
|
@ -1001,8 +1000,11 @@ void test_nghttp2_session_on_request_headers_received(void)
|
||||||
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
|
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
|
||||||
stream_id, 1 << 20, NULL, 0);
|
stream_id, 1 << 20, NULL, 0);
|
||||||
|
|
||||||
|
user_data.begin_headers_cb_called = 0;
|
||||||
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame));
|
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame));
|
||||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
||||||
stream = nghttp2_session_get_stream(session, stream_id);
|
stream = nghttp2_session_get_stream(session, stream_id);
|
||||||
CU_ASSERT(NGHTTP2_STREAM_OPENING == stream->state);
|
CU_ASSERT(NGHTTP2_STREAM_OPENING == stream->state);
|
||||||
CU_ASSERT(1 << 20 == stream->pri);
|
CU_ASSERT(1 << 20 == stream->pri);
|
||||||
|
@ -1047,10 +1049,10 @@ void test_nghttp2_session_on_request_headers_received(void)
|
||||||
nghttp2_frame_headers_init(&frame.headers,
|
nghttp2_frame_headers_init(&frame.headers,
|
||||||
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
|
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
|
||||||
1, 1 << 20, nva, nvlen);
|
1, 1 << 20, nva, nvlen);
|
||||||
user_data.frame_recv_cb_called = 0;
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame));
|
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame));
|
||||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
|
CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
|
||||||
|
|
||||||
nghttp2_frame_headers_free(&frame.headers);
|
nghttp2_frame_headers_free(&frame.headers);
|
||||||
|
@ -1067,10 +1069,8 @@ void test_nghttp2_session_on_response_headers_received(void)
|
||||||
nghttp2_stream *stream;
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
callbacks.on_begin_headers_callback = on_begin_headers_callback;
|
||||||
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
||||||
user_data.frame_recv_cb_called = 0;
|
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
|
||||||
|
|
||||||
nghttp2_session_client_new(&session, &callbacks, &user_data);
|
nghttp2_session_client_new(&session, &callbacks, &user_data);
|
||||||
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
|
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
|
||||||
|
@ -1079,9 +1079,12 @@ void test_nghttp2_session_on_response_headers_received(void)
|
||||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
|
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
|
||||||
NGHTTP2_PRI_DEFAULT, NULL, 0);
|
NGHTTP2_PRI_DEFAULT, NULL, 0);
|
||||||
|
|
||||||
|
user_data.begin_headers_cb_called = 0;
|
||||||
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_on_response_headers_received
|
CU_ASSERT(0 == nghttp2_session_on_response_headers_received
|
||||||
(session, &frame, stream));
|
(session, &frame, stream));
|
||||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
|
CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
|
||||||
|
|
||||||
nghttp2_frame_headers_free(&frame.headers);
|
nghttp2_frame_headers_free(&frame.headers);
|
||||||
|
@ -1097,10 +1100,8 @@ void test_nghttp2_session_on_headers_received(void)
|
||||||
nghttp2_stream *stream;
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
callbacks.on_begin_headers_callback = on_begin_headers_callback;
|
||||||
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
||||||
user_data.frame_recv_cb_called = 0;
|
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
|
||||||
|
|
||||||
nghttp2_session_client_new(&session, &callbacks, &user_data);
|
nghttp2_session_client_new(&session, &callbacks, &user_data);
|
||||||
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
|
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
|
||||||
|
@ -1110,15 +1111,18 @@ void test_nghttp2_session_on_headers_received(void)
|
||||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
|
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
|
||||||
NGHTTP2_PRI_DEFAULT, NULL, 0);
|
NGHTTP2_PRI_DEFAULT, NULL, 0);
|
||||||
|
|
||||||
|
user_data.begin_headers_cb_called = 0;
|
||||||
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream));
|
CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream));
|
||||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
|
CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
|
||||||
|
|
||||||
/* stream closed */
|
/* stream closed */
|
||||||
frame.hd.flags |= NGHTTP2_FLAG_END_STREAM;
|
frame.hd.flags |= NGHTTP2_FLAG_END_STREAM;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream));
|
CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream));
|
||||||
CU_ASSERT(2 == user_data.frame_recv_cb_called);
|
CU_ASSERT(2 == user_data.begin_headers_cb_called);
|
||||||
|
|
||||||
/* Check to see when NGHTTP2_STREAM_CLOSING, incoming HEADERS is
|
/* Check to see when NGHTTP2_STREAM_CLOSING, incoming HEADERS is
|
||||||
discarded. */
|
discarded. */
|
||||||
|
@ -1130,7 +1134,7 @@ void test_nghttp2_session_on_headers_received(void)
|
||||||
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
||||||
nghttp2_session_on_headers_received(session, &frame, stream));
|
nghttp2_session_on_headers_received(session, &frame, stream));
|
||||||
/* See no counters are updated */
|
/* See no counters are updated */
|
||||||
CU_ASSERT(2 == user_data.frame_recv_cb_called);
|
CU_ASSERT(2 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
|
CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
|
||||||
|
|
||||||
/* Server initiated stream */
|
/* Server initiated stream */
|
||||||
|
@ -1143,7 +1147,7 @@ void test_nghttp2_session_on_headers_received(void)
|
||||||
frame.hd.stream_id = 2;
|
frame.hd.stream_id = 2;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream));
|
CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream));
|
||||||
CU_ASSERT(3 == user_data.frame_recv_cb_called);
|
CU_ASSERT(3 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(NGHTTP2_STREAM_OPENING == stream->state);
|
CU_ASSERT(NGHTTP2_STREAM_OPENING == stream->state);
|
||||||
|
|
||||||
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
||||||
|
@ -1168,10 +1172,8 @@ void test_nghttp2_session_on_push_response_headers_received(void)
|
||||||
nghttp2_outbound_item *item;
|
nghttp2_outbound_item *item;
|
||||||
|
|
||||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
callbacks.on_begin_headers_callback = on_begin_headers_callback;
|
||||||
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
||||||
user_data.frame_recv_cb_called = 0;
|
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
|
||||||
|
|
||||||
nghttp2_session_client_new(&session, &callbacks, &user_data);
|
nghttp2_session_client_new(&session, &callbacks, &user_data);
|
||||||
stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
|
stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
|
||||||
|
@ -1182,9 +1184,13 @@ void test_nghttp2_session_on_push_response_headers_received(void)
|
||||||
/* nghttp2_session_on_push_response_headers_received assumes
|
/* nghttp2_session_on_push_response_headers_received assumes
|
||||||
stream's state is NGHTTP2_STREAM_RESERVED and session->server is
|
stream's state is NGHTTP2_STREAM_RESERVED and session->server is
|
||||||
0. */
|
0. */
|
||||||
|
|
||||||
|
user_data.begin_headers_cb_called = 0;
|
||||||
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_on_push_response_headers_received
|
CU_ASSERT(0 == nghttp2_session_on_push_response_headers_received
|
||||||
(session, &frame, stream));
|
(session, &frame, stream));
|
||||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
|
CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
|
||||||
CU_ASSERT(1 == session->num_incoming_streams);
|
CU_ASSERT(1 == session->num_incoming_streams);
|
||||||
|
|
||||||
|
@ -1407,10 +1413,8 @@ void test_nghttp2_session_on_push_promise_received(void)
|
||||||
|
|
||||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
callbacks.send_callback = null_send_callback;
|
callbacks.send_callback = null_send_callback;
|
||||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
callbacks.on_begin_headers_callback = on_begin_headers_callback;
|
||||||
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
||||||
user_data.frame_recv_cb_called = 0;
|
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
|
||||||
|
|
||||||
nghttp2_session_client_new(&session, &callbacks, &user_data);
|
nghttp2_session_client_new(&session, &callbacks, &user_data);
|
||||||
memset(session->iframe.buf, 0, 4);
|
memset(session->iframe.buf, 0, 4);
|
||||||
|
@ -1422,9 +1426,12 @@ void test_nghttp2_session_on_push_promise_received(void)
|
||||||
NGHTTP2_FLAG_END_PUSH_PROMISE, 1, 2,
|
NGHTTP2_FLAG_END_PUSH_PROMISE, 1, 2,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
|
|
||||||
|
user_data.begin_headers_cb_called = 0;
|
||||||
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_on_push_promise_received(session, &frame));
|
CU_ASSERT(0 == nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
||||||
promised_stream = nghttp2_session_get_stream(session, 2);
|
promised_stream = nghttp2_session_get_stream(session, 2);
|
||||||
CU_ASSERT(NGHTTP2_STREAM_RESERVED == promised_stream->state);
|
CU_ASSERT(NGHTTP2_STREAM_RESERVED == promised_stream->state);
|
||||||
CU_ASSERT(2 == session->last_recv_stream_id);
|
CU_ASSERT(2 == session->last_recv_stream_id);
|
||||||
|
@ -1433,12 +1440,12 @@ void test_nghttp2_session_on_push_promise_received(void)
|
||||||
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
||||||
frame.push_promise.promised_stream_id = 4;
|
frame.push_promise.promised_stream_id = 4;
|
||||||
|
|
||||||
user_data.frame_recv_cb_called = 0;
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
||||||
nghttp2_session_on_push_promise_received(session, &frame));
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.frame_recv_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
|
||||||
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 4));
|
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 4));
|
||||||
item = nghttp2_session_get_next_ob_item(session);
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
@ -1453,12 +1460,12 @@ void test_nghttp2_session_on_push_promise_received(void)
|
||||||
stream->state = NGHTTP2_STREAM_CLOSING;
|
stream->state = NGHTTP2_STREAM_CLOSING;
|
||||||
frame.push_promise.promised_stream_id = 6;
|
frame.push_promise.promised_stream_id = 6;
|
||||||
|
|
||||||
user_data.frame_recv_cb_called = 0;
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
||||||
nghttp2_session_on_push_promise_received(session, &frame));
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.frame_recv_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 6));
|
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 6));
|
||||||
item = nghttp2_session_get_next_ob_item(session);
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(item));
|
CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(item));
|
||||||
|
@ -1470,12 +1477,12 @@ void test_nghttp2_session_on_push_promise_received(void)
|
||||||
frame.hd.stream_id = 3;
|
frame.hd.stream_id = 3;
|
||||||
frame.push_promise.promised_stream_id = 8;
|
frame.push_promise.promised_stream_id = 8;
|
||||||
|
|
||||||
user_data.frame_recv_cb_called = 0;
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
||||||
nghttp2_session_on_push_promise_received(session, &frame));
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.frame_recv_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8));
|
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8));
|
||||||
item = nghttp2_session_get_next_ob_item(session);
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(item));
|
CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(item));
|
||||||
|
@ -1486,12 +1493,12 @@ void test_nghttp2_session_on_push_promise_received(void)
|
||||||
/* Same ID twice */
|
/* Same ID twice */
|
||||||
stream->state = NGHTTP2_STREAM_OPENING;
|
stream->state = NGHTTP2_STREAM_OPENING;
|
||||||
|
|
||||||
user_data.frame_recv_cb_called = 0;
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
||||||
nghttp2_session_on_push_promise_received(session, &frame));
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.frame_recv_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8));
|
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8));
|
||||||
item = nghttp2_session_get_next_ob_item(session);
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
|
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
|
||||||
|
@ -1501,12 +1508,12 @@ void test_nghttp2_session_on_push_promise_received(void)
|
||||||
/* After GOAWAY, PUSH_PROMISE will be discarded */
|
/* After GOAWAY, PUSH_PROMISE will be discarded */
|
||||||
frame.push_promise.promised_stream_id = 10;
|
frame.push_promise.promised_stream_id = 10;
|
||||||
|
|
||||||
user_data.frame_recv_cb_called = 0;
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
||||||
nghttp2_session_on_push_promise_received(session, &frame));
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.frame_recv_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 10));
|
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 10));
|
||||||
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
|
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
|
||||||
|
|
||||||
|
@ -1524,12 +1531,12 @@ void test_nghttp2_session_on_push_promise_received(void)
|
||||||
NGHTTP2_FLAG_END_PUSH_PROMISE, 2, 4,
|
NGHTTP2_FLAG_END_PUSH_PROMISE, 2, 4,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
|
|
||||||
user_data.frame_recv_cb_called = 0;
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
||||||
nghttp2_session_on_push_promise_received(session, &frame));
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.frame_recv_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
|
||||||
|
|
||||||
nghttp2_frame_push_promise_free(&frame.push_promise);
|
nghttp2_frame_push_promise_free(&frame.push_promise);
|
||||||
|
@ -1549,12 +1556,12 @@ void test_nghttp2_session_on_push_promise_received(void)
|
||||||
NGHTTP2_FLAG_END_PUSH_PROMISE, 1, 2,
|
NGHTTP2_FLAG_END_PUSH_PROMISE, 1, 2,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
|
|
||||||
user_data.frame_recv_cb_called = 0;
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
||||||
nghttp2_session_on_push_promise_received(session, &frame));
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.frame_recv_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
|
||||||
|
|
||||||
nghttp2_frame_push_promise_free(&frame.push_promise);
|
nghttp2_frame_push_promise_free(&frame.push_promise);
|
||||||
|
@ -1571,11 +1578,11 @@ void test_nghttp2_session_on_push_promise_received(void)
|
||||||
nghttp2_frame_push_promise_init(&frame.push_promise,
|
nghttp2_frame_push_promise_init(&frame.push_promise,
|
||||||
NGHTTP2_FLAG_END_PUSH_PROMISE, 1, 2,
|
NGHTTP2_FLAG_END_PUSH_PROMISE, 1, 2,
|
||||||
nva, nvlen);
|
nva, nvlen);
|
||||||
user_data.frame_recv_cb_called = 0;
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
CU_ASSERT(0 == nghttp2_session_on_push_promise_received(session, &frame));
|
CU_ASSERT(0 == nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
|
CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
|
||||||
|
|
||||||
nghttp2_frame_push_promise_free(&frame.push_promise);
|
nghttp2_frame_push_promise_free(&frame.push_promise);
|
||||||
|
@ -3635,43 +3642,43 @@ void test_nghttp2_session_on_request_recv_callback(void)
|
||||||
nghttp2_session_callbacks callbacks;
|
nghttp2_session_callbacks callbacks;
|
||||||
my_user_data user_data;
|
my_user_data user_data;
|
||||||
nghttp2_frame frame;
|
nghttp2_frame frame;
|
||||||
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
callbacks.on_request_recv_callback = on_request_recv_callback;
|
callbacks.on_request_recv_callback = on_request_recv_callback;
|
||||||
user_data.stream_id = 0;
|
|
||||||
|
|
||||||
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
||||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
|
nghttp2_frame_headers_init(&frame.headers,
|
||||||
1, NGHTTP2_PRI_DEFAULT, NULL, 0);
|
NGHTTP2_FLAG_END_HEADERS |
|
||||||
CU_ASSERT(0 == nghttp2_session_end_request_headers_received(session, &frame));
|
NGHTTP2_FLAG_END_STREAM,
|
||||||
CU_ASSERT(0 == user_data.stream_id);
|
3, NGHTTP2_PRI_DEFAULT, NULL, 0);
|
||||||
|
|
||||||
/* nghttp2_session_end_* does not open stream, so we do it here */
|
/* nghttp2_session_end_* does not open stream, so we do it here */
|
||||||
nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE,
|
stream = nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE,
|
||||||
NGHTTP2_PRI_DEFAULT,
|
NGHTTP2_PRI_DEFAULT,
|
||||||
NGHTTP2_STREAM_OPENING, NULL);
|
NGHTTP2_STREAM_OPENING, NULL);
|
||||||
frame.hd.stream_id = 3;
|
|
||||||
frame.hd.flags |= NGHTTP2_FLAG_END_STREAM;
|
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_end_request_headers_received(session, &frame));
|
user_data.stream_id = 0;
|
||||||
|
CU_ASSERT(0 == nghttp2_session_end_request_headers_received
|
||||||
|
(session, &frame, stream));
|
||||||
CU_ASSERT(3 == user_data.stream_id);
|
CU_ASSERT(3 == user_data.stream_id);
|
||||||
|
|
||||||
nghttp2_frame_headers_free(&frame.headers);
|
nghttp2_frame_headers_free(&frame.headers);
|
||||||
|
|
||||||
user_data.stream_id = 0;
|
user_data.stream_id = 0;
|
||||||
|
|
||||||
nghttp2_session_open_stream(session, 5, NGHTTP2_STREAM_FLAG_NONE,
|
stream = nghttp2_session_open_stream(session, 5, NGHTTP2_STREAM_FLAG_NONE,
|
||||||
NGHTTP2_PRI_DEFAULT,
|
NGHTTP2_PRI_DEFAULT,
|
||||||
NGHTTP2_STREAM_OPENING, NULL);
|
NGHTTP2_STREAM_OPENING, NULL);
|
||||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
|
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
|
||||||
5, NGHTTP2_PRI_DEFAULT, NULL, 0);
|
5, NGHTTP2_PRI_DEFAULT, NULL, 0);
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_end_headers_received(session, &frame));
|
CU_ASSERT(0 == nghttp2_session_end_headers_received(session, &frame, stream));
|
||||||
CU_ASSERT(0 == user_data.stream_id);
|
CU_ASSERT(0 == user_data.stream_id);
|
||||||
|
|
||||||
frame.headers.hd.flags |= NGHTTP2_FLAG_END_STREAM;
|
frame.headers.hd.flags |= NGHTTP2_FLAG_END_STREAM;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_end_headers_received(session, &frame));
|
CU_ASSERT(0 == nghttp2_session_end_headers_received(session, &frame, stream));
|
||||||
CU_ASSERT(5 == user_data.stream_id);
|
CU_ASSERT(5 == user_data.stream_id);
|
||||||
|
|
||||||
nghttp2_frame_headers_free(&frame.headers);
|
nghttp2_frame_headers_free(&frame.headers);
|
||||||
|
|
Loading…
Reference in New Issue