forked from premiere/premiere-libtorrent
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)
|
||||
* added support for hashing pieces in multiple threads
|
||||
|
||||
* improved error handling of gzip
|
||||
* fixed crash when web seeds redirect
|
||||
* fix compiler warnings
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
97
src/gzip.cpp
97
src/gzip.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue