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