]> git.tdb.fi Git - libs/net.git/blob - source/server.cpp
Add Server class
[libs/net.git] / source / server.cpp
1 /* $Id$
2
3 This file is part of libmsphttp
4 Copyright © 2008  Mikkosoft Productions, Mikko Rasa
5 Distributed under the LGPL
6 */
7
8 #include <exception>
9 #include <msp/core/refptr.h>
10 #include <msp/net/inet.h>
11 #include <msp/net/streamsocket.h>
12 #include "request.h"
13 #include "response.h"
14 #include "server.h"
15
16 using namespace std;
17
18 namespace Msp {
19 namespace Http {
20
21 Server::Server(unsigned port):
22         sock(Net::INET),
23         event_disp(0)
24 {
25         sock.signal_data_available.connect(sigc::mem_fun(this, &Server::data_available));
26         sock.listen(Net::InetAddr(0, port), 8);
27 }
28
29 void Server::use_event_dispatcher(IO::EventDispatcher *ed)
30 {
31         if(event_disp)
32         {
33                 event_disp->remove(sock);
34                 for(list<Client>::iterator i=clients.begin(); i!=clients.end(); ++i)
35                         event_disp->remove(*i->sock);
36         }
37         event_disp=ed;
38         if(event_disp)
39         {
40                 event_disp->add(sock);
41                 for(list<Client>::iterator i=clients.begin(); i!=clients.end(); ++i)
42                         event_disp->add(*i->sock);
43         }
44 }
45
46 void Server::data_available()
47 {
48         Net::StreamSocket *csock=sock.accept();
49         clients.push_back(Client(csock));
50         csock->signal_data_available.connect(sigc::bind(sigc::mem_fun(this, &Server::client_data_available), sigc::ref(clients.back())));
51         csock->signal_end_of_file.connect(sigc::bind(sigc::mem_fun(this, &Server::client_end_of_file), sigc::ref(clients.back())));
52         if(event_disp)
53                 event_disp->add(*csock);
54 }
55
56 void Server::client_data_available(Client &cl)
57 {
58         for(list<Client>::iterator i=clients.begin(); i!=clients.end(); ++i)
59                 if(i->stale && &*i!=&cl)
60                 {
61                         clients.erase(i);
62                         break;
63                 }
64
65         char rbuf[4096];
66         unsigned len=cl.sock->read(rbuf, sizeof(rbuf));
67         cl.in_buf.append(rbuf, len);
68
69         RefPtr<Response> response;
70         if(!cl.request)
71         {
72                 if(cl.in_buf.find("\r\n\r\n")!=string::npos || cl.in_buf.find("\n\n")!=string::npos)
73                 {
74                         try
75                         {
76                                 cl.request=new Request(Request::parse(cl.in_buf));
77                                 if(cl.request->get_method()!="GET")
78                                 {
79                                         response=new Response(NOT_IMPLEMENTED);
80                                         response->add_content("Method not implemented");
81                                 }
82                         }
83                         catch(const exception &e)
84                         {
85                                 response=new Response(BAD_REQUEST);
86                                 response->add_content(e.what());
87                         }
88                         cl.in_buf=string();
89                 }
90         }
91         else
92         {
93                 len=cl.request->parse_content(cl.in_buf);
94                 cl.in_buf.erase(0, len);
95         }
96
97         if(cl.request && cl.request->is_complete() && !response)
98         {
99                 response=new Response(NONE);
100                 try
101                 {
102                         signal_request.emit(*cl.request, *response);
103                         if(response->get_status()==NONE)
104                         {
105                                 response=new Response(NOT_FOUND);
106                                 response->add_content("The requested resource was not found");
107                         }
108                 }
109                 catch(const exception &e)
110                 {
111                         response=new Response(INTERNAL_ERROR);
112                         response->add_content(e.what());
113                 }
114         }
115
116         if(response)
117         {
118                 cl.sock->write(response->str());
119                 cl.sock->close();
120                 cl.stale=true;
121         }
122 }
123
124 void Server::client_end_of_file(Client &cl)
125 {
126         cl.stale=true;
127 }
128
129
130 Server::Client::Client(RefPtr<Net::StreamSocket> s):
131         sock(s),
132         request(0),
133         stale(false)
134 { }
135
136 Server::Client::~Client()
137 {
138         delete request;
139 }
140
141 } // namespace Http
142 } // namespace Msp