I want to connect to an HTTPS server using boost::asio. I managed to successfully shake hands with the server, but I just can't manage to get the server to respond to my POST request.
This is the related code (I left out debugging and try-catch to save some space):
HTTPSClient::HTTPSClient()
{
ssl::context context(ssl::context::sslv23);
context.set_verify_mode(ssl::verify_peer);
context.set_default_verify_paths();
context.load_verify_file("certificate.pem");
mSSLSocket = new ssl::stream<ip::tcp::socket>(mIOService, context);
}
void HTTPSClient::SendRequest(const ptree &crPTree, const std::string cHost,
const std::string cURI)
{
tcp::resolver resolver(mIOService);
tcp::resolver::query query(cHost, "https");
resolver.async_resolve(query, boost::bind(&HTTPSClient::HandleResolve, this,
placeholders::error, placeholders::iterator, request));
}
void HTTPSClient::HandleResolve(const error_code &crError,
const iterator &criEndpoints, HTTPSRequest &rRequest)
{
async_connect(mSSLSocket->lowest_layer(), criEndpoints,
boost::bind(&HTTPSClient::HandleConnect, this, placeholders::error,
rRequest));
}
void HTTPSClient::HandleConnect(const error_code &crError, HTTPSRequest &rRequest)
{
mSSLSocket->lowest_layer().set_option(ip::tcp::no_delay(true));
mSSLSocket->set_verify_callback(ssl::rfc2818_verification(rRequest.mcHost));
mSSLSocket->handshake(ssl::stream_base::client);
// Write the json into a stringstream
std::ostringstream json;
boost::property_tree::write_json(json, rRequest.mcPTree);
std::string result;
result = json.str();
// Form the request
streambuf request;
std::ostream requestStream(&request);
requestStream << "POST " << rRequest.mcURI << " HTTP/1.1\r\n";
requestStream << "Host: " << rRequest.mcHost << "\r\n";
requestStream << "Accept: application/json\r\n";
requestStream << "Content-Type: application/json; charset=UTF-8\r\n";
requestStream << "Content-Length: " << result.length() << "\r\n";
requestStream << result << "\r\n\r\n";
write(*mSSLSocket, request);
streambuf response;
read_until(*mSSLSocket, response, "\r\n");
std::istream responseStream(&response);
}
read_until hangs until it throws the error read_until: End of file. Everything before that goes successfully, including the SSL handshake (which I just recently figured out).
I used to do everything asynchronously until I started debugging, and started trying to backtrace to the problem, to no avail. It would be awesome if someone could help me out after two painful days of debugging.
EDIT I just realized it might be useful to add the contents of requestStream after composing the header:
POST /authenticate HTTP/1.1
Host: <hostname>
Accept: application/json
Content-Type: application/json; charset=UTF-8
Content-Length: 136
{
"username": "vijfhoek",
"password": "test123",
<other json content>
}
You need a double linefeed before the body (POST contents)
POST /authenticate HTTP/1.1
Host: <hostname>
Accept: application/json
Content-Type: application/json; charset=UTF-8
Content-Length: 136
{
"username": "vijfhoek",
"password": "test123",
<other json content>
}
Otherwise, the content will have been received by the server as header lines and the server just keeps waiting for 136
bytes of content data (also make sure that Content-Length is accurate, which it isn't in this example)
So, basically:
requestStream << "Content-Length: " << result.length() << "\r\n";
requestStream << "\r\n"; // THIS LINE ADDED
I managed to figure out what I was doing wrong. For some reason, I couldn't get boost to write data using the boost::asio::streambuf and std::ostream approach. Instead, I put the POST data in a std::string and sent it like this:
write(*mSSLSocket, boost::asio::buffer(requestString));
Which worked out fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With