mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-18 16:49:58 +00:00
handle compressed addressbook
This commit is contained in:
parent
b4e324ec0e
commit
9a6d478eb1
@ -507,6 +507,7 @@ namespace client
|
||||
<< "Host: " << u.host_ << "\r\n"
|
||||
<< "Accept: */*\r\n"
|
||||
<< "User-Agent: Wget/1.11.4\r\n"
|
||||
//<< "Accept-Encoding: gzip\r\n"
|
||||
<< "Connection: close\r\n";
|
||||
if (m_Etag.length () > 0) // etag
|
||||
request << i2p::util::http::IF_NONE_MATCH << ": \"" << m_Etag << "\"\r\n";
|
||||
@ -545,7 +546,7 @@ namespace client
|
||||
response >> status; // status
|
||||
if (status == 200) // OK
|
||||
{
|
||||
bool isChunked = false;
|
||||
bool isChunked = false, isGzip = false;
|
||||
std::string header, statusMessage;
|
||||
std::getline (response, statusMessage);
|
||||
// read until new line meaning end of header
|
||||
@ -563,6 +564,8 @@ namespace client
|
||||
m_LastModified = header.substr (colon + 1);
|
||||
else if (field == i2p::util::http::TRANSFER_ENCODING)
|
||||
isChunked = !header.compare (colon + 1, std::string::npos, "chunked");
|
||||
else if (field == i2p::util::http::CONTENT_ENCODING)
|
||||
isGzip = !header.compare (colon + 1, std::string::npos, "gzip");
|
||||
}
|
||||
}
|
||||
LogPrint (eLogInfo, "Addressbook: ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified);
|
||||
@ -570,13 +573,13 @@ namespace client
|
||||
{
|
||||
success = true;
|
||||
if (!isChunked)
|
||||
m_Book.LoadHostsFromStream (response);
|
||||
success = ProcessResponse (response, isGzip);
|
||||
else
|
||||
{
|
||||
// merge chunks
|
||||
std::stringstream merged;
|
||||
i2p::util::http::MergeChunkedResponse (response, merged);
|
||||
m_Book.LoadHostsFromStream (merged);
|
||||
success = ProcessResponse (merged, isGzip);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -599,6 +602,23 @@ namespace client
|
||||
|
||||
m_Book.DownloadComplete (success);
|
||||
}
|
||||
|
||||
bool AddressBookSubscription::ProcessResponse (std::stringstream& s, bool isGzip)
|
||||
{
|
||||
if (isGzip)
|
||||
{
|
||||
std::stringstream uncompressed;
|
||||
i2p::data::GzipInflator inflator;
|
||||
inflator.Inflate (s, uncompressed);
|
||||
if (!uncompressed.fail ())
|
||||
m_Book.LoadHostsFromStream (uncompressed);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_Book.LoadHostsFromStream (s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,7 @@ namespace client
|
||||
private:
|
||||
|
||||
void Request ();
|
||||
bool ProcessResponse (std::stringstream& s, bool isGzip = false);
|
||||
|
||||
private:
|
||||
|
||||
|
32
Base.cpp
32
Base.cpp
@ -302,6 +302,38 @@ namespace data
|
||||
}
|
||||
}
|
||||
|
||||
bool GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& s)
|
||||
{
|
||||
m_IsDirty = true;
|
||||
uint8_t * out = new uint8_t[GZIP_CHUNK_SIZE];
|
||||
m_Inflator.next_in = const_cast<uint8_t *>(in);
|
||||
m_Inflator.avail_in = inLen;
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
m_Inflator.next_out = out;
|
||||
m_Inflator.avail_out = GZIP_CHUNK_SIZE;
|
||||
ret = inflate (&m_Inflator, Z_NO_FLUSH);
|
||||
if (ret < 0)
|
||||
{
|
||||
LogPrint (eLogError, "Decompression error ", ret);
|
||||
inflateEnd (&m_Inflator);
|
||||
s.setstate(std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
else
|
||||
s.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out);
|
||||
}
|
||||
while (!m_Inflator.avail_out); // more data to read
|
||||
delete[] out;
|
||||
return ret == Z_STREAM_END || ret < 0;
|
||||
}
|
||||
|
||||
void GzipInflator::Inflate (const std::stringstream& in, std::ostream& out)
|
||||
{
|
||||
Inflate ((const uint8_t *)in.str ().c_str (), in.str ().length (), out);
|
||||
}
|
||||
|
||||
GzipDeflator::GzipDeflator (): m_IsDirty (false)
|
||||
{
|
||||
memset (&m_Deflator, 0, sizeof (m_Deflator));
|
||||
|
6
Base.h
6
Base.h
@ -5,6 +5,8 @@
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <zlib.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
@ -92,6 +94,7 @@ namespace data
|
||||
};
|
||||
};
|
||||
|
||||
const size_t GZIP_CHUNK_SIZE = 16384;
|
||||
class GzipInflator
|
||||
{
|
||||
public:
|
||||
@ -100,6 +103,9 @@ namespace data
|
||||
~GzipInflator ();
|
||||
|
||||
size_t Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen);
|
||||
bool Inflate (const uint8_t * in, size_t inLen, std::ostream& s);
|
||||
// return true when finshed or error, s failbit will be set in case of error
|
||||
void Inflate (const std::stringstream& in, std::ostream& out);
|
||||
|
||||
private:
|
||||
|
||||
|
1
util.h
1
util.h
@ -34,6 +34,7 @@ namespace util
|
||||
const char IF_MODIFIED_SINCE[] = "If-Modified-Since";
|
||||
const char LAST_MODIFIED[] = "Last-Modified";
|
||||
const char TRANSFER_ENCODING[] = "Transfer-Encoding";
|
||||
const char CONTENT_ENCODING[] = "Content-Encoding";
|
||||
|
||||
std::string GetHttpContent (std::istream& response);
|
||||
void MergeChunkedResponse (std::istream& response, std::ostream& merged);
|
||||
|
Loading…
x
Reference in New Issue
Block a user