added support for chunked encoding for web seeds
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
* support chunked encoding for web seeds (only for BEP 19, web seeds)
|
||||||
* optimized session startup time
|
* optimized session startup time
|
||||||
* support SSL for web seeds, through all proxies
|
* support SSL for web seeds, through all proxies
|
||||||
* support extending web seeds with custom authorization and extra headers
|
* support extending web seeds with custom authorization and extra headers
|
||||||
|
@@ -89,6 +89,29 @@ namespace libtorrent
|
|||||||
std::pair<size_type, size_type> content_range() const
|
std::pair<size_type, size_type> content_range() const
|
||||||
{ return std::make_pair(m_range_start, m_range_end); }
|
{ return std::make_pair(m_range_start, m_range_end); }
|
||||||
|
|
||||||
|
// returns true if this response is using chunked encoding.
|
||||||
|
// in this case the body is split up into chunks. You need
|
||||||
|
// to call parse_chunk_header() for each chunk, starting with
|
||||||
|
// the start of the body.
|
||||||
|
bool chunked_encoding() const { return m_chunked_encoding; }
|
||||||
|
|
||||||
|
// returns false if the buffer doesn't contain a complete
|
||||||
|
// chunk header. In this case, call the function again with
|
||||||
|
// a bigger buffer once more bytes have been received.
|
||||||
|
// chunk_size is filled in with the number of bytes in the
|
||||||
|
// chunk that follows. 0 means the response terminated. In
|
||||||
|
// this case there might be additional headers in the parser
|
||||||
|
// object.
|
||||||
|
// header_size is filled in with the number of bytes the header
|
||||||
|
// itself was. Skip this number of bytes to get to the actual
|
||||||
|
// chunk data.
|
||||||
|
// if the function returns false, the chunk size and header
|
||||||
|
// size may still have been modified, but their values are
|
||||||
|
// undefined
|
||||||
|
bool parse_chunk_header(buffer::const_interval buf
|
||||||
|
, size_type* chunk_size, int* header_size);
|
||||||
|
|
||||||
|
// reset the whole state and start over
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
std::map<std::string, std::string> const& headers() const { return m_header; }
|
std::map<std::string, std::string> const& headers() const { return m_header; }
|
||||||
@@ -111,6 +134,7 @@ namespace libtorrent
|
|||||||
buffer::const_interval m_recv_buffer;
|
buffer::const_interval m_recv_buffer;
|
||||||
int m_body_start_pos;
|
int m_body_start_pos;
|
||||||
|
|
||||||
|
bool m_chunked_encoding;
|
||||||
bool m_finished;
|
bool m_finished;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -621,7 +621,7 @@ namespace libtorrent
|
|||||||
bool allocate_disk_receive_buffer(int disk_buffer_size);
|
bool allocate_disk_receive_buffer(int disk_buffer_size);
|
||||||
char* release_disk_receive_buffer();
|
char* release_disk_receive_buffer();
|
||||||
bool has_disk_receive_buffer() const { return m_disk_recv_buffer; }
|
bool has_disk_receive_buffer() const { return m_disk_recv_buffer; }
|
||||||
void cut_receive_buffer(int size, int packet_size);
|
void cut_receive_buffer(int size, int packet_size, int offset = 0);
|
||||||
void reset_recv_buffer(int packet_size);
|
void reset_recv_buffer(int packet_size);
|
||||||
void set_soft_packet_size(int size) { m_soft_packet_size = size; }
|
void set_soft_packet_size(int size) { m_soft_packet_size = size; }
|
||||||
|
|
||||||
|
@@ -133,6 +133,18 @@ namespace libtorrent
|
|||||||
|
|
||||||
// the position in the current block
|
// the position in the current block
|
||||||
int m_block_pos;
|
int m_block_pos;
|
||||||
|
|
||||||
|
// this is the offset inside the current receive
|
||||||
|
// buffer where the next chunk header will be.
|
||||||
|
// this is updated for each chunk header that's
|
||||||
|
// parsed. It does not necessarily point to a valid
|
||||||
|
// offset in the receive buffer, if we haven't received
|
||||||
|
// it yet. This offset never includes the HTTP header
|
||||||
|
int m_chunk_pos;
|
||||||
|
|
||||||
|
// this is the number of bytes we've already received
|
||||||
|
// from the next chunk header we're waiting for
|
||||||
|
int m_partial_chunk_header;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -69,6 +69,7 @@ namespace libtorrent
|
|||||||
, 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)
|
||||||
|
, m_chunked_encoding(false)
|
||||||
, m_finished(false)
|
, m_finished(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -214,6 +215,10 @@ namespace libtorrent
|
|||||||
// the http range is inclusive
|
// the http range is inclusive
|
||||||
m_content_length = m_range_end - m_range_start + 1;
|
m_content_length = m_range_end - m_range_start + 1;
|
||||||
}
|
}
|
||||||
|
else if (name == "transfer-encoding")
|
||||||
|
{
|
||||||
|
m_chunked_encoding = string_begins_no_case("chunked", value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
TORRENT_ASSERT(m_recv_pos <= (int)recv_buffer.left());
|
TORRENT_ASSERT(m_recv_pos <= (int)recv_buffer.left());
|
||||||
newline = std::find(pos, recv_buffer.end, '\n');
|
newline = std::find(pos, recv_buffer.end, '\n');
|
||||||
@@ -241,6 +246,89 @@ namespace libtorrent
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool http_parser::parse_chunk_header(buffer::const_interval buf
|
||||||
|
, size_type* chunk_size, int* header_size)
|
||||||
|
{
|
||||||
|
char const* pos = buf.begin;
|
||||||
|
|
||||||
|
// ignore one optional new-line. This is since each chunk
|
||||||
|
// is terminated by a newline. we're likely to see one
|
||||||
|
// before the actual header.
|
||||||
|
|
||||||
|
if (pos[0] == '\r' && pos[1] == '\n') pos += 2;
|
||||||
|
else if (pos[0] == '\n') pos += 1;
|
||||||
|
|
||||||
|
char const* newline = std::find(pos, buf.end, '\n');
|
||||||
|
if (newline == buf.end) return false;
|
||||||
|
++newline;
|
||||||
|
|
||||||
|
// the chunk header is a single line, a hex length of the
|
||||||
|
// chunk followed by an optional semi-colon with a comment
|
||||||
|
// in case the length is 0, the stream is terminated and
|
||||||
|
// there are extra tail headers, which is terminated by an
|
||||||
|
// empty line
|
||||||
|
|
||||||
|
// first, read the chunk length
|
||||||
|
*chunk_size = strtoll(pos, 0, 16);
|
||||||
|
if (*chunk_size != 0)
|
||||||
|
{
|
||||||
|
*header_size = newline - buf.begin;
|
||||||
|
// the newline alone is two bytes
|
||||||
|
TORRENT_ASSERT(newline - buf.begin > 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is the terminator of the stream. Also read headers
|
||||||
|
std::map<std::string, std::string> tail_headers;
|
||||||
|
pos = newline;
|
||||||
|
newline = std::find(pos, buf.end, '\n');
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (newline != buf.end)
|
||||||
|
{
|
||||||
|
// if the LF character is preceeded by a CR
|
||||||
|
// charachter, don't copy it into the line string.
|
||||||
|
char const* line_end = newline;
|
||||||
|
if (pos != line_end && *(line_end - 1) == '\r') --line_end;
|
||||||
|
line.assign(pos, line_end);
|
||||||
|
++newline;
|
||||||
|
pos = newline;
|
||||||
|
|
||||||
|
std::string::size_type separator = line.find(':');
|
||||||
|
if (separator == std::string::npos)
|
||||||
|
{
|
||||||
|
// this means we got a blank line,
|
||||||
|
// the header is finished and the body
|
||||||
|
// starts.
|
||||||
|
*header_size = newline - buf.begin;
|
||||||
|
|
||||||
|
// the newline alone is two bytes
|
||||||
|
TORRENT_ASSERT(newline - buf.begin > 2);
|
||||||
|
|
||||||
|
// we were successfull in parsing the headers.
|
||||||
|
// add them to the headers in the parser
|
||||||
|
for (std::map<std::string, std::string>::const_iterator i = tail_headers.begin();
|
||||||
|
i != tail_headers.end(); ++i)
|
||||||
|
m_header[i->first] = i->second;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name = line.substr(0, separator);
|
||||||
|
std::transform(name.begin(), name.end(), name.begin(), &to_lower);
|
||||||
|
++separator;
|
||||||
|
// skip whitespace
|
||||||
|
while (separator < line.size()
|
||||||
|
&& (line[separator] == ' ' || line[separator] == '\t'))
|
||||||
|
++separator;
|
||||||
|
std::string value = line.substr(separator, std::string::npos);
|
||||||
|
tail_headers.insert(std::make_pair(name, value));
|
||||||
|
|
||||||
|
newline = std::find(pos, buf.end, '\n');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
buffer::const_interval http_parser::get_body() const
|
buffer::const_interval http_parser::get_body() const
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(m_state == read_body);
|
TORRENT_ASSERT(m_state == read_body);
|
||||||
|
@@ -3635,17 +3635,18 @@ namespace libtorrent
|
|||||||
|
|
||||||
// size = the packet size to remove from the receive buffer
|
// size = the packet size to remove from the receive buffer
|
||||||
// packet_size = the next packet size to receive in the buffer
|
// packet_size = the next packet size to receive in the buffer
|
||||||
void peer_connection::cut_receive_buffer(int size, int packet_size)
|
void peer_connection::cut_receive_buffer(int size, int packet_size, int offset)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
TORRENT_ASSERT(packet_size > 0);
|
TORRENT_ASSERT(packet_size > 0);
|
||||||
TORRENT_ASSERT(int(m_recv_buffer.size()) >= size);
|
TORRENT_ASSERT(int(m_recv_buffer.size()) >= size);
|
||||||
TORRENT_ASSERT(int(m_recv_buffer.size()) >= m_recv_pos);
|
TORRENT_ASSERT(int(m_recv_buffer.size()) >= m_recv_pos);
|
||||||
TORRENT_ASSERT(m_recv_pos >= size);
|
TORRENT_ASSERT(m_recv_pos >= size + offset);
|
||||||
|
TORRENT_ASSERT(offset >= 0);
|
||||||
|
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
std::memmove(&m_recv_buffer[0], &m_recv_buffer[0] + size, m_recv_pos - size);
|
std::memmove(&m_recv_buffer[0] + offset, &m_recv_buffer[0] + offset + size, m_recv_pos - size - offset);
|
||||||
|
|
||||||
m_recv_pos -= size;
|
m_recv_pos -= size;
|
||||||
|
|
||||||
|
@@ -6848,8 +6848,8 @@ namespace libtorrent
|
|||||||
TORRENT_ASSERT(b > 0);
|
TORRENT_ASSERT(b > 0);
|
||||||
m_total_failed_bytes += b;
|
m_total_failed_bytes += b;
|
||||||
m_ses.add_failed_bytes(b);
|
m_ses.add_failed_bytes(b);
|
||||||
TORRENT_ASSERT(m_total_redundant_bytes + m_total_failed_bytes
|
// TORRENT_ASSERT(m_total_redundant_bytes + m_total_failed_bytes
|
||||||
<= m_stat.total_payload_download());
|
// <= m_stat.total_payload_download());
|
||||||
}
|
}
|
||||||
|
|
||||||
int torrent::num_seeds() const
|
int torrent::num_seeds() const
|
||||||
|
@@ -68,6 +68,8 @@ namespace libtorrent
|
|||||||
, m_url(url)
|
, m_url(url)
|
||||||
, m_range_pos(0)
|
, m_range_pos(0)
|
||||||
, m_block_pos(0)
|
, m_block_pos(0)
|
||||||
|
, m_chunk_pos(0)
|
||||||
|
, m_partial_chunk_header(0)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
@@ -89,7 +91,7 @@ namespace libtorrent
|
|||||||
request_large_blocks(true);
|
request_large_blocks(true);
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
(*m_logger) << "*** web_peer_connection " << url << "\n";
|
(*m_logger) << time_now_string() << " *** web_peer_connection " << url << "\n";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +239,7 @@ namespace libtorrent
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
(*m_logger) << request << "\n";
|
(*m_logger) << time_now_string() << " " << request << "\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
send_buffer(request.c_str(), request.size(), message_type_request);
|
send_buffer(request.c_str(), request.size(), message_type_request);
|
||||||
@@ -263,12 +265,22 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
size_type dl_target = m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded() + bytes_transferred;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
m_statistics.received_bytes(0, bytes_transferred);
|
m_statistics.received_bytes(0, bytes_transferred);
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
(*m_logger) << "*** web_peer_connection error: "
|
(*m_logger) << time_now_string() << " *** web_peer_connection error: "
|
||||||
<< error.message() << "\n";
|
<< error.message() << "\n";
|
||||||
|
#endif
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded()
|
||||||
|
== dl_target);
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -278,6 +290,12 @@ namespace libtorrent
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded() + bytes_transferred
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
|
|
||||||
buffer::const_interval recv_buffer = receive_buffer();
|
buffer::const_interval recv_buffer = receive_buffer();
|
||||||
|
|
||||||
int payload;
|
int payload;
|
||||||
@@ -288,6 +306,7 @@ namespace libtorrent
|
|||||||
bool error = false;
|
bool error = false;
|
||||||
boost::tie(payload, protocol) = m_parser.incoming(recv_buffer, error);
|
boost::tie(payload, protocol) = m_parser.incoming(recv_buffer, error);
|
||||||
m_statistics.received_bytes(0, protocol);
|
m_statistics.received_bytes(0, protocol);
|
||||||
|
TORRENT_ASSERT(bytes_transferred >= protocol);
|
||||||
bytes_transferred -= protocol;
|
bytes_transferred -= protocol;
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
@@ -297,6 +316,11 @@ namespace libtorrent
|
|||||||
(*m_logger) << "*** " << std::string(recv_buffer.begin, recv_buffer.end) << "\n";
|
(*m_logger) << "*** " << std::string(recv_buffer.begin, recv_buffer.end) << "\n";
|
||||||
#endif
|
#endif
|
||||||
disconnect(errors::http_parse_error, 2);
|
disconnect(errors::http_parse_error, 2);
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded()
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,6 +333,11 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
TORRENT_ASSERT(payload == 0);
|
TORRENT_ASSERT(payload == 0);
|
||||||
TORRENT_ASSERT(bytes_transferred == 0);
|
TORRENT_ASSERT(bytes_transferred == 0);
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded() + bytes_transferred
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,6 +345,11 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
TORRENT_ASSERT(payload == 0);
|
TORRENT_ASSERT(payload == 0);
|
||||||
TORRENT_ASSERT(bytes_transferred == 0);
|
TORRENT_ASSERT(bytes_transferred == 0);
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded() + bytes_transferred
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +361,7 @@ namespace libtorrent
|
|||||||
if (!header_finished)
|
if (!header_finished)
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
(*m_logger) << "*** STATUS: " << m_parser.status_code()
|
(*m_logger) << time_now_string() << " *** STATUS: " << m_parser.status_code()
|
||||||
<< " " << m_parser.message() << "\n";
|
<< " " << m_parser.message() << "\n";
|
||||||
std::map<std::string, std::string> const& headers = m_parser.headers();
|
std::map<std::string, std::string> const& headers = m_parser.headers();
|
||||||
for (std::map<std::string, std::string>::const_iterator i = headers.begin()
|
for (std::map<std::string, std::string>::const_iterator i = headers.begin()
|
||||||
@@ -350,6 +384,11 @@ namespace libtorrent
|
|||||||
}
|
}
|
||||||
m_statistics.received_bytes(0, bytes_transferred);
|
m_statistics.received_bytes(0, bytes_transferred);
|
||||||
disconnect(errors::http_error, 1);
|
disconnect(errors::http_error, 1);
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded()
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (is_redirect(m_parser.status_code()))
|
if (is_redirect(m_parser.status_code()))
|
||||||
@@ -364,6 +403,11 @@ namespace libtorrent
|
|||||||
// we should not try this server again.
|
// we should not try this server again.
|
||||||
t->remove_web_seed(this);
|
t->remove_web_seed(this);
|
||||||
disconnect(errors::missing_location, 2);
|
disconnect(errors::missing_location, 2);
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded()
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,13 +433,23 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
t->remove_web_seed(this);
|
t->remove_web_seed(this);
|
||||||
disconnect(errors::invalid_redirection, 2);
|
disconnect(errors::invalid_redirection, 2);
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded()
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
location.resize(i);
|
location.resize(i);
|
||||||
}
|
}
|
||||||
t->add_web_seed(location, web_seed_entry::url_seed);
|
t->add_web_seed(location, web_seed_entry::url_seed, m_external_auth, m_extra_headers);
|
||||||
t->remove_web_seed(this);
|
t->remove_web_seed(this);
|
||||||
disconnect(errors::redirecting, 2);
|
disconnect(errors::redirecting, 2);
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded()
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,7 +471,15 @@ namespace libtorrent
|
|||||||
recv_buffer.begin += m_body_start;
|
recv_buffer.begin += m_body_start;
|
||||||
|
|
||||||
// we only received the header, no data
|
// we only received the header, no data
|
||||||
if (recv_buffer.left() == 0) break;
|
if (recv_buffer.left() == 0)
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded()
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
size_type range_start;
|
size_type range_start;
|
||||||
size_type range_end;
|
size_type range_end;
|
||||||
@@ -430,6 +492,11 @@ namespace libtorrent
|
|||||||
// we should not try this server again.
|
// we should not try this server again.
|
||||||
t->remove_web_seed(this);
|
t->remove_web_seed(this);
|
||||||
disconnect(errors::invalid_range);
|
disconnect(errors::invalid_range);
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded()
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// the http range is inclusive
|
// the http range is inclusive
|
||||||
@@ -445,6 +512,11 @@ namespace libtorrent
|
|||||||
// we should not try this server again.
|
// we should not try this server again.
|
||||||
t->remove_web_seed(this);
|
t->remove_web_seed(this);
|
||||||
disconnect(errors::no_content_length, 2);
|
disconnect(errors::no_content_length, 2);
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded()
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -453,9 +525,67 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
m_statistics.received_bytes(0, bytes_transferred);
|
m_statistics.received_bytes(0, bytes_transferred);
|
||||||
disconnect(errors::http_error, 2);
|
disconnect(errors::http_error, 2);
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded()
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// === CHUNKED ENCODING ===
|
||||||
|
// =========================
|
||||||
|
while (m_parser.chunked_encoding()
|
||||||
|
&& m_chunk_pos >= 0
|
||||||
|
&& m_chunk_pos < recv_buffer.left())
|
||||||
|
{
|
||||||
|
int header_size = 0;
|
||||||
|
size_type chunk_size = 0;
|
||||||
|
buffer::const_interval chunk_start = recv_buffer;
|
||||||
|
chunk_start.begin += m_chunk_pos;
|
||||||
|
TORRENT_ASSERT(chunk_start.begin[0] == '\r' || is_hex(chunk_start.begin, 1));
|
||||||
|
bool ret = m_parser.parse_chunk_header(chunk_start, &chunk_size, &header_size);
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(bytes_transferred >= chunk_start.left() - m_partial_chunk_header);
|
||||||
|
bytes_transferred -= chunk_start.left() - m_partial_chunk_header;
|
||||||
|
m_statistics.received_bytes(0, chunk_start.left() - m_partial_chunk_header);
|
||||||
|
m_partial_chunk_header = chunk_start.left();
|
||||||
|
if (bytes_transferred == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
(*m_logger) << time_now_string() << " *** parsed chunk: " << chunk_size
|
||||||
|
<< " header_size: " << header_size << "\n";
|
||||||
|
#endif
|
||||||
|
TORRENT_ASSERT(bytes_transferred >= header_size - m_partial_chunk_header);
|
||||||
|
bytes_transferred -= header_size - m_partial_chunk_header;
|
||||||
|
m_statistics.received_bytes(0, header_size - m_partial_chunk_header);
|
||||||
|
m_partial_chunk_header = 0;
|
||||||
|
TORRENT_ASSERT(chunk_size != 0 || chunk_start.left() <= header_size || chunk_start.begin[header_size] == 'H');
|
||||||
|
// cut out the chunk header from the receive buffer
|
||||||
|
cut_receive_buffer(header_size, t->block_size() + 1024, m_chunk_pos);
|
||||||
|
recv_buffer = receive_buffer();
|
||||||
|
recv_buffer.begin += m_body_start;
|
||||||
|
m_chunk_pos += chunk_size;
|
||||||
|
if (chunk_size == 0)
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
chunk_start = recv_buffer;
|
||||||
|
chunk_start.begin += m_chunk_pos;
|
||||||
|
TORRENT_ASSERT(chunk_start.left() == 0 || chunk_start.begin[0] == 'H');
|
||||||
|
#endif
|
||||||
|
m_chunk_pos = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int left_in_response = range_end - range_start - m_range_pos;
|
int left_in_response = range_end - range_start - m_range_pos;
|
||||||
int payload_transferred = (std::min)(left_in_response, int(bytes_transferred));
|
int payload_transferred = (std::min)(left_in_response, int(bytes_transferred));
|
||||||
|
|
||||||
@@ -466,11 +596,12 @@ namespace libtorrent
|
|||||||
TORRENT_ASSERT(m_block_pos >= 0);
|
TORRENT_ASSERT(m_block_pos >= 0);
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
(*m_logger) << "*** payload_transferred: " << payload_transferred
|
(*m_logger) << time_now_string() << " *** payload_transferred: " << payload_transferred
|
||||||
<< " [" << front_request.piece << ":" << front_request.start
|
<< " [" << front_request.piece << ":" << front_request.start
|
||||||
<< " = " << front_request.length << "]\n";
|
<< " = " << front_request.length << "]\n";
|
||||||
#endif
|
#endif
|
||||||
m_statistics.received_bytes(payload_transferred, 0);
|
m_statistics.received_bytes(payload_transferred, 0);
|
||||||
|
TORRENT_ASSERT(bytes_transferred >= payload_transferred);
|
||||||
bytes_transferred -= payload_transferred;
|
bytes_transferred -= payload_transferred;
|
||||||
m_range_pos += payload_transferred;
|
m_range_pos += payload_transferred;
|
||||||
m_block_pos += payload_transferred;
|
m_block_pos += payload_transferred;
|
||||||
@@ -577,6 +708,11 @@ namespace libtorrent
|
|||||||
TORRENT_ASSERT(receive_buffer().begin + m_body_start == recv_buffer.begin);
|
TORRENT_ASSERT(receive_buffer().begin + m_body_start == recv_buffer.begin);
|
||||||
TORRENT_ASSERT(m_received_body <= range_end - range_start);
|
TORRENT_ASSERT(m_received_body <= range_end - range_start);
|
||||||
cut_receive_buffer(r.length + m_body_start, t->block_size() + 1024);
|
cut_receive_buffer(r.length + m_body_start, t->block_size() + 1024);
|
||||||
|
if (m_chunk_pos > 0)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_chunk_pos >= r.length);
|
||||||
|
m_chunk_pos -= r.length;
|
||||||
|
}
|
||||||
m_body_start = 0;
|
m_body_start = 0;
|
||||||
recv_buffer = receive_buffer();
|
recv_buffer = receive_buffer();
|
||||||
}
|
}
|
||||||
@@ -608,19 +744,38 @@ namespace libtorrent
|
|||||||
TORRENT_ASSERT(m_received_body <= range_end - range_start);
|
TORRENT_ASSERT(m_received_body <= range_end - range_start);
|
||||||
if (m_received_body == range_end - range_start)
|
if (m_received_body == range_end - range_start)
|
||||||
{
|
{
|
||||||
cut_receive_buffer(recv_buffer.begin - receive_buffer().begin
|
int size_to_cut = recv_buffer.begin - receive_buffer().begin;
|
||||||
, t->block_size() + 1024);
|
cut_receive_buffer(size_to_cut, t->block_size() + 1024);
|
||||||
|
if (m_chunk_pos > 0)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_chunk_pos >= size_to_cut);
|
||||||
|
m_chunk_pos -= size_to_cut;
|
||||||
|
}
|
||||||
recv_buffer = receive_buffer();
|
recv_buffer = receive_buffer();
|
||||||
m_file_requests.pop_front();
|
m_file_requests.pop_front();
|
||||||
m_parser.reset();
|
m_parser.reset();
|
||||||
m_body_start = 0;
|
m_body_start = 0;
|
||||||
m_received_body = 0;
|
m_received_body = 0;
|
||||||
|
m_chunk_pos = 0;
|
||||||
|
m_partial_chunk_header = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (bytes_transferred == 0) break;
|
if (bytes_transferred == 0)
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded()
|
||||||
|
== dl_target);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
TORRENT_ASSERT(payload_transferred > 0);
|
TORRENT_ASSERT(payload_transferred > 0);
|
||||||
}
|
}
|
||||||
TORRENT_ASSERT(bytes_transferred == 0);
|
TORRENT_ASSERT(bytes_transferred == 0);
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded()
|
||||||
|
+ m_statistics.last_protocol_downloaded() == dl_target);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void web_peer_connection::get_specific_peer_info(peer_info& p) const
|
void web_peer_connection::get_specific_peer_info(peer_info& p) const
|
||||||
|
@@ -511,9 +511,9 @@ void stop_web_server()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void web_server_thread(int* port, bool ssl);
|
void web_server_thread(int* port, bool ssl, bool chunked);
|
||||||
|
|
||||||
int start_web_server(bool ssl)
|
int start_web_server(bool ssl, bool chunked_encoding)
|
||||||
{
|
{
|
||||||
stop_web_server();
|
stop_web_server();
|
||||||
|
|
||||||
@@ -537,7 +537,8 @@ int start_web_server(bool ssl)
|
|||||||
|
|
||||||
int port = 0;
|
int port = 0;
|
||||||
|
|
||||||
web_server.reset(new libtorrent::thread(boost::bind(&web_server_thread, &port, ssl)));
|
web_server.reset(new libtorrent::thread(boost::bind(
|
||||||
|
&web_server_thread, &port, ssl, chunked_encoding)));
|
||||||
|
|
||||||
{
|
{
|
||||||
libtorrent::mutex::scoped_lock l(web_lock);
|
libtorrent::mutex::scoped_lock l(web_lock);
|
||||||
@@ -553,16 +554,22 @@ int start_web_server(bool ssl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void send_response(socket_type& s, error_code& ec
|
void send_response(socket_type& s, error_code& ec
|
||||||
, int code, char const* status_message, char const* extra_header
|
, int code, char const* status_message, char const** extra_header
|
||||||
, int len)
|
, int len)
|
||||||
{
|
{
|
||||||
char msg[400];
|
char msg[600];
|
||||||
int pkt_len = snprintf(msg, sizeof(msg), "HTTP/1.0 %d %s\r\n"
|
int pkt_len = snprintf(msg, sizeof(msg), "HTTP/1.0 %d %s\r\n"
|
||||||
"content-length: %d\r\n"
|
"content-length: %d\r\n"
|
||||||
"%s"
|
"%s"
|
||||||
|
"%s"
|
||||||
|
"%s"
|
||||||
|
"%s"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
, code, status_message, len
|
, code, status_message, len
|
||||||
, extra_header ? extra_header : "");
|
, extra_header[0]
|
||||||
|
, extra_header[1]
|
||||||
|
, extra_header[2]
|
||||||
|
, extra_header[3]);
|
||||||
// fprintf(stderr, ">> %s\n", msg);
|
// fprintf(stderr, ">> %s\n", msg);
|
||||||
write(s, boost::asio::buffer(msg, pkt_len), boost::asio::transfer_all(), ec);
|
write(s, boost::asio::buffer(msg, pkt_len), boost::asio::transfer_all(), ec);
|
||||||
}
|
}
|
||||||
@@ -583,7 +590,42 @@ void on_accept(error_code const& ec)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void web_server_thread(int* port, bool ssl)
|
void send_content(socket_type& s, char const* file, int size, bool chunked)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
if (chunked)
|
||||||
|
{
|
||||||
|
int chunk_size = 13;
|
||||||
|
char head[20];
|
||||||
|
std::vector<boost::asio::const_buffer> bufs(3);
|
||||||
|
bufs[2] = asio::const_buffer("\r\n", 2);
|
||||||
|
while (chunk_size > 0)
|
||||||
|
{
|
||||||
|
chunk_size = std::min(chunk_size, size);
|
||||||
|
int len = snprintf(head, sizeof(head), "%x\r\n", chunk_size);
|
||||||
|
bufs[0] = asio::const_buffer(head, len);
|
||||||
|
if (chunk_size == 0)
|
||||||
|
{
|
||||||
|
// terminate
|
||||||
|
bufs.erase(bufs.begin()+1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bufs[1] = asio::const_buffer(file, chunk_size);
|
||||||
|
}
|
||||||
|
write(s, bufs, boost::asio::transfer_all(), ec);
|
||||||
|
size -= chunk_size;
|
||||||
|
file += chunk_size;
|
||||||
|
chunk_size *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write(s, boost::asio::buffer(file, size), boost::asio::transfer_all(), ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void web_server_thread(int* port, bool ssl, bool chunked)
|
||||||
{
|
{
|
||||||
io_service ios;
|
io_service ios;
|
||||||
socket_acceptor acceptor(ios);
|
socket_acceptor acceptor(ios);
|
||||||
@@ -699,6 +741,8 @@ void web_server_thread(int* port, bool ssl)
|
|||||||
|
|
||||||
p.incoming(buffer::const_interval(buf + offset, buf + len), error);
|
p.incoming(buffer::const_interval(buf + offset, buf + len), error);
|
||||||
|
|
||||||
|
char const* extra_header[4] = {"","","",""};
|
||||||
|
|
||||||
TEST_CHECK(error == false);
|
TEST_CHECK(error == false);
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
@@ -766,19 +810,22 @@ void web_server_thread(int* port, bool ssl)
|
|||||||
|
|
||||||
if (path == "/redirect")
|
if (path == "/redirect")
|
||||||
{
|
{
|
||||||
send_response(s, ec, 301, "Moved Permanently", "Location: /test_file\r\n", 0);
|
extra_header[0] = "Location: /test_file\r\n";
|
||||||
|
send_response(s, ec, 301, "Moved Permanently", extra_header, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path == "/infinite_redirect")
|
if (path == "/infinite_redirect")
|
||||||
{
|
{
|
||||||
send_response(s, ec, 301, "Moved Permanently", "Location: /infinite_redirect\r\n", 0);
|
extra_header[0] = "Location: /infinite_redirext\r\n";
|
||||||
|
send_response(s, ec, 301, "Moved Permanently", extra_header, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path == "/relative/redirect")
|
if (path == "/relative/redirect")
|
||||||
{
|
{
|
||||||
send_response(s, ec, 301, "Moved Permanently", "Location: ../test_file\r\n", 0);
|
extra_header[0] = "Location: ../test_file\r\n";
|
||||||
|
send_response(s, ec, 301, "Moved Permanently", extra_header, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -792,7 +839,7 @@ void web_server_thread(int* port, bool ssl)
|
|||||||
std::vector<char> buf;
|
std::vector<char> buf;
|
||||||
bencode(std::back_inserter(buf), announce);
|
bencode(std::back_inserter(buf), announce);
|
||||||
|
|
||||||
send_response(s, ec, 200, "OK", 0, buf.size());
|
send_response(s, ec, 200, "OK", extra_header, buf.size());
|
||||||
write(s, boost::asio::buffer(&buf[0], buf.size()), boost::asio::transfer_all(), ec);
|
write(s, boost::asio::buffer(&buf[0], buf.size()), boost::asio::transfer_all(), ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -834,10 +881,10 @@ void web_server_thread(int* port, bool ssl)
|
|||||||
error_code ec;
|
error_code ec;
|
||||||
if (res == -1 || file_buf.empty())
|
if (res == -1 || file_buf.empty())
|
||||||
{
|
{
|
||||||
send_response(s, ec, 404, "Not Found", 0, 0);
|
send_response(s, ec, 404, "Not Found", extra_header, 0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
send_response(s, ec, 200, "OK", 0, size);
|
send_response(s, ec, 200, "OK", extra_header, size);
|
||||||
// fprintf(stderr, "sending %d bytes of payload [%d, %d)\n"
|
// fprintf(stderr, "sending %d bytes of payload [%d, %d)\n"
|
||||||
// , size, int(off), int(off + size));
|
// , size, int(off), int(off + size));
|
||||||
write(s, boost::asio::buffer(&file_buf[0] + off, size)
|
write(s, boost::asio::buffer(&file_buf[0] + off, size)
|
||||||
@@ -856,24 +903,27 @@ void web_server_thread(int* port, bool ssl)
|
|||||||
int res = load_file(path, file_buf);
|
int res = load_file(path, file_buf);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
{
|
{
|
||||||
send_response(s, ec, 404, "Not Found", 0, 0);
|
send_response(s, ec, 404, "Not Found", extra_header, 0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
{
|
{
|
||||||
// this means the file was either too big or couldn't be read
|
// this means the file was either too big or couldn't be read
|
||||||
send_response(s, ec, 503, "Internal Error", 0, 0);
|
send_response(s, ec, 503, "Internal Error", extra_header, 0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// serve file
|
// serve file
|
||||||
|
|
||||||
char const* extra_header = 0;
|
|
||||||
|
|
||||||
if (extension(path) == ".gz")
|
if (extension(path) == ".gz")
|
||||||
{
|
{
|
||||||
extra_header = "Content-Encoding: gzip\r\n";
|
extra_header[0] = "Content-Encoding: gzip\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunked)
|
||||||
|
{
|
||||||
|
extra_header[2] = "Transfer-Encoding: chunked\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p.header("range").empty())
|
if (!p.header("range").empty())
|
||||||
@@ -881,14 +931,13 @@ void web_server_thread(int* port, bool ssl)
|
|||||||
std::string range = p.header("range");
|
std::string range = p.header("range");
|
||||||
int start, end;
|
int start, end;
|
||||||
sscanf(range.c_str(), "bytes=%d-%d", &start, &end);
|
sscanf(range.c_str(), "bytes=%d-%d", &start, &end);
|
||||||
char eh[200];
|
char eh[400];
|
||||||
snprintf(eh, sizeof(eh), "%sContent-Range: bytes %d-%d\r\n"
|
snprintf(eh, sizeof(eh), "Content-Range: bytes %d-%d\r\n", start, end);
|
||||||
, extra_header ? extra_header : "", start, end);
|
extra_header[1] = eh;
|
||||||
send_response(s, ec, 206, "Partial", eh, end - start + 1);
|
send_response(s, ec, 206, "Partial", extra_header, end - start + 1);
|
||||||
if (!file_buf.empty())
|
if (!file_buf.empty())
|
||||||
{
|
{
|
||||||
write(s, boost::asio::buffer(&file_buf[0] + start, end - start + 1)
|
send_content(s, &file_buf[0] + start, end - start + 1, chunked);
|
||||||
, boost::asio::transfer_all(), ec);
|
|
||||||
}
|
}
|
||||||
// fprintf(stderr, "send %d bytes of payload\n", end - start + 1);
|
// fprintf(stderr, "send %d bytes of payload\n", end - start + 1);
|
||||||
}
|
}
|
||||||
@@ -896,7 +945,7 @@ void web_server_thread(int* port, bool ssl)
|
|||||||
{
|
{
|
||||||
send_response(s, ec, 200, "OK", extra_header, file_buf.size());
|
send_response(s, ec, 200, "OK", extra_header, file_buf.size());
|
||||||
if (!file_buf.empty())
|
if (!file_buf.empty())
|
||||||
write(s, boost::asio::buffer(&file_buf[0], file_buf.size()), boost::asio::transfer_all(), ec);
|
send_content(s, &file_buf[0], file_buf.size(), chunked);
|
||||||
}
|
}
|
||||||
// fprintf(stderr, "%d bytes left in receive buffer. offset: %d\n", len - offset, offset);
|
// fprintf(stderr, "%d bytes left in receive buffer. offset: %d\n", len - offset, offset);
|
||||||
memmove(buf, buf + offset, len - offset);
|
memmove(buf, buf + offset, len - offset);
|
||||||
|
@@ -62,7 +62,7 @@ setup_transfer(libtorrent::session* ses1, libtorrent::session* ses2
|
|||||||
, boost::intrusive_ptr<libtorrent::torrent_info>* torrent = 0, bool super_seeding = false
|
, boost::intrusive_ptr<libtorrent::torrent_info>* torrent = 0, bool super_seeding = false
|
||||||
, libtorrent::add_torrent_params const* p = 0);
|
, libtorrent::add_torrent_params const* p = 0);
|
||||||
|
|
||||||
int start_web_server(bool ssl = false);
|
int start_web_server(bool ssl = false, bool chunked = false);
|
||||||
void stop_web_server();
|
void stop_web_server();
|
||||||
void start_proxy(int port, int type);
|
void start_proxy(int port, int type);
|
||||||
void stop_proxy(int port);
|
void stop_proxy(int port);
|
||||||
|
@@ -815,7 +815,6 @@ int test_main()
|
|||||||
std::cerr << unescape_string(escape_string(test_string, strlen(test_string)), ec) << std::endl;
|
std::cerr << unescape_string(escape_string(test_string, strlen(test_string)), ec) << std::endl;
|
||||||
|
|
||||||
// verify_encoding
|
// verify_encoding
|
||||||
|
|
||||||
test = "\b?filename=4";
|
test = "\b?filename=4";
|
||||||
TEST_CHECK(!verify_encoding(test));
|
TEST_CHECK(!verify_encoding(test));
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
@@ -827,8 +826,8 @@ int test_main()
|
|||||||
test = "filename=4";
|
test = "filename=4";
|
||||||
TEST_CHECK(verify_encoding(test));
|
TEST_CHECK(verify_encoding(test));
|
||||||
TEST_CHECK(test == "filename=4");
|
TEST_CHECK(test == "filename=4");
|
||||||
// HTTP request parser
|
|
||||||
|
|
||||||
|
// HTTP request parser
|
||||||
http_parser parser;
|
http_parser parser;
|
||||||
boost::tuple<int, int, bool> received;
|
boost::tuple<int, int, bool> received;
|
||||||
|
|
||||||
@@ -939,8 +938,38 @@ int test_main()
|
|||||||
TEST_CHECK(received == make_tuple(5, int(strlen(web_seed_response) - 5), false));
|
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_range() == (std::pair<size_type, size_type>(0, 4)));
|
||||||
TEST_CHECK(parser.content_length() == 5);
|
TEST_CHECK(parser.content_length() == 5);
|
||||||
// test xml parser
|
|
||||||
|
|
||||||
|
{
|
||||||
|
// test chunked encoding parser
|
||||||
|
char const chunk_header1[] = "f;this is a comment\r\n";
|
||||||
|
size_type chunk_size;
|
||||||
|
int header_size;
|
||||||
|
bool ret = parser.parse_chunk_header(buffer::const_interval(chunk_header1, chunk_header1 + 10)
|
||||||
|
, &chunk_size, &header_size);
|
||||||
|
TEST_EQUAL(ret, false);
|
||||||
|
ret = parser.parse_chunk_header(buffer::const_interval(chunk_header1, chunk_header1 + sizeof(chunk_header1))
|
||||||
|
, &chunk_size, &header_size);
|
||||||
|
TEST_EQUAL(ret, true);
|
||||||
|
TEST_EQUAL(chunk_size, 15);
|
||||||
|
TEST_EQUAL(header_size, sizeof(chunk_header1) - 1);
|
||||||
|
|
||||||
|
char const chunk_header2[] =
|
||||||
|
"0;this is a comment\r\n"
|
||||||
|
"test1: foo\r\n"
|
||||||
|
"test2: bar\r\n"
|
||||||
|
"\r\n";
|
||||||
|
|
||||||
|
ret = parser.parse_chunk_header(buffer::const_interval(chunk_header2, chunk_header2 + sizeof(chunk_header2))
|
||||||
|
, &chunk_size, &header_size);
|
||||||
|
TEST_EQUAL(ret, true);
|
||||||
|
TEST_EQUAL(chunk_size, 0);
|
||||||
|
TEST_EQUAL(header_size, sizeof(chunk_header2) - 1);
|
||||||
|
|
||||||
|
TEST_EQUAL(parser.headers().find("test1")->second, "foo");
|
||||||
|
TEST_EQUAL(parser.headers().find("test2")->second, "bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
// test xml parser
|
||||||
char xml1[] = "<a>foo<b/>bar</a>";
|
char xml1[] = "<a>foo<b/>bar</a>";
|
||||||
std::string out1;
|
std::string out1;
|
||||||
|
|
||||||
|
@@ -48,7 +48,7 @@ using namespace libtorrent;
|
|||||||
|
|
||||||
// proxy: 0=none, 1=socks4, 2=socks5, 3=socks5_pw 4=http 5=http_pw
|
// proxy: 0=none, 1=socks4, 2=socks5, 3=socks5_pw 4=http 5=http_pw
|
||||||
void test_transfer(boost::intrusive_ptr<torrent_info> torrent_file
|
void test_transfer(boost::intrusive_ptr<torrent_info> torrent_file
|
||||||
, int proxy, int port, char const* protocol, bool url_seed)
|
, int proxy, int port, char const* protocol, bool url_seed, bool chunked_encoding)
|
||||||
{
|
{
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
@@ -63,8 +63,8 @@ void test_transfer(boost::intrusive_ptr<torrent_info> torrent_file
|
|||||||
|
|
||||||
char const* test_name[] = {"no", "SOCKS4", "SOCKS5", "SOCKS5 password", "HTTP", "HTTP password"};
|
char const* test_name[] = {"no", "SOCKS4", "SOCKS5", "SOCKS5 password", "HTTP", "HTTP password"};
|
||||||
|
|
||||||
fprintf(stderr, "\n\n ==== TESTING %s proxy ==== %s ==== %s ===\n\n\n"
|
fprintf(stderr, "\n\n ==== TESTING === proxy: %s ==== protocol: %s ==== seed: %s === transfer-encoding: %s\n\n\n"
|
||||||
, test_name[proxy], protocol, url_seed ? "URL seed" : "HTTP seed");
|
, test_name[proxy], protocol, url_seed ? "URL seed" : "HTTP seed", chunked_encoding ? "chunked": "none");
|
||||||
|
|
||||||
if (proxy)
|
if (proxy)
|
||||||
{
|
{
|
||||||
@@ -187,7 +187,7 @@ sha1_hash file_hash(std::string const& name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test_url_seed determines whether to use url-seed or http-seed
|
// test_url_seed determines whether to use url-seed or http-seed
|
||||||
int run_suite(char const* protocol, bool test_url_seed)
|
int run_suite(char const* protocol, bool test_url_seed, bool chunked_encoding)
|
||||||
{
|
{
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ int run_suite(char const* protocol, bool test_url_seed)
|
|||||||
fs.add_file("seed", sizeof(random_data));
|
fs.add_file("seed", sizeof(random_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
int port = start_web_server(strcmp(protocol, "https") == 0);
|
int port = start_web_server(strcmp(protocol, "https") == 0, chunked_encoding);
|
||||||
|
|
||||||
libtorrent::create_torrent t(fs, 16, 0, libtorrent::create_torrent::calculate_file_hashes);
|
libtorrent::create_torrent t(fs, 16, 0, libtorrent::create_torrent::calculate_file_hashes);
|
||||||
char tmp[512];
|
char tmp[512];
|
||||||
@@ -262,12 +262,12 @@ int run_suite(char const* protocol, bool test_url_seed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 6; ++i)
|
for (int i = 0; i < 6; ++i)
|
||||||
test_transfer(torrent_file, i, port, protocol, test_url_seed);
|
test_transfer(torrent_file, i, port, protocol, test_url_seed, chunked_encoding);
|
||||||
|
|
||||||
if (test_url_seed)
|
if (test_url_seed)
|
||||||
{
|
{
|
||||||
torrent_file->rename_file(0, "./tmp2_web_seed/test_torrent_dir/renamed_test1");
|
torrent_file->rename_file(0, "./tmp2_web_seed/test_torrent_dir/renamed_test1");
|
||||||
test_transfer(torrent_file, 0, port, protocol, test_url_seed);
|
test_transfer(torrent_file, 0, port, protocol, test_url_seed, chunked_encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_web_server();
|
stop_web_server();
|
||||||
@@ -280,10 +280,16 @@ int test_main()
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
for (int i = 0; i < 2; ++i)
|
for (int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
|
// we only support chunked encoding for
|
||||||
|
// URL seeds (not HTTP seeds).
|
||||||
|
// that's why the variable limit on this loop
|
||||||
|
for (int j = 0; j < (i==0?2:1); ++j)
|
||||||
|
{
|
||||||
#ifdef TORRENT_USE_OPENSSL
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
run_suite("https", i);
|
run_suite("https", i, j);
|
||||||
#endif
|
#endif
|
||||||
run_suite("http", i);
|
run_suite("http", i, j);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user