diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e691bf..7da9be8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,7 @@ set( sources src/ssh.cpp src/process.cpp src/http_connection.cpp -# src/http_server.cpp + src/http_server.cpp src/json_rpc_connection.cpp src/json_rpc_stream_connection.cpp src/json_rpc_tcp_connection.cpp diff --git a/include/fc/http/connection.hpp b/include/fc/http/connection.hpp index 557f57a..41e94e5 100644 --- a/include/fc/http/connection.hpp +++ b/include/fc/http/connection.hpp @@ -10,6 +10,9 @@ namespace fc { namespace http { struct header { + header( fc::string k, fc::string v ) + :key(fc::move(k)),val(fc::move(v)){} + header(){} fc::string key; fc::string val; }; diff --git a/src/http_connection.cpp b/src/http_connection.cpp index 648305c..38b745e 100644 --- a/src/http_connection.cpp +++ b/src/http_connection.cpp @@ -121,8 +121,37 @@ fc::tcp_socket& connection::get_socket()const { } http::request connection::read_request()const { - http::request r; - return r; + http::request req; + fc::vector line(1024*8); + int s = my->read_until( line.data(), line.data()+line.size(), ' ' ); // METHOD + req.method = line.data(); + s = my->read_until( line.data(), line.data()+line.size(), ' ' ); // PATH + req.path = line.data(); + s = my->read_until( line.data(), line.data()+line.size(), '\n' ); // HTTP/1.0 + + while( (s = my->read_until( line.data(), line.data()+line.size(), '\n' )) > 1 ) { + fc::http::header h; + char* end = line.data(); + while( *end != ':' )++end; + h.key = fc::string(line.data(),end); + ++end; // skip ':' + ++end; // skip space + char* skey = end; + while( *end != '\r' ) ++end; + h.val = fc::string(skey,end); + req.headers.push_back(h); + if( h.key == "Content-Length" ) { + req.body.resize( fc::lexical_cast( fc::string(h.val) ) ); + } + if( h.key == "Host" ) { + req.domain = h.val; + } + } + if( req.body.size() ) { + slog( "Reading body size %d", req.body.size() ); + my->sock.read( req.body.data(), req.body.size() ); + } + return req; } } } // fc::http diff --git a/src/http_server.cpp b/src/http_server.cpp index 90be148..09db676 100644 --- a/src/http_server.cpp +++ b/src/http_server.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace fc { namespace http { @@ -8,9 +9,30 @@ namespace fc { namespace http { class server::response::impl : public fc::retainable { public: impl( const fc::http::connection& c, const std::function& cont = std::function() ) - :con(c),handle_next_req(cont) + :body_bytes_sent(0),body_length(0),con(c),handle_next_req(cont) {} + void send_header() { + fc::stringstream ss; + ss << "HTTP/1.1 " << rep.status << " "; + switch( rep.status ) { + case fc::http::reply::OK: ss << "OK\n\r"; break; + case fc::http::reply::RecordCreated: ss << "Record Created\n\r"; break; + case fc::http::reply::NotFound: ss << "Not Found\n\r"; break; + case fc::http::reply::Found: ss << "Found\n\r"; break; + case fc::http::reply::InternalServerError: ss << "Internal Server Error\r\n"; break; + } + for( uint32_t i = 0; i < rep.headers.size(); ++i ) { + ss << rep.headers[i].key <<": "< handle_next_req; }; @@ -78,7 +100,37 @@ namespace fc { namespace http { server::response& server::response::operator=(const server::response& s) { my = s.my; return *this; } server::response& server::response::operator=(server::response&& s) { fc_swap(my,s.my); return *this; } + void server::response::add_header( const fc::string& key, const fc::string& val )const { + wlog( "Attempt to add header after sending headers" ); + my->rep.headers.push_back( fc::http::header( key, val ) ); + } + void server::response::set_status( const http::reply::status_code& s )const { + if( my->body_bytes_sent != 0 ) { + wlog( "Attempt to set status after sending headers" ); + } + my->rep.status = s; + } + void server::response::set_length( uint64_t s )const { + if( my->body_bytes_sent != 0 ) { + wlog( "Attempt to set length after sending headers" ); + } + my->body_length = s; + } + void server::response::write( const char* data, uint64_t len )const { + if( my->body_bytes_sent + len > my->body_length ) { + wlog( "Attempt to send to many bytes.." ); + len = my->body_bytes_sent + len - my->body_length; + } + if( my->body_bytes_sent == 0 ) { + my->send_header(); + } + my->body_bytes_sent += len; + my->con.get_socket().write( data, len ); + } + server::response::~response(){} + void server::on_request( const std::function& cb ) + { my->on_req = cb; }