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)
* added support for hashing pieces in multiple threads
* improved error handling of gzip
* fixed crash when web seeds redirect
* fix compiler warnings

View File

@ -34,19 +34,98 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_GZIP_HPP_INCLUDED
#include "libtorrent/config.hpp"
#include <string>
#include "libtorrent/error_code.hpp"
#include <vector>
namespace libtorrent
{
TORRENT_EXTRA_EXPORT bool inflate_gzip(
TORRENT_EXTRA_EXPORT void inflate_gzip(
char const* in, int size
, std::vector<char>& buffer
, 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

View File

@ -65,6 +65,8 @@ namespace libtorrent {
duplicated_id,
num_errors
};
TORRENT_EXPORT boost::system::error_code make_error_code(i2p_error_code e);
}
// 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

View File

@ -422,10 +422,7 @@ namespace libtorrent
};
// hidden
inline boost::system::error_code make_error_code(error_code_enum e)
{
return boost::system::error_code(e, get_bdecode_category());
}
TORRENT_EXPORT boost::system::error_code make_error_code(error_code_enum e);
}
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

View File

@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/assert.hpp"
#include "libtorrent/puff.hpp"
#include "libtorrent/gzip.hpp"
#include <vector>
#include <string>
@ -55,6 +56,59 @@ namespace
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
int gzip_header(const char* buf, int size)
{
@ -129,21 +183,21 @@ namespace libtorrent
return total_size - size;
}
// TODO: 2 it would be nice to use proper error handling here
TORRENT_EXTRA_EXPORT bool inflate_gzip(
TORRENT_EXTRA_EXPORT void inflate_gzip(
char const* in
, int size
, std::vector<char>& buffer
, int maximum_size
, std::string& error)
, error_code& ec)
{
ec.clear();
TORRENT_ASSERT(maximum_size > 0);
int header_len = gzip_header(in, size);
if (header_len < 0)
{
error = "invalid gzip header";
return true;
ec = gzip_errors::invalid_gzip_header;
return;
}
// start off with 4 kilobytes and grow
@ -158,9 +212,8 @@ namespace libtorrent
TORRENT_TRY {
buffer.resize(destlen);
} TORRENT_CATCH(std::exception& e) {
error = "out of memory: ";
error += e.what();
return true;
ec = errors::no_memory;
return;
}
ret = puff((unsigned char*)&buffer[0], &destlen, (unsigned char*)in, &srclen);
@ -172,8 +225,8 @@ namespace libtorrent
{
if (destlen == boost::uint32_t(maximum_size))
{
error = "inflated data too big";
return true;
ec = gzip_errors::inflated_data_too_large;
return;
}
destlen *= 2;
@ -184,19 +237,31 @@ namespace libtorrent
if (ret != 0)
{
error = "error while inflating data";
return true;
switch (ret)
{
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())
{
error = "internal gzip error";
return true;
ec = gzip_errors::unknown_gzip_error;
return;
}
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");
if ((encoding == "gzip" || encoding == "x-gzip") && size > 0 && data)
{
std::string error;
if (inflate_gzip(data, size, buf, m_max_bottled_buffer_size, error))
error_code ec;
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();
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;
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)
: m_state(sam_idle)
, m_io_service(ios)

View File

@ -685,5 +685,12 @@ namespace libtorrent
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())
{
std::vector<char> buf;
std::string error;
if (inflate_gzip(&m_torrent_file_buf[0], m_torrent_file_buf.size()
, buf, 4 * 1024 * 1024, error))
error_code ec;
inflate_gzip(&m_torrent_file_buf[0], m_torrent_file_buf.size()
, buf, 4 * 1024 * 1024, ex);
if (ec)
{
set_error(errors::http_failed_decompress, error_file_url);
set_error(ec, error_file_url);
pause();
std::vector<char>().swap(m_torrent_file_buf);
return;

View File

@ -48,13 +48,12 @@ int test_main()
TEST_CHECK(!ec);
std::vector<char> inflated;
std::string error;
bool ret = inflate_gzip(&zipped[0], zipped.size(), inflated, 1000000, error);
inflate_gzip(&zipped[0], zipped.size(), inflated, 1000000, ec);
if (ret != 0) {
fprintf(stderr, "failed to unzip\n");
if (ec) {
fprintf(stderr, "failed to unzip: %s\n", ec.message().c_str());
}
TEST_CHECK(ret == 0);
TEST_CHECK(!ec);
TEST_CHECK(inflated.size() > 0);
for (int i = 0; i < inflated.size(); ++i)
TEST_EQUAL(inflated[i], 0);