#include "http_connection.h" #include #include #include namespace response_map_init { typedef std::pair P; const P m[] = { P(200, "OK"), P(400, "Bad Request"), P(403, "Forbidden"), P(404, "Not Found"), P(500, "Internal Server Error"), P(501, "Not Implemented") }; const P* begin = m; const P* end = m + sizeof(m) / sizeof(P); } const std::map response_map(response_map_init::begin, response_map_init::end); void HTTP::Connection::send_error(int code) { boost::asio::write(socket, boost::asio::buffer(boost::str(boost::format("HTTP/1.1 %1$d %2$s\r\n\r\n

%1$d %2$s

") % code % response_map.find(code)->second))); } 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) { write_headers(); boost::asio::write(socket, boost::asio::buffer(data)); } void HTTP::Connection::send_data(const void* data, std::size_t size) { write_headers(); boost::asio::write(socket, boost::asio::buffer(data, size)); } void HTTP::Connection::send_data(std::istream& stream) { char data[0x1000]; std::streamsize size = 1; while(size) { stream.read(data, 0x1000); size = stream.gcount(); if(size > 0) send_data(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) { } void HTTP::Connection::handle_read(const boost::system::error_code& error, size_t bytes_transferred, Handler callback) { try { if(!parse_request(buf)) { // Request parse error. std::cout << "Request parse error." << std::endl; send_error(400); return; } std::cout << "Path: " << std::endl; for(PathList::iterator it = path.begin(); it != path.end(); it++) { std::cout << " " << *it << std::endl; } std::cout << "Args: " << std::endl; for(std::map::iterator it = args.begin(); it != args.end(); it++) { std::cout << " " << it->first << " = " << it->second << std::endl; } std::cout << "Headers: " << std::endl; for(std::map::iterator it = headers.begin(); it != headers.end(); it++) { std::cout << " " << it->first << " = " << it->second << std::endl; } callback(shared_from_this()); // Catch unhandled exceptions. } catch(std::exception& e) { std::cerr << "Unhandled exception while handling request: " << e.what() << std::endl; try { send_error(500); } catch(...) { // Ignored. } } } 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)); } std::string HTTP::Connection::pop_path_base() { if(!path.size()) { return ""; } base_path.push_back(path.front()); path.pop_front(); return base_path.back(); } void HTTP::Connection::write_headers() { if(headers_written) { return; } headers_written = true; boost::asio::write(socket, boost::asio::buffer(std::string("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(std::string("\r\n"))); }