mirror of
https://github.com/nghttp2/nghttp2.git
synced 2026-03-27 00:16:15 +08:00
19
README.rst
19
README.rst
@@ -29,10 +29,10 @@ Public Test Server
|
||||
The following endpoints are available to try out our nghttp2
|
||||
implementation.
|
||||
|
||||
* https://nghttp2.org/ (TLS + ALPN/NPN and HTTP/3)
|
||||
* https://nghttp2.org/ (TLS + ALPN and HTTP/3)
|
||||
|
||||
This endpoint supports ``h2``, ``h2-16``, ``h2-14``, and
|
||||
``http/1.1`` via ALPN/NPN and requires TLSv1.2 for HTTP/2
|
||||
``http/1.1`` via ALPN and requires TLSv1.2 for HTTP/2
|
||||
connection.
|
||||
|
||||
It also supports HTTP/3.
|
||||
@@ -537,7 +537,7 @@ nghttp - client
|
||||
+++++++++++++++
|
||||
|
||||
``nghttp`` is a HTTP/2 client. It can connect to the HTTP/2 server
|
||||
with prior knowledge, HTTP Upgrade and NPN/ALPN TLS extension.
|
||||
with prior knowledge, HTTP Upgrade and ALPN TLS extension.
|
||||
|
||||
It has verbose output mode for framing information. Here is sample
|
||||
output from ``nghttp`` client:
|
||||
@@ -763,8 +763,8 @@ nghttpd - server
|
||||
By default, it uses SSL/TLS connection. Use ``--no-tls`` option to
|
||||
disable it.
|
||||
|
||||
``nghttpd`` only accepts HTTP/2 connections via NPN/ALPN or direct
|
||||
HTTP/2 connections. No HTTP Upgrade is supported.
|
||||
``nghttpd`` only accepts HTTP/2 connections via ALPN or direct HTTP/2
|
||||
connections. No HTTP Upgrade is supported.
|
||||
|
||||
The ``-p`` option allows users to configure server push.
|
||||
|
||||
@@ -845,7 +845,7 @@ to know how to migrate from earlier releases.
|
||||
``nghttpx`` implements `important performance-oriented features
|
||||
<https://istlsfastyet.com/#server-performance>`_ in TLS, such as
|
||||
session IDs, session tickets (with automatic key rotation), OCSP
|
||||
stapling, dynamic record sizing, ALPN/NPN, forward secrecy and HTTP/2.
|
||||
stapling, dynamic record sizing, ALPN, forward secrecy and HTTP/2.
|
||||
``nghttpx`` also offers the functionality to share session cache and
|
||||
ticket keys among multiple ``nghttpx`` instances via memcached.
|
||||
|
||||
@@ -972,12 +972,15 @@ threads to avoid saturating a single core on client side.
|
||||
servers.
|
||||
|
||||
If the experimental HTTP/3 is enabled, h2load can send requests to
|
||||
HTTP/3 server. To do this, specify ``h3`` to ``--npn-list`` option
|
||||
HTTP/3 server. To do this, specify ``h3`` to ``--alpn-list`` option
|
||||
like so:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ h2load --npn-list h3 https://127.0.0.1:4433
|
||||
$ h2load --alpn-list h3 https://127.0.0.1:4433
|
||||
|
||||
For nghttp2 v1.58 or earlier, use ``--npn-list`` instead of
|
||||
``--alpn-list``.
|
||||
|
||||
HPACK tools
|
||||
-----------
|
||||
|
||||
@@ -86,6 +86,7 @@ APIDOCS= \
|
||||
nghttp2_rcbuf_incref.rst \
|
||||
nghttp2_rcbuf_is_static.rst \
|
||||
nghttp2_select_next_protocol.rst \
|
||||
nghttp2_select_alpn.rst \
|
||||
nghttp2_session_callbacks_del.rst \
|
||||
nghttp2_session_callbacks_new.rst \
|
||||
nghttp2_session_callbacks_set_before_frame_send_callback.rst \
|
||||
|
||||
@@ -30,8 +30,8 @@ In order to set benchmark settings, specify following 3 options.
|
||||
:option:`-m`
|
||||
The max concurrent streams to issue per client. Default: 1
|
||||
|
||||
For SSL/TLS connection, the protocol will be negotiated via ALPN/NPN.
|
||||
You can set specific protocols in :option:`--npn-list` option. For
|
||||
For SSL/TLS connection, the protocol will be negotiated via ALPN. You
|
||||
can set specific protocols in :option:`--alpn-list` option. For
|
||||
cleartext connection, the default protocol is HTTP/2. To change the
|
||||
protocol in cleartext connection, use :option:`--no-tls-proto` option.
|
||||
For convenience, :option:`--h1` option forces HTTP/1.1 for both
|
||||
@@ -139,4 +139,4 @@ h2load supports HTTP/3 if it is built with HTTP/3 enabled. HTTP/3
|
||||
support is experimental.
|
||||
|
||||
In order to send HTTP/3 request, specify ``h3`` to
|
||||
:option:`--npn-list`.
|
||||
:option:`--alpn-list`.
|
||||
|
||||
@@ -20,7 +20,7 @@ known as "HTTP/2 router".
|
||||
By default, frontend connection is encrypted using SSL/TLS. So
|
||||
server's private key and certificate must be supplied to the command
|
||||
line (or through configuration file). In this case, the frontend
|
||||
protocol selection will be done via ALPN or NPN.
|
||||
protocol selection will be done via ALPN.
|
||||
|
||||
To turn off encryption on frontend connection, use ``no-tls`` keyword
|
||||
in :option:`--frontend` option. HTTP/2 and HTTP/1 are available on
|
||||
|
||||
@@ -18,34 +18,8 @@ note that nghttp2 itself does not depend on libevent.
|
||||
|
||||
The client starts with some libevent and OpenSSL setup in the
|
||||
``main()`` and ``run()`` functions. This setup isn't specific to
|
||||
nghttp2, but one thing you should look at is setup of the NPN
|
||||
callback. The NPN callback is used by the client to select the next
|
||||
application protocol over TLS. In this tutorial, we use the
|
||||
`nghttp2_select_next_protocol()` helper function to select the HTTP/2
|
||||
protocol the library supports::
|
||||
|
||||
static int select_next_proto_cb(SSL *ssl _U_, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg _U_) {
|
||||
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
|
||||
errx(1, "Server did not advertise " NGHTTP2_PROTO_VERSION_ID);
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
If you are following TLS related RFC, you know that NPN is not the
|
||||
standardized way to negotiate HTTP/2. NPN itself is not event
|
||||
published as RFC. The standard way to negotiate HTTP/2 is ALPN,
|
||||
Application-Layer Protocol Negotiation Extension, defined in `RFC 7301
|
||||
<https://tools.ietf.org/html/rfc7301>`_. The one caveat of ALPN is
|
||||
that OpenSSL >= 1.0.2 is required. We use macro to enable/disable
|
||||
ALPN support depending on OpenSSL version. OpenSSL's ALPN
|
||||
implementation does not require callback function like the above. But
|
||||
we have to instruct OpenSSL SSL_CTX to use ALPN, which we'll talk
|
||||
about soon.
|
||||
|
||||
The callback is added to the SSL_CTX object using
|
||||
``SSL_CTX_set_next_proto_select_cb()``::
|
||||
nghttp2, but one thing you should look at is setup of ALPN. Client
|
||||
tells application protocols that it supports to server via ALPN::
|
||||
|
||||
static SSL_CTX *create_ssl_ctx(void) {
|
||||
SSL_CTX *ssl_ctx;
|
||||
@@ -58,7 +32,6 @@ The callback is added to the SSL_CTX object using
|
||||
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
|
||||
|
||||
SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
|
||||
|
||||
@@ -153,10 +126,7 @@ underlying network socket::
|
||||
|
||||
ssl = bufferevent_openssl_get_ssl(session_data->bev);
|
||||
|
||||
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
|
||||
if (alpn == NULL) {
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
}
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
|
||||
if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
|
||||
fprintf(stderr, "h2 is not negotiated\n");
|
||||
|
||||
@@ -21,40 +21,18 @@ note that nghttp2 itself does not depend on libevent.
|
||||
|
||||
The server starts with some libevent and OpenSSL setup in the
|
||||
``main()`` and ``run()`` functions. This setup isn't specific to
|
||||
nghttp2, but one thing you should look at is setup of the NPN
|
||||
callback. The NPN callback is used by the server to advertise which
|
||||
application protocols the server supports to a client. In this
|
||||
example program, when creating the ``SSL_CTX`` object, we store the
|
||||
application protocol name in the wire format of NPN in a statically
|
||||
allocated buffer. This is safe because we only create one ``SSL_CTX``
|
||||
object in the program's entire lifetime.
|
||||
|
||||
If you are following TLS related RFC, you know that NPN is not the
|
||||
standardized way to negotiate HTTP/2. NPN itself is not even
|
||||
published as RFC. The standard way to negotiate HTTP/2 is ALPN,
|
||||
Application-Layer Protocol Negotiation Extension, defined in `RFC 7301
|
||||
<https://tools.ietf.org/html/rfc7301>`_. The one caveat of ALPN is
|
||||
that OpenSSL >= 1.0.2 is required. We use macro to enable/disable
|
||||
ALPN support depending on OpenSSL version. In ALPN, client sends the
|
||||
list of supported application protocols, and server selects one of
|
||||
them. We provide the callback for it::
|
||||
|
||||
static unsigned char next_proto_list[256];
|
||||
static size_t next_proto_list_len;
|
||||
|
||||
static int next_proto_cb(SSL *s _U_, const unsigned char **data,
|
||||
unsigned int *len, void *arg _U_) {
|
||||
*data = next_proto_list;
|
||||
*len = (unsigned int)next_proto_list_len;
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
nghttp2, but one thing you should look at is setup of ALPN callback.
|
||||
The ALPN callback is used by the server to select application
|
||||
protocols offered by client. In ALPN, client sends the list of
|
||||
supported application protocols, and server selects one of them. We
|
||||
provide the callback for it::
|
||||
|
||||
static int alpn_select_proto_cb(SSL *ssl _U_, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg _U_) {
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in, inlen);
|
||||
rv = nghttp2_select_alpn(out, outlen, in, inlen);
|
||||
|
||||
if (rv != 1) {
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
@@ -71,31 +49,14 @@ them. We provide the callback for it::
|
||||
|
||||
...
|
||||
|
||||
next_proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
|
||||
memcpy(&next_proto_list[1], NGHTTP2_PROTO_VERSION_ID,
|
||||
NGHTTP2_PROTO_VERSION_ID_LEN);
|
||||
next_proto_list_len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN;
|
||||
|
||||
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL);
|
||||
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL);
|
||||
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
The wire format of NPN is a sequence of length prefixed strings, with
|
||||
exactly one byte used to specify the length of each protocol
|
||||
identifier. In this tutorial, we advertise the specific HTTP/2
|
||||
protocol version the current nghttp2 library supports, which is
|
||||
exported in the identifier :macro:`NGHTTP2_PROTO_VERSION_ID`. The
|
||||
``next_proto_cb()`` function is the server-side NPN callback. In the
|
||||
OpenSSL implementation, we just assign the pointer to the NPN buffers
|
||||
we filled in earlier. The NPN callback function is set to the
|
||||
``SSL_CTX`` object using ``SSL_CTX_set_next_protos_advertised_cb()``.
|
||||
|
||||
In ``alpn_select_proto_cb()``, we use `nghttp2_select_next_protocol()`
|
||||
to select application protocol. The `nghttp2_select_next_protocol()`
|
||||
returns 1 only if it selected h2 (ALPN identifier for HTTP/2), and out
|
||||
In ``alpn_select_proto_cb()``, we use `nghttp2_select_alpn()` to
|
||||
select application protocol. The `nghttp2_select_alpn()` returns 1
|
||||
only if it selected h2 (ALPN identifier for HTTP/2), and out
|
||||
parameters were assigned accordingly.
|
||||
|
||||
Next, let's take a look at the main structures used by the example
|
||||
@@ -209,10 +170,7 @@ underlying network socket::
|
||||
|
||||
ssl = bufferevent_openssl_get_ssl(session_data->bev);
|
||||
|
||||
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
|
||||
if (alpn == NULL) {
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
}
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
|
||||
if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
|
||||
fprintf(stderr, "%s h2 is not negotiated\n", session_data->client_addr);
|
||||
|
||||
@@ -345,29 +345,6 @@ static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks) {
|
||||
callbacks, on_data_chunk_recv_callback);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
/*
|
||||
* Callback function for TLS NPN. Since this program only supports
|
||||
* HTTP/2 protocol, if server does not offer HTTP/2 the nghttp2
|
||||
* library supports, we terminate program.
|
||||
*/
|
||||
static int select_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
int rv;
|
||||
(void)ssl;
|
||||
(void)arg;
|
||||
|
||||
/* nghttp2_select_next_protocol() selects HTTP/2 protocol the
|
||||
nghttp2 library supports. */
|
||||
rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
|
||||
if (rv <= 0) {
|
||||
die("Server did not advertise HTTP/2 protocol");
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
/*
|
||||
* Setup SSL/TLS context.
|
||||
*/
|
||||
@@ -376,10 +353,6 @@ static void init_ssl_ctx(SSL_CTX *ssl_ctx) {
|
||||
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
/* Set NPN callback */
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
|
||||
}
|
||||
|
||||
@@ -308,23 +308,6 @@ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
/* NPN TLS extension client callback. We check that server advertised
|
||||
the HTTP/2 protocol the nghttp2 library supports. If not, exit
|
||||
the program. */
|
||||
static int select_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
(void)ssl;
|
||||
(void)arg;
|
||||
|
||||
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
|
||||
errx(1, "Server did not advertise " NGHTTP2_PROTO_VERSION_ID);
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
/* Create SSL_CTX. */
|
||||
static SSL_CTX *create_ssl_ctx(void) {
|
||||
SSL_CTX *ssl_ctx;
|
||||
@@ -337,9 +320,6 @@ static SSL_CTX *create_ssl_ctx(void) {
|
||||
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
|
||||
|
||||
@@ -506,9 +486,6 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr) {
|
||||
|
||||
ssl = bufferevent_openssl_get_ssl(session_data->bev);
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
if (alpn == NULL) {
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
}
|
||||
|
||||
@@ -106,21 +106,6 @@ struct app_context {
|
||||
struct event_base *evbase;
|
||||
};
|
||||
|
||||
static unsigned char next_proto_list[256];
|
||||
static size_t next_proto_list_len;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
static int next_proto_cb(SSL *ssl, const unsigned char **data,
|
||||
unsigned int *len, void *arg) {
|
||||
(void)ssl;
|
||||
(void)arg;
|
||||
|
||||
*data = next_proto_list;
|
||||
*len = (unsigned int)next_proto_list_len;
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
@@ -128,7 +113,7 @@ static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
|
||||
(void)ssl;
|
||||
(void)arg;
|
||||
|
||||
rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in, inlen);
|
||||
rv = nghttp2_select_alpn(out, outlen, in, inlen);
|
||||
|
||||
if (rv != 1) {
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
@@ -175,15 +160,6 @@ static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
|
||||
errx(1, "Could not read certificate file %s", cert_file);
|
||||
}
|
||||
|
||||
next_proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
|
||||
memcpy(&next_proto_list[1], NGHTTP2_PROTO_VERSION_ID,
|
||||
NGHTTP2_PROTO_VERSION_ID_LEN);
|
||||
next_proto_list_len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL);
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL);
|
||||
|
||||
return ssl_ctx;
|
||||
@@ -698,12 +674,7 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr) {
|
||||
|
||||
ssl = bufferevent_openssl_get_ssl(session_data->bev);
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
if (alpn == NULL) {
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
}
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
|
||||
if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
|
||||
fprintf(stderr, "%s h2 is not negotiated\n", session_data->client_addr);
|
||||
|
||||
@@ -200,6 +200,7 @@ OPTIONS = [
|
||||
"frontend-quic-initial-rtt",
|
||||
"require-http-scheme",
|
||||
"tls-ktls",
|
||||
"alpn-list",
|
||||
]
|
||||
|
||||
LOGVARS = [
|
||||
|
||||
@@ -14,7 +14,7 @@ set(NGHTTP2_SOURCES
|
||||
nghttp2_stream.c nghttp2_outbound_item.c
|
||||
nghttp2_session.c nghttp2_submit.c
|
||||
nghttp2_helper.c
|
||||
nghttp2_npn.c
|
||||
nghttp2_alpn.c
|
||||
nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c
|
||||
nghttp2_version.c
|
||||
nghttp2_priority_spec.c
|
||||
|
||||
@@ -41,7 +41,7 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
|
||||
nghttp2_stream.c nghttp2_outbound_item.c \
|
||||
nghttp2_session.c nghttp2_submit.c \
|
||||
nghttp2_helper.c \
|
||||
nghttp2_npn.c \
|
||||
nghttp2_alpn.c \
|
||||
nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c \
|
||||
nghttp2_version.c \
|
||||
nghttp2_priority_spec.c \
|
||||
@@ -60,7 +60,7 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
|
||||
nghttp2_frame.h \
|
||||
nghttp2_buf.h \
|
||||
nghttp2_session.h nghttp2_helper.h nghttp2_stream.h nghttp2_int.h \
|
||||
nghttp2_npn.h \
|
||||
nghttp2_alpn.h \
|
||||
nghttp2_submit.h nghttp2_outbound_item.h \
|
||||
nghttp2_net.h \
|
||||
nghttp2_hd.h nghttp2_hd_huffman.h \
|
||||
|
||||
@@ -74,7 +74,7 @@ NGHTTP2_SRC := nghttp2_pq.c \
|
||||
nghttp2_session.c \
|
||||
nghttp2_submit.c \
|
||||
nghttp2_helper.c \
|
||||
nghttp2_npn.c \
|
||||
nghttp2_alpn.c \
|
||||
nghttp2_hd.c \
|
||||
nghttp2_hd_huffman.c \
|
||||
nghttp2_hd_huffman_data.c \
|
||||
|
||||
@@ -5022,11 +5022,14 @@ NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs,
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* 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, ``h2`` and
|
||||
* ``http/1.1`` stored in |in| like this::
|
||||
* .. warning::
|
||||
*
|
||||
* Deprecated. Use `nghttp2_select_alpn` instead.
|
||||
*
|
||||
* A helper function for dealing with 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,
|
||||
* ``h2`` and ``http/1.1`` stored in |in| like this::
|
||||
*
|
||||
* in[0] = 2
|
||||
* in[1..2] = "h2"
|
||||
@@ -5051,20 +5054,18 @@ NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs,
|
||||
*
|
||||
* For ALPN, refer to https://tools.ietf.org/html/rfc7301
|
||||
*
|
||||
* See http://technotes.googlecode.com/git/nextprotoneg.html for more
|
||||
* details about NPN.
|
||||
* To use this method you should do something like::
|
||||
*
|
||||
* For NPN, to use this method you should do something like::
|
||||
*
|
||||
* static int select_next_proto_cb(SSL* ssl,
|
||||
* unsigned char **out,
|
||||
* static int alpn_select_proto_cb(SSL* ssl,
|
||||
* const unsigned char **out,
|
||||
* unsigned char *outlen,
|
||||
* const unsigned char *in,
|
||||
* unsigned int inlen,
|
||||
* void *arg)
|
||||
* {
|
||||
* int rv;
|
||||
* rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
|
||||
* rv = nghttp2_select_next_protocol((unsigned char**)out, outlen,
|
||||
* in, inlen);
|
||||
* if (rv == -1) {
|
||||
* return SSL_TLSEXT_ERR_NOACK;
|
||||
* }
|
||||
@@ -5074,7 +5075,7 @@ NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs,
|
||||
* return SSL_TLSEXT_ERR_OK;
|
||||
* }
|
||||
* ...
|
||||
* SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, my_obj);
|
||||
* SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, my_obj);
|
||||
*
|
||||
*/
|
||||
NGHTTP2_EXTERN int nghttp2_select_next_protocol(unsigned char **out,
|
||||
@@ -5082,6 +5083,65 @@ NGHTTP2_EXTERN int nghttp2_select_next_protocol(unsigned char **out,
|
||||
const unsigned char *in,
|
||||
unsigned int inlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* A helper function for dealing with 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,
|
||||
* ``h2`` and ``http/1.1`` stored in |in| like this::
|
||||
*
|
||||
* in[0] = 2
|
||||
* in[1..2] = "h2"
|
||||
* in[3] = 8
|
||||
* in[4..11] = "http/1.1"
|
||||
* inlen = 12
|
||||
*
|
||||
* The selection algorithm is as follows:
|
||||
*
|
||||
* 1. If peer's list contains HTTP/2 protocol the library supports,
|
||||
* it is selected and returns 1. The following step is not taken.
|
||||
*
|
||||
* 2. If peer's list contains ``http/1.1``, this function selects
|
||||
* ``http/1.1`` and returns 0. The following step is not taken.
|
||||
*
|
||||
* 3. This function selects nothing and returns -1 (So called
|
||||
* non-overlap case). In this case, |out| and |outlen| are left
|
||||
* untouched.
|
||||
*
|
||||
* 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/rfc7301
|
||||
*
|
||||
* To use this method you should do something like::
|
||||
*
|
||||
* static int alpn_select_proto_cb(SSL* ssl,
|
||||
* const unsigned char **out,
|
||||
* unsigned char *outlen,
|
||||
* const unsigned char *in,
|
||||
* unsigned int inlen,
|
||||
* void *arg)
|
||||
* {
|
||||
* int rv;
|
||||
* rv = nghttp2_select_alpn(out, outlen, in, inlen);
|
||||
* if (rv == -1) {
|
||||
* return SSL_TLSEXT_ERR_NOACK;
|
||||
* }
|
||||
* if (rv == 1) {
|
||||
* ((MyType*)arg)->http2_selected = 1;
|
||||
* }
|
||||
* return SSL_TLSEXT_ERR_OK;
|
||||
* }
|
||||
* ...
|
||||
* SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, my_obj);
|
||||
*
|
||||
*/
|
||||
NGHTTP2_EXTERN int nghttp2_select_alpn(const unsigned char **out,
|
||||
unsigned char *outlen,
|
||||
const unsigned char *in,
|
||||
unsigned int inlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_npn.h"
|
||||
#include "nghttp2_alpn.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static int select_next_protocol(unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen,
|
||||
const char *key, unsigned int keylen) {
|
||||
static int select_alpn(const unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen,
|
||||
const char *key, unsigned int keylen) {
|
||||
unsigned int i;
|
||||
for (i = 0; i + keylen <= inlen; i += (unsigned int)(in[i] + 1)) {
|
||||
if (memcmp(&in[i], key, keylen) == 0) {
|
||||
@@ -45,12 +45,25 @@ static int select_next_protocol(unsigned char **out, unsigned char *outlen,
|
||||
|
||||
int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen) {
|
||||
if (select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN,
|
||||
NGHTTP2_PROTO_ALPN_LEN) == 0) {
|
||||
if (select_alpn((const unsigned char **)out, outlen, in, inlen,
|
||||
NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN) == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (select_next_protocol(out, outlen, in, inlen, NGHTTP2_HTTP_1_1_ALPN,
|
||||
NGHTTP2_HTTP_1_1_ALPN_LEN) == 0) {
|
||||
if (select_alpn((const unsigned char **)out, outlen, in, inlen,
|
||||
NGHTTP2_HTTP_1_1_ALPN, NGHTTP2_HTTP_1_1_ALPN_LEN) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nghttp2_select_alpn(const unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen) {
|
||||
if (select_alpn(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN,
|
||||
NGHTTP2_PROTO_ALPN_LEN) == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (select_alpn(out, outlen, in, inlen, NGHTTP2_HTTP_1_1_ALPN,
|
||||
NGHTTP2_HTTP_1_1_ALPN_LEN) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
@@ -22,8 +22,8 @@
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_NPN_H
|
||||
#define NGHTTP2_NPN_H
|
||||
#ifndef NGHTTP2_ALPN_H
|
||||
#define NGHTTP2_ALPN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
@@ -31,4 +31,4 @@
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#endif /* NGHTTP2_NPN_H */
|
||||
#endif /* NGHTTP2_ALPN_H */
|
||||
@@ -725,7 +725,7 @@ int Http2Handler::tls_handshake() {
|
||||
std::cerr << "SSL/TLS handshake completed" << std::endl;
|
||||
}
|
||||
|
||||
if (verify_npn_result() != 0) {
|
||||
if (verify_alpn_result() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -892,25 +892,18 @@ int Http2Handler::connection_made() {
|
||||
return on_write();
|
||||
}
|
||||
|
||||
int Http2Handler::verify_npn_result() {
|
||||
int Http2Handler::verify_alpn_result() {
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
// Check the negotiated protocol in NPN or ALPN
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (next_proto) {
|
||||
auto proto = StringRef{next_proto, next_proto_len};
|
||||
if (sessions_->get_config()->verbose) {
|
||||
std::cout << "The negotiated protocol: " << proto << std::endl;
|
||||
}
|
||||
if (util::check_h2_is_selected(proto)) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
SSL_get0_alpn_selected(ssl_, &next_proto, &next_proto_len);
|
||||
// Check the negotiated protocol in ALPN
|
||||
SSL_get0_alpn_selected(ssl_, &next_proto, &next_proto_len);
|
||||
if (next_proto) {
|
||||
auto proto = StringRef{next_proto, next_proto_len};
|
||||
if (sessions_->get_config()->verbose) {
|
||||
std::cout << "The negotiated protocol: " << proto << std::endl;
|
||||
}
|
||||
if (util::check_h2_is_selected(proto)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (sessions_->get_config()->verbose) {
|
||||
@@ -1988,18 +1981,6 @@ HttpServer::HttpServer(const Config *config) : config_(config) {
|
||||
};
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
namespace {
|
||||
int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
|
||||
void *arg) {
|
||||
auto next_proto = static_cast<std::vector<unsigned char> *>(arg);
|
||||
*data = next_proto->data();
|
||||
*len = next_proto->size();
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
namespace {
|
||||
int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
|
||||
// We don't verify the client certificate. Just request it for the
|
||||
@@ -2222,9 +2203,6 @@ int HttpServer::run() {
|
||||
|
||||
next_proto = util::get_default_alpn();
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, &next_proto);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
// ALPN selection callback
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, this);
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ public:
|
||||
int on_read();
|
||||
int on_write();
|
||||
int connection_made();
|
||||
int verify_npn_result();
|
||||
int verify_alpn_result();
|
||||
|
||||
int submit_file_response(const StringRef &status, Stream *stream,
|
||||
time_t last_modified, off_t file_length,
|
||||
|
||||
@@ -155,8 +155,8 @@ bool Config::has_base_uri() const { return (!this->base_uri.empty()); }
|
||||
bool Config::rps_enabled() const { return this->rps > 0.0; }
|
||||
bool Config::is_quic() const {
|
||||
#ifdef ENABLE_HTTP3
|
||||
return !npn_list.empty() &&
|
||||
(npn_list[0] == NGHTTP3_ALPN_H3 || npn_list[0] == "\x5h3-29");
|
||||
return !alpn_list.empty() &&
|
||||
(alpn_list[0] == NGHTTP3_ALPN_H3 || alpn_list[0] == "\x5h3-29");
|
||||
#else // !ENABLE_HTTP3
|
||||
return false;
|
||||
#endif // !ENABLE_HTTP3
|
||||
@@ -1095,12 +1095,7 @@ int Client::connection_made() {
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
if (next_proto == nullptr) {
|
||||
SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
|
||||
|
||||
if (next_proto) {
|
||||
auto proto = StringRef{next_proto, next_proto_len};
|
||||
@@ -1128,11 +1123,10 @@ int Client::connection_made() {
|
||||
std::cout << "No protocol negotiated. Fallback behaviour may be activated"
|
||||
<< std::endl;
|
||||
|
||||
for (const auto &proto : config.npn_list) {
|
||||
for (const auto &proto : config.alpn_list) {
|
||||
if (util::streq(NGHTTP2_H1_1_ALPN, StringRef{proto})) {
|
||||
std::cout
|
||||
<< "Server does not support NPN/ALPN. Falling back to HTTP/1.1."
|
||||
<< std::endl;
|
||||
std::cout << "Server does not support ALPN. Falling back to HTTP/1.1."
|
||||
<< std::endl;
|
||||
session = std::make_unique<Http1Session>(this);
|
||||
selected_proto = NGHTTP2_H1_1.str();
|
||||
break;
|
||||
@@ -1148,7 +1142,7 @@ int Client::connection_made() {
|
||||
std::cout
|
||||
<< "No supported protocol was negotiated. Supported protocols were:"
|
||||
<< std::endl;
|
||||
for (const auto &proto : config.npn_list) {
|
||||
for (const auto &proto : config.alpn_list) {
|
||||
std::cout << proto.substr(1) << std::endl;
|
||||
}
|
||||
disconnect();
|
||||
@@ -1882,23 +1876,6 @@ std::string get_reqline(const char *uri, const http_parser_url &u) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
namespace {
|
||||
int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
if (util::select_protocol(const_cast<const unsigned char **>(out), outlen, in,
|
||||
inlen, config.npn_list)) {
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
// OpenSSL will terminate handshake with fatal alert if we return
|
||||
// NOACK. So there is no way to fallback.
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
} // namespace
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
namespace {
|
||||
constexpr char UNIX_PATH_PREFIX[] = "unix:";
|
||||
} // namespace
|
||||
@@ -2110,7 +2087,7 @@ benchmarking tool for HTTP/2 server)"
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
constexpr char DEFAULT_NPN_LIST[] = "h2,h2-16,h2-14,http/1.1";
|
||||
constexpr char DEFAULT_ALPN_LIST[] = "h2,h2-16,h2-14,http/1.1";
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
@@ -2270,16 +2247,15 @@ Options:
|
||||
instead of TCP. In this case, scheme is inferred from
|
||||
the first URI appeared in the command line or inside
|
||||
input files as usual.
|
||||
--npn-list=<LIST>
|
||||
--alpn-list=<LIST>
|
||||
Comma delimited list of ALPN protocol identifier sorted
|
||||
in the order of preference. That means most desirable
|
||||
protocol comes first. This is used in both ALPN and
|
||||
NPN. The parameter must be delimited by a single comma
|
||||
only and any white spaces are treated as a part of
|
||||
protocol string.
|
||||
protocol comes first. The parameter must be delimited
|
||||
by a single comma only and any white spaces are treated
|
||||
as a part of protocol string.
|
||||
Default: )"
|
||||
<< DEFAULT_NPN_LIST << R"(
|
||||
--h1 Short hand for --npn-list=http/1.1
|
||||
<< DEFAULT_ALPN_LIST << R"(
|
||||
--h1 Short hand for --alpn-list=http/1.1
|
||||
--no-tls-proto=http/1.1, which effectively force
|
||||
http/1.1 for both http and https URI.
|
||||
--header-table-size=<SIZE>
|
||||
@@ -2383,6 +2359,7 @@ int main(int argc, char **argv) {
|
||||
{"qlog-file-base", required_argument, &flag, 16},
|
||||
{"max-udp-payload-size", required_argument, &flag, 17},
|
||||
{"ktls", no_argument, &flag, 18},
|
||||
{"alpn-list", required_argument, &flag, 19},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
int option_index = 0;
|
||||
auto c = getopt_long(argc, argv,
|
||||
@@ -2610,10 +2587,6 @@ int main(int argc, char **argv) {
|
||||
config.ifile = optarg;
|
||||
config.timing_script = true;
|
||||
break;
|
||||
case 4:
|
||||
// npn-list option
|
||||
config.npn_list = util::parse_config_str_list(StringRef{optarg});
|
||||
break;
|
||||
case 5:
|
||||
// rate-period
|
||||
config.rate_period = util::parse_duration_with_unit(optarg);
|
||||
@@ -2624,7 +2597,7 @@ int main(int argc, char **argv) {
|
||||
break;
|
||||
case 6:
|
||||
// --h1
|
||||
config.npn_list =
|
||||
config.alpn_list =
|
||||
util::parse_config_str_list(StringRef::from_lit("http/1.1"));
|
||||
config.no_tls_proto = Config::PROTO_HTTP1_1;
|
||||
break;
|
||||
@@ -2714,6 +2687,15 @@ int main(int argc, char **argv) {
|
||||
// --ktls
|
||||
config.ktls = true;
|
||||
break;
|
||||
case 4:
|
||||
// npn-list option
|
||||
std::cerr << "--npn-list: deprecated. Use --alpn-list instead."
|
||||
<< std::endl;
|
||||
// fall through
|
||||
case 19:
|
||||
// alpn-list option
|
||||
config.alpn_list = util::parse_config_str_list(StringRef{optarg});
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -2734,13 +2716,13 @@ int main(int argc, char **argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (config.npn_list.empty()) {
|
||||
config.npn_list =
|
||||
util::parse_config_str_list(StringRef::from_lit(DEFAULT_NPN_LIST));
|
||||
if (config.alpn_list.empty()) {
|
||||
config.alpn_list =
|
||||
util::parse_config_str_list(StringRef::from_lit(DEFAULT_ALPN_LIST));
|
||||
}
|
||||
|
||||
// serialize the APLN tokens
|
||||
for (auto &proto : config.npn_list) {
|
||||
for (auto &proto : config.alpn_list) {
|
||||
proto.insert(proto.begin(), static_cast<unsigned char>(proto.size()));
|
||||
}
|
||||
|
||||
@@ -2980,13 +2962,8 @@ int main(int argc, char **argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, client_select_next_proto_cb,
|
||||
nullptr);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
std::vector<unsigned char> proto_list;
|
||||
for (const auto &proto : config.npn_list) {
|
||||
for (const auto &proto : config.alpn_list) {
|
||||
std::copy_n(proto.c_str(), proto.size(), std::back_inserter(proto_list));
|
||||
}
|
||||
|
||||
|
||||
@@ -127,9 +127,9 @@ struct Config {
|
||||
bool base_uri_unix;
|
||||
// used when UNIX domain socket is used (base_uri_unix is true).
|
||||
sockaddr_un unix_addr;
|
||||
// list of supported NPN/ALPN protocol strings in the order of
|
||||
// list of supported ALPN protocol strings in the order of
|
||||
// preference.
|
||||
std::vector<std::string> npn_list;
|
||||
std::vector<std::string> alpn_list;
|
||||
// The number of request per second for each client.
|
||||
double rps;
|
||||
// Disables GSO for UDP connections.
|
||||
|
||||
@@ -438,11 +438,11 @@ int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
|
||||
},
|
||||
};
|
||||
|
||||
assert(config->npn_list.size());
|
||||
assert(config->alpn_list.size());
|
||||
|
||||
uint32_t quic_version;
|
||||
|
||||
if (config->npn_list[0] == NGHTTP3_ALPN_H3) {
|
||||
if (config->alpn_list[0] == NGHTTP3_ALPN_H3) {
|
||||
quic_version = NGTCP2_PROTO_VER_V1;
|
||||
} else {
|
||||
quic_version = NGTCP2_PROTO_VER_MIN;
|
||||
|
||||
@@ -1115,24 +1115,19 @@ int HttpClient::connection_made() {
|
||||
}
|
||||
|
||||
if (ssl) {
|
||||
// Check NPN or ALPN result
|
||||
// Check ALPN result
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (next_proto) {
|
||||
auto proto = StringRef{next_proto, next_proto_len};
|
||||
if (config.verbose) {
|
||||
std::cout << "The negotiated protocol: " << proto << std::endl;
|
||||
}
|
||||
if (!util::check_h2_is_selected(proto)) {
|
||||
next_proto = nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
|
||||
if (next_proto) {
|
||||
auto proto = StringRef{next_proto, next_proto_len};
|
||||
if (config.verbose) {
|
||||
std::cout << "The negotiated protocol: " << proto << std::endl;
|
||||
}
|
||||
if (!util::check_h2_is_selected(proto)) {
|
||||
next_proto = nullptr;
|
||||
}
|
||||
SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
if (!next_proto) {
|
||||
print_protocol_nego_error();
|
||||
@@ -2242,32 +2237,6 @@ id responseEnd requestStart process code size request path)"
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
namespace {
|
||||
int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
if (config.verbose) {
|
||||
print_timer();
|
||||
std::cout << "[NPN] server offers:" << std::endl;
|
||||
}
|
||||
for (unsigned int i = 0; i < inlen; i += in[i] + 1) {
|
||||
if (config.verbose) {
|
||||
std::cout << " * ";
|
||||
std::cout.write(reinterpret_cast<const char *>(&in[i + 1]), in[i]);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
if (!util::select_h2(const_cast<const unsigned char **>(out), outlen, in,
|
||||
inlen)) {
|
||||
print_protocol_nego_error();
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
namespace {
|
||||
int communicate(
|
||||
const std::string &scheme, const std::string &host, uint16_t port,
|
||||
@@ -2338,10 +2307,6 @@ int communicate(
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, client_select_next_proto_cb,
|
||||
nullptr);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
auto proto_list = util::get_default_alpn();
|
||||
|
||||
|
||||
24
src/shrpx.cc
24
src/shrpx.cc
@@ -1911,7 +1911,7 @@ bool conf_exists(const char *path) {
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
constexpr auto DEFAULT_NPN_LIST =
|
||||
constexpr auto DEFAULT_ALPN_LIST =
|
||||
StringRef::from_lit("h2,h2-16,h2-14,http/1.1");
|
||||
} // namespace
|
||||
|
||||
@@ -2798,15 +2798,14 @@ SSL/TLS:
|
||||
Path to file that contains DH parameters in PEM format.
|
||||
Without this option, DHE cipher suites are not
|
||||
available.
|
||||
--npn-list=<LIST>
|
||||
--alpn-list=<LIST>
|
||||
Comma delimited list of ALPN protocol identifier sorted
|
||||
in the order of preference. That means most desirable
|
||||
protocol comes first. This is used in both ALPN and
|
||||
NPN. The parameter must be delimited by a single comma
|
||||
only and any white spaces are treated as a part of
|
||||
protocol string.
|
||||
protocol comes first. The parameter must be delimited
|
||||
by a single comma only and any white spaces are treated
|
||||
as a part of protocol string.
|
||||
Default: )"
|
||||
<< DEFAULT_NPN_LIST
|
||||
<< DEFAULT_ALPN_LIST
|
||||
<< R"(
|
||||
--verify-client
|
||||
Require and verify client certificate.
|
||||
@@ -3750,8 +3749,8 @@ int process_options(Config *config,
|
||||
|
||||
auto &tlsconf = config->tls;
|
||||
|
||||
if (tlsconf.npn_list.empty()) {
|
||||
tlsconf.npn_list = util::split_str(DEFAULT_NPN_LIST, ',');
|
||||
if (tlsconf.alpn_list.empty()) {
|
||||
tlsconf.alpn_list = util::split_str(DEFAULT_ALPN_LIST, ',');
|
||||
}
|
||||
|
||||
if (!tlsconf.tls_proto_list.empty()) {
|
||||
@@ -3766,7 +3765,7 @@ int process_options(Config *config,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tls::set_alpn_prefs(tlsconf.alpn_prefs, tlsconf.npn_list) != 0) {
|
||||
if (tls::set_alpn_prefs(tlsconf.alpn_prefs, tlsconf.alpn_list) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -4377,6 +4376,7 @@ int main(int argc, char **argv) {
|
||||
190},
|
||||
{SHRPX_OPT_REQUIRE_HTTP_SCHEME.c_str(), no_argument, &flag, 191},
|
||||
{SHRPX_OPT_TLS_KTLS.c_str(), no_argument, &flag, 192},
|
||||
{SHRPX_OPT_ALPN_LIST.c_str(), required_argument, &flag, 193},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
|
||||
int option_index = 0;
|
||||
@@ -5290,6 +5290,10 @@ int main(int argc, char **argv) {
|
||||
// --tls-ktls
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_TLS_KTLS, StringRef::from_lit("yes"));
|
||||
break;
|
||||
case 193:
|
||||
// --alpn-list
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_ALPN_LIST, StringRef{optarg});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -616,12 +616,7 @@ int ClientHandler::validate_next_proto() {
|
||||
// First set callback for catch all cases
|
||||
on_read_ = &ClientHandler::upstream_read;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
if (next_proto == nullptr) {
|
||||
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
|
||||
StringRef proto;
|
||||
|
||||
@@ -639,7 +634,7 @@ int ClientHandler::validate_next_proto() {
|
||||
proto = StringRef::from_lit("http/1.1");
|
||||
}
|
||||
|
||||
if (!tls::in_proto_list(get_config()->tls.npn_list, proto)) {
|
||||
if (!tls::in_proto_list(get_config()->tls.alpn_list, proto)) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "The negotiated protocol is not supported: " << proto;
|
||||
}
|
||||
|
||||
@@ -1912,6 +1912,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||
return SHRPX_OPTID_LOG_LEVEL;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (util::strieq_l("alpn-lis", name, 8)) {
|
||||
return SHRPX_OPTID_ALPN_LIST;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
@@ -3341,15 +3346,6 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
||||
case SHRPX_OPTID_WORKER_WRITE_BURST:
|
||||
LOG(WARN) << opt << ": not implemented yet";
|
||||
return 0;
|
||||
case SHRPX_OPTID_NPN_LIST: {
|
||||
auto list = util::split_str(optarg, ',');
|
||||
config->tls.npn_list.resize(list.size());
|
||||
for (size_t i = 0; i < list.size(); ++i) {
|
||||
config->tls.npn_list[i] = make_string_ref(config->balloc, list[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
case SHRPX_OPTID_TLS_PROTO_LIST: {
|
||||
LOG(WARN) << opt
|
||||
<< ": deprecated. Use tls-min-proto-version and "
|
||||
@@ -4174,6 +4170,18 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
||||
case SHRPX_OPTID_TLS_KTLS:
|
||||
config->tls.ktls = util::strieq_l("yes", optarg);
|
||||
return 0;
|
||||
case SHRPX_OPTID_NPN_LIST:
|
||||
LOG(WARN) << opt << ": deprecated. Use alpn-list instead.";
|
||||
// fall through
|
||||
case SHRPX_OPTID_ALPN_LIST: {
|
||||
auto list = util::split_str(optarg, ',');
|
||||
config->tls.alpn_list.resize(list.size());
|
||||
for (size_t i = 0; i < list.size(); ++i) {
|
||||
config->tls.alpn_list[i] = make_string_ref(config->balloc, list[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
case SHRPX_OPTID_CONF:
|
||||
LOG(WARN) << "conf: ignored";
|
||||
|
||||
|
||||
@@ -405,6 +405,7 @@ constexpr auto SHRPX_OPT_FRONTEND_QUIC_INITIAL_RTT =
|
||||
constexpr auto SHRPX_OPT_REQUIRE_HTTP_SCHEME =
|
||||
StringRef::from_lit("require-http-scheme");
|
||||
constexpr auto SHRPX_OPT_TLS_KTLS = StringRef::from_lit("tls-ktls");
|
||||
constexpr auto SHRPX_OPT_ALPN_LIST = StringRef::from_lit("alpn-list");
|
||||
|
||||
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
||||
|
||||
@@ -753,9 +754,9 @@ struct TLSConfig {
|
||||
// The list of additional TLS certificate pair
|
||||
std::vector<TLSCertificate> subcerts;
|
||||
std::vector<unsigned char> alpn_prefs;
|
||||
// list of supported NPN/ALPN protocol strings in the order of
|
||||
// list of supported ALPN protocol strings in the order of
|
||||
// preference.
|
||||
std::vector<StringRef> npn_list;
|
||||
std::vector<StringRef> alpn_list;
|
||||
// list of supported SSL/TLS protocol strings.
|
||||
std::vector<StringRef> tls_proto_list;
|
||||
std::vector<uint8_t> sct_data;
|
||||
@@ -1183,6 +1184,7 @@ enum {
|
||||
SHRPX_OPTID_ADD_REQUEST_HEADER,
|
||||
SHRPX_OPTID_ADD_RESPONSE_HEADER,
|
||||
SHRPX_OPTID_ADD_X_FORWARDED_FOR,
|
||||
SHRPX_OPTID_ALPN_LIST,
|
||||
SHRPX_OPTID_ALTSVC,
|
||||
SHRPX_OPTID_API_MAX_REQUEST_BODY,
|
||||
SHRPX_OPTID_BACKEND,
|
||||
|
||||
@@ -794,12 +794,7 @@ int Connection::check_http2_requirement() {
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(tls.ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
if (next_proto == nullptr) {
|
||||
SSL_get0_alpn_selected(tls.ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
SSL_get0_alpn_selected(tls.ssl, &next_proto, &next_proto_len);
|
||||
if (next_proto == nullptr ||
|
||||
!util::check_h2_is_selected(StringRef{next_proto, next_proto_len})) {
|
||||
return 0;
|
||||
|
||||
@@ -265,7 +265,7 @@ int ConnectionHandler::create_single_worker() {
|
||||
nb_,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
tlsconf.cacert, memcachedconf.cert_file,
|
||||
memcachedconf.private_key_file, nullptr);
|
||||
memcachedconf.private_key_file);
|
||||
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
|
||||
#ifdef ENABLE_HTTP3
|
||||
quic_all_ssl_ctx_.push_back(nullptr);
|
||||
@@ -367,7 +367,7 @@ int ConnectionHandler::create_worker_thread(size_t num) {
|
||||
nb_,
|
||||
# endif // HAVE_NEVERBLEED
|
||||
tlsconf.cacert, memcachedconf.cert_file,
|
||||
memcachedconf.private_key_file, nullptr);
|
||||
memcachedconf.private_key_file);
|
||||
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
|
||||
# ifdef ENABLE_HTTP3
|
||||
quic_all_ssl_ctx_.push_back(nullptr);
|
||||
@@ -935,8 +935,7 @@ SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() {
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
nb_,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
tlsconf.cacert, memcachedconf.cert_file, memcachedconf.private_key_file,
|
||||
nullptr);
|
||||
tlsconf.cacert, memcachedconf.cert_file, memcachedconf.private_key_file);
|
||||
|
||||
all_ssl_ctx_.push_back(ssl_ctx);
|
||||
#ifdef ENABLE_HTTP3
|
||||
|
||||
@@ -1672,12 +1672,7 @@ int Http2Session::connection_made() {
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len = 0;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
if (!next_proto) {
|
||||
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
|
||||
if (!next_proto) {
|
||||
downstream_failure(addr_, raddr_);
|
||||
|
||||
@@ -405,12 +405,7 @@ int LiveCheck::tls_handshake() {
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len = 0;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
if (next_proto == nullptr) {
|
||||
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
|
||||
auto proto = StringRef{next_proto, next_proto_len};
|
||||
|
||||
|
||||
@@ -96,18 +96,6 @@ namespace shrpx {
|
||||
|
||||
namespace tls {
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
namespace {
|
||||
int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
|
||||
void *arg) {
|
||||
auto &prefs = get_config()->tls.alpn_prefs;
|
||||
*data = prefs.data();
|
||||
*len = prefs.size();
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
namespace {
|
||||
int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
|
||||
if (!preverify_ok) {
|
||||
@@ -650,10 +638,10 @@ namespace {
|
||||
int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
// We assume that get_config()->npn_list contains ALPN protocol
|
||||
// We assume that get_config()->alpn_list contains ALPN protocol
|
||||
// identifier sorted by preference order. So we just break when we
|
||||
// found the first overlap.
|
||||
for (const auto &target_proto_id : get_config()->tls.npn_list) {
|
||||
for (const auto &target_proto_id : get_config()->tls.alpn_list) {
|
||||
for (auto p = in, end = in + inlen; p < end;) {
|
||||
auto proto_id = p + 1;
|
||||
auto proto_len = *p;
|
||||
@@ -1065,10 +1053,6 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
|
||||
SSL_CTX_set_early_data_enabled(ssl_ctx, 1);
|
||||
#endif // NGHTTP2_OPENSSL_IS_BORINGSSL
|
||||
|
||||
// NPN advertisement
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, nullptr);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
// ALPN selection callback
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, nullptr);
|
||||
|
||||
@@ -1384,62 +1368,12 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file,
|
||||
}
|
||||
#endif // ENABLE_HTTP3
|
||||
|
||||
namespace {
|
||||
int select_h2_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
if (!util::select_h2(const_cast<const unsigned char **>(out), outlen, in,
|
||||
inlen)) {
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int select_h1_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
auto end = in + inlen;
|
||||
for (; in < end;) {
|
||||
if (util::streq(NGHTTP2_H1_1_ALPN, StringRef{in, in + (in[0] + 1)})) {
|
||||
*out = const_cast<unsigned char *>(in) + 1;
|
||||
*outlen = in[0];
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
in += in[0] + 1;
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int select_next_proto_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen,
|
||||
void *arg) {
|
||||
auto conn = static_cast<Connection *>(SSL_get_app_data(ssl));
|
||||
switch (conn->proto) {
|
||||
case Proto::HTTP1:
|
||||
return select_h1_next_proto_cb(ssl, out, outlen, in, inlen, arg);
|
||||
case Proto::HTTP2:
|
||||
return select_h2_next_proto_cb(ssl, out, outlen, in, inlen, arg);
|
||||
default:
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
SSL_CTX *create_ssl_client_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
neverbleed_t *nb,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
const StringRef &cacert, const StringRef &cert_file,
|
||||
const StringRef &private_key_file,
|
||||
int (*next_proto_select_cb)(SSL *s, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg)) {
|
||||
const StringRef &private_key_file) {
|
||||
auto ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||
if (!ssl_ctx) {
|
||||
LOG(FATAL) << ERR_error_string(ERR_get_error(), nullptr);
|
||||
@@ -1539,12 +1473,6 @@ SSL_CTX *create_ssl_client_context(
|
||||
SSL_CTX_set_psk_client_callback(ssl_ctx, psk_client_cb);
|
||||
#endif // !OPENSSL_NO_PSK
|
||||
|
||||
// NPN selection callback. This is required to set SSL_CTX because
|
||||
// OpenSSL does not offer SSL_set_next_proto_select_cb.
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_cb, nullptr);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
@@ -2249,8 +2177,8 @@ SSL_CTX *setup_downstream_client_ssl_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
nb,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
tlsconf.cacert, tlsconf.client.cert_file, tlsconf.client.private_key_file,
|
||||
select_next_proto_cb);
|
||||
tlsconf.cacert, tlsconf.client.cert_file,
|
||||
tlsconf.client.private_key_file);
|
||||
}
|
||||
|
||||
void setup_downstream_http2_alpn(SSL *ssl) {
|
||||
|
||||
@@ -89,28 +89,12 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
|
||||
);
|
||||
|
||||
// Create client side SSL_CTX. This does not configure ALPN settings.
|
||||
// |next_proto_select_cb| is for NPN.
|
||||
SSL_CTX *create_ssl_client_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
neverbleed_t *nb,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
const StringRef &cacert, const StringRef &cert_file,
|
||||
const StringRef &private_key_file,
|
||||
int (*next_proto_select_cb)(SSL *s, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg));
|
||||
|
||||
#ifdef ENABLE_HTTP3
|
||||
SSL_CTX *create_quic_ssl_client_context(
|
||||
# ifdef HAVE_NEVERBLEED
|
||||
neverbleed_t *nb,
|
||||
# endif // HAVE_NEVERBLEED
|
||||
const StringRef &cacert, const StringRef &cert_file,
|
||||
const StringRef &private_key_file,
|
||||
int (*next_proto_select_cb)(SSL *s, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg));
|
||||
#endif // ENABLE_HTTP3
|
||||
const StringRef &private_key_file);
|
||||
|
||||
ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
|
||||
int addrlen, const UpstreamAddr *faddr);
|
||||
|
||||
@@ -17,7 +17,7 @@ if(HAVE_CUNIT)
|
||||
nghttp2_stream_test.c
|
||||
nghttp2_session_test.c
|
||||
nghttp2_hd_test.c
|
||||
nghttp2_npn_test.c
|
||||
nghttp2_alpn_test.c
|
||||
nghttp2_helper_test.c
|
||||
nghttp2_buf_test.c
|
||||
nghttp2_http_test.c
|
||||
|
||||
@@ -38,7 +38,7 @@ OBJECTS = main.c nghttp2_pq_test.c nghttp2_map_test.c nghttp2_queue_test.c \
|
||||
nghttp2_stream_test.c \
|
||||
nghttp2_session_test.c \
|
||||
nghttp2_hd_test.c \
|
||||
nghttp2_npn_test.c \
|
||||
nghttp2_alpn_test.c \
|
||||
nghttp2_helper_test.c \
|
||||
nghttp2_buf_test.c \
|
||||
nghttp2_http_test.c \
|
||||
@@ -48,7 +48,7 @@ OBJECTS = main.c nghttp2_pq_test.c nghttp2_map_test.c nghttp2_queue_test.c \
|
||||
HFILES = nghttp2_pq_test.h nghttp2_map_test.h nghttp2_queue_test.h \
|
||||
nghttp2_session_test.h \
|
||||
nghttp2_frame_test.h nghttp2_stream_test.h nghttp2_hd_test.h \
|
||||
nghttp2_npn_test.h nghttp2_helper_test.h \
|
||||
nghttp2_alpn_test.h nghttp2_helper_test.h \
|
||||
nghttp2_test_helper.h \
|
||||
nghttp2_buf_test.h \
|
||||
nghttp2_http_test.h \
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "nghttp2_frame_test.h"
|
||||
#include "nghttp2_stream_test.h"
|
||||
#include "nghttp2_hd_test.h"
|
||||
#include "nghttp2_npn_test.h"
|
||||
#include "nghttp2_alpn_test.h"
|
||||
#include "nghttp2_helper_test.h"
|
||||
#include "nghttp2_buf_test.h"
|
||||
#include "nghttp2_http_test.h"
|
||||
@@ -75,7 +75,7 @@ int main(void) {
|
||||
!CU_add_test(pSuite, "map_functional", test_nghttp2_map_functional) ||
|
||||
!CU_add_test(pSuite, "map_each_free", test_nghttp2_map_each_free) ||
|
||||
!CU_add_test(pSuite, "queue", test_nghttp2_queue) ||
|
||||
!CU_add_test(pSuite, "npn", test_nghttp2_npn) ||
|
||||
!CU_add_test(pSuite, "alpn", test_nghttp2_alpn) ||
|
||||
!CU_add_test(pSuite, "session_recv", test_nghttp2_session_recv) ||
|
||||
!CU_add_test(pSuite, "session_recv_invalid_stream_id",
|
||||
test_nghttp2_session_recv_invalid_stream_id) ||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_npn_test.h"
|
||||
#include "nghttp2_alpn_test.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -34,8 +34,16 @@ static void http2(void) {
|
||||
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)));
|
||||
const unsigned char *out;
|
||||
CU_ASSERT(1 == nghttp2_select_next_protocol((unsigned char **)&out, &outlen,
|
||||
p, sizeof(p)));
|
||||
CU_ASSERT(NGHTTP2_PROTO_VERSION_ID_LEN == outlen);
|
||||
CU_ASSERT(memcmp(NGHTTP2_PROTO_VERSION_ID, out, outlen) == 0);
|
||||
|
||||
outlen = 0;
|
||||
out = NULL;
|
||||
|
||||
CU_ASSERT(1 == nghttp2_select_alpn(&out, &outlen, p, sizeof(p)));
|
||||
CU_ASSERT(NGHTTP2_PROTO_VERSION_ID_LEN == outlen);
|
||||
CU_ASSERT(memcmp(NGHTTP2_PROTO_VERSION_ID, out, outlen) == 0);
|
||||
}
|
||||
@@ -46,9 +54,16 @@ static void http11(void) {
|
||||
'2', '.', '1', 8, 'h', 't', 't', 'p', '/', '1', '.', '1',
|
||||
};
|
||||
unsigned char outlen;
|
||||
unsigned char *out;
|
||||
CU_ASSERT(0 ==
|
||||
nghttp2_select_next_protocol(&out, &outlen, spdy, sizeof(spdy)));
|
||||
const unsigned char *out;
|
||||
CU_ASSERT(0 == nghttp2_select_next_protocol((unsigned char **)&out, &outlen,
|
||||
spdy, sizeof(spdy)));
|
||||
CU_ASSERT(8 == outlen);
|
||||
CU_ASSERT(memcmp("http/1.1", out, outlen) == 0);
|
||||
|
||||
outlen = 0;
|
||||
out = NULL;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_select_alpn(&out, &outlen, spdy, sizeof(spdy)));
|
||||
CU_ASSERT(8 == outlen);
|
||||
CU_ASSERT(memcmp("http/1.1", out, outlen) == 0);
|
||||
}
|
||||
@@ -59,14 +74,21 @@ static void no_overlap(void) {
|
||||
'2', '.', '1', 8, 'h', 't', 't', 'p', '/', '1', '.', '0',
|
||||
};
|
||||
unsigned char outlen = 0;
|
||||
unsigned char *out = NULL;
|
||||
CU_ASSERT(-1 ==
|
||||
nghttp2_select_next_protocol(&out, &outlen, spdy, sizeof(spdy)));
|
||||
const unsigned char *out = NULL;
|
||||
CU_ASSERT(-1 == nghttp2_select_next_protocol((unsigned char **)&out, &outlen,
|
||||
spdy, sizeof(spdy)));
|
||||
CU_ASSERT(0 == outlen);
|
||||
CU_ASSERT(NULL == out);
|
||||
|
||||
outlen = 0;
|
||||
out = NULL;
|
||||
|
||||
CU_ASSERT(-1 == nghttp2_select_alpn(&out, &outlen, spdy, sizeof(spdy)));
|
||||
CU_ASSERT(0 == outlen);
|
||||
CU_ASSERT(NULL == out);
|
||||
}
|
||||
|
||||
void test_nghttp2_npn(void) {
|
||||
void test_nghttp2_alpn(void) {
|
||||
http2();
|
||||
http11();
|
||||
no_overlap();
|
||||
@@ -22,13 +22,13 @@
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_NPN_TEST_H
|
||||
#define NGHTTP2_NPN_TEST_H
|
||||
#ifndef NGHTTP2_ALPN_TEST_H
|
||||
#define NGHTTP2_ALPN_TEST_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
void test_nghttp2_npn(void);
|
||||
void test_nghttp2_alpn(void);
|
||||
|
||||
#endif /* NGHTTP2_NPN_TEST_H */
|
||||
#endif /* NGHTTP2_ALPN_TEST_H */
|
||||
Reference in New Issue
Block a user