Commit e186e019 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

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.
parent ff475104
......@@ -231,20 +231,19 @@ static int on_header_callback(nghttp2_session *session,
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)
/* 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) {
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, "Response headers for stream ID=%d:\n",
frame->hd.stream_id);
}
break;
}
......@@ -252,7 +251,7 @@ static int on_end_headers_callback(nghttp2_session *session,
}
/* nghttp2_on_frame_recv_callback: Called when nghttp2 library
received a frame from the remote peer. */
received a complete frame from the remote peer. */
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data)
{
......@@ -261,8 +260,7 @@ static int on_frame_recv_callback(nghttp2_session *session,
case NGHTTP2_HEADERS:
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
fprintf(stderr, "Response headers for stream ID=%d:\n",
frame->hd.stream_id);
fprintf(stderr, "All headers received\n");
}
break;
}
......@@ -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_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);
}
......
......@@ -325,56 +325,6 @@ static char* percent_decode(const uint8_t *value, size_t valuelen)
return res;
}
/* nghttp2_on_header_callback: Called when nghttp2 library emits
single header name/value pair. */
static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame,
const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
void *user_data)
{
http2_stream_data *stream_data;
const char PATH[] = ":path";
switch(frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
break;
}
stream_data = nghttp2_session_get_stream_user_data(session,
frame->hd.stream_id);
if(stream_data->request_path) {
break;
}
if(namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
size_t j;
for(j = 0; j < valuelen && value[j] != '?'; ++j);
stream_data->request_path = percent_decode(value, j);
}
break;
}
return 0;
}
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
http2_stream_data *stream_data;
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,
......@@ -443,6 +393,53 @@ static int error_reply(nghttp2_session *session,
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)
......@@ -455,19 +452,16 @@ static int check_path(const char *path)
!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;
......@@ -492,13 +486,40 @@ static int on_request_recv_callback(nghttp2_session *session,
}
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,
......@@ -519,9 +540,9 @@ static void initialize_nghttp2_session(http2_session_data *session_data)
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);
}
......
......@@ -916,10 +916,6 @@ typedef int (*nghttp2_on_frame_recv_callback)
* 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
......@@ -1076,6 +1072,30 @@ typedef int (*nghttp2_on_unknown_frame_recv_callback)
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
*
......@@ -1083,9 +1103,11 @@ typedef int (*nghttp2_on_unknown_frame_recv_callback)
* 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|.
......@@ -1102,7 +1124,7 @@ typedef int (*nghttp2_on_unknown_frame_recv_callback)
* 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
......@@ -1121,32 +1143,6 @@ typedef int (*nghttp2_on_header_callback)
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
*
......@@ -1205,16 +1201,16 @@ typedef struct {
* 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;
/**
......@@ -1462,14 +1458,19 @@ int nghttp2_session_send(nghttp2_session *session);
*
* 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,
* 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 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,
......
This diff is collapsed.
......@@ -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,
nghttp2_frame *frame);
nghttp2_frame *frame,
nghttp2_stream *stream);
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,
nghttp2_frame *frame);
nghttp2_frame *frame,
nghttp2_stream *stream);
int nghttp2_session_on_request_headers_received(nghttp2_session *session,
nghttp2_frame *frame);
......
......@@ -65,7 +65,6 @@ const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION;
Config::Config()
: data_ptr(nullptr),
on_request_recv_callback(nullptr),
output_upper_thres(1024*1024),
header_table_size(-1),
port(0),
......@@ -801,45 +800,17 @@ int on_header_callback(nghttp2_session *session,
} // namespace
namespace {
int on_end_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
nghttp2_error_code error_code,
void *user_data)
int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data)
{
if(error_code != NGHTTP2_NO_ERROR) {
return 0;
}
auto hd = static_cast<Http2Handler*>(user_data);
if(frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
return 0;
}
auto hd = static_cast<Http2Handler*>(user_data);
auto stream = hd->get_stream(frame->hd.stream_id);
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;
}
auto stream = util::make_unique<Request>(frame->hd.stream_id);
hd->add_stream(frame->hd.stream_id, std::move(stream));
return 0;
}
} // namespace
......@@ -856,12 +827,49 @@ int hd_on_frame_recv_callback
switch(frame->hd.type) {
case NGHTTP2_DATA:
// 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;
case NGHTTP2_HEADERS:
switch(frame->headers.cat) {
case NGHTTP2_HCAT_REQUEST: {
auto req = util::make_unique<Request>(frame->hd.stream_id);
hd->add_stream(frame->hd.stream_id, std::move(req));
auto stream = hd->get_stream(frame->hd.stream_id);
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;
}
default:
......@@ -885,17 +893,6 @@ int hd_on_frame_recv_callback
}
} // 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 {
int hd_before_frame_send_callback
(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;
}
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_end_headers_callback = on_end_headers_callback;
callbacks.on_begin_headers_callback = on_begin_headers_callback;
}
} // namespace
......
......@@ -55,7 +55,6 @@ struct Config {
std::string private_key_file;
std::string cert_file;
void *data_ptr;
nghttp2_on_request_recv_callback on_request_recv_callback;
size_t output_upper_thres;
ssize_t header_table_size;
uint16_t port;
......@@ -144,9 +143,6 @@ private:
const Config *config_;
};
int htdocs_on_request_recv_callback
(nghttp2_session *session, int32_t stream_id, void *user_data);
ssize_t file_read_callback
(nghttp2_session *session, int32_t stream_id,
uint8_t *buf, size_t length, int *eof,
......
......@@ -1176,30 +1176,6 @@ int on_header_callback(nghttp2_session *session,
}
} // 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 {
int on_frame_recv_callback2
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
......@@ -1212,9 +1188,9 @@ int on_frame_recv_callback2
// req is nullptr.
if(req) {
req->record_response_time();
check_response_header(session, req);
}
}
if(frame->hd.type == NGHTTP2_SETTINGS &&
} else if(frame->hd.type == NGHTTP2_SETTINGS &&
(frame->hd.flags & NGHTTP2_FLAG_ACK)) {
auto client = get_session(user_data);
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_header_callback = on_header_callback;
callbacks.on_end_headers_callback = on_end_headers_callback;
std::string prev_scheme;
std::string prev_host;
......
......@@ -236,7 +236,6 @@ int main(int argc, char **argv)
SSL_load_error_strings();
SSL_library_init();
reset_timer();
config.on_request_recv_callback = htdocs_on_request_recv_callback;
HttpServer server(&config);
server.run();
......
......@@ -833,20 +833,44 @@ int on_header_callback(nghttp2_session *session,
} // namespace
namespace {
int on_end_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
nghttp2_error_code error_code,
void *user_data)
int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data)
{
if(error_code != NGHTTP2_NO_ERROR) {
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->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
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 http2session = static_cast<Http2Session*>(user_data);
auto sd = static_cast<StreamData*>
(nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
if(!sd || !sd->dconn) {
......@@ -952,32 +976,8 @@ int on_frame_recv_callback
{
auto http2session = static_cast<Http2Session*>(user_data);
switch(frame->hd.type) {
case NGHTTP2_HEADERS: {
if(frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
// 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_HEADERS:
return on_response_headers(http2session, session, frame);
case NGHTTP2_RST_STREAM: {
auto sd = static_cast<StreamData*>
(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_unknown_frame_recv_callback = on_unknown_frame_recv_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;
opt_set.no_auto_stream_window_update = 1;
......
......@@ -230,20 +230,35 @@ int on_header_callback(nghttp2_session *session,
} // namespace
namespace {
int on_end_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
nghttp2_error_code error_code,
void *user_data)
int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data)
{
if(error_code != NGHTTP2_NO_ERROR) {
auto upstream = static_cast<Http2Upstream*>(user_data);
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
return 0;
}
if(frame->hd.type != NGHTTP2_HEADERS ||
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 upstream = static_cast<Http2Upstream*>(user_data);
auto downstream = upstream->find_downstream(frame->hd.stream_id);
if(!downstream) {
return 0;
......@@ -357,21 +372,8 @@ int on_frame_recv_callback
}
break;
}
case NGHTTP2_HEADERS: {
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
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_HEADERS:
return on_request_headers(upstream, session, frame);
case NGHTTP2_PRIORITY: {
auto downstream = upstream->find_downstream(frame->hd.stream_id);
if(!downstream) {
......@@ -505,7 +507,7 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
callbacks.on_frame_not_send_callback = on_frame_not_send_callback;
callbacks.on_unknown_frame_recv_callback = on_unknown_frame_recv_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;
opt_set.no_auto_stream_window_update = 1;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment