forked from premiere/premiere-libtorrent
changed http_parser slightly. uses http_parser in lsd.cpp. added more tests to the http_parser
This commit is contained in:
parent
1df7c2006a
commit
d48236a738
|
@ -69,13 +69,20 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
http_parser();
|
http_parser();
|
||||||
template <class T>
|
std::string const& header(char const* key) const
|
||||||
T header(char const* key) const;
|
{
|
||||||
|
static std::string empty;
|
||||||
|
std::map<std::string, std::string>::const_iterator i
|
||||||
|
= m_header.find(key);
|
||||||
|
if (i == m_header.end()) return empty;
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
|
|
||||||
std::string const& protocol() const { return m_protocol; }
|
std::string const& protocol() const { return m_protocol; }
|
||||||
int status_code() const { return m_status_code; }
|
int status_code() const { return m_status_code; }
|
||||||
std::string const& method() const { return m_method; }
|
std::string const& method() const { return m_method; }
|
||||||
std::string const& path() const { return m_path; }
|
std::string const& path() const { return m_path; }
|
||||||
std::string message() const { return m_server_message; }
|
std::string const& message() const { return m_server_message; }
|
||||||
buffer::const_interval get_body() const;
|
buffer::const_interval get_body() const;
|
||||||
bool header_finished() const { return m_state == read_body; }
|
bool header_finished() const { return m_state == read_body; }
|
||||||
bool finished() const { return m_finished; }
|
bool finished() const { return m_finished; }
|
||||||
|
@ -103,15 +110,6 @@ namespace libtorrent
|
||||||
bool m_finished;
|
bool m_finished;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
|
||||||
T http_parser::header(char const* key) const
|
|
||||||
{
|
|
||||||
std::map<std::string, std::string>::const_iterator i
|
|
||||||
= m_header.find(key);
|
|
||||||
if (i == m_header.end()) return T();
|
|
||||||
return boost::lexical_cast<T>(i->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
class TORRENT_EXPORT http_tracker_connection
|
class TORRENT_EXPORT http_tracker_connection
|
||||||
: public tracker_connection
|
: public tracker_connection
|
||||||
{
|
{
|
||||||
|
|
|
@ -263,7 +263,7 @@ void http_connection::on_read(asio::error_code const& e
|
||||||
if (code >= 300 && code < 400)
|
if (code >= 300 && code < 400)
|
||||||
{
|
{
|
||||||
// attempt a redirect
|
// attempt a redirect
|
||||||
std::string url = m_parser.header<std::string>("location");
|
std::string const& url = m_parser.header("location");
|
||||||
if (url.empty())
|
if (url.empty())
|
||||||
{
|
{
|
||||||
// missing location header
|
// missing location header
|
||||||
|
|
|
@ -679,7 +679,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_parser.header_finished())
|
if (m_parser.header_finished())
|
||||||
{
|
{
|
||||||
int cl = m_parser.header<int>("content-length");
|
int cl = atoi(m_parser.header("content-length").c_str());
|
||||||
if (cl > m_settings.tracker_maximum_response_length)
|
if (cl > m_settings.tracker_maximum_response_length)
|
||||||
{
|
{
|
||||||
fail(-1, "content-length is greater than maximum response length");
|
fail(-1, "content-length is greater than maximum response length");
|
||||||
|
@ -718,7 +718,7 @@ namespace libtorrent
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string location = m_parser.header<std::string>("location");
|
std::string location = m_parser.header("location");
|
||||||
|
|
||||||
boost::shared_ptr<request_callback> cb = requester();
|
boost::shared_ptr<request_callback> cb = requester();
|
||||||
|
|
||||||
|
@ -763,7 +763,7 @@ namespace libtorrent
|
||||||
|
|
||||||
buffer::const_interval buf(&m_buffer[0] + m_parser.body_start(), &m_buffer[0] + m_recv_pos);
|
buffer::const_interval buf(&m_buffer[0] + m_parser.body_start(), &m_buffer[0] + m_recv_pos);
|
||||||
|
|
||||||
std::string content_encoding = m_parser.header<std::string>("content-encoding");
|
std::string content_encoding = m_parser.header("content-encoding");
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
if (cb) cb->debug_log("content-encoding: \"" + content_encoding + "\"");
|
if (cb) cb->debug_log("content-encoding: \"" + content_encoding + "\"");
|
||||||
|
|
73
src/lsd.cpp
73
src/lsd.cpp
|
@ -121,48 +121,53 @@ void lsd::on_announce(udp::endpoint const& from, char* buffer
|
||||||
{
|
{
|
||||||
using namespace libtorrent::detail;
|
using namespace libtorrent::detail;
|
||||||
|
|
||||||
char* p = buffer;
|
http_parser p;
|
||||||
char* end = buffer + bytes_transferred;
|
|
||||||
char* line = std::find(p, end, '\n');
|
p.incoming(buffer::const_interval(buffer, buffer + bytes_transferred));
|
||||||
for (char* i = p; i < line; ++i) *i = std::tolower(*i);
|
|
||||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
if (!p.header_finished())
|
||||||
m_log << time_now_string()
|
|
||||||
<< " <== announce: " << std::string(p, line) << std::endl;
|
|
||||||
#endif
|
|
||||||
if (line == end || (line - p >= 9 && std::memcmp("bt-search", p, 9)))
|
|
||||||
{
|
{
|
||||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
m_log << time_now_string()
|
m_log << time_now_string()
|
||||||
<< " *** assumed 'bt-search', ignoring" << std::endl;
|
<< " <== announce: incomplete HTTP message\n";
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p = line + 1;
|
|
||||||
int port = 0;
|
if (p.method() != "bt-search")
|
||||||
sha1_hash ih(0);
|
|
||||||
while (p != end)
|
|
||||||
{
|
{
|
||||||
line = std::find(p, end, '\n');
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
if (line == end) break;
|
m_log << time_now_string()
|
||||||
*line = 0;
|
<< " <== announce: invalid HTTP method: " << p.method() << std::endl;
|
||||||
for (char* i = p; i < line; ++i) *i = std::tolower(*i);
|
#endif
|
||||||
if (line - p >= 5 && memcmp(p, "port:", 5) == 0)
|
return;
|
||||||
{
|
|
||||||
p += 5;
|
|
||||||
while (*p == ' ') ++p;
|
|
||||||
port = atoi(p);
|
|
||||||
}
|
|
||||||
else if (line - p >= 9 && memcmp(p, "infohash:", 9) == 0)
|
|
||||||
{
|
|
||||||
p += 9;
|
|
||||||
while (*p == ' ') ++p;
|
|
||||||
if (line - p > 40) p[40] = 0;
|
|
||||||
try { ih = boost::lexical_cast<sha1_hash>(p); }
|
|
||||||
catch (std::exception&) {}
|
|
||||||
}
|
|
||||||
p = line + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string const& port_str = p.header("port");
|
||||||
|
if (port_str.empty())
|
||||||
|
{
|
||||||
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
|
m_log << time_now_string()
|
||||||
|
<< " <== announce: invalid BT-SEARCH, missing port" << std::endl;
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const& ih_str = p.header("infohash");
|
||||||
|
if (ih_str.empty())
|
||||||
|
{
|
||||||
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
|
m_log << time_now_string()
|
||||||
|
<< " <== announce: invalid BT-SEARCH, missing infohash" << std::endl;
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sha1_hash ih(0);
|
||||||
|
std::istringstream ih_sstr(ih_str);
|
||||||
|
ih_sstr >> ih;
|
||||||
|
int port = atoi(port_str.c_str());
|
||||||
|
|
||||||
if (!ih.is_all_zeros() && port != 0)
|
if (!ih.is_all_zeros() && port != 0)
|
||||||
{
|
{
|
||||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
|
|
|
@ -300,7 +300,7 @@ try
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string url = p.header<std::string>("location");
|
std::string url = p.header("location");
|
||||||
if (url.empty())
|
if (url.empty())
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_UPNP_LOGGING
|
#ifdef TORRENT_UPNP_LOGGING
|
||||||
|
|
|
@ -387,7 +387,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
// this means we got a redirection request
|
// this means we got a redirection request
|
||||||
// look for the location header
|
// look for the location header
|
||||||
std::string location = m_parser.header<std::string>("location");
|
std::string location = m_parser.header("location");
|
||||||
|
|
||||||
if (location.empty())
|
if (location.empty())
|
||||||
{
|
{
|
||||||
|
@ -423,7 +423,7 @@ namespace libtorrent
|
||||||
throw std::runtime_error("redirecting to " + location);
|
throw std::runtime_error("redirecting to " + location);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string server_version = m_parser.header<std::string>("server");
|
std::string const& server_version = m_parser.header("server");
|
||||||
if (!server_version.empty())
|
if (!server_version.empty())
|
||||||
{
|
{
|
||||||
m_server_string = "URL seed @ ";
|
m_server_string = "URL seed @ ";
|
||||||
|
@ -445,7 +445,7 @@ namespace libtorrent
|
||||||
size_type range_end;
|
size_type range_end;
|
||||||
if (m_parser.status_code() == 206)
|
if (m_parser.status_code() == 206)
|
||||||
{
|
{
|
||||||
std::stringstream range_str(m_parser.header<std::string>("content-range"));
|
std::stringstream range_str(m_parser.header("content-range"));
|
||||||
char dummy;
|
char dummy;
|
||||||
std::string bytes;
|
std::string bytes;
|
||||||
range_str >> bytes >> range_start >> dummy >> range_end;
|
range_str >> bytes >> range_start >> dummy >> range_end;
|
||||||
|
@ -461,7 +461,7 @@ namespace libtorrent
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
range_start = 0;
|
range_start = 0;
|
||||||
range_end = m_parser.header<size_type>("content-length");
|
range_end = atol(m_parser.header("content-length").c_str());
|
||||||
if (range_end == -1)
|
if (range_end == -1)
|
||||||
{
|
{
|
||||||
// we should not try this server again.
|
// we should not try this server again.
|
||||||
|
|
|
@ -102,8 +102,8 @@ int test_main()
|
||||||
TEST_CHECK(received == make_tuple(4, 64));
|
TEST_CHECK(received == make_tuple(4, 64));
|
||||||
TEST_CHECK(parser.finished());
|
TEST_CHECK(parser.finished());
|
||||||
TEST_CHECK(std::equal(parser.get_body().begin, parser.get_body().end, "test"));
|
TEST_CHECK(std::equal(parser.get_body().begin, parser.get_body().end, "test"));
|
||||||
TEST_CHECK(parser.header<std::string>("content-type") == "text/plain");
|
TEST_CHECK(parser.header("content-type") == "text/plain");
|
||||||
TEST_CHECK(parser.header<int>("content-length") == 4);
|
TEST_CHECK(atoi(parser.header("content-length").c_str()) == 4);
|
||||||
|
|
||||||
parser.reset();
|
parser.reset();
|
||||||
|
|
||||||
|
@ -123,11 +123,11 @@ int test_main()
|
||||||
|
|
||||||
TEST_CHECK(received == make_tuple(0, int(strlen(upnp_response))));
|
TEST_CHECK(received == make_tuple(0, int(strlen(upnp_response))));
|
||||||
TEST_CHECK(parser.get_body().left() == 0);
|
TEST_CHECK(parser.get_body().left() == 0);
|
||||||
TEST_CHECK(parser.header<std::string>("st") == "upnp:rootdevice");
|
TEST_CHECK(parser.header("st") == "upnp:rootdevice");
|
||||||
TEST_CHECK(parser.header<std::string>("location")
|
TEST_CHECK(parser.header("location")
|
||||||
== "http://192.168.1.1:5431/dyndev/uuid:000f-66d6-7296000099dc");
|
== "http://192.168.1.1:5431/dyndev/uuid:000f-66d6-7296000099dc");
|
||||||
TEST_CHECK(parser.header<std::string>("ext") == "");
|
TEST_CHECK(parser.header("ext") == "");
|
||||||
TEST_CHECK(parser.header<std::string>("date") == "Fri, 02 Jan 1970 08:10:38 GMT");
|
TEST_CHECK(parser.header("date") == "Fri, 02 Jan 1970 08:10:38 GMT");
|
||||||
|
|
||||||
parser.reset();
|
parser.reset();
|
||||||
TEST_CHECK(!parser.finished());
|
TEST_CHECK(!parser.finished());
|
||||||
|
@ -148,6 +148,41 @@ int test_main()
|
||||||
TEST_CHECK(parser.method() == "notify");
|
TEST_CHECK(parser.method() == "notify");
|
||||||
TEST_CHECK(parser.path() == "*");
|
TEST_CHECK(parser.path() == "*");
|
||||||
|
|
||||||
|
parser.reset();
|
||||||
|
TEST_CHECK(!parser.finished());
|
||||||
|
|
||||||
|
char const* bt_lsd = "BT-SEARCH * HTTP/1.1\r\n"
|
||||||
|
"Host: 239.192.152.143:6771\r\n"
|
||||||
|
"Port: 6881\r\n"
|
||||||
|
"Infohash: 12345678901234567890\r\n"
|
||||||
|
"\r\n\r\n";
|
||||||
|
|
||||||
|
received = feed_bytes(parser, bt_lsd);
|
||||||
|
|
||||||
|
TEST_CHECK(received == make_tuple(2, int(strlen(bt_lsd) - 2)));
|
||||||
|
TEST_CHECK(parser.method() == "bt-search");
|
||||||
|
TEST_CHECK(parser.path() == "*");
|
||||||
|
TEST_CHECK(atoi(parser.header("port").c_str()) == 6881);
|
||||||
|
TEST_CHECK(parser.header("infohash") == "12345678901234567890");
|
||||||
|
|
||||||
|
TEST_CHECK(!parser.finished());
|
||||||
|
|
||||||
|
parser.reset();
|
||||||
|
TEST_CHECK(!parser.finished());
|
||||||
|
|
||||||
|
// make sure we support trackers with incorrect line endings
|
||||||
|
char const* tracker_response =
|
||||||
|
"HTTP/1.1 200 OK\n"
|
||||||
|
"content-length: 5\n"
|
||||||
|
"content-type: test/plain\n"
|
||||||
|
"\n"
|
||||||
|
"\ntest";
|
||||||
|
|
||||||
|
received = feed_bytes(parser, tracker_response);
|
||||||
|
|
||||||
|
TEST_CHECK(received == make_tuple(5, int(strlen(tracker_response) - 5)));
|
||||||
|
TEST_CHECK(parser.get_body().left() == 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