Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
nghttp2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
nghttp2
Commits
d6def22a
Commit
d6def22a
authored
Jun 19, 2016
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update tutorials according to the updated tutorial client/server sources
parent
cdd72bad
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
104 additions
and
2 deletions
+104
-2
doc/sources/tutorial-client.rst
doc/sources/tutorial-client.rst
+43
-0
doc/sources/tutorial-server.rst
doc/sources/tutorial-server.rst
+61
-2
No files found.
doc/sources/tutorial-client.rst
View file @
d6def22a
...
@@ -31,6 +31,17 @@ protocol the library supports::
...
@@ -31,6 +31,17 @@ protocol the library supports::
return SSL_TLSEXT_ERR_OK;
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
The callback is added to the SSL_CTX object using
``SSL_CTX_set_next_proto_select_cb()``::
``SSL_CTX_set_next_proto_select_cb()``::
...
@@ -46,9 +57,18 @@ The callback is added to the SSL_CTX object using
...
@@ -46,9 +57,18 @@ The callback is added to the SSL_CTX object using
SSL_OP_NO_COMPRESSION |
SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
return ssl_ctx;
return ssl_ctx;
}
}
Here we see ``SSL_CTX_get_alpn_protos()`` function call. We instructs
OpenSSL to notify the server that we support h2, ALPN identifier for
HTTP/2.
The example client defines a couple of structs:
The example client defines a couple of structs:
We define and use a ``http2_session_data`` structure to store data
We define and use a ``http2_session_data`` structure to store data
...
@@ -124,7 +144,27 @@ underlying network socket::
...
@@ -124,7 +144,27 @@ underlying network socket::
if (events & BEV_EVENT_CONNECTED) {
if (events & BEV_EVENT_CONNECTED) {
int fd = bufferevent_getfd(bev);
int fd = bufferevent_getfd(bev);
int val = 1;
int val = 1;
const unsigned char *alpn = NULL;
unsigned int alpnlen = 0;
SSL *ssl;
fprintf(stderr, "Connected\n");
fprintf(stderr, "Connected\n");
ssl = bufferevent_openssl_get_ssl(session_data->bev);
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (alpn == NULL) {
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
}
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
fprintf(stderr, "h2 is not negotiated\n");
delete_http2_session_data(session_data);
return;
}
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
initialize_nghttp2_session(session_data);
initialize_nghttp2_session(session_data);
send_client_connection_header(session_data);
send_client_connection_header(session_data);
...
@@ -144,6 +184,9 @@ underlying network socket::
...
@@ -144,6 +184,9 @@ underlying network socket::
delete_http2_session_data(session_data);
delete_http2_session_data(session_data);
}
}
Here we validate that HTTP/2 is negotiated, and if not, drop
connection.
For ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR``, and ``BEV_EVENT_TIMEOUT``
For ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR``, and ``BEV_EVENT_TIMEOUT``
events, we just simply tear down the connection.
events, we just simply tear down the connection.
...
...
doc/sources/tutorial-server.rst
View file @
d6def22a
...
@@ -25,7 +25,17 @@ application protocols the server supports to a client. In this
...
@@ -25,7 +25,17 @@ application protocols the server supports to a client. In this
example program, when creating the ``SSL_CTX`` object, we store the
example program, when creating the ``SSL_CTX`` object, we store the
application protocol name in the wire format of NPN in a statically
application protocol name in the wire format of NPN in a statically
allocated buffer. This is safe because we only create one ``SSL_CTX``
allocated buffer. This is safe because we only create one ``SSL_CTX``
object in the program's entire lifetime::
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 unsigned char next_proto_list[256];
static size_t next_proto_list_len;
static size_t next_proto_list_len;
...
@@ -37,6 +47,22 @@ object in the program's entire lifetime::
...
@@ -37,6 +47,22 @@ object in the program's entire lifetime::
return SSL_TLSEXT_ERR_OK;
return SSL_TLSEXT_ERR_OK;
}
}
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
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);
if (rv != 1) {
return SSL_TLSEXT_ERR_NOACK;
}
return SSL_TLSEXT_ERR_OK;
}
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
SSL_CTX *ssl_ctx;
SSL_CTX *ssl_ctx;
EC_KEY *ecdh;
EC_KEY *ecdh;
...
@@ -51,6 +77,11 @@ object in the program's entire lifetime::
...
@@ -51,6 +77,11 @@ object in the program's entire lifetime::
next_proto_list_len = 1 + 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_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL);
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
return ssl_ctx;
return ssl_ctx;
}
}
...
@@ -64,6 +95,11 @@ OpenSSL implementation, we just assign the pointer to the NPN buffers
...
@@ -64,6 +95,11 @@ OpenSSL implementation, we just assign the pointer to the NPN buffers
we filled in earlier. The NPN callback function is set to the
we filled in earlier. The NPN callback function is set to the
``SSL_CTX`` object using ``SSL_CTX_set_next_protos_advertised_cb()``.
``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
parameters were assigned accordingly.
Next, let's take a look at the main structures used by the example
Next, let's take a look at the main structures used by the example
application:
application:
...
@@ -167,11 +203,31 @@ underlying network socket::
...
@@ -167,11 +203,31 @@ underlying network socket::
static void eventcb(struct bufferevent *bev _U_, short events, void *ptr) {
static void eventcb(struct bufferevent *bev _U_, short events, void *ptr) {
http2_session_data *session_data = (http2_session_data *)ptr;
http2_session_data *session_data = (http2_session_data *)ptr;
if (events & BEV_EVENT_CONNECTED) {
if (events & BEV_EVENT_CONNECTED) {
const unsigned char *alpn = NULL;
unsigned int alpnlen = 0;
SSL *ssl;
fprintf(stderr, "%s connected\n", session_data->client_addr);
fprintf(stderr, "%s connected\n", session_data->client_addr);
ssl = bufferevent_openssl_get_ssl(session_data->bev);
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (alpn == NULL) {
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
}
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
fprintf(stderr, "%s h2 is not negotiated\n", session_data->client_addr);
delete_http2_session_data(session_data);
return;
}
initialize_nghttp2_session(session_data);
initialize_nghttp2_session(session_data);
if (send_server_connection_header(session_data) != 0) {
if (send_server_connection_header(session_data) != 0 ||
session_send(session_data) != 0) {
delete_http2_session_data(session_data);
delete_http2_session_data(session_data);
return;
return;
}
}
...
@@ -188,6 +244,9 @@ underlying network socket::
...
@@ -188,6 +244,9 @@ underlying network socket::
delete_http2_session_data(session_data);
delete_http2_session_data(session_data);
}
}
Here we validate that HTTP/2 is negotiated, and if not, drop
connection.
For the ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR``, and
For the ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR``, and
``BEV_EVENT_TIMEOUT`` events, we just simply tear down the connection.
``BEV_EVENT_TIMEOUT`` events, we just simply tear down the connection.
The ``delete_http2_session_data()`` function destroys the
The ``delete_http2_session_data()`` function destroys the
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment