diff --git a/ChangeLog b/ChangeLog index 3d0cbd0d9..4081879ae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -43,6 +43,7 @@ * fix uTP edge case where udp socket buffer fills up * fix nagle implementation in uTP + * improve error handling in http gunzip * fix debug logging for banning web seeds * improve support for de-selected files in full allocation mode * fix dht_bootstrap_alert being posted diff --git a/src/gzip.cpp b/src/gzip.cpp index c44015b2b..83472dc6c 100644 --- a/src/gzip.cpp +++ b/src/gzip.cpp @@ -129,6 +129,7 @@ namespace libtorrent return total_size - size; } + // TODO: 2 it would be nice to use proper error handling here bool inflate_gzip( char const* in , int size @@ -145,18 +146,44 @@ namespace libtorrent return true; } - // start off with one kilobyte and grow + // start off with 4 kilobytes and grow // if needed - buffer.resize(maximum_size); - - boost::uint32_t destlen = buffer.size(); - boost::uint32_t srclen = size - header_len; - in += header_len; - int ret = puff((unsigned char*)&buffer[0], &destlen, (unsigned char*)in, &srclen); - - if (ret == -1) + boost::uint32_t destlen = 4096; + int ret = 0; + do { - error = "inflated data too big"; + TORRENT_TRY { + buffer.resize(destlen); + } TORRENT_CATCH(std::exception& e) { + error = "out of memory"; + return true; + } + + boost::uint32_t srclen = size - header_len; + in += header_len; + ret = puff((unsigned char*)&buffer[0], &destlen, (unsigned char*)in, &srclen); + + // if the destination buffer wasn't large enough, double its + // size and try again. Unless it's already at its max, in which + // case we fail + if (ret == -1) + { + if (destlen == maximum_size) + { + error = "inflated data too big"; + return true; + } + + destlen *= 2; + if (destlen > maximum_size) + destlen = maximum_size; + continue; + } + } while (false); + + if (destlen > buffer.size()) + { + error = "internal gzip error"; return true; }