forked from premiere/premiere-libtorrent
moved content-range parsing into http_parser and added unittest
This commit is contained in:
parent
a79932c9fd
commit
066d6ce799
|
@ -81,6 +81,8 @@ namespace libtorrent
|
||||||
, bool& error);
|
, bool& error);
|
||||||
int body_start() const { return m_body_start_pos; }
|
int body_start() const { return m_body_start_pos; }
|
||||||
size_type content_length() const { return m_content_length; }
|
size_type content_length() const { return m_content_length; }
|
||||||
|
std::pair<size_type, size_type> content_range() const
|
||||||
|
{ return std::make_pair(m_range_start, m_range_end); }
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
@ -95,6 +97,8 @@ namespace libtorrent
|
||||||
std::string m_server_message;
|
std::string m_server_message;
|
||||||
|
|
||||||
size_type m_content_length;
|
size_type m_content_length;
|
||||||
|
size_type m_range_start;
|
||||||
|
size_type m_range_end;
|
||||||
|
|
||||||
enum { read_status, read_header, read_body, error_state } m_state;
|
enum { read_status, read_header, read_body, error_state } m_state;
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,8 @@ namespace libtorrent
|
||||||
: m_recv_pos(0)
|
: m_recv_pos(0)
|
||||||
, m_status_code(-1)
|
, m_status_code(-1)
|
||||||
, m_content_length(-1)
|
, m_content_length(-1)
|
||||||
|
, m_range_start(-1)
|
||||||
|
, m_range_end(-1)
|
||||||
, m_state(read_status)
|
, m_state(read_status)
|
||||||
, m_recv_buffer(0, 0)
|
, m_recv_buffer(0, 0)
|
||||||
, m_body_start_pos(0)
|
, m_body_start_pos(0)
|
||||||
|
@ -162,31 +164,37 @@ namespace libtorrent
|
||||||
|
|
||||||
if (name == "content-length")
|
if (name == "content-length")
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_WINDOWS
|
m_content_length = strtoll(value.c_str(), 0, 10);
|
||||||
m_content_length = _atoi64(value.c_str());
|
|
||||||
#else
|
|
||||||
m_content_length = atoll(value.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else if (name == "content-range")
|
else if (name == "content-range")
|
||||||
{
|
{
|
||||||
std::stringstream range_str(value);
|
bool success = true;
|
||||||
char dummy;
|
char const* ptr = value.c_str();
|
||||||
std::string bytes;
|
|
||||||
size_type range_start, range_end;
|
|
||||||
// apparently some web servers do not send the "bytes"
|
// apparently some web servers do not send the "bytes"
|
||||||
// in their content-range
|
// in their content-range. Don't treat it as an error
|
||||||
if (value.find(' ') != std::string::npos)
|
// if we can't find it, just assume the byte counters
|
||||||
range_str >> bytes;
|
// start immediately
|
||||||
range_str >> range_start >> dummy >> range_end;
|
if (string_begins_no_case("bytes ", ptr)) ptr += 6;
|
||||||
if (!range_str || range_end < range_start)
|
char* end;
|
||||||
|
m_range_start = strtoll(ptr, &end, 10);
|
||||||
|
if (end == ptr) success = false;
|
||||||
|
else if (*end != '-') success = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ptr = end + 1;
|
||||||
|
m_range_end = strtoll(ptr, &end, 10);
|
||||||
|
if (end == ptr) success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success || m_range_end < m_range_start)
|
||||||
{
|
{
|
||||||
m_state = error_state;
|
m_state = error_state;
|
||||||
error = true;
|
error = true;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
// the http range is inclusive
|
// the http range is inclusive
|
||||||
m_content_length = range_end - range_start + 1;
|
m_content_length = m_range_end - m_range_start + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_ASSERT(m_recv_pos <= (int)recv_buffer.left());
|
TORRENT_ASSERT(m_recv_pos <= (int)recv_buffer.left());
|
||||||
|
@ -233,6 +241,8 @@ namespace libtorrent
|
||||||
m_body_start_pos = 0;
|
m_body_start_pos = 0;
|
||||||
m_status_code = -1;
|
m_status_code = -1;
|
||||||
m_content_length = -1;
|
m_content_length = -1;
|
||||||
|
m_range_start = -1;
|
||||||
|
m_range_end = -1;
|
||||||
m_finished = false;
|
m_finished = false;
|
||||||
m_state = read_status;
|
m_state = read_status;
|
||||||
m_recv_buffer.begin = 0;
|
m_recv_buffer.begin = 0;
|
||||||
|
|
|
@ -480,31 +480,14 @@ namespace libtorrent
|
||||||
size_type range_end;
|
size_type range_end;
|
||||||
if (m_parser.status_code() == 206)
|
if (m_parser.status_code() == 206)
|
||||||
{
|
{
|
||||||
std::string const& range_str = m_parser.header("content-range");
|
boost::tie(range_start, range_end) = m_parser.content_range();
|
||||||
|
if (range_start < 0 || range_end < range_start)
|
||||||
bool success = true;
|
|
||||||
char const* ptr = range_str.c_str();
|
|
||||||
if (string_begins_no_case("bytes ", ptr)) ptr += 6;
|
|
||||||
else success = false;
|
|
||||||
char* end;
|
|
||||||
range_start = strtoll(ptr, &end, 10);
|
|
||||||
if (end == ptr) success = false;
|
|
||||||
else if (*end != '-') success = false;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ptr = end + 1;
|
|
||||||
range_end = strtoll(ptr, &end, 10);
|
|
||||||
if (end == ptr) success = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
{
|
{
|
||||||
m_statistics.received_bytes(0, bytes_transferred);
|
m_statistics.received_bytes(0, bytes_transferred);
|
||||||
// we should not try this server again.
|
// we should not try this server again.
|
||||||
t->remove_web_seed(m_url, web_seed_entry::url_seed);
|
t->remove_web_seed(m_url, web_seed_entry::url_seed);
|
||||||
char msg[200];
|
char msg[200];
|
||||||
snprintf(msg, 200, "invalid range in HTTP response: %s"
|
snprintf(msg, 200, "invalid range in HTTP response");
|
||||||
, range_str.c_str());
|
|
||||||
disconnect(msg, 2);
|
disconnect(msg, 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -546,6 +546,22 @@ int test_main()
|
||||||
TEST_CHECK(received == make_tuple(5, int(strlen(tracker_response) - 5), false));
|
TEST_CHECK(received == make_tuple(5, int(strlen(tracker_response) - 5), false));
|
||||||
TEST_CHECK(parser.get_body().left() == 5);
|
TEST_CHECK(parser.get_body().left() == 5);
|
||||||
|
|
||||||
|
parser.reset();
|
||||||
|
|
||||||
|
// make sure we support content-range responses
|
||||||
|
// and that we're case insensitive
|
||||||
|
char const* web_seed_response =
|
||||||
|
"HTTP/1.1 206 OK\n"
|
||||||
|
"contEnt-rAngE: bYTes 0-4\n"
|
||||||
|
"conTent-TyPe: test/plain\n"
|
||||||
|
"\n"
|
||||||
|
"\ntest";
|
||||||
|
|
||||||
|
received = feed_bytes(parser, web_seed_response);
|
||||||
|
|
||||||
|
TEST_CHECK(received == make_tuple(5, int(strlen(web_seed_response) - 5), false));
|
||||||
|
TEST_CHECK(parser.content_range() == (std::pair<size_type, size_type>(0, 4)));
|
||||||
|
TEST_CHECK(parser.content_length() == 5);
|
||||||
// test xml parser
|
// test xml parser
|
||||||
|
|
||||||
char xml1[] = "<a>foo<b/>bar</a>";
|
char xml1[] = "<a>foo<b/>bar</a>";
|
||||||
|
|
Loading…
Reference in New Issue