]> git.tdb.fi Git - libs/net.git/blob - source/server.cpp
Use maputils.h
[libs/net.git] / source / server.cpp
1 #include <exception>
2 #include <msp/core/refptr.h>
3 #include <msp/net/inet.h>
4 #include <msp/net/streamsocket.h>
5 #include "request.h"
6 #include "response.h"
7 #include "server.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace Http {
13
14 Server::Server(unsigned port):
15         sock(Net::INET),
16         event_disp(0)
17 {
18         sock.signal_data_available.connect(sigc::mem_fun(this, &Server::data_available));
19         sock.listen(Net::InetAddr(0, port), 8);
20 }
21
22 unsigned Server::get_port() const
23 {
24         const Net::SockAddr &addr = sock.get_local_address();
25         if(addr.get_family()==Net::INET)
26                 return static_cast<const Net::InetAddr &>(addr).get_port();
27         return 0;
28 }
29
30 void Server::use_event_dispatcher(IO::EventDispatcher *ed)
31 {
32         if(event_disp)
33         {
34                 event_disp->remove(sock);
35                 for(list<Client>::iterator i=clients.begin(); i!=clients.end(); ++i)
36                         event_disp->remove(*i->sock);
37         }
38         event_disp = ed;
39         if(event_disp)
40         {
41                 event_disp->add(sock);
42                 for(list<Client>::iterator i=clients.begin(); i!=clients.end(); ++i)
43                         event_disp->add(*i->sock);
44         }
45 }
46
47 void Server::delay_response(Response &resp)
48 {
49         get_client_by_response(resp).async = true;
50 }
51
52 void Server::submit_response(Response &resp)
53 {
54         Client &cl = get_client_by_response(resp);
55         if(cl.async)
56         {
57                 cl.sock->write(resp.str());
58                 cl.stale = true;
59         }
60 }
61
62 void Server::data_available()
63 {
64         Net::StreamSocket *csock = sock.accept();
65         clients.push_back(Client(csock));
66         csock->signal_data_available.connect(sigc::bind(sigc::mem_fun(this, &Server::client_data_available), sigc::ref(clients.back())));
67         csock->signal_end_of_file.connect(sigc::bind(sigc::mem_fun(this, &Server::client_end_of_file), sigc::ref(clients.back())));
68         if(event_disp)
69                 event_disp->add(*csock);
70 }
71
72 void Server::client_data_available(Client &cl)
73 {
74         for(list<Client>::iterator i=clients.begin(); i!=clients.end(); ++i)
75                 if(i->stale && &*i!=&cl)
76                 {
77                         clients.erase(i);
78                         break;
79                 }
80
81         char rbuf[4096];
82         unsigned len = cl.sock->read(rbuf, sizeof(rbuf));
83         cl.in_buf.append(rbuf, len);
84
85         RefPtr<Response> response;
86         if(!cl.request)
87         {
88                 if(cl.in_buf.find("\r\n\r\n")!=string::npos || cl.in_buf.find("\n\n")!=string::npos)
89                 {
90                         try
91                         {
92                                 cl.request = new Request(Request::parse(cl.in_buf));
93
94                                 string addr_str = cl.sock->get_peer_address().str();
95                                 unsigned colon = addr_str.find(':');
96                                 cl.request->set_header("-Client-Host", addr_str.substr(0, colon));
97
98                                 if(cl.request->get_method()!="GET" && cl.request->get_method()!="POST")
99                                 {
100                                         response = new Response(NOT_IMPLEMENTED);
101                                         response->add_content("Method not implemented\n");
102                                 }
103                         }
104                         catch(const exception &e)
105                         {
106                                 response = new Response(BAD_REQUEST);
107                                 response->add_content(e.what());
108                         }
109                         cl.in_buf = string();
110                 }
111         }
112         else
113         {
114                 len = cl.request->parse_content(cl.in_buf);
115                 cl.in_buf.erase(0, len);
116         }
117
118         if(cl.request && cl.request->is_complete() && !response)
119         {
120                 response = new Response(NONE);
121                 try
122                 {
123                         cl.response = response.get();
124                         signal_request.emit(*cl.request, *response);
125                         if(cl.async)
126                                 response.release();
127                         else
128                         {
129                                 cl.response = 0;
130                                 if(response->get_status()==NONE)
131                                 {
132                                         response = new Response(NOT_FOUND);
133                                         response->add_content("The requested resource was not found\n");
134                                 }
135                         }
136                 }
137                 catch(const exception &e)
138                 {
139                         cl.response = 0;
140                         response = new Response(INTERNAL_ERROR);
141                         response->add_content(e.what());
142                 }
143         }
144
145         if(response)
146         {
147                 cl.sock->write(response->str());
148                 cl.stale = true;
149         }
150 }
151
152 void Server::client_end_of_file(Client &cl)
153 {
154         cl.stale = true;
155 }
156
157 Server::Client &Server::get_client_by_response(Response &resp)
158 {
159         for(list<Client>::iterator i=clients.begin(); i!=clients.end(); ++i)
160                 if(i->response==&resp)
161                         return *i;
162
163         // XXX Do this differently
164         throw invalid_argument("Response does not belong to any client");
165 }
166
167
168 Server::Client::Client(RefPtr<Net::StreamSocket> s):
169         sock(s),
170         request(0),
171         response(0),
172         async(false),
173         stale(false)
174 { }
175
176 Server::Client::~Client()
177 {
178         delete request;
179         delete response;
180 }
181
182 } // namespace Http
183 } // namespace Msp