diff options
author | Vegard Storheil Eriksen <zyp@jvnv.net> | 2011-01-02 22:28:26 +0100 |
---|---|---|
committer | Vegard Storheil Eriksen <zyp@jvnv.net> | 2011-01-02 22:28:26 +0100 |
commit | 0e3c3380d519b033500b4ed1ccd3acf707c34372 (patch) | |
tree | 115cbbf0200fc34011e68b32e56d58458a72d87f | |
parent | 237c3e226b7c2ac391b0e8d354e5fc6f587a41ba (diff) |
Merge HTTPResponse into HTTP::Connection.
-rw-r--r-- | http.cpp | 105 | ||||
-rw-r--r-- | http.h | 38 | ||||
-rw-r--r-- | http_connection.cpp | 38 | ||||
-rw-r--r-- | http_connection.h | 29 | ||||
-rw-r--r-- | main.cpp | 13 | ||||
-rw-r--r-- | music.cpp | 24 | ||||
-rw-r--r-- | music.h | 9 | ||||
-rw-r--r-- | transcode.cpp | 4 | ||||
-rw-r--r-- | transcode.h | 6 |
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); -} @@ -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; @@ -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"); } } @@ -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()); } } } @@ -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(); }; |