From 01af6ea70c466b8ace7f22c25737418babddb8b5 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 22 Mar 2015 23:22:06 +0900 Subject: [PATCH 01/14] Remove ALTSVC related code HTTP/2 and HPACK are going to be published as RFC, but ALTSVC is still in draft state. To make our API stable, it would be better to remove ALTSVC API for 1.0.0 release. --- lib/includes/nghttp2/nghttp2.h | 73 +--------------------------------- lib/nghttp2_frame.h | 2 +- lib/nghttp2_submit.c | 9 ----- src/app_helper.cc | 30 -------------- src/shrpx.cc | 8 ++-- src/shrpx_http2_upstream.cc | 18 --------- 6 files changed, 7 insertions(+), 133 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 32b9b2d6..98c1d4f0 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -495,21 +495,6 @@ typedef enum { NGHTTP2_CONTINUATION = 0x09 } nghttp2_frame_type; -/** - * @enum - * - * The extension frame types. - * - * TODO: The assigned frame types were carried from draft-12, and now - * actually TBD. - */ -typedef enum { - /** - * The ALTSVC extension frame. - */ - NGHTTP2_EXT_ALTSVC = 0x0a -} nghttp2_ext_frame_type; - /** * @enum * @@ -1078,52 +1063,12 @@ typedef struct { * The pointer to extension payload. The exact pointer type is * determined by hd.type. * - * If hd.type == :enum:`NGHTTP2_EXT_ALTSVC`, it is a pointer to - * :type:`nghttp2_ext_altsvc`. + * Currently, no extension is supported. This is a place holder for + * the future extensions. */ void *payload; } nghttp2_extension; -/** - * @struct - * - * The ALTSVC extension frame payload. It has following members: - */ -typedef struct { - /** - * Protocol ID - */ - uint8_t *protocol_id; - /** - * Host - */ - uint8_t *host; - /** - * Origin - */ - uint8_t *origin; - /** - * The length of |protocol_id| - */ - size_t protocol_id_len; - /** - * The length of |host| - */ - size_t host_len; - /** - * The length of |origin| - */ - size_t origin_len; - /** - * Max-Age - */ - uint32_t max_age; - /** - * Port - */ - uint16_t port; -} nghttp2_ext_altsvc; - /** * @union * @@ -3419,20 +3364,6 @@ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session, int32_t stream_id, int32_t window_size_increment); -/** - * @function - * - * This function previously submits ALTSVC frame with given - * parameters, but is deprecated and will be removed in a future - * release. This function does nothing and just return 0. - */ -NGHTTP2_EXTERN int -nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags, - int32_t stream_id, uint32_t max_age, uint16_t port, - const uint8_t *protocol_id, size_t protocol_id_len, - const uint8_t *host, size_t host_len, - const uint8_t *origin, size_t origin_len); - /** * @function * diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index 2c4d6e9c..7fc336c1 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -75,7 +75,7 @@ #define NGHTTP2_MAX_PADLEN 256 /* Union of extension frame payload */ -typedef union { nghttp2_ext_altsvc altsvc; } nghttp2_ext_frame_payload; +typedef union { int dummy; } nghttp2_ext_frame_payload; void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd); diff --git a/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index bde78a20..40d82ac5 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -376,15 +376,6 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags, return 0; } -int nghttp2_submit_altsvc(nghttp2_session *session _U_, uint8_t flags _U_, - int32_t stream_id _U_, uint32_t max_age _U_, - uint16_t port _U_, const uint8_t *protocol_id _U_, - size_t protocol_id_len _U_, const uint8_t *host _U_, - size_t host_len _U_, const uint8_t *origin _U_, - size_t origin_len _U_) { - return 0; -} - static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec, const nghttp2_data_provider *data_prd) { uint8_t flags = NGHTTP2_FLAG_NONE; diff --git a/src/app_helper.cc b/src/app_helper.cc index af7653c1..e23fddd2 100644 --- a/src/app_helper.cc +++ b/src/app_helper.cc @@ -130,8 +130,6 @@ const char *strframetype(uint8_t type) { return "GOAWAY"; case NGHTTP2_WINDOW_UPDATE: return "WINDOW_UPDATE"; - case NGHTTP2_EXT_ALTSVC: - return "ALTSVC"; default: return "UNKNOWN"; } @@ -362,34 +360,6 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) { fprintf(outfile, "(window_size_increment=%d)\n", frame->window_update.window_size_increment); break; - case NGHTTP2_EXT_ALTSVC: { - print_frame_attr_indent(); - - auto altsvc = static_cast(frame->ext.payload); - - fprintf(outfile, "(max-age=%u, port=%u, protocol_id=", altsvc->max_age, - altsvc->port); - - if (altsvc->protocol_id_len) { - fwrite(altsvc->protocol_id, altsvc->protocol_id_len, 1, outfile); - } - - fprintf(outfile, ", host="); - - if (altsvc->host_len) { - fwrite(altsvc->host, altsvc->host_len, 1, outfile); - } - - fprintf(outfile, ", origin="); - - if (altsvc->origin_len) { - fwrite(altsvc->origin, altsvc->origin_len, 1, outfile); - } - - fprintf(outfile, ")\n"); - - break; - } default: break; } diff --git a/src/shrpx.cc b/src/shrpx.cc index 9273f7e9..86e4a637 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1342,10 +1342,10 @@ HTTP: --altsvc= Specify protocol ID, port, host and origin of alternative service. and are optional. - They are advertised in alt-svc header field or HTTP/2 - ALTSVC frame. This option can be used multiple times to - specify multiple alternative services. Example: - --altsvc=h2,443 + They are advertised in alt-svc header field only in + HTTP/1.1 frontend. This option can be used multiple + times to specify multiple alternative services. + Example: --altsvc=h2,443 --add-response-header=
Specify additional header field to add to response header set. This option just appends header field and diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index f7915561..64af8afa 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -734,24 +734,6 @@ Http2Upstream::Http2Upstream(ClientHandler *handler) } } - if (!get_config()->altsvcs.empty()) { - // Set max_age to 24hrs, which is default for alt-svc header - // field. - for (auto &altsvc : get_config()->altsvcs) { - rv = nghttp2_submit_altsvc( - session_, NGHTTP2_FLAG_NONE, 0, 86400, altsvc.port, - reinterpret_cast(altsvc.protocol_id), - altsvc.protocol_id_len, - reinterpret_cast(altsvc.host), altsvc.host_len, - reinterpret_cast(altsvc.origin), altsvc.origin_len); - - if (rv != 0) { - ULOG(ERROR, this) << "nghttp2_submit_altsvc() returned error: " - << nghttp2_strerror(rv); - } - } - } - // We wait for SETTINGS ACK at least 10 seconds. ev_timer_init(&settings_timer_, settings_timeout_cb, 10., 0.); From 250ea53e4b968bfc2a3dd0e301a1878fdfa41efb Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Mon, 23 Mar 2015 00:12:27 +0900 Subject: [PATCH 02/14] Deal with 24 bytes client connection preface by default Since HTTP/2 spec requires for client to send connection preface, it is reasonable to make this option enabled by default. It is still a use case to disable this, so replace this option with nghttp2_option_set_no_recv_client_preface(). --- examples/libevent-server.c | 11 +--------- examples/tiny-nghttpd.c | 13 +----------- lib/includes/nghttp2/nghttp2.h | 35 +++++++++++++++++++------------- lib/nghttp2_option.c | 7 ++++--- lib/nghttp2_option.h | 6 +++--- lib/nghttp2_session.c | 26 ++++++++++++------------ lib/nghttp2_session.h | 2 +- python/nghttp2.pyx | 35 ++++++++++---------------------- src/HttpServer.cc | 17 ++++++---------- src/HttpServer.h | 1 - src/asio_server_http2_handler.cc | 12 +---------- src/shrpx.cc | 1 + tests/main.c | 4 ++-- tests/nghttp2_session_test.c | 20 ++++++++++-------- 14 files changed, 76 insertions(+), 114 deletions(-) diff --git a/examples/libevent-server.c b/examples/libevent-server.c index 9746f234..ef4c2f7d 100644 --- a/examples/libevent-server.c +++ b/examples/libevent-server.c @@ -537,15 +537,8 @@ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id, } static void initialize_nghttp2_session(http2_session_data *session_data) { - nghttp2_option *option; nghttp2_session_callbacks *callbacks; - nghttp2_option_new(&option); - - /* Tells nghttp2_session object that it handles client connection - preface */ - nghttp2_option_set_recv_client_preface(option, 1); - nghttp2_session_callbacks_new(&callbacks); nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); @@ -562,11 +555,9 @@ static void initialize_nghttp2_session(http2_session_data *session_data) { nghttp2_session_callbacks_set_on_begin_headers_callback( callbacks, on_begin_headers_callback); - nghttp2_session_server_new2(&session_data->session, callbacks, session_data, - option); + nghttp2_session_server_new(&session_data->session, callbacks, session_data); nghttp2_session_callbacks_del(callbacks); - nghttp2_option_del(option); } /* Send HTTP/2 client connection header, which includes 24 bytes diff --git a/examples/tiny-nghttpd.c b/examples/tiny-nghttpd.c index b25293fe..c586adfb 100644 --- a/examples/tiny-nghttpd.c +++ b/examples/tiny-nghttpd.c @@ -153,7 +153,6 @@ const char *docroot; size_t docrootlen; nghttp2_session_callbacks *shared_callbacks; -nghttp2_option *shared_option; static int handle_accept(io_loop *loop, uint32_t events, void *ptr); static int handle_connection(io_loop *loop, uint32_t events, void *ptr); @@ -388,8 +387,7 @@ static connection *connection_new(int fd) { conn = malloc(sizeof(connection)); - rv = nghttp2_session_server_new2(&conn->session, shared_callbacks, conn, - shared_option); + rv = nghttp2_session_server_new(&conn->session, shared_callbacks, conn); if (rv != 0) { goto cleanup; @@ -1309,14 +1307,6 @@ int main(int argc, char **argv) { nghttp2_session_callbacks_set_send_data_callback(shared_callbacks, send_data_callback); - rv = nghttp2_option_new(&shared_option); - if (rv != 0) { - fprintf(stderr, "nghttp2_option_new: %s", nghttp2_strerror(rv)); - exit(EXIT_FAILURE); - } - - nghttp2_option_set_recv_client_preface(shared_option, 1); - rv = io_loop_add(&loop, serv.fd, EPOLLIN, &serv); if (rv != 0) { @@ -1333,7 +1323,6 @@ int main(int argc, char **argv) { io_loop_run(&loop, &serv); - nghttp2_option_del(shared_option); nghttp2_session_callbacks_del(shared_callbacks); return 0; diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 98c1d4f0..4b5bfb9b 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -1962,21 +1962,26 @@ nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option, /** * @function * - * By default, nghttp2 library only handles HTTP/2 frames and does not - * recognize first 24 bytes of client connection preface. This design - * choice is done due to the fact that server may want to detect the - * application protocol based on first few bytes on clear text - * communication. But for simple servers which only speak HTTP/2, it - * is easier for developers if nghttp2 library takes care of client - * connection preface. + * By default, nghttp2 library, if configured as server, requires + * first 24 bytes of client connection preface. In most cases, this + * will simplify the implementation of server. But sometimes erver + * may want to detect the application protocol based on first few + * bytes on clear text communication. * - * If this option is used with nonzero |val|, nghttp2 library checks - * first 24 bytes client connection preface. If it is not a valid - * one, `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` will - * return error :enum:`NGHTTP2_ERR_BAD_PREFACE`, which is fatal error. + * If this option is used with nonzero |val|, nghttp2 library does not + * handle first 24 bytes client connection preface. It still checks + * following SETTINGS frame. This means that applications should deal + * with 24 bytes connection preface by themselves. + * + * If this option is not used or used with zero value, if client + * connection preface does not match the one + * (:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`) in the HTTP/2 + * specification, `nghttp2_session_recv()` and + * `nghttp2_session_mem_recv()` will return error + * :enum:`NGHTTP2_ERR_BAD_PREFACE`, which is fatal error. */ NGHTTP2_EXTERN void -nghttp2_option_set_recv_client_preface(nghttp2_option *option, int val); +nghttp2_option_set_no_recv_client_preface(nghttp2_option *option, int val); /** * @function @@ -2296,7 +2301,8 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session, * :enum:`NGHTTP2_ERR_BAD_PREFACE` * Invalid client preface was detected. This error only returns * when |session| was configured as server and - * `nghttp2_option_set_recv_client_preface()` is used. + * `nghttp2_option_set_no_recv_client_preface()` is not used with + * nonzero value. */ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session); @@ -2331,7 +2337,8 @@ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session); * :enum:`NGHTTP2_ERR_BAD_PREFACE` * Invalid client preface was detected. This error only returns * when |session| was configured as server and - * `nghttp2_option_set_recv_client_preface()` is used. + * `nghttp2_option_set_no_recv_client_preface()` is not used with + * nonzero value. */ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, diff --git a/lib/nghttp2_option.c b/lib/nghttp2_option.c index db2a27aa..cf9bae02 100644 --- a/lib/nghttp2_option.c +++ b/lib/nghttp2_option.c @@ -47,9 +47,10 @@ void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option, option->peer_max_concurrent_streams = val; } -void nghttp2_option_set_recv_client_preface(nghttp2_option *option, int val) { - option->opt_set_mask |= NGHTTP2_OPT_RECV_CLIENT_PREFACE; - option->recv_client_preface = val; +void nghttp2_option_set_no_recv_client_preface(nghttp2_option *option, + int val) { + option->opt_set_mask |= NGHTTP2_OPT_NO_RECV_CLIENT_PREFACE; + option->no_recv_client_preface = val; } void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val) { diff --git a/lib/nghttp2_option.h b/lib/nghttp2_option.h index db94be55..f35339ab 100644 --- a/lib/nghttp2_option.h +++ b/lib/nghttp2_option.h @@ -57,7 +57,7 @@ typedef enum { * SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint. */ NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1, - NGHTTP2_OPT_RECV_CLIENT_PREFACE = 1 << 2, + NGHTTP2_OPT_NO_RECV_CLIENT_PREFACE = 1 << 2, NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3, } nghttp2_option_flag; @@ -79,9 +79,9 @@ struct nghttp2_option { */ uint8_t no_auto_window_update; /** - * NGHTTP2_OPT_RECV_CLIENT_PREFACE + * NGHTTP2_OPT_NO_RECV_CLIENT_PREFACE */ - uint8_t recv_client_preface; + uint8_t no_recv_client_preface; /** * NGHTTP2_OPT_NO_HTTP_MESSAGING */ diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 4af67f30..ba3aa7b0 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -314,7 +314,7 @@ static void active_outbound_item_reset(nghttp2_active_outbound_item *aob, /* This global variable exists for tests where we want to disable this check. */ -int nghttp2_enable_strict_first_settings_check = 1; +int nghttp2_enable_strict_connection_preface_check = 1; static int session_new(nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks, @@ -415,10 +415,10 @@ static int session_new(nghttp2_session **session_ptr, option->peer_max_concurrent_streams; } - if ((option->opt_set_mask & NGHTTP2_OPT_RECV_CLIENT_PREFACE) && - option->recv_client_preface) { + if ((option->opt_set_mask & NGHTTP2_OPT_NO_RECV_CLIENT_PREFACE) && + option->no_recv_client_preface) { - (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE; + (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_RECV_CLIENT_PREFACE; } if ((option->opt_set_mask & NGHTTP2_OPT_NO_HTTP_MESSAGING) && @@ -433,17 +433,17 @@ static int session_new(nghttp2_session **session_ptr, session_inbound_frame_reset(*session_ptr); - if (server && - ((*session_ptr)->opt_flags & NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE)) { - + if (nghttp2_enable_strict_connection_preface_check) { nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe; - iframe->state = NGHTTP2_IB_READ_CLIENT_PREFACE; - iframe->payloadleft = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN; - } else if (nghttp2_enable_strict_first_settings_check) { - nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe; - - iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS; + if (server && + ((*session_ptr)->opt_flags & NGHTTP2_OPTMASK_NO_RECV_CLIENT_PREFACE) == + 0) { + iframe->state = NGHTTP2_IB_READ_CLIENT_PREFACE; + iframe->payloadleft = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN; + } else { + iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS; + } } return 0; diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index 94f990cc..ea532262 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -46,7 +46,7 @@ */ typedef enum { NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0, - NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE = 1 << 1, + NGHTTP2_OPTMASK_NO_RECV_CLIENT_PREFACE = 1 << 1, NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2, } nghttp2_optmask; diff --git a/python/nghttp2.pyx b/python/nghttp2.pyx index ad1ebb82..10b12759 100644 --- a/python/nghttp2.pyx +++ b/python/nghttp2.pyx @@ -1237,7 +1237,6 @@ if asyncio: logging.info('connection_made, address:%s, port:%s', address[0], address[1]) self.transport = transport - self.connection_header = cnghttp2.NGHTTP2_CLIENT_CONNECTION_PREFACE sock = self.transport.get_extra_info('socket') sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) ssl_ctx = self.transport.get_extra_info('sslcontext') @@ -1247,6 +1246,16 @@ if asyncio: if protocol.encode('utf-8') != \ cnghttp2.NGHTTP2_PROTO_VERSION_ID: self.transport.abort() + return + try: + self.http2 = _HTTP2SessionCore\ + (self.transport, + self.RequestHandlerClass) + except Exception as err: + sys.stderr.write(traceback.format_exc()) + self.transport.abort() + return + def connection_lost(self, exc): logging.info('connection_lost') @@ -1254,28 +1263,6 @@ if asyncio: self.http2 = None def data_received(self, data): - nread = min(len(data), len(self.connection_header)) - - if self.connection_header.startswith(data[:nread]): - data = data[nread:] - self.connection_header = self.connection_header[nread:] - if len(self.connection_header) == 0: - try: - self.http2 = _HTTP2SessionCore\ - (self.transport, - self.RequestHandlerClass) - except Exception as err: - sys.stderr.write(traceback.format_exc()) - self.transport.abort() - return - - self.data_received = self.data_received2 - self.resume_writing = self.resume_writing2 - self.data_received(data) - else: - self.transport.abort() - - def data_received2(self, data): try: self.http2.data_received(data) except Exception as err: @@ -1283,7 +1270,7 @@ if asyncio: self.transport.close() return - def resume_writing2(self): + def resume_writing(self): try: self.http2.send_data() except Exception as err: diff --git a/src/HttpServer.cc b/src/HttpServer.cc index e8377a6e..1aa2aea7 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -92,16 +92,12 @@ template void append_nv(Stream *stream, const Array &nva) { } // namespace Config::Config() - : stream_read_timeout(60.), stream_write_timeout(60.), - session_option(nullptr), data_ptr(nullptr), padding(0), num_worker(1), - header_table_size(-1), port(0), verbose(false), daemon(false), - verify_client(false), no_tls(false), error_gzip(false), - early_response(false), hexdump(false) { - nghttp2_option_new(&session_option); - nghttp2_option_set_recv_client_preface(session_option, 1); -} + : stream_read_timeout(60.), stream_write_timeout(60.), data_ptr(nullptr), + padding(0), num_worker(1), header_table_size(-1), port(0), verbose(false), + daemon(false), verify_client(false), no_tls(false), error_gzip(false), + early_response(false), hexdump(false) {} -Config::~Config() { nghttp2_option_del(session_option); } +Config::~Config() {} namespace { void stream_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) { @@ -634,8 +630,7 @@ int Http2Handler::on_write() { return write_(*this); } int Http2Handler::connection_made() { int r; - r = nghttp2_session_server_new2(&session_, sessions_->get_callbacks(), this, - sessions_->get_config()->session_option); + r = nghttp2_session_server_new(&session_, sessions_->get_callbacks(), this); if (r != 0) { return r; } diff --git a/src/HttpServer.h b/src/HttpServer.h index 62d50a5d..f28a5282 100644 --- a/src/HttpServer.h +++ b/src/HttpServer.h @@ -59,7 +59,6 @@ struct Config { std::string address; ev_tstamp stream_read_timeout; ev_tstamp stream_write_timeout; - nghttp2_option *session_option; void *data_ptr; size_t padding; size_t num_worker; diff --git a/src/asio_server_http2_handler.cc b/src/asio_server_http2_handler.cc index 7e2304ae..c55cb329 100644 --- a/src/asio_server_http2_handler.cc +++ b/src/asio_server_http2_handler.cc @@ -268,17 +268,7 @@ int http2_handler::start() { nghttp2_session_callbacks_set_on_frame_not_send_callback( callbacks, on_frame_not_send_callback); - nghttp2_option *option; - rv = nghttp2_option_new(&option); - if (rv != 0) { - return -1; - } - - auto opt_del = defer(nghttp2_option_del, option); - - nghttp2_option_set_recv_client_preface(option, 1); - - rv = nghttp2_session_server_new2(&session_, callbacks, this, option); + rv = nghttp2_session_server_new(&session_, callbacks, this); if (rv != 0) { return -1; } diff --git a/src/shrpx.cc b/src/shrpx.cc index 86e4a637..4b64ce39 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -904,6 +904,7 @@ void fill_default_config() { nghttp2_option_new(&mod_config()->http2_option); nghttp2_option_set_no_auto_window_update(get_config()->http2_option, 1); + nghttp2_option_set_no_recv_client_preface(get_config()->http2_option, 1); nghttp2_option_new(&mod_config()->http2_client_option); nghttp2_option_set_no_auto_window_update(get_config()->http2_client_option, diff --git a/tests/main.c b/tests/main.c index 09a92124..9b9e8e63 100644 --- a/tests/main.c +++ b/tests/main.c @@ -41,7 +41,7 @@ #include "nghttp2_helper_test.h" #include "nghttp2_buf_test.h" -extern int nghttp2_enable_strict_first_settings_check; +extern int nghttp2_enable_strict_connection_preface_check; static int init_suite1(void) { return 0; } @@ -51,7 +51,7 @@ int main(int argc _U_, char *argv[] _U_) { CU_pSuite pSuite = NULL; unsigned int num_tests_failed; - nghttp2_enable_strict_first_settings_check = 0; + nghttp2_enable_strict_connection_preface_check = 0; /* initialize the CUnit test registry */ if (CUE_SUCCESS != CU_initialize_registry()) diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 1a4589c9..ef94e3d7 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -36,6 +36,8 @@ #include "nghttp2_test_helper.h" #include "nghttp2_priority_spec.h" +extern int nghttp2_enable_strict_connection_preface_check; + #define OB_CTRL(ITEM) nghttp2_outbound_item_get_ctrl_frame(ITEM) #define OB_CTRL_TYPE(ITEM) nghttp2_outbound_item_get_ctrl_frame_type(ITEM) #define OB_DATA(ITEM) nghttp2_outbound_item_get_data_frame(ITEM) @@ -6723,20 +6725,18 @@ void test_nghttp2_session_on_header_temporal_failure(void) { void test_nghttp2_session_recv_client_preface(void) { nghttp2_session *session; nghttp2_session_callbacks callbacks; - nghttp2_option *option; ssize_t rv; nghttp2_frame ping_frame; uint8_t buf[16]; + /* enable global nghttp2_enable_strict_connection_preface_check + here */ + nghttp2_enable_strict_connection_preface_check = 1; + memset(&callbacks, 0, sizeof(callbacks)); - nghttp2_option_new(&option); - nghttp2_option_set_recv_client_preface(option, 1); - /* Check success case */ - nghttp2_session_server_new2(&session, &callbacks, NULL, option); - - CU_ASSERT(session->opt_flags & NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE); + nghttp2_session_server_new(&session, &callbacks, NULL); rv = nghttp2_session_mem_recv( session, (const uint8_t *)NGHTTP2_CLIENT_CONNECTION_PREFACE, @@ -6760,7 +6760,7 @@ void test_nghttp2_session_recv_client_preface(void) { nghttp2_session_del(session); /* Check bad case */ - nghttp2_session_server_new2(&session, &callbacks, NULL, option); + nghttp2_session_server_new(&session, &callbacks, NULL); /* Feed preface with one byte less */ rv = nghttp2_session_mem_recv( @@ -6777,7 +6777,9 @@ void test_nghttp2_session_recv_client_preface(void) { nghttp2_session_del(session); - nghttp2_option_del(option); + /* disable global nghttp2_enable_strict_connection_preface_check + here */ + nghttp2_enable_strict_connection_preface_check = 0; } void test_nghttp2_session_delete_data_item(void) { From ebf214c8fc45ea96f60a5edb7737b96f1d59e3ee Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Mon, 23 Mar 2015 21:18:55 +0900 Subject: [PATCH 03/14] nghttp2_on_invalid_frame_recv_callback should have lib_error_code as param nghttp2_error_code is HTTP/2 standard error code and is too coarse to know what's going on. --- lib/includes/nghttp2/nghttp2.h | 28 +++-- lib/nghttp2_helper.c | 6 ++ lib/nghttp2_session.c | 187 ++++++++++++++++----------------- src/app_helper.cc | 5 +- src/app_helper.h | 3 +- tests/nghttp2_session_test.c | 2 +- 6 files changed, 123 insertions(+), 108 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 4b5bfb9b..e80049b7 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -367,6 +367,18 @@ typedef enum { * closed. */ NGHTTP2_ERR_HTTP_HEADER = -531, + /** + * Violation in HTTP messaging rule. + */ + NGHTTP2_ERR_HTTP_MESSAGING = -532, + /** + * Stream was refused. + */ + NGHTTP2_ERR_REFUSED_STREAM = -533, + /** + * Unexpected internal error, but recovered. + */ + NGHTTP2_ERR_INTERNAL = -534, /** * The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is * under unexpected condition and processing was terminated (e.g., @@ -1259,12 +1271,12 @@ typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session, * @functypedef * * Callback function invoked by `nghttp2_session_recv()` when an - * invalid non-DATA frame is received. The |error_code| indicates the - * error. It is usually one of the :enum:`nghttp2_error_code` but - * that is not guaranteed. When this callback function is invoked, - * the library automatically submits either RST_STREAM or GOAWAY - * frame. The |user_data| pointer is the third argument passed in to - * the call to `nghttp2_session_client_new()` or + * invalid non-DATA frame is received. The error is indicated by the + * |lib_error_code|, which is one of the values defined in + * :type:`nghttp2_error`. When this callback function is invoked, the + * library automatically submits either RST_STREAM or GOAWAY frame. + * The |user_data| pointer is the third argument passed in to the call + * to `nghttp2_session_client_new()` or * `nghttp2_session_server_new()`. * * If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen`` @@ -1280,7 +1292,7 @@ typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session, * `nghttp2_session_callbacks_set_on_invalid_frame_recv_callback()`. */ typedef int (*nghttp2_on_invalid_frame_recv_callback)( - nghttp2_session *session, const nghttp2_frame *frame, uint32_t error_code, + nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code, void *user_data); /** @@ -3462,7 +3474,7 @@ NGHTTP2_EXTERN nghttp2_info *nghttp2_version(int least_version); * Returns nonzero if the :type:`nghttp2_error` library error code * |lib_error| is fatal. */ -NGHTTP2_EXTERN int nghttp2_is_fatal(int lib_error); +NGHTTP2_EXTERN int nghttp2_is_fatal(int lib_error_code); /** * @function diff --git a/lib/nghttp2_helper.c b/lib/nghttp2_helper.c index 79f8e92b..5883f72c 100644 --- a/lib/nghttp2_helper.c +++ b/lib/nghttp2_helper.c @@ -297,6 +297,12 @@ const char *nghttp2_strerror(int error_code) { return "The current session is closing"; case NGHTTP2_ERR_HTTP_HEADER: return "Invalid HTTP header field was received"; + case NGHTTP2_ERR_HTTP_MESSAGING: + return "Violation in HTTP messaging rule"; + case NGHTTP2_ERR_REFUSED_STREAM: + return "Stream was refused"; + case NGHTTP2_ERR_INTERNAL: + return "Internal error"; case NGHTTP2_ERR_NOMEM: return "Out of memory"; case NGHTTP2_ERR_CALLBACK_FAILURE: diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index ba3aa7b0..bbb9aaa3 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -71,11 +71,13 @@ session_is_incoming_concurrent_streams_pending_max(nghttp2_session *session) { /* * Returns non-zero if |lib_error| is non-fatal error. */ -static int is_non_fatal(int lib_error) { - return lib_error < 0 && lib_error > NGHTTP2_ERR_FATAL; +static int is_non_fatal(int lib_error_code) { + return lib_error_code < 0 && lib_error_code > NGHTTP2_ERR_FATAL; } -int nghttp2_is_fatal(int lib_error) { return lib_error < NGHTTP2_ERR_FATAL; } +int nghttp2_is_fatal(int lib_error_code) { + return lib_error_code < NGHTTP2_ERR_FATAL; +} static int session_enforce_http_messaging(nghttp2_session *session) { return (session->opt_flags & NGHTTP2_OPTMASK_NO_HTTP_MESSAGING) == 0; @@ -3128,18 +3130,38 @@ static int session_handle_frame_size_error(nghttp2_session *session, return nghttp2_session_terminate_session(session, NGHTTP2_FRAME_SIZE_ERROR); } +static int get_error_code_from_lib_error_code(int lib_error_code) { + switch (lib_error_code) { + case NGHTTP2_ERR_STREAM_CLOSED: + return NGHTTP2_STREAM_CLOSED; + case NGHTTP2_ERR_HEADER_COMP: + return NGHTTP2_COMPRESSION_ERROR; + case NGHTTP2_ERR_FRAME_SIZE_ERROR: + return NGHTTP2_FRAME_SIZE_ERROR; + case NGHTTP2_ERR_FLOW_CONTROL: + return NGHTTP2_FLOW_CONTROL_ERROR; + case NGHTTP2_ERR_REFUSED_STREAM: + return NGHTTP2_REFUSED_STREAM; + case NGHTTP2_ERR_PROTO: + return NGHTTP2_PROTOCOL_ERROR; + default: + return NGHTTP2_INTERNAL_ERROR; + } +} + static int session_handle_invalid_stream2(nghttp2_session *session, int32_t stream_id, nghttp2_frame *frame, - uint32_t error_code) { + int lib_error_code) { int rv; - rv = nghttp2_session_add_rst_stream(session, stream_id, error_code); + rv = nghttp2_session_add_rst_stream( + session, stream_id, get_error_code_from_lib_error_code(lib_error_code)); if (rv != 0) { return rv; } if (session->callbacks.on_invalid_frame_recv_callback) { if (session->callbacks.on_invalid_frame_recv_callback( - session, frame, error_code, session->user_data) != 0) { + session, frame, lib_error_code, session->user_data) != 0) { return NGHTTP2_ERR_CALLBACK_FAILURE; } } @@ -3148,16 +3170,16 @@ static int session_handle_invalid_stream2(nghttp2_session *session, static int session_handle_invalid_stream(nghttp2_session *session, nghttp2_frame *frame, - uint32_t error_code) { + int lib_error_code) { return session_handle_invalid_stream2(session, frame->hd.stream_id, frame, - error_code); + lib_error_code); } static int session_inflate_handle_invalid_stream(nghttp2_session *session, nghttp2_frame *frame, - uint32_t error_code) { + int lib_error_code) { int rv; - rv = session_handle_invalid_stream(session, frame, error_code); + rv = session_handle_invalid_stream(session, frame, lib_error_code); if (nghttp2_is_fatal(rv)) { return rv; } @@ -3169,24 +3191,25 @@ static int session_inflate_handle_invalid_stream(nghttp2_session *session, */ static int session_handle_invalid_connection(nghttp2_session *session, nghttp2_frame *frame, - uint32_t error_code, + int lib_error_code, const char *reason) { if (session->callbacks.on_invalid_frame_recv_callback) { if (session->callbacks.on_invalid_frame_recv_callback( - session, frame, error_code, session->user_data) != 0) { + session, frame, lib_error_code, session->user_data) != 0) { return NGHTTP2_ERR_CALLBACK_FAILURE; } } - return nghttp2_session_terminate_session_with_reason(session, error_code, - reason); + return nghttp2_session_terminate_session_with_reason( + session, get_error_code_from_lib_error_code(lib_error_code), reason); } static int session_inflate_handle_invalid_connection(nghttp2_session *session, nghttp2_frame *frame, - uint32_t error_code, + int lib_error_code, const char *reason) { int rv; - rv = session_handle_invalid_connection(session, frame, error_code, reason); + rv = + session_handle_invalid_connection(session, frame, lib_error_code, reason); if (nghttp2_is_fatal(rv)) { return rv; } @@ -3291,7 +3314,7 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, rv = session_handle_invalid_stream2(session, subject_stream->stream_id, - frame, NGHTTP2_PROTOCOL_ERROR); + frame, NGHTTP2_ERR_HTTP_HEADER); if (nghttp2_is_fatal(rv)) { return rv; } @@ -3466,7 +3489,7 @@ static int session_after_header_block_received(nghttp2_session *session) { call_cb = 0; rv = session_handle_invalid_stream2(session, stream_id, frame, - NGHTTP2_PROTOCOL_ERROR); + NGHTTP2_ERR_HTTP_MESSAGING); if (nghttp2_is_fatal(rv)) { return rv; } @@ -3505,8 +3528,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session, nghttp2_stream *stream; if (frame->hd.stream_id == 0) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, - "request HEADERS: stream_id == 0"); + session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: stream_id == 0"); } /* If client recieves idle stream from server, it is invalid @@ -3515,7 +3537,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session, if (!session->server) { if (session_detect_idle_stream(session, frame->hd.stream_id)) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, + session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: client received request"); } @@ -3532,7 +3554,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session, just ignore HEADERS for now. */ if (session_detect_idle_stream(session, frame->hd.stream_id)) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, + session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: invalid stream_id"); } @@ -3547,19 +3569,18 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session, if (session_is_incoming_concurrent_streams_max(session)) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, + session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: max concurrent streams exceeded"); } if (frame->headers.pri_spec.stream_id == frame->hd.stream_id) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, - "request HEADERS: depend on itself"); + session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: depend on itself"); } if (session_is_incoming_concurrent_streams_pending_max(session)) { return session_inflate_handle_invalid_stream(session, frame, - NGHTTP2_REFUSED_STREAM); + NGHTTP2_ERR_REFUSED_STREAM); } stream = nghttp2_session_open_stream( @@ -3586,8 +3607,7 @@ int nghttp2_session_on_response_headers_received(nghttp2_session *session, nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)); if (frame->hd.stream_id == 0) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, - "response HEADERS: stream_id == 0"); + session, frame, NGHTTP2_ERR_PROTO, "response HEADERS: stream_id == 0"); } if (stream->shut_flags & NGHTTP2_SHUT_RD) { /* half closed (remote): from the spec: @@ -3597,7 +3617,7 @@ int nghttp2_session_on_response_headers_received(nghttp2_session *session, 5.4.2) of type STREAM_CLOSED. */ return session_inflate_handle_invalid_stream(session, frame, - NGHTTP2_STREAM_CLOSED); + NGHTTP2_ERR_STREAM_CLOSED); } stream->state = NGHTTP2_STREAM_OPENED; rv = session_call_on_begin_headers(session, frame); @@ -3614,7 +3634,7 @@ int nghttp2_session_on_push_response_headers_received(nghttp2_session *session, assert(stream->state == NGHTTP2_STREAM_RESERVED); if (frame->hd.stream_id == 0) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, + session, frame, NGHTTP2_ERR_PROTO, "push response HEADERS: stream_id == 0"); } if (session->goaway_flags) { @@ -3624,12 +3644,12 @@ int nghttp2_session_on_push_response_headers_received(nghttp2_session *session, if (session_is_incoming_concurrent_streams_max(session)) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, + session, frame, NGHTTP2_ERR_PROTO, "push response HEADERS: max concurrent streams exceeded"); } if (session_is_incoming_concurrent_streams_pending_max(session)) { return session_inflate_handle_invalid_stream(session, frame, - NGHTTP2_REFUSED_STREAM); + NGHTTP2_ERR_REFUSED_STREAM); } nghttp2_stream_promise_fulfilled(stream); @@ -3647,7 +3667,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session, int rv = 0; if (frame->hd.stream_id == 0) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, "HEADERS: stream_id == 0"); + session, frame, NGHTTP2_ERR_PROTO, "HEADERS: stream_id == 0"); } if (stream->state == NGHTTP2_STREAM_RESERVED) { /* reserved. The valid push response HEADERS is processed by @@ -3655,7 +3675,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session, generic HEADERS is called invalid cases for HEADERS against reserved state. */ return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, "HEADERS: stream in reserved"); + session, frame, NGHTTP2_ERR_PROTO, "HEADERS: stream in reserved"); } if ((stream->shut_flags & NGHTTP2_SHUT_RD)) { /* half closed (remote): from the spec: @@ -3665,7 +3685,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session, 5.4.2) of type STREAM_CLOSED. */ return session_inflate_handle_invalid_stream(session, frame, - NGHTTP2_STREAM_CLOSED); + NGHTTP2_ERR_STREAM_CLOSED); } if (nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { if (stream->state == NGHTTP2_STREAM_OPENED) { @@ -3681,7 +3701,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session, return NGHTTP2_ERR_IGN_HEADER_BLOCK; } else { return session_inflate_handle_invalid_stream(session, frame, - NGHTTP2_PROTOCOL_ERROR); + NGHTTP2_ERR_PROTO); } } /* If this is remote peer initiated stream, it is OK unless it @@ -3741,8 +3761,8 @@ int nghttp2_session_on_priority_received(nghttp2_session *session, nghttp2_stream *stream; if (frame->hd.stream_id == 0) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, "PRIORITY: stream_id == 0"); + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "PRIORITY: stream_id == 0"); } if (!session->server) { @@ -3793,14 +3813,14 @@ int nghttp2_session_on_rst_stream_received(nghttp2_session *session, int rv; nghttp2_stream *stream; if (frame->hd.stream_id == 0) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, "RST_STREAM: stream_id == 0"); + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "RST_STREAM: stream_id == 0"); } stream = nghttp2_session_get_stream(session, frame->hd.stream_id); if (!stream) { if (session_detect_idle_stream(session, frame->hd.stream_id)) { return session_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, "RST_STREAM: stream in idle"); + session, frame, NGHTTP2_ERR_PROTO, "RST_STREAM: stream in idle"); } } @@ -4020,18 +4040,18 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, mem = &session->mem; if (frame->hd.stream_id != 0) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, "SETTINGS: stream_id != 0"); + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "SETTINGS: stream_id != 0"); } if (frame->hd.flags & NGHTTP2_FLAG_ACK) { if (frame->settings.niv != 0) { return session_handle_invalid_connection( - session, frame, NGHTTP2_FRAME_SIZE_ERROR, + session, frame, NGHTTP2_ERR_FRAME_SIZE_ERROR, "SETTINGS: ACK and payload != 0"); } if (session->inflight_niv == -1) { return session_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, "SETTINGS: unexpected ACK"); + session, frame, NGHTTP2_ERR_PROTO, "SETTINGS: unexpected ACK"); } rv = nghttp2_session_update_local_settings(session, session->inflight_iv, session->inflight_niv); @@ -4039,15 +4059,10 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, session->inflight_iv = NULL; session->inflight_niv = -1; if (rv != 0) { - uint32_t error_code = NGHTTP2_INTERNAL_ERROR; if (nghttp2_is_fatal(rv)) { return rv; } - if (rv == NGHTTP2_ERR_HEADER_COMP) { - error_code = NGHTTP2_COMPRESSION_ERROR; - } - return session_handle_invalid_connection(session, frame, error_code, - NULL); + return session_handle_invalid_connection(session, frame, rv, NULL); } return session_call_on_frame_received(session, frame); } @@ -4060,7 +4075,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, if (entry->value > NGHTTP2_MAX_HEADER_TABLE_SIZE) { return session_handle_invalid_connection( - session, frame, NGHTTP2_COMPRESSION_ERROR, + session, frame, NGHTTP2_ERR_HEADER_COMP, "SETTINGS: too large SETTINGS_HEADER_TABLE_SIZE"); } @@ -4071,7 +4086,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, return rv; } else { return session_handle_invalid_connection( - session, frame, NGHTTP2_COMPRESSION_ERROR, NULL); + session, frame, NGHTTP2_ERR_HEADER_COMP, NULL); } } @@ -4082,13 +4097,13 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, if (entry->value != 0 && entry->value != 1) { return session_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, + session, frame, NGHTTP2_ERR_PROTO, "SETTINGS: invalid SETTINGS_ENBLE_PUSH"); } if (!session->server && entry->value != 0) { return session_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, + session, frame, NGHTTP2_ERR_PROTO, "SETTINGS: server attempted to enable push"); } @@ -4106,7 +4121,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, /* Check that initial_window_size < (1u << 31) */ if (entry->value > NGHTTP2_MAX_WINDOW_SIZE) { return session_handle_invalid_connection( - session, frame, NGHTTP2_FLOW_CONTROL_ERROR, + session, frame, NGHTTP2_ERR_FLOW_CONTROL, "SETTINGS: too large SETTINGS_INITIAL_WINDOW_SIZE"); } @@ -4118,7 +4133,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, if (rv != 0) { return session_handle_invalid_connection( - session, frame, NGHTTP2_FLOW_CONTROL_ERROR, NULL); + session, frame, NGHTTP2_ERR_FLOW_CONTROL, NULL); } session->remote_settings.initial_window_size = entry->value; @@ -4129,7 +4144,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, if (entry->value < NGHTTP2_MAX_FRAME_SIZE_MIN || entry->value > NGHTTP2_MAX_FRAME_SIZE_MAX) { return session_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, + session, frame, NGHTTP2_ERR_PROTO, "SETTINGS: invalid SETTINGS_MAX_FRAME_SIZE"); } @@ -4153,7 +4168,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, } return session_handle_invalid_connection(session, frame, - NGHTTP2_INTERNAL_ERROR, NULL); + NGHTTP2_ERR_INTERNAL, NULL); } } @@ -4206,11 +4221,11 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, if (frame->hd.stream_id == 0) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, "PUSH_PROMISE: stream_id == 0"); + session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: stream_id == 0"); } if (session->server || session->local_settings.enable_push == 0) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, "PUSH_PROMISE: push disabled"); + session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: push disabled"); } if (session->goaway_flags) { /* We just dicard PUSH_PROMISE after GOAWAY is sent or @@ -4220,8 +4235,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, if (!nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, - "PUSH_PROMISE: invalid stream_id"); + session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: invalid stream_id"); } if (!session_is_new_peer_stream_id(session, @@ -4230,7 +4244,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, illegal stream ID is subject to a connection error of type PROTOCOL_ERROR. */ return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, + session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: invalid promised_stream_id"); } session->last_recv_stream_id = frame->push_promise.promised_stream_id; @@ -4240,8 +4254,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, if (!stream) { if (session_detect_idle_stream(session, frame->hd.stream_id)) { return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, - "PUSH_PROMISE: stream in idle"); + session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: stream in idle"); } } rv = nghttp2_session_add_rst_stream(session, @@ -4310,8 +4323,8 @@ int nghttp2_session_on_ping_received(nghttp2_session *session, nghttp2_frame *frame) { int rv = 0; if (frame->hd.stream_id != 0) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, "PING: stream_id != 0"); + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "PING: stream_id != 0"); } if ((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0 && !session_is_closing(session)) { @@ -4340,8 +4353,8 @@ int nghttp2_session_on_goaway_received(nghttp2_session *session, int rv; if (frame->hd.stream_id != 0) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, "GOAWAY: stream_id != 0"); + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "GOAWAY: stream_id != 0"); } /* Spec says Endpoints MUST NOT increase the value they send in the last stream identifier. */ @@ -4349,8 +4362,7 @@ int nghttp2_session_on_goaway_received(nghttp2_session *session, !nghttp2_session_is_my_stream_id(session, frame->goaway.last_stream_id)) || session->remote_last_stream_id < frame->goaway.last_stream_id) { - return session_handle_invalid_connection(session, frame, - NGHTTP2_PROTOCOL_ERROR, + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, "GOAWAY: invalid last_stream_id"); } @@ -4386,14 +4398,14 @@ session_on_connection_window_update_received(nghttp2_session *session, nghttp2_frame *frame) { /* Handle connection-level flow control */ if (frame->window_update.window_size_increment == 0) { - return session_handle_invalid_connection(session, frame, - NGHTTP2_PROTOCOL_ERROR, NULL); + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + NULL); } if (NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment < session->remote_window_size) { return session_handle_invalid_connection(session, frame, - NGHTTP2_FLOW_CONTROL_ERROR, NULL); + NGHTTP2_ERR_FLOW_CONTROL, NULL); } session->remote_window_size += frame->window_update.window_size_increment; @@ -4407,25 +4419,22 @@ static int session_on_stream_window_update_received(nghttp2_session *session, stream = nghttp2_session_get_stream(session, frame->hd.stream_id); if (!stream) { if (session_detect_idle_stream(session, frame->hd.stream_id)) { - return session_handle_invalid_connection(session, frame, - NGHTTP2_PROTOCOL_ERROR, - "WINDOW_UPDATE to idle stream"); + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, "WINDOW_UPDATE to idle stream"); } return 0; } if (state_reserved_remote(session, stream)) { return session_handle_invalid_connection( - session, frame, NGHTTP2_PROTOCOL_ERROR, - "WINDOW_UPADATE to reserved stream"); + session, frame, NGHTTP2_ERR_PROTO, "WINDOW_UPADATE to reserved stream"); } if (frame->window_update.window_size_increment == 0) { - return session_handle_invalid_stream(session, frame, - NGHTTP2_PROTOCOL_ERROR); + return session_handle_invalid_stream(session, frame, NGHTTP2_ERR_PROTO); } if (NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment < stream->remote_window_size) { return session_handle_invalid_stream(session, frame, - NGHTTP2_FLOW_CONTROL_ERROR); + NGHTTP2_ERR_FLOW_CONTROL); } stream->remote_window_size += frame->window_update.window_size_increment; @@ -4461,18 +4470,6 @@ static int session_process_window_update_frame(nghttp2_session *session) { return nghttp2_session_on_window_update_received(session, frame); } -/* static int get_error_code_from_lib_error_code(int lib_error_code) */ -/* { */ -/* switch(lib_error_code) { */ -/* case NGHTTP2_ERR_HEADER_COMP: */ -/* return NGHTTP2_COMPRESSION_ERROR; */ -/* case NGHTTP2_ERR_FRAME_SIZE_ERROR: */ -/* return NGHTTP2_FRAME_SIZE_ERROR; */ -/* default: */ -/* return NGHTTP2_PROTOCOL_ERROR; */ -/* } */ -/* } */ - int nghttp2_session_on_data_received(nghttp2_session *session, nghttp2_frame *frame) { int rv = 0; diff --git a/src/app_helper.cc b/src/app_helper.cc index e23fddd2..f2981bc2 100644 --- a/src/app_helper.cc +++ b/src/app_helper.cc @@ -399,10 +399,11 @@ int verbose_on_frame_recv_callback(nghttp2_session *session, int verbose_on_invalid_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame, - uint32_t error_code, + int lib_error_code, void *user_data) { print_timer(); - fprintf(outfile, " [INVALID; status=%s] recv ", strstatus(error_code)); + fprintf(outfile, " [INVALID; error=%s] recv ", + nghttp2_strerror(lib_error_code)); print_frame(PRINT_RECV, frame); fflush(outfile); return 0; diff --git a/src/app_helper.h b/src/app_helper.h index 6675fde5..9f11661f 100644 --- a/src/app_helper.h +++ b/src/app_helper.h @@ -49,8 +49,7 @@ int verbose_on_frame_recv_callback(nghttp2_session *session, int verbose_on_invalid_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame, - uint32_t error_code, - void *user_data); + int lib_error_code, void *user_data); int verbose_on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame, void *user_data); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index ef94e3d7..4e77019b 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -186,7 +186,7 @@ static int on_frame_recv_callback(nghttp2_session *session _U_, static int on_invalid_frame_recv_callback(nghttp2_session *session _U_, const nghttp2_frame *frame _U_, - nghttp2_error_code error_code _U_, + int lib_error_code _U_, void *user_data) { my_user_data *ud = (my_user_data *)user_data; ++ud->invalid_frame_recv_cb_called; From d0c27d52296a0adb6f5614cb58408c8617f39aab Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 5 Apr 2015 22:35:40 +0900 Subject: [PATCH 04/14] Send 24 bytes client magic byte string by library Previously nghttp2_session_send() and nghttp2_session_mem_send() did not send 24 bytes client magic byte string (MAGIC). We made nghttp2_session_recv() and nghttp2_session_mem_recv() process MAGIC by default, so it is natural to make library send MAGIC as well. This commit makes nghttp2_session_send() and nghttp2_session_mem_send() send MAGIC. This commit also replace "connection preface" with "client magic", since we call MAGIC as "connection preface" but it is just a part of connection preface. NGHTTP2_CLIENT_CONNECTION_PREFACE macro was replaced with NGHTTP2_CLIENT_MAGIC. The already deprecated NGHTTP2_CLIENT_CONNECTION_HEADER macro was removed permanently. nghttp2_option_set_no_recv_client_preface() was renamed as nghttp2_option_set_no_recv_client_magic(). NGHTTP2_ERR_BAD_PREFACE was renamed as NGHTTP2_ERR_BAD_CLIENT_MAGIC. --- doc/programmers-guide.rst | 20 +++++----- doc/sources/tutorial-client.rst | 9 ++--- doc/sources/tutorial-server.rst | 16 +------- examples/client.c | 8 ---- examples/libevent-client.c | 3 +- lib/includes/nghttp2/nghttp2.h | 68 ++++++++++++-------------------- lib/nghttp2_helper.c | 4 +- lib/nghttp2_option.c | 7 ++-- lib/nghttp2_option.h | 6 +-- lib/nghttp2_session.c | 70 ++++++++++++++++++++++----------- lib/nghttp2_session.h | 7 ++-- python/nghttp2.pyx | 2 - src/HttpServer.cc | 4 +- src/asio_client_session_impl.cc | 4 -- src/h2load_http2_session.cc | 6 --- src/nghttp.cc | 3 -- src/shrpx.cc | 2 +- src/shrpx_client_handler.cc | 10 ++--- src/shrpx_http2_session.cc | 7 ---- src/shrpx_http2_upstream.cc | 2 +- tests/main.c | 8 ++-- tests/nghttp2_session_test.c | 34 +++++++--------- tests/nghttp2_session_test.h | 2 +- 23 files changed, 129 insertions(+), 173 deletions(-) diff --git a/doc/programmers-guide.rst b/doc/programmers-guide.rst index c67c09a3..94c72e98 100644 --- a/doc/programmers-guide.rst +++ b/doc/programmers-guide.rst @@ -20,17 +20,15 @@ nghttp2 callback functions directly or indirectly. It will lead to the crash. You can submit requests or frames in the callbacks then call these functions outside the callbacks. -Currently, `nghttp2_session_send()` and `nghttp2_session_mem_send()` -do not send client connection preface -(:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`). The applications are -responsible to send it before sending any HTTP/2 frames using these -functions if :type:`nghttp2_session` is configured as client. -Similarly, `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` -do not consume client connection preface unless -`nghttp2_option_set_recv_client_preface()` is used with nonzero option -value. The applications are responsible to receive it before calling -these functions if :type:`nghttp2_session` is configured as server and -`nghttp2_option_set_recv_client_preface()` is not used. +`nghttp2_session_send()` and `nghttp2_session_mem_send()` send first +24 bytes of client magic string (MAGIC) +(:macro:`NGHTTP2_CLIENT_MAGIC`) on client configuration. The +applications are responsible to send SETTINGS frame as part of +connection preface using `nghttp2_submit_settings()`. Similarly, +`nghttp2_session_recv()` and `nghttp2_session_mem_recv()` consume +MAGIC on server configuration unless +`nghttp2_option_set_no_recv_client_magic()` is used with nonzero +option value. .. _http-messaging: diff --git a/doc/sources/tutorial-client.rst b/doc/sources/tutorial-client.rst index 0d168991..ceaa14c8 100644 --- a/doc/sources/tutorial-client.rst +++ b/doc/sources/tutorial-client.rst @@ -184,9 +184,9 @@ its bufferevent, so it closes underlying connection as well. It also calls `nghttp2_session_del()` to delete nghttp2 session object. We begin HTTP/2 communication by sending client connection preface, -which is 24 bytes magic byte sequence -(:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`) and SETTINGS frame. The -transmission of client connection header is done in +which is 24 bytes magic byte string (:macro:`NGHTTP2_CLIENT_MAGIC`) +followed by SETTINGS frame. First 24 bytes magic string is +automatically sent by nghttp2 library. We send SETTINGS frame in ``send_client_connection_header()``:: static void send_client_connection_header(http2_session_data *session_data) { @@ -194,8 +194,7 @@ transmission of client connection header is done in {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}}; int rv; - bufferevent_write(session_data->bev, NGHTTP2_CLIENT_CONNECTION_PREFACE, - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN); + /* client 24 bytes magic string will be sent by nghttp2 library */ rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv, ARRLEN(iv)); if (rv != 0) { diff --git a/doc/sources/tutorial-server.rst b/doc/sources/tutorial-server.rst index 12347ef6..8f5b5833 100644 --- a/doc/sources/tutorial-server.rst +++ b/doc/sources/tutorial-server.rst @@ -194,15 +194,8 @@ We initialize a nghttp2 session object which is done in ``initialize_nghttp2_session()``:: static void initialize_nghttp2_session(http2_session_data *session_data) { - nghttp2_option *option; nghttp2_session_callbacks *callbacks; - nghttp2_option_new(&option); - - /* Tells nghttp2_session object that it handles client connection - preface */ - nghttp2_option_set_recv_client_preface(option, 1); - nghttp2_session_callbacks_new(&callbacks); nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); @@ -219,20 +212,15 @@ We initialize a nghttp2 session object which is done in nghttp2_session_callbacks_set_on_begin_headers_callback( callbacks, on_begin_headers_callback); - nghttp2_session_server_new2(&session_data->session, callbacks, session_data, - option); + nghttp2_session_server_new(&session_data->session, callbacks, session_data); nghttp2_session_callbacks_del(callbacks); - nghttp2_option_del(option); } Since we are creating a server and uses options, the nghttp2 session object is created using `nghttp2_session_server_new2()` function. We registers five callbacks for nghttp2 session object. We'll talk about -these callbacks later. Our server only speaks HTTP/2. In this case, -we use `nghttp2_option_set_recv_client_preface()` to make -:type:`nghttp2_session` object handle client connection preface, which -saves some lines of application code. +these callbacks later. After initialization of the nghttp2 session object, we are going to send a server connection header in ``send_server_connection_header()``:: diff --git a/examples/client.c b/examples/client.c index 314efb34..b202df18 100644 --- a/examples/client.c +++ b/examples/client.c @@ -528,14 +528,6 @@ static void fetch_uri(const struct URI *uri) { connection.ssl = ssl; connection.want_io = IO_NONE; - /* Send connection header in blocking I/O mode */ - rv = SSL_write(ssl, NGHTTP2_CLIENT_CONNECTION_PREFACE, - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN); - if (rv <= 0) { - dief("SSL_write failed: could not send connection preface", - ERR_error_string(ERR_get_error(), NULL)); - } - /* Here make file descriptor non-block */ make_non_block(fd); set_tcp_nodelay(fd); diff --git a/examples/libevent-client.c b/examples/libevent-client.c index 98c194a6..c970629b 100644 --- a/examples/libevent-client.c +++ b/examples/libevent-client.c @@ -345,8 +345,7 @@ static void send_client_connection_header(http2_session_data *session_data) { {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}}; int rv; - bufferevent_write(session_data->bev, NGHTTP2_CLIENT_CONNECTION_PREFACE, - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN); + /* client 24 bytes magic string will be sent by nghttp2 library */ rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv, ARRLEN(iv)); if (rv != 0) { diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index e80049b7..969726f4 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -194,32 +194,17 @@ typedef struct { /** * @macro * - * The client connection preface. + * The client magic string, which is the first 24 bytes byte string of + * client connection preface. */ -#define NGHTTP2_CLIENT_CONNECTION_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" +#define NGHTTP2_CLIENT_MAGIC "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" /** * @macro * - * The length of :macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`. + * The length of :macro:`NGHTTP2_CLIENT_MAGIC`. */ -#define NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN 24 - -/** - * @macro - * - * The client connection header. This macro is obsoleted by - * NGHTTP2_CLIENT_CONNECTION_PREFACE. - */ -#define NGHTTP2_CLIENT_CONNECTION_HEADER NGHTTP2_CLIENT_CONNECTION_PREFACE - -/** - * @macro - * - * The length of :macro:`NGHTTP2_CLIENT_CONNECTION_HEADER`. - */ -#define NGHTTP2_CLIENT_CONNECTION_HEADER_LEN \ - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN +#define NGHTTP2_CLIENT_MAGIC_LEN 24 /** * @enum @@ -397,10 +382,10 @@ typedef enum { */ NGHTTP2_ERR_CALLBACK_FAILURE = -902, /** - * Invalid connection preface was received and further processing is - * not possible. + * Invalid client magic (see :macro:`NGHTTP2_CLIENT_MAGIC`) was + * received and further processing is not possible. */ - NGHTTP2_ERR_BAD_PREFACE = -903 + NGHTTP2_ERR_BAD_CLIENT_MAGIC = -903 } nghttp2_error; /** @@ -1975,25 +1960,22 @@ nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option, * @function * * By default, nghttp2 library, if configured as server, requires - * first 24 bytes of client connection preface. In most cases, this - * will simplify the implementation of server. But sometimes erver - * may want to detect the application protocol based on first few - * bytes on clear text communication. + * first 24 bytes of client magic byte string (MAGIC). In most cases, + * this will simplify the implementation of server. But sometimes + * server may want to detect the application protocol based on first + * few bytes on clear text communication. * * If this option is used with nonzero |val|, nghttp2 library does not - * handle first 24 bytes client connection preface. It still checks - * following SETTINGS frame. This means that applications should deal - * with 24 bytes connection preface by themselves. + * handle MAGIC. It still checks following SETTINGS frame. This + * means that applications should deal with MAGIC by themselves. * - * If this option is not used or used with zero value, if client - * connection preface does not match the one - * (:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`) in the HTTP/2 - * specification, `nghttp2_session_recv()` and - * `nghttp2_session_mem_recv()` will return error - * :enum:`NGHTTP2_ERR_BAD_PREFACE`, which is fatal error. + * If this option is not used or used with zero value, if MAGIC does + * not match :macro:`NGHTTP2_CLIENT_MAGIC`, `nghttp2_session_recv()` + * and `nghttp2_session_mem_recv()` will return error + * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal error. */ NGHTTP2_EXTERN void -nghttp2_option_set_no_recv_client_preface(nghttp2_option *option, int val); +nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val); /** * @function @@ -2310,10 +2292,10 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session, * Out of memory. * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` * The callback function failed. - * :enum:`NGHTTP2_ERR_BAD_PREFACE` - * Invalid client preface was detected. This error only returns + * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC` + * Invalid client magic was detected. This error only returns * when |session| was configured as server and - * `nghttp2_option_set_no_recv_client_preface()` is not used with + * `nghttp2_option_set_no_recv_client_magic()` is not used with * nonzero value. */ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session); @@ -2346,10 +2328,10 @@ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session); * Out of memory. * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` * The callback function failed. - * :enum:`NGHTTP2_ERR_BAD_PREFACE` - * Invalid client preface was detected. This error only returns + * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC` + * Invalid client magic was detected. This error only returns * when |session| was configured as server and - * `nghttp2_option_set_no_recv_client_preface()` is not used with + * `nghttp2_option_set_no_recv_client_magic()` is not used with * nonzero value. */ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session, diff --git a/lib/nghttp2_helper.c b/lib/nghttp2_helper.c index 5883f72c..15f329cc 100644 --- a/lib/nghttp2_helper.c +++ b/lib/nghttp2_helper.c @@ -307,8 +307,8 @@ const char *nghttp2_strerror(int error_code) { return "Out of memory"; case NGHTTP2_ERR_CALLBACK_FAILURE: return "The user callback function failed"; - case NGHTTP2_ERR_BAD_PREFACE: - return "Received bad connection preface"; + case NGHTTP2_ERR_BAD_CLIENT_MAGIC: + return "Received bad clinet magic byte string"; default: return "Unknown error code"; } diff --git a/lib/nghttp2_option.c b/lib/nghttp2_option.c index cf9bae02..a45b5e0e 100644 --- a/lib/nghttp2_option.c +++ b/lib/nghttp2_option.c @@ -47,10 +47,9 @@ void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option, option->peer_max_concurrent_streams = val; } -void nghttp2_option_set_no_recv_client_preface(nghttp2_option *option, - int val) { - option->opt_set_mask |= NGHTTP2_OPT_NO_RECV_CLIENT_PREFACE; - option->no_recv_client_preface = val; +void nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val) { + option->opt_set_mask |= NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC; + option->no_recv_client_magic = val; } void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val) { diff --git a/lib/nghttp2_option.h b/lib/nghttp2_option.h index f35339ab..2e56ff07 100644 --- a/lib/nghttp2_option.h +++ b/lib/nghttp2_option.h @@ -57,7 +57,7 @@ typedef enum { * SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint. */ NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1, - NGHTTP2_OPT_NO_RECV_CLIENT_PREFACE = 1 << 2, + NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2, NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3, } nghttp2_option_flag; @@ -79,9 +79,9 @@ struct nghttp2_option { */ uint8_t no_auto_window_update; /** - * NGHTTP2_OPT_NO_RECV_CLIENT_PREFACE + * NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC */ - uint8_t no_recv_client_preface; + uint8_t no_recv_client_magic; /** * NGHTTP2_OPT_NO_HTTP_MESSAGING */ diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index bbb9aaa3..15d0f02c 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -314,9 +314,9 @@ static void active_outbound_item_reset(nghttp2_active_outbound_item *aob, aob->state = NGHTTP2_OB_POP_ITEM; } -/* This global variable exists for tests where we want to disable this - check. */ -int nghttp2_enable_strict_connection_preface_check = 1; +/* The global variable for tests where we want to disable strict + preface handling. */ +int nghttp2_enable_strict_preface = 1; static int session_new(nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks, @@ -417,10 +417,10 @@ static int session_new(nghttp2_session **session_ptr, option->peer_max_concurrent_streams; } - if ((option->opt_set_mask & NGHTTP2_OPT_NO_RECV_CLIENT_PREFACE) && - option->no_recv_client_preface) { + if ((option->opt_set_mask & NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC) && + option->no_recv_client_magic) { - (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_RECV_CLIENT_PREFACE; + (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC; } if ((option->opt_set_mask & NGHTTP2_OPT_NO_HTTP_MESSAGING) && @@ -435,17 +435,23 @@ static int session_new(nghttp2_session **session_ptr, session_inbound_frame_reset(*session_ptr); - if (nghttp2_enable_strict_connection_preface_check) { + if (nghttp2_enable_strict_preface) { nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe; if (server && - ((*session_ptr)->opt_flags & NGHTTP2_OPTMASK_NO_RECV_CLIENT_PREFACE) == + ((*session_ptr)->opt_flags & NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC) == 0) { - iframe->state = NGHTTP2_IB_READ_CLIENT_PREFACE; - iframe->payloadleft = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN; + iframe->state = NGHTTP2_IB_READ_CLIENT_MAGIC; + iframe->payloadleft = NGHTTP2_CLIENT_MAGIC_LEN; } else { iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS; } + + if (!server) { + (*session_ptr)->aob.state = NGHTTP2_OB_SEND_CLIENT_MAGIC; + nghttp2_bufs_add(&(*session_ptr)->aob.framebufs, NGHTTP2_CLIENT_MAGIC, + NGHTTP2_CLIENT_MAGIC_LEN); + } } return 0; @@ -2979,6 +2985,25 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, break; } + case NGHTTP2_OB_SEND_CLIENT_MAGIC: { + size_t datalen; + nghttp2_buf *buf; + + buf = &framebufs->cur->buf; + + if (buf->pos == buf->last) { + DEBUGF(fprintf(stderr, "send: end transmission of client magic\n")); + active_outbound_item_reset(aob, mem); + break; + } + + *data_ptr = buf->pos; + datalen = nghttp2_buf_len(buf); + + buf->pos += datalen; + + return datalen; + } } } } @@ -2993,14 +3018,16 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session, return len; } - /* We have to call session_after_frame_sent1 here to handle stream - closure upon transmission of frames. Otherwise, END_STREAM may - be reached to client before we call nghttp2_session_mem_send - again and we may get exceeding number of incoming streams. */ - rv = session_after_frame_sent1(session); - if (rv < 0) { - assert(nghttp2_is_fatal(rv)); - return (ssize_t)rv; + if (session->aob.item) { + /* We have to call session_after_frame_sent1 here to handle stream + closure upon transmission of frames. Otherwise, END_STREAM may + be reached to client before we call nghttp2_session_mem_send + again and we may get exceeding number of incoming streams. */ + rv = session_after_frame_sent1(session); + if (rv < 0) { + assert(nghttp2_is_fatal(rv)); + return (ssize_t)rv; + } } return len; @@ -4907,14 +4934,13 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, for (;;) { switch (iframe->state) { - case NGHTTP2_IB_READ_CLIENT_PREFACE: + case NGHTTP2_IB_READ_CLIENT_MAGIC: readlen = nghttp2_min(inlen, iframe->payloadleft); - if (memcmp(NGHTTP2_CLIENT_CONNECTION_PREFACE + - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - + if (memcmp(NGHTTP2_CLIENT_MAGIC + NGHTTP2_CLIENT_MAGIC_LEN - iframe->payloadleft, in, readlen) != 0) { - return NGHTTP2_ERR_BAD_PREFACE; + return NGHTTP2_ERR_BAD_CLIENT_MAGIC; } iframe->payloadleft -= readlen; diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index ea532262..9d14c8ee 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -46,14 +46,15 @@ */ typedef enum { NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0, - NGHTTP2_OPTMASK_NO_RECV_CLIENT_PREFACE = 1 << 1, + NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1, NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2, } nghttp2_optmask; typedef enum { NGHTTP2_OB_POP_ITEM, NGHTTP2_OB_SEND_DATA, - NGHTTP2_OB_SEND_NO_COPY + NGHTTP2_OB_SEND_NO_COPY, + NGHTTP2_OB_SEND_CLIENT_MAGIC } nghttp2_outbound_state; typedef struct { @@ -69,7 +70,7 @@ typedef struct { /* Internal state when receiving incoming frame */ typedef enum { /* Receiving frame header */ - NGHTTP2_IB_READ_CLIENT_PREFACE, + NGHTTP2_IB_READ_CLIENT_MAGIC, NGHTTP2_IB_READ_FIRST_SETTINGS, NGHTTP2_IB_READ_HEAD, NGHTTP2_IB_READ_NBYTE, diff --git a/python/nghttp2.pyx b/python/nghttp2.pyx index 10b12759..c6b9b66c 100644 --- a/python/nghttp2.pyx +++ b/python/nghttp2.pyx @@ -1477,8 +1477,6 @@ if asyncio: cnghttp2.NGHTTP2_PROTO_VERSION_ID: self.transport.abort() - # Send preamble - self.transport.write(cnghttp2.NGHTTP2_CLIENT_CONNECTION_PREFACE) self.http2 = _HTTP2ClientSessionCore(self.transport) # Clear pending requests diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 1aa2aea7..b9bb557f 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -431,7 +431,7 @@ int Http2Handler::read_clear() { rv = nghttp2_session_mem_recv(session_, buf.data(), nread); if (rv < 0) { - if (rv != NGHTTP2_ERR_BAD_PREFACE) { + if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) { std::cerr << "nghttp2_session_mem_recv() returned error: " << nghttp2_strerror(rv) << std::endl; } @@ -558,7 +558,7 @@ int Http2Handler::read_tls() { rv = nghttp2_session_mem_recv(session_, buf.data(), nread); if (rv < 0) { - if (rv != NGHTTP2_ERR_BAD_PREFACE) { + if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) { std::cerr << "nghttp2_session_mem_recv() returned error: " << nghttp2_strerror(rv) << std::endl; } diff --git a/src/asio_client_session_impl.cc b/src/asio_client_session_impl.cc index 844b1957..e705105d 100644 --- a/src/asio_client_session_impl.cc +++ b/src/asio_client_session_impl.cc @@ -75,10 +75,6 @@ void session_impl::connected(tcp::resolver::iterator endpoint_it) { socket().set_option(boost::asio::ip::tcp::no_delay(true)); - std::copy_n(NGHTTP2_CLIENT_CONNECTION_PREFACE, - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN, std::begin(wb_)); - wblen_ = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN; - do_write(); do_read(); diff --git a/src/h2load_http2_session.cc b/src/h2load_http2_session.cc index bc658380..0f0ef0f6 100644 --- a/src/h2load_http2_session.cc +++ b/src/h2load_http2_session.cc @@ -202,12 +202,6 @@ void Http2Session::on_connect() { extra_connection_window); } - auto &wb = client_->wb; - assert(wb.wleft() >= NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN); - - wb.write(NGHTTP2_CLIENT_CONNECTION_PREFACE, - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN); - client_->signal_write(); } diff --git a/src/nghttp.cc b/src/nghttp.cc index fa57a99e..34f84820 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -962,9 +962,6 @@ int HttpClient::connection_made() { request_done(stream_user_data); } } - // Send connection header here - wb.write(NGHTTP2_CLIENT_CONNECTION_PREFACE, - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN); // If upgrade succeeds, the SETTINGS value sent with // HTTP2-Settings header field has already been submitted to // session object. diff --git a/src/shrpx.cc b/src/shrpx.cc index 4b64ce39..8904ce13 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -904,7 +904,7 @@ void fill_default_config() { nghttp2_option_new(&mod_config()->http2_option); nghttp2_option_set_no_auto_window_update(get_config()->http2_option, 1); - nghttp2_option_set_no_recv_client_preface(get_config()->http2_option, 1); + nghttp2_option_set_no_recv_client_magic(get_config()->http2_option, 1); nghttp2_option_new(&mod_config()->http2_client_option); nghttp2_option_set_no_auto_window_update(get_config()->http2_client_option, diff --git a/src/shrpx_client_handler.cc b/src/shrpx_client_handler.cc index c8065bb4..58d9eb74 100644 --- a/src/shrpx_client_handler.cc +++ b/src/shrpx_client_handler.cc @@ -279,8 +279,7 @@ int ClientHandler::upstream_write() { int ClientHandler::upstream_http2_connhd_read() { auto nread = std::min(left_connhd_len_, rb_.rleft()); - if (memcmp(NGHTTP2_CLIENT_CONNECTION_PREFACE + - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - left_connhd_len_, + if (memcmp(NGHTTP2_CLIENT_MAGIC + NGHTTP2_CLIENT_MAGIC_LEN - left_connhd_len_, rb_.pos, nread) != 0) { // There is no downgrade path here. Just drop the connection. if (LOG_ENABLED(INFO)) { @@ -309,8 +308,7 @@ int ClientHandler::upstream_http2_connhd_read() { int ClientHandler::upstream_http1_connhd_read() { auto nread = std::min(left_connhd_len_, rb_.rleft()); - if (memcmp(NGHTTP2_CLIENT_CONNECTION_PREFACE + - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - left_connhd_len_, + if (memcmp(NGHTTP2_CLIENT_MAGIC + NGHTTP2_CLIENT_MAGIC_LEN - left_connhd_len_, rb_.pos, nread) != 0) { if (LOG_ENABLED(INFO)) { CLOG(INFO, this) << "This is HTTP/1.1 connection, " @@ -318,7 +316,7 @@ int ClientHandler::upstream_http1_connhd_read() { } // Reset header length for later HTTP/2 upgrade - left_connhd_len_ = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN; + left_connhd_len_ = NGHTTP2_CLIENT_MAGIC_LEN; on_read_ = &ClientHandler::upstream_read; on_write_ = &ClientHandler::upstream_write; @@ -362,7 +360,7 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl, get_config()->read_burst, writecb, readcb, timeoutcb, this), ipaddr_(ipaddr), port_(port), worker_(worker), http2session_(worker_->next_http2_session()), - left_connhd_len_(NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN), + left_connhd_len_(NGHTTP2_CLIENT_MAGIC_LEN), should_close_after_write_(false) { ++worker_->get_worker_stat()->num_connections; diff --git a/src/shrpx_http2_session.cc b/src/shrpx_http2_session.cc index a73c91c5..5fc5f7e3 100644 --- a/src/shrpx_http2_session.cc +++ b/src/shrpx_http2_session.cc @@ -1278,13 +1278,6 @@ int Http2Session::connection_made() { } } - auto nwrite = wb_.write(NGHTTP2_CLIENT_CONNECTION_PREFACE, - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN); - if (nwrite != NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN) { - SSLOG(FATAL, this) << "buffer is too small to send connection preface"; - return -1; - } - auto must_terminate = !get_config()->downstream_no_tls && !ssl::check_http2_requirement(conn_.tls.ssl); diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 64af8afa..121db248 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -769,7 +769,7 @@ int Http2Upstream::on_read() { if (rb->rleft()) { rv = nghttp2_session_mem_recv(session_, rb->pos, rb->rleft()); if (rv < 0) { - if (rv != NGHTTP2_ERR_BAD_PREFACE) { + if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) { ULOG(ERROR, this) << "nghttp2_session_recv() returned error: " << nghttp2_strerror(rv); } diff --git a/tests/main.c b/tests/main.c index 9b9e8e63..396c0081 100644 --- a/tests/main.c +++ b/tests/main.c @@ -41,7 +41,7 @@ #include "nghttp2_helper_test.h" #include "nghttp2_buf_test.h" -extern int nghttp2_enable_strict_connection_preface_check; +extern int nghttp2_enable_strict_preface; static int init_suite1(void) { return 0; } @@ -51,7 +51,7 @@ int main(int argc _U_, char *argv[] _U_) { CU_pSuite pSuite = NULL; unsigned int num_tests_failed; - nghttp2_enable_strict_connection_preface_check = 0; + nghttp2_enable_strict_preface = 0; /* initialize the CUnit test registry */ if (CUE_SUCCESS != CU_initialize_registry()) @@ -250,8 +250,8 @@ int main(int argc _U_, char *argv[] _U_) { test_nghttp2_session_graceful_shutdown) || !CU_add_test(pSuite, "session_on_header_temporal_failure", test_nghttp2_session_on_header_temporal_failure) || - !CU_add_test(pSuite, "session_recv_client_preface", - test_nghttp2_session_recv_client_preface) || + !CU_add_test(pSuite, "session_recv_client_magic", + test_nghttp2_session_recv_client_magic) || !CU_add_test(pSuite, "session_delete_data_item", test_nghttp2_session_delete_data_item) || !CU_add_test(pSuite, "session_open_idle_stream", diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 4e77019b..8721eeae 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -36,7 +36,7 @@ #include "nghttp2_test_helper.h" #include "nghttp2_priority_spec.h" -extern int nghttp2_enable_strict_connection_preface_check; +extern int nghttp2_enable_strict_preface; #define OB_CTRL(ITEM) nghttp2_outbound_item_get_ctrl_frame(ITEM) #define OB_CTRL_TYPE(ITEM) nghttp2_outbound_item_get_ctrl_frame_type(ITEM) @@ -6722,27 +6722,25 @@ void test_nghttp2_session_on_header_temporal_failure(void) { nghttp2_session_del(session); } -void test_nghttp2_session_recv_client_preface(void) { +void test_nghttp2_session_recv_client_magic(void) { nghttp2_session *session; nghttp2_session_callbacks callbacks; ssize_t rv; nghttp2_frame ping_frame; uint8_t buf[16]; - /* enable global nghttp2_enable_strict_connection_preface_check - here */ - nghttp2_enable_strict_connection_preface_check = 1; + /* enable global nghttp2_enable_strict_preface here */ + nghttp2_enable_strict_preface = 1; memset(&callbacks, 0, sizeof(callbacks)); /* Check success case */ nghttp2_session_server_new(&session, &callbacks, NULL); - rv = nghttp2_session_mem_recv( - session, (const uint8_t *)NGHTTP2_CLIENT_CONNECTION_PREFACE, - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN); + rv = nghttp2_session_mem_recv(session, (const uint8_t *)NGHTTP2_CLIENT_MAGIC, + NGHTTP2_CLIENT_MAGIC_LEN); - CU_ASSERT(rv == NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN); + CU_ASSERT(rv == NGHTTP2_CLIENT_MAGIC_LEN); CU_ASSERT(NGHTTP2_IB_READ_FIRST_SETTINGS == session->iframe.state); /* Receiving PING is error because we want SETTINGS. */ @@ -6762,24 +6760,22 @@ void test_nghttp2_session_recv_client_preface(void) { /* Check bad case */ nghttp2_session_server_new(&session, &callbacks, NULL); - /* Feed preface with one byte less */ - rv = nghttp2_session_mem_recv( - session, (const uint8_t *)NGHTTP2_CLIENT_CONNECTION_PREFACE, - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - 1); + /* Feed magic with one byte less */ + rv = nghttp2_session_mem_recv(session, (const uint8_t *)NGHTTP2_CLIENT_MAGIC, + NGHTTP2_CLIENT_MAGIC_LEN - 1); - CU_ASSERT(rv == NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - 1); - CU_ASSERT(NGHTTP2_IB_READ_CLIENT_PREFACE == session->iframe.state); + CU_ASSERT(rv == NGHTTP2_CLIENT_MAGIC_LEN - 1); + CU_ASSERT(NGHTTP2_IB_READ_CLIENT_MAGIC == session->iframe.state); CU_ASSERT(1 == session->iframe.payloadleft); rv = nghttp2_session_mem_recv(session, (const uint8_t *)"\0", 1); - CU_ASSERT(NGHTTP2_ERR_BAD_PREFACE == rv); + CU_ASSERT(NGHTTP2_ERR_BAD_CLIENT_MAGIC == rv); nghttp2_session_del(session); - /* disable global nghttp2_enable_strict_connection_preface_check - here */ - nghttp2_enable_strict_connection_preface_check = 0; + /* disable global nghttp2_enable_strict_preface here */ + nghttp2_enable_strict_preface = 0; } void test_nghttp2_session_delete_data_item(void) { diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index b6fe967d..406cfb78 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -118,7 +118,7 @@ void test_nghttp2_session_detach_idle_stream(void); void test_nghttp2_session_large_dep_tree(void); void test_nghttp2_session_graceful_shutdown(void); void test_nghttp2_session_on_header_temporal_failure(void); -void test_nghttp2_session_recv_client_preface(void); +void test_nghttp2_session_recv_client_magic(void); void test_nghttp2_session_delete_data_item(void); void test_nghttp2_session_open_idle_stream(void); void test_nghttp2_session_cancel_reserved_remote(void); From 87602e5d7296b37ed3f2864db1965d139657aba6 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 5 Apr 2015 22:46:05 +0900 Subject: [PATCH 05/14] Use NGHTTP2_PROTOCOL_ERROR for NGHTTP2_ERR_HTTP_{HEADER,MESSAGING} --- lib/nghttp2_session.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 15d0f02c..cae5c614 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -3170,6 +3170,8 @@ static int get_error_code_from_lib_error_code(int lib_error_code) { case NGHTTP2_ERR_REFUSED_STREAM: return NGHTTP2_REFUSED_STREAM; case NGHTTP2_ERR_PROTO: + case NGHTTP2_ERR_HTTP_HEADER: + case NGHTTP2_ERR_HTTP_MESSAGING: return NGHTTP2_PROTOCOL_ERROR; default: return NGHTTP2_INTERNAL_ERROR; From 3e50ef439d914dbf6c611fc4afc8925c9e79d6c7 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 5 Apr 2015 23:00:59 +0900 Subject: [PATCH 06/14] Announce h2, final HTTP/2 ALPN identifier --- lib/includes/nghttp2/nghttp2.h | 10 +++++----- src/shrpx.cc | 2 +- src/shrpx_client_handler.cc | 4 +--- src/util.cc | 18 +++++++++--------- src/util.h | 8 ++++---- src/util_test.cc | 7 ++++--- tests/nghttp2_npn_test.c | 5 ++--- 7 files changed, 26 insertions(+), 28 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 969726f4..c1a725cb 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -55,13 +55,13 @@ extern "C" { * The protocol version identification string of this library * supports. This identifier is used if HTTP/2 is used over TLS. */ -#define NGHTTP2_PROTO_VERSION_ID "h2-14" +#define NGHTTP2_PROTO_VERSION_ID "h2" /** * @macro * * The length of :macro:`NGHTTP2_PROTO_VERSION_ID`. */ -#define NGHTTP2_PROTO_VERSION_ID_LEN 5 +#define NGHTTP2_PROTO_VERSION_ID_LEN 2 /** * @macro @@ -72,7 +72,7 @@ extern "C" { * extension `_. This is useful * to process incoming ALPN tokens in wire format. */ -#define NGHTTP2_PROTO_ALPN "\x5h2-14" +#define NGHTTP2_PROTO_ALPN "\x2h2" /** * @macro @@ -88,14 +88,14 @@ extern "C" { * supports. This identifier is used if HTTP/2 is used over cleartext * TCP. */ -#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "h2c-14" +#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "h2c" /** * @macro * * The length of :macro:`NGHTTP2_CLEARTEXT_PROTO_VERSION_ID`. */ -#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN 6 +#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN 3 struct nghttp2_session; /** diff --git a/src/shrpx.cc b/src/shrpx.cc index 8904ce13..7e1ff06e 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -769,7 +769,7 @@ bool conf_exists(const char *path) { } // namespace namespace { -const char *DEFAULT_NPN_LIST = "h2,h2-16," NGHTTP2_PROTO_VERSION_ID "," +const char *DEFAULT_NPN_LIST = "h2,h2-16,h2-14," #ifdef HAVE_SPDYLAY "spdy/3.1," #endif // HAVE_SPDYLAY diff --git a/src/shrpx_client_handler.cc b/src/shrpx_client_handler.cc index 58d9eb74..4554f428 100644 --- a/src/shrpx_client_handler.cc +++ b/src/shrpx_client_handler.cc @@ -454,9 +454,7 @@ int ClientHandler::validate_next_proto() { next_proto_len)) { break; } - if (util::check_h2_is_selected(next_proto, next_proto_len) || - (next_proto_len == sizeof("h2-16") - 1 && - memcmp("h2-16", next_proto, next_proto_len) == 0)) { + if (util::check_h2_is_selected(next_proto, next_proto_len)) { on_read_ = &ClientHandler::upstream_http2_connhd_read; diff --git a/src/util.cc b/src/util.cc index d08d8b5b..9c59f92e 100644 --- a/src/util.cc +++ b/src/util.cc @@ -763,9 +763,9 @@ int64_t to_time64(const timeval &tv) { } bool check_h2_is_selected(const unsigned char *proto, size_t len) { - return streq_l(NGHTTP2_H2, proto, len) || + return streq_l(NGHTTP2_PROTO_VERSION_ID, proto, len) || streq_l(NGHTTP2_H2_16, proto, len) || - streq_l(NGHTTP2_PROTO_VERSION_ID, proto, len); + streq_l(NGHTTP2_H2_14, proto, len); } namespace { @@ -785,23 +785,23 @@ bool select_h2(const unsigned char **out, unsigned char *outlen, bool select_h2(const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen) { - return select_h2(out, outlen, in, inlen, NGHTTP2_H2_ALPN, - str_size(NGHTTP2_H2_ALPN)) || + return select_h2(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN, + str_size(NGHTTP2_PROTO_ALPN)) || select_h2(out, outlen, in, inlen, NGHTTP2_H2_16_ALPN, str_size(NGHTTP2_H2_16_ALPN)) || - select_h2(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN, - str_size(NGHTTP2_PROTO_ALPN)); + select_h2(out, outlen, in, inlen, NGHTTP2_H2_14_ALPN, + str_size(NGHTTP2_H2_14_ALPN)); } std::vector get_default_alpn() { auto res = std::vector(str_size(NGHTTP2_PROTO_ALPN) + str_size(NGHTTP2_H2_16_ALPN) + - str_size(NGHTTP2_H2_ALPN)); + str_size(NGHTTP2_H2_14_ALPN)); auto p = std::begin(res); - p = std::copy_n(NGHTTP2_H2_ALPN, str_size(NGHTTP2_H2_ALPN), p); - p = std::copy_n(NGHTTP2_H2_16_ALPN, str_size(NGHTTP2_H2_16_ALPN), p); p = std::copy_n(NGHTTP2_PROTO_ALPN, str_size(NGHTTP2_PROTO_ALPN), p); + p = std::copy_n(NGHTTP2_H2_16_ALPN, str_size(NGHTTP2_H2_16_ALPN), p); + p = std::copy_n(NGHTTP2_H2_14_ALPN, str_size(NGHTTP2_H2_14_ALPN), p); return res; } diff --git a/src/util.h b/src/util.h index f20624d5..06861f6c 100644 --- a/src/util.h +++ b/src/util.h @@ -46,13 +46,13 @@ namespace nghttp2 { // The additional HTTP/2 protocol ALPN protocol identifier we also -// supports for our applications. This will be removed once HTTP/2 -// specification is finalized. +// supports for our applications to make smooth migration into final +// h2 ALPN ID. #define NGHTTP2_H2_16_ALPN "\x5h2-16" #define NGHTTP2_H2_16 "h2-16" -#define NGHTTP2_H2_ALPN "\x2h2" -#define NGHTTP2_H2 "h2" +#define NGHTTP2_H2_14_ALPN "\x5h2-14" +#define NGHTTP2_H2_14 "h2-14" namespace util { diff --git a/src/util_test.cc b/src/util_test.cc index 21d992d8..c1100b76 100644 --- a/src/util_test.cc +++ b/src/util_test.cc @@ -184,7 +184,7 @@ void test_util_select_h2(void) { unsigned char outlen = 0; // Check single entry and select it. - const unsigned char t1[] = "\x5h2-14"; + const unsigned char t1[] = "\x2h2"; CU_ASSERT(util::select_h2(&out, &outlen, t1, sizeof(t1) - 1)); CU_ASSERT( memcmp(NGHTTP2_PROTO_VERSION_ID, out, NGHTTP2_PROTO_VERSION_ID_LEN) == 0); @@ -198,9 +198,10 @@ void test_util_select_h2(void) { const unsigned char t2[] = "\x6h2-14"; CU_ASSERT(!util::select_h2(&out, &outlen, t2, sizeof(t2) - 1)); - // Check the case where h2-14 is located after bogus ID. - const unsigned char t3[] = "\x2h3\x5h2-14"; + // Check the case where h2 is located after bogus ID. + const unsigned char t3[] = "\x2h3\x2h2"; CU_ASSERT(util::select_h2(&out, &outlen, t3, sizeof(t3) - 1)); + CU_ASSERT( memcmp(NGHTTP2_PROTO_VERSION_ID, out, NGHTTP2_PROTO_VERSION_ID_LEN) == 0); CU_ASSERT(NGHTTP2_PROTO_VERSION_ID_LEN == outlen); diff --git a/tests/nghttp2_npn_test.c b/tests/nghttp2_npn_test.c index bae6082b..cbd65b71 100644 --- a/tests/nghttp2_npn_test.c +++ b/tests/nghttp2_npn_test.c @@ -30,9 +30,8 @@ #include static void http2(void) { - const unsigned char p[] = {8, 'h', 't', 't', 'p', '/', '1', '.', - '1', 5, 'h', '2', '-', '1', '4', 6, - 's', 'p', 'd', 'y', '/', '3'}; + const unsigned char p[] = {8, 'h', 't', 't', 'p', '/', '1', '.', '1', 2, + 'h', '2', 6, 's', 'p', 'd', 'y', '/', '3'}; unsigned char outlen; unsigned char *out; CU_ASSERT(1 == nghttp2_select_next_protocol(&out, &outlen, p, sizeof(p))); From 24897aa50decdde2bf360f5805bc2cfb722f4cc8 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 5 Apr 2015 23:07:42 +0900 Subject: [PATCH 07/14] Update README.rst --- README.rst | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/README.rst b/README.rst index 3dee09b4..4d39dd2a 100644 --- a/README.rst +++ b/README.rst @@ -19,20 +19,16 @@ code coverage yet. Development Status ------------------ -We started to implement h2-14 -(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), and header -compression -(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09). +We have implemented final HTTP/2 protocol specification. The RFC is +not published yet, so we use draft-17 specification for HTTP/2 +(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), and draft-11 +for header compression (aka HPACK) +(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-11). +These documents have been approved by IETF and no technical changes +are made before RFC publication. -The nghttp2 code base was forked from the spdylay project. - -=========================== ======= -HTTP/2 Features Support -=========================== ======= -Core frames handling Yes -Dependency Tree Yes -Large header (CONTINUATION) Yes -=========================== ======= +The nghttp2 code base was forked from the spdylay +(https://github.com/tatsuhiro-t/spdylay) project. Public Test Server ------------------ @@ -46,9 +42,9 @@ implementation. and ``http/1.1`` via ALPN/NPN and requires TLSv1.2 for HTTP/2 connection. -* http://nghttp2.org/ (Upgrade / Direct) +* http://nghttp2.org/ (HTTP Upgrade and HTTP/2 Direct) - ``h2c-14`` and ``http/1.1``. + ``h2c`` and ``http/1.1``. Requirements ------------ @@ -228,10 +224,10 @@ output from ``nghttp`` client:: $ nghttp -nv https://nghttp2.org [ 0.033][NPN] server offers: - * h2-14 + * h2 * spdy/3.1 * http/1.1 - The negotiated protocol: h2-14 + The negotiated protocol: h2 [ 0.068] send SETTINGS frame (niv=3) [SETTINGS_MAX_CONCURRENT_STREAMS(3):100] @@ -458,8 +454,9 @@ information. Here is sample output from ``nghttpd``:: nghttpx - proxy +++++++++++++++ -``nghttpx`` is a multi-threaded reverse proxy for ``h2-14``, SPDY and -HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server push. +``nghttpx`` is a multi-threaded reverse proxy for HTTP/2, SPDY and +HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server +push. ``nghttpx`` implements `important performance-oriented features `_ in TLS, such as @@ -480,8 +477,8 @@ default mode HTTP/2, SPDY, HTTP/1.1 (TLS) HTTP/1.1 Reverse proxy ================== ============================ ============== ============= The interesting mode at the moment is the default mode. It works like -a reverse proxy and listens for ``h2-14``, SPDY and HTTP/1.1 and can -be deployed as a SSL/TLS terminator for existing web server. +a reverse proxy and listens for HTTP/2, SPDY and HTTP/1.1 and can be +deployed as a SSL/TLS terminator for existing web server. The default mode, ``--http2-proxy`` and ``--http2-bridge`` modes use SSL/TLS in the frontend connection by default. To disable SSL/TLS, From 084e4487edee1a0cd9c503a074519888ab347af4 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 5 Apr 2015 23:53:19 +0900 Subject: [PATCH 08/14] Add migration section --- README.rst | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/README.rst b/README.rst index 4d39dd2a..4d45fff5 100644 --- a/README.rst +++ b/README.rst @@ -208,6 +208,104 @@ To run the tests, run the following command under Inside the tests, we use port 3009 to run the test subject server. +Migration from v0.7.9 or earlier +-------------------------------- + +nghttp2 v1.0.0 introduced several backward incompatible changes. In +this section, we describe these changes and how to migrate to v1.0.0. + +ALPN protocol ID is now ``h2`` and ``h2c`` +++++++++++++++++++++++++++++++++++++++++++ + +Previously we announced ``h2-14`` and ``h2c-14``. v1.0.0 implements +final protocol version, and we changed ALPN ID to ``h2`` and ``h2c``. +The macros ``NGHTTP2_PROTO_VERSION_ID``, +``NGHTTP2_PROTO_VERSION_ID_LEN``, +``NGHTTP2_CLEARTEXT_PROTO_VERSION_ID``, and +``NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN`` have been updated to +reflect this change. + +Basically, existing applications do not have to do anything, just +recompiling is enough for this change. + +Use word "client magic" where we use "client connection preface" +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +We use "client connection preface" to mean first 24 bytes of client +connection preface. This is technically not correct, since client +connection preface is composed of 24 bytes client magic byte string +followed by SETTINGS frame. For clarification, we call "client magic" +for this 24 bytes byte string and updated API. + +* ``NGHTTP2_CLIENT_CONNECTION_PREFACE`` was replaced with + ``NGHTTP2_CLIENT_MAGIC``. +* ``NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN`` was replaced with + ``NGHTTP2_CLIENT_MAGIC_LEN``. +* ``NGHTTP2_BAD_PREFACE`` was renamed as ``NGHTTP2_BAD_CLIENT_MAGIC`` + +The alreay deprecated ``NGHTTP2_CLIENT_CONNECTION_HEADER`` and +``NGHTTP2_CLIENT_CONNECTION_HEADER_LEN`` were removed. + +If application uses these macros, just replace old ones with new ones. +Since v1.0.0, client magic is sent by library (see next subsection), +so client application may just remove these macro use. + +Client magic is sent by library ++++++++++++++++++++++++++++++++ + +Previously nghttp2 library did not send client magic, which is first +24 bytes byte string of client connection preface, and client +applications have to send it by themselves. Since v1.0.0, client +magic is sent by library via first call of ``nghttp2_session_send()`` +or ``nghttp2_session_mem_send()``. + +The client applications which send client magic must remove the +relevant code. + +Remove HTTP Alternative Services (Alt-Svc) related code ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Alt-Svc specification is not finalized yet. To make our API stable, +we have decided to remove all Alt-Svc related API from nghttp2. + +* ``NGHTTP2_EXT_ALTSVC`` was removed. +* ``nghttp2_ext_altsvc`` was removed. + +We have already removed the functionality of Alt-Svc in v0.7 series +and they have been essentially noop. The application using these +macro and struct, remove those lines. + +Use nghttp2_error in nghttp2_on_invalid_frame_recv_callback ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Previously ``nghttp2_on_invalid_frame_recv_cb_called`` took the +``error_code``, defined in ``nghttp2_error_code``, as parameter. But +they are not detailed enough to debug. Therefore, we decided to use +more detailed ``nghttp2_error`` values instead. + +The application using this callback should update the callback +signature. If it treats ``error_code`` as HTTP/2 error code, update +the code so that it is treated as ``nghttp2_error``. + +Receive client magic by default ++++++++++++++++++++++++++++++++ + +Previously nghttp2 did not process client magic (24 bytes byte +string). To make it deal with it, we had to use +``nghttp2_option_set_recv_client_preface()``. Since v1.0.0, nghttp2 +processes client magic by default and +``nghttp2_option_set_recv_client_preface()`` was removed. + +Some application may want to disable this behaviour, so we added +``nghttp2_option_set_no_recv_client_magic()`` to achieve this. + +The application using ``nghttp2_option_set_recv_client_preface()`` +with nonzero value, just remove it. + +The application using ``nghttp2_option_set_recv_client_preface()`` +with zero value or not using it must use +``nghttp2_option_set_no_recv_client_magic()`` with nonzero value. + Client, Server and Proxy programs --------------------------------- From 59e3783f3f34cf8663b51fd98fdae14993aa1cb8 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 7 Apr 2015 00:19:57 +0900 Subject: [PATCH 09/14] Update manual entry --- doc/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index daeea105..265e1683 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -49,7 +49,7 @@ APIDOCS= \ nghttp2_option_set_no_auto_window_update.rst \ nghttp2_option_set_no_http_messaging.rst \ nghttp2_option_set_peer_max_concurrent_streams.rst \ - nghttp2_option_set_recv_client_preface.rst \ + nghttp2_option_set_no_recv_client_magic.rst \ nghttp2_pack_settings_payload.rst \ nghttp2_priority_spec_check_default.rst \ nghttp2_priority_spec_default_init.rst \ From 90bfea77e098d54429445ee8cf8eee6854ccc767 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Wed, 8 Apr 2015 18:12:54 +0900 Subject: [PATCH 10/14] doc: Remove nghttp2_submit_altsvc.rst --- doc/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index 1849badb..62008819 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -108,7 +108,6 @@ APIDOCS= \ nghttp2_session_want_read.rst \ nghttp2_session_want_write.rst \ nghttp2_strerror.rst \ - nghttp2_submit_altsvc.rst \ nghttp2_submit_data.rst \ nghttp2_submit_goaway.rst \ nghttp2_submit_headers.rst \ From 1c4df1832b179802052b9785001381855e03981c Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 28 Apr 2015 23:05:00 +0900 Subject: [PATCH 11/14] Update doc, mainly for RFC numbers --- README.rst | 10 +++------ lib/includes/nghttp2/nghttp2.h | 28 ++++++++++++------------- src/shrpx_client_handler.cc | 2 -- src/shrpx_http_downstream_connection.cc | 2 +- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/README.rst b/README.rst index 4d45fff5..7ff2dde1 100644 --- a/README.rst +++ b/README.rst @@ -19,13 +19,9 @@ code coverage yet. Development Status ------------------ -We have implemented final HTTP/2 protocol specification. The RFC is -not published yet, so we use draft-17 specification for HTTP/2 -(http://tools.ietf.org/html/draft-ietf-httpbis-http2-14), and draft-11 -for header compression (aka HPACK) -(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-11). -These documents have been approved by IETF and no technical changes -are made before RFC publication. +We have implemented `RFC 7540 `_ +HTTP/2 and ``RFC 7541 `_ HPACK - +Header Compression for HTTP/2 The nghttp2 code base was forked from the spdylay (https://github.com/tatsuhiro-t/spdylay) project. diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 4d6ad0ef..490f81fa 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -2001,10 +2001,10 @@ nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val); * * By default, nghttp2 library enforces subset of HTTP Messaging rules * described in `HTTP/2 specification, section 8 - * `_. - * See :ref:`http-messaging` section for details. For those - * applications who use nghttp2 library as non-HTTP use, give nonzero - * to |val| to disable this enforcement. + * `_. See + * :ref:`http-messaging` section for details. For those applications + * who use nghttp2 library as non-HTTP use, give nonzero to |val| to + * disable this enforcement. */ NGHTTP2_EXTERN void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val); @@ -3452,14 +3452,14 @@ NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs, * A helper function for dealing with NPN in client side or ALPN in * server side. The |in| contains peer's protocol list in preferable * order. The format of |in| is length-prefixed and not - * null-terminated. For example, ``HTTP-draft-04/2.0`` and + * null-terminated. For example, ``h2`` and * ``http/1.1`` stored in |in| like this:: * - * in[0] = 17 - * in[1..17] = "HTTP-draft-04/2.0" - * in[18] = 8 - * in[19..26] = "http/1.1" - * inlen = 27 + * in[0] = 2 + * in[1..2] = "h2" + * in[3] = 8 + * in[4..11] = "http/1.1" + * inlen = 12 * * The selection algorithm is as follows: * @@ -3473,12 +3473,10 @@ NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs, * non-overlap case). In this case, |out| and |outlen| are left * untouched. * - * Selecting ``HTTP-draft-04/2.0`` means that ``HTTP-draft-04/2.0`` is - * written into |*out| and its length (which is 17) is assigned to - * |*outlen|. + * Selecting ``h2`` means that ``h2`` is written into |*out| and its + * length (which is 2) is assigned to |*outlen|. * - * For ALPN, refer to - * https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-05 + * For ALPN, refer to https://tools.ietf.org/html/rfc7301 * * See http://technotes.googlecode.com/git/nextprotoneg.html for more * details about NPN. diff --git a/src/shrpx_client_handler.cc b/src/shrpx_client_handler.cc index 53f8ce82..886ac722 100644 --- a/src/shrpx_client_handler.cc +++ b/src/shrpx_client_handler.cc @@ -644,8 +644,6 @@ ConnectBlocker *ClientHandler::get_connect_blocker() const { void ClientHandler::direct_http2_upgrade() { upstream_ = make_unique(this); - // TODO We don't know exact h2 draft version in direct upgrade. We - // just use library default for now. alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID; on_read_ = &ClientHandler::upstream_read; } diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index 329fdce5..72ab410e 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -567,7 +567,7 @@ int htp_hdrs_completecb(http_parser *htp) { // Content-Length or Transfer-Encoding: chunked. Some server send // 304 status code with nonzero Content-Length, but without response // body. See - // http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-20#section-3.3 + // https://tools.ietf.org/html/rfc7230#section-3.3 // TODO It seems that the cases other than HEAD are handled by // http-parser. Need test. From de4735092a2970f9f5d93de617dc0faf2db9952d Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 28 Apr 2015 23:06:48 +0900 Subject: [PATCH 12/14] Fix doc formatting --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 7ff2dde1..11deca99 100644 --- a/README.rst +++ b/README.rst @@ -20,7 +20,7 @@ Development Status ------------------ We have implemented `RFC 7540 `_ -HTTP/2 and ``RFC 7541 `_ HPACK - +HTTP/2 and `RFC 7541 `_ HPACK - Header Compression for HTTP/2 The nghttp2 code base was forked from the spdylay From 64b1aae56748c7b6816409aee649817ee56aa1e8 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 8 May 2015 19:35:09 +0900 Subject: [PATCH 13/14] integration: Fix TestH2H1Upgrade test failure --- integration-tests/nghttpx_http2_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/nghttpx_http2_test.go b/integration-tests/nghttpx_http2_test.go index 0a3115f3..953e9d42 100644 --- a/integration-tests/nghttpx_http2_test.go +++ b/integration-tests/nghttpx_http2_test.go @@ -607,7 +607,7 @@ func TestH2H1Upgrade(t *testing.T) { name: "TestH2H1Upgrade", header: []hpack.HeaderField{ pair("Connection", "Upgrade, HTTP2-Settings"), - pair("Upgrade", "h2c-14"), + pair("Upgrade", "h2c"), pair("HTTP2-Settings", "AAMAAABkAAQAAP__"), }, }) From a869c39a2c2c7ec0db4e8db477b2dfed5f3eaa0f Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 15 May 2015 23:30:24 +0900 Subject: [PATCH 14/14] Bump up version number to 1.0.0-DEV --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index ce1d551f..4067178d 100644 --- a/configure.ac +++ b/configure.ac @@ -25,7 +25,7 @@ dnl Do not change user variables! dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html AC_PREREQ(2.61) -AC_INIT([nghttp2], [0.7.15], [t-tujikawa@users.sourceforge.net]) +AC_INIT([nghttp2], [1.0.0-DEV], [t-tujikawa@users.sourceforge.net]) AC_USE_SYSTEM_EXTENSIONS LT_PREREQ([2.2.6])