summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVegard Storheil Eriksen <zyp@jvnv.net>2011-01-02 22:28:26 +0100
committerVegard Storheil Eriksen <zyp@jvnv.net>2011-01-02 22:28:26 +0100
commit0e3c3380d519b033500b4ed1ccd3acf707c34372 (patch)
tree115cbbf0200fc34011e68b32e56d58458a72d87f
parent237c3e226b7c2ac391b0e8d354e5fc6f587a41ba (diff)
Merge HTTPResponse into HTTP::Connection.
-rw-r--r--http.cpp105
-rw-r--r--http.h38
-rw-r--r--http_connection.cpp38
-rw-r--r--http_connection.h29
-rw-r--r--main.cpp13
-rw-r--r--music.cpp24
-rw-r--r--music.h9
-rw-r--r--transcode.cpp4
-rw-r--r--transcode.h6
9 files changed, 80 insertions, 186 deletions
diff --git a/http.cpp b/http.cpp
deleted file mode 100644
index d7b1dc9..0000000
--- a/http.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-#include "http.h"
-
-#include <boost/format.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/algorithm/string/regex.hpp>
-
-#include <vector>
-
-HTTPRequest::HTTPRequest(std::istream& is) {
- std::string firstline, query_str;
- std::getline(is, firstline);
-
- std::vector<std::string> splitvec;
- boost::algorithm::split(splitvec, firstline, boost::algorithm::is_space());
-
- type = splitvec[0];
- path = splitvec[1];
- httpver = splitvec[2];
-
- if(path.find("?") != std::string::npos) {
- boost::algorithm::split(splitvec, path, boost::is_any_of("?"));
- path = splitvec[0];
- query_str = splitvec[1];
- boost::algorithm::split(splitvec, query_str, boost::is_any_of("&"));
- for(std::vector<std::string>::iterator it = splitvec.begin(); it != splitvec.end(); it++) {
- std::vector<std::string> sv;
- boost::algorithm::split(sv, *it, boost::is_any_of("="));
- std::string key = sv[0];
- std::string value = sv[1];
- url_decode(key);
- url_decode(value);
- query[key] = value;
- std::cout << boost::format("%s: %s") % key % value << std::endl;
- }
- }
- url_decode(path);
-
- std::cout << boost::format("%s %s %s\n") % type % path % httpver;
-
- while(is.good()) {
- std::string line;
- std::getline(is, line);
- boost::trim(line);
- if(!line.size()) continue;
- std::vector<std::string> v;
- boost::algorithm::split_regex(v, line, boost::regex(": "));
- headers[v[0]] = v[1];
- }
-}
-
-void HTTPRequest::url_decode(std::string& str) {
- std::string::const_iterator start, end, prev;
- start = str.begin();
- end = str.end();
- boost::match_results<std::string::const_iterator> what;
- boost::match_flag_type flags = boost::match_default;
- boost::regex re("%([0-9a-fA-F]{2})");
- prev = start;
- std::string out;
- while(boost::regex_search(start, end, what, re, flags)) {
- std::istringstream hs(what[1]);
- char c;
- int hi;
- hs >> std::hex >> hi;
- c = hi;
- out += std::string(prev, what[1].first - 1) + c;
- start = what[1].second;
- prev = start;
- }
- out += std::string(prev, end);
- str = out;
-}
-
-HTTPResponse::HTTPResponse(boost::asio::ip::tcp::socket& socket_) : socket(socket_){
- httpver = "1.1";
- headers_written = false;
-}
-
-void HTTPResponse::add_header(std::string key, std::string value) {
- headers[key] = value;
-}
-
-void HTTPResponse::write_headers() {
- write(boost::str(boost::format("HTTP/%s %d %s\r\n") % httpver % code % status));
- for(HTTPHeaders::iterator it = headers.begin(); it != headers.end(); it++) {
- write(boost::str(boost::format("%s: %s\r\n") % it->first % it->second));
- }
- write("\r\n");
-}
-
-void HTTPResponse::write(char *data, unsigned int len) {
- write(std::string(data, len));
-}
-
-void HTTPResponse::write(std::string str) {
- if(!headers_written) {
- // make sure to set headers_written before calling write_headers
- headers_written = true;
- write_headers();
- }
- boost::asio::streambuf b;
- std::ostream os(&b);
- os << str;
- boost::asio::write(socket, b);
-}
diff --git a/http.h b/http.h
deleted file mode 100644
index 29add9a..0000000
--- a/http.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef HTTP_H
-#define HTTP_H
-
-#include <boost/asio.hpp>
-
-#include <iostream>
-#include <string>
-#include <map>
-
-typedef std::map<std::string, std::string> stringmap;
-typedef stringmap HTTPHeaders;
-typedef stringmap HTTPQuery;
-
-class HTTPRequest {
- public:
- std::string type, path, httpver;
- HTTPQuery query;
- HTTPHeaders headers;
- HTTPRequest(std::istream& is);
- static void url_decode(std::string& str);
-};
-
-class HTTPResponse {
- private:
- HTTPHeaders headers;
- boost::asio::ip::tcp::socket& socket;
- void write_headers();
- bool headers_written;
- public:
- int code;
- std::string httpver, status;
- HTTPResponse(boost::asio::ip::tcp::socket& socket_);
- void add_header(std::string key, std::string value);
- void write(char *data, unsigned int len);
- void write(std::string str);
-};
-
-#endif
diff --git a/http_connection.cpp b/http_connection.cpp
index a86d2ac..863aca1 100644
--- a/http_connection.cpp
+++ b/http_connection.cpp
@@ -1,11 +1,28 @@
#include "http_connection.h"
-#include "http.h"
+#include <iostream>
#include <boost/bind.hpp>
#include <boost/format.hpp>
+void HTTP::Connection::send_error(int code, std::string name) {
+ boost::asio::write(socket, boost::asio::buffer(boost::str(boost::format("HTTP/1.1 %1$d %2$s\r\n\r\n<h1>%1$d %2$s</h1>") % code % name)));
+}
+
+void HTTP::Connection::add_header(std::string key, std::string value) {
+ response_headers.push_back(std::make_pair(key, value));
+}
+
+void HTTP::Connection::send_data(const std::string& data) {
+ boost::asio::write(socket, boost::asio::buffer(data));
+}
+
+void HTTP::Connection::send_data(const void* data, std::size_t size) {
+ boost::asio::write(socket, boost::asio::buffer(data, size));
+}
+
HTTP::Connection::Connection(boost::asio::io_service& io_service) : socket(io_service) {
+ headers_written = false;
}
void HTTP::Connection::handle_write(const boost::system::error_code& error, size_t bytes_transferred) {
@@ -37,10 +54,6 @@ void HTTP::Connection::handle_read(const boost::system::error_code& error, size_
callback(shared_from_this());
}
-void print(char c) {
- std::cout << "Char: " << int(c) << std::endl;
-}
-
void HTTP::Connection::read_request(Handler callback) {
boost::asio::async_read_until(socket, buf, "\r\n\r\n", boost::bind(&Connection::handle_read, shared_from_this(),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, callback));
@@ -57,6 +70,17 @@ std::string HTTP::Connection::pop_path_base() {
return base_path.back();
}
-void HTTP::Connection::send_error(int code, std::string name) {
- boost::asio::write(socket, boost::asio::buffer(boost::str(boost::format("HTTP/1.1 %1$d %2$s\r\n\r\n<h1>%1$d %2$s</h1>") % code % name)));
+void HTTP::Connection::write_headers() {
+ if(headers_written) {
+ return;
+ }
+ headers_written = true;
+
+ boost::asio::write(socket, boost::asio::buffer("HTTP/1.1 200 OK\r\n"));
+
+ 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)));
+ }
+
+ boost::asio::write(socket, boost::asio::buffer("\r\n"));
}
diff --git a/http_connection.h b/http_connection.h
index 5a01273..446f0af 100644
--- a/http_connection.h
+++ b/http_connection.h
@@ -2,6 +2,7 @@
#define HTTP_CONNECTION_H
#include <string>
+#include <vector>
#include <list>
#include <map>
@@ -20,9 +21,6 @@ namespace HTTP {
typedef boost::function<void (Connection::p)> Handler;
typedef std::list<std::string> PathList;
- //! Start reading the request headers.
- void read_request(Handler callback);
-
//! Request method.
std::string method;
@@ -47,16 +45,39 @@ namespace HTTP {
//! Send error.
void send_error(int code, std::string name);
- tcp::socket socket;
+ //! Add response header.
+ void add_header(std::string key, std::string value);
+
+ //! Send data.
+ void send_data(const std::string& data);
+ void send_data(const void* data, std::size_t size);
+
private:
+ typedef std::vector<std::pair<std::string, std::string> > HeaderList;
+
+ //! Constructor.
Connection(boost::asio::io_service& io_service);
+
+ //! Start reading the request headers.
+ void read_request(Handler callback);
+
void handle_write(const boost::system::error_code& error, size_t bytes_transferred);
void handle_read(const boost::system::error_code& error, size_t bytes_transferred, Handler callback);
+ tcp::socket socket;
boost::asio::streambuf buf;
+ //! Response headers.
+ HeaderList response_headers;
+
//! Parse request headers.
bool parse_request(boost::asio::streambuf& buf);
+
+ //! Write response headers.
+ void write_headers();
+
+ //! Response headers written?
+ bool headers_written;
};
typedef Connection::Handler Handler;
diff --git a/main.cpp b/main.cpp
index ebe3554..1099960 100644
--- a/main.cpp
+++ b/main.cpp
@@ -13,18 +13,11 @@
void foo_handler(HTTP::Connection::p connection) {
std::cout << "Handling!" << std::endl;
- HTTPResponse res(connection->socket);
-
- //MusicListing::p ml = music::get(connection->path);
- bool ml = 0;
+ MusicListing::p ml = music::get(connection->path);
if(ml) {
- res.code = 200;
- res.status = "OK";
-
- //ml->render(connection, res);
+ ml->render(connection);
} else {
- res.code = 404;
- res.status = "Not Found";
+ connection->send_error(404, "Not Found");
}
}
diff --git a/music.cpp b/music.cpp
index 9892526..3552f8e 100644
--- a/music.cpp
+++ b/music.cpp
@@ -23,11 +23,11 @@ void music::init(std::string root) {
root_directory = root;
}
-MusicListing::p music::get(const std::vector<std::string>& path) {
+MusicListing::p music::get(const HTTP::Connection::PathList& path) {
// prefix path with our root_directory
fs::path p = root_directory;
- for(std::vector<std::string>::const_iterator it = path.begin(); it != path.end(); it++) {
+ for(HTTP::Connection::PathList::const_iterator it = path.begin(); it != path.end(); it++) {
// don't allow requests with /../ in the path
if(*it == "..") {
return MusicListing::p();
@@ -48,7 +48,7 @@ MusicListing::p music::get(const std::vector<std::string>& path) {
}
MusicListing::p music::get(const std::string& path) {
- std::vector<std::string> path_vector;
+ HTTP::Connection::PathList path_vector;
boost::algorithm::split(path_vector, path, boost::algorithm::is_any_of("/\\"));
return get(path_vector);
}
@@ -93,16 +93,16 @@ void music::update(const MusicDirectory& dir) {
std::for_each(dir.directories.begin(), dir.directories.end(), update);
}
-void MusicDirectory::render(HTTP::Connection::p req, HTTPResponse& res) {
- res.add_header("content-type", "text/html");
+void MusicDirectory::render(HTTP::Connection::p req) {
+ req->add_header("content-type", "text/html");
for(PathListings::iterator it = directories.begin(); it != directories.end(); it++) {
std::string rel_path = it->string().substr(music::root_directory.string().size());
- res.write(boost::str(boost::format("<a href=\"/files%s\">%s</a><br />") % rel_path % rel_path));
+ req->send_data(boost::str(boost::format("<a href=\"/files%s\">%s</a><br />") % rel_path % rel_path));
}
for(PathListings::iterator it = tracks.begin(); it != tracks.end(); it++) {
std::string rel_path = it->string().substr(music::root_directory.string().size());
- res.write(boost::str(boost::format("<a href=\"/files%s\">%s</a><br />") % rel_path % rel_path));
+ req->send_data(boost::str(boost::format("<a href=\"/files%s\">%s</a><br />") % rel_path % rel_path));
}
}
@@ -125,8 +125,8 @@ MusicDirectory::MusicDirectory(const fs::path root) {
}
}
-void MusicTrack::render(HTTP::Connection::p req, HTTPResponse& res) {
- res.add_header("content-type", "application/octet-stream");
+void MusicTrack::render(HTTP::Connection::p req) {
+ req->add_header("content-type", "application/octet-stream");
// tag test
Tag *t = new ID3Tag(path.string());
@@ -135,20 +135,20 @@ void MusicTrack::render(HTTP::Connection::p req, HTTPResponse& res) {
if(req->args.count("decoder") && req->args.count("encoder")) {
DecoderBase *d = decoder::get_decoder(req->args["decoder"]);
EncoderBase *e = encoder::get_encoder(req->args["encoder"]);
- Transcoder t(path.string(), res, *d, *e);
+ Transcoder t(path.string(), req, *d, *e);
t.run();
delete d;
delete e;
} else {
fs::ifstream is(path, std::ios::in | std::ios::binary);
is.seekg(0, std::ios::end);
- res.add_header("content-length", boost::str(boost::format("%d") % is.tellg()));
+ req->add_header("content-length", boost::str(boost::format("%d") % is.tellg()));
is.seekg(0, std::ios::beg);
char data[0x1000];
while(is.good()) {
is.read(data, 0x1000);
- res.write(data, is.gcount());
+ req->send_data(data, is.gcount());
}
}
}
diff --git a/music.h b/music.h
index 1362a7a..c019136 100644
--- a/music.h
+++ b/music.h
@@ -1,7 +1,6 @@
#ifndef MUSIC_H
#define MUSIC_H
-#include "http.h"
#include "http_connection.h"
#include <boost/filesystem.hpp>
@@ -14,13 +13,13 @@ class MusicListing {
public:
typedef boost::shared_ptr<MusicListing> p;
fs::path path;
- virtual void render(HTTP::Connection::p req, HTTPResponse& res) = 0;
+ virtual void render(HTTP::Connection::p req) = 0;
};
class MusicTrack : public MusicListing {
public:
MusicTrack(const fs::path path);
- virtual void render(HTTP::Connection::p req, HTTPResponse& res);
+ virtual void render(HTTP::Connection::p req);
};
class MusicDirectory : public MusicListing {
@@ -31,13 +30,13 @@ class MusicDirectory : public MusicListing {
PathListings tracks;
MusicDirectory(const fs::path root);
- virtual void render(HTTP::Connection::p req, HTTPResponse& res);
+ virtual void render(HTTP::Connection::p req);
};
namespace music {
extern fs::path root_directory;
void init(std::string root);
- MusicListing::p get(const std::vector<std::string>& path);
+ MusicListing::p get(const HTTP::Connection::PathList& path);
MusicListing::p get(const std::string& path);
MusicDirectory::p get_directory(const std::string& path);
std::vector<MusicListing::p> find_artist(const std::string artist);
diff --git a/transcode.cpp b/transcode.cpp
index 5244627..81d5274 100644
--- a/transcode.cpp
+++ b/transcode.cpp
@@ -3,7 +3,7 @@
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
-Transcoder::Transcoder(std::string p, HTTPResponse& r, DecoderBase& d, EncoderBase& e) : path(p), res(r), decoder(d), encoder(e) {
+Transcoder::Transcoder(std::string p, HTTP::Connection::p r, DecoderBase& d, EncoderBase& e) : path(p), res(r), decoder(d), encoder(e) {
}
void Transcoder::run() {
@@ -20,6 +20,6 @@ void Transcoder::run() {
s.read(data, 0x1000);
size = s.gcount();
if(size > 0)
- res.write(data, size);
+ res->send_data(data, size);
}
}
diff --git a/transcode.h b/transcode.h
index d0e781d..70d0113 100644
--- a/transcode.h
+++ b/transcode.h
@@ -3,19 +3,19 @@
#include "decoder.h"
#include "encoder.h"
-#include "http.h"
+#include "http_connection.h"
#include <string>
class Transcoder {
private:
std::string path;
- HTTPResponse& res;
+ HTTP::Connection::p res;
DecoderBase& decoder;
EncoderBase& encoder;
public:
- Transcoder(std::string p, HTTPResponse& r, DecoderBase& d, EncoderBase& e);
+ Transcoder(std::string p, HTTP::Connection::p r, DecoderBase& d, EncoderBase& e);
void run();
};