added support for chunked encoding for web seeds
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -537,7 +537,8 @@ int start_web_server(bool ssl)
|
||||
|
||||
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);
|
||||
@@ -553,16 +554,22 @@ int start_web_server(bool ssl)
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
char msg[400];
|
||||
char msg[600];
|
||||
int pkt_len = snprintf(msg, sizeof(msg), "HTTP/1.0 %d %s\r\n"
|
||||
"content-length: %d\r\n"
|
||||
"%s"
|
||||
"%s"
|
||||
"%s"
|
||||
"%s"
|
||||
"\r\n"
|
||||
, 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);
|
||||
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;
|
||||
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);
|
||||
|
||||
char const* extra_header[4] = {"","","",""};
|
||||
|
||||
TEST_CHECK(error == false);
|
||||
if (error)
|
||||
{
|
||||
@@ -766,19 +810,22 @@ void web_server_thread(int* port, bool ssl)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -792,7 +839,7 @@ void web_server_thread(int* port, bool ssl)
|
||||
std::vector<char> buf;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -834,10 +881,10 @@ void web_server_thread(int* port, bool ssl)
|
||||
error_code ec;
|
||||
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;
|
||||
}
|
||||
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"
|
||||
// , size, int(off), int(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);
|
||||
if (res == -1)
|
||||
{
|
||||
send_response(s, ec, 404, "Not Found", 0, 0);
|
||||
send_response(s, ec, 404, "Not Found", extra_header, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
// serve file
|
||||
|
||||
char const* extra_header = 0;
|
||||
|
||||
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())
|
||||
@@ -881,14 +931,13 @@ void web_server_thread(int* port, bool ssl)
|
||||
std::string range = p.header("range");
|
||||
int start, end;
|
||||
sscanf(range.c_str(), "bytes=%d-%d", &start, &end);
|
||||
char eh[200];
|
||||
snprintf(eh, sizeof(eh), "%sContent-Range: bytes %d-%d\r\n"
|
||||
, extra_header ? extra_header : "", start, end);
|
||||
send_response(s, ec, 206, "Partial", eh, end - start + 1);
|
||||
char eh[400];
|
||||
snprintf(eh, sizeof(eh), "Content-Range: bytes %d-%d\r\n", start, end);
|
||||
extra_header[1] = eh;
|
||||
send_response(s, ec, 206, "Partial", extra_header, end - start + 1);
|
||||
if (!file_buf.empty())
|
||||
{
|
||||
write(s, boost::asio::buffer(&file_buf[0] + start, end - start + 1)
|
||||
, boost::asio::transfer_all(), ec);
|
||||
send_content(s, &file_buf[0] + start, end - start + 1, chunked);
|
||||
}
|
||||
// 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());
|
||||
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);
|
||||
memmove(buf, buf + offset, len - offset);
|
||||
|
Reference in New Issue
Block a user