Browse Source

compressed addressbook request

pull/759/merge
orignal 8 years ago
parent
commit
b097938f47
  1. 50
      AddressBook.cpp
  2. 11
      HTTP.cpp
  3. 6
      HTTP.h

50
AddressBook.cpp

@ -705,6 +705,7 @@ namespace client
i2p::http::HTTPReq req; i2p::http::HTTPReq req;
req.AddHeader("Host", dest_host); req.AddHeader("Host", dest_host);
req.AddHeader("User-Agent", "Wget/1.11.4"); req.AddHeader("User-Agent", "Wget/1.11.4");
req.AddHeader("X-Accept-Encoding", "x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n");
req.AddHeader("Connection", "close"); req.AddHeader("Connection", "close");
if (!m_Etag.empty()) if (!m_Etag.empty())
req.AddHeader("If-None-Match", m_Etag); req.AddHeader("If-None-Match", m_Etag);
@ -721,7 +722,9 @@ namespace client
std::string response; std::string response;
uint8_t recv_buf[4096]; uint8_t recv_buf[4096];
bool end = false; bool end = false;
while (!end) { int numAttempts = 5;
while (!end)
{
stream->AsyncReceive (boost::asio::buffer (recv_buf, 4096), stream->AsyncReceive (boost::asio::buffer (recv_buf, 4096),
[&](const boost::system::error_code& ecode, std::size_t bytes_transferred) [&](const boost::system::error_code& ecode, std::size_t bytes_transferred)
{ {
@ -734,60 +737,69 @@ namespace client
30); // wait for 30 seconds 30); // wait for 30 seconds
std::unique_lock<std::mutex> l(newDataReceivedMutex); std::unique_lock<std::mutex> l(newDataReceivedMutex);
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout) if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout)
{
LogPrint (eLogError, "Addressbook: subscriptions request timeout expired"); LogPrint (eLogError, "Addressbook: subscriptions request timeout expired");
numAttempts++;
if (numAttempts > 5) end = true;
}
} }
// process remaining buffer // process remaining buffer
while (size_t len = stream->ReadSome (recv_buf, sizeof(recv_buf))) { while (size_t len = stream->ReadSome (recv_buf, sizeof(recv_buf)))
response.append ((char *)recv_buf, len); response.append ((char *)recv_buf, len);
}
/* parse response */ /* parse response */
i2p::http::HTTPRes res; i2p::http::HTTPRes res;
int res_head_len = res.parse(response); int res_head_len = res.parse(response);
if (res_head_len < 0) { if (res_head_len < 0)
{
LogPrint(eLogError, "Addressbook: can't parse http response from ", dest_host); LogPrint(eLogError, "Addressbook: can't parse http response from ", dest_host);
return false; return false;
} }
if (res_head_len == 0) { if (res_head_len == 0)
{
LogPrint(eLogError, "Addressbook: incomplete http response from ", dest_host, ", interrupted by timeout"); LogPrint(eLogError, "Addressbook: incomplete http response from ", dest_host, ", interrupted by timeout");
return false; return false;
} }
/* assert: res_head_len > 0 */ /* assert: res_head_len > 0 */
response.erase(0, res_head_len); response.erase(0, res_head_len);
if (res.code == 304) { if (res.code == 304)
{
LogPrint (eLogInfo, "Addressbook: no updates from ", dest_host, ", code 304"); LogPrint (eLogInfo, "Addressbook: no updates from ", dest_host, ", code 304");
return false; return false;
} }
if (res.code != 200) { if (res.code != 200)
{
LogPrint (eLogWarning, "Adressbook: can't get updates from ", dest_host, ", response code ", res.code); LogPrint (eLogWarning, "Adressbook: can't get updates from ", dest_host, ", response code ", res.code);
return false; return false;
} }
int len = res.content_length(); int len = res.content_length();
if (response.empty()) { if (response.empty())
{
LogPrint(eLogError, "Addressbook: empty response from ", dest_host, ", expected ", len, " bytes"); LogPrint(eLogError, "Addressbook: empty response from ", dest_host, ", expected ", len, " bytes");
return false; return false;
} }
if (len > 0 && len != (int) response.length()) { if (!res.is_gzipped () && len > 0 && len != (int) response.length())
LogPrint(eLogError, "Addressbook: response size mismatch, expected: ", response.length(), ", got: ", len, "bytes"); {
LogPrint(eLogError, "Addressbook: response size mismatch, expected: ", len, ", got: ", response.length(), "bytes");
return false; return false;
} }
/* assert: res.code == 200 */ /* assert: res.code == 200 */
auto it = res.headers.find("ETag"); auto it = res.headers.find("ETag");
if (it != res.headers.end()) { if (it != res.headers.end()) m_Etag = it->second;
m_Etag = it->second;
}
it = res.headers.find("If-Modified-Since"); it = res.headers.find("If-Modified-Since");
if (it != res.headers.end()) { if (it != res.headers.end()) m_LastModified = it->second;
m_LastModified = it->second; if (res.is_chunked())
} {
if (res.is_chunked()) {
std::stringstream in(response), out; std::stringstream in(response), out;
i2p::http::MergeChunkedResponse (in, out); i2p::http::MergeChunkedResponse (in, out);
response = out.str(); response = out.str();
} else if (res.is_gzipped()) { }
else if (res.is_gzipped())
{
std::stringstream out; std::stringstream out;
i2p::data::GzipInflator inflator; i2p::data::GzipInflator inflator;
inflator.Inflate ((const uint8_t *) response.data(), response.length(), out); inflator.Inflate ((const uint8_t *) response.data(), response.length(), out);
if (out.fail()) { if (out.fail())
{
LogPrint(eLogError, "Addressbook: can't gunzip http response"); LogPrint(eLogError, "Addressbook: can't gunzip http response");
return false; return false;
} }

11
HTTP.cpp

@ -312,7 +312,8 @@ namespace http {
return ""; return "";
} }
bool HTTPRes::is_chunked() { bool HTTPRes::is_chunked() const
{
auto it = headers.find("Transfer-Encoding"); auto it = headers.find("Transfer-Encoding");
if (it == headers.end()) if (it == headers.end())
return false; return false;
@ -321,16 +322,20 @@ namespace http {
return false; return false;
} }
bool HTTPRes::is_gzipped() { bool HTTPRes::is_gzipped(bool includingI2PGzip) const
{
auto it = headers.find("Content-Encoding"); auto it = headers.find("Content-Encoding");
if (it == headers.end()) if (it == headers.end())
return false; /* no header */ return false; /* no header */
if (it->second.find("gzip") != std::string::npos) if (it->second.find("gzip") != std::string::npos)
return true; /* gotcha! */ return true; /* gotcha! */
if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos)
return true;
return false; return false;
} }
long int HTTPMsg::content_length() { long int HTTPMsg::content_length() const
{
unsigned long int length = 0; unsigned long int length = 0;
auto it = headers.find("Content-Length"); auto it = headers.find("Content-Length");
if (it == headers.end()) if (it == headers.end())

6
HTTP.h

@ -64,7 +64,7 @@ namespace http {
void del_header(const char *name); void del_header(const char *name);
/** @brief Returns declared message length or -1 if unknown */ /** @brief Returns declared message length or -1 if unknown */
long int content_length(); long int content_length() const;
}; };
struct HTTPReq struct HTTPReq
@ -129,10 +129,10 @@ namespace http {
void write(std::ostream & o); void write(std::ostream & o);
/** @brief Checks that response declared as chunked data */ /** @brief Checks that response declared as chunked data */
bool is_chunked(); bool is_chunked() const ;
/** @brief Checks that response contains compressed data */ /** @brief Checks that response contains compressed data */
bool is_gzipped(); bool is_gzipped(bool includingI2PGzip = true) const;
}; };
/** /**

Loading…
Cancel
Save