Make spdycat and spdyd barely work

This commit is contained in:
Tatsuhiro Tsujikawa 2013-07-16 00:15:04 +09:00
parent 48cb017245
commit 24cab312cf
12 changed files with 344 additions and 390 deletions

View File

@ -492,7 +492,7 @@ typedef struct {
/**
* The error code. See :type:`nghttp2_error_code`.
*/
uint32_t error_code;
nghttp2_error_code error_code;
} nghttp2_rst_stream;
/**
@ -575,7 +575,7 @@ typedef struct {
/**
* The error code. See :type:`nghttp2_error_code`.
*/
uint32_t error_code;
nghttp2_error_code error_code;
/**
* The additional debug data
*/
@ -743,7 +743,7 @@ typedef void (*nghttp2_on_data_chunk_recv_callback)
* :type:`nghttp2_on_data_chunk_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);
/**
@ -784,7 +784,7 @@ typedef void (*nghttp2_on_frame_not_send_callback)
* Callback function invoked after DATA frame is sent.
*/
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);
/**

View File

@ -1126,10 +1126,10 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
if(session->callbacks.on_data_send_callback) {
session->callbacks.on_data_send_callback
(session,
session->aob.framebuflen - NGHTTP2_FRAME_HEAD_LENGTH,
data_frame->eof ? data_frame->hd.flags :
(data_frame->hd.flags & (~NGHTTP2_FLAG_END_STREAM)),
data_frame->hd.stream_id,
session->aob.framebuflen - NGHTTP2_FRAME_HEAD_LENGTH,
session->user_data);
}
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) {
return rv;
}
} else {
return nghttp2_session_fail_session(session, NGHTTP2_PROTOCOL_ERROR);
}
}
session->remote_settings[entry->settings_id] = entry->value;
@ -1915,7 +1917,7 @@ int nghttp2_session_on_data_received(nghttp2_session *session,
valid = 1;
if(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) {
error_code = NGHTTP2_PROTOCOL_ERROR;
@ -1927,7 +1929,7 @@ int nghttp2_session_on_data_received(nghttp2_session *session,
valid = 1;
if(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) {
nghttp2_session_call_on_request_recv(session, stream_id);

View File

@ -31,6 +31,7 @@ AM_CFLAGS = -Wall
AM_CPPFLAGS = -Wall -I$(srcdir)/../lib/includes -I$(builddir)/../lib/includes \
@OPENSSL_CFLAGS@ @XML_CPPFLAGS@ @LIBEVENT_OPENSSL_CFLAGS@ @DEFS@
AM_LDFLAGS = @OPENSSL_LIBS@ @XML_LIBS@ @LIBEVENT_OPENSSL_LIBS@ @SRC_LIBS@
AM_CXXFLAGS = -std=c++11
LDADD = $(top_builddir)/lib/libnghttp2.la

View File

@ -61,7 +61,7 @@ const std::string SPDYD_SERVER = "spdyd nghttp2/" NGHTTP2_VERSION;
Config::Config(): verbose(false), daemon(false), port(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)
@ -93,10 +93,9 @@ public:
{}
~Sessions()
{
for(std::set<EventHandler*>::iterator i = handlers_.begin(),
eoi = handlers_.end(); i != eoi; ++i) {
on_close(*this, *i);
delete *i;
for(auto handler : handlers_) {
on_close(*this, handler);
delete handler;
}
SSL_CTX_free(ssl_ctx_);
}
@ -175,22 +174,19 @@ void on_session_closed(EventHandler *hd, int64_t session_id)
SpdyEventHandler::SpdyEventHandler(const Config* config,
int fd, SSL *ssl,
uint16_t version,
const nghttp2_session_callbacks *callbacks,
int64_t session_id)
: EventHandler(config),
fd_(fd), ssl_(ssl), version_(version), session_id_(session_id),
fd_(fd), ssl_(ssl), session_id_(session_id),
io_flags_(0)
{
int r;
r = nghttp2_session_server_new(&session_, version, callbacks, this);
r = nghttp2_session_server_new(&session_, callbacks, this);
assert(r == 0);
nghttp2_settings_entry entry;
entry.settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
entry.value = NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS;
entry.flags = NGHTTP2_ID_FLAG_SETTINGS_NONE;
r = nghttp2_submit_settings(session_, NGHTTP2_FLAG_SETTINGS_NONE,
&entry, 1);
r = nghttp2_submit_settings(session_, &entry, 1);
assert(r == 0);
}
@ -198,9 +194,8 @@ SpdyEventHandler::~SpdyEventHandler()
{
on_session_closed(this, session_id_);
nghttp2_session_del(session_);
for(std::map<int32_t, Request*>::iterator i = id2req_.begin(),
eoi = id2req_.end(); i != eoi; ++i) {
delete (*i).second;
for(auto& item : id2req_) {
delete item.second;
}
if(ssl_) {
SSL_shutdown(ssl_);
@ -210,11 +205,6 @@ SpdyEventHandler::~SpdyEventHandler()
close(fd_);
}
uint16_t SpdyEventHandler::version() const
{
return version_;
}
int SpdyEventHandler::execute(Sessions *sessions)
{
int r;
@ -300,18 +290,17 @@ int SpdyEventHandler::submit_file_response(const std::string& status,
std::string last_modified_str;
const char *nv[] = {
":status", status.c_str(),
":version", "HTTP/1.1",
"server", SPDYD_SERVER.c_str(),
"content-length", content_length.c_str(),
"cache-control", "max-age=3600",
"date", date_str.c_str(),
0, 0,
0
nullptr, nullptr,
nullptr
};
if(last_modified != 0) {
last_modified_str = util::http_date(last_modified);
nv[12] = "last-modified";
nv[13] = last_modified_str.c_str();
nv[10] = "last-modified";
nv[11] = last_modified_str.c_str();
}
return nghttp2_submit_response(session_, stream_id, nv, data_prd);
}
@ -323,20 +312,18 @@ int SpdyEventHandler::submit_response
nghttp2_data_provider *data_prd)
{
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[1] = status.c_str();
nv[2] = ":version";
nv[3] = "HTTP/1.1";
nv[4] = "server";
nv[5] = SPDYD_SERVER.c_str();
nv[6] = "date";
nv[7] = date_str.c_str();
nv[2] = "server";
nv[3] = SPDYD_SERVER.c_str();
nv[4] = "date";
nv[5] = date_str.c_str();
for(int i = 0; i < (int)headers.size(); ++i) {
nv[8+i*2] = headers[i].first.c_str();
nv[8+i*2+1] = headers[i].second.c_str();
nv[6+i*2] = headers[i].first.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);
delete [] nv;
return r;
@ -348,9 +335,8 @@ int SpdyEventHandler::submit_response(const std::string& status,
{
const char *nv[] = {
":status", status.c_str(),
":version", "HTTP/1.1",
"server", SPDYD_SERVER.c_str(),
0
nullptr
};
return nghttp2_submit_response(session_, stream_id, nv, data_prd);
}
@ -568,29 +554,33 @@ void append_nv(Request *req, char **nv)
} // namespace
namespace {
void hd_on_ctrl_recv_callback
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
void *user_data)
void hd_on_frame_recv_callback
(nghttp2_session *session, nghttp2_frame *frame, void *user_data)
{
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
if(hd->config()->verbose) {
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) {
case NGHTTP2_SYN_STREAM: {
int32_t stream_id = frame->syn_stream.stream_id;
Request *req = new Request(stream_id);
append_nv(req, frame->syn_stream.nv);
hd->add_stream(stream_id, req);
switch(frame->hd.type) {
case NGHTTP2_HEADERS:
switch(frame->headers.cat) {
case NGHTTP2_HCAT_START_STREAM: {
int32_t stream_id = frame->hd.stream_id;
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;
}
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:
break;
}
@ -605,14 +595,14 @@ void htdocs_on_request_recv_callback
}
namespace {
void hd_on_ctrl_send_callback
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
void hd_on_frame_send_callback
(nghttp2_session *session, nghttp2_frame *frame,
void *user_data)
{
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
if(hd->config()->verbose) {
print_session_id(hd->session_id());
on_ctrl_send_callback(session, type, frame, user_data);
on_frame_send_callback(session, frame, user_data);
}
}
} // namespace
@ -628,34 +618,34 @@ void on_data_chunk_recv_callback
namespace {
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)
{
// TODO Handle POST
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
if(hd->config()->verbose) {
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 {
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)
{
SpdyEventHandler *hd = (SpdyEventHandler*)user_data;
if(hd->config()->verbose) {
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 {
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)
{
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.recv_callback = hd_recv_callback;
callbacks.on_stream_close_callback = on_stream_close_callback;
callbacks.on_ctrl_recv_callback = hd_on_ctrl_recv_callback;
callbacks.on_ctrl_send_callback = hd_on_ctrl_send_callback;
callbacks.on_frame_recv_callback = hd_on_frame_recv_callback;
callbacks.on_frame_send_callback = hd_on_frame_send_callback;
callbacks.on_data_recv_callback = hd_on_data_recv_callback;
callbacks.on_data_send_callback = hd_on_data_send_callback;
if(config->verbose) {
callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback;
callbacks.on_ctrl_recv_parse_error_callback =
on_ctrl_recv_parse_error_callback;
callbacks.on_unknown_ctrl_recv_callback = on_unknown_ctrl_recv_callback;
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
callbacks.on_frame_recv_parse_error_callback =
on_frame_recv_parse_error_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_request_recv_callback = config->on_request_recv_callback;
@ -696,7 +686,7 @@ public:
SSLAcceptEventHandler(const Config *config,
int fd, SSL *ssl, int64_t session_id)
: EventHandler(config),
fd_(fd), ssl_(ssl), version_(0), fail_(false), finish_(false),
fd_(fd), ssl_(ssl), fail_(false), finish_(false),
io_flags_(WANT_READ),
session_id_(session_id)
{}
@ -725,17 +715,11 @@ public:
if(config()->verbose) {
std::cout << "The negotiated next protocol: " << proto << std::endl;
}
version_ = nghttp2_npn_get_version(next_proto, next_proto_len);
if(config()->version != 0) {
if(config()->version != version_) {
version_ = 0;
std::cerr << "The negotiated next protocol is not supported."
<< std::endl;
}
}
if(version_) {
if(proto == "HTTP-draft-04/2.0") {
add_next_handler(sessions);
} else {
std::cerr << "The negotiated next protocol is not supported."
<< std::endl;
fail_ = true;
}
} else {
@ -779,7 +763,7 @@ private:
nghttp2_session_callbacks callbacks;
fill_callback(callbacks, config());
SpdyEventHandler *hd = new SpdyEventHandler(config(),
fd_, ssl_, version_, &callbacks,
fd_, ssl_, &callbacks,
session_id_);
if(sessions->mod_poll(hd) == -1) {
// fd_, ssl_ are freed by ~SpdyEventHandler()
@ -791,7 +775,6 @@ private:
int fd_;
SSL *ssl_;
uint16_t version_;
bool fail_, finish_;
uint8_t io_flags_;
int64_t session_id_;
@ -842,10 +825,8 @@ private:
if(config()->no_tls) {
nghttp2_session_callbacks callbacks;
fill_callback(callbacks, config());
SpdyEventHandler *hd = new SpdyEventHandler(config(),
cfd, 0,
config()->version, &callbacks,
session_id);
auto hd = new SpdyEventHandler(config(), cfd, nullptr, &callbacks,
session_id);
if(sessions->add_poll(hd) == -1) {
delete hd;
} else {
@ -857,8 +838,7 @@ private:
close(cfd);
return;
}
SSLAcceptEventHandler *hd = new SSLAcceptEventHandler(config(), cfd, ssl,
session_id);
auto hd = new SSLAcceptEventHandler(config(), cfd, ssl, session_id);
if(sessions->add_poll(hd) == -1) {
delete hd;
SSL_free(ssl);
@ -946,7 +926,7 @@ int SpdyServer::run()
{
SSL_CTX *ssl_ctx = 0;
std::pair<unsigned char*, size_t> next_proto;
unsigned char proto_list[14];
unsigned char proto_list[255];
if(!config_->no_tls) {
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if(!ssl_ctx) {
@ -978,25 +958,11 @@ int SpdyServer::run()
verify_callback);
}
// We speaks "spdy/2" and "spdy/3".
proto_list[0] = 6;
memcpy(&proto_list[1], "spdy/3", 6);
proto_list[7] = 6;
memcpy(&proto_list[8], "spdy/2", 6);
proto_list[0] = 17;
memcpy(&proto_list[1], "HTTP-draft-04/2.0", 17);
next_proto.first = proto_list;
next_proto.second = 18;
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);
}
@ -1011,9 +977,8 @@ int SpdyServer::run()
if(sfd_[i] == -1) {
continue;
}
ListenEventHandler *listen_hd = new ListenEventHandler(config_,
sfd_[i],
&session_id_seed);
auto listen_hd = new ListenEventHandler(config_, sfd_[i],
&session_id_seed);
if(sessions.add_poll(listen_hd) == -1) {
std::cerr << ipv << ": Adding listening socket to poll failed."
<< std::endl;
@ -1034,8 +999,7 @@ int SpdyServer::run()
perror("EventPoll");
} else {
for(int i = 0; i < n; ++i) {
EventHandler *hd = reinterpret_cast<EventHandler*>
(sessions.get_user_data(i));
auto hd = reinterpret_cast<EventHandler*>(sessions.get_user_data(i));
int events = sessions.get_events(i);
int r = 0;
if(hd->mark_del()) {
@ -1059,10 +1023,9 @@ int SpdyServer::run()
del_list.push_back(hd);
}
}
for(std::vector<EventHandler*>::iterator i = del_list.begin(),
eoi = del_list.end(); i != eoi; ++i) {
on_close(sessions, *i);
sessions.remove_handler(*i);
for(auto handler : del_list) {
on_close(sessions, handler);
sessions.remove_handler(handler);
}
del_list.clear();
}

View File

@ -52,7 +52,6 @@ struct Config {
std::string cert_file;
nghttp2_on_request_recv_callback on_request_recv_callback;
void *data_ptr;
uint16_t version;
bool verify_client;
bool no_tls;
Config();
@ -88,7 +87,7 @@ private:
struct Request {
int32_t stream_id;
std::vector<std::pair<std::string, std::string> > headers;
std::vector<std::pair<std::string, std::string>> headers;
int file;
std::pair<std::string, size_t> response_body;
Request(int32_t stream_id);
@ -98,7 +97,7 @@ struct Request {
class SpdyEventHandler : public EventHandler {
public:
SpdyEventHandler(const Config* config,
int fd, SSL *ssl, uint16_t version,
int fd, SSL *ssl,
const nghttp2_session_callbacks *callbacks,
int64_t session_id);
virtual ~SpdyEventHandler();
@ -108,8 +107,6 @@ public:
virtual int fd() const;
virtual bool finish();
uint16_t version() const;
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);
@ -129,7 +126,7 @@ public:
int submit_response
(const std::string& status,
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);
void add_stream(int32_t stream_id, Request *req);
@ -140,7 +137,6 @@ private:
nghttp2_session *session_;
int fd_;
SSL* ssl_;
uint16_t version_;
int64_t session_id_;
uint8_t io_flags_;
std::map<int32_t, Request*> id2req_;

View File

@ -50,13 +50,12 @@ namespace nghttp2 {
bool ssl_debug = false;
Spdylay::Spdylay(int fd, SSL *ssl, uint16_t version,
Spdylay::Spdylay(int fd, SSL *ssl,
const nghttp2_session_callbacks *callbacks,
void *user_data)
: fd_(fd), ssl_(ssl), version_(version), user_data_(user_data),
io_flags_(0)
: fd_(fd), ssl_(ssl), user_data_(user_data), 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);
}
@ -152,17 +151,16 @@ int Spdylay::submit_request(const std::string& scheme,
{
POS_METHOD = 0,
POS_PATH,
POS_VERSION,
POS_SCHEME,
POS_HOST,
POS_ACCEPT,
POS_ACCEPT_ENCODING,
POS_USERAGENT
};
const char *static_nv[] = {
":method", data_prd ? "POST" : "GET",
":path", path.c_str(),
":version", "HTTP/1.1",
":scheme", scheme.c_str(),
":host", hostport.c_str(),
"accept", "*/*",
@ -181,8 +179,8 @@ int Spdylay::submit_request(const std::string& scheme,
memcpy(nv, static_nv, hardcoded_entry_count * sizeof(*static_nv));
std::map<std::string,std::string>::const_iterator i = headers.begin();
std::map<std::string,std::string>::const_iterator end = headers.end();
auto i = std::begin(headers);
auto end = std::end(headers);
int pos = hardcoded_entry_count;
@ -213,7 +211,7 @@ int Spdylay::submit_request(const std::string& scheme,
}
++i;
}
nv[pos] = NULL;
nv[pos] = nullptr;
int r = nghttp2_submit_request(session_, pri, nv, data_prd,
stream_user_data);
@ -223,9 +221,9 @@ int Spdylay::submit_request(const std::string& scheme,
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()
@ -456,15 +454,41 @@ ssize_t recv_callback(nghttp2_session *session,
}
namespace {
const char *ctrl_names[] = {
"SYN_STREAM",
"SYN_REPLY",
const char* strstatus(nghttp2_error_code error_code)
{
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",
"SETTINGS",
"NOOP",
"PUSH_PROMISE",
"PING",
"GOAWAY",
"HEADERS",
"WINDOW_UPDATE"
};
} // namespace
@ -521,10 +545,57 @@ void print_timer()
}
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",
hd.version, hd.flags, hd.length);
printf("<length=%d, flags=%u, stream_id=%d>\n",
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
@ -541,60 +612,69 @@ const char* frame_name_ansi_esc(print_type ptype)
} // namespace
namespace {
void print_frame(print_type ptype, nghttp2_frame_type type,
nghttp2_frame *frame)
void print_frame(print_type ptype, nghttp2_frame *frame)
{
printf("%s%s%s frame ",
frame_name_ansi_esc(ptype),
ctrl_names[type-1],
frame_names[frame->hd.type],
ansi_escend());
print_ctrl_hd(frame->syn_stream.hd);
switch(type) {
case NGHTTP2_SYN_STREAM:
print_frame_hd(frame->hd);
if(frame->hd.flags) {
print_frame_attr_indent();
printf("(stream_id=%d, assoc_stream_id=%d, pri=%u)\n",
frame->syn_stream.stream_id, frame->syn_stream.assoc_stream_id,
frame->syn_stream.pri);
print_nv(frame->syn_stream.nv);
break;
case NGHTTP2_SYN_REPLY:
print_flags(frame->hd);
}
switch(frame->hd.type) {
case NGHTTP2_HEADERS:
print_frame_attr_indent();
printf("(stream_id=%d)\n", frame->syn_reply.stream_id);
print_nv(frame->syn_reply.nv);
printf("(pri=%d)\n", frame->headers.pri);
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;
case NGHTTP2_RST_STREAM:
print_frame_attr_indent();
printf("(stream_id=%d, status_code=%u)\n",
frame->rst_stream.stream_id, frame->rst_stream.status_code);
printf("(error_code=%s(%u))\n",
strstatus(frame->rst_stream.error_code),
frame->rst_stream.error_code);
break;
case NGHTTP2_SETTINGS:
print_frame_attr_indent();
printf("(niv=%lu)\n", static_cast<unsigned long>(frame->settings.niv));
for(size_t i = 0; i < frame->settings.niv; ++i) {
print_frame_attr_indent();
printf("[%d(%u):%u]\n",
printf("[%d:%u]\n",
frame->settings.iv[i].settings_id,
frame->settings.iv[i].flags, frame->settings.iv[i].value);
frame->settings.iv[i].value);
}
break;
case NGHTTP2_PING:
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;
case NGHTTP2_GOAWAY:
print_frame_attr_indent();
printf("(last_good_stream_id=%d)\n", frame->goaway.last_good_stream_id);
break;
case NGHTTP2_HEADERS:
print_frame_attr_indent();
printf("(stream_id=%d)\n", frame->headers.stream_id);
print_nv(frame->headers.nv);
printf("(last_stream_id=%d, error_code=%s(%u), opaque_data=%s)\n",
frame->goaway.last_stream_id,
strstatus(frame->goaway.error_code),
frame->goaway.error_code,
util::format_hex(frame->goaway.opaque_data,
frame->goaway.opaque_data_len).c_str());
break;
case NGHTTP2_WINDOW_UPDATE:
print_frame_attr_indent();
printf("(stream_id=%d, delta_window_size=%d)\n",
frame->window_update.stream_id,
frame->window_update.delta_window_size);
printf("(window_size_increment=%d)\n",
frame->window_update.window_size_increment);
break;
default:
printf("\n");
@ -603,57 +683,22 @@ void print_frame(print_type ptype, nghttp2_frame_type type,
}
} // namespace
void on_ctrl_recv_callback
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
void *user_data)
void on_frame_recv_callback
(nghttp2_session *session, nghttp2_frame *frame, void *user_data)
{
print_timer();
printf(" recv ");
print_frame(PRINT_RECV, type, frame);
print_frame(PRINT_RECV, frame);
fflush(stdout);
}
namespace {
const char* strstatus(uint32_t status_code)
{
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)
void on_invalid_frame_recv_callback
(nghttp2_session *session, nghttp2_frame *frame,
nghttp2_error_code error_code, void *user_data)
{
print_timer();
printf(" [INVALID; status=%s] recv ", strstatus(status_code));
print_frame(PRINT_RECV, type, frame);
printf(" [INVALID; status=%s] recv ", strstatus(error_code));
print_frame(PRINT_RECV, frame);
fflush(stdout);
}
@ -670,7 +715,7 @@ void dump_header(const uint8_t *head, size_t headlen)
}
} // 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,
const uint8_t *head,
size_t headlen,
@ -681,7 +726,7 @@ void on_ctrl_recv_parse_error_callback(nghttp2_session *session,
print_timer();
printf(" [PARSE_ERROR] recv %s%s%s frame\n",
frame_name_ansi_esc(PRINT_RECV),
ctrl_names[type-1],
frame_names[type],
ansi_escend());
print_frame_attr_indent();
printf("Error: %s\n", nghttp2_strerror(error_code));
@ -689,7 +734,7 @@ void on_ctrl_recv_parse_error_callback(nghttp2_session *session,
fflush(stdout);
}
void on_unknown_ctrl_recv_callback(nghttp2_session *session,
void on_unknown_frame_recv_callback(nghttp2_session *session,
const uint8_t *head,
size_t headlen,
const uint8_t *payload,
@ -702,43 +747,43 @@ void on_unknown_ctrl_recv_callback(nghttp2_session *session,
fflush(stdout);
}
void on_ctrl_send_callback
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
void *user_data)
void on_frame_send_callback
(nghttp2_session *session, nghttp2_frame *frame, void *user_data)
{
print_timer();
printf(" send ");
print_frame(PRINT_SEND, type, frame);
print_frame(PRINT_SEND, frame);
fflush(stdout);
}
namespace {
void print_data_frame(print_type ptype, uint8_t flags, int32_t stream_id,
int32_t length)
void print_data_frame(print_type ptype, uint16_t length, uint8_t flags,
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(),
stream_id, flags, length);
length, flags, stream_id);
print_frame_attr_indent();
}
} // namespace
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)
{
print_timer();
printf(" recv ");
print_data_frame(PRINT_RECV, flags, stream_id, length);
print_data_frame(PRINT_RECV, length, flags, stream_id);
fflush(stdout);
}
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)
{
print_timer();
printf(" send ");
print_data_frame(PRINT_SEND, flags, stream_id, length);
print_data_frame(PRINT_SEND, length, flags, stream_id);
fflush(stdout);
}
@ -770,18 +815,10 @@ int select_next_proto_cb(SSL* ssl,
std::cout << std::endl;
}
}
std::string& next_proto = *(std::string*)arg;
if(next_proto.empty()) {
if(nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
std::cerr << "Server did not advertise spdy/2 or spdy/3 protocol."
<< std::endl;
abort();
} else {
next_proto.assign(&(*out)[0], &(*out)[*outlen]);
}
} else {
*out = (unsigned char*)(next_proto.c_str());
*outlen = next_proto.size();
if(nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
std::cerr << "Server did not advertise HTTP/2.0 protocol."
<< std::endl;
abort();
}
if(ssl_debug) {
std::cout << " NPN selected the protocol: "

View File

@ -43,7 +43,7 @@ extern bool ssl_debug;
class Spdylay {
public:
Spdylay(int fd, SSL *ssl, uint16_t version,
Spdylay(int fd, SSL *ssl,
const nghttp2_session_callbacks *callbacks,
void *user_data);
~Spdylay();
@ -62,13 +62,12 @@ public:
const nghttp2_data_provider *data_prd,
int64_t data_length,
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();
void* user_data();
private:
int fd_;
SSL *ssl_;
uint16_t version_;
nghttp2_session *session_;
void *user_data_;
uint8_t io_flags_;
@ -94,15 +93,14 @@ ssize_t recv_callback(nghttp2_session *session,
void print_nv(char **nv);
void on_ctrl_recv_callback
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
void *user_data);
void on_frame_recv_callback
(nghttp2_session *session, nghttp2_frame *frame, void *user_data);
void on_invalid_ctrl_recv_callback
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
uint32_t status_code, void *user_data);
void on_invalid_frame_recv_callback
(nghttp2_session *session, nghttp2_frame *frame,
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,
const uint8_t *head,
size_t headlen,
@ -110,23 +108,22 @@ void on_ctrl_recv_parse_error_callback(nghttp2_session *session,
size_t payloadlen,
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,
size_t headlen,
const uint8_t *payload,
size_t payloadlen,
void *user_data);
void on_ctrl_send_callback
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
void *user_data);
void on_frame_send_callback
(nghttp2_session *session, nghttp2_frame *frame, void *user_data);
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 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 ctl_poll(pollfd *pollfd, Spdylay *sc);

View File

@ -75,7 +75,6 @@ struct Config {
bool stat;
bool no_tls;
int multiply;
int spdy_version;
// milliseconds
int timeout;
std::string certfile;
@ -85,7 +84,7 @@ struct Config {
std::string datafile;
Config():null_out(false), remote_name(false), verbose(false),
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,
nghttp2_frame_type type, nghttp2_frame *frame,
void check_stream_id(nghttp2_session *session, nghttp2_frame *frame,
void *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,
stream_id);
spdySession->streams[stream_id] = req;
req->record_syn_stream_time();
}
void on_ctrl_send_callback2
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
void *user_data)
void on_frame_send_callback2
(nghttp2_session *session, nghttp2_frame *frame, void *user_data)
{
if(type == NGHTTP2_SYN_STREAM) {
check_stream_id(session, type, frame, user_data);
if(frame->hd.type == NGHTTP2_HEADERS &&
frame->headers.cat == NGHTTP2_HCAT_START_STREAM) {
check_stream_id(session, frame, user_data);
}
if(config.verbose) {
on_ctrl_send_callback(session, type, frame, user_data);
on_frame_send_callback(session, frame, user_data);
}
}
void check_response_header
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
void *user_data)
(nghttp2_session *session, nghttp2_frame *frame, void *user_data)
{
char **nv;
int32_t stream_id;
if(type == NGHTTP2_SYN_REPLY) {
nv = frame->syn_reply.nv;
stream_id = frame->syn_reply.stream_id;
} else if(type == NGHTTP2_HEADERS) {
if(frame->hd.type == NGHTTP2_HEADERS) {
nv = frame->headers.nv;
stream_id = frame->headers.stream_id;
stream_id = frame->hd.stream_id;
} else {
return;
}
Request *req = (Request*)nghttp2_session_get_stream_user_data(session,
stream_id);
auto req = (Request*)nghttp2_session_get_stream_user_data(session,
stream_id);
if(!req) {
// Server-pushed stream does not have stream user data
return;
@ -512,35 +506,34 @@ void check_response_header
}
}
void on_ctrl_recv_callback2
(nghttp2_session *session, nghttp2_frame_type type, nghttp2_frame *frame,
void *user_data)
void on_frame_recv_callback2
(nghttp2_session *session, nghttp2_frame *frame, void *user_data)
{
if(type == NGHTTP2_SYN_REPLY) {
Request *req = (Request*)nghttp2_session_get_stream_user_data
(session, frame->syn_reply.stream_id);
if(frame->hd.type == NGHTTP2_HEADERS &&
frame->headers.cat == NGHTTP2_HCAT_REPLY) {
auto req = (Request*)nghttp2_session_get_stream_user_data
(session, frame->hd.stream_id);
assert(req);
req->record_syn_reply_time();
}
check_response_header(session, type, frame, user_data);
check_response_header(session, frame, user_data);
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
(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)
{
SpdySession *spdySession = get_session(user_data);
std::map<int32_t, Request*>::iterator itr =
spdySession->streams.find(stream_id);
auto itr = spdySession->streams.find(stream_id);
if(itr != spdySession->streams.end()) {
update_html_parser(spdySession, (*itr).second, 0, 0, 1);
(*itr).second->record_complete_time();
++spdySession->complete;
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;
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 << " Status: " << req->status << std::endl;
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)
{
int result = 0;
Spdylay sc(fd, ssl, spdy_version, callbacks, &spdySession);
int rv;
Spdylay sc(fd, ssl, callbacks, &spdySession);
spdySession.sc = &sc;
nfds_t npollfds = 1;
pollfd pollfds[1];
if(spdy_version >= NGHTTP2_PROTO_SPDY3 && config.window_bits != -1) {
if(config.window_bits != -1) {
nghttp2_settings_entry iv[1];
iv[0].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
iv[0].flags = NGHTTP2_ID_FLAG_SETTINGS_NONE;
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);
}
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 rv;
int spdy_version;
std::string next_proto;
int timeout = config.timeout;
SSL_CTX *ssl_ctx = 0;
SSL *ssl = 0;
@ -683,15 +673,6 @@ int communicate(const std::string& host, uint16_t port,
<< 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) {
ssl_ctx = SSL_CTX_new(TLSv1_client_method());
if(!ssl_ctx) {
@ -699,7 +680,7 @@ int communicate(const std::string& host, uint16_t port,
result = -1;
goto fin;
}
setup_ssl_ctx(ssl_ctx, &next_proto);
setup_ssl_ctx(ssl_ctx, nullptr);
if(!config.keyfile.empty()) {
if(SSL_CTX_use_PrivateKey_file(ssl_ctx, config.keyfile.c_str(),
SSL_FILETYPE_PEM) != 1) {
@ -722,23 +703,23 @@ int communicate(const std::string& host, uint16_t port,
result = -1;
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
// SNI extension
const char *host_string = 0;
std::map<std::string,std::string>::const_iterator i =
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;
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);
if(rv == -1) {
@ -759,16 +740,7 @@ int communicate(const std::string& host, uint16_t port,
}
spdySession.record_handshake_time();
spdy_version = nghttp2_npn_get_version(
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);
result = spdy_evloop(fd, ssl, spdySession, callbacks, timeout);
fin:
if(ssl) {
SSL_shutdown(ssl);
@ -787,7 +759,7 @@ ssize_t file_read_callback
uint8_t *buf, size_t length, int *eof,
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);
int fd = source->fd;
ssize_t r;
@ -812,14 +784,14 @@ int run(char **uris, int n)
callbacks.send_callback = send_callback;
callbacks.recv_callback = recv_callback;
callbacks.on_stream_close_callback = on_stream_close_callback;
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback2;
callbacks.on_ctrl_send_callback = on_ctrl_send_callback2;
callbacks.on_frame_recv_callback = on_frame_recv_callback2;
callbacks.on_frame_send_callback = on_frame_send_callback2;
if(config.verbose) {
callbacks.on_data_recv_callback = on_data_recv_callback;
callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback;
callbacks.on_ctrl_recv_parse_error_callback =
on_ctrl_recv_parse_error_callback;
callbacks.on_unknown_ctrl_recv_callback = on_unknown_ctrl_recv_callback;
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
callbacks.on_frame_recv_parse_error_callback =
on_frame_recv_parse_error_callback;
callbacks.on_unknown_frame_recv_callback = on_unknown_frame_recv_callback;
}
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
ssl_debug = config.verbose;
@ -882,7 +854,7 @@ int run(char **uris, int n)
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>..."
<< std::endl;
}
@ -899,8 +871,6 @@ void print_help(std::ostream& out)
<< " The filename is dereived from URI. If URI\n"
<< " ends with '/', 'index.html' is used as a\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"
<< " -w, --window-bits=<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"
<< " --key=<KEY> Use the client private key file. The file\n"
<< " must be in PEM format.\n"
<< " --no-tls Disable SSL/TLS. Use -2 or -3 to specify\n"
<< " SPDY protocol version to use.\n"
<< " --no-tls Disable SSL/TLS.\n"
<< " -d, --data=<FILE> Post FILE to server. If - is given, data\n"
<< " will be read from stdin.\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' },
{"null-out", no_argument, 0, 'n' },
{"remote-name", no_argument, 0, 'O' },
{"spdy2", no_argument, 0, '2' },
{"spdy3", no_argument, 0, '3' },
{"timeout", required_argument, 0, 't' },
{"window-bits", required_argument, 0, 'w' },
{"get-assets", no_argument, 0, 'a' },
@ -949,7 +916,7 @@ int main(int argc, char **argv)
{0, 0, 0, 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);
if(c == -1) {
break;
@ -967,12 +934,6 @@ int main(int argc, char **argv)
case 'v':
config.verbose = true;
break;
case '2':
config.spdy_version = NGHTTP2_PROTO_SPDY2;
break;
case '3':
config.spdy_version = NGHTTP2_PROTO_SPDY3;
break;
case 't':
config.timeout = atoi(optarg) * 1000;
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)));
struct sigaction act;

View File

@ -47,7 +47,7 @@ extern bool ssl_debug;
namespace {
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;
}
} // namespace
@ -74,10 +74,7 @@ void print_help(std::ostream& out)
<< " current working directory.\n"
<< " -v, --verbose Print debug information such as reception/\n"
<< " transmission of frames and name/value pairs.\n"
<< " -2, --spdy2 Only use SPDY/2.\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"
<< " --no-tls Disable SSL/TLS.\n"
<< " -h, --help Print this help.\n"
<< std::endl;
}
@ -93,14 +90,12 @@ int main(int argc, char **argv)
{"htdocs", required_argument, 0, 'd' },
{"help", no_argument, 0, 'h' },
{"verbose", no_argument, 0, 'v' },
{"spdy2", no_argument, 0, '2' },
{"spdy3", no_argument, 0, '3' },
{"verify-client", no_argument, 0, 'V' },
{"no-tls", no_argument, &flag, 1 },
{0, 0, 0, 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) {
break;
}
@ -120,12 +115,6 @@ int main(int argc, char **argv)
case 'v':
config.verbose = true;
break;
case '2':
config.version = NGHTTP2_PROTO_SPDY2;
break;
case '3':
config.version = NGHTTP2_PROTO_SPDY3;
break;
case '?':
exit(EXIT_FAILURE);
case 0:
@ -140,7 +129,7 @@ int main(int argc, char **argv)
break;
}
}
if(argc-optind < (config.no_tls ? 1 : 3)) {
if(argc - optind < (config.no_tls ? 1 : 3)) {
print_usage(std::cerr);
std::cerr << "Too few arguments" << std::endl;
exit(EXIT_FAILURE);
@ -148,13 +137,7 @@ int main(int argc, char **argv)
config.port = strtol(argv[optind++], 0, 10);
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 {
if(!config.no_tls) {
config.private_key_file = argv[optind++];
config.cert_file = argv[optind++];
}

View File

@ -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 nghttp2

View File

@ -204,6 +204,8 @@ std::string percentEncode(const std::string& target);
std::string percentDecode
(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);
time_t parse_http_date(const std::string& s);

View File

@ -174,8 +174,8 @@ static void on_data_chunk_recv_callback(nghttp2_session *session,
}
static void on_data_recv_callback(nghttp2_session *session,
uint8_t flags, int32_t stream_id,
int32_t length, void *user_data)
uint16_t length, uint8_t flags,
int32_t stream_id, void *user_data)
{
my_user_data *ud = (my_user_data*)user_data;
++ud->data_recv_cb_called;