+#include "server.h"
#include <exception>
#include <typeinfo>
#include <msp/core/maputils.h>
-#include <msp/core/refptr.h>
#include <msp/debug/demangle.h>
#include <msp/net/inet.h>
#include <msp/net/resolve.h>
#include <msp/strings/utils.h>
#include "request.h"
#include "response.h"
-#include "server.h"
using namespace std;
namespace Http {
Server::Server():
- sock(Net::INET6),
- event_disp(0)
+ sock(Net::INET6)
{ }
Server::Server(unsigned port):
- sock(Net::INET6),
- event_disp(0)
+ sock(Net::INET6)
{
listen(port);
}
void Server::listen(unsigned port)
{
- RefPtr<Net::SockAddr> addr = Net::resolve("*", format("%d", port), Net::INET6);
+ unique_ptr<Net::SockAddr> addr(Net::resolve("*", format("%d", port), Net::INET6));
sock.listen(*addr, 8);
sock.signal_data_available.connect(sigc::mem_fun(this, &Server::data_available));
}
if(event_disp)
{
event_disp->remove(sock);
- for(list<Client>::iterator i=clients.begin(); i!=clients.end(); ++i)
- event_disp->remove(*i->sock);
+ for(Client &c: clients)
+ event_disp->remove(*c.sock);
}
event_disp = ed;
if(event_disp)
{
event_disp->add(sock);
- for(list<Client>::iterator i=clients.begin(); i!=clients.end(); ++i)
- event_disp->add(*i->sock);
+ for(Client &c: clients)
+ event_disp->add(*c.sock);
}
}
get_client_by_response(resp).keepalive = false;
}
+void Server::close_connections(const Time::TimeDelta &timeout)
+{
+ IO::Poller poller;
+ for(Client &c: clients)
+ {
+ c.sock->shutdown(IO::M_WRITE);
+ poller.set_object(*c.sock, IO::P_INPUT);
+ }
+
+ while(!clients.empty() && poller.poll(timeout))
+ {
+ for(const IO::Poller::PolledObject &p: poller.get_result())
+ for(auto j=clients.begin(); j!=clients.end(); ++j)
+ if(j->sock.get()==p.object)
+ {
+ poller.set_object(*j->sock, IO::P_NONE);
+ clients.erase(j);
+ break;
+ }
+ }
+}
+
void Server::data_available()
{
- Net::StreamSocket *csock = sock.accept();
- clients.push_back(Client(csock));
- csock->signal_data_available.connect(sigc::bind(sigc::mem_fun(this, &Server::client_data_available), sigc::ref(clients.back())));
- csock->signal_end_of_file.connect(sigc::bind(sigc::mem_fun(this, &Server::client_end_of_file), sigc::ref(clients.back())));
+ unique_ptr<Net::StreamSocket> csock(sock.accept());
+ clients.emplace_back(move(csock));
+ Client &cl = clients.back();
+ cl.sock->signal_data_available.connect(sigc::bind(sigc::mem_fun(this, &Server::client_data_available), sigc::ref(clients.back())));
+ cl.sock->signal_end_of_file.connect(sigc::bind(sigc::mem_fun(this, &Server::client_end_of_file), sigc::ref(clients.back())));
if(event_disp)
- event_disp->add(*csock);
+ event_disp->add(*cl.sock);
}
void Server::client_data_available(Client &cl)
{
- for(list<Client>::iterator i=clients.begin(); i!=clients.end(); ++i)
+ for(auto i=clients.begin(); i!=clients.end(); ++i)
if(i->stale && &*i!=&cl)
{
clients.erase(i);
return;
}
- RefPtr<Response> response;
+ unique_ptr<Response> response;
if(!cl.request)
{
if(cl.in_buf.find("\r\n\r\n")!=string::npos || cl.in_buf.find("\n\n")!=string::npos)
{
try
{
- cl.request = new Request(Request::parse(cl.in_buf));
+ cl.request = make_unique<Request>(Request::parse(cl.in_buf));
string addr_str = cl.sock->get_peer_address().str();
string::size_type colon = addr_str.find(':');
if(cl.request->get_method()!="GET" && cl.request->get_method()!="POST")
{
- response = new Response(NOT_IMPLEMENTED);
+ response = make_unique<Response>(NOT_IMPLEMENTED);
response->add_content("Method not implemented\n");
}
else if(cl.request->get_path()[0]!='/')
{
- response = new Response(BAD_REQUEST);
+ response = make_unique<Response>(BAD_REQUEST);
response->add_content("Path must be absolute\n");
}
}
catch(const exception &e)
{
- response = new Response(BAD_REQUEST);
+ response = make_unique<Response>(BAD_REQUEST);
response->add_content(format("An error occurred while parsing request headers:\ntype: %s\nwhat: %s",
Debug::demangle(typeid(e).name()), e.what()));
}
if(cl.request->has_header("Connection"))
cl.keepalive = !strcasecmp(cl.request->get_header("Connection"), "keep-alive");
- response = new Response(NONE);
+ response = make_unique<Response>(NONE);
try
{
- cl.response = response.get();
- responses[cl.response] = &cl;
- signal_request.emit(*cl.request, *response);
- if(cl.async)
- response.release();
- else
+ cl.response = move(response);
+ responses[cl.response.get()] = &cl;
+ signal_request.emit(*cl.request, *cl.response);
+ if(!cl.async)
{
- responses.erase(cl.response);
- cl.response = 0;
+ responses.erase(cl.response.get());
+ response = move(cl.response);
if(response->get_status()==NONE)
{
- response = new Response(NOT_FOUND);
+ response = make_unique<Response>(NOT_FOUND);
response->add_content("The requested resource was not found\n");
}
}
}
catch(const exception &e)
{
- responses.erase(cl.response);
- cl.response = 0;
- response = new Response(INTERNAL_ERROR);
+ responses.erase(cl.response.get());
+ cl.response.reset();
+ response = make_unique<Response>(INTERNAL_ERROR);
response->add_content(format("An error occurred while processing the request:\ntype: %s\nwhat: %s",
Debug::demangle(typeid(e).name()), e.what()));
}
cl.async = false;
if(cl.keepalive)
{
- delete cl.request;
- cl.request = 0;
- delete cl.response;
- cl.response = 0;
+ cl.request.reset();
+ cl.response.reset();
}
else
{
}
-Server::Client::Client(RefPtr<Net::StreamSocket> s):
- sock(s),
- request(0),
- response(0),
- keepalive(false),
- async(false),
- stale(false)
+Server::Client::Client(unique_ptr<Net::StreamSocket> s):
+ sock(move(s))
{ }
-Server::Client::~Client()
-{
- delete request;
- delete response;
-}
-
} // namespace Http
} // namespace Msp