X-Git-Url: http://git.tdb.fi/?p=libs%2Fnet.git;a=blobdiff_plain;f=source%2Fhttp%2Fserver.cpp;h=f0474fd18e993c57de16b1a3f51c07dc260f069f;hp=9205cc1096383caa797f1af237ec9e02e1b07724;hb=b4e0f7ed23f24e78fd09c9b7f206279e16d38c1e;hpb=cf8d2e48581eeb8f1b83e8c48321a0bc2ffa6d83 diff --git a/source/http/server.cpp b/source/http/server.cpp index 9205cc1..f0474fd 100644 --- a/source/http/server.cpp +++ b/source/http/server.cpp @@ -1,9 +1,11 @@ #include +#include #include #include #include #include #include +#include #include "request.h" #include "response.h" #include "server.h" @@ -22,6 +24,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(); @@ -56,10 +63,12 @@ void Server::submit_response(Response &resp) { Client &cl = get_client_by_response(resp); if(cl.async) - { - cl.sock->write(resp.str()); - cl.stale = true; - } + send_response(cl, *cl.response); +} + +void Server::cancel_keepalive(Response &resp) +{ + get_client_by_response(resp).keepalive = false; } void Server::data_available() @@ -83,6 +92,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; @@ -95,7 +106,7 @@ void Server::client_data_available(Client &cl) cl.request = new Request(Request::parse(cl.in_buf)); string addr_str = cl.sock->get_peer_address().str(); - unsigned colon = addr_str.find(':'); + string::size_type colon = addr_str.find(':'); cl.request->set_header("-Client-Host", addr_str.substr(0, colon)); if(cl.request->get_method()!="GET" && cl.request->get_method()!="POST") @@ -103,6 +114,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) { @@ -120,15 +136,21 @@ void Server::client_data_available(Client &cl) if(cl.request && cl.request->is_complete() && !response) { + cl.keepalive = false; + if(cl.request->has_header("Connection")) + cl.keepalive = !strcasecmp(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 +161,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()); @@ -146,8 +169,25 @@ void Server::client_data_available(Client &cl) } if(response) + send_response(cl, *response); +} + +void Server::send_response(Client &cl, Response &resp) +{ + if(cl.keepalive) + resp.set_header("Connection", "keep-alive"); + cl.sock->write(resp.str()); + cl.async = false; + if(cl.keepalive) { - cl.sock->write(response->str()); + delete cl.request; + cl.request = 0; + delete cl.response; + cl.response = 0; + } + else + { + cl.sock->shutdown(IO::M_WRITE); cl.stale = true; } } @@ -159,12 +199,7 @@ void Server::client_end_of_file(Client &cl) 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; - - // XXX Do this differently - throw invalid_argument("Response does not belong to any client"); + return *get_item(responses, &resp); } @@ -172,6 +207,7 @@ Server::Client::Client(RefPtr s): sock(s), request(0), response(0), + keepalive(false), async(false), stale(false) { }