nghttp: Wait for pushed resources to complete
The statistics of pushed resources are also calculated.
This commit is contained in:
parent
d1c1deaf03
commit
9cc7f9fb36
129
src/nghttp.cc
129
src/nghttp.cc
|
@ -248,6 +248,7 @@ std::string strip_fragment(const char *raw_uri)
|
||||||
namespace {
|
namespace {
|
||||||
struct Request {
|
struct Request {
|
||||||
Headers res_nva;
|
Headers res_nva;
|
||||||
|
Headers push_req_nva;
|
||||||
// URI without fragment
|
// URI without fragment
|
||||||
std::string uri;
|
std::string uri;
|
||||||
std::string status;
|
std::string status;
|
||||||
|
@ -261,6 +262,7 @@ struct Request {
|
||||||
int32_t pri;
|
int32_t pri;
|
||||||
// Recursion level: 0: first entity, 1: entity linked from first entity
|
// Recursion level: 0: first entity, 1: entity linked from first entity
|
||||||
int level;
|
int level;
|
||||||
|
// For pushed request, |uri| is empty and |u| is zero-cleared.
|
||||||
Request(const std::string& uri, const http_parser_url &u,
|
Request(const std::string& uri, const http_parser_url &u,
|
||||||
const nghttp2_data_provider *data_prd, int64_t data_length,
|
const nghttp2_data_provider *data_prd, int64_t data_length,
|
||||||
int32_t pri, int level = 0)
|
int32_t pri, int level = 0)
|
||||||
|
@ -1149,6 +1151,29 @@ void check_response_header(nghttp2_session *session, Request* req)
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int on_begin_headers_callback(nghttp2_session *session,
|
||||||
|
const nghttp2_frame *frame,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
auto client = get_session(user_data);
|
||||||
|
switch(frame->hd.type) {
|
||||||
|
case NGHTTP2_PUSH_PROMISE: {
|
||||||
|
auto stream_id = frame->push_promise.promised_stream_id;
|
||||||
|
http_parser_url u;
|
||||||
|
memset(&u, 0, sizeof(u));
|
||||||
|
// TODO Set pri and level
|
||||||
|
auto req = util::make_unique<Request>("", u, nullptr, 0, 0, 0);
|
||||||
|
nghttp2_session_set_stream_user_data(session, stream_id, req.get());
|
||||||
|
client->reqvec.push_back(std::move(req));
|
||||||
|
check_stream_id(session, stream_id, user_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} //namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int on_header_callback(nghttp2_session *session,
|
int on_header_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame,
|
const nghttp2_frame *frame,
|
||||||
|
@ -1160,17 +1185,30 @@ int on_header_callback(nghttp2_session *session,
|
||||||
verbose_on_header_callback(session, frame, name, namelen, value, valuelen,
|
verbose_on_header_callback(session, frame, name, namelen, value, valuelen,
|
||||||
user_data);
|
user_data);
|
||||||
}
|
}
|
||||||
if(frame->hd.type != NGHTTP2_HEADERS ||
|
switch(frame->hd.type) {
|
||||||
frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
|
case NGHTTP2_HEADERS: {
|
||||||
return 0;
|
if(frame->headers.cat != NGHTTP2_HCAT_RESPONSE &&
|
||||||
|
frame->headers.cat != NGHTTP2_HCAT_PUSH_RESPONSE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto req = (Request*)nghttp2_session_get_stream_user_data
|
||||||
|
(session, frame->hd.stream_id);
|
||||||
|
if(!req) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
http2::split_add_header(req->res_nva, name, namelen, value, valuelen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NGHTTP2_PUSH_PROMISE: {
|
||||||
|
auto req = (Request*)nghttp2_session_get_stream_user_data
|
||||||
|
(session, frame->push_promise.promised_stream_id);
|
||||||
|
if(!req) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
http2::split_add_header(req->push_req_nva, name, namelen, value, valuelen);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
http2::split_add_header(req->res_nva, name, namelen, value, valuelen);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -1179,8 +1217,13 @@ 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)
|
||||||
{
|
{
|
||||||
if(frame->hd.type == NGHTTP2_HEADERS &&
|
auto client = get_session(user_data);
|
||||||
frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
|
switch(frame->hd.type) {
|
||||||
|
case NGHTTP2_HEADERS: {
|
||||||
|
if(frame->headers.cat != NGHTTP2_HCAT_RESPONSE &&
|
||||||
|
frame->headers.cat != NGHTTP2_HCAT_PUSH_RESPONSE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
auto req = (Request*)nghttp2_session_get_stream_user_data
|
auto req = (Request*)nghttp2_session_get_stream_user_data
|
||||||
(session, frame->hd.stream_id);
|
(session, frame->hd.stream_id);
|
||||||
// If this is the HTTP Upgrade with OPTIONS method to avoid POST,
|
// If this is the HTTP Upgrade with OPTIONS method to avoid POST,
|
||||||
|
@ -1189,14 +1232,65 @@ int on_frame_recv_callback2
|
||||||
req->record_response_time();
|
req->record_response_time();
|
||||||
check_response_header(session, req);
|
check_response_header(session, req);
|
||||||
}
|
}
|
||||||
} else if(frame->hd.type == NGHTTP2_SETTINGS &&
|
break;
|
||||||
(frame->hd.flags & NGHTTP2_FLAG_ACK)) {
|
}
|
||||||
auto client = get_session(user_data);
|
case NGHTTP2_SETTINGS:
|
||||||
|
if((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(client->settings_timerev) {
|
if(client->settings_timerev) {
|
||||||
evtimer_del(client->settings_timerev);
|
evtimer_del(client->settings_timerev);
|
||||||
event_free(client->settings_timerev);
|
event_free(client->settings_timerev);
|
||||||
client->settings_timerev = nullptr;
|
client->settings_timerev = nullptr;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case NGHTTP2_PUSH_PROMISE: {
|
||||||
|
auto req = (Request*)nghttp2_session_get_stream_user_data
|
||||||
|
(session, frame->push_promise.promised_stream_id);
|
||||||
|
if(!req) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::string scheme, authority, method, path;
|
||||||
|
for(auto& nv : req->push_req_nva) {
|
||||||
|
if(nv.first == ":scheme") {
|
||||||
|
scheme = nv.second;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(nv.first == ":authority" || nv.first == "host") {
|
||||||
|
authority = nv.second;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(nv.first == ":method") {
|
||||||
|
method = nv.second;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(nv.first == ":path") {
|
||||||
|
path = nv.second;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(scheme.empty() || authority.empty() || method.empty() || path.empty() ||
|
||||||
|
path[0] != '/') {
|
||||||
|
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||||
|
frame->push_promise.promised_stream_id,
|
||||||
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::string uri = scheme;
|
||||||
|
uri += "://";
|
||||||
|
uri += authority;
|
||||||
|
uri += path;
|
||||||
|
http_parser_url u;
|
||||||
|
if(http_parser_parse_url(uri.c_str(), uri.size(), 0, &u) != 0) {
|
||||||
|
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||||
|
frame->push_promise.promised_stream_id,
|
||||||
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
req->uri = uri;
|
||||||
|
req->u = u;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(config.verbose) {
|
if(config.verbose) {
|
||||||
verbose_on_frame_recv_callback(session, frame, user_data);
|
verbose_on_frame_recv_callback(session, frame, user_data);
|
||||||
|
@ -1216,9 +1310,9 @@ int on_stream_close_callback
|
||||||
update_html_parser(client, (*itr).second, nullptr, 0, 1);
|
update_html_parser(client, (*itr).second, nullptr, 0, 1);
|
||||||
(*itr).second->record_complete_time();
|
(*itr).second->record_complete_time();
|
||||||
++client->complete;
|
++client->complete;
|
||||||
if(client->all_requests_processed()) {
|
}
|
||||||
nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
|
if(client->all_requests_processed()) {
|
||||||
}
|
nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1554,6 +1648,7 @@ int run(char **uris, int n)
|
||||||
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_begin_headers_callback = on_begin_headers_callback;
|
||||||
callbacks.on_header_callback = on_header_callback;
|
callbacks.on_header_callback = on_header_callback;
|
||||||
if(config.padding) {
|
if(config.padding) {
|
||||||
callbacks.select_padding_callback = select_padding_callback;
|
callbacks.select_padding_callback = select_padding_callback;
|
||||||
|
|
Loading…
Reference in New Issue