mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2026-08-15 15:40:59 +00:00
rollback to old implemntation without boost::beast
This commit is contained in:
@@ -12,10 +12,8 @@
|
||||
#include <unordered_map>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <openssl/rand.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/beast.hpp>
|
||||
#include "Base.h"
|
||||
#include "util.h"
|
||||
#include "Timestamp.h"
|
||||
@@ -23,7 +21,6 @@
|
||||
#include "FS.h"
|
||||
#include "Log.h"
|
||||
#include "Config.h"
|
||||
#include "BoostStream.h"
|
||||
#include "HTTP.h"
|
||||
#include "NetDb.hpp"
|
||||
#include "ClientContext.h"
|
||||
@@ -952,6 +949,7 @@ namespace client
|
||||
m_Book.DownloadComplete (result, m_Ident, m_Etag, m_LastModified);
|
||||
}
|
||||
|
||||
|
||||
bool AddressBookSubscription::MakeRequest ()
|
||||
{
|
||||
i2p::http::URL url;
|
||||
@@ -985,88 +983,117 @@ namespace client
|
||||
// destroy stream in destination's thread on exit
|
||||
boost::asio::post (i2p::client::context.GetSharedLocalDestination ()->GetService (), [s = std::move (stream)](){});
|
||||
});
|
||||
|
||||
if (m_Etag.empty() && m_LastModified.empty())
|
||||
{
|
||||
m_Book.GetEtag (m_Ident, m_Etag, m_LastModified);
|
||||
LogPrint (eLogDebug, "Addressbook: Loaded for ", url.host, ": ETag: ", m_Etag, ", Last-Modified: ", m_LastModified);
|
||||
}
|
||||
// create http request & send it
|
||||
boost::beast::http::request<boost::beast::http::string_body> req (boost::beast::http::verb::get, url.to_string (true), 11); // HTTP 1.1
|
||||
req.set (boost::beast::http::field::host, dest_host);
|
||||
req.set (boost::beast::http::field::user_agent, "Wget/1.11.4");
|
||||
req.set (boost::beast::http::field::accept_encoding, "gzip");
|
||||
req.set ("X-Accept-Encoding", "x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0");
|
||||
i2p::http::HTTPReq req;
|
||||
req.AddHeader("Host", dest_host);
|
||||
req.AddHeader("User-Agent", "Wget/1.11.4");
|
||||
req.AddHeader("Accept-Encoding", "gzip");
|
||||
req.AddHeader("X-Accept-Encoding", "x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0");
|
||||
req.AddHeader("Connection", "close");
|
||||
if (!m_Etag.empty())
|
||||
req.set (boost::beast::http::field::if_none_match, m_Etag); // If-None-Match
|
||||
req.AddHeader("If-None-Match", m_Etag);
|
||||
if (!m_LastModified.empty())
|
||||
req.set (boost::beast::http::field::if_modified_since, m_LastModified); // If-Modified-Since
|
||||
req.keep_alive (false); // Connection: close
|
||||
|
||||
i2p::client::BoostAsyncStream httpStream (stream, SUBSCRIPTION_REQUEST_TIMEOUT);
|
||||
std::future<size_t> sending = boost::beast::http::async_write (httpStream, req, boost::asio::use_future);
|
||||
try
|
||||
req.AddHeader("If-Modified-Since", m_LastModified);
|
||||
// convert url to relative
|
||||
url.schema = "";
|
||||
url.host = "";
|
||||
req.uri = url.to_string();
|
||||
req.version = "HTTP/1.1";
|
||||
std::string request = req.to_string();
|
||||
stream->Send ((const uint8_t *) request.data(), request.length());
|
||||
// read response
|
||||
std::string response;
|
||||
uint8_t recv_buf[4096];
|
||||
bool end = false;
|
||||
int numAttempts = 0;
|
||||
while (!end)
|
||||
{
|
||||
size_t bytes_transferred = sending.get();
|
||||
if (!bytes_transferred)
|
||||
size_t received = stream->Receive (recv_buf, 4096, SUBSCRIPTION_REQUEST_TIMEOUT);
|
||||
if (received)
|
||||
{
|
||||
LogPrint(eLogError, "Addressbook: HTTP request to ", dest_host, " was not sent");
|
||||
return false;
|
||||
response.append ((char *)recv_buf, received);
|
||||
if (!stream->IsOpen ()) end = true;
|
||||
}
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint(eLogError, "Addressbook: Send HTTP request exception: ", ex.what ());
|
||||
return false;
|
||||
}
|
||||
boost::beast::flat_buffer receiveBuffer;
|
||||
boost::beast::http::response<boost::beast::http::string_body> res;
|
||||
std::future<size_t> receiving = boost::beast::http::async_read (httpStream, receiveBuffer, res, boost::asio::use_future);
|
||||
try
|
||||
{
|
||||
size_t bytes_transferred = receiving.get();
|
||||
if (!bytes_transferred)
|
||||
{
|
||||
LogPrint(eLogError, "Addressbook: HTTP response from ", dest_host, " was not received");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint(eLogError, "Addressbook: Receive HTTP response exception: ", ex.what ());
|
||||
return false;
|
||||
}
|
||||
stream->AsyncClose ();
|
||||
// check result
|
||||
if (res.result () != boost::beast::http::status::ok)
|
||||
{
|
||||
if (res.result_int() == 304)
|
||||
LogPrint (eLogInfo, "Addressbook: No updates from ", dest_host, ", code 304");
|
||||
else if (!stream->IsOpen ())
|
||||
end = true;
|
||||
else
|
||||
LogPrint (eLogWarning, "Addressbook: Response code ", res.result_int(), " from ", dest_host);
|
||||
{
|
||||
LogPrint (eLogError, "Addressbook: Subscriptions request timeout expired");
|
||||
numAttempts++;
|
||||
if (numAttempts > 5) end = true;
|
||||
}
|
||||
}
|
||||
// process remaining buffer
|
||||
while (size_t len = stream->ReadSome (recv_buf, sizeof(recv_buf)))
|
||||
response.append ((char *)recv_buf, len);
|
||||
// parse response
|
||||
i2p::http::HTTPRes res;
|
||||
int res_head_len = res.parse(response);
|
||||
if (res_head_len < 0)
|
||||
{
|
||||
LogPrint(eLogError, "Addressbook: Can't parse http response from ", dest_host);
|
||||
return false;
|
||||
}
|
||||
// update Etag and Last-Modified
|
||||
auto eTag = res[boost::beast::http::field::etag];
|
||||
if (!eTag.empty ()) m_Etag = std::string (eTag);
|
||||
auto lastModified = res[boost::beast::http::field::last_modified];
|
||||
if (!lastModified.empty ()) m_LastModified = std::string (lastModified);
|
||||
// parse response
|
||||
LogPrint (eLogInfo, "Addressbook: Got update from ", dest_host);
|
||||
if (res[boost::beast::http::field::content_encoding] == "gzip" ||
|
||||
res[boost::beast::http::field::content_encoding] =="x-i2p-gzip")
|
||||
if (res_head_len == 0)
|
||||
{
|
||||
std::stringstream unzipped;
|
||||
LogPrint(eLogError, "Addressbook: Incomplete http response from ", dest_host, ", interrupted by timeout");
|
||||
return false;
|
||||
}
|
||||
// assert: res_head_len > 0
|
||||
response.erase(0, res_head_len);
|
||||
if (res.code == 304)
|
||||
{
|
||||
LogPrint (eLogInfo, "Addressbook: No updates from ", dest_host, ", code 304");
|
||||
return false;
|
||||
}
|
||||
if (res.code != 200)
|
||||
{
|
||||
LogPrint (eLogWarning, "Adressbook: Can't get updates from ", dest_host, ", response code ", res.code);
|
||||
return false;
|
||||
}
|
||||
int len = res.content_length();
|
||||
if (response.empty())
|
||||
{
|
||||
LogPrint(eLogError, "Addressbook: Empty response from ", dest_host, ", expected ", len, " bytes");
|
||||
return false;
|
||||
}
|
||||
if (!res.is_gzipped () && len > 0 && len != (int) response.length())
|
||||
{
|
||||
LogPrint(eLogError, "Addressbook: Response size mismatch, expected: ", len, ", got: ", response.length(), "bytes");
|
||||
return false;
|
||||
}
|
||||
// assert: res.code == 200
|
||||
auto it = res.headers.find("ETag");
|
||||
if (it != res.headers.end()) m_Etag = it->second;
|
||||
it = res.headers.find("Last-Modified");
|
||||
if (it != res.headers.end()) m_LastModified = it->second;
|
||||
if (res.is_chunked())
|
||||
{
|
||||
std::stringstream in(response), out;
|
||||
i2p::http::MergeChunkedResponse (in, out);
|
||||
response = out.str();
|
||||
}
|
||||
if (res.is_gzipped())
|
||||
{
|
||||
std::stringstream out;
|
||||
i2p::data::GzipInflator inflator;
|
||||
inflator.Inflate ((const uint8_t *)res.body().data(), res.body().size(), unzipped);
|
||||
if (unzipped.fail())
|
||||
inflator.Inflate ((const uint8_t *) response.data(), response.length(), out);
|
||||
if (out.fail())
|
||||
{
|
||||
LogPrint(eLogError, "Addressbook: Can't gunzip http response");
|
||||
return false;
|
||||
}
|
||||
m_Book.LoadHostsFromStream (std::move (unzipped), true);
|
||||
response = out.str();
|
||||
}
|
||||
else
|
||||
m_Book.LoadHostsFromStream (std::stringstream(res.body ()), true);
|
||||
std::stringstream ss(response);
|
||||
LogPrint (eLogInfo, "Addressbook: Got update from ", dest_host);
|
||||
m_Book.LoadHostsFromStream (std::move (ss), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user