diff --git a/AddressBook.cpp b/AddressBook.cpp index 20a118fb..c41dec50 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -705,6 +705,7 @@ namespace client i2p::http::HTTPReq req; req.AddHeader("Host", dest_host); 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"); if (!m_Etag.empty()) req.AddHeader("If-None-Match", m_Etag); @@ -721,7 +722,9 @@ namespace client std::string response; uint8_t recv_buf[4096]; bool end = false; - while (!end) { + int numAttempts = 5; + while (!end) + { stream->AsyncReceive (boost::asio::buffer (recv_buf, 4096), [&](const boost::system::error_code& ecode, std::size_t bytes_transferred) { @@ -734,60 +737,69 @@ namespace client 30); // wait for 30 seconds std::unique_lock l(newDataReceivedMutex); if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout) + { 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))) { + 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) { + if (res_head_len < 0) + { LogPrint(eLogError, "Addressbook: can't parse http response from ", dest_host); return false; } - if (res_head_len == 0) { + if (res_head_len == 0) + { 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) { + if (res.code == 304) + { LogPrint (eLogInfo, "Addressbook: no updates from ", dest_host, ", code 304"); return false; } - if (res.code != 200) { + 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()) { + if (response.empty()) + { LogPrint(eLogError, "Addressbook: empty response from ", dest_host, ", expected ", len, " bytes"); return false; } - if (len > 0 && len != (int) response.length()) { - LogPrint(eLogError, "Addressbook: response size mismatch, expected: ", response.length(), ", got: ", len, "bytes"); + 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; - } + if (it != res.headers.end()) m_Etag = it->second; it = res.headers.find("If-Modified-Since"); - if (it != res.headers.end()) { - m_LastModified = it->second; - } - if (res.is_chunked()) { + 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(); - } else if (res.is_gzipped()) { + } + else if (res.is_gzipped()) + { std::stringstream out; i2p::data::GzipInflator inflator; inflator.Inflate ((const uint8_t *) response.data(), response.length(), out); - if (out.fail()) { + if (out.fail()) + { LogPrint(eLogError, "Addressbook: can't gunzip http response"); return false; } diff --git a/HTTP.cpp b/HTTP.cpp index 6ab6ecf4..77922686 100644 --- a/HTTP.cpp +++ b/HTTP.cpp @@ -312,7 +312,8 @@ namespace http { return ""; } - bool HTTPRes::is_chunked() { + bool HTTPRes::is_chunked() const + { auto it = headers.find("Transfer-Encoding"); if (it == headers.end()) return false; @@ -321,16 +322,20 @@ namespace http { return false; } - bool HTTPRes::is_gzipped() { + bool HTTPRes::is_gzipped(bool includingI2PGzip) const + { auto it = headers.find("Content-Encoding"); if (it == headers.end()) return false; /* no header */ if (it->second.find("gzip") != std::string::npos) return true; /* gotcha! */ + if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos) + return true; return false; } - - long int HTTPMsg::content_length() { + + long int HTTPMsg::content_length() const + { unsigned long int length = 0; auto it = headers.find("Content-Length"); if (it == headers.end()) diff --git a/HTTP.h b/HTTP.h index 3175cb79..251d98bc 100644 --- a/HTTP.h +++ b/HTTP.h @@ -64,7 +64,7 @@ namespace http { void del_header(const char *name); /** @brief Returns declared message length or -1 if unknown */ - long int content_length(); + long int content_length() const; }; struct HTTPReq @@ -129,10 +129,10 @@ namespace http { void write(std::ostream & o); /** @brief Checks that response declared as chunked data */ - bool is_chunked(); + bool is_chunked() const ; /** @brief Checks that response contains compressed data */ - bool is_gzipped(); + bool is_gzipped(bool includingI2PGzip = true) const; }; /**