Make spdycat and spdyd barely work
This commit is contained in:
parent
48cb017245
commit
24cab312cf
|
@ -492,7 +492,7 @@ typedef struct {
|
||||||
/**
|
/**
|
||||||
* The error code. See :type:`nghttp2_error_code`.
|
* The error code. See :type:`nghttp2_error_code`.
|
||||||
*/
|
*/
|
||||||
uint32_t error_code;
|
nghttp2_error_code error_code;
|
||||||
} nghttp2_rst_stream;
|
} nghttp2_rst_stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -575,7 +575,7 @@ typedef struct {
|
||||||
/**
|
/**
|
||||||
* The error code. See :type:`nghttp2_error_code`.
|
* The error code. See :type:`nghttp2_error_code`.
|
||||||
*/
|
*/
|
||||||
uint32_t error_code;
|
nghttp2_error_code error_code;
|
||||||
/**
|
/**
|
||||||
* The additional debug data
|
* The additional debug data
|
||||||
*/
|
*/
|
||||||
|
@ -743,7 +743,7 @@ typedef void (*nghttp2_on_data_chunk_recv_callback)
|
||||||
* :type:`nghttp2_on_data_chunk_recv_callback`.
|
* :type:`nghttp2_on_data_chunk_recv_callback`.
|
||||||
*/
|
*/
|
||||||
typedef void (*nghttp2_on_data_recv_callback)
|
typedef void (*nghttp2_on_data_recv_callback)
|
||||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id, int32_t length,
|
(nghttp2_session *session, uint16_t length, uint8_t flags, int32_t stream_id,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -784,7 +784,7 @@ typedef void (*nghttp2_on_frame_not_send_callback)
|
||||||
* Callback function invoked after DATA frame is sent.
|
* Callback function invoked after DATA frame is sent.
|
||||||
*/
|
*/
|
||||||
typedef void (*nghttp2_on_data_send_callback)
|
typedef void (*nghttp2_on_data_send_callback)
|
||||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id, int32_t length,
|
(nghttp2_session *session, uint16_t length, uint8_t flags, int32_t stream_id,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1126,10 +1126,10 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
|
||||||
if(session->callbacks.on_data_send_callback) {
|
if(session->callbacks.on_data_send_callback) {
|
||||||
session->callbacks.on_data_send_callback
|
session->callbacks.on_data_send_callback
|
||||||
(session,
|
(session,
|
||||||
|
session->aob.framebuflen - NGHTTP2_FRAME_HEAD_LENGTH,
|
||||||
data_frame->eof ? data_frame->hd.flags :
|
data_frame->eof ? data_frame->hd.flags :
|
||||||
(data_frame->hd.flags & (~NGHTTP2_FLAG_END_STREAM)),
|
(data_frame->hd.flags & (~NGHTTP2_FLAG_END_STREAM)),
|
||||||
data_frame->hd.stream_id,
|
data_frame->hd.stream_id,
|
||||||
session->aob.framebuflen - NGHTTP2_FRAME_HEAD_LENGTH,
|
|
||||||
session->user_data);
|
session->user_data);
|
||||||
}
|
}
|
||||||
if(data_frame->eof && (data_frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) {
|
if(data_frame->eof && (data_frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) {
|
||||||
|
@ -1650,6 +1650,8 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return nghttp2_session_fail_session(session, NGHTTP2_PROTOCOL_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
session->remote_settings[entry->settings_id] = entry->value;
|
session->remote_settings[entry->settings_id] = entry->value;
|
||||||
|
@ -1915,7 +1917,7 @@ int nghttp2_session_on_data_received(nghttp2_session *session,
|
||||||
valid = 1;
|
valid = 1;
|
||||||
if(session->callbacks.on_data_recv_callback) {
|
if(session->callbacks.on_data_recv_callback) {
|
||||||
session->callbacks.on_data_recv_callback
|
session->callbacks.on_data_recv_callback
|
||||||
(session, flags, stream_id, length, session->user_data);
|
(session, length, flags, stream_id, session->user_data);
|
||||||
}
|
}
|
||||||
} else if(stream->state != NGHTTP2_STREAM_CLOSING) {
|
} else if(stream->state != NGHTTP2_STREAM_CLOSING) {
|
||||||
error_code = NGHTTP2_PROTOCOL_ERROR;
|
error_code = NGHTTP2_PROTOCOL_ERROR;
|
||||||
|
@ -1927,7 +1929,7 @@ int nghttp2_session_on_data_received(nghttp2_session *session,
|
||||||
valid = 1;
|
valid = 1;
|
||||||
if(session->callbacks.on_data_recv_callback) {
|
if(session->callbacks.on_data_recv_callback) {
|
||||||
session->callbacks.on_data_recv_callback
|
session->callbacks.on_data_recv_callback
|
||||||
(session, flags, stream_id, length, session->user_data);
|
(session, length, flags, stream_id, session->user_data);
|
||||||
}
|
}
|
||||||
if(flags & NGHTTP2_FLAG_END_STREAM) {
|
if(flags & NGHTTP2_FLAG_END_STREAM) {
|
||||||
nghttp2_session_call_on_request_recv(session, stream_id);
|
nghttp2_session_call_on_request_recv(session, stream_id);
|
||||||
|
|
|
@ -31,6 +31,7 @@ AM_CFLAGS = -Wall
|
||||||
AM_CPPFLAGS = -Wall -I$(srcdir)/../lib/includes -I$(builddir)/../lib/includes \
|
AM_CPPFLAGS = -Wall -I$(srcdir)/../lib/includes -I$(builddir)/../lib/includes \
|
||||||
@OPENSSL_CFLAGS@ @XML_CPPFLAGS@ @LIBEVENT_OPENSSL_CFLAGS@ @DEFS@
|
@OPENSSL_CFLAGS@ @XML_CPPFLAGS@ @LIBEVENT_OPENSSL_CFLAGS@ @DEFS@
|
||||||
AM_LDFLAGS = @OPENSSL_LIBS@ @XML_LIBS@ @LIBEVENT_OPENSSL_LIBS@ @SRC_LIBS@
|
AM_LDFLAGS = @OPENSSL_LIBS@ @XML_LIBS@ @LIBEVENT_OPENSSL_LIBS@ @SRC_LIBS@
|
||||||
|
AM_CXXFLAGS = -std=c++11
|
||||||
|
|
||||||
LDADD = $(top_builddir)/lib/libnghttp2.la
|
LDADD = $(top_builddir)/lib/libnghttp2.la
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ const std::string SPDYD_SERVER = "spdyd nghttp2/" NGHTTP2_VERSION;
|
||||||
|
|
||||||
Config::Config(): verbose(false), daemon(false), port(0),
|
Config::Config(): verbose(false), daemon(false), port(0),
|
||||||
on_request_recv_callback(0), data_ptr(0),
|
on_request_recv_callback(0), data_ptr(0),
|
||||||
version(0), verify_client(false), no_tls(false)
|
verify_client(false), no_tls(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Request::Request(int32_t stream_id)
|
Request::Request(int32_t stream_id)
|
||||||
|
@ -93,10 +93,9 @@ public:
|
||||||
{}
|
{}
|
||||||
~Sessions()
|
~Sessions()
|
||||||
{
|
{
|
||||||
for(std::set<EventHandler*>::iterator i = handlers_.begin(),
|
for(auto handler : handlers_) {
|
||||||
eoi = handlers_.end(); i != eoi; ++i) {
|
on_close(*this, handler);
|
||||||
on_close(*this, *i);
|
delete handler;
|
||||||
delete *i;
|
|
||||||
}
|
}
|
||||||
SSL_CTX_free(ssl_ctx_);
|
SSL_CTX_free(ssl_ctx_);
|
||||||
}
|
}
|
||||||
|
@ -175,22 +174,19 @@ void on_session_closed(EventHandler *hd, int64_t session_id)
|
||||||
|
|
||||||
SpdyEventHandler::SpdyEventHandler(const Config* config,
|
SpdyEventHandler::SpdyEventHandler(const Config* config,
|
||||||
int fd, SSL *ssl,
|
int fd, SSL *ssl,
|
||||||
uint16_t version,
|
|
||||||
const nghttp2_session_callbacks *callbacks,
|
const nghttp2_session_callbacks *callbacks,
|
||||||
int64_t session_id)
|
int64_t session_id)
|
||||||
: EventHandler(config),
|
: EventHandler(config),
|
||||||
fd_(fd), ssl_(ssl), version_(version), session_id_(session_id),
|
fd_(fd), ssl_(ssl), session_id_(session_id),
|
||||||
io_flags_(0)
|
io_flags_(0)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = nghttp2_session_server_new(&session_, version, callbacks, this);
|
r = nghttp2_session_server_new(&session_, callbacks, this);
|
||||||
assert(r == 0);
|
assert(r == 0);
|
||||||
nghttp2_settings_entry entry;
|
nghttp2_settings_entry entry;
|
||||||
entry.settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
entry.settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
||||||
entry.value = NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS;
|
entry.value = NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS;
|
||||||
entry.flags = NGHTTP2_ID_FLAG_SETTINGS_NONE;
|
r = nghttp2_submit_settings(session_, &entry, 1);
|
||||||
r = nghttp2_submit_settings(session_, NGHTTP2_FLAG_SETTINGS_NONE,
|
|
||||||
&entry, 1);
|
|
||||||
assert(r == 0);
|
assert(r == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,9 +194,8 @@ SpdyEventHandler::~SpdyEventHandler()
|
||||||
{
|
{
|
||||||
on_session_closed(this, session_id_);
|
on_session_closed(this, session_id_);
|
||||||
nghttp2_session_del(session_);
|
nghttp2_session_del(session_);
|
||||||
for(std::map<int32_t, Request*>::iterator i = id2req_.begin(),
|
for(auto& item : id2req_) {
|
||||||
eoi = id2req_.end(); i != eoi; ++i) {
|
delete item.second;
|
||||||
delete (*i).second;
|
|
||||||
}
|
}
|
||||||
if(ssl_) {
|
if(ssl_) {
|
||||||
SSL_shutdown(ssl_);
|
SSL_shutdown(ssl_);
|
||||||
|
@ -210,11 +205,6 @@ SpdyEventHandler::~SpdyEventHandler()
|
||||||
close(fd_);
|
close(fd_);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t SpdyEventHandler::version() const
|
|
||||||
{
|
|
||||||
return version_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SpdyEventHandler::execute(Sessions *sessions)
|
int SpdyEventHandler::execute(Sessions *sessions)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
@ -300,18 +290,17 @@ int SpdyEventHandler::submit_file_response(const std::string& status,
|
||||||
std::string last_modified_str;
|
std::string last_modified_str;
|
||||||
const char *nv[] = {
|
const char *nv[] = {
|
||||||
":status", status.c_str(),
|
":status", status.c_str(),
|
||||||
":version", "HTTP/1.1",
|
|
||||||
"server", SPDYD_SERVER.c_str(),
|
"server", SPDYD_SERVER.c_str(),
|
||||||
"content-length", content_length.c_str(),
|
"content-length", content_length.c_str(),
|
||||||
"cache-control", "max-age=3600",
|
"cache-control", "max-age=3600",
|
||||||
"date", date_str.c_str(),
|
"date", date_str.c_str(),
|
||||||
0, 0,
|
nullptr, nullptr,
|
||||||
0
|
nullptr
|
||||||
};
|
};
|
||||||
if(last_modified != 0) {
|
if(last_modified != 0) {
|
||||||
last_modified_str = util::http_date(last_modified);
|
last_modified_str = util::http_date(last_modified);
|
||||||
nv[12] = "last-modified";
|
nv[10] = "last-modified";
|
||||||
nv[13] = last_modified_str.c_str();
|
nv[11] = last_modified_str.c_str();
|
||||||
}
|
}
|
||||||
return nghttp2_submit_response(session_, stream_id, nv, data_prd);
|
return nghttp2_submit_response(session_, stream_id, nv, data_prd);
|
||||||
}
|
}
|
||||||
|
@ -323,20 +312,18 @@ int SpdyEventHandler::submit_response
|
||||||
nghttp2_data_provider *data_prd)
|
nghttp2_data_provider *data_prd)
|
||||||
{
|
{
|
||||||
std::string date_str = util::http_date(time(0));
|
std::string date_str = util::http_date(time(0));
|
||||||
const char **nv = new const char*[8+headers.size()*2+1];
|
const char **nv = new const char*[6+headers.size()*2+1];
|
||||||
nv[0] = ":status";
|
nv[0] = ":status";
|
||||||
nv[1] = status.c_str();
|
nv[1] = status.c_str();
|
||||||
nv[2] = ":version";
|
nv[2] = "server";
|
||||||
nv[3] = "HTTP/1.1";
|
nv[3] = SPDYD_SERVER.c_str();
|
||||||
nv[4] = "server";
|
nv[4] = "date";
|
||||||
nv[5] = SPDYD_SERVER.c_str();
|
nv[5] = date_str.c_str();
|
||||||
nv[6] = "date";
|
|
||||||
nv[7] = date_str.c_str();
|
|
||||||
for(int i = 0; i < (int)headers.size(); ++i) {
|
for(int i = 0; i < (int)headers.size(); ++i) {
|
||||||
nv[8+i*2] = headers[i].first.c_str();
|
nv[6+i*2] = headers[i].first.c_str();
|
||||||
nv[8+i*2+1] = headers[i].second.c_str();
|
nv[6+i*2+1] = headers[i].second.c_str();
|
||||||
}
|
}
|
||||||
nv[8+headers.size()*2] = 0;
|
nv[6+headers.size()*2] = nullptr;
|
||||||
int r = nghttp2_submit_response(session_, stream_id, nv, data_prd);
|
int r = nghttp2_submit_response(session_, stream_id, nv, data_prd);
|
||||||
delete [] nv;
|
delete [] nv;
|
||||||
return r;
|
return r;
|
||||||
|
@ -348,9 +335,8 @@ int SpdyEventHandler::submit_response(const std::string& status,
|
||||||
{
|
{
|
||||||
const char *nv[] = {
|
const char *nv[] = {
|
||||||
":status", status.c_str(),
|
":status", status.c_str(),
|
||||||
":version", "HTTP/1.1",
|
|
||||||
"server", SPDYD_SERVER.c_str(),
|
"server", SPDYD_SERVER.c_str(),
|
||||||
0
|
nullptr
|
||||||
};
|
};
|
||||||
return nghttp2_submit_response(session_, stream_id, nv, data_prd);
|
return nghttp2_submit_response(session_, stream_id, nv, data_prd);
|
||||||
}
|
}
|
||||||
|
@ -568,29 +554,33 @@ void append_nv(Request *req, char **nv)
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void hd_on_ctrl_recv_callback
|
void hd_on_frame_recv_callback
|
||||||
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
|
(nghttp2_session *session, nghttp2_frame *frame, void *user_data)
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
|
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
|
||||||
if(hd->config()->verbose) {
|
if(hd->config()->verbose) {
|
||||||
print_session_id(hd->session_id());
|
print_session_id(hd->session_id());
|
||||||
on_ctrl_recv_callback(session, type, frame, user_data);
|
on_frame_recv_callback(session, frame, user_data);
|
||||||
}
|
}
|
||||||
switch(type) {
|
switch(frame->hd.type) {
|
||||||
case NGHTTP2_SYN_STREAM: {
|
case NGHTTP2_HEADERS:
|
||||||
int32_t stream_id = frame->syn_stream.stream_id;
|
switch(frame->headers.cat) {
|
||||||
Request *req = new Request(stream_id);
|
case NGHTTP2_HCAT_START_STREAM: {
|
||||||
append_nv(req, frame->syn_stream.nv);
|
int32_t stream_id = frame->hd.stream_id;
|
||||||
hd->add_stream(stream_id, req);
|
auto req = new Request(stream_id);
|
||||||
|
append_nv(req, frame->headers.nv);
|
||||||
|
hd->add_stream(stream_id, req);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NGHTTP2_HCAT_HEADERS: {
|
||||||
|
Request *req = hd->get_stream(frame->hd.stream_id);
|
||||||
|
append_nv(req, frame->headers.nv);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case NGHTTP2_HEADERS: {
|
|
||||||
int32_t stream_id = frame->headers.stream_id;
|
|
||||||
Request *req = hd->get_stream(stream_id);
|
|
||||||
append_nv(req, frame->headers.nv);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -605,14 +595,14 @@ void htdocs_on_request_recv_callback
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void hd_on_ctrl_send_callback
|
void hd_on_frame_send_callback
|
||||||
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
|
(nghttp2_session *session, nghttp2_frame *frame,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
|
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
|
||||||
if(hd->config()->verbose) {
|
if(hd->config()->verbose) {
|
||||||
print_session_id(hd->session_id());
|
print_session_id(hd->session_id());
|
||||||
on_ctrl_send_callback(session, type, frame, user_data);
|
on_frame_send_callback(session, frame, user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -628,34 +618,34 @@ void on_data_chunk_recv_callback
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void hd_on_data_recv_callback
|
void hd_on_data_recv_callback
|
||||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id, int32_t length,
|
(nghttp2_session *session, uint16_t length, uint8_t flags, int32_t stream_id,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
// TODO Handle POST
|
// TODO Handle POST
|
||||||
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
|
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
|
||||||
if(hd->config()->verbose) {
|
if(hd->config()->verbose) {
|
||||||
print_session_id(hd->session_id());
|
print_session_id(hd->session_id());
|
||||||
on_data_recv_callback(session, flags, stream_id, length, user_data);
|
on_data_recv_callback(session, length, flags, stream_id, user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void hd_on_data_send_callback
|
void hd_on_data_send_callback
|
||||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id, int32_t length,
|
(nghttp2_session *session, uint16_t length, uint8_t flags, int32_t stream_id,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
|
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
|
||||||
if(hd->config()->verbose) {
|
if(hd->config()->verbose) {
|
||||||
print_session_id(hd->session_id());
|
print_session_id(hd->session_id());
|
||||||
on_data_send_callback(session, flags, stream_id, length, user_data);
|
on_data_send_callback(session, length, flags, stream_id, user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void on_stream_close_callback
|
void on_stream_close_callback
|
||||||
(nghttp2_session *session, int32_t stream_id, nghttp2_status_code status_code,
|
(nghttp2_session *session, int32_t stream_id, nghttp2_error_code error_code,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
|
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
|
||||||
|
@ -676,15 +666,15 @@ void fill_callback(nghttp2_session_callbacks& callbacks, const Config *config)
|
||||||
callbacks.send_callback = hd_send_callback;
|
callbacks.send_callback = hd_send_callback;
|
||||||
callbacks.recv_callback = hd_recv_callback;
|
callbacks.recv_callback = hd_recv_callback;
|
||||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
callbacks.on_stream_close_callback = on_stream_close_callback;
|
||||||
callbacks.on_ctrl_recv_callback = hd_on_ctrl_recv_callback;
|
callbacks.on_frame_recv_callback = hd_on_frame_recv_callback;
|
||||||
callbacks.on_ctrl_send_callback = hd_on_ctrl_send_callback;
|
callbacks.on_frame_send_callback = hd_on_frame_send_callback;
|
||||||
callbacks.on_data_recv_callback = hd_on_data_recv_callback;
|
callbacks.on_data_recv_callback = hd_on_data_recv_callback;
|
||||||
callbacks.on_data_send_callback = hd_on_data_send_callback;
|
callbacks.on_data_send_callback = hd_on_data_send_callback;
|
||||||
if(config->verbose) {
|
if(config->verbose) {
|
||||||
callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback;
|
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
||||||
callbacks.on_ctrl_recv_parse_error_callback =
|
callbacks.on_frame_recv_parse_error_callback =
|
||||||
on_ctrl_recv_parse_error_callback;
|
on_frame_recv_parse_error_callback;
|
||||||
callbacks.on_unknown_ctrl_recv_callback = on_unknown_ctrl_recv_callback;
|
callbacks.on_unknown_frame_recv_callback = 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_request_recv_callback = config->on_request_recv_callback;
|
||||||
|
@ -696,7 +686,7 @@ public:
|
||||||
SSLAcceptEventHandler(const Config *config,
|
SSLAcceptEventHandler(const Config *config,
|
||||||
int fd, SSL *ssl, int64_t session_id)
|
int fd, SSL *ssl, int64_t session_id)
|
||||||
: EventHandler(config),
|
: EventHandler(config),
|
||||||
fd_(fd), ssl_(ssl), version_(0), fail_(false), finish_(false),
|
fd_(fd), ssl_(ssl), fail_(false), finish_(false),
|
||||||
io_flags_(WANT_READ),
|
io_flags_(WANT_READ),
|
||||||
session_id_(session_id)
|
session_id_(session_id)
|
||||||
{}
|
{}
|
||||||
|
@ -725,17 +715,11 @@ public:
|
||||||
if(config()->verbose) {
|
if(config()->verbose) {
|
||||||
std::cout << "The negotiated next protocol: " << proto << std::endl;
|
std::cout << "The negotiated next protocol: " << proto << std::endl;
|
||||||
}
|
}
|
||||||
version_ = nghttp2_npn_get_version(next_proto, next_proto_len);
|
if(proto == "HTTP-draft-04/2.0") {
|
||||||
if(config()->version != 0) {
|
|
||||||
if(config()->version != version_) {
|
|
||||||
version_ = 0;
|
|
||||||
std::cerr << "The negotiated next protocol is not supported."
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(version_) {
|
|
||||||
add_next_handler(sessions);
|
add_next_handler(sessions);
|
||||||
} else {
|
} else {
|
||||||
|
std::cerr << "The negotiated next protocol is not supported."
|
||||||
|
<< std::endl;
|
||||||
fail_ = true;
|
fail_ = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -779,7 +763,7 @@ private:
|
||||||
nghttp2_session_callbacks callbacks;
|
nghttp2_session_callbacks callbacks;
|
||||||
fill_callback(callbacks, config());
|
fill_callback(callbacks, config());
|
||||||
SpdyEventHandler *hd = new SpdyEventHandler(config(),
|
SpdyEventHandler *hd = new SpdyEventHandler(config(),
|
||||||
fd_, ssl_, version_, &callbacks,
|
fd_, ssl_, &callbacks,
|
||||||
session_id_);
|
session_id_);
|
||||||
if(sessions->mod_poll(hd) == -1) {
|
if(sessions->mod_poll(hd) == -1) {
|
||||||
// fd_, ssl_ are freed by ~SpdyEventHandler()
|
// fd_, ssl_ are freed by ~SpdyEventHandler()
|
||||||
|
@ -791,7 +775,6 @@ private:
|
||||||
|
|
||||||
int fd_;
|
int fd_;
|
||||||
SSL *ssl_;
|
SSL *ssl_;
|
||||||
uint16_t version_;
|
|
||||||
bool fail_, finish_;
|
bool fail_, finish_;
|
||||||
uint8_t io_flags_;
|
uint8_t io_flags_;
|
||||||
int64_t session_id_;
|
int64_t session_id_;
|
||||||
|
@ -842,10 +825,8 @@ private:
|
||||||
if(config()->no_tls) {
|
if(config()->no_tls) {
|
||||||
nghttp2_session_callbacks callbacks;
|
nghttp2_session_callbacks callbacks;
|
||||||
fill_callback(callbacks, config());
|
fill_callback(callbacks, config());
|
||||||
SpdyEventHandler *hd = new SpdyEventHandler(config(),
|
auto hd = new SpdyEventHandler(config(), cfd, nullptr, &callbacks,
|
||||||
cfd, 0,
|
session_id);
|
||||||
config()->version, &callbacks,
|
|
||||||
session_id);
|
|
||||||
if(sessions->add_poll(hd) == -1) {
|
if(sessions->add_poll(hd) == -1) {
|
||||||
delete hd;
|
delete hd;
|
||||||
} else {
|
} else {
|
||||||
|
@ -857,8 +838,7 @@ private:
|
||||||
close(cfd);
|
close(cfd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SSLAcceptEventHandler *hd = new SSLAcceptEventHandler(config(), cfd, ssl,
|
auto hd = new SSLAcceptEventHandler(config(), cfd, ssl, session_id);
|
||||||
session_id);
|
|
||||||
if(sessions->add_poll(hd) == -1) {
|
if(sessions->add_poll(hd) == -1) {
|
||||||
delete hd;
|
delete hd;
|
||||||
SSL_free(ssl);
|
SSL_free(ssl);
|
||||||
|
@ -946,7 +926,7 @@ int SpdyServer::run()
|
||||||
{
|
{
|
||||||
SSL_CTX *ssl_ctx = 0;
|
SSL_CTX *ssl_ctx = 0;
|
||||||
std::pair<unsigned char*, size_t> next_proto;
|
std::pair<unsigned char*, size_t> next_proto;
|
||||||
unsigned char proto_list[14];
|
unsigned char proto_list[255];
|
||||||
if(!config_->no_tls) {
|
if(!config_->no_tls) {
|
||||||
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
|
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
|
||||||
if(!ssl_ctx) {
|
if(!ssl_ctx) {
|
||||||
|
@ -978,25 +958,11 @@ int SpdyServer::run()
|
||||||
verify_callback);
|
verify_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We speaks "spdy/2" and "spdy/3".
|
proto_list[0] = 17;
|
||||||
proto_list[0] = 6;
|
memcpy(&proto_list[1], "HTTP-draft-04/2.0", 17);
|
||||||
memcpy(&proto_list[1], "spdy/3", 6);
|
next_proto.first = proto_list;
|
||||||
proto_list[7] = 6;
|
next_proto.second = 18;
|
||||||
memcpy(&proto_list[8], "spdy/2", 6);
|
|
||||||
|
|
||||||
switch(config_->version) {
|
|
||||||
case NGHTTP2_PROTO_SPDY3:
|
|
||||||
next_proto.first = proto_list;
|
|
||||||
next_proto.second = 7;
|
|
||||||
break;
|
|
||||||
case NGHTTP2_PROTO_SPDY2:
|
|
||||||
next_proto.first = proto_list+7;
|
|
||||||
next_proto.second = 7;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
next_proto.first = proto_list;
|
|
||||||
next_proto.second = sizeof(proto_list);
|
|
||||||
}
|
|
||||||
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, &next_proto);
|
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, &next_proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1011,9 +977,8 @@ int SpdyServer::run()
|
||||||
if(sfd_[i] == -1) {
|
if(sfd_[i] == -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ListenEventHandler *listen_hd = new ListenEventHandler(config_,
|
auto listen_hd = new ListenEventHandler(config_, sfd_[i],
|
||||||
sfd_[i],
|
&session_id_seed);
|
||||||
&session_id_seed);
|
|
||||||
if(sessions.add_poll(listen_hd) == -1) {
|
if(sessions.add_poll(listen_hd) == -1) {
|
||||||
std::cerr << ipv << ": Adding listening socket to poll failed."
|
std::cerr << ipv << ": Adding listening socket to poll failed."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
@ -1034,8 +999,7 @@ int SpdyServer::run()
|
||||||
perror("EventPoll");
|
perror("EventPoll");
|
||||||
} else {
|
} else {
|
||||||
for(int i = 0; i < n; ++i) {
|
for(int i = 0; i < n; ++i) {
|
||||||
EventHandler *hd = reinterpret_cast<EventHandler*>
|
auto hd = reinterpret_cast<EventHandler*>(sessions.get_user_data(i));
|
||||||
(sessions.get_user_data(i));
|
|
||||||
int events = sessions.get_events(i);
|
int events = sessions.get_events(i);
|
||||||
int r = 0;
|
int r = 0;
|
||||||
if(hd->mark_del()) {
|
if(hd->mark_del()) {
|
||||||
|
@ -1059,10 +1023,9 @@ int SpdyServer::run()
|
||||||
del_list.push_back(hd);
|
del_list.push_back(hd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(std::vector<EventHandler*>::iterator i = del_list.begin(),
|
for(auto handler : del_list) {
|
||||||
eoi = del_list.end(); i != eoi; ++i) {
|
on_close(sessions, handler);
|
||||||
on_close(sessions, *i);
|
sessions.remove_handler(handler);
|
||||||
sessions.remove_handler(*i);
|
|
||||||
}
|
}
|
||||||
del_list.clear();
|
del_list.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,6 @@ struct Config {
|
||||||
std::string cert_file;
|
std::string cert_file;
|
||||||
nghttp2_on_request_recv_callback on_request_recv_callback;
|
nghttp2_on_request_recv_callback on_request_recv_callback;
|
||||||
void *data_ptr;
|
void *data_ptr;
|
||||||
uint16_t version;
|
|
||||||
bool verify_client;
|
bool verify_client;
|
||||||
bool no_tls;
|
bool no_tls;
|
||||||
Config();
|
Config();
|
||||||
|
@ -88,7 +87,7 @@ private:
|
||||||
|
|
||||||
struct Request {
|
struct Request {
|
||||||
int32_t stream_id;
|
int32_t stream_id;
|
||||||
std::vector<std::pair<std::string, std::string> > headers;
|
std::vector<std::pair<std::string, std::string>> headers;
|
||||||
int file;
|
int file;
|
||||||
std::pair<std::string, size_t> response_body;
|
std::pair<std::string, size_t> response_body;
|
||||||
Request(int32_t stream_id);
|
Request(int32_t stream_id);
|
||||||
|
@ -98,7 +97,7 @@ struct Request {
|
||||||
class SpdyEventHandler : public EventHandler {
|
class SpdyEventHandler : public EventHandler {
|
||||||
public:
|
public:
|
||||||
SpdyEventHandler(const Config* config,
|
SpdyEventHandler(const Config* config,
|
||||||
int fd, SSL *ssl, uint16_t version,
|
int fd, SSL *ssl,
|
||||||
const nghttp2_session_callbacks *callbacks,
|
const nghttp2_session_callbacks *callbacks,
|
||||||
int64_t session_id);
|
int64_t session_id);
|
||||||
virtual ~SpdyEventHandler();
|
virtual ~SpdyEventHandler();
|
||||||
|
@ -108,8 +107,6 @@ public:
|
||||||
virtual int fd() const;
|
virtual int fd() const;
|
||||||
virtual bool finish();
|
virtual bool finish();
|
||||||
|
|
||||||
uint16_t version() const;
|
|
||||||
|
|
||||||
ssize_t send_data(const uint8_t *data, size_t len, int flags);
|
ssize_t send_data(const uint8_t *data, size_t len, int flags);
|
||||||
|
|
||||||
ssize_t recv_data(uint8_t *data, size_t len, int flags);
|
ssize_t recv_data(uint8_t *data, size_t len, int flags);
|
||||||
|
@ -129,7 +126,7 @@ public:
|
||||||
int submit_response
|
int submit_response
|
||||||
(const std::string& status,
|
(const std::string& status,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
const std::vector<std::pair<std::string, std::string> >& headers,
|
const std::vector<std::pair<std::string, std::string>>& headers,
|
||||||
nghttp2_data_provider *data_prd);
|
nghttp2_data_provider *data_prd);
|
||||||
|
|
||||||
void add_stream(int32_t stream_id, Request *req);
|
void add_stream(int32_t stream_id, Request *req);
|
||||||
|
@ -140,7 +137,6 @@ private:
|
||||||
nghttp2_session *session_;
|
nghttp2_session *session_;
|
||||||
int fd_;
|
int fd_;
|
||||||
SSL* ssl_;
|
SSL* ssl_;
|
||||||
uint16_t version_;
|
|
||||||
int64_t session_id_;
|
int64_t session_id_;
|
||||||
uint8_t io_flags_;
|
uint8_t io_flags_;
|
||||||
std::map<int32_t, Request*> id2req_;
|
std::map<int32_t, Request*> id2req_;
|
||||||
|
|
|
@ -50,13 +50,12 @@ namespace nghttp2 {
|
||||||
|
|
||||||
bool ssl_debug = false;
|
bool ssl_debug = false;
|
||||||
|
|
||||||
Spdylay::Spdylay(int fd, SSL *ssl, uint16_t version,
|
Spdylay::Spdylay(int fd, SSL *ssl,
|
||||||
const nghttp2_session_callbacks *callbacks,
|
const nghttp2_session_callbacks *callbacks,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
: fd_(fd), ssl_(ssl), version_(version), user_data_(user_data),
|
: fd_(fd), ssl_(ssl), user_data_(user_data), io_flags_(0)
|
||||||
io_flags_(0)
|
|
||||||
{
|
{
|
||||||
int r = nghttp2_session_client_new(&session_, version_, callbacks, this);
|
int r = nghttp2_session_client_new(&session_, callbacks, this);
|
||||||
assert(r == 0);
|
assert(r == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,17 +151,16 @@ int Spdylay::submit_request(const std::string& scheme,
|
||||||
{
|
{
|
||||||
POS_METHOD = 0,
|
POS_METHOD = 0,
|
||||||
POS_PATH,
|
POS_PATH,
|
||||||
POS_VERSION,
|
|
||||||
POS_SCHEME,
|
POS_SCHEME,
|
||||||
POS_HOST,
|
POS_HOST,
|
||||||
POS_ACCEPT,
|
POS_ACCEPT,
|
||||||
|
POS_ACCEPT_ENCODING,
|
||||||
POS_USERAGENT
|
POS_USERAGENT
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *static_nv[] = {
|
const char *static_nv[] = {
|
||||||
":method", data_prd ? "POST" : "GET",
|
":method", data_prd ? "POST" : "GET",
|
||||||
":path", path.c_str(),
|
":path", path.c_str(),
|
||||||
":version", "HTTP/1.1",
|
|
||||||
":scheme", scheme.c_str(),
|
":scheme", scheme.c_str(),
|
||||||
":host", hostport.c_str(),
|
":host", hostport.c_str(),
|
||||||
"accept", "*/*",
|
"accept", "*/*",
|
||||||
|
@ -181,8 +179,8 @@ int Spdylay::submit_request(const std::string& scheme,
|
||||||
|
|
||||||
memcpy(nv, static_nv, hardcoded_entry_count * sizeof(*static_nv));
|
memcpy(nv, static_nv, hardcoded_entry_count * sizeof(*static_nv));
|
||||||
|
|
||||||
std::map<std::string,std::string>::const_iterator i = headers.begin();
|
auto i = std::begin(headers);
|
||||||
std::map<std::string,std::string>::const_iterator end = headers.end();
|
auto end = std::end(headers);
|
||||||
|
|
||||||
int pos = hardcoded_entry_count;
|
int pos = hardcoded_entry_count;
|
||||||
|
|
||||||
|
@ -213,7 +211,7 @@ int Spdylay::submit_request(const std::string& scheme,
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
nv[pos] = NULL;
|
nv[pos] = nullptr;
|
||||||
|
|
||||||
int r = nghttp2_submit_request(session_, pri, nv, data_prd,
|
int r = nghttp2_submit_request(session_, pri, nv, data_prd,
|
||||||
stream_user_data);
|
stream_user_data);
|
||||||
|
@ -223,9 +221,9 @@ int Spdylay::submit_request(const std::string& scheme,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Spdylay::submit_settings(int flags, nghttp2_settings_entry *iv, size_t niv)
|
int Spdylay::submit_settings(nghttp2_settings_entry *iv, size_t niv)
|
||||||
{
|
{
|
||||||
return nghttp2_submit_settings(session_, flags, iv, niv);
|
return nghttp2_submit_settings(session_, iv, niv);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Spdylay::would_block()
|
bool Spdylay::would_block()
|
||||||
|
@ -456,15 +454,41 @@ ssize_t recv_callback(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char *ctrl_names[] = {
|
const char* strstatus(nghttp2_error_code error_code)
|
||||||
"SYN_STREAM",
|
{
|
||||||
"SYN_REPLY",
|
switch(error_code) {
|
||||||
|
case NGHTTP2_NO_ERROR:
|
||||||
|
return "NO_ERROR";
|
||||||
|
case NGHTTP2_PROTOCOL_ERROR:
|
||||||
|
return "PROTOCOL_ERROR";
|
||||||
|
case NGHTTP2_INTERNAL_ERROR:
|
||||||
|
return "INTERNAL_ERROR";
|
||||||
|
case NGHTTP2_FLOW_CONTROL_ERROR:
|
||||||
|
return "FLOW_CONTROL_ERROR";
|
||||||
|
case NGHTTP2_STREAM_CLOSED:
|
||||||
|
return "STREAM_CLOSED";
|
||||||
|
case NGHTTP2_FRAME_TOO_LARGE:
|
||||||
|
return "FRAME_TOO_LARGE";
|
||||||
|
case NGHTTP2_REFUSED_STREAM:
|
||||||
|
return "REFUSED_STREAM";
|
||||||
|
case NGHTTP2_CANCEL:
|
||||||
|
return "CANCEL";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const char *frame_names[] = {
|
||||||
|
"DATA",
|
||||||
|
"HEADERS",
|
||||||
|
"PRIORITY",
|
||||||
"RST_STREAM",
|
"RST_STREAM",
|
||||||
"SETTINGS",
|
"SETTINGS",
|
||||||
"NOOP",
|
"PUSH_PROMISE",
|
||||||
"PING",
|
"PING",
|
||||||
"GOAWAY",
|
"GOAWAY",
|
||||||
"HEADERS",
|
|
||||||
"WINDOW_UPDATE"
|
"WINDOW_UPDATE"
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -521,10 +545,57 @@ void print_timer()
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void print_ctrl_hd(const nghttp2_ctrl_hd& hd)
|
void print_frame_hd(const nghttp2_frame_hd& hd)
|
||||||
{
|
{
|
||||||
printf("<version=%u, flags=%u, length=%d>\n",
|
printf("<length=%d, flags=%u, stream_id=%d>\n",
|
||||||
hd.version, hd.flags, hd.length);
|
hd.length, hd.flags, hd.stream_id);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void print_flags(const nghttp2_frame_hd& hd)
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
switch(hd.type) {
|
||||||
|
case NGHTTP2_DATA:
|
||||||
|
if(hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||||
|
s += "END_STREAM";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NGHTTP2_HEADERS:
|
||||||
|
if(hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||||
|
s += "END_STREAM";
|
||||||
|
}
|
||||||
|
if(hd.flags & NGHTTP2_FLAG_END_HEADERS) {
|
||||||
|
if(!s.empty()) {
|
||||||
|
s += " | ";
|
||||||
|
}
|
||||||
|
s += "END_HEADERS";
|
||||||
|
}
|
||||||
|
if(hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||||
|
if(!s.empty()) {
|
||||||
|
s += " | ";
|
||||||
|
}
|
||||||
|
s += "PRIORITY";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NGHTTP2_PUSH_PROMISE:
|
||||||
|
if(hd.flags & NGHTTP2_FLAG_END_PUSH_PROMISE) {
|
||||||
|
s += "END_PUSH_PROMISE";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NGHTTP2_PING:
|
||||||
|
if(hd.flags & NGHTTP2_FLAG_PONG) {
|
||||||
|
s += "PONG";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NGHTTP2_WINDOW_UPDATE:
|
||||||
|
if(hd.flags & NGHTTP2_FLAG_END_FLOW_CONTROL) {
|
||||||
|
s += "END_FLOW_CONTROL";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("; %s\n", s.c_str());
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -541,60 +612,69 @@ const char* frame_name_ansi_esc(print_type ptype)
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void print_frame(print_type ptype, nghttp2_frame_type type,
|
void print_frame(print_type ptype, nghttp2_frame *frame)
|
||||||
nghttp2_frame *frame)
|
|
||||||
{
|
{
|
||||||
printf("%s%s%s frame ",
|
printf("%s%s%s frame ",
|
||||||
frame_name_ansi_esc(ptype),
|
frame_name_ansi_esc(ptype),
|
||||||
ctrl_names[type-1],
|
frame_names[frame->hd.type],
|
||||||
ansi_escend());
|
ansi_escend());
|
||||||
print_ctrl_hd(frame->syn_stream.hd);
|
print_frame_hd(frame->hd);
|
||||||
switch(type) {
|
if(frame->hd.flags) {
|
||||||
case NGHTTP2_SYN_STREAM:
|
|
||||||
print_frame_attr_indent();
|
print_frame_attr_indent();
|
||||||
printf("(stream_id=%d, assoc_stream_id=%d, pri=%u)\n",
|
print_flags(frame->hd);
|
||||||
frame->syn_stream.stream_id, frame->syn_stream.assoc_stream_id,
|
}
|
||||||
frame->syn_stream.pri);
|
switch(frame->hd.type) {
|
||||||
print_nv(frame->syn_stream.nv);
|
case NGHTTP2_HEADERS:
|
||||||
break;
|
|
||||||
case NGHTTP2_SYN_REPLY:
|
|
||||||
print_frame_attr_indent();
|
print_frame_attr_indent();
|
||||||
printf("(stream_id=%d)\n", frame->syn_reply.stream_id);
|
printf("(pri=%d)\n", frame->headers.pri);
|
||||||
print_nv(frame->syn_reply.nv);
|
switch(frame->headers.cat) {
|
||||||
|
case NGHTTP2_HCAT_START_STREAM:
|
||||||
|
print_frame_attr_indent();
|
||||||
|
printf("; Open new stream\n");
|
||||||
|
break;
|
||||||
|
case NGHTTP2_HCAT_REPLY:
|
||||||
|
print_frame_attr_indent();
|
||||||
|
printf("; First response header\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
print_nv(frame->headers.nv);
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_RST_STREAM:
|
case NGHTTP2_RST_STREAM:
|
||||||
print_frame_attr_indent();
|
print_frame_attr_indent();
|
||||||
printf("(stream_id=%d, status_code=%u)\n",
|
printf("(error_code=%s(%u))\n",
|
||||||
frame->rst_stream.stream_id, frame->rst_stream.status_code);
|
strstatus(frame->rst_stream.error_code),
|
||||||
|
frame->rst_stream.error_code);
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_SETTINGS:
|
case NGHTTP2_SETTINGS:
|
||||||
print_frame_attr_indent();
|
print_frame_attr_indent();
|
||||||
printf("(niv=%lu)\n", static_cast<unsigned long>(frame->settings.niv));
|
printf("(niv=%lu)\n", static_cast<unsigned long>(frame->settings.niv));
|
||||||
for(size_t i = 0; i < frame->settings.niv; ++i) {
|
for(size_t i = 0; i < frame->settings.niv; ++i) {
|
||||||
print_frame_attr_indent();
|
print_frame_attr_indent();
|
||||||
printf("[%d(%u):%u]\n",
|
printf("[%d:%u]\n",
|
||||||
frame->settings.iv[i].settings_id,
|
frame->settings.iv[i].settings_id,
|
||||||
frame->settings.iv[i].flags, frame->settings.iv[i].value);
|
frame->settings.iv[i].value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_PING:
|
case NGHTTP2_PING:
|
||||||
print_frame_attr_indent();
|
print_frame_attr_indent();
|
||||||
printf("(unique_id=%d)\n", frame->ping.unique_id);
|
printf("(opaque_data=%s)\n",
|
||||||
|
util::format_hex(frame->ping.opaque_data, 8).c_str());
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_GOAWAY:
|
case NGHTTP2_GOAWAY:
|
||||||
print_frame_attr_indent();
|
print_frame_attr_indent();
|
||||||
printf("(last_good_stream_id=%d)\n", frame->goaway.last_good_stream_id);
|
printf("(last_stream_id=%d, error_code=%s(%u), opaque_data=%s)\n",
|
||||||
break;
|
frame->goaway.last_stream_id,
|
||||||
case NGHTTP2_HEADERS:
|
strstatus(frame->goaway.error_code),
|
||||||
print_frame_attr_indent();
|
frame->goaway.error_code,
|
||||||
printf("(stream_id=%d)\n", frame->headers.stream_id);
|
util::format_hex(frame->goaway.opaque_data,
|
||||||
print_nv(frame->headers.nv);
|
frame->goaway.opaque_data_len).c_str());
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_WINDOW_UPDATE:
|
case NGHTTP2_WINDOW_UPDATE:
|
||||||
print_frame_attr_indent();
|
print_frame_attr_indent();
|
||||||
printf("(stream_id=%d, delta_window_size=%d)\n",
|
printf("(window_size_increment=%d)\n",
|
||||||
frame->window_update.stream_id,
|
frame->window_update.window_size_increment);
|
||||||
frame->window_update.delta_window_size);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
@ -603,57 +683,22 @@ void print_frame(print_type ptype, nghttp2_frame_type type,
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void on_ctrl_recv_callback
|
void on_frame_recv_callback
|
||||||
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
|
(nghttp2_session *session, nghttp2_frame *frame, void *user_data)
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
print_timer();
|
print_timer();
|
||||||
printf(" recv ");
|
printf(" recv ");
|
||||||
print_frame(PRINT_RECV, type, frame);
|
print_frame(PRINT_RECV, frame);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
void on_invalid_frame_recv_callback
|
||||||
const char* strstatus(uint32_t status_code)
|
(nghttp2_session *session, nghttp2_frame *frame,
|
||||||
{
|
nghttp2_error_code error_code, void *user_data)
|
||||||
switch(status_code) {
|
|
||||||
case NGHTTP2_OK:
|
|
||||||
return "OK";
|
|
||||||
case NGHTTP2_PROTOCOL_ERROR:
|
|
||||||
return "PROTOCOL_ERROR";
|
|
||||||
case NGHTTP2_INVALID_STREAM:
|
|
||||||
return "INVALID_STREAM";
|
|
||||||
case NGHTTP2_REFUSED_STREAM:
|
|
||||||
return "REFUSED_STREAM";
|
|
||||||
case NGHTTP2_UNSUPPORTED_VERSION:
|
|
||||||
return "UNSUPPORTED_VERSION";
|
|
||||||
case NGHTTP2_CANCEL:
|
|
||||||
return "CANCEL";
|
|
||||||
case NGHTTP2_INTERNAL_ERROR:
|
|
||||||
return "INTERNAL_ERROR";
|
|
||||||
case NGHTTP2_FLOW_CONTROL_ERROR:
|
|
||||||
return "FLOW_CONTROL_ERROR";
|
|
||||||
case NGHTTP2_STREAM_IN_USE:
|
|
||||||
return "STREAM_IN_USE";
|
|
||||||
case NGHTTP2_STREAM_ALREADY_CLOSED:
|
|
||||||
return "STREAM_ALREADY_CLOSED";
|
|
||||||
case NGHTTP2_INVALID_CREDENTIALS:
|
|
||||||
return "INVALID_CREDENTIALS";
|
|
||||||
case NGHTTP2_FRAME_TOO_LARGE:
|
|
||||||
return "FRAME_TOO_LARGE";
|
|
||||||
default:
|
|
||||||
return "Unknown status code";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void on_invalid_ctrl_recv_callback
|
|
||||||
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
|
|
||||||
uint32_t status_code, void *user_data)
|
|
||||||
{
|
{
|
||||||
print_timer();
|
print_timer();
|
||||||
printf(" [INVALID; status=%s] recv ", strstatus(status_code));
|
printf(" [INVALID; status=%s] recv ", strstatus(error_code));
|
||||||
print_frame(PRINT_RECV, type, frame);
|
print_frame(PRINT_RECV, frame);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,7 +715,7 @@ void dump_header(const uint8_t *head, size_t headlen)
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void on_ctrl_recv_parse_error_callback(nghttp2_session *session,
|
void on_frame_recv_parse_error_callback(nghttp2_session *session,
|
||||||
nghttp2_frame_type type,
|
nghttp2_frame_type type,
|
||||||
const uint8_t *head,
|
const uint8_t *head,
|
||||||
size_t headlen,
|
size_t headlen,
|
||||||
|
@ -681,7 +726,7 @@ void on_ctrl_recv_parse_error_callback(nghttp2_session *session,
|
||||||
print_timer();
|
print_timer();
|
||||||
printf(" [PARSE_ERROR] recv %s%s%s frame\n",
|
printf(" [PARSE_ERROR] recv %s%s%s frame\n",
|
||||||
frame_name_ansi_esc(PRINT_RECV),
|
frame_name_ansi_esc(PRINT_RECV),
|
||||||
ctrl_names[type-1],
|
frame_names[type],
|
||||||
ansi_escend());
|
ansi_escend());
|
||||||
print_frame_attr_indent();
|
print_frame_attr_indent();
|
||||||
printf("Error: %s\n", nghttp2_strerror(error_code));
|
printf("Error: %s\n", nghttp2_strerror(error_code));
|
||||||
|
@ -689,7 +734,7 @@ void on_ctrl_recv_parse_error_callback(nghttp2_session *session,
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_unknown_ctrl_recv_callback(nghttp2_session *session,
|
void on_unknown_frame_recv_callback(nghttp2_session *session,
|
||||||
const uint8_t *head,
|
const uint8_t *head,
|
||||||
size_t headlen,
|
size_t headlen,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload,
|
||||||
|
@ -702,43 +747,43 @@ void on_unknown_ctrl_recv_callback(nghttp2_session *session,
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_ctrl_send_callback
|
void on_frame_send_callback
|
||||||
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
|
(nghttp2_session *session, nghttp2_frame *frame, void *user_data)
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
print_timer();
|
print_timer();
|
||||||
printf(" send ");
|
printf(" send ");
|
||||||
print_frame(PRINT_SEND, type, frame);
|
print_frame(PRINT_SEND, frame);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void print_data_frame(print_type ptype, uint8_t flags, int32_t stream_id,
|
void print_data_frame(print_type ptype, uint16_t length, uint8_t flags,
|
||||||
int32_t length)
|
int32_t stream_id)
|
||||||
{
|
{
|
||||||
printf("%sDATA%s frame (stream_id=%d, flags=%d, length=%d)\n",
|
printf("%sDATA%s frame (length=%d, flags=%d, stream_id=%d)\n",
|
||||||
frame_name_ansi_esc(ptype), ansi_escend(),
|
frame_name_ansi_esc(ptype), ansi_escend(),
|
||||||
stream_id, flags, length);
|
length, flags, stream_id);
|
||||||
|
print_frame_attr_indent();
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void on_data_recv_callback
|
void on_data_recv_callback
|
||||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id, int32_t length,
|
(nghttp2_session *session, uint16_t length, uint8_t flags, int32_t stream_id,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
print_timer();
|
print_timer();
|
||||||
printf(" recv ");
|
printf(" recv ");
|
||||||
print_data_frame(PRINT_RECV, flags, stream_id, length);
|
print_data_frame(PRINT_RECV, length, flags, stream_id);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_data_send_callback
|
void on_data_send_callback
|
||||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id, int32_t length,
|
(nghttp2_session *session, uint16_t length, uint8_t flags, int32_t stream_id,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
print_timer();
|
print_timer();
|
||||||
printf(" send ");
|
printf(" send ");
|
||||||
print_data_frame(PRINT_SEND, flags, stream_id, length);
|
print_data_frame(PRINT_SEND, length, flags, stream_id);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,18 +815,10 @@ int select_next_proto_cb(SSL* ssl,
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string& next_proto = *(std::string*)arg;
|
if(nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
|
||||||
if(next_proto.empty()) {
|
std::cerr << "Server did not advertise HTTP/2.0 protocol."
|
||||||
if(nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
|
<< std::endl;
|
||||||
std::cerr << "Server did not advertise spdy/2 or spdy/3 protocol."
|
abort();
|
||||||
<< std::endl;
|
|
||||||
abort();
|
|
||||||
} else {
|
|
||||||
next_proto.assign(&(*out)[0], &(*out)[*outlen]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*out = (unsigned char*)(next_proto.c_str());
|
|
||||||
*outlen = next_proto.size();
|
|
||||||
}
|
}
|
||||||
if(ssl_debug) {
|
if(ssl_debug) {
|
||||||
std::cout << " NPN selected the protocol: "
|
std::cout << " NPN selected the protocol: "
|
||||||
|
|
|
@ -43,7 +43,7 @@ extern bool ssl_debug;
|
||||||
|
|
||||||
class Spdylay {
|
class Spdylay {
|
||||||
public:
|
public:
|
||||||
Spdylay(int fd, SSL *ssl, uint16_t version,
|
Spdylay(int fd, SSL *ssl,
|
||||||
const nghttp2_session_callbacks *callbacks,
|
const nghttp2_session_callbacks *callbacks,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
~Spdylay();
|
~Spdylay();
|
||||||
|
@ -62,13 +62,12 @@ public:
|
||||||
const nghttp2_data_provider *data_prd,
|
const nghttp2_data_provider *data_prd,
|
||||||
int64_t data_length,
|
int64_t data_length,
|
||||||
void *stream_user_data);
|
void *stream_user_data);
|
||||||
int submit_settings(int flags, nghttp2_settings_entry *iv, size_t niv);
|
int submit_settings(nghttp2_settings_entry *iv, size_t niv);
|
||||||
bool would_block();
|
bool would_block();
|
||||||
void* user_data();
|
void* user_data();
|
||||||
private:
|
private:
|
||||||
int fd_;
|
int fd_;
|
||||||
SSL *ssl_;
|
SSL *ssl_;
|
||||||
uint16_t version_;
|
|
||||||
nghttp2_session *session_;
|
nghttp2_session *session_;
|
||||||
void *user_data_;
|
void *user_data_;
|
||||||
uint8_t io_flags_;
|
uint8_t io_flags_;
|
||||||
|
@ -94,15 +93,14 @@ ssize_t recv_callback(nghttp2_session *session,
|
||||||
|
|
||||||
void print_nv(char **nv);
|
void print_nv(char **nv);
|
||||||
|
|
||||||
void on_ctrl_recv_callback
|
void on_frame_recv_callback
|
||||||
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
|
(nghttp2_session *session, nghttp2_frame *frame, void *user_data);
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
void on_invalid_ctrl_recv_callback
|
void on_invalid_frame_recv_callback
|
||||||
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
|
(nghttp2_session *session, nghttp2_frame *frame,
|
||||||
uint32_t status_code, void *user_data);
|
nghttp2_error_code error_code, void *user_data);
|
||||||
|
|
||||||
void on_ctrl_recv_parse_error_callback(nghttp2_session *session,
|
void on_frame_recv_parse_error_callback(nghttp2_session *session,
|
||||||
nghttp2_frame_type type,
|
nghttp2_frame_type type,
|
||||||
const uint8_t *head,
|
const uint8_t *head,
|
||||||
size_t headlen,
|
size_t headlen,
|
||||||
|
@ -110,23 +108,22 @@ void on_ctrl_recv_parse_error_callback(nghttp2_session *session,
|
||||||
size_t payloadlen,
|
size_t payloadlen,
|
||||||
int error_code, void *user_data);
|
int error_code, void *user_data);
|
||||||
|
|
||||||
void on_unknown_ctrl_recv_callback(nghttp2_session *session,
|
void on_unknown_frame_recv_callback(nghttp2_session *session,
|
||||||
const uint8_t *head,
|
const uint8_t *head,
|
||||||
size_t headlen,
|
size_t headlen,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload,
|
||||||
size_t payloadlen,
|
size_t payloadlen,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
void on_ctrl_send_callback
|
void on_frame_send_callback
|
||||||
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
|
(nghttp2_session *session, nghttp2_frame *frame, void *user_data);
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
void on_data_recv_callback
|
void on_data_recv_callback
|
||||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id, int32_t length,
|
(nghttp2_session *session, uint16_t length, uint8_t flags, int32_t stream_id,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
void on_data_send_callback
|
void on_data_send_callback
|
||||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id, int32_t length,
|
(nghttp2_session *session, uint16_t length, uint8_t flags, int32_t stream_id,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
void ctl_poll(pollfd *pollfd, Spdylay *sc);
|
void ctl_poll(pollfd *pollfd, Spdylay *sc);
|
||||||
|
|
165
src/spdycat.cc
165
src/spdycat.cc
|
@ -75,7 +75,6 @@ struct Config {
|
||||||
bool stat;
|
bool stat;
|
||||||
bool no_tls;
|
bool no_tls;
|
||||||
int multiply;
|
int multiply;
|
||||||
int spdy_version;
|
|
||||||
// milliseconds
|
// milliseconds
|
||||||
int timeout;
|
int timeout;
|
||||||
std::string certfile;
|
std::string certfile;
|
||||||
|
@ -85,7 +84,7 @@ struct Config {
|
||||||
std::string datafile;
|
std::string datafile;
|
||||||
Config():null_out(false), remote_name(false), verbose(false),
|
Config():null_out(false), remote_name(false), verbose(false),
|
||||||
get_assets(false), stat(false), no_tls(false), multiply(1),
|
get_assets(false), stat(false), no_tls(false), multiply(1),
|
||||||
spdy_version(-1), timeout(-1), window_bits(-1)
|
timeout(-1), window_bits(-1)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -447,47 +446,42 @@ void on_data_chunk_recv_callback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_stream_id(nghttp2_session *session,
|
void check_stream_id(nghttp2_session *session, nghttp2_frame *frame,
|
||||||
nghttp2_frame_type type, nghttp2_frame *frame,
|
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
SpdySession *spdySession = get_session(user_data);
|
SpdySession *spdySession = get_session(user_data);
|
||||||
int32_t stream_id = frame->syn_stream.stream_id;
|
int32_t stream_id = frame->hd.stream_id;
|
||||||
Request *req = (Request*)nghttp2_session_get_stream_user_data(session,
|
Request *req = (Request*)nghttp2_session_get_stream_user_data(session,
|
||||||
stream_id);
|
stream_id);
|
||||||
spdySession->streams[stream_id] = req;
|
spdySession->streams[stream_id] = req;
|
||||||
req->record_syn_stream_time();
|
req->record_syn_stream_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_ctrl_send_callback2
|
void on_frame_send_callback2
|
||||||
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
|
(nghttp2_session *session, nghttp2_frame *frame, void *user_data)
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
if(type == NGHTTP2_SYN_STREAM) {
|
if(frame->hd.type == NGHTTP2_HEADERS &&
|
||||||
check_stream_id(session, type, frame, user_data);
|
frame->headers.cat == NGHTTP2_HCAT_START_STREAM) {
|
||||||
|
check_stream_id(session, frame, user_data);
|
||||||
}
|
}
|
||||||
if(config.verbose) {
|
if(config.verbose) {
|
||||||
on_ctrl_send_callback(session, type, frame, user_data);
|
on_frame_send_callback(session, frame, user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_response_header
|
void check_response_header
|
||||||
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
|
(nghttp2_session *session, nghttp2_frame *frame, void *user_data)
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
char **nv;
|
char **nv;
|
||||||
int32_t stream_id;
|
int32_t stream_id;
|
||||||
if(type == NGHTTP2_SYN_REPLY) {
|
if(frame->hd.type == NGHTTP2_HEADERS) {
|
||||||
nv = frame->syn_reply.nv;
|
|
||||||
stream_id = frame->syn_reply.stream_id;
|
|
||||||
} else if(type == NGHTTP2_HEADERS) {
|
|
||||||
nv = frame->headers.nv;
|
nv = frame->headers.nv;
|
||||||
stream_id = frame->headers.stream_id;
|
stream_id = frame->hd.stream_id;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Request *req = (Request*)nghttp2_session_get_stream_user_data(session,
|
auto req = (Request*)nghttp2_session_get_stream_user_data(session,
|
||||||
stream_id);
|
stream_id);
|
||||||
if(!req) {
|
if(!req) {
|
||||||
// Server-pushed stream does not have stream user data
|
// Server-pushed stream does not have stream user data
|
||||||
return;
|
return;
|
||||||
|
@ -512,35 +506,34 @@ void check_response_header
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_ctrl_recv_callback2
|
void on_frame_recv_callback2
|
||||||
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
|
(nghttp2_session *session, nghttp2_frame *frame, void *user_data)
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
if(type == NGHTTP2_SYN_REPLY) {
|
if(frame->hd.type == NGHTTP2_HEADERS &&
|
||||||
Request *req = (Request*)nghttp2_session_get_stream_user_data
|
frame->headers.cat == NGHTTP2_HCAT_REPLY) {
|
||||||
(session, frame->syn_reply.stream_id);
|
auto req = (Request*)nghttp2_session_get_stream_user_data
|
||||||
|
(session, frame->hd.stream_id);
|
||||||
assert(req);
|
assert(req);
|
||||||
req->record_syn_reply_time();
|
req->record_syn_reply_time();
|
||||||
}
|
}
|
||||||
check_response_header(session, type, frame, user_data);
|
check_response_header(session, frame, user_data);
|
||||||
if(config.verbose) {
|
if(config.verbose) {
|
||||||
on_ctrl_recv_callback(session, type, frame, user_data);
|
on_frame_recv_callback(session, frame, user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_stream_close_callback
|
void on_stream_close_callback
|
||||||
(nghttp2_session *session, int32_t stream_id, nghttp2_status_code status_code,
|
(nghttp2_session *session, int32_t stream_id, nghttp2_error_code error_code,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
SpdySession *spdySession = get_session(user_data);
|
SpdySession *spdySession = get_session(user_data);
|
||||||
std::map<int32_t, Request*>::iterator itr =
|
auto itr = spdySession->streams.find(stream_id);
|
||||||
spdySession->streams.find(stream_id);
|
|
||||||
if(itr != spdySession->streams.end()) {
|
if(itr != spdySession->streams.end()) {
|
||||||
update_html_parser(spdySession, (*itr).second, 0, 0, 1);
|
update_html_parser(spdySession, (*itr).second, 0, 0, 1);
|
||||||
(*itr).second->record_complete_time();
|
(*itr).second->record_complete_time();
|
||||||
++spdySession->complete;
|
++spdySession->complete;
|
||||||
if(spdySession->all_requests_processed()) {
|
if(spdySession->all_requests_processed()) {
|
||||||
nghttp2_submit_goaway(session, NGHTTP2_GOAWAY_OK);
|
nghttp2_submit_goaway(session, NGHTTP2_NO_ERROR, NULL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -549,7 +542,7 @@ void print_stats(const SpdySession& spdySession)
|
||||||
{
|
{
|
||||||
std::cout << "***** Statistics *****" << std::endl;
|
std::cout << "***** Statistics *****" << std::endl;
|
||||||
for(size_t i = 0; i < spdySession.reqvec.size(); ++i) {
|
for(size_t i = 0; i < spdySession.reqvec.size(); ++i) {
|
||||||
const Request *req = spdySession.reqvec[i];
|
auto req = spdySession.reqvec[i];
|
||||||
std::cout << "#" << i+1 << ": " << req->uri << std::endl;
|
std::cout << "#" << i+1 << ": " << req->uri << std::endl;
|
||||||
std::cout << " Status: " << req->status << std::endl;
|
std::cout << " Status: " << req->status << std::endl;
|
||||||
std::cout << " Delta (ms) from SSL/TLS handshake(SYN_STREAM):"
|
std::cout << " Delta (ms) from SSL/TLS handshake(SYN_STREAM):"
|
||||||
|
@ -578,22 +571,21 @@ void print_stats(const SpdySession& spdySession)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int spdy_evloop(int fd, SSL *ssl, int spdy_version, SpdySession& spdySession,
|
int spdy_evloop(int fd, SSL *ssl, SpdySession& spdySession,
|
||||||
const nghttp2_session_callbacks *callbacks, int timeout)
|
const nghttp2_session_callbacks *callbacks, int timeout)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
Spdylay sc(fd, ssl, spdy_version, callbacks, &spdySession);
|
int rv;
|
||||||
|
Spdylay sc(fd, ssl, callbacks, &spdySession);
|
||||||
spdySession.sc = ≻
|
spdySession.sc = ≻
|
||||||
|
|
||||||
nfds_t npollfds = 1;
|
nfds_t npollfds = 1;
|
||||||
pollfd pollfds[1];
|
pollfd pollfds[1];
|
||||||
|
if(config.window_bits != -1) {
|
||||||
if(spdy_version >= NGHTTP2_PROTO_SPDY3 && config.window_bits != -1) {
|
|
||||||
nghttp2_settings_entry iv[1];
|
nghttp2_settings_entry iv[1];
|
||||||
iv[0].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
iv[0].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||||
iv[0].flags = NGHTTP2_ID_FLAG_SETTINGS_NONE;
|
|
||||||
iv[0].value = 1 << config.window_bits;
|
iv[0].value = 1 << config.window_bits;
|
||||||
int rv = sc.submit_settings(NGHTTP2_FLAG_SETTINGS_NONE, iv, 1);
|
rv = sc.submit_settings(iv, 1);
|
||||||
assert(rv == 0);
|
assert(rv == 0);
|
||||||
}
|
}
|
||||||
for(int i = 0, n = spdySession.reqvec.size(); i < n; ++i) {
|
for(int i = 0, n = spdySession.reqvec.size(); i < n; ++i) {
|
||||||
|
@ -660,8 +652,6 @@ int communicate(const std::string& host, uint16_t port,
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int rv;
|
int rv;
|
||||||
int spdy_version;
|
|
||||||
std::string next_proto;
|
|
||||||
int timeout = config.timeout;
|
int timeout = config.timeout;
|
||||||
SSL_CTX *ssl_ctx = 0;
|
SSL_CTX *ssl_ctx = 0;
|
||||||
SSL *ssl = 0;
|
SSL *ssl = 0;
|
||||||
|
@ -683,15 +673,6 @@ int communicate(const std::string& host, uint16_t port,
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(config.spdy_version) {
|
|
||||||
case NGHTTP2_PROTO_SPDY2:
|
|
||||||
next_proto = "spdy/2";
|
|
||||||
break;
|
|
||||||
case NGHTTP2_PROTO_SPDY3:
|
|
||||||
next_proto = "spdy/3";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!config.no_tls) {
|
if(!config.no_tls) {
|
||||||
ssl_ctx = SSL_CTX_new(TLSv1_client_method());
|
ssl_ctx = SSL_CTX_new(TLSv1_client_method());
|
||||||
if(!ssl_ctx) {
|
if(!ssl_ctx) {
|
||||||
|
@ -699,7 +680,7 @@ int communicate(const std::string& host, uint16_t port,
|
||||||
result = -1;
|
result = -1;
|
||||||
goto fin;
|
goto fin;
|
||||||
}
|
}
|
||||||
setup_ssl_ctx(ssl_ctx, &next_proto);
|
setup_ssl_ctx(ssl_ctx, nullptr);
|
||||||
if(!config.keyfile.empty()) {
|
if(!config.keyfile.empty()) {
|
||||||
if(SSL_CTX_use_PrivateKey_file(ssl_ctx, config.keyfile.c_str(),
|
if(SSL_CTX_use_PrivateKey_file(ssl_ctx, config.keyfile.c_str(),
|
||||||
SSL_FILETYPE_PEM) != 1) {
|
SSL_FILETYPE_PEM) != 1) {
|
||||||
|
@ -722,23 +703,23 @@ int communicate(const std::string& host, uint16_t port,
|
||||||
result = -1;
|
result = -1;
|
||||||
goto fin;
|
goto fin;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
// If the user overrode the host header, use that value for the
|
||||||
|
// SNI extension
|
||||||
|
const char *host_string = 0;
|
||||||
|
auto i = config.headers.find( "Host" );
|
||||||
|
if ( i != config.headers.end() ) {
|
||||||
|
host_string = (*i).second.c_str();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
host_string = host.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
// If the user overrode the host header, use that value for the
|
if (!SSL_set_tlsext_host_name(ssl, host_string)) {
|
||||||
// SNI extension
|
std::cerr << ERR_error_string(ERR_get_error(), 0) << std::endl;
|
||||||
const char *host_string = 0;
|
result = -1;
|
||||||
std::map<std::string,std::string>::const_iterator i =
|
goto fin;
|
||||||
config.headers.find( "Host" );
|
}
|
||||||
if ( i != config.headers.end() ) {
|
|
||||||
host_string = (*i).second.c_str();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
host_string = host.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SSL_set_tlsext_host_name(ssl, host_string)) {
|
|
||||||
std::cerr << ERR_error_string(ERR_get_error(), 0) << std::endl;
|
|
||||||
result = -1;
|
|
||||||
goto fin;
|
|
||||||
}
|
}
|
||||||
rv = ssl_nonblock_handshake(ssl, fd, timeout);
|
rv = ssl_nonblock_handshake(ssl, fd, timeout);
|
||||||
if(rv == -1) {
|
if(rv == -1) {
|
||||||
|
@ -759,16 +740,7 @@ int communicate(const std::string& host, uint16_t port,
|
||||||
}
|
}
|
||||||
|
|
||||||
spdySession.record_handshake_time();
|
spdySession.record_handshake_time();
|
||||||
spdy_version = nghttp2_npn_get_version(
|
result = spdy_evloop(fd, ssl, spdySession, callbacks, timeout);
|
||||||
reinterpret_cast<const unsigned char*>(next_proto.c_str()),
|
|
||||||
next_proto.size());
|
|
||||||
if (spdy_version <= 0) {
|
|
||||||
std::cerr << "No supported SPDY version was negotiated." << std::endl;
|
|
||||||
result = -1;
|
|
||||||
goto fin;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = spdy_evloop(fd, ssl, spdy_version, spdySession, callbacks, timeout);
|
|
||||||
fin:
|
fin:
|
||||||
if(ssl) {
|
if(ssl) {
|
||||||
SSL_shutdown(ssl);
|
SSL_shutdown(ssl);
|
||||||
|
@ -787,7 +759,7 @@ ssize_t file_read_callback
|
||||||
uint8_t *buf, size_t length, int *eof,
|
uint8_t *buf, size_t length, int *eof,
|
||||||
nghttp2_data_source *source, void *user_data)
|
nghttp2_data_source *source, void *user_data)
|
||||||
{
|
{
|
||||||
Request *req = (Request*)nghttp2_session_get_stream_user_data
|
auto req = (Request*)nghttp2_session_get_stream_user_data
|
||||||
(session, stream_id);
|
(session, stream_id);
|
||||||
int fd = source->fd;
|
int fd = source->fd;
|
||||||
ssize_t r;
|
ssize_t r;
|
||||||
|
@ -812,14 +784,14 @@ int run(char **uris, int n)
|
||||||
callbacks.send_callback = send_callback;
|
callbacks.send_callback = send_callback;
|
||||||
callbacks.recv_callback = recv_callback;
|
callbacks.recv_callback = recv_callback;
|
||||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
callbacks.on_stream_close_callback = on_stream_close_callback;
|
||||||
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback2;
|
callbacks.on_frame_recv_callback = on_frame_recv_callback2;
|
||||||
callbacks.on_ctrl_send_callback = on_ctrl_send_callback2;
|
callbacks.on_frame_send_callback = on_frame_send_callback2;
|
||||||
if(config.verbose) {
|
if(config.verbose) {
|
||||||
callbacks.on_data_recv_callback = on_data_recv_callback;
|
callbacks.on_data_recv_callback = on_data_recv_callback;
|
||||||
callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback;
|
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
||||||
callbacks.on_ctrl_recv_parse_error_callback =
|
callbacks.on_frame_recv_parse_error_callback =
|
||||||
on_ctrl_recv_parse_error_callback;
|
on_frame_recv_parse_error_callback;
|
||||||
callbacks.on_unknown_ctrl_recv_callback = on_unknown_ctrl_recv_callback;
|
callbacks.on_unknown_frame_recv_callback = 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;
|
||||||
ssl_debug = config.verbose;
|
ssl_debug = config.verbose;
|
||||||
|
@ -882,7 +854,7 @@ int run(char **uris, int n)
|
||||||
|
|
||||||
void print_usage(std::ostream& out)
|
void print_usage(std::ostream& out)
|
||||||
{
|
{
|
||||||
out << "Usage: spdycat [-Oansv23] [-t <SECONDS>] [-w <WINDOW_BITS>] [--cert=<CERT>]\n"
|
out << "Usage: spdycat [-Oansv] [-t <SECONDS>] [-w <WINDOW_BITS>] [--cert=<CERT>]\n"
|
||||||
<< " [--key=<KEY>] [--no-tls] [-d <FILE>] [-m <N>] <URI>..."
|
<< " [--key=<KEY>] [--no-tls] [-d <FILE>] [-m <N>] <URI>..."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
@ -899,8 +871,6 @@ void print_help(std::ostream& out)
|
||||||
<< " The filename is dereived from URI. If URI\n"
|
<< " The filename is dereived from URI. If URI\n"
|
||||||
<< " ends with '/', 'index.html' is used as a\n"
|
<< " ends with '/', 'index.html' is used as a\n"
|
||||||
<< " filename. Not implemented yet.\n"
|
<< " filename. Not implemented yet.\n"
|
||||||
<< " -2, --spdy2 Only use SPDY/2.\n"
|
|
||||||
<< " -3, --spdy3 Only use SPDY/3.\n"
|
|
||||||
<< " -t, --timeout=<N> Timeout each request after <N> seconds.\n"
|
<< " -t, --timeout=<N> Timeout each request after <N> seconds.\n"
|
||||||
<< " -w, --window-bits=<N>\n"
|
<< " -w, --window-bits=<N>\n"
|
||||||
<< " Sets the initial window size to 2**<N>.\n"
|
<< " Sets the initial window size to 2**<N>.\n"
|
||||||
|
@ -915,8 +885,7 @@ void print_help(std::ostream& out)
|
||||||
<< " The file must be in PEM format.\n"
|
<< " The file must be in PEM format.\n"
|
||||||
<< " --key=<KEY> Use the client private key file. The file\n"
|
<< " --key=<KEY> Use the client private key file. The file\n"
|
||||||
<< " must be in PEM format.\n"
|
<< " must be in PEM format.\n"
|
||||||
<< " --no-tls Disable SSL/TLS. Use -2 or -3 to specify\n"
|
<< " --no-tls Disable SSL/TLS.\n"
|
||||||
<< " SPDY protocol version to use.\n"
|
|
||||||
<< " -d, --data=<FILE> Post FILE to server. If - is given, data\n"
|
<< " -d, --data=<FILE> Post FILE to server. If - is given, data\n"
|
||||||
<< " will be read from stdin.\n"
|
<< " will be read from stdin.\n"
|
||||||
<< " -m, --multiply=<N> Request each URI <N> times. By default, same\n"
|
<< " -m, --multiply=<N> Request each URI <N> times. By default, same\n"
|
||||||
|
@ -933,8 +902,6 @@ int main(int argc, char **argv)
|
||||||
{"verbose", no_argument, 0, 'v' },
|
{"verbose", no_argument, 0, 'v' },
|
||||||
{"null-out", no_argument, 0, 'n' },
|
{"null-out", no_argument, 0, 'n' },
|
||||||
{"remote-name", no_argument, 0, 'O' },
|
{"remote-name", no_argument, 0, 'O' },
|
||||||
{"spdy2", no_argument, 0, '2' },
|
|
||||||
{"spdy3", no_argument, 0, '3' },
|
|
||||||
{"timeout", required_argument, 0, 't' },
|
{"timeout", required_argument, 0, 't' },
|
||||||
{"window-bits", required_argument, 0, 'w' },
|
{"window-bits", required_argument, 0, 'w' },
|
||||||
{"get-assets", no_argument, 0, 'a' },
|
{"get-assets", no_argument, 0, 'a' },
|
||||||
|
@ -949,7 +916,7 @@ int main(int argc, char **argv)
|
||||||
{0, 0, 0, 0 }
|
{0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
int c = getopt_long(argc, argv, "Oad:m:nhH:v23st:w:", long_options,
|
int c = getopt_long(argc, argv, "Oad:m:nhH:vst:w:", long_options,
|
||||||
&option_index);
|
&option_index);
|
||||||
if(c == -1) {
|
if(c == -1) {
|
||||||
break;
|
break;
|
||||||
|
@ -967,12 +934,6 @@ int main(int argc, char **argv)
|
||||||
case 'v':
|
case 'v':
|
||||||
config.verbose = true;
|
config.verbose = true;
|
||||||
break;
|
break;
|
||||||
case '2':
|
|
||||||
config.spdy_version = NGHTTP2_PROTO_SPDY2;
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
config.spdy_version = NGHTTP2_PROTO_SPDY3;
|
|
||||||
break;
|
|
||||||
case 't':
|
case 't':
|
||||||
config.timeout = atoi(optarg) * 1000;
|
config.timeout = atoi(optarg) * 1000;
|
||||||
break;
|
break;
|
||||||
|
@ -1052,14 +1013,6 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(config.no_tls) {
|
|
||||||
if(config.spdy_version == -1) {
|
|
||||||
std::cerr << "Specify SPDY protocol version using either -2 or -3."
|
|
||||||
<< std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set_color_output(isatty(fileno(stdout)));
|
set_color_output(isatty(fileno(stdout)));
|
||||||
|
|
||||||
struct sigaction act;
|
struct sigaction act;
|
||||||
|
|
27
src/spdyd.cc
27
src/spdyd.cc
|
@ -47,7 +47,7 @@ extern bool ssl_debug;
|
||||||
namespace {
|
namespace {
|
||||||
void print_usage(std::ostream& out)
|
void print_usage(std::ostream& out)
|
||||||
{
|
{
|
||||||
out << "Usage: spdyd [-23DVhv] [-d <PATH>] [--no-tls] <PORT> [<PRIVATE_KEY> <CERT>]"
|
out << "Usage: spdyd [-DVhv] [-d <PATH>] [--no-tls] <PORT> [<PRIVATE_KEY> <CERT>]"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -74,10 +74,7 @@ void print_help(std::ostream& out)
|
||||||
<< " current working directory.\n"
|
<< " current working directory.\n"
|
||||||
<< " -v, --verbose Print debug information such as reception/\n"
|
<< " -v, --verbose Print debug information such as reception/\n"
|
||||||
<< " transmission of frames and name/value pairs.\n"
|
<< " transmission of frames and name/value pairs.\n"
|
||||||
<< " -2, --spdy2 Only use SPDY/2.\n"
|
<< " --no-tls Disable SSL/TLS.\n"
|
||||||
<< " -3, --spdy3 Only use SPDY/3.\n"
|
|
||||||
<< " --no-tls Disable SSL/TLS. Use -2 or -3 to specify\n"
|
|
||||||
<< " SPDY protocol version to use.\n"
|
|
||||||
<< " -h, --help Print this help.\n"
|
<< " -h, --help Print this help.\n"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
@ -93,14 +90,12 @@ int main(int argc, char **argv)
|
||||||
{"htdocs", required_argument, 0, 'd' },
|
{"htdocs", required_argument, 0, 'd' },
|
||||||
{"help", no_argument, 0, 'h' },
|
{"help", no_argument, 0, 'h' },
|
||||||
{"verbose", no_argument, 0, 'v' },
|
{"verbose", no_argument, 0, 'v' },
|
||||||
{"spdy2", no_argument, 0, '2' },
|
|
||||||
{"spdy3", no_argument, 0, '3' },
|
|
||||||
{"verify-client", no_argument, 0, 'V' },
|
{"verify-client", no_argument, 0, 'V' },
|
||||||
{"no-tls", no_argument, &flag, 1 },
|
{"no-tls", no_argument, &flag, 1 },
|
||||||
{0, 0, 0, 0 }
|
{0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
int c = getopt_long(argc, argv, "DVd:hv23", long_options, &option_index);
|
int c = getopt_long(argc, argv, "DVd:hv", long_options, &option_index);
|
||||||
if(c == -1) {
|
if(c == -1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -120,12 +115,6 @@ int main(int argc, char **argv)
|
||||||
case 'v':
|
case 'v':
|
||||||
config.verbose = true;
|
config.verbose = true;
|
||||||
break;
|
break;
|
||||||
case '2':
|
|
||||||
config.version = NGHTTP2_PROTO_SPDY2;
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
config.version = NGHTTP2_PROTO_SPDY3;
|
|
||||||
break;
|
|
||||||
case '?':
|
case '?':
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -140,7 +129,7 @@ int main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(argc-optind < (config.no_tls ? 1 : 3)) {
|
if(argc - optind < (config.no_tls ? 1 : 3)) {
|
||||||
print_usage(std::cerr);
|
print_usage(std::cerr);
|
||||||
std::cerr << "Too few arguments" << std::endl;
|
std::cerr << "Too few arguments" << std::endl;
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -148,13 +137,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
config.port = strtol(argv[optind++], 0, 10);
|
config.port = strtol(argv[optind++], 0, 10);
|
||||||
|
|
||||||
if(config.no_tls) {
|
if(!config.no_tls) {
|
||||||
if(config.version == 0) {
|
|
||||||
std::cerr << "Specify SPDY protocol version using either -2 or -3."
|
|
||||||
<< std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
config.private_key_file = argv[optind++];
|
config.private_key_file = argv[optind++];
|
||||||
config.cert_file = argv[optind++];
|
config.cert_file = argv[optind++];
|
||||||
}
|
}
|
||||||
|
|
20
src/util.cc
20
src/util.cc
|
@ -184,6 +184,26 @@ char upcase(char c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string format_hex(const unsigned char *s, size_t len)
|
||||||
|
{
|
||||||
|
std::string res;
|
||||||
|
for(size_t i = 0; i < len; ++i) {
|
||||||
|
unsigned char c = s[i] >> 4;
|
||||||
|
if(c > 9) {
|
||||||
|
res += c - 10 + 'a';
|
||||||
|
} else {
|
||||||
|
res += c + '0';
|
||||||
|
}
|
||||||
|
c = s[i] & 0xf;
|
||||||
|
if(c > 9) {
|
||||||
|
res += c - 10 + 'a';
|
||||||
|
} else {
|
||||||
|
res += c + '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
|
|
||||||
} // namespace nghttp2
|
} // namespace nghttp2
|
||||||
|
|
|
@ -204,6 +204,8 @@ std::string percentEncode(const std::string& target);
|
||||||
std::string percentDecode
|
std::string percentDecode
|
||||||
(std::string::const_iterator first, std::string::const_iterator last);
|
(std::string::const_iterator first, std::string::const_iterator last);
|
||||||
|
|
||||||
|
std::string format_hex(const unsigned char *s, size_t len);
|
||||||
|
|
||||||
std::string http_date(time_t t);
|
std::string http_date(time_t t);
|
||||||
|
|
||||||
time_t parse_http_date(const std::string& s);
|
time_t parse_http_date(const std::string& s);
|
||||||
|
|
|
@ -174,8 +174,8 @@ static void on_data_chunk_recv_callback(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_data_recv_callback(nghttp2_session *session,
|
static void on_data_recv_callback(nghttp2_session *session,
|
||||||
uint8_t flags, int32_t stream_id,
|
uint16_t length, uint8_t flags,
|
||||||
int32_t length, void *user_data)
|
int32_t stream_id, void *user_data)
|
||||||
{
|
{
|
||||||
my_user_data *ud = (my_user_data*)user_data;
|
my_user_data *ud = (my_user_data*)user_data;
|
||||||
++ud->data_recv_cb_called;
|
++ud->data_recv_cb_called;
|
||||||
|
|
Loading…
Reference in New Issue