I have programmed a small http client class using boost::asio to be able to send https requests to Amazon's S3.
HttpClient::HttpClient(boost::asio::io_service& io_service,
boost::asio::ssl::context& context,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator,
std::string request) : socket_(io_service, context)
{
request_ = request;
//Set ssl verification mode
//As it is a client, just verify servers certificate
socket_.set_verify_mode(boost::asio::ssl::verify_peer);
//Verify Certificate
socket_.set_verify_callback(boost::bind(&HttpClient::verify_certificate, this, _1, _2));
//Prior to making any requests, handshake must be made
boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
boost::bind(&HttpClient::handle_connect, this,
boost::asio::placeholders::error));
}
HttpClient::~HttpClient()
{
}
bool HttpClient::verify_certificate(bool preverified,
boost::asio::ssl::verify_context& ctx)
{
// The verify callback can be used to check whether the certificate that is
// being presented is valid for the peer. For example, RFC 2818 describes
// the steps involved in doing this for HTTPS. Consult the OpenSSL
// documentation for more details. Note that the callback is called once
// for each certificate in the certificate chain, starting from the root
// certificate authority.
// In this example we will simply print the certificate's subject name.
char subject_name[256];
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
//std::cout << "Verifying " << subject_name << "\n";
return preverified;
}
void HttpClient::handle_connect(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_handshake(boost::asio::ssl::stream_base::client,
boost::bind(&HttpClient::handle_handshake, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "Connect failed: " << error.message() << "\n";
}
}
void HttpClient::handle_handshake(const boost::system::error_code& error)
{
if (!error)
{
size_t request_length = strlen(request_.c_str());
boost::asio::async_write(socket_,
boost::asio::buffer(request_.c_str(), request_length),
boost::bind(&HttpClient::handle_write, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << "Handshake failed: " << error.message() << "\n";
}
}
void HttpClient::handle_write(const boost::system::error_code& error,
size_t bytes_transferred)
{
if (!error)
{
boost::asio::async_read(socket_,
boost::asio::buffer(reply_, bytes_transferred),
boost::bind(&HttpClient::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << "Write failed: " << error.message() << "\n";
}
}
void HttpClient::handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
//Reads response from server
if (!error)
{
std::cout << "Reply: ";
std::cout.write(reply_, bytes_transferred);
std::cout << "\n";
}
else
{
std::cout << "Read failed: " << error.message() << "\n";
}
}
The request is working, and I have managed to upload a file to S3, but every time i get the error: Read failed: End of file
. Why am I getting this error if the request is succesful? Is there any way to avoid it or should I just ignore it? How can i get the 200 OK response from AWS?
EDIT: The problem was that I was reading a fixed number of bytes. As stated in the other SO question, async_read_until can be used to read until the response has been received. Here is the boost example of how the async_read_until can be done http://www.boost.org/doc/libs/1_45_0/doc/html/boost_asio/example/http/client/async_client.cpp