mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Refactor HTTPClient
This commit is contained in:
@@ -556,7 +556,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (!getConfig ().VALIDATORS_SITE.empty ())
|
if (!getConfig ().VALIDATORS_SITE.empty ())
|
||||||
{
|
{
|
||||||
HttpsClient::httpsGet (
|
HTTPClient::get (
|
||||||
true,
|
true,
|
||||||
getApp().getIOService (),
|
getApp().getIOService (),
|
||||||
getConfig ().VALIDATORS_SITE,
|
getConfig ().VALIDATORS_SITE,
|
||||||
@@ -1434,7 +1434,7 @@ private:
|
|||||||
deqSites.push_back (str (boost::format ("www.%s") % strDomain));
|
deqSites.push_back (str (boost::format ("www.%s") % strDomain));
|
||||||
deqSites.push_back (strDomain);
|
deqSites.push_back (strDomain);
|
||||||
|
|
||||||
HttpsClient::httpsGet (
|
HTTPClient::get (
|
||||||
true,
|
true,
|
||||||
getApp().getIOService (),
|
getApp().getIOService (),
|
||||||
deqSites,
|
deqSites,
|
||||||
@@ -1473,7 +1473,7 @@ private:
|
|||||||
&& -1 == iPort
|
&& -1 == iPort
|
||||||
&& strScheme == "https")
|
&& strScheme == "https")
|
||||||
{
|
{
|
||||||
HttpsClient::httpsGet (
|
HTTPClient::get (
|
||||||
true,
|
true,
|
||||||
getApp().getIOService (),
|
getApp().getIOService (),
|
||||||
strDomain,
|
strDomain,
|
||||||
@@ -1507,7 +1507,7 @@ private:
|
|||||||
&& -1 == iPort
|
&& -1 == iPort
|
||||||
&& strScheme == "https")
|
&& strScheme == "https")
|
||||||
{
|
{
|
||||||
HttpsClient::httpsGet (
|
HTTPClient::get (
|
||||||
true,
|
true,
|
||||||
getApp().getIOService (),
|
getApp().getIOService (),
|
||||||
strDomain,
|
strDomain,
|
||||||
|
|||||||
@@ -2729,7 +2729,7 @@ Json::Value RPCHandler::doSMS (Json::Value params, LoadType* loadType, Applicati
|
|||||||
if (!params.isMember ("text"))
|
if (!params.isMember ("text"))
|
||||||
return rpcError (rpcINVALID_PARAMS);
|
return rpcError (rpcINVALID_PARAMS);
|
||||||
|
|
||||||
HttpsClient::sendSMS (getApp().getIOService (), params["text"].asString ());
|
HTTPClient::sendSMS (getApp().getIOService (), params["text"].asString ());
|
||||||
|
|
||||||
return "sms dispatched";
|
return "sms dispatched";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,403 +5,455 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
//
|
//
|
||||||
// Fetch a web page via https.
|
// Fetch a web page via http or https.
|
||||||
//
|
//
|
||||||
|
|
||||||
SETUP_LOG (HttpsClient)
|
SETUP_LOG (HTTPClient)
|
||||||
|
|
||||||
// VFALCO NOTE Why use getConfig ().SSL_CONTEXT instead of just passing it?
|
class HTTPClientImp
|
||||||
// TODO Remove all theConfig deps from this file
|
: public boost::enable_shared_from_this <HTTPClientImp>
|
||||||
//
|
, public HTTPClient
|
||||||
HttpsClient::HttpsClient (boost::asio::io_service& io_service,
|
, LeakChecked <HTTPClientImp>
|
||||||
const unsigned short port,
|
|
||||||
std::size_t responseMax)
|
|
||||||
: mSocket (io_service, getConfig ().SSL_CONTEXT)
|
|
||||||
, mResolver (io_service)
|
|
||||||
, mHeader (maxClientHeaderBytes)
|
|
||||||
, mPort (port)
|
|
||||||
, mResponseMax (responseMax)
|
|
||||||
, mDeadline (io_service)
|
|
||||||
{
|
{
|
||||||
if (!getConfig ().SSL_VERIFY)
|
public:
|
||||||
mSocket.SSLSocket ().set_verify_mode (boost::asio::ssl::verify_none);
|
// VFALCO NOTE Why use getConfig ().SSL_CONTEXT instead of just passing it?
|
||||||
}
|
// TODO Remove all theConfig deps from this file
|
||||||
|
//
|
||||||
void HttpsClient::makeGet (const std::string& strPath, boost::asio::streambuf& sb, const std::string& strHost)
|
HTTPClientImp (boost::asio::io_service& io_service,
|
||||||
{
|
const unsigned short port,
|
||||||
std::ostream osRequest (&sb);
|
std::size_t responseMax)
|
||||||
|
: mSocket (io_service, getConfig ().SSL_CONTEXT)
|
||||||
osRequest <<
|
, mResolver (io_service)
|
||||||
"GET " << strPath << " HTTP/1.0\r\n"
|
, mHeader (maxClientHeaderBytes)
|
||||||
"Host: " << strHost << "\r\n"
|
, mPort (port)
|
||||||
"Accept: */*\r\n" // YYY Do we need this line?
|
, mResponseMax (responseMax)
|
||||||
"Connection: close\r\n\r\n";
|
, mDeadline (io_service)
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::httpsRequest (
|
|
||||||
bool bSSL,
|
|
||||||
std::deque<std::string> deqSites,
|
|
||||||
FUNCTION_TYPE<void (boost::asio::streambuf& sb, const std::string& strHost)> build,
|
|
||||||
boost::posix_time::time_duration timeout,
|
|
||||||
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete)
|
|
||||||
{
|
|
||||||
mSSL = bSSL;
|
|
||||||
mDeqSites = deqSites;
|
|
||||||
mBuild = build;
|
|
||||||
mComplete = complete;
|
|
||||||
mTimeout = timeout;
|
|
||||||
|
|
||||||
httpsNext ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::httpsGet (
|
|
||||||
bool bSSL,
|
|
||||||
std::deque<std::string> deqSites,
|
|
||||||
const std::string& strPath,
|
|
||||||
boost::posix_time::time_duration timeout,
|
|
||||||
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete)
|
|
||||||
{
|
|
||||||
|
|
||||||
mComplete = complete;
|
|
||||||
mTimeout = timeout;
|
|
||||||
|
|
||||||
httpsRequest (
|
|
||||||
bSSL,
|
|
||||||
deqSites,
|
|
||||||
BIND_TYPE (&HttpsClient::makeGet, shared_from_this (), strPath, P_1, P_2),
|
|
||||||
timeout,
|
|
||||||
complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::httpsNext ()
|
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Fetch: " << mDeqSites[0];
|
|
||||||
|
|
||||||
boost::shared_ptr <boost::asio::ip::tcp::resolver::query> query (
|
|
||||||
new boost::asio::ip::tcp::resolver::query (
|
|
||||||
mDeqSites[0],
|
|
||||||
lexicalCast <std::string> (mPort),
|
|
||||||
boost::asio::ip::resolver_query_base::numeric_service));
|
|
||||||
mQuery = query;
|
|
||||||
|
|
||||||
mDeadline.expires_from_now (mTimeout, mShutdown);
|
|
||||||
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "expires_from_now: " << mShutdown.message ();
|
|
||||||
|
|
||||||
if (!mShutdown)
|
|
||||||
{
|
{
|
||||||
mDeadline.async_wait (
|
if (!getConfig ().SSL_VERIFY)
|
||||||
boost::bind (
|
mSocket.SSLSocket ().set_verify_mode (boost::asio::ssl::verify_none);
|
||||||
&HttpsClient::handleDeadline,
|
|
||||||
shared_from_this (),
|
|
||||||
boost::asio::placeholders::error));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mShutdown)
|
//--------------------------------------------------------------------------
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Resolving: " << mDeqSites[0];
|
|
||||||
|
|
||||||
mResolver.async_resolve (*mQuery,
|
void makeGet (const std::string& strPath, boost::asio::streambuf& sb,
|
||||||
boost::bind (
|
const std::string& strHost)
|
||||||
&HttpsClient::handleResolve,
|
{
|
||||||
shared_from_this (),
|
std::ostream osRequest (&sb);
|
||||||
boost::asio::placeholders::error,
|
|
||||||
boost::asio::placeholders::iterator));
|
osRequest <<
|
||||||
|
"GET " << strPath << " HTTP/1.0\r\n"
|
||||||
|
"Host: " << strHost << "\r\n"
|
||||||
|
"Accept: */*\r\n" // YYY Do we need this line?
|
||||||
|
"Connection: close\r\n\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mShutdown)
|
//--------------------------------------------------------------------------
|
||||||
invokeComplete (mShutdown);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::handleDeadline (const boost::system::error_code& ecResult)
|
void request (
|
||||||
{
|
bool bSSL,
|
||||||
if (ecResult == boost::asio::error::operation_aborted)
|
std::deque<std::string> deqSites,
|
||||||
|
FUNCTION_TYPE<void (boost::asio::streambuf& sb, const std::string& strHost)> build,
|
||||||
|
boost::posix_time::time_duration timeout,
|
||||||
|
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult,
|
||||||
|
int iStatus, const std::string& strData)> complete)
|
||||||
{
|
{
|
||||||
// Timer canceled because deadline no longer needed.
|
mSSL = bSSL;
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Deadline cancelled.";
|
mDeqSites = deqSites;
|
||||||
|
mBuild = build;
|
||||||
|
mComplete = complete;
|
||||||
|
mTimeout = timeout;
|
||||||
|
|
||||||
nothing (); // Aborter is done.
|
httpsNext ();
|
||||||
}
|
|
||||||
else if (ecResult)
|
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Deadline error: " << mDeqSites[0] << ": " << ecResult.message ();
|
|
||||||
|
|
||||||
// Can't do anything sound.
|
|
||||||
abort ();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Deadline arrived.";
|
|
||||||
|
|
||||||
// Mark us as shutting down.
|
|
||||||
// XXX Use our own error code.
|
|
||||||
mShutdown = boost::system::error_code (boost::system::errc::bad_address, boost::system::system_category ());
|
|
||||||
|
|
||||||
// Cancel any resolving.
|
|
||||||
mResolver.cancel ();
|
|
||||||
|
|
||||||
// Stop the transaction.
|
|
||||||
mSocket.async_shutdown (boost::bind (
|
|
||||||
&HttpsClient::handleShutdown,
|
|
||||||
shared_from_this (),
|
|
||||||
boost::asio::placeholders::error));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::handleShutdown (
|
|
||||||
const boost::system::error_code& ecResult
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (ecResult)
|
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Shutdown error: " << mDeqSites[0] << ": " << ecResult.message ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::handleResolve (
|
|
||||||
const boost::system::error_code& ecResult,
|
|
||||||
boost::asio::ip::tcp::resolver::iterator itrEndpoint
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (!mShutdown)
|
|
||||||
mShutdown = ecResult;
|
|
||||||
|
|
||||||
if (mShutdown)
|
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Resolve error: " << mDeqSites[0] << ": " << mShutdown.message ();
|
|
||||||
|
|
||||||
invokeComplete (mShutdown);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Resolve complete.";
|
|
||||||
|
|
||||||
boost::asio::async_connect (
|
|
||||||
mSocket.lowest_layer (),
|
|
||||||
itrEndpoint,
|
|
||||||
boost::bind (
|
|
||||||
&HttpsClient::handleConnect,
|
|
||||||
shared_from_this (),
|
|
||||||
boost::asio::placeholders::error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::handleConnect (const boost::system::error_code& ecResult)
|
|
||||||
{
|
|
||||||
if (!mShutdown)
|
|
||||||
mShutdown = ecResult;
|
|
||||||
|
|
||||||
if (mShutdown)
|
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Connect error: " << mShutdown.message ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mShutdown)
|
//--------------------------------------------------------------------------
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Connected.";
|
|
||||||
|
|
||||||
if (getConfig ().SSL_VERIFY)
|
void get (
|
||||||
|
bool bSSL,
|
||||||
|
std::deque<std::string> deqSites,
|
||||||
|
const std::string& strPath,
|
||||||
|
boost::posix_time::time_duration timeout,
|
||||||
|
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus,
|
||||||
|
const std::string& strData)> complete)
|
||||||
|
{
|
||||||
|
|
||||||
|
mComplete = complete;
|
||||||
|
mTimeout = timeout;
|
||||||
|
|
||||||
|
request (
|
||||||
|
bSSL,
|
||||||
|
deqSites,
|
||||||
|
BIND_TYPE (&HTTPClientImp::makeGet, shared_from_this (), strPath, P_1, P_2),
|
||||||
|
timeout,
|
||||||
|
complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void httpsNext ()
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Fetch: " << mDeqSites[0];
|
||||||
|
|
||||||
|
boost::shared_ptr <boost::asio::ip::tcp::resolver::query> query (
|
||||||
|
new boost::asio::ip::tcp::resolver::query (
|
||||||
|
mDeqSites[0],
|
||||||
|
lexicalCast <std::string> (mPort),
|
||||||
|
boost::asio::ip::resolver_query_base::numeric_service));
|
||||||
|
mQuery = query;
|
||||||
|
|
||||||
|
mDeadline.expires_from_now (mTimeout, mShutdown);
|
||||||
|
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "expires_from_now: " << mShutdown.message ();
|
||||||
|
|
||||||
|
if (!mShutdown)
|
||||||
{
|
{
|
||||||
mShutdown = mSocket.verify (mDeqSites[0]);
|
mDeadline.async_wait (
|
||||||
|
boost::bind (
|
||||||
|
&HTTPClientImp::handleDeadline,
|
||||||
|
shared_from_this (),
|
||||||
|
boost::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mShutdown)
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Resolving: " << mDeqSites[0];
|
||||||
|
|
||||||
|
mResolver.async_resolve (*mQuery,
|
||||||
|
boost::bind (
|
||||||
|
&HTTPClientImp::handleResolve,
|
||||||
|
shared_from_this (),
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::iterator));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mShutdown)
|
||||||
|
invokeComplete (mShutdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleDeadline (const boost::system::error_code& ecResult)
|
||||||
|
{
|
||||||
|
if (ecResult == boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
// Timer canceled because deadline no longer needed.
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Deadline cancelled.";
|
||||||
|
|
||||||
|
nothing (); // Aborter is done.
|
||||||
|
}
|
||||||
|
else if (ecResult)
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Deadline error: " << mDeqSites[0] << ": " << ecResult.message ();
|
||||||
|
|
||||||
|
// Can't do anything sound.
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Deadline arrived.";
|
||||||
|
|
||||||
|
// Mark us as shutting down.
|
||||||
|
// XXX Use our own error code.
|
||||||
|
mShutdown = boost::system::error_code (boost::system::errc::bad_address, boost::system::system_category ());
|
||||||
|
|
||||||
|
// Cancel any resolving.
|
||||||
|
mResolver.cancel ();
|
||||||
|
|
||||||
|
// Stop the transaction.
|
||||||
|
mSocket.async_shutdown (boost::bind (
|
||||||
|
&HTTPClientImp::handleShutdown,
|
||||||
|
shared_from_this (),
|
||||||
|
boost::asio::placeholders::error));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleShutdown (
|
||||||
|
const boost::system::error_code& ecResult
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (ecResult)
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Shutdown error: " << mDeqSites[0] << ": " << ecResult.message ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleResolve (
|
||||||
|
const boost::system::error_code& ecResult,
|
||||||
|
boost::asio::ip::tcp::resolver::iterator itrEndpoint
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (!mShutdown)
|
||||||
|
mShutdown = ecResult;
|
||||||
|
|
||||||
|
if (mShutdown)
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Resolve error: " << mDeqSites[0] << ": " << mShutdown.message ();
|
||||||
|
|
||||||
|
invokeComplete (mShutdown);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Resolve complete.";
|
||||||
|
|
||||||
|
boost::asio::async_connect (
|
||||||
|
mSocket.lowest_layer (),
|
||||||
|
itrEndpoint,
|
||||||
|
boost::bind (
|
||||||
|
&HTTPClientImp::handleConnect,
|
||||||
|
shared_from_this (),
|
||||||
|
boost::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleConnect (const boost::system::error_code& ecResult)
|
||||||
|
{
|
||||||
|
if (!mShutdown)
|
||||||
|
mShutdown = ecResult;
|
||||||
|
|
||||||
|
if (mShutdown)
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Connect error: " << mShutdown.message ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mShutdown)
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Connected.";
|
||||||
|
|
||||||
|
if (getConfig ().SSL_VERIFY)
|
||||||
|
{
|
||||||
|
mShutdown = mSocket.verify (mDeqSites[0]);
|
||||||
|
|
||||||
|
if (mShutdown)
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "set_verify_callback: " << mDeqSites[0] << ": " << mShutdown.message ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mShutdown)
|
||||||
|
{
|
||||||
|
invokeComplete (mShutdown);
|
||||||
|
}
|
||||||
|
else if (mSSL)
|
||||||
|
{
|
||||||
|
mSocket.async_handshake (
|
||||||
|
AutoSocket::ssl_socket::client,
|
||||||
|
boost::bind (
|
||||||
|
&HTTPClientImp::handleRequest,
|
||||||
|
shared_from_this (),
|
||||||
|
boost::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handleRequest (ecResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleRequest (const boost::system::error_code& ecResult)
|
||||||
|
{
|
||||||
|
if (!mShutdown)
|
||||||
|
mShutdown = ecResult;
|
||||||
|
|
||||||
|
if (mShutdown)
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Handshake error:" << mShutdown.message ();
|
||||||
|
|
||||||
|
invokeComplete (mShutdown);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Session started.";
|
||||||
|
|
||||||
|
mBuild (mRequest, mDeqSites[0]);
|
||||||
|
|
||||||
|
mSocket.async_write (
|
||||||
|
mRequest,
|
||||||
|
boost::bind (&HTTPClientImp::handleWrite,
|
||||||
|
shared_from_this (),
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleWrite (const boost::system::error_code& ecResult, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
if (!mShutdown)
|
||||||
|
mShutdown = ecResult;
|
||||||
|
|
||||||
|
if (mShutdown)
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Write error: " << mShutdown.message ();
|
||||||
|
|
||||||
|
invokeComplete (mShutdown);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Wrote.";
|
||||||
|
|
||||||
|
mSocket.async_read_until (
|
||||||
|
mHeader,
|
||||||
|
"\r\n\r\n",
|
||||||
|
boost::bind (&HTTPClientImp::handleHeader,
|
||||||
|
shared_from_this (),
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleHeader (const boost::system::error_code& ecResult, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
std::string strHeader ((std::istreambuf_iterator<char> (&mHeader)), std::istreambuf_iterator<char> ());
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Header: \"" << strHeader << "\"";
|
||||||
|
|
||||||
|
static boost::regex reStatus ("\\`HTTP/1\\S+ (\\d{3}) .*\\'"); // HTTP/1.1 200 OK
|
||||||
|
static boost::regex reSize ("\\`.*\\r\\nContent-Length:\\s+([0-9]+).*\\'");
|
||||||
|
static boost::regex reBody ("\\`.*\\r\\n\\r\\n(.*)\\'");
|
||||||
|
|
||||||
|
boost::smatch smMatch;
|
||||||
|
|
||||||
|
bool bMatch = boost::regex_match (strHeader, smMatch, reStatus); // Match status code.
|
||||||
|
|
||||||
|
if (!bMatch)
|
||||||
|
{
|
||||||
|
// XXX Use our own error code.
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "No status code";
|
||||||
|
invokeComplete (boost::system::error_code (boost::system::errc::bad_address, boost::system::system_category ()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mStatus = lexicalCastThrow <int> (std::string (smMatch[1]));
|
||||||
|
|
||||||
|
if (boost::regex_match (strHeader, smMatch, reBody)) // we got some body
|
||||||
|
mBody = smMatch[1];
|
||||||
|
|
||||||
|
if (boost::regex_match (strHeader, smMatch, reSize))
|
||||||
|
{
|
||||||
|
int size = lexicalCastThrow <int> (std::string(smMatch[1]));
|
||||||
|
|
||||||
|
if (size < mResponseMax)
|
||||||
|
mResponseMax = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mResponseMax == 0)
|
||||||
|
{
|
||||||
|
// no body wanted or available
|
||||||
|
invokeComplete (ecResult, mStatus);
|
||||||
|
}
|
||||||
|
else if (mBody.size () >= mResponseMax)
|
||||||
|
{
|
||||||
|
// we got the whole thing
|
||||||
|
invokeComplete (ecResult, mStatus, mBody);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mSocket.async_read (
|
||||||
|
mResponse.prepare (mResponseMax - mBody.size ()),
|
||||||
|
boost::asio::transfer_all (),
|
||||||
|
boost::bind (&HTTPClientImp::handleData,
|
||||||
|
shared_from_this (),
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleData (const boost::system::error_code& ecResult, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
if (!mShutdown)
|
||||||
|
mShutdown = ecResult;
|
||||||
|
|
||||||
|
if (mShutdown && mShutdown != boost::asio::error::eof)
|
||||||
|
{
|
||||||
|
WriteLog (lsTRACE, HTTPClient) << "Read error: " << mShutdown.message ();
|
||||||
|
|
||||||
|
invokeComplete (mShutdown);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (mShutdown)
|
if (mShutdown)
|
||||||
{
|
{
|
||||||
WriteLog (lsTRACE, HttpsClient) << "set_verify_callback: " << mDeqSites[0] << ": " << mShutdown.message ();
|
WriteLog (lsTRACE, HTTPClient) << "Complete.";
|
||||||
|
|
||||||
|
nothing ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mResponse.commit (bytes_transferred);
|
||||||
|
std::string strBody ((std::istreambuf_iterator<char> (&mResponse)), std::istreambuf_iterator<char> ());
|
||||||
|
invokeComplete (ecResult, mStatus, mBody + strBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mShutdown)
|
// Call cancel the deadline timer and invoke the completion routine.
|
||||||
|
void invokeComplete (const boost::system::error_code& ecResult, int iStatus = 0, const std::string& strData = "")
|
||||||
{
|
{
|
||||||
invokeComplete (mShutdown);
|
boost::system::error_code ecCancel;
|
||||||
}
|
|
||||||
else if (mSSL)
|
|
||||||
{
|
|
||||||
mSocket.async_handshake (
|
|
||||||
AutoSocket::ssl_socket::client,
|
|
||||||
boost::bind (
|
|
||||||
&HttpsClient::handleRequest,
|
|
||||||
shared_from_this (),
|
|
||||||
boost::asio::placeholders::error));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
handleRequest (ecResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::handleRequest (const boost::system::error_code& ecResult)
|
(void) mDeadline.cancel (ecCancel);
|
||||||
{
|
|
||||||
if (!mShutdown)
|
|
||||||
mShutdown = ecResult;
|
|
||||||
|
|
||||||
if (mShutdown)
|
if (ecCancel)
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Handshake error:" << mShutdown.message ();
|
|
||||||
|
|
||||||
invokeComplete (mShutdown);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Session started.";
|
|
||||||
|
|
||||||
mBuild (mRequest, mDeqSites[0]);
|
|
||||||
|
|
||||||
mSocket.async_write (
|
|
||||||
mRequest,
|
|
||||||
boost::bind (&HttpsClient::handleWrite,
|
|
||||||
shared_from_this (),
|
|
||||||
boost::asio::placeholders::error,
|
|
||||||
boost::asio::placeholders::bytes_transferred));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::handleWrite (const boost::system::error_code& ecResult, std::size_t bytes_transferred)
|
|
||||||
{
|
|
||||||
if (!mShutdown)
|
|
||||||
mShutdown = ecResult;
|
|
||||||
|
|
||||||
if (mShutdown)
|
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Write error: " << mShutdown.message ();
|
|
||||||
|
|
||||||
invokeComplete (mShutdown);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Wrote.";
|
|
||||||
|
|
||||||
mSocket.async_read_until (
|
|
||||||
mHeader,
|
|
||||||
"\r\n\r\n",
|
|
||||||
boost::bind (&HttpsClient::handleHeader,
|
|
||||||
shared_from_this (),
|
|
||||||
boost::asio::placeholders::error,
|
|
||||||
boost::asio::placeholders::bytes_transferred));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::handleHeader (const boost::system::error_code& ecResult, std::size_t bytes_transferred)
|
|
||||||
{
|
|
||||||
std::string strHeader ((std::istreambuf_iterator<char> (&mHeader)), std::istreambuf_iterator<char> ());
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Header: \"" << strHeader << "\"";
|
|
||||||
|
|
||||||
static boost::regex reStatus ("\\`HTTP/1\\S+ (\\d{3}) .*\\'"); // HTTP/1.1 200 OK
|
|
||||||
static boost::regex reSize ("\\`.*\\r\\nContent-Length:\\s+([0-9]+).*\\'");
|
|
||||||
static boost::regex reBody ("\\`.*\\r\\n\\r\\n(.*)\\'");
|
|
||||||
|
|
||||||
boost::smatch smMatch;
|
|
||||||
|
|
||||||
bool bMatch = boost::regex_match (strHeader, smMatch, reStatus); // Match status code.
|
|
||||||
|
|
||||||
if (!bMatch)
|
|
||||||
{
|
|
||||||
// XXX Use our own error code.
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "No status code";
|
|
||||||
invokeComplete (boost::system::error_code (boost::system::errc::bad_address, boost::system::system_category ()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mStatus = lexicalCastThrow <int> (std::string (smMatch[1]));
|
|
||||||
|
|
||||||
if (boost::regex_match (strHeader, smMatch, reBody)) // we got some body
|
|
||||||
mBody = smMatch[1];
|
|
||||||
|
|
||||||
if (boost::regex_match (strHeader, smMatch, reSize))
|
|
||||||
{
|
|
||||||
int size = lexicalCastThrow <int> (std::string(smMatch[1]));
|
|
||||||
|
|
||||||
if (size < mResponseMax)
|
|
||||||
mResponseMax = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mResponseMax == 0)
|
|
||||||
{
|
|
||||||
// no body wanted or available
|
|
||||||
invokeComplete (ecResult, mStatus);
|
|
||||||
}
|
|
||||||
else if (mBody.size () >= mResponseMax)
|
|
||||||
{
|
|
||||||
// we got the whole thing
|
|
||||||
invokeComplete (ecResult, mStatus, mBody);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mSocket.async_read (
|
|
||||||
mResponse.prepare (mResponseMax - mBody.size ()),
|
|
||||||
boost::asio::transfer_all (),
|
|
||||||
boost::bind (&HttpsClient::handleData,
|
|
||||||
shared_from_this (),
|
|
||||||
boost::asio::placeholders::error,
|
|
||||||
boost::asio::placeholders::bytes_transferred));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::handleData (const boost::system::error_code& ecResult, std::size_t bytes_transferred)
|
|
||||||
{
|
|
||||||
if (!mShutdown)
|
|
||||||
mShutdown = ecResult;
|
|
||||||
|
|
||||||
if (mShutdown && mShutdown != boost::asio::error::eof)
|
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Read error: " << mShutdown.message ();
|
|
||||||
|
|
||||||
invokeComplete (mShutdown);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (mShutdown)
|
|
||||||
{
|
{
|
||||||
WriteLog (lsTRACE, HttpsClient) << "Complete.";
|
WriteLog (lsTRACE, HTTPClient) << "invokeComplete: Deadline cancel error: " << ecCancel.message ();
|
||||||
|
|
||||||
nothing ();
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
WriteLog (lsDEBUG, HTTPClient) << "invokeComplete: Deadline popping: " << mDeqSites.size ();
|
||||||
|
|
||||||
|
if (!mDeqSites.empty ())
|
||||||
{
|
{
|
||||||
mResponse.commit (bytes_transferred);
|
mDeqSites.pop_front ();
|
||||||
std::string strBody ((std::istreambuf_iterator<char> (&mResponse)), std::istreambuf_iterator<char> ());
|
}
|
||||||
invokeComplete (ecResult, mStatus, mBody + strBody);
|
|
||||||
|
bool bAgain = true;
|
||||||
|
|
||||||
|
if (mDeqSites.empty () || !ecResult)
|
||||||
|
{
|
||||||
|
// ecResult: !0 = had an error, last entry
|
||||||
|
// iStatus: result, if no error
|
||||||
|
// strData: data, if no error
|
||||||
|
bAgain = mComplete && mComplete (ecResult ? ecResult : ecCancel, iStatus, strData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mDeqSites.empty () && bAgain)
|
||||||
|
{
|
||||||
|
httpsNext ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Call cancel the deadline timer and invoke the completion routine.
|
static bool onSMSResponse (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)
|
||||||
void HttpsClient::invokeComplete (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)
|
|
||||||
{
|
|
||||||
boost::system::error_code ecCancel;
|
|
||||||
|
|
||||||
(void) mDeadline.cancel (ecCancel);
|
|
||||||
|
|
||||||
if (ecCancel)
|
|
||||||
{
|
{
|
||||||
WriteLog (lsTRACE, HttpsClient) << "HttpsClient::invokeComplete: Deadline cancel error: " << ecCancel.message ();
|
WriteLog (lsINFO, HTTPClient) << "SMS: Response:" << iStatus << " :" << strData;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteLog (lsDEBUG, HttpsClient) << "HttpsClient::invokeComplete: Deadline popping: " << mDeqSites.size ();
|
private:
|
||||||
|
typedef boost::shared_ptr<HTTPClient> pointer;
|
||||||
|
|
||||||
if (!mDeqSites.empty ())
|
bool mSSL;
|
||||||
{
|
AutoSocket mSocket;
|
||||||
mDeqSites.pop_front ();
|
boost::asio::ip::tcp::resolver mResolver;
|
||||||
}
|
boost::shared_ptr<boost::asio::ip::tcp::resolver::query> mQuery;
|
||||||
|
boost::asio::streambuf mRequest;
|
||||||
|
boost::asio::streambuf mHeader;
|
||||||
|
boost::asio::streambuf mResponse;
|
||||||
|
std::string mBody;
|
||||||
|
const unsigned short mPort;
|
||||||
|
int mResponseMax;
|
||||||
|
int mStatus;
|
||||||
|
FUNCTION_TYPE<void (boost::asio::streambuf& sb, const std::string& strHost)> mBuild;
|
||||||
|
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> mComplete;
|
||||||
|
|
||||||
bool bAgain = true;
|
boost::asio::deadline_timer mDeadline;
|
||||||
|
|
||||||
if (mDeqSites.empty () || !ecResult)
|
// If not success, we are shutting down.
|
||||||
{
|
boost::system::error_code mShutdown;
|
||||||
// ecResult: !0 = had an error, last entry
|
|
||||||
// iStatus: result, if no error
|
|
||||||
// strData: data, if no error
|
|
||||||
bAgain = mComplete && mComplete (ecResult ? ecResult : ecCancel, iStatus, strData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mDeqSites.empty () && bAgain)
|
std::deque<std::string> mDeqSites;
|
||||||
{
|
boost::posix_time::time_duration mTimeout;
|
||||||
httpsNext ();
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::httpsGet (
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void HTTPClient::get (
|
||||||
bool bSSL,
|
bool bSSL,
|
||||||
boost::asio::io_service& io_service,
|
boost::asio::io_service& io_service,
|
||||||
std::deque<std::string> deqSites,
|
std::deque<std::string> deqSites,
|
||||||
@@ -409,15 +461,16 @@ void HttpsClient::httpsGet (
|
|||||||
const std::string& strPath,
|
const std::string& strPath,
|
||||||
std::size_t responseMax,
|
std::size_t responseMax,
|
||||||
boost::posix_time::time_duration timeout,
|
boost::posix_time::time_duration timeout,
|
||||||
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete)
|
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus,
|
||||||
|
const std::string& strData)> complete)
|
||||||
{
|
{
|
||||||
|
boost::shared_ptr <HTTPClientImp> client (
|
||||||
|
new HTTPClientImp (io_service, port, responseMax));
|
||||||
|
|
||||||
boost::shared_ptr<HttpsClient> client (new HttpsClient (io_service, port, responseMax));
|
client->get (bSSL, deqSites, strPath, timeout, complete);
|
||||||
|
|
||||||
client->httpsGet (bSSL, deqSites, strPath, timeout, complete);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpsClient::httpsGet (
|
void HTTPClient::get (
|
||||||
bool bSSL,
|
bool bSSL,
|
||||||
boost::asio::io_service& io_service,
|
boost::asio::io_service& io_service,
|
||||||
std::string strSite,
|
std::string strSite,
|
||||||
@@ -425,17 +478,18 @@ void HttpsClient::httpsGet (
|
|||||||
const std::string& strPath,
|
const std::string& strPath,
|
||||||
std::size_t responseMax,
|
std::size_t responseMax,
|
||||||
boost::posix_time::time_duration timeout,
|
boost::posix_time::time_duration timeout,
|
||||||
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete)
|
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus,
|
||||||
|
const std::string& strData)> complete)
|
||||||
{
|
{
|
||||||
|
|
||||||
std::deque<std::string> deqSites (1, strSite);
|
std::deque<std::string> deqSites (1, strSite);
|
||||||
|
|
||||||
boost::shared_ptr<HttpsClient> client (new HttpsClient (io_service, port, responseMax));
|
boost::shared_ptr <HTTPClientImp> client (
|
||||||
|
new HTTPClientImp (io_service, port, responseMax));
|
||||||
|
|
||||||
client->httpsGet (bSSL, deqSites, strPath, timeout, complete);
|
client->get (bSSL, deqSites, strPath, timeout, complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpsClient::httpsRequest (
|
void HTTPClient::request (
|
||||||
bool bSSL,
|
bool bSSL,
|
||||||
boost::asio::io_service& io_service,
|
boost::asio::io_service& io_service,
|
||||||
std::string strSite,
|
std::string strSite,
|
||||||
@@ -443,26 +497,18 @@ void HttpsClient::httpsRequest (
|
|||||||
FUNCTION_TYPE<void (boost::asio::streambuf& sb, const std::string& strHost)> setRequest,
|
FUNCTION_TYPE<void (boost::asio::streambuf& sb, const std::string& strHost)> setRequest,
|
||||||
std::size_t responseMax,
|
std::size_t responseMax,
|
||||||
boost::posix_time::time_duration timeout,
|
boost::posix_time::time_duration timeout,
|
||||||
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete)
|
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus,
|
||||||
|
const std::string& strData)> complete)
|
||||||
{
|
{
|
||||||
|
|
||||||
std::deque<std::string> deqSites (1, strSite);
|
std::deque<std::string> deqSites (1, strSite);
|
||||||
|
|
||||||
boost::shared_ptr<HttpsClient> client (new HttpsClient (io_service, port, responseMax));
|
boost::shared_ptr <HTTPClientImp> client (
|
||||||
|
new HTTPClientImp (io_service, port, responseMax));
|
||||||
|
|
||||||
client->httpsRequest (bSSL, deqSites, setRequest, timeout, complete);
|
client->request (bSSL, deqSites, setRequest, timeout, complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SMS_TIMEOUT 30
|
void HTTPClient::sendSMS (boost::asio::io_service& io_service, const std::string& strText)
|
||||||
|
|
||||||
bool responseSMS (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)
|
|
||||||
{
|
|
||||||
WriteLog (lsINFO, HttpsClient) << "SMS: Response:" << iStatus << " :" << strData;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpsClient::sendSMS (boost::asio::io_service& io_service, const std::string& strText)
|
|
||||||
{
|
{
|
||||||
std::string strScheme;
|
std::string strScheme;
|
||||||
std::string strDomain;
|
std::string strDomain;
|
||||||
@@ -471,11 +517,11 @@ void HttpsClient::sendSMS (boost::asio::io_service& io_service, const std::strin
|
|||||||
|
|
||||||
if (getConfig ().SMS_URL == "" || !parseUrl (getConfig ().SMS_URL, strScheme, strDomain, iPort, strPath))
|
if (getConfig ().SMS_URL == "" || !parseUrl (getConfig ().SMS_URL, strScheme, strDomain, iPort, strPath))
|
||||||
{
|
{
|
||||||
WriteLog (lsWARNING, HttpsClient) << "SMSRequest: Bad URL:" << getConfig ().SMS_URL;
|
WriteLog (lsWARNING, HTTPClient) << "SMSRequest: Bad URL:" << getConfig ().SMS_URL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool bSSL = strScheme == "https";
|
bool const bSSL = strScheme == "https";
|
||||||
|
|
||||||
std::deque<std::string> deqSites (1, strDomain);
|
std::deque<std::string> deqSites (1, strDomain);
|
||||||
std::string strURI =
|
std::string strURI =
|
||||||
@@ -488,15 +534,16 @@ void HttpsClient::sendSMS (boost::asio::io_service& io_service, const std::strin
|
|||||||
% urlEncode (strText));
|
% urlEncode (strText));
|
||||||
|
|
||||||
// WriteLog (lsINFO) << "SMS: Request:" << strURI;
|
// WriteLog (lsINFO) << "SMS: Request:" << strURI;
|
||||||
WriteLog (lsINFO, HttpsClient) << "SMS: Request: '" << strText << "'";
|
WriteLog (lsINFO, HTTPClient) << "SMS: Request: '" << strText << "'";
|
||||||
|
|
||||||
if (iPort < 0)
|
if (iPort < 0)
|
||||||
iPort = bSSL ? 443 : 80;
|
iPort = bSSL ? 443 : 80;
|
||||||
|
|
||||||
boost::shared_ptr<HttpsClient> client (new HttpsClient (io_service, iPort, maxClientHeaderBytes));
|
boost::shared_ptr <HTTPClientImp> client (
|
||||||
|
new HTTPClientImp (io_service, iPort, maxClientHeaderBytes));
|
||||||
|
|
||||||
client->httpsGet (bSSL, deqSites, strURI, boost::posix_time::seconds (SMS_TIMEOUT),
|
client->get (bSSL, deqSites, strURI, boost::posix_time::seconds (smsTimeoutSeconds),
|
||||||
BIND_TYPE (&responseSMS, P_1, P_2, P_3));
|
BIND_TYPE (&HTTPClientImp::onSMSResponse, P_1, P_2, P_3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// vim:ts=4
|
|
||||||
|
|||||||
@@ -7,43 +7,17 @@
|
|||||||
#ifndef RIPPLE_NET_BASICS_HTTPCLIENT_H_INCLUDED
|
#ifndef RIPPLE_NET_BASICS_HTTPCLIENT_H_INCLUDED
|
||||||
#define RIPPLE_NET_BASICS_HTTPCLIENT_H_INCLUDED
|
#define RIPPLE_NET_BASICS_HTTPCLIENT_H_INCLUDED
|
||||||
|
|
||||||
// VFALCO TODO Make this an abstract interface.
|
/** Provides an asynchronous HTTP client implementation with optional SSL.
|
||||||
//
|
|
||||||
/** Provides an asynchronous HTTPS client implementation.
|
|
||||||
*/
|
*/
|
||||||
class HttpsClient
|
class HTTPClient
|
||||||
: public boost::enable_shared_from_this <HttpsClient>
|
|
||||||
, LeakChecked <HttpsClient>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HttpsClient (
|
enum
|
||||||
boost::asio::io_service& io_service,
|
{
|
||||||
const unsigned short port,
|
maxClientHeaderBytes = 32 * 1024
|
||||||
std::size_t responseMax
|
};
|
||||||
);
|
|
||||||
|
|
||||||
// VFALCO NOTE Putting "https" is redundant, the class is
|
static void get (
|
||||||
// already called HttpsClient.
|
|
||||||
//
|
|
||||||
// VFALCO TODO Rename these to request, get, and next.
|
|
||||||
//
|
|
||||||
void httpsRequest (
|
|
||||||
bool bSSL,
|
|
||||||
std::deque<std::string> deqSites,
|
|
||||||
FUNCTION_TYPE <void (boost::asio::streambuf& sb, const std::string& strHost)> build,
|
|
||||||
boost::posix_time::time_duration timeout,
|
|
||||||
FUNCTION_TYPE <bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
|
||||||
|
|
||||||
void httpsGet (
|
|
||||||
bool bSSL,
|
|
||||||
std::deque<std::string> deqSites,
|
|
||||||
const std::string& strPath,
|
|
||||||
boost::posix_time::time_duration timeout,
|
|
||||||
FUNCTION_TYPE <bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
|
||||||
|
|
||||||
// VFALCO TODO These statics all belong in some HttpsClientOperations class
|
|
||||||
//
|
|
||||||
static void httpsGet (
|
|
||||||
bool bSSL,
|
bool bSSL,
|
||||||
boost::asio::io_service& io_service,
|
boost::asio::io_service& io_service,
|
||||||
std::deque <std::string> deqSites,
|
std::deque <std::string> deqSites,
|
||||||
@@ -53,7 +27,7 @@ public:
|
|||||||
boost::posix_time::time_duration timeout,
|
boost::posix_time::time_duration timeout,
|
||||||
FUNCTION_TYPE <bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
FUNCTION_TYPE <bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
||||||
|
|
||||||
static void httpsGet (
|
static void get (
|
||||||
bool bSSL,
|
bool bSSL,
|
||||||
boost::asio::io_service& io_service,
|
boost::asio::io_service& io_service,
|
||||||
std::string strSite,
|
std::string strSite,
|
||||||
@@ -63,7 +37,7 @@ public:
|
|||||||
boost::posix_time::time_duration timeout,
|
boost::posix_time::time_duration timeout,
|
||||||
FUNCTION_TYPE <bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
FUNCTION_TYPE <bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
||||||
|
|
||||||
static void httpsRequest (
|
static void request (
|
||||||
bool bSSL,
|
bool bSSL,
|
||||||
boost::asio::io_service& io_service,
|
boost::asio::io_service& io_service,
|
||||||
std::string strSite,
|
std::string strSite,
|
||||||
@@ -73,57 +47,12 @@ public:
|
|||||||
boost::posix_time::time_duration timeout,
|
boost::posix_time::time_duration timeout,
|
||||||
FUNCTION_TYPE <bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
FUNCTION_TYPE <bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
smsTimeoutSeconds = 30
|
||||||
|
};
|
||||||
|
|
||||||
static void sendSMS (boost::asio::io_service& io_service, const std::string& strText);
|
static void sendSMS (boost::asio::io_service& io_service, const std::string& strText);
|
||||||
|
|
||||||
private:
|
|
||||||
static const int maxClientHeaderBytes = 32 * 1024;
|
|
||||||
|
|
||||||
typedef boost::shared_ptr<HttpsClient> pointer;
|
|
||||||
|
|
||||||
bool mSSL;
|
|
||||||
AutoSocket mSocket;
|
|
||||||
boost::asio::ip::tcp::resolver mResolver;
|
|
||||||
boost::shared_ptr<boost::asio::ip::tcp::resolver::query> mQuery;
|
|
||||||
boost::asio::streambuf mRequest;
|
|
||||||
boost::asio::streambuf mHeader;
|
|
||||||
boost::asio::streambuf mResponse;
|
|
||||||
std::string mBody;
|
|
||||||
const unsigned short mPort;
|
|
||||||
int mResponseMax;
|
|
||||||
int mStatus;
|
|
||||||
FUNCTION_TYPE<void (boost::asio::streambuf& sb, const std::string& strHost)> mBuild;
|
|
||||||
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> mComplete;
|
|
||||||
|
|
||||||
boost::asio::deadline_timer mDeadline;
|
|
||||||
|
|
||||||
// If not success, we are shutting down.
|
|
||||||
boost::system::error_code mShutdown;
|
|
||||||
|
|
||||||
std::deque<std::string> mDeqSites;
|
|
||||||
boost::posix_time::time_duration mTimeout;
|
|
||||||
|
|
||||||
void handleDeadline (const boost::system::error_code& ecResult);
|
|
||||||
|
|
||||||
void handleResolve (const boost::system::error_code& ecResult, boost::asio::ip::tcp::resolver::iterator endpoint_iterator);
|
|
||||||
|
|
||||||
void handleConnect (const boost::system::error_code& ecResult);
|
|
||||||
|
|
||||||
void handleRequest (const boost::system::error_code& ecResult);
|
|
||||||
|
|
||||||
void handleWrite (const boost::system::error_code& ecResult, std::size_t bytes_transferred);
|
|
||||||
|
|
||||||
void handleHeader (const boost::system::error_code& ecResult, std::size_t bytes_transferred);
|
|
||||||
|
|
||||||
void handleData (const boost::system::error_code& ecResult, std::size_t bytes_transferred);
|
|
||||||
|
|
||||||
void handleShutdown (const boost::system::error_code& ecResult);
|
|
||||||
|
|
||||||
void httpsNext ();
|
|
||||||
|
|
||||||
void invokeComplete (const boost::system::error_code& ecResult, int iStatus = 0, const std::string& strData = "");
|
|
||||||
|
|
||||||
void makeGet (const std::string& strPath, boost::asio::streambuf& sb, const std::string& strHost);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1130,7 +1130,7 @@ void RPCCall::fromNetwork (
|
|||||||
const int RPC_REPLY_MAX_BYTES (128*1024*1024);
|
const int RPC_REPLY_MAX_BYTES (128*1024*1024);
|
||||||
const int RPC_NOTIFY_SECONDS (30);
|
const int RPC_NOTIFY_SECONDS (30);
|
||||||
|
|
||||||
HttpsClient::httpsRequest (
|
HTTPClient::request (
|
||||||
bSSL,
|
bSSL,
|
||||||
io_service,
|
io_service,
|
||||||
strIp,
|
strIp,
|
||||||
|
|||||||
Reference in New Issue
Block a user