handle compressed addressbook

pull/386/head
orignal 8 years ago
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:

@ -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));

@ -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,7 +103,10 @@ 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:
z_stream m_Inflator;

@ -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…
Cancel
Save