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.
This commit is contained in:
Tatsuhiro Tsujikawa 2015-04-05 22:35:40 +09:00
parent ebf214c8fc
commit d0c27d5229
23 changed files with 129 additions and 173 deletions

View File

@ -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 crash. You can submit requests or frames in the callbacks then call
these functions outside the callbacks. these functions outside the callbacks.
Currently, `nghttp2_session_send()` and `nghttp2_session_mem_send()` `nghttp2_session_send()` and `nghttp2_session_mem_send()` send first
do not send client connection preface 24 bytes of client magic string (MAGIC)
(:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`). The applications are (:macro:`NGHTTP2_CLIENT_MAGIC`) on client configuration. The
responsible to send it before sending any HTTP/2 frames using these applications are responsible to send SETTINGS frame as part of
functions if :type:`nghttp2_session` is configured as client. connection preface using `nghttp2_submit_settings()`. Similarly,
Similarly, `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` consume
do not consume client connection preface unless MAGIC on server configuration unless
`nghttp2_option_set_recv_client_preface()` is used with nonzero option `nghttp2_option_set_no_recv_client_magic()` is used with nonzero
value. The applications are responsible to receive it before calling option value.
these functions if :type:`nghttp2_session` is configured as server and
`nghttp2_option_set_recv_client_preface()` is not used.
.. _http-messaging: .. _http-messaging:

View File

@ -184,9 +184,9 @@ its bufferevent, so it closes underlying connection as well. It also
calls `nghttp2_session_del()` to delete nghttp2 session object. calls `nghttp2_session_del()` to delete nghttp2 session object.
We begin HTTP/2 communication by sending client connection preface, We begin HTTP/2 communication by sending client connection preface,
which is 24 bytes magic byte sequence which is 24 bytes magic byte string (:macro:`NGHTTP2_CLIENT_MAGIC`)
(:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`) and SETTINGS frame. The followed by SETTINGS frame. First 24 bytes magic string is
transmission of client connection header is done in automatically sent by nghttp2 library. We send SETTINGS frame in
``send_client_connection_header()``:: ``send_client_connection_header()``::
static void send_client_connection_header(http2_session_data *session_data) { 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}}; {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv; int rv;
bufferevent_write(session_data->bev, NGHTTP2_CLIENT_CONNECTION_PREFACE, /* client 24 bytes magic string will be sent by nghttp2 library */
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv, rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
ARRLEN(iv)); ARRLEN(iv));
if (rv != 0) { if (rv != 0) {

View File

@ -194,15 +194,8 @@ We initialize a nghttp2 session object which is done in
``initialize_nghttp2_session()``:: ``initialize_nghttp2_session()``::
static void initialize_nghttp2_session(http2_session_data *session_data) { static void initialize_nghttp2_session(http2_session_data *session_data) {
nghttp2_option *option;
nghttp2_session_callbacks *callbacks; 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_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); 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( nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback); callbacks, on_begin_headers_callback);
nghttp2_session_server_new2(&session_data->session, callbacks, session_data, nghttp2_session_server_new(&session_data->session, callbacks, session_data);
option);
nghttp2_session_callbacks_del(callbacks); nghttp2_session_callbacks_del(callbacks);
nghttp2_option_del(option);
} }
Since we are creating a server and uses options, the nghttp2 session Since we are creating a server and uses options, the nghttp2 session
object is created using `nghttp2_session_server_new2()` function. We object is created using `nghttp2_session_server_new2()` function. We
registers five callbacks for nghttp2 session object. We'll talk about registers five callbacks for nghttp2 session object. We'll talk about
these callbacks later. Our server only speaks HTTP/2. In this case, these callbacks later.
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.
After initialization of the nghttp2 session object, we are going to send After initialization of the nghttp2 session object, we are going to send
a server connection header in ``send_server_connection_header()``:: a server connection header in ``send_server_connection_header()``::

View File

@ -528,14 +528,6 @@ static void fetch_uri(const struct URI *uri) {
connection.ssl = ssl; connection.ssl = ssl;
connection.want_io = IO_NONE; 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 */ /* Here make file descriptor non-block */
make_non_block(fd); make_non_block(fd);
set_tcp_nodelay(fd); set_tcp_nodelay(fd);

View File

@ -345,8 +345,7 @@ static void send_client_connection_header(http2_session_data *session_data) {
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}}; {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
int rv; int rv;
bufferevent_write(session_data->bev, NGHTTP2_CLIENT_CONNECTION_PREFACE, /* client 24 bytes magic string will be sent by nghttp2 library */
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv, rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
ARRLEN(iv)); ARRLEN(iv));
if (rv != 0) { if (rv != 0) {

View File

@ -194,32 +194,17 @@ typedef struct {
/** /**
* @macro * @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 * @macro
* *
* The length of :macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`. * The length of :macro:`NGHTTP2_CLIENT_MAGIC`.
*/ */
#define NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN 24 #define NGHTTP2_CLIENT_MAGIC_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
/** /**
* @enum * @enum
@ -397,10 +382,10 @@ typedef enum {
*/ */
NGHTTP2_ERR_CALLBACK_FAILURE = -902, NGHTTP2_ERR_CALLBACK_FAILURE = -902,
/** /**
* Invalid connection preface was received and further processing is * Invalid client magic (see :macro:`NGHTTP2_CLIENT_MAGIC`) was
* not possible. * received and further processing is not possible.
*/ */
NGHTTP2_ERR_BAD_PREFACE = -903 NGHTTP2_ERR_BAD_CLIENT_MAGIC = -903
} nghttp2_error; } nghttp2_error;
/** /**
@ -1975,25 +1960,22 @@ nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
* @function * @function
* *
* By default, nghttp2 library, if configured as server, requires * By default, nghttp2 library, if configured as server, requires
* first 24 bytes of client connection preface. In most cases, this * first 24 bytes of client magic byte string (MAGIC). In most cases,
* will simplify the implementation of server. But sometimes erver * this will simplify the implementation of server. But sometimes
* may want to detect the application protocol based on first few * server may want to detect the application protocol based on first
* bytes on clear text communication. * few bytes on clear text communication.
* *
* If this option is used with nonzero |val|, nghttp2 library does not * If this option is used with nonzero |val|, nghttp2 library does not
* handle first 24 bytes client connection preface. It still checks * handle MAGIC. It still checks following SETTINGS frame. This
* following SETTINGS frame. This means that applications should deal * means that applications should deal with MAGIC by themselves.
* with 24 bytes connection preface by themselves.
* *
* If this option is not used or used with zero value, if client * If this option is not used or used with zero value, if MAGIC does
* connection preface does not match the one * not match :macro:`NGHTTP2_CLIENT_MAGIC`, `nghttp2_session_recv()`
* (:macro:`NGHTTP2_CLIENT_CONNECTION_PREFACE`) in the HTTP/2 * and `nghttp2_session_mem_recv()` will return error
* specification, `nghttp2_session_recv()` and * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal error.
* `nghttp2_session_mem_recv()` will return error
* :enum:`NGHTTP2_ERR_BAD_PREFACE`, which is fatal error.
*/ */
NGHTTP2_EXTERN void 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 * @function
@ -2310,10 +2292,10 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session,
* Out of memory. * Out of memory.
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
* The callback function failed. * The callback function failed.
* :enum:`NGHTTP2_ERR_BAD_PREFACE` * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
* Invalid client preface was detected. This error only returns * Invalid client magic was detected. This error only returns
* when |session| was configured as server and * 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. * nonzero value.
*/ */
NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session); 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. * Out of memory.
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
* The callback function failed. * The callback function failed.
* :enum:`NGHTTP2_ERR_BAD_PREFACE` * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
* Invalid client preface was detected. This error only returns * Invalid client magic was detected. This error only returns
* when |session| was configured as server and * 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. * nonzero value.
*/ */
NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session, NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session,

View File

@ -307,8 +307,8 @@ const char *nghttp2_strerror(int error_code) {
return "Out of memory"; return "Out of memory";
case NGHTTP2_ERR_CALLBACK_FAILURE: case NGHTTP2_ERR_CALLBACK_FAILURE:
return "The user callback function failed"; return "The user callback function failed";
case NGHTTP2_ERR_BAD_PREFACE: case NGHTTP2_ERR_BAD_CLIENT_MAGIC:
return "Received bad connection preface"; return "Received bad clinet magic byte string";
default: default:
return "Unknown error code"; return "Unknown error code";
} }

View File

@ -47,10 +47,9 @@ void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
option->peer_max_concurrent_streams = val; option->peer_max_concurrent_streams = val;
} }
void nghttp2_option_set_no_recv_client_preface(nghttp2_option *option, void nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val) {
int val) { option->opt_set_mask |= NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC;
option->opt_set_mask |= NGHTTP2_OPT_NO_RECV_CLIENT_PREFACE; option->no_recv_client_magic = val;
option->no_recv_client_preface = val;
} }
void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val) { void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val) {

View File

@ -57,7 +57,7 @@ typedef enum {
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint. * SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
*/ */
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1, 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_OPT_NO_HTTP_MESSAGING = 1 << 3,
} nghttp2_option_flag; } nghttp2_option_flag;
@ -79,9 +79,9 @@ struct nghttp2_option {
*/ */
uint8_t no_auto_window_update; 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 * NGHTTP2_OPT_NO_HTTP_MESSAGING
*/ */

View File

@ -314,9 +314,9 @@ static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
aob->state = NGHTTP2_OB_POP_ITEM; aob->state = NGHTTP2_OB_POP_ITEM;
} }
/* This global variable exists for tests where we want to disable this /* The global variable for tests where we want to disable strict
check. */ preface handling. */
int nghttp2_enable_strict_connection_preface_check = 1; int nghttp2_enable_strict_preface = 1;
static int session_new(nghttp2_session **session_ptr, static int session_new(nghttp2_session **session_ptr,
const nghttp2_session_callbacks *callbacks, const nghttp2_session_callbacks *callbacks,
@ -417,10 +417,10 @@ static int session_new(nghttp2_session **session_ptr,
option->peer_max_concurrent_streams; option->peer_max_concurrent_streams;
} }
if ((option->opt_set_mask & NGHTTP2_OPT_NO_RECV_CLIENT_PREFACE) && if ((option->opt_set_mask & NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC) &&
option->no_recv_client_preface) { 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) && 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); 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; nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe;
if (server && if (server &&
((*session_ptr)->opt_flags & NGHTTP2_OPTMASK_NO_RECV_CLIENT_PREFACE) == ((*session_ptr)->opt_flags & NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC) ==
0) { 0) {
iframe->state = NGHTTP2_IB_READ_CLIENT_PREFACE; iframe->state = NGHTTP2_IB_READ_CLIENT_MAGIC;
iframe->payloadleft = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN; iframe->payloadleft = NGHTTP2_CLIENT_MAGIC_LEN;
} else { } else {
iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS; 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; return 0;
@ -2979,6 +2985,25 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
break; 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; return len;
} }
/* We have to call session_after_frame_sent1 here to handle stream if (session->aob.item) {
closure upon transmission of frames. Otherwise, END_STREAM may /* We have to call session_after_frame_sent1 here to handle stream
be reached to client before we call nghttp2_session_mem_send closure upon transmission of frames. Otherwise, END_STREAM may
again and we may get exceeding number of incoming streams. */ be reached to client before we call nghttp2_session_mem_send
rv = session_after_frame_sent1(session); again and we may get exceeding number of incoming streams. */
if (rv < 0) { rv = session_after_frame_sent1(session);
assert(nghttp2_is_fatal(rv)); if (rv < 0) {
return (ssize_t)rv; assert(nghttp2_is_fatal(rv));
return (ssize_t)rv;
}
} }
return len; return len;
@ -4907,14 +4934,13 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
for (;;) { for (;;) {
switch (iframe->state) { switch (iframe->state) {
case NGHTTP2_IB_READ_CLIENT_PREFACE: case NGHTTP2_IB_READ_CLIENT_MAGIC:
readlen = nghttp2_min(inlen, iframe->payloadleft); readlen = nghttp2_min(inlen, iframe->payloadleft);
if (memcmp(NGHTTP2_CLIENT_CONNECTION_PREFACE + if (memcmp(NGHTTP2_CLIENT_MAGIC + NGHTTP2_CLIENT_MAGIC_LEN -
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN -
iframe->payloadleft, iframe->payloadleft,
in, readlen) != 0) { in, readlen) != 0) {
return NGHTTP2_ERR_BAD_PREFACE; return NGHTTP2_ERR_BAD_CLIENT_MAGIC;
} }
iframe->payloadleft -= readlen; iframe->payloadleft -= readlen;

View File

@ -46,14 +46,15 @@
*/ */
typedef enum { typedef enum {
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0, 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_NO_HTTP_MESSAGING = 1 << 2,
} nghttp2_optmask; } nghttp2_optmask;
typedef enum { typedef enum {
NGHTTP2_OB_POP_ITEM, NGHTTP2_OB_POP_ITEM,
NGHTTP2_OB_SEND_DATA, NGHTTP2_OB_SEND_DATA,
NGHTTP2_OB_SEND_NO_COPY NGHTTP2_OB_SEND_NO_COPY,
NGHTTP2_OB_SEND_CLIENT_MAGIC
} nghttp2_outbound_state; } nghttp2_outbound_state;
typedef struct { typedef struct {
@ -69,7 +70,7 @@ typedef struct {
/* Internal state when receiving incoming frame */ /* Internal state when receiving incoming frame */
typedef enum { typedef enum {
/* Receiving frame header */ /* Receiving frame header */
NGHTTP2_IB_READ_CLIENT_PREFACE, NGHTTP2_IB_READ_CLIENT_MAGIC,
NGHTTP2_IB_READ_FIRST_SETTINGS, NGHTTP2_IB_READ_FIRST_SETTINGS,
NGHTTP2_IB_READ_HEAD, NGHTTP2_IB_READ_HEAD,
NGHTTP2_IB_READ_NBYTE, NGHTTP2_IB_READ_NBYTE,

View File

@ -1477,8 +1477,6 @@ if asyncio:
cnghttp2.NGHTTP2_PROTO_VERSION_ID: cnghttp2.NGHTTP2_PROTO_VERSION_ID:
self.transport.abort() self.transport.abort()
# Send preamble
self.transport.write(cnghttp2.NGHTTP2_CLIENT_CONNECTION_PREFACE)
self.http2 = _HTTP2ClientSessionCore(self.transport) self.http2 = _HTTP2ClientSessionCore(self.transport)
# Clear pending requests # Clear pending requests

View File

@ -431,7 +431,7 @@ int Http2Handler::read_clear() {
rv = nghttp2_session_mem_recv(session_, buf.data(), nread); rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
if (rv < 0) { if (rv < 0) {
if (rv != NGHTTP2_ERR_BAD_PREFACE) { if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
std::cerr << "nghttp2_session_mem_recv() returned error: " std::cerr << "nghttp2_session_mem_recv() returned error: "
<< nghttp2_strerror(rv) << std::endl; << nghttp2_strerror(rv) << std::endl;
} }
@ -558,7 +558,7 @@ int Http2Handler::read_tls() {
rv = nghttp2_session_mem_recv(session_, buf.data(), nread); rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
if (rv < 0) { if (rv < 0) {
if (rv != NGHTTP2_ERR_BAD_PREFACE) { if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
std::cerr << "nghttp2_session_mem_recv() returned error: " std::cerr << "nghttp2_session_mem_recv() returned error: "
<< nghttp2_strerror(rv) << std::endl; << nghttp2_strerror(rv) << std::endl;
} }

View File

@ -75,10 +75,6 @@ void session_impl::connected(tcp::resolver::iterator endpoint_it) {
socket().set_option(boost::asio::ip::tcp::no_delay(true)); 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_write();
do_read(); do_read();

View File

@ -202,12 +202,6 @@ void Http2Session::on_connect() {
extra_connection_window); 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(); client_->signal_write();
} }

View File

@ -962,9 +962,6 @@ int HttpClient::connection_made() {
request_done(stream_user_data); 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 // If upgrade succeeds, the SETTINGS value sent with
// HTTP2-Settings header field has already been submitted to // HTTP2-Settings header field has already been submitted to
// session object. // session object.

View File

@ -904,7 +904,7 @@ void fill_default_config() {
nghttp2_option_new(&mod_config()->http2_option); nghttp2_option_new(&mod_config()->http2_option);
nghttp2_option_set_no_auto_window_update(get_config()->http2_option, 1); 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_new(&mod_config()->http2_client_option);
nghttp2_option_set_no_auto_window_update(get_config()->http2_client_option, nghttp2_option_set_no_auto_window_update(get_config()->http2_client_option,

View File

@ -279,8 +279,7 @@ int ClientHandler::upstream_write() {
int ClientHandler::upstream_http2_connhd_read() { int ClientHandler::upstream_http2_connhd_read() {
auto nread = std::min(left_connhd_len_, rb_.rleft()); auto nread = std::min(left_connhd_len_, rb_.rleft());
if (memcmp(NGHTTP2_CLIENT_CONNECTION_PREFACE + if (memcmp(NGHTTP2_CLIENT_MAGIC + NGHTTP2_CLIENT_MAGIC_LEN - left_connhd_len_,
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - left_connhd_len_,
rb_.pos, nread) != 0) { rb_.pos, nread) != 0) {
// There is no downgrade path here. Just drop the connection. // There is no downgrade path here. Just drop the connection.
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
@ -309,8 +308,7 @@ int ClientHandler::upstream_http2_connhd_read() {
int ClientHandler::upstream_http1_connhd_read() { int ClientHandler::upstream_http1_connhd_read() {
auto nread = std::min(left_connhd_len_, rb_.rleft()); auto nread = std::min(left_connhd_len_, rb_.rleft());
if (memcmp(NGHTTP2_CLIENT_CONNECTION_PREFACE + if (memcmp(NGHTTP2_CLIENT_MAGIC + NGHTTP2_CLIENT_MAGIC_LEN - left_connhd_len_,
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - left_connhd_len_,
rb_.pos, nread) != 0) { rb_.pos, nread) != 0) {
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
CLOG(INFO, this) << "This is HTTP/1.1 connection, " 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 // 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_read_ = &ClientHandler::upstream_read;
on_write_ = &ClientHandler::upstream_write; 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), get_config()->read_burst, writecb, readcb, timeoutcb, this),
ipaddr_(ipaddr), port_(port), worker_(worker), ipaddr_(ipaddr), port_(port), worker_(worker),
http2session_(worker_->next_http2_session()), 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) { should_close_after_write_(false) {
++worker_->get_worker_stat()->num_connections; ++worker_->get_worker_stat()->num_connections;

View File

@ -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 && auto must_terminate = !get_config()->downstream_no_tls &&
!ssl::check_http2_requirement(conn_.tls.ssl); !ssl::check_http2_requirement(conn_.tls.ssl);

View File

@ -769,7 +769,7 @@ int Http2Upstream::on_read() {
if (rb->rleft()) { if (rb->rleft()) {
rv = nghttp2_session_mem_recv(session_, rb->pos, rb->rleft()); rv = nghttp2_session_mem_recv(session_, rb->pos, rb->rleft());
if (rv < 0) { if (rv < 0) {
if (rv != NGHTTP2_ERR_BAD_PREFACE) { if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
ULOG(ERROR, this) << "nghttp2_session_recv() returned error: " ULOG(ERROR, this) << "nghttp2_session_recv() returned error: "
<< nghttp2_strerror(rv); << nghttp2_strerror(rv);
} }

View File

@ -41,7 +41,7 @@
#include "nghttp2_helper_test.h" #include "nghttp2_helper_test.h"
#include "nghttp2_buf_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; } static int init_suite1(void) { return 0; }
@ -51,7 +51,7 @@ int main(int argc _U_, char *argv[] _U_) {
CU_pSuite pSuite = NULL; CU_pSuite pSuite = NULL;
unsigned int num_tests_failed; unsigned int num_tests_failed;
nghttp2_enable_strict_connection_preface_check = 0; nghttp2_enable_strict_preface = 0;
/* initialize the CUnit test registry */ /* initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry()) if (CUE_SUCCESS != CU_initialize_registry())
@ -250,8 +250,8 @@ int main(int argc _U_, char *argv[] _U_) {
test_nghttp2_session_graceful_shutdown) || test_nghttp2_session_graceful_shutdown) ||
!CU_add_test(pSuite, "session_on_header_temporal_failure", !CU_add_test(pSuite, "session_on_header_temporal_failure",
test_nghttp2_session_on_header_temporal_failure) || test_nghttp2_session_on_header_temporal_failure) ||
!CU_add_test(pSuite, "session_recv_client_preface", !CU_add_test(pSuite, "session_recv_client_magic",
test_nghttp2_session_recv_client_preface) || test_nghttp2_session_recv_client_magic) ||
!CU_add_test(pSuite, "session_delete_data_item", !CU_add_test(pSuite, "session_delete_data_item",
test_nghttp2_session_delete_data_item) || test_nghttp2_session_delete_data_item) ||
!CU_add_test(pSuite, "session_open_idle_stream", !CU_add_test(pSuite, "session_open_idle_stream",

View File

@ -36,7 +36,7 @@
#include "nghttp2_test_helper.h" #include "nghttp2_test_helper.h"
#include "nghttp2_priority_spec.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(ITEM) nghttp2_outbound_item_get_ctrl_frame(ITEM)
#define OB_CTRL_TYPE(ITEM) nghttp2_outbound_item_get_ctrl_frame_type(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); 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 *session;
nghttp2_session_callbacks callbacks; nghttp2_session_callbacks callbacks;
ssize_t rv; ssize_t rv;
nghttp2_frame ping_frame; nghttp2_frame ping_frame;
uint8_t buf[16]; uint8_t buf[16];
/* enable global nghttp2_enable_strict_connection_preface_check /* enable global nghttp2_enable_strict_preface here */
here */ nghttp2_enable_strict_preface = 1;
nghttp2_enable_strict_connection_preface_check = 1;
memset(&callbacks, 0, sizeof(callbacks)); memset(&callbacks, 0, sizeof(callbacks));
/* Check success case */ /* Check success case */
nghttp2_session_server_new(&session, &callbacks, NULL); nghttp2_session_server_new(&session, &callbacks, NULL);
rv = nghttp2_session_mem_recv( rv = nghttp2_session_mem_recv(session, (const uint8_t *)NGHTTP2_CLIENT_MAGIC,
session, (const uint8_t *)NGHTTP2_CLIENT_CONNECTION_PREFACE, NGHTTP2_CLIENT_MAGIC_LEN);
NGHTTP2_CLIENT_CONNECTION_PREFACE_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); CU_ASSERT(NGHTTP2_IB_READ_FIRST_SETTINGS == session->iframe.state);
/* Receiving PING is error because we want SETTINGS. */ /* Receiving PING is error because we want SETTINGS. */
@ -6762,24 +6760,22 @@ void test_nghttp2_session_recv_client_preface(void) {
/* Check bad case */ /* Check bad case */
nghttp2_session_server_new(&session, &callbacks, NULL); nghttp2_session_server_new(&session, &callbacks, NULL);
/* Feed preface with one byte less */ /* Feed magic with one byte less */
rv = nghttp2_session_mem_recv( rv = nghttp2_session_mem_recv(session, (const uint8_t *)NGHTTP2_CLIENT_MAGIC,
session, (const uint8_t *)NGHTTP2_CLIENT_CONNECTION_PREFACE, NGHTTP2_CLIENT_MAGIC_LEN - 1);
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - 1);
CU_ASSERT(rv == NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - 1); CU_ASSERT(rv == NGHTTP2_CLIENT_MAGIC_LEN - 1);
CU_ASSERT(NGHTTP2_IB_READ_CLIENT_PREFACE == session->iframe.state); CU_ASSERT(NGHTTP2_IB_READ_CLIENT_MAGIC == session->iframe.state);
CU_ASSERT(1 == session->iframe.payloadleft); CU_ASSERT(1 == session->iframe.payloadleft);
rv = nghttp2_session_mem_recv(session, (const uint8_t *)"\0", 1); 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); nghttp2_session_del(session);
/* disable global nghttp2_enable_strict_connection_preface_check /* disable global nghttp2_enable_strict_preface here */
here */ nghttp2_enable_strict_preface = 0;
nghttp2_enable_strict_connection_preface_check = 0;
} }
void test_nghttp2_session_delete_data_item(void) { void test_nghttp2_session_delete_data_item(void) {

View File

@ -118,7 +118,7 @@ void test_nghttp2_session_detach_idle_stream(void);
void test_nghttp2_session_large_dep_tree(void); void test_nghttp2_session_large_dep_tree(void);
void test_nghttp2_session_graceful_shutdown(void); void test_nghttp2_session_graceful_shutdown(void);
void test_nghttp2_session_on_header_temporal_failure(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_delete_data_item(void);
void test_nghttp2_session_open_idle_stream(void); void test_nghttp2_session_open_idle_stream(void);
void test_nghttp2_session_cancel_reserved_remote(void); void test_nghttp2_session_cancel_reserved_remote(void);