merge error code fix from RC_1_0
This commit is contained in:
parent
4284606cbc
commit
8552e75f21
|
@ -27,6 +27,7 @@
|
||||||
* almost completely changed the storage interface (for custom storage)
|
* almost completely changed the storage interface (for custom storage)
|
||||||
* added support for hashing pieces in multiple threads
|
* added support for hashing pieces in multiple threads
|
||||||
|
|
||||||
|
* improved error handling of gzip
|
||||||
* fixed crash when web seeds redirect
|
* fixed crash when web seeds redirect
|
||||||
* fix compiler warnings
|
* fix compiler warnings
|
||||||
|
|
||||||
|
|
|
@ -34,19 +34,98 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#define TORRENT_GZIP_HPP_INCLUDED
|
#define TORRENT_GZIP_HPP_INCLUDED
|
||||||
|
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
#include <string>
|
#include "libtorrent/error_code.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
TORRENT_EXTRA_EXPORT bool inflate_gzip(
|
TORRENT_EXTRA_EXPORT void inflate_gzip(
|
||||||
char const* in, int size
|
char const* in, int size
|
||||||
, std::vector<char>& buffer
|
, std::vector<char>& buffer
|
||||||
, int maximum_size
|
, int maximum_size
|
||||||
, std::string& error);
|
, error_code& error);
|
||||||
|
|
||||||
|
// get the ``error_category`` for zip errors
|
||||||
|
TORRENT_EXPORT boost::system::error_category& get_gzip_category();
|
||||||
|
|
||||||
|
namespace gzip_errors
|
||||||
|
{
|
||||||
|
// libtorrent uses boost.system's ``error_code`` class to represent errors. libtorrent has
|
||||||
|
// its own error category get_gzip_category() whith the error codes defined by error_code_enum.
|
||||||
|
enum error_code_enum
|
||||||
|
{
|
||||||
|
// Not an error
|
||||||
|
no_error = 0,
|
||||||
|
|
||||||
|
// the supplied gzip buffer has invalid header
|
||||||
|
invalid_gzip_header,
|
||||||
|
|
||||||
|
// the gzip buffer would inflate to more bytes than the specified
|
||||||
|
// maximum size, and was rejected.
|
||||||
|
inflated_data_too_large,
|
||||||
|
|
||||||
|
// available inflate data did not terminate
|
||||||
|
data_did_not_terminate,
|
||||||
|
|
||||||
|
// output space exhausted before completing inflate
|
||||||
|
space_exhausted,
|
||||||
|
|
||||||
|
// invalid block type (type == 3)
|
||||||
|
invalid_block_type,
|
||||||
|
|
||||||
|
// stored block length did not match one's complement
|
||||||
|
invalid_stored_block_length,
|
||||||
|
|
||||||
|
// dynamic block code description: too many length or distance codes
|
||||||
|
too_many_length_or_distance_codes,
|
||||||
|
|
||||||
|
// dynamic block code description: code lengths codes incomplete
|
||||||
|
code_lengths_codes_incomplete,
|
||||||
|
|
||||||
|
// dynamic block code description: repeat lengths with no first length
|
||||||
|
repeat_lengths_with_no_first_length,
|
||||||
|
|
||||||
|
// dynamic block code description: repeat more than specified lengths
|
||||||
|
repeat_more_than_specified_lengths,
|
||||||
|
|
||||||
|
// dynamic block code description: invalid literal/length code lengths
|
||||||
|
invalid_literal_length_code_lengths,
|
||||||
|
|
||||||
|
// dynamic block code description: invalid distance code lengths
|
||||||
|
invalid_distance_code_lengths,
|
||||||
|
|
||||||
|
// invalid literal/length or distance code in fixed or dynamic block
|
||||||
|
invalid_literal_code_in_block,
|
||||||
|
|
||||||
|
// distance is too far back in fixed or dynamic block
|
||||||
|
distance_too_far_back_in_block,
|
||||||
|
|
||||||
|
// an unknown error occurred during gzip inflation
|
||||||
|
unknown_gzip_error,
|
||||||
|
|
||||||
|
// the number of error codes
|
||||||
|
error_code_max
|
||||||
|
};
|
||||||
|
|
||||||
|
// hidden
|
||||||
|
TORRENT_EXPORT boost::system::error_code make_error_code(error_code_enum e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if BOOST_VERSION >= 103500
|
||||||
|
namespace boost { namespace system {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct is_error_code_enum<libtorrent::gzip_errors::error_code_enum>
|
||||||
|
{
|
||||||
|
static const bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
||||||
|
#endif // BOOST_VERSION
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,8 @@ namespace libtorrent {
|
||||||
duplicated_id,
|
duplicated_id,
|
||||||
num_errors
|
num_errors
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TORRENT_EXPORT boost::system::error_code make_error_code(i2p_error_code e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the error category for I2P errors
|
// returns the error category for I2P errors
|
||||||
|
@ -211,6 +213,19 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if BOOST_VERSION >= 103500
|
||||||
|
namespace boost { namespace system {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct is_error_code_enum<libtorrent::i2p_error::i2p_error_code>
|
||||||
|
{
|
||||||
|
static const bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
||||||
|
#endif // BOOST_VERSION
|
||||||
|
|
||||||
#endif // TORRENT_USE_I2P
|
#endif // TORRENT_USE_I2P
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -422,10 +422,7 @@ namespace libtorrent
|
||||||
};
|
};
|
||||||
|
|
||||||
// hidden
|
// hidden
|
||||||
inline boost::system::error_code make_error_code(error_code_enum e)
|
TORRENT_EXPORT boost::system::error_code make_error_code(error_code_enum e);
|
||||||
{
|
|
||||||
return boost::system::error_code(e, get_bdecode_category());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_EXTRA_EXPORT char const* parse_int(char const* start
|
TORRENT_EXTRA_EXPORT char const* parse_int(char const* start
|
||||||
|
@ -434,5 +431,16 @@ namespace libtorrent
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if BOOST_VERSION >= 103500
|
||||||
|
|
||||||
|
namespace boost { namespace system {
|
||||||
|
|
||||||
|
template<> struct is_error_code_enum<libtorrent::bdecode_errors::error_code_enum>
|
||||||
|
{ static const bool value = true; };
|
||||||
|
|
||||||
|
} }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
97
src/gzip.cpp
97
src/gzip.cpp
|
@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "libtorrent/assert.hpp"
|
#include "libtorrent/assert.hpp"
|
||||||
#include "libtorrent/puff.hpp"
|
#include "libtorrent/puff.hpp"
|
||||||
|
#include "libtorrent/gzip.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -55,6 +56,59 @@ namespace
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
struct gzip_error_category : boost::system::error_category
|
||||||
|
{
|
||||||
|
virtual const char* name() const BOOST_SYSTEM_NOEXCEPT;
|
||||||
|
virtual std::string message(int ev) const BOOST_SYSTEM_NOEXCEPT;
|
||||||
|
virtual boost::system::error_condition default_error_condition(int ev) const BOOST_SYSTEM_NOEXCEPT
|
||||||
|
{ return boost::system::error_condition(ev, *this); }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* gzip_error_category::name() const BOOST_SYSTEM_NOEXCEPT
|
||||||
|
{
|
||||||
|
return "gzip error";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gzip_error_category::message(int ev) const BOOST_SYSTEM_NOEXCEPT
|
||||||
|
{
|
||||||
|
static char const* msgs[] =
|
||||||
|
{
|
||||||
|
"no error",
|
||||||
|
"invalid gzip header",
|
||||||
|
"inflated data too large",
|
||||||
|
"available inflate data did not terminate",
|
||||||
|
"output space exhausted before completing inflate",
|
||||||
|
"invalid block type (type == 3)",
|
||||||
|
"stored block length did not match one's complement",
|
||||||
|
"dynamic block code description: too many length or distance codes",
|
||||||
|
"dynamic block code description: code lengths codes incomplete",
|
||||||
|
"dynamic block code description: repeat lengths with no first length",
|
||||||
|
"dynamic block code description: repeat more than specified lengths",
|
||||||
|
"dynamic block code description: invalid literal/length code lengths",
|
||||||
|
"dynamic block code description: invalid distance code lengths",
|
||||||
|
"invalid literal/length or distance code in fixed or dynamic block",
|
||||||
|
"distance is too far back in fixed or dynamic block",
|
||||||
|
"unknown gzip error",
|
||||||
|
};
|
||||||
|
if (ev < 0 || ev >= int(sizeof(msgs)/sizeof(msgs[0])))
|
||||||
|
return "Unknown error";
|
||||||
|
return msgs[ev];
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::system::error_category& get_gzip_category()
|
||||||
|
{
|
||||||
|
static gzip_error_category gzip_category;
|
||||||
|
return gzip_category;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace gzip_errors
|
||||||
|
{
|
||||||
|
boost::system::error_code make_error_code(error_code_enum e)
|
||||||
|
{
|
||||||
|
return boost::system::error_code(e, get_gzip_category());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// returns -1 if gzip header is invalid or the header size in bytes
|
// returns -1 if gzip header is invalid or the header size in bytes
|
||||||
int gzip_header(const char* buf, int size)
|
int gzip_header(const char* buf, int size)
|
||||||
{
|
{
|
||||||
|
@ -129,21 +183,21 @@ namespace libtorrent
|
||||||
return total_size - size;
|
return total_size - size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 2 it would be nice to use proper error handling here
|
TORRENT_EXTRA_EXPORT void inflate_gzip(
|
||||||
TORRENT_EXTRA_EXPORT bool inflate_gzip(
|
|
||||||
char const* in
|
char const* in
|
||||||
, int size
|
, int size
|
||||||
, std::vector<char>& buffer
|
, std::vector<char>& buffer
|
||||||
, int maximum_size
|
, int maximum_size
|
||||||
, std::string& error)
|
, error_code& ec)
|
||||||
{
|
{
|
||||||
|
ec.clear();
|
||||||
TORRENT_ASSERT(maximum_size > 0);
|
TORRENT_ASSERT(maximum_size > 0);
|
||||||
|
|
||||||
int header_len = gzip_header(in, size);
|
int header_len = gzip_header(in, size);
|
||||||
if (header_len < 0)
|
if (header_len < 0)
|
||||||
{
|
{
|
||||||
error = "invalid gzip header";
|
ec = gzip_errors::invalid_gzip_header;
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// start off with 4 kilobytes and grow
|
// start off with 4 kilobytes and grow
|
||||||
|
@ -158,9 +212,8 @@ namespace libtorrent
|
||||||
TORRENT_TRY {
|
TORRENT_TRY {
|
||||||
buffer.resize(destlen);
|
buffer.resize(destlen);
|
||||||
} TORRENT_CATCH(std::exception& e) {
|
} TORRENT_CATCH(std::exception& e) {
|
||||||
error = "out of memory: ";
|
ec = errors::no_memory;
|
||||||
error += e.what();
|
return;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = puff((unsigned char*)&buffer[0], &destlen, (unsigned char*)in, &srclen);
|
ret = puff((unsigned char*)&buffer[0], &destlen, (unsigned char*)in, &srclen);
|
||||||
|
@ -172,8 +225,8 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
if (destlen == boost::uint32_t(maximum_size))
|
if (destlen == boost::uint32_t(maximum_size))
|
||||||
{
|
{
|
||||||
error = "inflated data too big";
|
ec = gzip_errors::inflated_data_too_large;
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
destlen *= 2;
|
destlen *= 2;
|
||||||
|
@ -184,19 +237,31 @@ namespace libtorrent
|
||||||
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
error = "error while inflating data";
|
switch (ret)
|
||||||
return true;
|
{
|
||||||
|
case 2: ec = gzip_errors::data_did_not_terminate; return;
|
||||||
|
case 1: ec = gzip_errors::space_exhausted; return;
|
||||||
|
case -1: ec = gzip_errors::invalid_block_type; return;
|
||||||
|
case -2: ec = gzip_errors::invalid_stored_block_length; return;
|
||||||
|
case -3: ec = gzip_errors::too_many_length_or_distance_codes; return;
|
||||||
|
case -4: ec = gzip_errors::code_lengths_codes_incomplete; return;
|
||||||
|
case -5: ec = gzip_errors::repeat_lengths_with_no_first_length; return;
|
||||||
|
case -6: ec = gzip_errors::repeat_more_than_specified_lengths; return;
|
||||||
|
case -7: ec = gzip_errors::invalid_literal_length_code_lengths; return;
|
||||||
|
case -8: ec = gzip_errors::invalid_distance_code_lengths; return;
|
||||||
|
case -9: ec = gzip_errors::invalid_literal_code_in_block; return;
|
||||||
|
case -10: ec = gzip_errors::distance_too_far_back_in_block; return;
|
||||||
|
default: ec = gzip_errors::unknown_gzip_error; return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destlen > buffer.size())
|
if (destlen > buffer.size())
|
||||||
{
|
{
|
||||||
error = "internal gzip error";
|
ec = gzip_errors::unknown_gzip_error;
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.resize(destlen);
|
buffer.resize(destlen);
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -682,10 +682,12 @@ void http_connection::callback(error_code e, char const* data, int size)
|
||||||
std::string const& encoding = m_parser.header("content-encoding");
|
std::string const& encoding = m_parser.header("content-encoding");
|
||||||
if ((encoding == "gzip" || encoding == "x-gzip") && size > 0 && data)
|
if ((encoding == "gzip" || encoding == "x-gzip") && size > 0 && data)
|
||||||
{
|
{
|
||||||
std::string error;
|
error_code ec;
|
||||||
if (inflate_gzip(data, size, buf, m_max_bottled_buffer_size, error))
|
inflate_gzip(data, size, buf, m_max_bottled_buffer_size, ec);
|
||||||
|
|
||||||
|
if (ec)
|
||||||
{
|
{
|
||||||
if (m_handler) m_handler(errors::http_failed_decompress, m_parser, data, size, *this);
|
if (m_handler) m_handler(ec, m_parser, data, size, *this);
|
||||||
close();
|
close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,11 +76,20 @@ namespace libtorrent
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TORRENT_EXPORT boost::system::error_category& get_i2p_category()
|
boost::system::error_category& get_i2p_category()
|
||||||
{
|
{
|
||||||
static i2p_error_category i2p_category;
|
static i2p_error_category i2p_category;
|
||||||
return i2p_category;
|
return i2p_category;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace i2p_error
|
||||||
|
{
|
||||||
|
boost::system::error_code make_error_code(i2p_error_code e)
|
||||||
|
{
|
||||||
|
return error_code(e, get_i2p_category());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
i2p_connection::i2p_connection(io_service& ios)
|
i2p_connection::i2p_connection(io_service& ios)
|
||||||
: m_state(sam_idle)
|
: m_state(sam_idle)
|
||||||
, m_io_service(ios)
|
, m_io_service(ios)
|
||||||
|
|
|
@ -685,5 +685,12 @@ namespace libtorrent
|
||||||
return bdecode_category;
|
return bdecode_category;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace bdecode_errors
|
||||||
|
{
|
||||||
|
boost::system::error_code make_error_code(error_code_enum e)
|
||||||
|
{
|
||||||
|
return boost::system::error_code(e, get_bdecode_category());
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -428,11 +428,12 @@ namespace libtorrent
|
||||||
if ((encoding == "gzip" || encoding == "x-gzip") && m_torrent_file_buf.size())
|
if ((encoding == "gzip" || encoding == "x-gzip") && m_torrent_file_buf.size())
|
||||||
{
|
{
|
||||||
std::vector<char> buf;
|
std::vector<char> buf;
|
||||||
std::string error;
|
error_code ec;
|
||||||
if (inflate_gzip(&m_torrent_file_buf[0], m_torrent_file_buf.size()
|
inflate_gzip(&m_torrent_file_buf[0], m_torrent_file_buf.size()
|
||||||
, buf, 4 * 1024 * 1024, error))
|
, buf, 4 * 1024 * 1024, ex);
|
||||||
|
if (ec)
|
||||||
{
|
{
|
||||||
set_error(errors::http_failed_decompress, error_file_url);
|
set_error(ec, error_file_url);
|
||||||
pause();
|
pause();
|
||||||
std::vector<char>().swap(m_torrent_file_buf);
|
std::vector<char>().swap(m_torrent_file_buf);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -48,13 +48,12 @@ int test_main()
|
||||||
TEST_CHECK(!ec);
|
TEST_CHECK(!ec);
|
||||||
|
|
||||||
std::vector<char> inflated;
|
std::vector<char> inflated;
|
||||||
std::string error;
|
inflate_gzip(&zipped[0], zipped.size(), inflated, 1000000, ec);
|
||||||
bool ret = inflate_gzip(&zipped[0], zipped.size(), inflated, 1000000, error);
|
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ec) {
|
||||||
fprintf(stderr, "failed to unzip\n");
|
fprintf(stderr, "failed to unzip: %s\n", ec.message().c_str());
|
||||||
}
|
}
|
||||||
TEST_CHECK(ret == 0);
|
TEST_CHECK(!ec);
|
||||||
TEST_CHECK(inflated.size() > 0);
|
TEST_CHECK(inflated.size() > 0);
|
||||||
for (int i = 0; i < inflated.size(); ++i)
|
for (int i = 0; i < inflated.size(); ++i)
|
||||||
TEST_EQUAL(inflated[i], 0);
|
TEST_EQUAL(inflated[i], 0);
|
||||||
|
|
Loading…
Reference in New Issue