]> andersk Git - test.git/blob - libhttp/httpconnection.c
ad391fa93b304d62dd46be1eadbf18b1783d75b3
[test.git] / libhttp / httpconnection.c
1 // httpconnection.c -- Manage state machine for HTTP connections
2 // Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com>
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License version 2 as
6 // published by the Free Software Foundation.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License along
14 // with this program; if not, write to the Free Software Foundation, Inc.,
15 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 //
17 // In addition to these license terms, the author grants the following
18 // additional rights:
19 //
20 // If you modify this program, or any covered work, by linking or
21 // combining it with the OpenSSL project's OpenSSL library (or a
22 // modified version of that library), containing parts covered by the
23 // terms of the OpenSSL or SSLeay licenses, the author
24 // grants you additional permission to convey the resulting work.
25 // Corresponding Source for a non-source form of such a combination
26 // shall include the source code for the parts of OpenSSL used as well
27 // as that of the covered work.
28 //
29 // You may at your option choose to remove this additional permission from
30 // the work, or from any part of it.
31 //
32 // It is possible to build this program in a way that it loads OpenSSL
33 // libraries at run-time. If doing so, the following notices are required
34 // by the OpenSSL and SSLeay licenses:
35 //
36 // This product includes software developed by the OpenSSL Project
37 // for use in the OpenSSL Toolkit. (http://www.openssl.org/)
38 //
39 // This product includes cryptographic software written by Eric Young
40 // (eay@cryptsoft.com)
41 //
42 //
43 // The most up-to-date version of this program is always available from
44 // http://shellinabox.com
45
46 #define _GNU_SOURCE
47 #include "config.h"
48
49 #include <errno.h>
50 #include <arpa/inet.h>
51 #include <math.h>
52 #include <netdb.h>
53 #include <netinet/in.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <sys/poll.h>
58 #include <sys/socket.h>
59 #include <sys/types.h>
60 #include <unistd.h>
61
62 #ifdef HAVE_ZLIB
63 #include <zlib.h>
64 #endif
65
66 #ifdef HAVE_STRLCAT
67 #define strncat(a,b,c) ({ char *_a = (a); strlcat(_a, (b), (c)+1); _a; })
68 #endif
69 #ifndef HAVE_ISNAN
70 #define isnan(x) ({ typeof(x) _x = (x); _x != _x; })
71 #endif
72 #define max(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b);                  \
73                      _a > _b ? _a : _b; })
74
75 #include "libhttp/httpconnection.h"
76 #include "logging/logging.h"
77
78 #define MAX_HEADER_LENGTH   (64<<10)
79 #define CONNECTION_TIMEOUT  (10*60)
80
81 static int httpPromoteToSSL(struct HttpConnection *http, const char *buf,
82                             int len) {
83   if (http->ssl->enabled && !http->sslHndl) {
84     debug("Switching to SSL (replaying %d+%d bytes)",
85           http->partialLength, len);
86     if (http->partial && len > 0) {
87       check(http->partial  = realloc(http->partial,
88                                      http->partialLength + len));
89       memcpy(http->partial + http->partialLength, buf, len);
90       http->partialLength += len;
91     }
92     int rc                 = sslPromoteToSSL(
93                                     http->ssl, &http->sslHndl, http->fd,
94                                     http->partial ? http->partial : buf,
95                                     http->partial ? http->partialLength : len);
96     if (http->sslHndl) {
97       check(!rc);
98       SSL_set_app_data(http->sslHndl, http);
99     }
100     free(http->partial);
101     http->partialLength    = 0;
102     return rc;
103   } else {
104     errno                  = EINVAL;
105     return -1;
106   }
107 }
108
109 static ssize_t httpRead(struct HttpConnection *http, char *buf, ssize_t len) {
110   sslBlockSigPipe();
111   int rc;
112   if (http->sslHndl) {
113     dcheck(!ERR_peek_error());
114     rc                        = SSL_read(http->sslHndl, buf, len);
115     switch (rc) {
116     case 0:
117     case -1:
118       switch (http->lastError = SSL_get_error(http->sslHndl, rc)) {
119       case SSL_ERROR_WANT_READ:
120       case SSL_ERROR_WANT_WRITE:
121         errno                 = EAGAIN;
122         rc                    = -1;
123         break;
124       default:
125         errno                 = EINVAL;
126         break;
127       }
128       ERR_clear_error();
129       break;
130     default:
131       break;
132     }
133     dcheck(!ERR_peek_error());
134   } else {
135     rc = NOINTR(read(http->fd, buf, len));
136   }
137   sslUnblockSigPipe();
138   if (rc > 0) {
139     serverSetTimeout(httpGetServerConnection(http), CONNECTION_TIMEOUT);
140   }
141   return rc;
142 }
143
144 static ssize_t httpWrite(struct HttpConnection *http, const char *buf,
145                          ssize_t len) {
146   sslBlockSigPipe();
147   int rc;
148   if (http->sslHndl) {
149     dcheck(!ERR_peek_error());
150     rc                        = SSL_write(http->sslHndl, buf, len);
151     switch (rc) {
152     case 0:
153     case -1:
154       switch (http->lastError = SSL_get_error(http->sslHndl, rc)) {
155       case SSL_ERROR_WANT_READ:
156       case SSL_ERROR_WANT_WRITE:
157         errno                 = EAGAIN;
158         rc                    = -1;
159         break;
160       default:
161         errno                 = EINVAL;
162         break;
163       }
164       ERR_clear_error();
165       break;
166     default:
167       break;
168     }
169     dcheck(!ERR_peek_error());
170   } else {
171     rc = NOINTR(write(http->fd, buf, len));
172   }
173   sslUnblockSigPipe();
174   return rc;
175 }
176
177 static int httpShutdown(struct HttpConnection *http, int how) {
178   if (http->sslHndl) {
179     int rc        = 0;
180     if (how != SHUT_RD) {
181       dcheck(!ERR_peek_error());
182       for (int i = 0; i < 10; i++) {
183         sslBlockSigPipe();
184         rc        = SSL_shutdown(http->sslHndl);
185         int sPipe = sslUnblockSigPipe();
186         if (rc > 0) {
187           rc      = 0;
188           break;
189         } else {
190           rc      = -1;
191           // Retry a few times in order to prefer a clean bidirectional
192           // shutdown. But don't bother if the other side already closed
193           // the connection.
194           if (sPipe) {
195             break;
196           }
197         }
198       }
199       sslFreeHndl(&http->sslHndl);
200     }
201   }
202   return shutdown(http->fd, how);
203 }
204
205 static void httpCloseRead(struct HttpConnection *http) {
206   if (!http->closed) {
207     httpShutdown(http, SHUT_RD);
208     http->closed = 1;
209   }
210 }
211
212 #ifndef HAVE_STRCASESTR
213 static char *strcasestr(const char *haystack, const char *needle) {
214   // This algorithm is O(len(haystack)*len(needle)). Much better algorithms
215   // are available, but this code is much simpler and performance is not
216   // critical for our workloads.
217   int len = strlen(needle);
218   do {
219     if (!strncasecmp(haystack, needle, len)) {
220       return haystack;
221     }
222   } while (*haystack++);
223   return NULL;
224 }
225 #endif
226
227 static int httpFinishCommand(struct HttpConnection *http) {
228   int rc            = HTTP_DONE;
229   if ((http->callback || http->websocketHandler) && !http->done) {
230     rc              = http->callback ? http->callback(http, http->arg, NULL, 0)
231        : http->websocketHandler(http, http->arg, WS_CONNECTION_CLOSED, NULL,0);
232     check(rc != HTTP_SUSPEND);
233     check(rc != HTTP_PARTIAL_REPLY);
234     http->callback  = NULL;
235     http->arg       = NULL;
236     if (rc == HTTP_ERROR) {
237       httpCloseRead(http);
238     }
239   }
240   if (!http->closed) {
241     const char *con = getFromHashMap(&http->header, "connection");
242     if ((con && strcasestr(con, "close")) ||
243         !http->version || strcmp(http->version, "HTTP/1.1") < 0) {
244       httpCloseRead(http);
245     }
246   }
247   if (logIsInfo()) {
248     check(http->method);
249     check(http->path);
250     check(http->version);
251     if (http->peerName) {
252       time_t t      = currentTime;
253       struct tm *ltime;
254       check (ltime  = localtime(&t));
255       char timeBuf[80];
256       char lengthBuf[40];
257       check(strftime(timeBuf, sizeof(timeBuf),
258                      "[%d/%b/%Y:%H:%M:%S %z]", ltime));
259       if (http->totalWritten > 0) {
260         snprintf(lengthBuf, sizeof(lengthBuf), "%d", http->totalWritten);
261       } else {
262         *lengthBuf  = '\000';
263         strncat(lengthBuf, "-", sizeof(lengthBuf)-1);
264       }
265       info("%s - - %s \"%s %s %s\" %d %s",
266            http->peerName, timeBuf, http->method, http->path, http->version,
267            http->code, lengthBuf);
268     }
269   }
270   return rc;
271 }
272
273 static void httpDestroyHeaders(void *arg, char *key, char *value) {
274   (void)arg;
275   free(key);
276   free(value);
277 }
278
279 static char *getPeerName(int fd, int *port, int numericHosts) {
280   struct sockaddr peerAddr;
281   socklen_t sockLen = sizeof(peerAddr);
282   if (getpeername(fd, &peerAddr, &sockLen)) {
283     if (port) {
284       *port         = -1;
285     }
286     return NULL;
287   }
288   char host[256];
289   if (numericHosts ||
290       getnameinfo(&peerAddr, sockLen, host, sizeof(host), NULL, 0, NI_NOFQDN)){
291     check(inet_ntop(peerAddr.sa_family,
292                     &((struct sockaddr_in *)&peerAddr)->sin_addr,
293                     host, sizeof(host)));
294   }
295   if (port) {
296     *port           = ntohs(((struct sockaddr_in *)&peerAddr)->sin_port);
297   }
298   char *ret;
299   check(ret         = strdup(host));
300   return ret;
301 }
302
303 static void httpSetState(struct HttpConnection *http, int state) {
304   if (state == (int)http->state) {
305     return;
306   }
307
308   if (state == COMMAND) {
309     if (http->state != SNIFFING_SSL) {
310       int rc                 = httpFinishCommand(http);
311       check(rc != HTTP_SUSPEND);
312       check(rc != HTTP_PARTIAL_REPLY);
313     }
314     check(!http->private);
315     free(http->url);
316     free(http->method);
317     free(http->path);
318     free(http->matchedPath);
319     free(http->pathInfo);
320     free(http->query);
321     free(http->version);
322     http->done               = 0;
323     http->url                = NULL;
324     http->method             = NULL;
325     http->path               = NULL;
326     http->matchedPath        = NULL;
327     http->pathInfo           = NULL;
328     http->query              = NULL;
329     http->version            = NULL;
330     destroyHashMap(&http->header);
331     initHashMap(&http->header, httpDestroyHeaders, NULL);
332     http->headerLength       = 0;
333     http->callback           = NULL;
334     http->arg                = NULL;
335     http->totalWritten       = 0;
336     http->code               = 200;
337   }
338   http->state                = state;
339 }
340
341 struct HttpConnection *newHttpConnection(struct Server *server, int fd,
342                                          int port, struct SSLSupport *ssl,
343                                          int numericHosts) {
344   struct HttpConnection *http;
345   check(http = malloc(sizeof(struct HttpConnection)));
346   initHttpConnection(http, server, fd, port, ssl, numericHosts);
347   return http;
348 }
349
350 void initHttpConnection(struct HttpConnection *http, struct Server *server,
351                         int fd, int port, struct SSLSupport *ssl,
352                         int numericHosts) {
353   http->server             = server;
354   http->connection         = NULL;
355   http->fd                 = fd;
356   http->port               = port;
357   http->closed             = 0;
358   http->isSuspended        = 0;
359   http->isPartialReply     = 0;
360   http->done               = 0;
361   http->state              = ssl ? SNIFFING_SSL : COMMAND;
362   http->peerName           = getPeerName(fd, &http->peerPort, numericHosts);
363   http->url                = NULL;
364   http->method             = NULL;
365   http->path               = NULL;
366   http->matchedPath        = NULL;
367   http->pathInfo           = NULL;
368   http->query              = NULL;
369   http->version            = NULL;
370   initHashMap(&http->header, httpDestroyHeaders, NULL);
371   http->headerLength       = 0;
372   http->key                = NULL;
373   http->partial            = NULL;
374   http->partialLength      = 0;
375   http->msg                = NULL;
376   http->msgLength          = 0;
377   http->msgOffset          = 0;
378   http->totalWritten       = 0;
379   http->expecting          = 0;
380   http->websocketType      = WS_UNDEFINED;
381   http->callback           = NULL;
382   http->websocketHandler   = NULL;
383   http->arg                = NULL;
384   http->private            = NULL;
385   http->code               = 200;
386   http->ssl                = ssl;
387   http->sslHndl            = NULL;
388   http->lastError          = 0;
389   if (logIsInfo()) {
390     debug("Accepted connection from %s:%d",
391           http->peerName ? http->peerName : "???", http->peerPort);
392   }
393 }
394
395 void destroyHttpConnection(struct HttpConnection *http) {
396   if (http) {
397     if (http->isSuspended || http->isPartialReply) {
398       if (!http->done) {
399         if (http->callback) {
400           http->callback(http, http->arg, NULL, 0);
401         } else if (http->websocketHandler) {
402           http->websocketHandler(http, http->arg, WS_CONNECTION_CLOSED,NULL,0);
403         }
404       }
405       http->callback       = NULL;
406       http->isSuspended    = 0;
407       http->isPartialReply = 0;
408     }
409     httpSetState(http, COMMAND);
410     if (logIsInfo()) {
411       debug("Closing connection to %s:%d",
412             http->peerName ? http->peerName : "???", http->peerPort);
413     }
414     httpShutdown(http, http->closed ? SHUT_WR : SHUT_RDWR);
415     dcheck(!close(http->fd));
416     free(http->peerName);
417     free(http->url);
418     free(http->method);
419     free(http->path);
420     free(http->matchedPath);
421     free(http->pathInfo);
422     free(http->query);
423     free(http->version);
424     destroyHashMap(&http->header);
425     free(http->partial);
426     free(http->msg);
427   }
428 }
429
430 void deleteHttpConnection(struct HttpConnection *http) {
431   destroyHttpConnection(http);
432   free(http);
433 }
434
435 #ifdef HAVE_ZLIB
436 static int httpAcceptsEncoding(struct HttpConnection *http,
437                                const char *encoding) {
438   int encodingLength  = strlen(encoding);
439   const char *accepts = getFromHashMap(&http->header, "accept-encoding");
440   if (!accepts) {
441     return 0;
442   }
443   double all          = -1.0;
444   double match        = -1.0;
445   while (*accepts) {
446     while (*accepts == ' ' || *accepts == '\t' ||
447            *accepts == '\r' || *accepts == '\n') {
448       accepts++;
449     }
450     const char *ptr   = accepts;
451     while (*ptr && *ptr != ',' && *ptr != ';' &&
452            *ptr != ' ' && *ptr != '\t' &&
453            *ptr != '\r' && *ptr != '\n') {
454       ptr++;
455     }
456     int isAll         = ptr - accepts == 1 && *accepts == '*';
457     int isMatch       = ptr - accepts == encodingLength &&
458                         !strncasecmp(accepts, encoding, encodingLength);
459     while (*ptr && *ptr != ';' && *ptr != ',') {
460       ptr++;
461     }
462     double val        = 1.0;
463     if (*ptr == ';') {
464       ptr++;
465       while (*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n') {
466         ptr++;
467       }
468       if ((*ptr | 0x20) == 'q') {
469         ptr++;
470         while (*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n') {
471           ptr++;
472         }
473         if (*ptr == '=') {
474           val         = strtod(ptr + 1, (char **)&ptr);
475         }
476       }
477     }
478     if (isnan(val) || val == -HUGE_VAL || val < 0) {
479       val             = 0;
480     } else if (val == HUGE_VAL || val > 1.0) {
481       val             = 1.0;
482     }
483     if (isAll) {
484       all             = val;
485     } else if (isMatch) {
486       match           = val;
487     }
488     while (*ptr && *ptr != ',') {
489       ptr++;
490     }
491     while (*ptr == ',') {
492       ptr++;
493     }
494     accepts           = ptr;
495   }
496   if (match >= 0.0) {
497     return match > 0.0;
498   } else {
499     return all > 0.0;
500   }
501 }
502 #endif
503
504 static void removeHeader(char *header, int *headerLength, const char *id) {
505   check(header);
506   check(headerLength);
507   check(*headerLength >= 0);
508   check(id);
509   check(strchr(id, ':'));
510   int idLength       = strlen(id);
511   if (idLength <= 0) {
512     return;
513   }
514   for (char *ptr = header; header + *headerLength - ptr >= idLength; ) {
515     char *end        = ptr;
516     do {
517       end            = memchr(end, '\n', header + *headerLength - end);
518       if (end == NULL) {
519         end          = header + *headerLength;
520       } else {
521         ++end;
522       }
523     } while (end < header + *headerLength && *end == ' ');
524     if (!strncasecmp(ptr, id, idLength)) {
525       memmove(ptr, end, header + *headerLength - end);
526       *headerLength -= end - ptr;
527     } else {
528       ptr            = end;
529     }
530   }
531 }
532
533 static void addHeader(char **header, int *headerLength, const char *fmt, ...) {
534   check(header);
535   check(headerLength);
536   check(*headerLength >= 0);
537   check(strstr(fmt, "\r\n"));
538
539   va_list ap;
540   va_start(ap, fmt);
541   char *tmp        = vStringPrintf(NULL, fmt, ap);
542   va_end(ap);
543   int tmpLength    = strlen(tmp);
544
545   if (*headerLength >= 2 && !memcmp(*header + *headerLength - 2, "\r\n", 2)) {
546     *headerLength -= 2;
547   }
548   check(*header    = realloc(*header, *headerLength + tmpLength + 2));
549
550   memcpy(*header + *headerLength, tmp, tmpLength);
551   memcpy(*header + *headerLength + tmpLength, "\r\n", 2);
552   *headerLength   += tmpLength + 2;
553   free(tmp);
554 }
555
556 void httpTransfer(struct HttpConnection *http, char *msg, int len) {
557   check(msg);
558   check(len >= 0);
559
560   // Internet Explorer seems to have difficulties with compressed data. It
561   // also has difficulties with SSL connections that are being proxied.
562   int ieBug                 = 0;
563   const char *userAgent     = getFromHashMap(&http->header, "user-agent");
564   const char *msie          = userAgent ? strstr(userAgent, "MSIE ") : NULL;
565   if (msie) {
566     ieBug++;
567   }
568
569   char *header              = NULL;
570   int headerLength          = 0;
571   int bodyOffset            = 0;
572
573   int compress              = 0;
574   if (!http->totalWritten) {
575     // Perform some basic sanity checks. This does not necessarily catch all
576     // possible problems, though.
577     int l                   = len;
578     char *line              = msg;
579     for (char *eol, *lastLine = NULL;
580          l > 0 && (eol = memchr(line, '\n', l)) != NULL; ) {
581       // All lines end in CR LF
582       check(eol[-1] == '\r');
583       if (!lastLine) {
584         // The first line looks like "HTTP/1.x STATUS\r\n"
585         check(eol - line > 11);
586         check(!memcmp(line, "HTTP/1.", 7));
587         check(line[7] >= '0' && line[7] <= '9' &&
588               (line[8] == ' ' || line[8] == '\t'));
589         int i               = eol - line - 9;
590         for (char *ptr = line + 9; i-- > 0; ) {
591           char ch           = *ptr++;
592           if (ch < '0' || ch > '9') {
593             check(ptr > line + 10);
594             check(ch == ' ' || ch == '\t');
595             break;
596           }
597         }
598         check(i > 1);
599       } else if (line + 1 == eol) {
600         // Found the end of the headers.
601
602         // Check that we don't send any data with HEAD requests
603         int isHead          = !strcmp(http->method, "HEAD");
604         check(l == 2 || !isHead);
605
606         #ifdef HAVE_ZLIB
607         // Compress replies that might exceed the size of a single IP packet
608         compress            = !ieBug && !isHead &&
609                               !http->isPartialReply &&
610                               len > 1400 &&
611                               httpAcceptsEncoding(http, "deflate");
612         #endif
613         break;
614       } else {
615         // Header lines either contain a colon, or they are continuation
616         // lines
617         if (*line != ' ' && *line != '\t') {
618           check(memchr(line, ':', eol - line));
619         }
620       }
621       lastLine              = line;
622       l                    -= eol - line + 1;
623       line                  = eol + 1;
624     }
625
626     if (ieBug || compress) {
627       if (l >= 2 && !memcmp(line, "\r\n", 2)) {
628         line               += 2;
629         l                  -= 2;
630       }
631       headerLength          = line - msg;
632       bodyOffset            = headerLength;
633       check(header          = malloc(headerLength));
634       memcpy(header, msg, headerLength);
635     }
636     if (ieBug) {
637       removeHeader(header, &headerLength, "connection:");
638       addHeader(&header, &headerLength, "Connection: close\r\n");
639     }
640
641     if (compress) {
642       #ifdef HAVE_ZLIB
643       // Compress the message
644       char *compressed;
645       check(compressed      = malloc(len));
646       check(len >= bodyOffset + 2);
647       z_stream strm         = { .zalloc    = Z_NULL,
648                                 .zfree     = Z_NULL,
649                                 .opaque    = Z_NULL,
650                                 .avail_in  = l,
651                                 .next_in   = (unsigned char *)line,
652                                 .avail_out = len,
653                                 .next_out  = (unsigned char *)compressed
654                               };
655       if (deflateInit(&strm, Z_DEFAULT_COMPRESSION) == Z_OK) {
656         if (deflate(&strm, Z_FINISH) == Z_STREAM_END) {
657           // Compression was successful and resulted in reduction in size
658           debug("Compressed response from %d to %d", len, len-strm.avail_out);
659           free(msg);
660           msg               = compressed;
661           len              -= strm.avail_out;
662           bodyOffset        = 0;
663           removeHeader(header, &headerLength, "content-length:");
664           removeHeader(header, &headerLength, "content-encoding:");
665           addHeader(&header, &headerLength, "Content-Length: %d\r\n", len);
666           addHeader(&header, &headerLength, "Content-Encoding: deflate\r\n");
667         } else {
668           free(compressed);
669         }
670         deflateEnd(&strm);
671       } else {
672         free(compressed);
673       }
674       #endif
675     }
676   }
677
678   http->totalWritten       += headerLength + (len - bodyOffset);
679   if (!headerLength) {
680     free(header);
681   } else if (http->msg) {
682     check(http->msg         = realloc(http->msg,
683                                       http->msgLength - http->msgOffset +
684                                       max(http->msgOffset, headerLength)));
685     if (http->msgOffset) {
686       memmove(http->msg, http->msg + http->msgOffset,
687               http->msgLength - http->msgOffset);
688       http->msgLength      -= http->msgOffset;
689       http->msgOffset       = 0;
690     }
691     memcpy(http->msg + http->msgLength, header, headerLength);
692     http->msgLength        += headerLength;
693     free(header);
694   } else {
695     check(!http->msgOffset);
696     http->msg               = header;
697     http->msgLength         = headerLength;
698   }
699
700   if (len <= bodyOffset) {
701     free(msg);
702   } else if (http->msg) {
703     check(http->msg         = realloc(http->msg,
704                                       http->msgLength - http->msgOffset +
705                                       max(http->msgOffset, len - bodyOffset)));
706     if (http->msgOffset) {
707       memmove(http->msg, http->msg + http->msgOffset,
708               http->msgLength - http->msgOffset);
709       http->msgLength      -= http->msgOffset;
710       http->msgOffset       = 0;
711     }
712     memcpy(http->msg + http->msgLength, msg + bodyOffset, len - bodyOffset);
713     http->msgLength        += len - bodyOffset;
714     free(msg);
715   } else {
716     check(!http->msgOffset);
717     if (bodyOffset) {
718       memmove(msg, msg + bodyOffset, len - bodyOffset);
719     }
720     http->msg               = msg;
721     http->msgLength         = len - bodyOffset;
722   }
723
724   // The caller can suspend the connection, so that it can send an
725   // asynchronous reply. Once the reply has been sent, the connection
726   // gets reactivated. Normally, this means it would go back to listening
727   // for commands.
728   // Similarly, the caller can indicate that this is a partial message and
729   // return additional data in subsequent calls to the callback handler.
730   if (http->isSuspended || http->isPartialReply) {
731     if (http->msg && http->msgLength > 0) {
732       int wrote             = httpWrite(http, http->msg, http->msgLength);
733       if (wrote < 0 && errno != EAGAIN) {
734         httpCloseRead(http);
735         free(http->msg);
736         http->msgLength     = 0;
737         http->msg           = NULL;
738       } else if (wrote > 0) {
739         if (wrote == http->msgLength) {
740           free(http->msg);
741           http->msgLength   = 0;
742           http->msg         = NULL;
743         } else {
744           memmove(http->msg, http->msg + wrote, http->msgLength - wrote);
745           http->msgLength  -= wrote;
746         }
747       }
748     }
749
750     check(http->state == PAYLOAD || http->state == DISCARD_PAYLOAD);
751     if (!http->isPartialReply) {
752       if (http->expecting < 0) {
753         // If we do not know the length of the content, close the connection.
754         debug("Closing previously suspended connection");
755         httpCloseRead(http);
756         httpSetState(http, DISCARD_PAYLOAD);
757       } else if (http->expecting == 0) {
758         httpSetState(http, COMMAND);
759         http->isSuspended  = 0;
760         struct ServerConnection *connection = httpGetServerConnection(http);
761         if (!serverGetTimeout(connection)) {
762           serverSetTimeout(connection, CONNECTION_TIMEOUT);
763         }
764         serverConnectionSetEvents(http->server, connection,
765                                   http->msgLength ? POLLIN|POLLOUT : POLLIN);
766       }
767     }
768   }
769
770   if (ieBug) {
771     httpCloseRead(http);
772   }
773 }
774
775 void httpTransferPartialReply(struct HttpConnection *http, char *msg, int len){
776   check(!http->isSuspended);
777   http->isPartialReply = 1;
778   if (http->state != PAYLOAD && http->state != DISCARD_PAYLOAD) {
779     check(http->state == HEADERS);
780     httpSetState(http, PAYLOAD);
781   }
782   httpTransfer(http, msg, len);
783 }
784
785 static int httpHandleCommand(struct HttpConnection *http,
786                              const struct Trie *handlers) {
787   debug("Handling \"%s\" \"%s\"", http->method, http->path);
788   const char *contentLength                  = getFromHashMap(&http->header,
789                                                              "content-length");
790   if (contentLength != NULL && *contentLength) {
791     char *endptr;
792     http->expecting                          = strtol(contentLength,
793                                                       &endptr, 10);
794     if (*endptr) {
795       // Invalid length. Read until end of stream and then close
796       // connection.
797       http->expecting                        = -1;
798     }
799   } else {
800       // Unknown length. Read until end of stream and then close
801       // connection.
802     http->expecting                          = -1;
803   }
804   if (!strcmp(http->method, "OPTIONS")) {
805     char *response                           = stringPrintf(NULL,
806                                                 "HTTP/1.1 200 OK\r\n"
807                                                 "Content-Length: 0\r\n"
808                                                 "Allow: GET, POST, OPTIONS\r\n"
809                                                 "\r\n");
810     httpTransfer(http, response, strlen(response));
811     if (http->expecting < 0) {
812       http->expecting                        = 0;
813     }
814     return HTTP_READ_MORE;
815   } else if (!strcmp(http->method, "GET")) {
816     if (http->expecting < 0) {
817       http->expecting                        = 0;
818     }
819   } else if (!strcmp(http->method, "POST")) {
820   } else if (!strcmp(http->method, "HEAD")) {
821     if (http->expecting < 0) {
822       http->expecting                        = 0;
823     }
824   } else if (!strcmp(http->method, "PUT")    ||
825              !strcmp(http->method, "DELETE") ||
826              !strcmp(http->method, "TRACE")  ||
827              !strcmp(http->method, "CONNECT")) {
828     httpSendReply(http, 405, "Method Not Allowed", NO_MSG);
829     return HTTP_DONE;
830   } else {
831     httpSendReply(http, 501, "Method Not Implemented", NO_MSG);
832     return HTTP_DONE;
833   }
834   const char *host                           = getFromHashMap(&http->header,
835                                                               "host");
836   if (host) {
837     for (char ch, *ptr = (char *)host; (ch = *ptr) != '\000'; ptr++) {
838       if (ch == ':') {
839         *ptr                                 = '\000';
840         break;
841       }
842       if (ch != '-' && ch != '.' &&
843           (ch < '0' ||(ch > '9' && ch < 'A') ||
844           (ch > 'Z' && ch < 'a')||(ch > 'z' && ch <= 0x7E))) {
845         httpSendReply(http, 400, "Bad Request", NO_MSG);
846         return HTTP_DONE;
847       }
848     }
849   }
850
851   char *diff;
852   struct HttpHandler *h = (struct HttpHandler *)getFromTrie(handlers,
853                                                             http->path, &diff);
854
855   if (h) {
856     if (h->websocketHandler) {
857       // Check for WebSocket handshake
858       const char *upgrade                    = getFromHashMap(&http->header,
859                                                               "upgrade");
860       if (upgrade && !strcmp(upgrade, "WebSocket")) {
861         const char *connection               = getFromHashMap(&http->header,
862                                                               "connection");
863         if (connection && !strcmp(connection, "Upgrade")) {
864           const char *origin                 = getFromHashMap(&http->header,
865                                                               "origin");
866           if (origin) {
867             for (const char *ptr = origin; *ptr; ptr++) {
868               if ((unsigned char)*ptr < ' ') {
869                 goto bad_ws_upgrade;
870               }
871             }
872
873             const char *protocol             = getFromHashMap(&http->header,
874                                                          "websocket-protocol");
875             if (protocol) {
876               for (const char *ptr = protocol; *ptr; ptr++) {
877                 if ((unsigned char)*ptr < ' ') {
878                   goto bad_ws_upgrade;
879                 }
880               }
881             }
882             char *port                       = NULL;
883             if (http->port != (http->sslHndl ? 443 : 80)) {
884               port                           = stringPrintf(NULL,
885                                                             ":%d", http->port);
886             }
887             char *response                   = stringPrintf(NULL,
888               "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
889               "Upgrade: WebSocket\r\n"
890               "Connection: Upgrade\r\n"
891               "WebSocket-Origin: %s\r\n"
892               "WebSocket-Location: %s://%s%s%s\r\n"
893               "%s%s%s"
894               "\r\n",
895               origin,
896               http->sslHndl ? "wss" : "ws", host && *host ? host : "localhost",
897               port ? port : "", http->path,
898               protocol ? "WebSocket-Protocol: " : "",
899               protocol ? protocol : "",
900               protocol ? "\r\n" : "");
901             free(port);
902             debug("Switching to WebSockets");
903             httpTransfer(http, response, strlen(response));
904             if (http->expecting < 0) {
905               http->expecting                = 0;
906             }
907             http->websocketHandler           = h->websocketHandler;
908             httpSetState(http, WEBSOCKET);
909             return HTTP_READ_MORE;
910           }
911         }
912       }
913     }
914   bad_ws_upgrade:;
915
916     if (h->handler) {
917       check(diff);
918       while (diff > http->path && diff[-1] == '/') {
919         diff--;
920       }
921       if (!*diff || *diff == '/' || *diff == '?' || *diff == '#') {
922         check(!http->matchedPath);
923         check(!http->pathInfo);
924         check(!http->query);
925
926         check(http->matchedPath              = malloc(diff - http->path + 1));
927         memcpy(http->matchedPath, http->path, diff - http->path);
928         http->matchedPath[diff - http->path] = '\000';
929
930         const char *query = strchr(diff, '?');
931         if (*diff && *diff != '?') {
932           const char *endOfInfo              = query
933                                                ? query : strrchr(diff, '\000');
934           check(http->pathInfo               = malloc(endOfInfo - diff + 1));
935           memcpy(http->pathInfo, diff, endOfInfo - diff);
936           http->pathInfo[endOfInfo - diff]   = '\000';
937         }
938
939         if (query) {
940           check(http->query                  = strdup(query + 1));
941         }
942         return h->handler(http, h->arg);
943       }
944     }
945   }
946   httpSendReply(http, 404, "File Not Found", NO_MSG);
947   return HTTP_DONE;
948 }
949
950 static int httpGetChar(struct HttpConnection *http, const char *buf,
951                        int size, int *offset) {
952   if (*offset < 0) {
953     return (unsigned char)http->partial[http->partialLength + (*offset)++];
954   } else if (*offset < size) {
955     return (unsigned char)buf[(*offset)++];
956   } else {
957     return -1;
958   }
959 }
960
961 static int httpParseCommand(struct HttpConnection *http, int offset,
962                             const char *buf, int bytes, int firstSpace,
963                             int lastSpace, int lineLength) {
964   if (firstSpace < 1 || lastSpace < 0) {
965   bad_request:
966     if (!http->method) {
967       check(http->method  = strdup(""));
968     }
969     if (!http->path) {
970       check(http->path    = strdup(""));
971     }
972     if (!http->version) {
973       check(http->version = strdup(""));
974     }
975     httpSendReply(http, 400, "Bad Request", NO_MSG);
976     httpSetState(http, COMMAND);
977     return 0;
978   }
979   check(!http->method);
980   check(http->method      = malloc(firstSpace + 1));
981   int i                   = offset;
982   int j                   = 0;
983   for (; j < firstSpace; j++) {
984     int ch                = httpGetChar(http, buf, bytes, &i);
985     if (ch >= 'a' && ch <= 'z') {
986       ch                 &= ~0x20;
987     }
988     http->method[j]       = ch;
989   }
990   http->method[j]         = '\000';
991   check(!http->path);
992   check(http->path        = malloc(lastSpace - firstSpace));
993   j                       = 0;
994   while (i < offset + lastSpace) {
995     int ch                = httpGetChar(http, buf, bytes, &i);
996     if ((ch != ' ' && ch != '\t') || j) {
997       http->path[j++]     = ch;
998     }
999   }
1000   http->path[j]           = '\000';
1001   if (*http->path != '/' &&
1002       (strcmp(http->method, "OPTIONS") || strcmp(http->path, "*"))) {
1003     goto bad_request;
1004   }
1005   check(!http->version);
1006   check(http->version     = malloc(lineLength - lastSpace + 1));
1007   j                       = 0;
1008   while (i < offset + lineLength) {
1009     int ch                = httpGetChar(http, buf, bytes, &i);
1010     if (ch == '\r') {
1011       break;
1012     }
1013     if (ch >= 'a' && ch <= 'z') {
1014       ch                 &= ~0x20;
1015     }
1016     if ((ch != ' ' && ch != '\t') || j) {
1017       http->version[j]    = ch;
1018       j++;
1019     }
1020   }
1021   http->version[j]        = '\000';
1022   if (memcmp(http->version, "HTTP/", 5) ||
1023       (http->version[5] < '1' || http->version[5] > '9')) {
1024     goto bad_request;
1025   }
1026   httpSetState(http, HEADERS);
1027   return 1;
1028 }
1029
1030 static int httpParseHeaders(struct HttpConnection *http,
1031                             const struct Trie *handlers, int offset,
1032                             const char *buf, int bytes, int colon,
1033                             int lineLength) {
1034   int i                    = offset;
1035   int ch                   = httpGetChar(http, buf, bytes, &i);
1036   if (ch == ' ' || ch == '\t') {
1037     if (http->key) {
1038       char **oldValue      = getRefFromHashMap(&http->header, http->key);
1039       check(oldValue);
1040       int oldLength        = strlen(*oldValue);
1041       check(*oldValue      = realloc(*oldValue,
1042                                     oldLength + lineLength + 1));
1043       int j                = oldLength;
1044       int end              = oldLength + lineLength;
1045       (*oldValue)[j++]     = ' ';
1046       for (; j < end; j++) {
1047         ch                 = httpGetChar(http, buf, bytes, &i);
1048         if (ch == ' ' || ch == '\t') {
1049           end--;
1050           j--;
1051           continue;
1052         } else if (ch == '\r' && j == end - 1) {
1053           break;
1054         }
1055         (*oldValue)[j]     = ch;
1056       }
1057       (*oldValue)[j]       = '\000';
1058     }
1059   } else if ((ch == '\r' &&
1060               httpGetChar(http, buf, bytes, &i) == '\n') ||
1061              ch == '\n' || ch == -1) {
1062     check(!http->expecting);
1063     http->callback         = NULL;
1064     http->arg              = NULL;
1065     int rc                 = httpHandleCommand(http, handlers);
1066   retry:;
1067     struct ServerConnection *connection = httpGetServerConnection(http);
1068     switch (rc) {
1069     case HTTP_DONE:
1070     case HTTP_ERROR: {
1071       if (http->expecting < 0 || rc == HTTP_ERROR) {
1072         httpCloseRead(http);
1073       }
1074       http->done           = 1;
1075       http->isSuspended    = 0;
1076       http->isPartialReply = 0;
1077       if (!serverGetTimeout(connection)) {
1078         serverSetTimeout(connection, CONNECTION_TIMEOUT);
1079       }
1080       httpSetState(http, http->expecting ? DISCARD_PAYLOAD : COMMAND);
1081       break; }
1082     case HTTP_READ_MORE:
1083       http->isSuspended    = 0;
1084       http->isPartialReply = 0;
1085       if (!serverGetTimeout(connection)) {
1086         serverSetTimeout(connection, CONNECTION_TIMEOUT);
1087       }
1088       check(!http->done);
1089       if (!http->expecting) {
1090         if (http->callback) {
1091           rc                 = http->callback(http, http->arg, "", 0);
1092           if (rc != HTTP_READ_MORE) {
1093             goto retry;
1094           }
1095         } else if (http->websocketHandler) {
1096           http->websocketHandler(http, http->arg, WS_CONNECTION_OPENED,
1097                                  NULL, 0);
1098         }
1099       }
1100       if (http->state != WEBSOCKET) {
1101         httpSetState(http, http->expecting ? PAYLOAD : COMMAND);
1102       }
1103       break;
1104     case HTTP_SUSPEND:
1105       http->isSuspended    = 1;
1106       http->isPartialReply = 0;
1107       serverSetTimeout(connection, 0);
1108       if (http->state != PAYLOAD && http->state != DISCARD_PAYLOAD) {
1109         check(http->state == HEADERS);
1110         httpSetState(http, PAYLOAD);
1111       }
1112       break;
1113     case HTTP_PARTIAL_REPLY:
1114       http->isSuspended    = 0;
1115       http->isPartialReply = 1;
1116       if (http->state != PAYLOAD && http->state != DISCARD_PAYLOAD) {
1117         check(http->state == HEADERS);
1118         httpSetState(http, PAYLOAD);
1119       }
1120       break;
1121     default:
1122       check(0);
1123     }
1124     if (ch == -1) {
1125       httpCloseRead(http);
1126     }
1127   } else {
1128     if (colon <= 0) {
1129       httpSendReply(http, 400, "Bad Request", NO_MSG);
1130       return 0;
1131     }
1132     check(colon < lineLength);
1133     check(http->key        = malloc(colon + 1));
1134     int i                  = offset;
1135     for (int j = 0; j < colon; j++) {
1136       ch                   = httpGetChar(http, buf, bytes, &i);
1137       if (ch >= 'A' && ch <= 'Z') {
1138         ch                |= 0x20;
1139       }
1140       http->key[j]         = ch;
1141     }
1142     http->key[colon]       = '\000';
1143     char *value;
1144     check(value            = malloc(lineLength - colon));
1145     i++;
1146     int j                  = 0;
1147     for (int k = 0; k < lineLength - colon - 1; j++, k++) {
1148       int ch           = httpGetChar(http, buf, bytes, &i);
1149       if ((ch == ' ' || ch == '\t') && j == 0) {
1150         j--;
1151       } else if (ch == '\r' && k == lineLength - colon - 2) {
1152         break;
1153       } else {
1154         value[j]           = ch;
1155       }
1156     }
1157     value[j]               = '\000';
1158     if (getRefFromHashMap(&http->header, http->key)) {
1159       debug("Dropping duplicate header \"%s\"", http->key);
1160       free(http->key);
1161       free(value);
1162       http->key            = NULL;
1163     } else {
1164       addToHashMap(&http->header, http->key, value);
1165     }
1166   }
1167   return 1;
1168 }
1169
1170 static int httpConsumePayload(struct HttpConnection *http, const char *buf,
1171                               int len) {
1172   if (http->expecting >= 0) {
1173     // If positive, we know the expected length of payload and
1174     // can keep the connection open.
1175     // If negative, allow unlimited payload, but close connection
1176     // when done.
1177     if (len > http->expecting) {
1178       len                  = http->expecting;
1179     }
1180     http->expecting       -= len;
1181   }
1182   if (http->callback) {
1183     check(!http->done);
1184     int rc                 = http->callback(http, http->arg, buf, len);
1185     struct ServerConnection *connection = httpGetServerConnection(http);
1186     switch (rc) {
1187     case HTTP_DONE:
1188     case HTTP_ERROR:
1189       if (http->expecting < 0 || rc == HTTP_ERROR) {
1190         httpCloseRead(http);
1191       }
1192       http->done           = 1;
1193       http->isSuspended    = 0;
1194       http->isPartialReply = 0;
1195       if (!serverGetTimeout(connection)) {
1196         serverSetTimeout(connection, CONNECTION_TIMEOUT);
1197       }
1198       httpSetState(http, http->expecting ? DISCARD_PAYLOAD : COMMAND);
1199       break;
1200     case HTTP_READ_MORE:
1201       http->isSuspended    = 0;
1202       http->isPartialReply = 0;
1203       if (!serverGetTimeout(connection)) {
1204         serverSetTimeout(connection, CONNECTION_TIMEOUT);
1205       }
1206       if (!http->expecting) {
1207         httpSetState(http, COMMAND);
1208       }
1209       break;
1210     case HTTP_SUSPEND:
1211       http->isSuspended    = 1;
1212       http->isPartialReply = 0;
1213       serverSetTimeout(connection, 0);
1214       if (http->state != PAYLOAD && http->state != DISCARD_PAYLOAD) {
1215         check(http->state == HEADERS);
1216         httpSetState(http, PAYLOAD);
1217       }
1218       break;
1219     case HTTP_PARTIAL_REPLY:
1220       http->isSuspended    = 0;
1221       http->isPartialReply = 1;
1222       if (http->state != PAYLOAD && http->state != DISCARD_PAYLOAD) {
1223         check(http->state == HEADERS);
1224         httpSetState(http, PAYLOAD);
1225       }
1226       break;
1227     default:
1228       check(0);
1229     }
1230   } else {
1231     // If we do not have a callback for handling the payload, and we also do
1232     // not know how long the payload is (because there was not Content-Length),
1233     // we now close the connection.
1234     if (http->expecting < 0) {
1235       http->expecting      = 0;
1236       httpCloseRead(http);
1237       httpSetState(http, COMMAND);
1238     }
1239   }
1240   return len;
1241 }
1242
1243 static int httpParsePayload(struct HttpConnection *http, int offset,
1244                             const char *buf, int bytes) {
1245   int consumed               = 0;
1246   if (offset < 0) {
1247     check(-offset <= http->partialLength);
1248     if (http->expecting) {
1249       consumed               = httpConsumePayload(http,
1250                                   http->partial + http->partialLength + offset,
1251                                   -offset);
1252       if (consumed == http->partialLength) {
1253         free(http->partial);
1254         http->partial        = NULL;
1255         http->partialLength  = 0;
1256       } else {
1257         memmove(http->partial, http->partial + consumed,
1258                 http->partialLength - consumed);
1259         http->partialLength -= consumed;
1260       }
1261       offset                += consumed;
1262     }
1263   }
1264   if (http->expecting && bytes - offset > 0) {
1265     check(offset >= 0);
1266     consumed                += httpConsumePayload(http, buf + offset,
1267                                                   bytes - offset);
1268   }
1269   return consumed;
1270 }
1271
1272 static int httpHandleWebSocket(struct HttpConnection *http, int offset,
1273                                const char *buf, int bytes) {
1274   check(http->websocketHandler);
1275   int ch                          = 0x00;
1276   while (bytes > offset) {
1277     if (http->websocketType & WS_UNDEFINED) {
1278       ch                          = httpGetChar(http, buf, bytes, &offset);
1279       check(ch >= 0);
1280       if (http->websocketType & 0xFF) {
1281         // Reading another byte of length information.
1282         if (http->expecting > 0xFFFFFF) {
1283           return 0;
1284         }
1285         http->expecting           = (128 * http->expecting) + (ch & 0x7F);
1286         if ((ch & 0x80) == 0) {
1287           // Done reading length information.
1288           http->websocketType    &= ~WS_UNDEFINED;
1289
1290           // ch is used to detect when we read the terminating byte in text
1291           // mode. In binary mode, it must be set to something other than 0xFF.
1292           ch                      = 0x00;
1293         }
1294       } else {
1295         // Reading first byte of frame.
1296         http->websocketType       = (ch & 0xFF) | WS_START_OF_FRAME;
1297         if (ch & 0x80) {
1298           // For binary data, we have to read the length before we can start
1299           // processing payload.
1300           http->websocketType    |= WS_UNDEFINED;
1301           http->expecting         = 0;
1302         }
1303       }
1304     } else if (http->websocketType & 0x80) {
1305       // Binary data
1306       if (http->expecting) {
1307         if (offset < 0) {
1308         handle_partial:
1309           check(-offset <= http->partialLength);
1310           int len                 = -offset;
1311           if (len >= http->expecting) {
1312             len                   = http->expecting;
1313             http->websocketType  |= WS_END_OF_FRAME;
1314           }
1315           if (len &&
1316               http->websocketHandler(http, http->arg, http->websocketType,
1317                                   http->partial + http->partialLength + offset,
1318                                   len) != HTTP_DONE) {
1319             return 0;
1320           }
1321
1322           if (ch == 0xFF) {
1323             // In text mode, we jump to handle_partial, when we find the
1324             // terminating 0xFF byte. If so, we should try to consume it now.
1325             if (len < http->partialLength) {
1326               len++;
1327               http->websocketType = WS_UNDEFINED;
1328             }
1329           }
1330
1331           if (len == http->partialLength) {
1332             free(http->partial);
1333             http->partial         = NULL;
1334             http->partialLength   = 0;
1335           } else {
1336             memmove(http->partial, http->partial + len,
1337                     http->partialLength - len);
1338             http->partialLength  -= len;
1339           }
1340           offset                 += len;
1341           http->expecting        -= len;
1342         } else {
1343         handle_buffered:;
1344           int len                 = bytes - offset;
1345           if (len >= http->expecting) {
1346             len                   = http->expecting;
1347             http->websocketType  |= WS_END_OF_FRAME;
1348           }
1349           if (len &&
1350               http->websocketHandler(http, http->arg, http->websocketType,
1351                                      buf + offset, len) != HTTP_DONE) {
1352             return 0;
1353           }
1354
1355           if (ch == 0xFF) {
1356             // In text mode, we jump to handle_buffered, when we find the
1357             // terminating 0xFF byte. If so, we should consume it now.
1358             check(offset + len < bytes);
1359             len++;
1360             http->websocketType   = WS_UNDEFINED;
1361           }
1362           offset                 += len;
1363           http->expecting        -= len;
1364         }
1365         http->websocketType      &= ~(WS_START_OF_FRAME | WS_END_OF_FRAME);
1366       } else {
1367         // Read all data. Go back to looking for a new frame header.
1368         http->websocketType       = WS_UNDEFINED;
1369       }
1370     } else {
1371       // Process text data until we find a 0xFF bytes.
1372       int i                       = offset;
1373
1374       // If we have partial data, process that first.
1375       while (i < 0) {
1376         ch                        = httpGetChar(http, buf, bytes, &i);
1377         check(ch != -1);
1378
1379         // Terminate when we either find the 0xFF, or we have reached the end
1380         // of partial data.
1381         if (ch == 0xFF || !i) {
1382           // Set WS_END_OF_FRAME, iff we have found the 0xFF marker.
1383           http->expecting         = i - offset - (ch == 0xFF);
1384           goto handle_partial;
1385         }
1386       }
1387
1388       // Read all remaining buffered bytes (i.e. positive offset).
1389       while (bytes > i) {
1390         ch                        = httpGetChar(http, buf, bytes, &i);
1391         check(ch != -1);
1392
1393         // Terminate when we either find the 0xFF, or we have reached the end
1394         // of buffered data.
1395         if (ch == 0xFF || bytes == i) {
1396           // Set WS_END_OF_FRAME, iff we have found the 0xFF marker.
1397           http->expecting         = i - offset - (ch == 0xFF);
1398           goto handle_buffered;
1399         }
1400       }
1401     }
1402   }
1403   return 1;
1404 }
1405
1406 int httpHandleConnection(struct ServerConnection *connection, void *http_,
1407                          short *events, short revents) {
1408   struct HttpConnection *http        = (struct HttpConnection *)http_;
1409   struct Trie *handlers              = serverGetHttpHandlers(http->server);
1410   http->connection                   = connection;
1411   int  bytes;
1412   do {
1413     bytes                            = 0;
1414     *events                          = 0;
1415     char buf[4096];
1416     int  eof                         = http->closed;
1417     if ((revents & POLLIN) && !http->closed) {
1418       bytes                          = httpRead(http, buf, sizeof(buf));
1419       if (bytes > 0) {
1420         http->headerLength          += bytes;
1421         if (http->headerLength > MAX_HEADER_LENGTH) {
1422           httpSendReply(http, 413, "Header too big", NO_MSG);
1423           bytes                      = 0;
1424           eof                        = 1;
1425         }
1426       } else {
1427         if (bytes == 0 || errno != EAGAIN) {
1428           httpCloseRead(http);
1429           eof                        = 1;
1430         } else {
1431           if (http->sslHndl && http->lastError == SSL_ERROR_WANT_WRITE) {
1432             *events                 |= POLLOUT;
1433           }
1434         }
1435         bytes                        = 0;
1436       }
1437     }
1438
1439     if (bytes > 0 && http->state == SNIFFING_SSL) {
1440       // Assume that all legitimate HTTP commands start with a sequence of
1441       // letters followed by a space character. If we don't see this pattern,
1442       // or if the method does not match one of the known methods, we try
1443       // switching to SSL, instead.
1444       int isSSL                      = 0;
1445       char method[12]                = { 0 };
1446       for (int i = -http->partialLength, j = 0, ch;
1447            (ch = httpGetChar(http, buf, bytes, &i)) != -1;
1448            j++) {
1449         if ((j > 0 && (ch == ' ' || ch == '\t')) ||
1450             ch == '\r' || ch == '\n') {
1451           isSSL                      = strcmp(method, "OPTIONS") &&
1452                                        strcmp(method, "GET") &&
1453                                        strcmp(method, "HEAD") &&
1454                                        strcmp(method, "POST") &&
1455                                        strcmp(method, "PUT") &&
1456                                        strcmp(method, "DELETE") &&
1457                                        strcmp(method, "TRACE") &&
1458                                        strcmp(method, "CONNECT");
1459           http->state                = COMMAND;
1460           break;
1461         } else if (j >= (int)sizeof(method)-1 ||
1462                    ch < 'A' || (ch > 'Z' && ch < 'a') || ch > 'z') {
1463           isSSL                      = 1;
1464           http->state                = COMMAND;
1465           break;
1466         } else {
1467           method[j]                  = ch & ~0x20;
1468         }
1469       }
1470       if (isSSL) {
1471         if (httpPromoteToSSL(http, buf, bytes) < 0) {
1472           httpCloseRead(http);
1473           bytes                      = 0;
1474           eof                        = 1;
1475         } else {
1476           http->headerLength         = 0;
1477           *events                   |= POLLIN;
1478           continue;
1479         }
1480       }
1481     }
1482
1483     if (bytes > 0 || (eof && http->partial)) {
1484       check(!!http->partial == !!http->partialLength);
1485       int  offset                    = -http->partialLength;
1486       int  eob                       = 0;
1487       do {
1488         int pushBack                 = 0;
1489         int consumed                 = 0;
1490         if (http->state == SNIFFING_SSL || http->state == COMMAND ||
1491             http->state == HEADERS) {
1492           check(!http->expecting);
1493           int  lineLength            = 0;
1494           int  colon                 = -1;
1495           int  firstSpace            = -1;
1496           int  lastSpace             = -1;
1497           int  fullLine              = 1;
1498           for (int i = offset; ; lineLength++) {
1499             int ch                   = httpGetChar(http, buf, bytes, &i);
1500             if (ch == ':') {
1501               if (colon < 0) {
1502                 colon                = lineLength;
1503               }
1504             } else if (ch == ' ' || ch == '\t') {
1505               if (firstSpace < 0) {
1506                 firstSpace           = lineLength;
1507               } else {
1508                 lastSpace            = lineLength;
1509               }
1510             } else if (ch == '\n') {
1511               break;
1512             } else if (ch == -1) {
1513               fullLine               = 0;
1514               eob                    = 1;
1515               break;
1516             }
1517           }
1518           if (fullLine || eof) {
1519             consumed                 = lineLength + 1;
1520             if (lineLength) {
1521               if (http->state == SNIFFING_SSL || http->state == COMMAND) {
1522                 if (!httpParseCommand(http, offset, buf, bytes, firstSpace,
1523                                       lastSpace, lineLength)) {
1524                   break;
1525                 }
1526               } else {
1527                 check(http->state == HEADERS);
1528                 if (!httpParseHeaders(http, handlers, offset, buf, bytes,
1529                                       colon, lineLength)) {
1530                   break;
1531                 }
1532               }
1533             }
1534           } else {
1535             pushBack                 = lineLength;
1536           }
1537         } else if (http->state == PAYLOAD ||
1538                    http->state == DISCARD_PAYLOAD) {
1539           if (http->expecting) {
1540             int len                  = bytes - offset;
1541             if (http->expecting > 0 &&
1542                 bytes > http->expecting) {
1543               len                    = http->expecting;
1544             }
1545             if (http->state == PAYLOAD) {
1546               len                    = httpParsePayload(http, offset, buf,
1547                                                         len + offset);
1548             }
1549             consumed                 = len;
1550             pushBack                 = bytes - offset - len;
1551           }
1552         } else if (http->state == WEBSOCKET) {
1553           if (!httpHandleWebSocket(http, offset, buf, bytes)) {
1554             httpCloseRead(http);
1555             break;
1556           }
1557           consumed                  += bytes - offset;
1558         } else {
1559           check(0);
1560         }
1561
1562         if (pushBack) {
1563           check(offset + pushBack == bytes);
1564           if (offset >= 0) {
1565             check(http->partial      = realloc(http->partial, pushBack));
1566             memcpy(http->partial, buf + offset, pushBack);
1567           } else if (pushBack != http->partialLength) {
1568             char *partial;
1569             check(partial            = malloc(pushBack));
1570             for (int i = offset, j = 0; j < pushBack; j++) {
1571               partial[j]             = httpGetChar(http, buf, bytes, &i);
1572             }
1573             free(http->partial);
1574             http->partial            = partial;
1575           }
1576           http->partialLength        = pushBack;
1577           offset                     = -pushBack;
1578           break;
1579         } else {
1580           offset                    += consumed;
1581           eob                       |= offset >= bytes;
1582         }
1583       } while (!eob && !http->closed);
1584       if (http->closed || offset >= 0) {
1585         free(http->partial);
1586         http->partial                = NULL;
1587         http->partialLength          = 0;
1588       } else if (-offset != http->partialLength) {
1589         check(-offset < http->partialLength);
1590         memmove(http->partial, http->partial + http->partialLength + offset,
1591                 -offset);
1592         http->partialLength          = -offset;
1593       }
1594     }
1595
1596     // If the peer closed the connection, clean up now.
1597     if (eof) {
1598       check(!http->partial);
1599       switch (http->state) {
1600       case SNIFFING_SSL:
1601       case COMMAND:
1602         break;
1603       case HEADERS:
1604         check(!http->expecting);
1605         http->callback               = NULL;
1606         http->arg                    = NULL;
1607         httpHandleCommand(http, handlers);
1608         httpCloseRead(http);
1609         httpSetState(http, COMMAND);
1610         break;
1611       case PAYLOAD:
1612       case DISCARD_PAYLOAD:
1613       case WEBSOCKET:
1614         http->expecting              = 0;
1615         httpCloseRead(http);
1616         httpSetState(http, COMMAND);
1617         break;
1618       }
1619     }
1620
1621     for (;;) {
1622       // Try to write any pending outgoing data
1623       if (http->msg && http->msgLength > 0) {
1624         int wrote                    = httpWrite(http, http->msg,
1625                                                  http->msgLength);
1626         if (wrote < 0 && errno != EAGAIN) {
1627           httpCloseRead(http);
1628           free(http->msg);
1629           http->msgLength            = 0;
1630           http->msg                  = NULL;
1631           break;
1632         } else if (wrote > 0) {
1633           if (wrote == http->msgLength) {
1634             free(http->msg);
1635             http->msgLength          = 0;
1636             http->msg                = NULL;
1637           } else {
1638             memmove(http->msg, http->msg + wrote, http->msgLength - wrote);
1639             http->msgLength         -= wrote;
1640           }
1641         }
1642         // SSL might require reading in order to write
1643         else if (wrote < 0 && errno == EAGAIN && http->sslHndl) {
1644           if (http->lastError == SSL_ERROR_WANT_READ && !http->closed) {
1645             *events                 |= POLLIN;
1646           }
1647         }
1648       }
1649   
1650       // If the callback only provided partial data, refill the outgoing
1651       // buffer whenever it runs low.
1652       if (http->isPartialReply && (!http->msg || http->msgLength <= 0)) {
1653         httpConsumePayload(http, "", 0);
1654       } else {
1655         break;
1656       }
1657     }
1658
1659     *events                         |=
1660       (*events & ~(POLLIN|POLLOUT)) |
1661       (!http->closed && ((http->state != PAYLOAD &&
1662                           http->state != DISCARD_PAYLOAD) ||
1663                          http->expecting) ? POLLIN : 0) |
1664       (http->msg || http->isPartialReply ? POLLOUT : 0);
1665
1666     connection                       = httpGetServerConnection(http);
1667     int timedOut                     = serverGetTimeout(connection) < 0;
1668     if (timedOut) {
1669       free(http->partial);
1670       http->partial                  = NULL;
1671       http->partialLength            = 0;
1672       free(http->msg);
1673       http->msg                      = NULL;
1674       http->msgLength                = 0;
1675     }
1676   
1677     if ((!(*events || http->isSuspended) || timedOut) && http->sslHndl) {
1678       *events                        = 0;
1679       serverSetTimeout(connection, 1);
1680       int wasAlreadyClosed           = http->closed;
1681       httpCloseRead(http);
1682       dcheck(!ERR_peek_error());
1683       sslBlockSigPipe();
1684       int rc                         = SSL_shutdown(http->sslHndl);
1685       switch (rc) {
1686       case 1:
1687         sslFreeHndl(&http->sslHndl);
1688         break;
1689       case 0:
1690         if (!wasAlreadyClosed) {
1691           *events                   |= POLLIN;
1692         }
1693         break;
1694       case -1:
1695         switch (SSL_get_error(http->sslHndl, rc)) {
1696         case SSL_ERROR_WANT_READ:
1697           if (!wasAlreadyClosed) {
1698             *events                 |= POLLIN;
1699           }
1700           break;
1701         case SSL_ERROR_WANT_WRITE:
1702           *events                   |= POLLOUT;
1703           break;
1704         }
1705         break;
1706       }
1707       ERR_clear_error();
1708       dcheck(!ERR_peek_error());
1709       if (sslUnblockSigPipe()) {
1710         *events                      = 0;
1711         sslFreeHndl(&http->sslHndl);
1712       }
1713     } else if (!http->sslHndl && timedOut) {
1714       *events                        = 0;
1715       serverSetTimeout(connection, 0);
1716       httpCloseRead(http);
1717     }
1718     revents                          = POLLIN | POLLOUT;
1719   } while (bytes > 0 && *events & POLLIN && !http->closed);
1720   return (*events & (POLLIN|POLLOUT)) ||
1721          (!http->closed && http->isSuspended);
1722 }
1723
1724 void httpSetCallback(struct HttpConnection *http,
1725                      int (*callback)(struct HttpConnection *, void *,
1726                                      const char *, int), void *arg) {
1727   http->callback = callback;
1728   http->arg      = arg;
1729 }
1730
1731 void *httpGetPrivate(struct HttpConnection *http) {
1732   return http->private;
1733 }
1734
1735 void *httpSetPrivate(struct HttpConnection *http, void *private) {
1736   void *old     = http->private;
1737   http->private = private;
1738   return old;
1739 }
1740
1741 void httpSendReply(struct HttpConnection *http, int code,
1742                    const char *msg, const char *fmt, ...) {
1743   http->code     = code;
1744   char *body;
1745   char *title    = code != 200 ? stringPrintf(NULL, "%d %s", code, msg) : NULL;
1746   char *details  = NULL;
1747   if (fmt != NULL && strcmp(fmt, NO_MSG)) {
1748     va_list ap;
1749     va_start(ap, fmt);
1750     details      = vStringPrintf(NULL, fmt, ap);
1751     va_end(ap);
1752   }
1753   body           = stringPrintf(NULL,
1754      "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
1755      "<!DOCTYPE html PUBLIC "
1756                "\"-//W3C//DTD XHTML 1.0 Transitional//EN\" "
1757                "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
1758      "<html xmlns=\"http://www.w3.org/1999/xhtml\" "
1759      "xmlns:v=\"urn:schemas-microsoft-com:vml\" "
1760      "xml:lang=\"en\" lang=\"en\">\n"
1761      "<head>\n"
1762      "<title>%s</title>\n"
1763      "</head>\n"
1764      "<body>\n"
1765      "%s\n"
1766      "</body>\n"
1767      "</html>\n",
1768      title ? title : msg, fmt && strcmp(fmt, NO_MSG) ? details : msg);
1769   free(details);
1770   free(title);
1771   char *response = NULL;
1772   if (code) {
1773     response     = stringPrintf(NULL,
1774                                 "HTTP/1.1 %d %s\r\n"
1775                                 "%s"
1776                                 "Content-Type: text/html; charset=utf-8\r\n"
1777                                 "Content-Length: %ld\r\n"
1778                                 "\r\n",
1779                                 code, msg,
1780                                 code != 200 ? "Connection: close\r\n" : "",
1781                                 (long)strlen(body));
1782   }
1783   int isHead     = !strcmp(http->method, "HEAD");
1784   if (!isHead) {
1785     response     = stringPrintf(response, "%s", body);
1786   }
1787   free(body);
1788   httpTransfer(http, response, strlen(response));
1789   if (code != 200 || isHead) {
1790     httpCloseRead(http);
1791   }
1792 }
1793
1794 void httpSendWebSocketTextMsg(struct HttpConnection *http, int type,
1795                               const char *fmt, ...) {
1796   check(type >= 0 && type <= 0x7F);
1797   va_list ap;
1798   va_start(ap, fmt);
1799   char *buf;
1800   int len;
1801   if (strcmp(fmt, BINARY_MSG)) {
1802     // Send a printf() style text message
1803     buf              = vStringPrintf(NULL, fmt, ap);
1804     len              = strlen(buf);
1805   } else {
1806     // Send a binary message
1807     len              = va_arg(ap, int);
1808     buf              = va_arg(ap, char *);
1809   }
1810   va_end(ap);
1811   check(len >= 0 && len < 0x60000000);
1812
1813   // We assume that all input data is directly mapped in the range 0..255
1814   // (e.g. ISO-8859-1). In order to transparently send it over a web socket,
1815   // we have to encode it in UTF-8.
1816   int utf8Len        = len + 2;
1817   for (int i = 0; i < len; ++i) {
1818     if (buf[i] & 0x80) {
1819       ++utf8Len;
1820     }
1821   }
1822   char *utf8;
1823   check(utf8         = malloc(utf8Len));
1824   utf8[0]            = type;
1825   for (int i = 0, j = 1; i < len; ++i) {
1826     unsigned char ch = buf[i];
1827     if (ch & 0x80) {
1828       utf8[j++]      = 0xC0 + (ch >> 6);
1829       utf8[j++]      = 0x80 + (ch & 0x3F);
1830     } else {
1831       utf8[j++]      = ch;
1832     }
1833     check(j < utf8Len);
1834   }
1835   utf8[utf8Len-1]    = '\xFF';
1836
1837   // Free our temporary buffer, if we actually did allocate one.
1838   if (strcmp(fmt, BINARY_MSG)) {
1839     free(buf);
1840   }
1841
1842   // Send to browser.
1843   httpTransfer(http, utf8, utf8Len);
1844 }
1845
1846 void httpSendWebSocketBinaryMsg(struct HttpConnection *http, int type,
1847                                 const void *buf, int len) {
1848   check(type >= 0x80 && type <= 0xFF);
1849   check(len > 0 && len < 0x7FFFFFF0);
1850
1851   // Allocate buffer for header and payload.
1852   char *data;
1853   check(data  = malloc(len + 6));
1854   data[0]     = type;
1855
1856   // Convert length to base-128.
1857   int i       = 0;
1858   int l       = len;
1859   do {
1860     data[++i] = 0x80 + (l & 0x7F);
1861     l        /= 128;
1862   } while (l);
1863   data[i]    &= 0x7F;
1864
1865   // Reverse digits, so that they are big-endian.
1866   for (int j = 0; j < i/2; ++j) {
1867     char ch   = data[1+j];
1868     data[1+j] = data[i-j];
1869     data[i-j] = ch;
1870   }
1871
1872   // Transmit header and payload.
1873   memmove(data + i + 1, buf, len);
1874   httpTransfer(http, data, len + i + 1);
1875 }
1876
1877 void httpExitLoop(struct HttpConnection *http, int exitAll) {
1878   serverExitLoop(http->server, exitAll);
1879 }
1880
1881 struct Server *httpGetServer(const struct HttpConnection *http) {
1882   return http->server;
1883 }
1884
1885 struct ServerConnection *httpGetServerConnection(const struct HttpConnection *
1886                                                  http) {
1887   struct HttpConnection *httpW = (struct HttpConnection *)http;
1888   httpW->connection = serverGetConnection(http->server, http->connection,
1889                                           http->fd);
1890   return http->connection;
1891 }
1892
1893 int httpGetFd(const HttpConnection *http) {
1894   return http->fd;
1895 }
1896
1897 const char *httpGetPeerName(const struct HttpConnection *http) {
1898   return http->peerName;
1899 }
1900
1901 const char *httpGetMethod(const struct HttpConnection *http) {
1902   return http->method;
1903 }
1904
1905 const char *httpGetProtocol(const struct HttpConnection *http) {
1906   return http->sslHndl ? "https" : "http";
1907 }
1908
1909 const char *httpGetHost(const struct HttpConnection *http) {
1910   const char *host = getFromHashMap(&http->header, "host");
1911   if (!host || !*host) {
1912     host           = "localhost";
1913   }
1914   return host;
1915 }
1916
1917 int httpGetPort(const struct HttpConnection *http) {
1918   return http->port;
1919 }
1920
1921 const char *httpGetPath(const struct HttpConnection *http) {
1922   return http->matchedPath;
1923 }
1924
1925 const char *httpGetPathInfo(const struct HttpConnection *http) {
1926   return http->pathInfo ? http->pathInfo : "";
1927 }
1928
1929 const char *httpGetQuery(const struct HttpConnection *http) {
1930   return http->query ? http->query : "";
1931 }
1932
1933 const char *httpGetURL(const struct HttpConnection *http) {
1934   if (!http->url) {
1935     const char *host           = httpGetHost(http);
1936     int s_size                 = 8 + strlen(host) + 25 + strlen(http->path);
1937     check(*(char **)&http->url = malloc(s_size + 1));
1938     *http->url                 = '\000';
1939     strncat(http->url, http->sslHndl ? "https://" : "http://", s_size);
1940     strncat(http->url, host, s_size);
1941     if (http->port != (http->sslHndl ? 443 : 80)) {
1942       snprintf(strrchr(http->url, '\000'), 25, ":%d", http->port);
1943     }
1944     strncat(http->url, http->path, s_size);
1945   }
1946   return http->url;
1947 }
1948
1949 const char *httpGetVersion(const struct HttpConnection *http) {
1950   return http->version;
1951 }
1952
1953 const struct HashMap *httpGetHeaders(const struct HttpConnection *http) {
1954   return &http->header;
1955 }
This page took 0.325189 seconds and 3 git commands to generate.