From 0c2f90ee5c713fcb3aedb236fcebe7dd6d323ba3 Mon Sep 17 00:00:00 2001 From: Vegard Storheil Eriksen Date: Wed, 2 Mar 2011 22:25:09 +0100 Subject: Add ability to serve parts of a file. --- http_connection.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) (limited to 'http_connection.cpp') diff --git a/http_connection.cpp b/http_connection.cpp index 041cd05..daba10b 100644 --- a/http_connection.cpp +++ b/http_connection.cpp @@ -1,17 +1,24 @@ #include "http_connection.h" #include +#include #include #include +#include +#include + +#include namespace response_map_init { typedef std::pair P; const P m[] = { P(200, "OK"), + P(206, "Partial Content"), P(400, "Bad Request"), P(403, "Forbidden"), P(404, "Not Found"), + P(416, "Requested Range Not Satisfiable"), P(500, "Internal Server Error"), P(501, "Not Implemented") }; @@ -52,6 +59,59 @@ void HTTP::Connection::send_data(std::istream& stream) { } } +void HTTP::Connection::send_file(const fs::path& filename) { + //req->add_header("Content-Type", "application/octet-stream"); + + fs::ifstream is(filename, std::ios::in | std::ios::binary); + is.seekg(0, std::ios::end); + std::size_t length = is.tellg(); + is.seekg(0, std::ios::beg); + + // Simple Range-parser. + // TODO: Support other formats than a single range. + if(headers.count("Range")) { + std::string range_str = headers["Range"]; + + if(!boost::starts_with(range_str, "bytes=")) { + // Broken header? We can't cope with that. + return; + } + + range_str = range_str.substr(6); + + std::string::iterator it = std::find(range_str.begin(), range_str.end(), '-'); + + std::size_t begin = boost::lexical_cast(std::string(range_str.begin(), it)); + std::size_t end = boost::lexical_cast(std::string(it + 1, range_str.end())) + 1; + + // Is the range past the end of the file? + if(end > length) { + end = length; + } + + // Do the file contain requested range? + if(end && end < begin || begin > length) { + send_error(416); + } + + add_header("Content-Range", boost::str(boost::format("bytes %d-%d/%d") % begin % (end - 1) % length)); + add_header("Content-Length", boost::str(boost::format("%d") % (end - begin))); + + write_headers(206); + + is.seekg(begin); + + char* buf = new char[end - begin]; + is.read(buf, end - begin); + send_data(buf, is.gcount()); + delete buf; + + } else { + add_header("Content-Length", boost::str(boost::format("%d") % length)); + send_data(is); + } +} + HTTP::Connection::Connection(boost::asio::io_service& io_service) : socket(io_service) { headers_written = false; } @@ -114,13 +174,13 @@ std::string HTTP::Connection::pop_path_base() { return base_path.back(); } -void HTTP::Connection::write_headers() { +void HTTP::Connection::write_headers(int code) { if(headers_written) { return; } headers_written = true; - boost::asio::write(socket, boost::asio::buffer(std::string("HTTP/1.1 200 OK\r\n"))); + boost::asio::write(socket, boost::asio::buffer(boost::str(boost::format("HTTP/1.1 %d %s\r\n") % code % response_map.find(code)->second))); for(HeaderList::iterator it = response_headers.begin(); it != response_headers.end(); it++) { boost::asio::write(socket, boost::asio::buffer(boost::str(boost::format("%s: %s\r\n") % it->first % it->second))); -- cgit v1.2.3