summaryrefslogtreecommitdiff
path: root/http_connection.cpp
diff options
context:
space:
mode:
authorVegard Storheil Eriksen <zyp@jvnv.net>2011-03-02 22:25:09 +0100
committerVegard Storheil Eriksen <zyp@jvnv.net>2011-03-02 22:25:09 +0100
commit0c2f90ee5c713fcb3aedb236fcebe7dd6d323ba3 (patch)
tree5cd273e39a9679afd75a97bdb2bb6d1f839b0dc9 /http_connection.cpp
parent0649a5c78eeef6eba731ee1c698e18554cad5670 (diff)
Add ability to serve parts of a file.
Diffstat (limited to 'http_connection.cpp')
-rw-r--r--http_connection.cpp64
1 files changed, 62 insertions, 2 deletions
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 <iostream>
+#include <algorithm>
#include <boost/bind.hpp>
#include <boost/format.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <boost/filesystem/fstream.hpp>
namespace response_map_init {
typedef std::pair<int, std::string> 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<int>(std::string(range_str.begin(), it));
+ std::size_t end = boost::lexical_cast<int>(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)));