mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-23 22:55:39 +00:00
195 lines
4.5 KiB
C++
195 lines
4.5 KiB
C++
|
#include <iostream>
|
||
|
#include "HttpReq.h"
|
||
|
#include <boost/bind.hpp>
|
||
|
#include "Log.h"
|
||
|
|
||
|
boost::asio::io_service HttpReq::io_service;
|
||
|
|
||
|
HttpReq::HttpReq(const std::string& server, const std::string& path)
|
||
|
: mResolver(io_service), mSocket(io_service), mStatus(REQ_IN_PROGRESS)
|
||
|
{
|
||
|
std::ostream req_str(&mRequest);
|
||
|
req_str << "GET " << path << " HTTP/1.0\r\n";
|
||
|
req_str << "Host: " << server << "\r\n";
|
||
|
req_str << "Accept: */*\r\n";
|
||
|
req_str << "Connection: close\r\n\r\n";
|
||
|
|
||
|
tcp::resolver::query query(server, "http");
|
||
|
mResolver.async_resolve(query,
|
||
|
boost::bind(&HttpReq::handleResolve, this,
|
||
|
boost::asio::placeholders::error,
|
||
|
boost::asio::placeholders::iterator));
|
||
|
}
|
||
|
|
||
|
|
||
|
void HttpReq::handleResolve(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator)
|
||
|
{
|
||
|
if (!err)
|
||
|
{
|
||
|
// Attempt a connection to each endpoint in the list until we
|
||
|
// successfully establish a connection.
|
||
|
boost::asio::async_connect(mSocket, endpoint_iterator,
|
||
|
boost::bind(&HttpReq::handleConnect, this,
|
||
|
boost::asio::placeholders::error));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
onError(err);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HttpReq::handleConnect(const boost::system::error_code& err)
|
||
|
{
|
||
|
if (!err)
|
||
|
{
|
||
|
// The connection was successful. Send the request.
|
||
|
boost::asio::async_write(mSocket, mRequest,
|
||
|
boost::bind(&HttpReq::handleWriteRequest, this,
|
||
|
boost::asio::placeholders::error));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
onError(err);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HttpReq::handleWriteRequest(const boost::system::error_code& err)
|
||
|
{
|
||
|
if (!err)
|
||
|
{
|
||
|
// Read the response status line. The response_ streambuf will
|
||
|
// automatically grow to accommodate the entire line. The growth may be
|
||
|
// limited by passing a maximum size to the streambuf constructor.
|
||
|
boost::asio::async_read_until(mSocket, mResponse, "\r\n",
|
||
|
boost::bind(&HttpReq::handleReadStatusLine, this,
|
||
|
boost::asio::placeholders::error));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
onError(err);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HttpReq::handleReadStatusLine(const boost::system::error_code& err)
|
||
|
{
|
||
|
if (!err)
|
||
|
{
|
||
|
// Check that response is OK.
|
||
|
std::istream response_stream(&mResponse);
|
||
|
std::string http_version;
|
||
|
response_stream >> http_version;
|
||
|
response_stream >> mResponseStatusCode;
|
||
|
std::string status_message;
|
||
|
std::getline(response_stream, status_message);
|
||
|
if(!response_stream || http_version.substr(0, 5) != "HTTP/")
|
||
|
{
|
||
|
mStatus = REQ_INVALID_RESPONSE;
|
||
|
return;
|
||
|
}
|
||
|
if(mResponseStatusCode != 200)
|
||
|
{
|
||
|
mStatus = REQ_BAD_STATUS_CODE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Read the response headers, which are terminated by a blank line.
|
||
|
boost::asio::async_read_until(mSocket, mResponse, "\r\n\r\n",
|
||
|
boost::bind(&HttpReq::handleReadHeaders, this,
|
||
|
boost::asio::placeholders::error));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
onError(err);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HttpReq::handleReadHeaders(const boost::system::error_code& err)
|
||
|
{
|
||
|
if (!err)
|
||
|
{
|
||
|
// Process the response headers.
|
||
|
std::istream response_stream(&mResponse);
|
||
|
std::string header;
|
||
|
while (std::getline(response_stream, header) && header != "\r"); //and by process we mean ignore
|
||
|
|
||
|
// Write whatever content we already have to output.
|
||
|
if (mResponse.size() > 0)
|
||
|
mContent << &mResponse;
|
||
|
|
||
|
// Start reading remaining data until EOF.
|
||
|
boost::asio::async_read(mSocket, mResponse,
|
||
|
boost::asio::transfer_at_least(1),
|
||
|
boost::bind(&HttpReq::handleReadContent, this,
|
||
|
boost::asio::placeholders::error));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
onError(err);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HttpReq::handleReadContent(const boost::system::error_code& err)
|
||
|
{
|
||
|
if (!err)
|
||
|
{
|
||
|
// Write all of the data that has been read so far.
|
||
|
mContent << &mResponse;
|
||
|
|
||
|
// Continue reading remaining data until EOF.
|
||
|
boost::asio::async_read(mSocket, mResponse,
|
||
|
boost::asio::transfer_at_least(1),
|
||
|
boost::bind(&HttpReq::handleReadContent, this,
|
||
|
boost::asio::placeholders::error));
|
||
|
}else{
|
||
|
if (err != boost::asio::error::eof)
|
||
|
{
|
||
|
onError(err);
|
||
|
}else{
|
||
|
mStatus = REQ_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HttpReq::Status HttpReq::status()
|
||
|
{
|
||
|
io_service.poll();
|
||
|
return mStatus;
|
||
|
}
|
||
|
|
||
|
std::string HttpReq::getContent()
|
||
|
{
|
||
|
if(mStatus != REQ_SUCCESS)
|
||
|
{
|
||
|
LOG(LogError) << "Called getContent() on an unsuccessful HttpReq!";
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
return mContent.str();
|
||
|
}
|
||
|
|
||
|
//only called for boost-level errors (REQ_IO_ERROR)
|
||
|
void HttpReq::onError(const boost::system::error_code& err)
|
||
|
{
|
||
|
mError = err;
|
||
|
mStatus = REQ_IO_ERROR;
|
||
|
}
|
||
|
|
||
|
std::string HttpReq::getErrorMsg()
|
||
|
{
|
||
|
switch(mStatus)
|
||
|
{
|
||
|
case REQ_BAD_STATUS_CODE:
|
||
|
return "Bad status code";
|
||
|
case REQ_INVALID_RESPONSE:
|
||
|
return "Invalid response from server";
|
||
|
case REQ_IO_ERROR:
|
||
|
return mError.message();
|
||
|
case REQ_IN_PROGRESS:
|
||
|
return "Not done yet";
|
||
|
case REQ_SUCCESS:
|
||
|
return "No error";
|
||
|
default:
|
||
|
return "???";
|
||
|
}
|
||
|
}
|