]> git.tdb.fi Git - libs/net.git/blobdiff - source/http/server.cpp
Hide Http::Server destructor in the library
[libs/net.git] / source / http / server.cpp
index 9205cc1096383caa797f1af237ec9e02e1b07724..9bdfa61ac153cb188ea4688ad5a911df4114f539 100644 (file)
@@ -1,4 +1,5 @@
 #include <exception>
+#include <msp/core/maputils.h>
 #include <msp/core/refptr.h>
 #include <msp/net/inet.h>
 #include <msp/net/resolve.h>
@@ -22,6 +23,11 @@ Server::Server(unsigned port):
        sock.listen(*addr, 8);
 }
 
+// Avoid emitting sigc::signal destructor in files including server.h
+Server::~Server()
+{
+}
+
 unsigned Server::get_port() const
 {
        const Net::SockAddr &addr = sock.get_local_address();
@@ -83,6 +89,8 @@ void Server::client_data_available(Client &cl)
 
        char rbuf[4096];
        unsigned len = cl.sock->read(rbuf, sizeof(rbuf));
+       if(cl.stale)
+               return;
        cl.in_buf.append(rbuf, len);
 
        RefPtr<Response> response;
@@ -103,6 +111,11 @@ void Server::client_data_available(Client &cl)
                                        response = new Response(NOT_IMPLEMENTED);
                                        response->add_content("Method not implemented\n");
                                }
+                               else if(cl.request->get_path()[0]!='/')
+                               {
+                                       response = new Response(BAD_REQUEST);
+                                       response->add_content("Path must be absolute\n");
+                               }
                        }
                        catch(const exception &e)
                        {
@@ -118,17 +131,23 @@ void Server::client_data_available(Client &cl)
                cl.in_buf.erase(0, len);
        }
 
+       bool keepalive = false;
        if(cl.request && cl.request->is_complete() && !response)
        {
+               if(cl.request->has_header("Connection"))
+                       keepalive = (cl.request->get_header("Connection")=="keep-alive");
+
                response = new Response(NONE);
                try
                {
                        cl.response = response.get();
+                       responses[cl.response] = &cl;
                        signal_request.emit(*cl.request, *response);
                        if(cl.async)
                                response.release();
                        else
                        {
+                               responses.erase(cl.response);
                                cl.response = 0;
                                if(response->get_status()==NONE)
                                {
@@ -139,6 +158,7 @@ void Server::client_data_available(Client &cl)
                }
                catch(const exception &e)
                {
+                       responses.erase(cl.response);
                        cl.response = 0;
                        response = new Response(INTERNAL_ERROR);
                        response->add_content(e.what());
@@ -148,7 +168,18 @@ void Server::client_data_available(Client &cl)
        if(response)
        {
                cl.sock->write(response->str());
-               cl.stale = true;
+               if(keepalive)
+               {
+                       delete cl.request;
+                       cl.request = 0;
+                       delete cl.response;
+                       cl.response = 0;
+               }
+               else
+               {
+                       cl.sock->shutdown(IO::M_WRITE);
+                       cl.stale = true;
+               }
        }
 }
 
@@ -159,12 +190,7 @@ void Server::client_end_of_file(Client &cl)
 
 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;
-
-       // XXX Do this differently
-       throw invalid_argument("Response does not belong to any client");
+       return *get_item(responses, &resp);
 }