added support for chunked encoding for web seeds

This commit is contained in:
Arvid Norberg
2010-10-27 06:39:18 +00:00
parent 4968192654
commit d737dd051d
12 changed files with 419 additions and 54 deletions

View File

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