From 24cab312cfb5678bfff2b54261aa7592559bdbb8 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 16 Jul 2013 00:15:04 +0900 Subject: [PATCH] Make spdycat and spdyd barely work --- lib/includes/nghttp2/nghttp2.h | 8 +- lib/nghttp2_session.c | 8 +- src/Makefile.am | 1 + src/SpdyServer.cc | 189 +++++++++-------------- src/SpdyServer.h | 10 +- src/nghttp2_ssl.cc | 271 +++++++++++++++++++-------------- src/nghttp2_ssl.h | 29 ++-- src/spdycat.cc | 165 +++++++------------- src/spdyd.cc | 27 +--- src/util.cc | 20 +++ src/util.h | 2 + tests/nghttp2_session_test.c | 4 +- 12 files changed, 344 insertions(+), 390 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index e50df7e7..c1a9943a 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -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); /** diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index a83f5be0..ac5cde13 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -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); diff --git a/src/Makefile.am b/src/Makefile.am index c877865c..bd71022e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/SpdyServer.cc b/src/SpdyServer.cc index 730e4ccb..60a5f7d4 100644 --- a/src/SpdyServer.cc +++ b/src/SpdyServer.cc @@ -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::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::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 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 - (sessions.get_user_data(i)); + auto hd = reinterpret_cast(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::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(); } diff --git a/src/SpdyServer.h b/src/SpdyServer.h index 0c3468cb..0547453c 100644 --- a/src/SpdyServer.h +++ b/src/SpdyServer.h @@ -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 > headers; + std::vector> headers; int file; std::pair 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 >& headers, + const std::vector>& 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 id2req_; diff --git a/src/nghttp2_ssl.cc b/src/nghttp2_ssl.cc index c6b49621..75980c53 100644 --- a/src/nghttp2_ssl.cc +++ b/src/nghttp2_ssl.cc @@ -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::const_iterator i = headers.begin(); - std::map::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("\n", - hd.version, hd.flags, hd.length); + printf("\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(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: " diff --git a/src/nghttp2_ssl.h b/src/nghttp2_ssl.h index d2d06e78..611dc522 100644 --- a/src/nghttp2_ssl.h +++ b/src/nghttp2_ssl.h @@ -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); diff --git a/src/spdycat.cc b/src/spdycat.cc index b371c3c6..db664744 100644 --- a/src/spdycat.cc +++ b/src/spdycat.cc @@ -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::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 = ≻ 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::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(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 ] [-w ] [--cert=]\n" + out << "Usage: spdycat [-Oansv] [-t ] [-w ] [--cert=]\n" << " [--key=] [--no-tls] [-d ] [-m ] ..." << 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= Timeout each request after seconds.\n" << " -w, --window-bits=\n" << " Sets the initial window size to 2**.\n" @@ -915,8 +885,7 @@ void print_help(std::ostream& out) << " The file must be in PEM format.\n" << " --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= Post FILE to server. If - is given, data\n" << " will be read from stdin.\n" << " -m, --multiply= Request each URI 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; diff --git a/src/spdyd.cc b/src/spdyd.cc index e86d2874..e48573a3 100644 --- a/src/spdyd.cc +++ b/src/spdyd.cc @@ -47,7 +47,7 @@ extern bool ssl_debug; namespace { void print_usage(std::ostream& out) { - out << "Usage: spdyd [-23DVhv] [-d ] [--no-tls] [ ]" + out << "Usage: spdyd [-DVhv] [-d ] [--no-tls] [ ]" << 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++]; } diff --git a/src/util.cc b/src/util.cc index 346852aa..9f70e8f9 100644 --- a/src/util.cc +++ b/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 nghttp2 diff --git a/src/util.h b/src/util.h index f9fea60c..c8382f5a 100644 --- a/src/util.h +++ b/src/util.h @@ -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); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 5eed30e9..7ffe4391 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -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;