merge error code fix from RC_1_0

This commit is contained in:
Arvid Norberg 2014-07-20 20:49:56 +00:00
parent 4284606cbc
commit 8552e75f21
10 changed files with 222 additions and 36 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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