Browse Source

handle compressed addressbook

pull/386/head
orignal 9 years ago
parent
commit
9a6d478eb1
  1. 26
      AddressBook.cpp
  2. 1
      AddressBook.h
  3. 32
      Base.cpp
  4. 6
      Base.h
  5. 1
      util.h

26
AddressBook.cpp

@ -507,6 +507,7 @@ namespace client
<< "Host: " << u.host_ << "\r\n" << "Host: " << u.host_ << "\r\n"
<< "Accept: */*\r\n" << "Accept: */*\r\n"
<< "User-Agent: Wget/1.11.4\r\n" << "User-Agent: Wget/1.11.4\r\n"
//<< "Accept-Encoding: gzip\r\n"
<< "Connection: close\r\n"; << "Connection: close\r\n";
if (m_Etag.length () > 0) // etag if (m_Etag.length () > 0) // etag
request << i2p::util::http::IF_NONE_MATCH << ": \"" << m_Etag << "\"\r\n"; request << i2p::util::http::IF_NONE_MATCH << ": \"" << m_Etag << "\"\r\n";
@ -545,7 +546,7 @@ namespace client
response >> status; // status response >> status; // status
if (status == 200) // OK if (status == 200) // OK
{ {
bool isChunked = false; bool isChunked = false, isGzip = false;
std::string header, statusMessage; std::string header, statusMessage;
std::getline (response, statusMessage); std::getline (response, statusMessage);
// read until new line meaning end of header // read until new line meaning end of header
@ -563,6 +564,8 @@ namespace client
m_LastModified = header.substr (colon + 1); m_LastModified = header.substr (colon + 1);
else if (field == i2p::util::http::TRANSFER_ENCODING) else if (field == i2p::util::http::TRANSFER_ENCODING)
isChunked = !header.compare (colon + 1, std::string::npos, "chunked"); 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); LogPrint (eLogInfo, "Addressbook: ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified);
@ -570,13 +573,13 @@ namespace client
{ {
success = true; success = true;
if (!isChunked) if (!isChunked)
m_Book.LoadHostsFromStream (response); success = ProcessResponse (response, isGzip);
else else
{ {
// merge chunks // merge chunks
std::stringstream merged; std::stringstream merged;
i2p::util::http::MergeChunkedResponse (response, 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); 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;
}
} }
} }

1
AddressBook.h

@ -92,6 +92,7 @@ namespace client
private: private:
void Request (); void Request ();
bool ProcessResponse (std::stringstream& s, bool isGzip = false);
private: private:

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) GzipDeflator::GzipDeflator (): m_IsDirty (false)
{ {
memset (&m_Deflator, 0, sizeof (m_Deflator)); memset (&m_Deflator, 0, sizeof (m_Deflator));

6
Base.h

@ -5,6 +5,8 @@
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <zlib.h> #include <zlib.h>
#include <iostream>
#include <sstream>
namespace i2p namespace i2p
{ {
@ -92,6 +94,7 @@ namespace data
}; };
}; };
const size_t GZIP_CHUNK_SIZE = 16384;
class GzipInflator class GzipInflator
{ {
public: public:
@ -100,6 +103,9 @@ namespace data
~GzipInflator (); ~GzipInflator ();
size_t Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen); 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: private:

1
util.h

@ -34,6 +34,7 @@ namespace util
const char IF_MODIFIED_SINCE[] = "If-Modified-Since"; const char IF_MODIFIED_SINCE[] = "If-Modified-Since";
const char LAST_MODIFIED[] = "Last-Modified"; const char LAST_MODIFIED[] = "Last-Modified";
const char TRANSFER_ENCODING[] = "Transfer-Encoding"; const char TRANSFER_ENCODING[] = "Transfer-Encoding";
const char CONTENT_ENCODING[] = "Content-Encoding";
std::string GetHttpContent (std::istream& response); std::string GetHttpContent (std::istream& response);
void MergeChunkedResponse (std::istream& response, std::ostream& merged); void MergeChunkedResponse (std::istream& response, std::ostream& merged);

Loading…
Cancel
Save