From 077408f98f08fac1a098a501fffdb22728a57a46 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 5 Jul 2009 20:36:37 +0000 Subject: [PATCH] Support handling requests asynchronously Add urlencode/urldecode functions --- source/server.cpp | 55 ++++++++++++++++++++++++++++++++++++--- source/server.h | 6 +++++ source/utils.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++++++ source/utils.h | 22 ++++++++++++++++ 4 files changed, 145 insertions(+), 3 deletions(-) create mode 100644 source/utils.cpp create mode 100644 source/utils.h diff --git a/source/server.cpp b/source/server.cpp index 7f159ac..04eea52 100644 --- a/source/server.cpp +++ b/source/server.cpp @@ -26,6 +26,14 @@ Server::Server(unsigned port): sock.listen(Net::InetAddr(0, port), 8); } +unsigned Server::get_port() const +{ + const Net::SockAddr &addr=sock.get_local_address(); + if(addr.get_family()==Net::INET) + return static_cast(addr).get_port(); + return 0; +} + void Server::use_event_dispatcher(IO::EventDispatcher *ed) { if(event_disp) @@ -43,6 +51,22 @@ void Server::use_event_dispatcher(IO::EventDispatcher *ed) } } +void Server::delay_response(Response &resp) +{ + get_client_by_response(resp).async=true; +} + +void Server::submit_response(Response &resp) +{ + Client &cl=get_client_by_response(resp); + if(cl.async) + { + cl.sock->write(resp.str()); + cl.sock->close(); + cl.stale=true; + } +} + void Server::data_available() { Net::StreamSocket *csock=sock.accept(); @@ -74,6 +98,11 @@ void Server::client_data_available(Client &cl) try { cl.request=new Request(Request::parse(cl.in_buf)); + + string addr_str=cl.sock->get_peer_address().str(); + unsigned colon=addr_str.find(':'); + cl.request->set_header("-Client-Host", addr_str.substr(0, colon)); + if(cl.request->get_method()!="GET") { response=new Response(NOT_IMPLEMENTED); @@ -99,15 +128,23 @@ void Server::client_data_available(Client &cl) response=new Response(NONE); try { + cl.response=response.get(); signal_request.emit(*cl.request, *response); - if(response->get_status()==NONE) + if(cl.async) + response.release(); + else { - response=new Response(NOT_FOUND); - response->add_content("The requested resource was not found"); + cl.response=0; + if(response->get_status()==NONE) + { + response=new Response(NOT_FOUND); + response->add_content("The requested resource was not found"); + } } } catch(const exception &e) { + cl.response=0; response=new Response(INTERNAL_ERROR); response->add_content(e.what()); } @@ -126,16 +163,28 @@ void Server::client_end_of_file(Client &cl) cl.stale=true; } +Server::Client &Server::get_client_by_response(Response &resp) +{ + for(list::iterator i=clients.begin(); i!=clients.end(); ++i) + if(i->response==&resp) + return *i; + + throw InvalidParameterValue("Response does not belong to any client"); +} + Server::Client::Client(RefPtr s): sock(s), request(0), + response(0), + async(false), stale(false) { } Server::Client::~Client() { delete request; + delete response; } } // namespace Http diff --git a/source/server.h b/source/server.h index ea12134..93c1f59 100644 --- a/source/server.h +++ b/source/server.h @@ -29,6 +29,8 @@ private: RefPtr sock; std::string in_buf; Request *request; + Response *response; + bool async; bool stale; Client(RefPtr); @@ -41,11 +43,15 @@ private: public: Server(unsigned); + unsigned get_port() const; void use_event_dispatcher(IO::EventDispatcher *); + void delay_response(Response &); + void submit_response(Response &); private: void data_available(); void client_data_available(Client &); void client_end_of_file(Client &); + Client &get_client_by_response(Response &); }; } // namespace Http diff --git a/source/utils.cpp b/source/utils.cpp new file mode 100644 index 0000000..d550259 --- /dev/null +++ b/source/utils.cpp @@ -0,0 +1,65 @@ +/* $Id$ + +This file is part of libmsphttp +Copyright © 2009 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include "utils.h" + +using namespace std; + +namespace { + +const char reserved[]=" :/?#[]@!$&'()*+,;=%"; + +bool is_reserved(char c) +{ + for(const char *r=reserved; *r; ++r) + if(c==*r) + return true; + return false; +} + +} + +namespace Msp { +namespace Http { + +string urlencode(const string &str) +{ + string result; + for(string::const_iterator i=str.begin(); i!=str.end(); ++i) + { + if(is_reserved(*i)) + result+=format("%%%02X", *i); + else + result+=*i; + } + return result; +} + +string urldecode(const string &str) +{ + string result; + for(unsigned i=0; istr.size()) + throw InvalidParameterValue("Malformed data"); + result+=lexical_cast(str.substr(i+1, 2), "x"); + i+=2; + } + else if(c=='+') + result+=' '; + else + result+=c; + } + return result; +} + +} // namespace Http +} // namespace Msp diff --git a/source/utils.h b/source/utils.h new file mode 100644 index 0000000..76127a4 --- /dev/null +++ b/source/utils.h @@ -0,0 +1,22 @@ +/* $Id$ + +This file is part of libmsphttp +Copyright © 2009 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_HTTP_UTILS_H_ +#define MSP_HTTP_UTILS_H_ + +#include + +namespace Msp { +namespace Http { + +std::string urlencode(const std::string &); +std::string urldecode(const std::string &); + +} // namespace Http +} // namespace Msp + +#endif -- 2.43.0