"Fossies" - the Fresh Open Source Software Archive

Member "shellinabox-2.20/libhttp/httpconnection.c" (9 Nov 2016, 65853 Bytes) of package /linux/privat/shellinabox-2.20.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "httpconnection.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.19_vs_2.20.

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