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<const Net::InetAddr &>(addr).get_port();
+ return 0;
+}
+
void Server::use_event_dispatcher(IO::EventDispatcher *ed)
{
if(event_disp)
}
}
+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();
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);
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());
}
cl.stale=true;
}
+Server::Client &Server::get_client_by_response(Response &resp)
+{
+ for(list<Client>::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<Net::StreamSocket> s):
sock(s),
request(0),
+ response(0),
+ async(false),
stale(false)
{ }
Server::Client::~Client()
{
delete request;
+ delete response;
}
} // namespace Http
RefPtr<Net::StreamSocket> sock;
std::string in_buf;
Request *request;
+ Response *response;
+ bool async;
bool stale;
Client(RefPtr<Net::StreamSocket>);
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
--- /dev/null
+/* $Id$
+
+This file is part of libmsphttp
+Copyright © 2009 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <msp/strings/formatter.h>
+#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; i<str.size(); ++i)
+ {
+ char c=str[i];
+ if(c=='%')
+ {
+ if(i+3>str.size())
+ throw InvalidParameterValue("Malformed data");
+ result+=lexical_cast<unsigned char>(str.substr(i+1, 2), "x");
+ i+=2;
+ }
+ else if(c=='+')
+ result+=' ';
+ else
+ result+=c;
+ }
+ return result;
+}
+
+} // namespace Http
+} // namespace Msp
--- /dev/null
+/* $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 <string>
+
+namespace Msp {
+namespace Http {
+
+std::string urlencode(const std::string &);
+std::string urldecode(const std::string &);
+
+} // namespace Http
+} // namespace Msp
+
+#endif