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

View File

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

View File

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

View File

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