I'm having trouble to get the protocol (HTTP or HTTPS) of a request in boost beast webserver.
I can get the host using:
req[http::field::host]
but no such luck with the protocol.
req[http::field::protocol]
is empty.
There is no http::field for HTTPS.
For using HTTPS basically you are doing following (example):
1.Create io_context and ssl_context
boost::asio::io_context ioc;
boost::asio::ssl::context ctx(boost::asio::ssl::context::tlsv12_client)
2.create ssl stream from io_context and ssl::context
boost::beast::ssl_stream<boost::beast::tcp_stream> stream(ioc, ctx)
3.create tcp connection using lowest_layer
beast::get_lowest_layer(stream).connect(...endpoints iterator from query resolver..)
4.do the ssl handshake
stream.handshake(ssl::stream_base::client);
5.now you can make requests writing to stream as usual:
http::request<http::string_body> req{http::verb::get, target, version};
req.set(http::field::host, host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
// Send the HTTP request to the remote host
http::write(stream, req);
Check the official boost beast examples.
Considering the fact that you are behind a nginx server, Beast cannot solve your problem. But the additional headers that nginx will send to your server will.
You may rely on the HTTP_X_FORWARDED_PROTO or HTTP_X_FORWARDED_SSL headers. Here's what I came up with by following an answer to a similar question:
using namespace boost::beast;
using namespace std;
string find_scheme(const http::request<http::string_body>& request)
{
http::request<http::string_body>::const_iterator header;
header = request.find("HTTP_X_FORWARDED_PROTO");
if (header != request.end())
return header->value().data();
else
{
header = request.find("HTTP_X_FORWARDED_SSL");
if (header != request.end())
return header->value() == "on" ? "https" : "http";
}
return "http";
}
Related
I'm building an HTTP server in C++ using the Cesanta Mongoose c++ networking library. Essentially I'm trying to redirect traffic from my web browser to a proxy on the localhost. I recently added support for HTTPS by purchasing a certificate and domain and following the instructions to enable ssl with mongoose (https://cesanta.com/docs/http/ssl.html). The server is now listening on port 443, and it runs fine. I've configured my web browser to direct HTTPS requests to localhost:443, but it doesn't appear to be triggering the HTTP server. When my server is listening on port 8080 and the web browser is configured to send requests to localhost:8080, it triggers the web browser, but it doesn't support https. Is there something wrong with configuring the web browser to send requests to localhost:443?
ngrok solution is quite nice.
If you want to add a redirect in your application directly, set two listening connections: one HTTP, one HTTPS.
Use different event handler functions for those two listening connection: the HTTP handler would only send redirects, whereas HTTPS handler would do a real job:
static void f1(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
struct mg_str *host = mg_http_get_header(hm, "Host");
if (host == NULL) {
mg_printf(c, "HTTP/1.1 500 Failed\r\n\r\n");
} else {
mg_printf(c, "HTTP/1.1 301 Moved\r\n"
"Location: https://%.*s%.*s\r\n\r\n",
(int) host->len, host->ptr,);
(int) hm->uri.len, hm->uri.ptr); // Send redirect to HTTPS!
}
c->is_draining = 1;
}
}
...
mg_http_listen(&mgr, "http://0.0.0.0:80", f1, NULL); // HTTP
mg_http_listen(&mgr, "https://0.0.0.0:443", f2, NULL); // HTTPS
I am using Boost.Asio ssl streams, and got a working encrypted socket from which I can send and receive bytes.
I successfully did a GET request with the following code :
// Construct HTTP request (using vanilla std::ostream)
std::ostream request_stream(&request);
request_stream << "GET / HTTP/1.0\r\n";
request_stream << "Host: " << argv[1] << "\r\n";
...
// Send request
ssl::stream<tcp::socket> socket
boost::asio::write(socket, request);
And I would now love to find a small C++ library that would provide an easy way to get the ostream loaded with a valid HTTP request !
Since you're already using Boost.Asio, consider using Boost.Beast which is a low-level HTTP library. Example of sending a GET request using Boost.Beast:
using namespace boost::beast;
// Set up an HTTP GET request message
http::request<http::empty_body> req{http::verb::get, "/", 11};
req.set(http::field::host, "www.example.com");
req.set(http::field::user_agent, "Beast/1.0);
// Send the HTTP request to the remote host
http::write(socket, req);
The full example is here:
https://github.com/boostorg/beast/blob/master/example/http/client/sync/http_client_sync.cpp
Beast is available in Boost versions 1.66 and later. Here is the documentation page, which includes many examples:
http://www.boost.org/doc/libs/1_66_0/libs/beast/doc/html/index.html
If you really want to write the HTTP request to a std::ostream, Beast supports operator<< for HTTP messages (it is mainly there for debugging), but I think you are better off just writing it directly to the ip::tcp::socket or ssl::stream using Beast.
I am using POCO HTTPSClientSession for executing a HTTPS POST request. I want to compute SHA1 of the server certificate before transmitting any data. How can this be achieved?
This is sample of creating context which doesn't verify server certificate. The basic requirement is to fetch the server certificate during the SSL handshake and do a custom verification of the server certificate.
const Poco::Net::Context::Ptr context( new Poco::Net::Context( Poco::Net::Context::CLIENT_USE, "", "", "",Poco::Net::Context::VERIFY_NONE ) );
Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort(),context);
Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_POST,uri.getPath(), Poco::Net::HTTPMessage::HTTP_1_1);
Any help would be appreciable
I don't know if it can help you. Remove the parameter context from the session constructor. It will force to check the SSL certificate.
Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort() );
Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_POST,uri.getPath(), Poco::Net::HTTPMessage::HTTP_1_1);
I'm using boost::asio and I've been looking at the example code on how to connect to an ssl host. But I want to send a get request after I've connected to the server through ssl, how is this possible? Do I send a get request as the http example do exactly?
After the handshake is done (handle_handshake in the example) and there was no errors, you should be able to use the connection just as any other Boost ASIO connection.
I think this code is working though the server I want to connect to doesn't have their authentication working. I want to disable authentication checking but still connect using SSL? Here is the code:
// Create a context that uses the default paths for
// finding CA certificates.
ssl::context ctx(ssl::context::sslv23);
ctx.set_default_verify_paths();
// Open a socket and connect it to the remote host.
ssl_socket sock(io_service, ctx);
tcp::resolver::query query(host_name_, "https");
boost::asio::connect(sock.lowest_layer(), resolver_.resolve(query));
sock.lowest_layer().set_option(tcp::no_delay(true));
// Perform SSL handshake and verify the remote host's
// certificate.
sock.set_verify_mode(boost::asio::ssl::context::verify_none);
//sock.set_verify_callback();
//sock.set_verify_callback(ssl::rfc2818_verification(host_name_));
sock.handshake(ssl_socket::client);
How can I remove authentication checking?