0

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

gmm
  • 943
  • 1
  • 17
  • 30
  • 1
    You tell boost::asio to read as many bytes as you have sent to the server previously, is this what you want? – m.s. Sep 11 '15 at 09:49
  • Mm ok, no, not really, id like to just read as many bytes as the response takes – gmm Sep 11 '15 at 09:50
  • is the response size fixed? have a look at [this SO question](http://stackoverflow.com/questions/11274577/boost-asio-read-an-unknown-number-of-bytes) – m.s. Sep 11 '15 at 09:51
  • 2
    No that wasnt it, but you did point me in the right direction. I found the answer in this SO question: http://stackoverflow.com/questions/4933610/boostasio-async-read-guarantee-all-bytes-are-read Ill mark my question as duplicate – gmm Sep 11 '15 at 10:17

0 Answers0