moved content-range parsing into http_parser and added unittest

This commit is contained in:
Arvid Norberg 2009-04-12 17:52:25 +00:00
parent a79932c9fd
commit 066d6ce799
4 changed files with 48 additions and 35 deletions

View File

@ -81,6 +81,8 @@ namespace libtorrent
, bool& error);
int body_start() const { return m_body_start_pos; }
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();
@ -95,6 +97,8 @@ namespace libtorrent
std::string m_server_message;
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;

View File

@ -49,6 +49,8 @@ namespace libtorrent
: m_recv_pos(0)
, m_status_code(-1)
, m_content_length(-1)
, m_range_start(-1)
, m_range_end(-1)
, m_state(read_status)
, m_recv_buffer(0, 0)
, m_body_start_pos(0)
@ -162,31 +164,37 @@ namespace libtorrent
if (name == "content-length")
{
#ifdef TORRENT_WINDOWS
m_content_length = _atoi64(value.c_str());
#else
m_content_length = atoll(value.c_str());
#endif
m_content_length = strtoll(value.c_str(), 0, 10);
}
else if (name == "content-range")
{
std::stringstream range_str(value);
char dummy;
std::string bytes;
size_type range_start, range_end;
bool success = true;
char const* ptr = value.c_str();
// apparently some web servers do not send the "bytes"
// in their content-range
if (value.find(' ') != std::string::npos)
range_str >> bytes;
range_str >> range_start >> dummy >> range_end;
if (!range_str || range_end < range_start)
// in their content-range. Don't treat it as an error
// if we can't find it, just assume the byte counters
// start immediately
if (string_begins_no_case("bytes ", ptr)) ptr += 6;
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;
error = true;
return ret;
}
// 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());
@ -233,6 +241,8 @@ namespace libtorrent
m_body_start_pos = 0;
m_status_code = -1;
m_content_length = -1;
m_range_start = -1;
m_range_end = -1;
m_finished = false;
m_state = read_status;
m_recv_buffer.begin = 0;

View File

@ -480,31 +480,14 @@ namespace libtorrent
size_type range_end;
if (m_parser.status_code() == 206)
{
std::string const& range_str = m_parser.header("content-range");
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)
boost::tie(range_start, range_end) = m_parser.content_range();
if (range_start < 0 || range_end < range_start)
{
m_statistics.received_bytes(0, bytes_transferred);
// we should not try this server again.
t->remove_web_seed(m_url, web_seed_entry::url_seed);
char msg[200];
snprintf(msg, 200, "invalid range in HTTP response: %s"
, range_str.c_str());
snprintf(msg, 200, "invalid range in HTTP response");
disconnect(msg, 2);
return;
}

View File

@ -546,6 +546,22 @@ int test_main()
TEST_CHECK(received == make_tuple(5, int(strlen(tracker_response) - 5), false));
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
char xml1[] = "<a>foo<b/>bar</a>";