]> git.tdb.fi Git - libs/net.git/blob - source/server.cpp
Drop Id tags and copyright notices from source files
[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.sock->close();
59                 cl.stale = true;
60         }
61 }
62
63 void Server::data_available()
64 {
65         Net::StreamSocket *csock = sock.accept();
66         clients.push_back(Client(csock));
67         csock->signal_data_available.connect(sigc::bind(sigc::mem_fun(this, &Server::client_data_available), sigc::ref(clients.back())));
68         csock->signal_end_of_file.connect(sigc::bind(sigc::mem_fun(this, &Server::client_end_of_file), sigc::ref(clients.back())));
69         if(event_disp)
70                 event_disp->add(*csock);
71 }
72
73 void Server::client_data_available(Client &cl)
74 {
75         for(list<Client>::iterator i=clients.begin(); i!=clients.end(); ++i)
76                 if(i->stale && &*i!=&cl)
77                 {
78                         clients.erase(i);
79                         break;
80                 }
81
82         char rbuf[4096];
83         unsigned len = cl.sock->read(rbuf, sizeof(rbuf));
84         cl.in_buf.append(rbuf, len);
85
86         RefPtr<Response> response;
87         if(!cl.request)
88         {
89                 if(cl.in_buf.find("\r\n\r\n")!=string::npos || cl.in_buf.find("\n\n")!=string::npos)
90                 {
91                         try
92                         {
93                                 cl.request = new Request(Request::parse(cl.in_buf));
94
95                                 string addr_str = cl.sock->get_peer_address().str();
96                                 unsigned colon = addr_str.find(':');
97                                 cl.request->set_header("-Client-Host", addr_str.substr(0, colon));
98
99                                 if(cl.request->get_method()!="GET" && cl.request->get_method()!="POST")
100                                 {
101                                         response = new Response(NOT_IMPLEMENTED);
102                                         response->add_content("Method not implemented");
103                                 }
104                         }
105                         catch(const exception &e)
106                         {
107                                 response = new Response(BAD_REQUEST);
108                                 response->add_content(e.what());
109                         }
110                         cl.in_buf = string();
111                 }
112         }
113         else
114         {
115                 len = cl.request->parse_content(cl.in_buf);
116                 cl.in_buf.erase(0, len);
117         }
118
119         if(cl.request && cl.request->is_complete() && !response)
120         {
121                 response = new Response(NONE);
122                 try
123                 {
124                         cl.response = response.get();
125                         signal_request.emit(*cl.request, *response);
126                         if(cl.async)
127                                 response.release();
128                         else
129                         {
130                                 cl.response = 0;
131                                 if(response->get_status()==NONE)
132                                 {
133                                         response = new Response(NOT_FOUND);
134                                         response->add_content("The requested resource was not found");
135                                 }
136                         }
137                 }
138                 catch(const exception &e)
139                 {
140                         cl.response = 0;
141                         response = new Response(INTERNAL_ERROR);
142                         response->add_content(e.what());
143                 }
144         }
145
146         if(response)
147         {
148                 cl.sock->write(response->str());
149                 cl.sock->close();
150                 cl.stale = true;
151         }
152 }
153
154 void Server::client_end_of_file(Client &cl)
155 {
156         cl.stale = true;
157 }
158
159 Server::Client &Server::get_client_by_response(Response &resp)
160 {
161         for(list<Client>::iterator i=clients.begin(); i!=clients.end(); ++i)
162                 if(i->response==&resp)
163                         return *i;
164
165         throw InvalidParameterValue("Response does not belong to any client");
166 }
167
168
169 Server::Client::Client(RefPtr<Net::StreamSocket> s):
170         sock(s),
171         request(0),
172         response(0),
173         async(false),
174         stale(false)
175 { }
176
177 Server::Client::~Client()
178 {
179         delete request;
180         delete response;
181 }
182
183 } // namespace Http
184 } // namespace Msp