diff --git a/src/cpp/ripple/HttpsClient.cpp b/src/cpp/ripple/HttpsClient.cpp index 746e65a92..fb05bf381 100644 --- a/src/cpp/ripple/HttpsClient.cpp +++ b/src/cpp/ripple/HttpsClient.cpp @@ -17,6 +17,8 @@ SETUP_LOG(); +#define CLIENT_MAX_HEADER (32*1024) + using namespace boost::system; using namespace boost::asio; @@ -27,8 +29,9 @@ HttpsClient::HttpsClient( ) : mSocket(io_service, theConfig.SSL_CONTEXT), mResolver(io_service), - mResponse(responseMax), + mHeader(CLIENT_MAX_HEADER), mPort(port), + mResponseMax(responseMax), mDeadline(io_service) { } @@ -271,14 +274,59 @@ void HttpsClient::handleWrite(const boost::system::error_code& ecResult, std::si { cLog(lsTRACE) << "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(&mHeader)), std::istreambuf_iterator()); + cLog(lsTRACE) << "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. + cLog(lsTRACE) << "No status code"; + invokeComplete(boost::system::error_code(errc::bad_address, system_category())); + return; + } + mStatus = lexical_cast_st(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 = lexical_cast_st(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, + 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) @@ -302,11 +350,10 @@ void HttpsClient::handleData(const boost::system::error_code& ecResult, std::siz } else { - // XXX According to boost example code, this is what we should expect for success. - cLog(lsTRACE) << "Complete, no eof."; + mResponse.commit(bytes_transferred); + std::string strBody((std::istreambuf_iterator(&mResponse)), std::istreambuf_iterator()); + invokeComplete(ecResult, mStatus, mBody + strBody); } - - parseData(); } } @@ -340,36 +387,6 @@ void HttpsClient::invokeComplete(const boost::system::error_code& ecResult, int } } -void HttpsClient::parseData() -{ - std::string strData((std::istreambuf_iterator(&mResponse)), std::istreambuf_iterator()); - - static boost::regex reStatus("\\`HTTP/1\\S+ (\\d{3}) .*\\'"); // HTTP/1.1 200 OK - static boost::regex reBody("\\`(?:.*?\\r\\n\\r\\n){1}(.*)\\'"); - - boost::smatch smStatus; - boost::smatch smBody; - - bool bMatch = boost::regex_match(strData, smStatus, reStatus) // Match status code. - && boost::regex_match(strData, smBody, reBody); // Match body. - - // std::cerr << "Data:" << strData << std::endl; - // std::cerr << "Match: " << bMatch << std::endl; - // std::cerr << "Body:" << smBody[1] << std::endl; - - if (bMatch) - { - boost::system::error_code noErr; - - invokeComplete(noErr, lexical_cast_st(smStatus[1]), smBody[1]); - } - else - { - // XXX Use our own error code. - invokeComplete(boost::system::error_code(errc::bad_address, system_category())); - } -} - void HttpsClient::httpsGet( bool bSSL, boost::asio::io_service& io_service, diff --git a/src/cpp/ripple/HttpsClient.h b/src/cpp/ripple/HttpsClient.h index 41831a61c..d4e89df6c 100644 --- a/src/cpp/ripple/HttpsClient.h +++ b/src/cpp/ripple/HttpsClient.h @@ -27,8 +27,12 @@ private: boost::asio::ip::tcp::resolver mResolver; boost::shared_ptr mQuery; boost::asio::streambuf mRequest; + boost::asio::streambuf mHeader; boost::asio::streambuf mResponse; + std::string mBody; const unsigned short mPort; + int mResponseMax; + int mStatus; boost::function mBuild; boost::function mComplete; @@ -50,11 +54,12 @@ private: 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 parseData(); void httpsNext(); void invokeComplete(const boost::system::error_code& ecResult, int iStatus = 0, const std::string& strData = "");