1 #include <string.h>
2 #include <stdio.h>
3
4 #include "httpServer.h"
5 #include "logging.h"
6
HttpServer(int portNr)7 HttpServer::HttpServer(int portNr)
8 {
9 listenSocket.listen(static_cast<uint16_t>(portNr));
10 selector.add(listenSocket);
11 }
12
~HttpServer()13 HttpServer::~HttpServer()
14 {
15 listenSocket.close();
16 for(unsigned int n=0; n<connections.size(); n++)
17 delete connections[n];
18 for(unsigned int n=0; n<handlers.size(); n++)
19 delete handlers[n];
20 }
21
update(float)22 void HttpServer::update(float /*delta*/)
23 {
24 if (selector.wait(sf::microseconds(1)))
25 {
26 if (selector.isReady(listenSocket))
27 {
28 HttpServerConnection* connection = new HttpServerConnection(this);
29 if (listenSocket.accept(connection->socket) == sf::Socket::Done)
30 {
31 connections.push_back(connection);
32 selector.add(connection->socket);
33 }else{
34 delete connection;
35 }
36 }
37 for(unsigned int n=0; n<connections.size(); n++)
38 {
39 if (selector.isReady(connections[n]->socket))
40 {
41 if (!connections[n]->read())
42 {
43 selector.remove(connections[n]->socket);
44 delete connections[n];
45 connections.erase(connections.begin() + n);
46 }
47 }
48 }
49 }
50 }
51
HttpServerConnection(HttpServer * server)52 HttpServerConnection::HttpServerConnection(HttpServer* server)
53 : server(server)
54 {
55 recvBufferCount = 0;
56 status = METHOD;
57 }
58
read()59 bool HttpServerConnection::read()
60 {
61 char buffer[1024];
62 size_t size;
63 if (socket.receive(buffer, sizeof(buffer), size) != sf::Socket::Done)
64 return false;
65 if (recvBufferCount + size > recvBufferSize)
66 size = recvBufferSize - recvBufferCount;
67 if (size < 1)
68 return false;
69 memcpy(recvBuffer + recvBufferCount, buffer, size);
70 recvBufferCount += size;
71
72 while(true)
73 {
74 char* ptr = (char*)memchr(recvBuffer, '\n', recvBufferCount);
75 if (!ptr)
76 break;
77 *ptr = '\0';
78 string line(recvBuffer);
79 ptr++;
80 size_t len = ptr - recvBuffer;
81 recvBufferCount -= len;
82 memmove(recvBuffer, ptr, recvBufferCount);
83 if (line.endswith("\r"))
84 line = line.substr(0, -1);
85 if (!handleLine(line))
86 return false;
87 }
88 return true;
89 }
90
91 /** \brief Decode a percent-encoded URI
92 * Uri decoding according to RFC1630, RFC1738, RFC2396
93 * Credits: Jin Qing
94 * \param sSrc const string& Percent-encoded URI
95 * \return string Decoded URI-string
96 *
97 */
UriDecode(const string & sSrc)98 string HttpServerConnection::UriDecode(const string & sSrc)
99 {
100 // Note from RFC1630: "Sequences which start with a percent
101 // sign but are not followed by two hexadecimal characters
102 // (0-9, A-F) are reserved for future extension"
103
104 const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
105 const size_t SRC_LEN = sSrc.length();
106 const unsigned char * const SRC_END = pSrc + SRC_LEN;
107 // last decodable '%'
108 const unsigned char * const SRC_LAST_DEC = SRC_END - 2;
109
110 char * const pStart = new char[SRC_LEN];
111 char * pEnd = pStart;
112
113 while (pSrc < SRC_LAST_DEC)
114 {
115 if (*pSrc == '%')
116 {
117 char dec1, dec2;
118 if (-1 != (dec1 = HEX2DEC[*(pSrc + 1)])
119 && -1 != (dec2 = HEX2DEC[*(pSrc + 2)]))
120 {
121 *pEnd++ = (dec1 << 4) + dec2;
122 pSrc += 3;
123 continue;
124 }
125 }
126
127 *pEnd++ = *pSrc++;
128 }
129
130 // the last 2- chars
131 while (pSrc < SRC_END)
132 *pEnd++ = *pSrc++;
133
134 std::string sResult(pStart, pEnd);
135 delete [] pStart;
136 return (string) sResult;
137 }
138
139
140 /**< Map to convert between character encodings */
141 const signed char HttpServerConnection::HEX2DEC[256] =
142 {
143 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
144 /* 0 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
145 /* 1 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
146 /* 2 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
147 /* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
148
149 /* 4 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
150 /* 5 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
151 /* 6 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
152 /* 7 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
153
154 /* 8 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
155 /* 9 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
156 /* A */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
157 /* B */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
158
159 /* C */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
160 /* D */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
161 /* E */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
162 /* F */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
163 };
164
165
166 /** \brief Parse a URL, splitting it in its part and optional parameters
167 *
168 * \param sSrc const string& URL
169 * \return void
170 *
171 */
parseUri(const string & sSrc)172 void HttpServerConnection::parseUri(const string & sSrc)
173 {
174 string uri = UriDecode(sSrc);
175 std::size_t found = uri.find('?');
176 if (found==std::string::npos)
177 {
178 request.path = uri;
179 return;
180 }
181 else
182 {
183 std::vector<string> parts = uri.split("?", 1);
184 request.path = parts[0];
185
186 std::vector<string> parameters;
187 if (parts.size()>1)
188 {
189 parameters = parts[1].split("&");
190 }
191 for (unsigned int n=0; n<parameters.size(); n++)
192 {
193 string param = parameters[n];
194 found = param.find('=');
195 if (found==std::string::npos)
196 {
197 request.parameters[param] = "";
198 LOG(DEBUG) << "HTTP Parameter: " << param;
199 }
200 else
201 {
202 if (param.endswith('='))
203 {
204 auto param_end = static_cast<int>(param.length()) - 1;
205 auto param_key = param.substr(0, param_end);
206 request.parameters[param_key] = "";
207 LOG(DEBUG) << "HTTP Parameter: " << param_key;
208 }
209 else
210 {
211 std::vector<string> items = param.split("=", 1);
212 request.parameters[items[0]] = items[1];
213 LOG(DEBUG) << "HTTP Parameter: " << items[0] << " = " << items[1];
214 }
215 }
216 }
217 }
218 LOG(DEBUG) << "HTTP Path: " << request.path;
219 }
220
handleLine(string line)221 bool HttpServerConnection::handleLine(string line)
222 {
223 switch(status)
224 {
225 case METHOD:{
226 std::vector<string> parts = line.split();
227 if (parts.size() != 3)
228 return false;
229 request.method = parts[0];
230 parseUri(parts[1]);
231 status = HEADERS;
232 }break;
233 case HEADERS:
234 if (line.length() == 0)
235 {
236 request.post_data = "";
237 if (request.method == "POST")
238 {
239 if (request.headers.find("content-length") != request.headers.end())
240 {
241 unsigned int body_length = request.headers["content-length"].toInt();
242 if (body_length > recvBufferSize)
243 return false;
244 while (body_length > recvBufferCount)
245 {
246 size_t received;
247 if (socket.receive(recvBuffer + recvBufferCount, body_length - recvBufferCount, received) != sf::Socket::Done)
248 return false;
249 recvBufferCount += received;
250 }
251 request.post_data = string(recvBuffer, body_length);
252 recvBufferCount -= body_length;
253 memmove(recvBuffer, recvBuffer + body_length, recvBufferCount);
254 }
255 }
256 status = METHOD;
257 #ifdef DEBUG
258 for (std::unordered_map<string, string>::iterator iter = request.headers.begin(); iter != request.headers.end(); iter++)
259 {
260 string key=iter->first;
261 string value=iter->second;
262 LOG(DEBUG) << "HTTP header: (" << key << ", " << value << ")";
263 }
264 #endif // DEBUG
265 handleRequest();
266 }else{
267 std::vector<string> parts = line.split(":", 1);
268 if (parts.size() != 2)
269 LOG(WARNING) << "Invalid HTTP header: " << line;
270 else
271 request.headers[parts[0].strip().lower()] = parts[1];
272 }
273 break;
274 }
275 return true;
276 }
277
handleRequest()278 void HttpServerConnection::handleRequest()
279 {
280 reply_code = 200;
281 headers_send = false;
282
283 for(unsigned int n=0; n<server->handlers.size(); n++)
284 {
285 if (server->handlers[n]->handleRequest(request, this))
286 break;
287 if (headers_send)
288 break;
289 }
290
291 if (!headers_send)
292 {
293 reply_code = 404;
294 string replyData = "File not found";
295 sendData(replyData.c_str(), replyData.size());
296 }
297 string end_chunk = "0\r\n\r\n";
298 socket.send(end_chunk.c_str(), end_chunk.size());
299 request.parameters.clear();
300 }
301
sendHeaders()302 void HttpServerConnection::sendHeaders()
303 {
304 string reply = string("HTTP/1.1 ") + string(reply_code) + " OK\r\n";
305 reply += "Content-type: text/html\r\n";
306 reply += "Connection: Keep-Alive\r\n";
307 reply += "Transfer-Encoding: chunked\r\n";
308 reply += "\r\n";
309 socket.send(reply.c_str(), reply.size());
310 headers_send = true;
311 }
312
sendData(const char * data,size_t data_length)313 void HttpServerConnection::sendData(const char* data, size_t data_length)
314 {
315 if (!headers_send)
316 sendHeaders();
317 if (data_length < 1)
318 return;
319 string chunk_len_string = string::hex(static_cast<int>(data_length)) + "\r\n";
320 socket.send(chunk_len_string.c_str(), chunk_len_string.size());
321 socket.send(data, data_length);
322 socket.send("\r\n", 2);
323 }
324
handleRequest(HttpRequest & request,HttpServerConnection * connection)325 bool HttpRequestFileHandler::handleRequest(HttpRequest& request, HttpServerConnection* connection)
326 {
327 string replyData = "";
328 FILE* f = NULL;
329 if (request.path == "/")
330 request.path = "/index.html";
331 if (request.path.find("..") != -1)
332 return false;
333
334 string fullPath = base_path + request.path;
335 f = fopen(fullPath.c_str(), "rb");
336 if (!f)
337 return false;
338
339 while(true)
340 {
341 char buffer[1024];
342 size_t n = fread(buffer, 1, sizeof(buffer), f);
343 if (n < 1)
344 break;
345 connection->sendData(buffer, n);
346 }
347 fclose(f);
348 return true;
349 }
350