Skip to content

Integrating nghttp2-asio With Existing HTTP/1.1 Code #1

Description

@DragonOsman

Like I said elsewhere, I have this server app that I've enabled ALPN in that I want to support HTTP/2 in. I want to use the nghttp2 C++ API directly instead of dropping it in as a reverse proxy. Could you point me to a good example that shows how to do this? And where and what functions should I call from the nghttp2 library to do this?

I have this code in main:

                tcp::acceptor acceptor{ ioc, { address, port } };
		std::cout << "Starting server at " << address << ':' << port << "...\n";
		for (;;)
		{
			// This will receive the new connection
			tcp::socket socket{ ioc };

			// Block until we get a connection
			acceptor.accept(socket);

			// Launch the session, transferring ownership of the socket
			std::thread([=, socket = std::move(socket), &ctx]() mutable {
				do_session(socket, ctx, doc_root, googlekey, currencykey);
			}).detach();
		}

This is how I'm running the server. And I also have this code in do_session:

        // Construct the stream around the socket
	ssl::stream<tcp::socket&> stream{ socket, ctx };

	// call client hello processing function and pass in callback
	auto ssl_ctx{ ctx.native_handle() };
	SSL* ssl{ SSL_new(ssl_ctx) };
	int alert_val{ 1 };
	int* alert{ &alert_val };
	void* arg{};
	SSL_CTX_set_client_hello_cb(ssl_ctx, set_client_hello_cb(ssl, alert, arg), nullptr);

	// Perform the SSL handshake
	stream.handshake(ssl::stream_base::server, ec);
	if (ec)
	{
		std::cerr << "Lines 692 and 693:\n";
		fail(ec, "handshake");
	}

And these are the callbacks passed to the SSL_CTX_set_client_hello_cb and SSL_CTX_set_alpn_select_cb functions, respectively:

SSL_client_hello_cb_fn set_client_hello_cb(SSL* ssl, int* alert, void* arg)
{
	constexpr int ext_type{ TLSEXT_TYPE_application_layer_protocol_negotiation };
	const unsigned char** alpn_str{};
	std::size_t* alpn_str_len{};
	const int alpn_ext_present{ SSL_client_hello_get0_ext(ssl, ext_type, 
		                        alpn_str, alpn_str_len) };
	if (alpn_ext_present == 1)  // 1 means alpn extension is present
	{
		ssl::context ctx{ ssl::context::tlsv13 };
		load_server_certificate(ctx);
		auto* ssl_ctx{ ctx.native_handle() };
		const unsigned char** out{};
		unsigned char* outlen{};
		const unsigned char* in{};
		unsigned inlen{};
		void* arg{};
		SSL_CTX_set_alpn_select_cb(ssl_ctx, 
			set_alpn_cb(ssl, out, outlen, in, inlen, arg), 
			nullptr);

		return reinterpret_cast<SSL_client_hello_cb_fn>(SSL_CLIENT_HELLO_SUCCESS);
	}
	else if (alpn_ext_present == 0)  // 0 means alpn extension isn't present
	{
		return reinterpret_cast<SSL_client_hello_cb_fn>(SSL_CLIENT_HELLO_ERROR);
	}
}

and

SSL_CTX_alpn_select_cb_func set_alpn_cb(SSL* ssl, const unsigned char** out, unsigned char* outlen,
	const unsigned char* in, unsigned int inlen, void* arg)
{
	for (std::size_t i{}; i < inlen; i += 1 + in[i])
	{
		if (in[i + 0] == 2 && in[i + 1] == 'h' && in[i + 2] == '2')
		{
			*out = in + i + 1;
			*outlen = in[i];
		}
	}

	if (out[0][0] == 2 && out[0][1] == 'h' && out[0][2] == '2')
	{
		return reinterpret_cast<SSL_CTX_alpn_select_cb_func>(SSL_TLSEXT_ERR_OK);
	}
	return reinterpret_cast<SSL_CTX_alpn_select_cb_func>(SSL_TLSEXT_ERR_NOACK);
}

Did I do this right? And should I call the nghttp2 functions for HTTP/2 in main or in do_session?

And how come you're not maintaining nghttp2-asio? I mean, the last commit was just 10 days ago, wasn't it?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions