QUOTE: Love yourself first, then others.

libhttp.h - libhttp - A basic HTTP Framework

libhttp

A basic HTTP Framework
git clone git@soophie.de:/srv/git/libhttp
log | files | refs | readme

libhttp.h (24937B)


      1 #ifndef LIB_HTTP_H
      2 #define LIB_HTTP_H
      3 
      4 #include <stdbool.h>
      5 #include <openssl/ssl.h>
      6 #include <sys/socket.h>
      7 
      8 typedef enum {
      9   HTTP_ERR_OK                  = 0,
     10   HTTP_ERR_NO_SOCKET           = 1,
     11   HTTP_ERR_UNKNOWN_HOST        = 2,
     12   HTTP_ERR_NO_ADDR_REUSE       = 3,
     13   HTTP_ERR_ADDR_IN_USE         = 4,
     14   HTTP_ERR_NO_LISTEN           = 5,
     15   HTTP_ERR_NO_SSL_CONTEXT      = 6,
     16   HTTP_ERR_INVALID_CERTIFICATE = 7,
     17   HTTP_ERR_INVALID_PRIVATE_KEY = 8,
     18 } http_error_t;
     19 
     20 typedef enum {
     21   HTTP_STATUS_CONTINUE                        = 100,
     22   HTTP_STATUS_SWITCHING_PROTOCOLS             = 101,
     23   HTTP_STATUS_PROCESSING                      = 102,
     24   HTTP_STATUS_EARLY_HINTS                     = 103,
     25   HTTP_STATUS_OK                              = 200,
     26   HTTP_STATUS_CREATED                         = 201,
     27   HTTP_STATUS_ACCEPTED                        = 202,
     28   HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION   = 203,
     29   HTTP_STATUS_NO_CONTENT                      = 204,
     30   HTTP_STATUS_RESET_CONTENT                   = 205,
     31   HTTP_STATUS_PARTIAL_CONTENT                 = 206,
     32   HTTP_STATUS_MULTI_STATUS                    = 207,
     33   HTTP_STATUS_ALREADY_REPORTED                = 208,
     34   HTTP_STATUS_IM_USED                         = 226,
     35   HTTP_STATUS_MULTIPLE_CHOICES                = 300,
     36   HTTP_STATUS_MOVED_PERMANENTLY               = 301,
     37   HTTP_STATUS_FOUND                           = 302,
     38   HTTP_STATUS_SEE_OTHER                       = 303,
     39   HTTP_STATUS_NOT_MODIFIED                    = 304,
     40   HTTP_STATUS_TEMPORARY_REDIRECT              = 307,
     41   HTTP_STATUS_PERMANENT_REDIRECT              = 308,
     42   HTTP_STATUS_BAD_REQUEST                     = 400,
     43   HTTP_STATUS_UNAUTHORIZED                    = 401,
     44   HTTP_STATUS_PAYMENT_REQUIRED                = 402,
     45   HTTP_STATUS_FORBIDDEN                       = 403,
     46   HTTP_STATUS_NOT_FOUND                       = 404,
     47   HTTP_STATUS_METHOD_NOT_ALLOWED              = 405,
     48   HTTP_STATUS_NOT_ACCEPTABLE                  = 406,
     49   HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED   = 407,
     50   HTTP_STATUS_REQUEST_TIMEOUT                 = 408,
     51   HTTP_STATUS_CONFLICT                        = 409,
     52   HTTP_STATUS_GONE                            = 410,
     53   HTTP_STATUS_LENGTH_REQUIRED                 = 411,
     54   HTTP_STATUS_PRECONDITION_FAILED             = 412,
     55   HTTP_STATUS_PAYLOAD_TOO_LARGE               = 413,
     56   HTTP_STATUS_URI_TOO_LONG                    = 414,
     57   HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE          = 415,
     58   HTTP_STATUS_RANGE_NOT_SATISFIABLE           = 416,
     59   HTTP_STATUS_EXPECTATION_FAILED              = 417,
     60   HTTP_STATUS_I_AM_A_TEAPOT                   = 418,
     61   HTTP_STATUS_MISDIRECTED_REQUEST             = 421,
     62   HTTP_STATUS_UNPROCESSABLE_CONTENT           = 422,
     63   HTTP_STATUS_LOCKED                          = 423,
     64   HTTP_STATUS_FAILED_DEPENDENCY               = 424,
     65   HTTP_STATUS_TOO_EARLY                       = 425,
     66   HTTP_STATUS_UPGRADE_REQUIRED                = 426,
     67   HTTP_STATUS_PRECONDITION_REQUIRED           = 428,
     68   HTTP_STATUS_TOO_MANY_REQUESTS               = 429,
     69   HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
     70   HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS   = 451,
     71   HTTP_STATUS_INTERNAL_SERVER_ERROR           = 500,
     72   HTTP_STATUS_NOT_IMPLEMENTED                 = 501,
     73   HTTP_STATUS_BAD_GATEWAY                     = 502,
     74   HTTP_STATUS_SERVICE_UNAVAILABLE             = 503,
     75   HTTP_STATUS_GATEWAY_TIMEOUT                 = 504,
     76   HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED      = 505,
     77   HTTP_STATUS_VARIANT_ALSO_NEGOTITATES        = 506,
     78   HTTP_STATUS_INSUFFICIENT_STORAGE            = 507,
     79   HTTP_STATUS_LOOP_DETECTED                   = 508,
     80   HTTP_STATUS_NOT_EXTENDED                    = 510,
     81   HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511,
     82 } http_status_t;
     83 
     84 typedef struct Http http_t;
     85 
     86 typedef struct {
     87   char *hostname;
     88   char *certificate;
     89   char *private_key;
     90   SSL_CTX *ssl_ctx;
     91 } http_host_t;
     92 
     93 typedef struct {
     94   int sockfd;
     95   http_host_t *hosts;
     96   int hosts_len;
     97   int port;
     98 } http_bind_t;
     99 
    100 typedef struct {
    101   int sockfd;
    102   struct sockaddr addr;
    103   int addr_len;
    104   SSL *ssl;
    105   http_bind_t *curr_bind;
    106   http_host_t *curr_host;
    107   http_t *http;
    108 } http_conn_t;
    109 
    110 typedef struct {
    111   char *key;
    112   char *value;
    113 } http_header_t;
    114 
    115 typedef struct {
    116   http_conn_t *conn;
    117   char *method;
    118   char *url;
    119   char *version;
    120   http_header_t *headers;
    121   int headers_len;
    122   char *body;
    123   long body_len;
    124   void *ext_data;
    125 } http_request_t;
    126 
    127 typedef struct {
    128   char *version;
    129   http_status_t status;
    130   http_header_t *headers;
    131   int headers_len;
    132   char *body;
    133   long body_len;
    134 } http_response_t;
    135 
    136 struct Http {
    137   http_bind_t *binds;
    138   int binds_len;
    139   pthread_t thread;
    140   bool quit;
    141   SSL_CTX *ssl_ctx;
    142   http_response_t (*on_request_fn)(http_request_t *);
    143 };
    144 
    145 http_t *http_init(void);
    146 void http_cleanup(http_t *http);
    147 void http_on_request(http_t *http, http_response_t fn(http_request_t *));
    148 char *http_header_get(http_request_t *request, char *key);
    149 void http_header_set(http_response_t *response, char *key, char *value);
    150 http_response_t http_response_create(http_status_t status);
    151 void http_response_body(http_response_t *response, char *body, long len);
    152 void http_response_file(http_response_t *response, char *filename);
    153 http_error_t http_bind(http_t *http, char *hostname, int port, http_host_t *hosts, int hosts_len);
    154 http_error_t http_listen(http_t *http);
    155 void http_close(http_t *http);
    156 
    157 #ifdef LIB_HTTP_IMPL
    158 
    159 #include <stdio.h>
    160 #include <stdlib.h>
    161 #include <string.h>
    162 #include <time.h>
    163 #include <unistd.h>
    164 #include <pthread.h>
    165 #include <netdb.h>
    166 #include <poll.h>
    167 #include <signal.h>
    168 #include <fcntl.h>
    169 #include <openssl/ssl.h>
    170 #include <sys/socket.h>
    171 
    172 #define HTTP_MAX_REQUEST_HEAD_SIZE 1000000
    173 
    174 http_t *http_init(void) {
    175   http_t *http = (http_t *) malloc(sizeof(http_t));
    176   *http = (http_t) {
    177     .binds = NULL,
    178     .binds_len = 0,
    179     .quit = false,
    180     .ssl_ctx = NULL,
    181     .on_request_fn = NULL,
    182   };
    183   return http;
    184 }
    185 
    186 void http_cleanup(http_t *http) {
    187   free(http);
    188 }
    189 
    190 void http_on_request(http_t *http, http_response_t fn(http_request_t *)) {
    191   http->on_request_fn = fn;
    192 }
    193 
    194 char *http_read_file(char *filename) {
    195   FILE *fp = fopen(filename, "r");
    196   fseek(fp, 0, SEEK_END);
    197   long len = ftell(fp);
    198   fseek(fp, 0, SEEK_SET);
    199   char *content = (char *) malloc(sizeof(char) * (len + 1));
    200   fread(content, len, sizeof(char), fp);
    201   content[len] = '\0';
    202   fclose(fp);
    203   return content;
    204 }
    205 
    206 const char *http_status_str(http_status_t status) {
    207   switch (status) {
    208     case HTTP_STATUS_CONTINUE:
    209       return "Continue";
    210     case HTTP_STATUS_SWITCHING_PROTOCOLS:
    211       return "Switching Protocols";
    212     case HTTP_STATUS_PROCESSING:
    213       return "Processing";
    214     case HTTP_STATUS_EARLY_HINTS:
    215       return "Early Hints";
    216     case HTTP_STATUS_OK:
    217       return "OK";
    218     case HTTP_STATUS_CREATED:
    219       return "Created";
    220     case HTTP_STATUS_ACCEPTED:
    221       return "Accepted";
    222     case HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION:
    223       return "Non-Authoritative Information";
    224     case HTTP_STATUS_NO_CONTENT:
    225       return "No Content";
    226     case HTTP_STATUS_RESET_CONTENT:
    227       return "Reset Content";
    228     case HTTP_STATUS_PARTIAL_CONTENT:
    229       return "Partial Content";
    230     case HTTP_STATUS_MULTI_STATUS:
    231       return "Multi-Status";
    232     case HTTP_STATUS_ALREADY_REPORTED:
    233       return "Already Reported";
    234     case HTTP_STATUS_IM_USED:
    235       return "IM Used";
    236     case HTTP_STATUS_MULTIPLE_CHOICES:
    237       return "Multiple Choices";
    238     case HTTP_STATUS_MOVED_PERMANENTLY:
    239       return "Moved Permanently";
    240     case HTTP_STATUS_FOUND:
    241       return "Found";
    242     case HTTP_STATUS_SEE_OTHER:
    243       return "See Other";
    244     case HTTP_STATUS_NOT_MODIFIED:
    245       return "Not Modified";
    246     case HTTP_STATUS_TEMPORARY_REDIRECT:
    247       return "Temporary Redirect";
    248     case HTTP_STATUS_PERMANENT_REDIRECT:
    249       return "Permanent Redirect";
    250     case HTTP_STATUS_BAD_REQUEST:
    251       return "Bad Request";
    252     case HTTP_STATUS_UNAUTHORIZED:
    253       return "Unauthorized";
    254     case HTTP_STATUS_PAYMENT_REQUIRED:
    255       return "Payment Required";
    256     case HTTP_STATUS_FORBIDDEN:
    257       return "Forbidden";
    258     case HTTP_STATUS_NOT_FOUND:
    259       return "Not Found";
    260     case HTTP_STATUS_METHOD_NOT_ALLOWED:
    261       return "Method Not Allowed";
    262     case HTTP_STATUS_NOT_ACCEPTABLE:
    263       return "Not Acceptable";
    264     case HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED:
    265       return "Proxy Authentication Required";
    266     case HTTP_STATUS_REQUEST_TIMEOUT:
    267       return "Request Timeout";
    268     case HTTP_STATUS_CONFLICT:
    269       return "Conflict";
    270     case HTTP_STATUS_GONE:
    271       return "Gone";
    272     case HTTP_STATUS_LENGTH_REQUIRED:
    273       return "Length Required";
    274     case HTTP_STATUS_PRECONDITION_FAILED:
    275       return "Precondition Failed";
    276     case HTTP_STATUS_PAYLOAD_TOO_LARGE:
    277       return "Payload Too Large";
    278     case HTTP_STATUS_URI_TOO_LONG:
    279       return "URI Too Long";
    280     case HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE:
    281       return "Unsupported Media Type";
    282     case HTTP_STATUS_RANGE_NOT_SATISFIABLE:
    283       return "Range Not Satisfiable";
    284     case HTTP_STATUS_EXPECTATION_FAILED:
    285       return "Expectation Failed";
    286     case HTTP_STATUS_I_AM_A_TEAPOT:
    287       return "I'm a teapot";
    288     case HTTP_STATUS_MISDIRECTED_REQUEST:
    289       return "Misdirected Request";
    290     case HTTP_STATUS_UNPROCESSABLE_CONTENT:
    291       return "Unprocessable Content";
    292     case HTTP_STATUS_LOCKED:
    293       return "Locked";
    294     case HTTP_STATUS_FAILED_DEPENDENCY:
    295       return "Failed Dependency";
    296     case HTTP_STATUS_TOO_EARLY:
    297       return "Too Early";
    298     case HTTP_STATUS_UPGRADE_REQUIRED:
    299       return "Upgrade Required";
    300     case HTTP_STATUS_PRECONDITION_REQUIRED:
    301       return "Precondition Required";
    302     case HTTP_STATUS_TOO_MANY_REQUESTS:
    303       return "Too Many Requests";
    304     case HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE:
    305       return "Request Header Fields Too Large";
    306     case HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS:
    307       return "Unavailable For Legal Reasons";
    308     case HTTP_STATUS_INTERNAL_SERVER_ERROR:
    309       return "Internal Server Error";
    310     case HTTP_STATUS_NOT_IMPLEMENTED:
    311       return "Not Implemented";
    312     case HTTP_STATUS_BAD_GATEWAY:
    313       return "Bad Gateway";
    314     case HTTP_STATUS_SERVICE_UNAVAILABLE:
    315       return "Service Unavailable";
    316     case HTTP_STATUS_GATEWAY_TIMEOUT:
    317       return "Gateway Timeout";
    318     case HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED:
    319       return "HTTP Version Not Supported";
    320     case HTTP_STATUS_VARIANT_ALSO_NEGOTITATES:
    321       return "Variant Also Negotitates";
    322     case HTTP_STATUS_INSUFFICIENT_STORAGE:
    323       return "Insufficient Storage";
    324     case HTTP_STATUS_LOOP_DETECTED:
    325       return "Loop Detected";
    326     case HTTP_STATUS_NOT_EXTENDED:
    327       return "Not Extended";
    328     case HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED:
    329       return "Network Authentication Required";
    330     default:
    331       return NULL;
    332   }
    333 }
    334 
    335 ssize_t http_read(http_conn_t *conn, char *buffer, size_t len) {
    336   if (conn->ssl != NULL) {
    337     return SSL_read(conn->ssl, buffer, len);
    338   }
    339   return read(conn->sockfd, buffer, len);
    340 }
    341 
    342 ssize_t http_write(http_conn_t *conn, char *buffer, size_t len) {
    343   if (conn->ssl != NULL) {
    344     return SSL_write(conn->ssl, buffer, len);
    345   }
    346   return write(conn->sockfd, buffer, len);
    347 }
    348 
    349 char *http_header_get(http_request_t *request, char *key) {
    350   if (request->headers_len > 0) {
    351     for (int i = 0; i < request->headers_len; i++) {
    352       http_header_t *header = &request->headers[i];
    353       if (strcmp(header->key, key) == 0) {
    354         return header->value;
    355       }
    356     }
    357   }
    358   return NULL;
    359 }
    360 
    361 void http_header_set(http_response_t *response, char *key, char *value) {
    362   response->headers = (http_header_t *) realloc(response->headers, sizeof(http_header_t) * (response->headers_len + 1));
    363   http_header_t *new_header = &response->headers[response->headers_len];
    364   response->headers_len++;
    365   int key_len = strlen(key);
    366   new_header->key = (char *) malloc(sizeof(char) * (key_len + 1));
    367   memcpy(new_header->key, key, key_len);
    368   new_header->key[key_len] = '\0';
    369   int value_len = strlen(value);
    370   new_header->value = (char *) malloc(sizeof(char) * (value_len + 1));
    371   memcpy(new_header->value, value, value_len);
    372   new_header->value[value_len] = '\0';
    373 }
    374 
    375 http_response_t http_response_create(http_status_t status) {
    376   const char *version = "HTTP/1.1";
    377   int version_len = strlen(version);
    378   http_response_t response = { NULL, status, NULL, 0, NULL, 0 };
    379   response.version = (char *) malloc(sizeof(char) * (version_len + 1));
    380   memcpy(response.version, version, version_len);
    381   response.version[version_len] = '\0';
    382   return response;
    383 }
    384 
    385 void http_response_body(http_response_t *response, char *body, long len) {
    386   if (response != NULL && body != NULL) {
    387     response->body = (char *) malloc(sizeof(char) * len);
    388     memcpy(response->body, body, len);
    389     response->body_len = len;
    390     char content_length[50];
    391     snprintf(content_length, 50, "%ld", len);
    392     http_header_set(response, (char *) "Content-Length", content_length);
    393   }
    394 }
    395 
    396 void http_response_file(http_response_t *response, char *filename) {
    397   char *content = http_read_file(filename);
    398   if (content != NULL) {
    399     http_response_body(response, content, strlen(content));
    400     free(content);
    401   }
    402 }
    403 
    404 void http_request_free(http_request_t *request) {
    405   if (request->method != NULL) {
    406     free(request->method);
    407   }
    408   if (request->url != NULL) {
    409     free(request->url);
    410   }
    411   if (request->version != NULL) {
    412     free(request->version);
    413   }
    414   if (request->headers_len > 0) {
    415     for (int i = 0; i < request->headers_len; i++) {
    416       http_header_t *header = &request->headers[i];
    417       if (header->key != NULL) {
    418         free(header->key);
    419       }
    420       if (header->value != NULL) {
    421         free(header->value);
    422       }
    423     }
    424   }
    425   if (request->body != NULL) {
    426     free(request->body);
    427   }
    428   if (request->ext_data != NULL) {
    429     free(request->ext_data);
    430   }
    431 }
    432 
    433 void http_response_free(http_response_t *response) {
    434   if (response->version != NULL) {
    435     free(response->version);
    436   }
    437   if (response->headers_len > 0) {
    438     for (int i = 0; i < response->headers_len; i++) {
    439       http_header_t *header = &response->headers[i];
    440       if (header->key != NULL) {
    441         free(header->key);
    442       }
    443       if (header->value != NULL) {
    444         free(header->value);
    445       }
    446     }
    447   }
    448   if (response->body != NULL) {
    449     free(response->body);
    450   }
    451 }
    452 
    453 http_request_t http_read_request(http_conn_t *conn) {
    454   int len = 0;
    455   int ln = 0;
    456   int start = 0;
    457   char buffer[HTTP_MAX_REQUEST_HEAD_SIZE];
    458   http_request_t request = {
    459     .conn = conn,
    460     .method = NULL,
    461     .url = NULL,
    462     .version = NULL,
    463     .headers = NULL,
    464     .headers_len = 0,
    465     .body = NULL,
    466     .body_len = 0,
    467     .ext_data = NULL,
    468   };
    469   while (true) {
    470     char c;
    471     int read = http_read(conn, &c, 1);
    472     if (read == 0) {
    473       break;
    474     }
    475     // break if too long
    476     if (len == HTTP_MAX_REQUEST_HEAD_SIZE) {
    477       perror("request is too long");
    478       break;
    479     }
    480     buffer[len] = c;
    481     len++;
    482     // read head
    483     if (len >= 2) {
    484       char *slice = buffer + (len - 2);
    485       if (strncmp(slice, "\r\n", 2) == 0) {
    486         int line_len = (len - 2) - start;
    487         if (line_len > 0) {
    488           // read line
    489           char line[line_len + 1];
    490           memcpy(line, buffer + start, line_len);
    491           line[line_len] = '\0';
    492           // read method, url, and version
    493           if (ln == 0) {
    494             int arg = 0;
    495             int start = 0;
    496             for (int i = 0; i <= line_len; i++) {
    497               if (line[i] == ' ' || i == line_len) {
    498                 // read method
    499                 if (arg == 0) {
    500                   int method_length = i - start;
    501                   request.method = (char *) malloc(sizeof(char) * (method_length + 1));
    502                   memcpy(request.method, line + start, method_length);
    503                   request.method[method_length] = '\0';
    504                 }
    505                 // read url
    506                 if (arg == 1) {
    507                   int url_length = i - start;
    508                   request.url = (char *) malloc(sizeof(char) * (url_length + 1));
    509                   memcpy(request.url, line + start, url_length);
    510                   request.url[url_length] = '\0';
    511                 }
    512                 // read version
    513                 if (arg == 2) {
    514                   int version_length = i - start;
    515                   request.version = (char *) malloc(sizeof(char) * (version_length + 1));
    516                   memcpy(request.version, line + start, version_length);
    517                   request.version[version_length] = '\0';
    518                 }
    519                 start = i + 1;
    520                 arg++;
    521               }
    522             }
    523           }
    524           // read headers
    525           else {
    526             int sep = 0;
    527             request.headers = (http_header_t *) realloc(request.headers, sizeof(http_header_t) * (request.headers_len + 1));
    528             http_header_t *header = &request.headers[request.headers_len];
    529             request.headers_len++;
    530             for (int i = 0; i < line_len; i++) {
    531               if (line[i] == ':') {
    532                 int key_len = i;
    533                 header->key = (char *) malloc(sizeof(char) * (key_len + 1));
    534                 memcpy(header->key, line, key_len);
    535                 header->key[key_len] = '\0';
    536                 sep = i + 2;
    537                 break;
    538               }
    539             }
    540             int value_len = line_len - sep;
    541             header->value = (char *) malloc(sizeof(char) * (value_len + 1));
    542             memcpy(header->value, line + sep, value_len);
    543             header->value[value_len] = '\0';
    544           }
    545         }
    546         start = len;
    547         ln++;
    548       }
    549     }
    550     // read body
    551     if (len >= 4) {
    552       char *slice = buffer + (len - 4);
    553       if (strncmp(slice, "\r\n\r\n", 4) == 0) {
    554         char *content_length = http_header_get(&request, (char *) "Content-Length");
    555         if (content_length != NULL) {
    556           request.body_len = strtol(content_length, NULL, 10);
    557           if (request.body_len > 0) {
    558             request.body = (char *) malloc(sizeof(char) * (request.body_len + 1));
    559             http_read(conn, request.body, request.body_len);
    560             request.body[request.body_len] = '\0';
    561           }
    562         }
    563         break;
    564       }
    565     }
    566   }
    567   return request;
    568 }
    569 
    570 void http_write_response(http_conn_t *conn, http_response_t response) {
    571   http_write(conn, response.version, strlen(response.version));
    572   http_write(conn, (char *) " ", 1);
    573   char status[4];
    574   snprintf(status, 4, "%d", response.status);
    575   http_write(conn, status, strlen(status));
    576   http_write(conn, (char *) " ", 1);
    577   const char *status_message = http_status_str(response.status);
    578   http_write(conn, (char *) status_message, strlen(status_message));
    579   http_write(conn, (char *) "\r\n", 2);
    580   if (response.headers_len > 0) {
    581     for (int i = 0; i < response.headers_len; i++) {
    582       http_header_t *header = &response.headers[i];
    583       http_write(conn, header->key, strlen(header->key));
    584       http_write(conn, (char *) ": ", 2);
    585       http_write(conn, header->value, strlen(header->value));
    586       http_write(conn, (char *) "\r\n", 2);
    587     }
    588   }
    589   http_write(conn, (char *) "\r\n", 2);
    590   if (response.body != NULL) {
    591     http_write(conn, response.body, response.body_len);
    592   }
    593 }
    594 
    595 void *http_handle_client(void *ptr) {
    596   if (!ptr) {
    597     pthread_exit(0);
    598   }
    599   http_conn_t *conn = (http_conn_t *) ptr;
    600   if (conn->curr_bind->hosts_len > 0) {
    601     SSL_CTX_set_tlsext_servername_arg(conn->http->ssl_ctx, (void *) conn);
    602     conn->ssl = SSL_new(conn->http->ssl_ctx);
    603     SSL_set_fd(conn->ssl, conn->sockfd);
    604     if (SSL_accept(conn->ssl) <= 0) {
    605       pthread_exit(0);
    606     }
    607   }
    608   int flags = fcntl(conn->sockfd, F_GETFL, 0);
    609   if (flags == -1) {
    610     close(conn->sockfd);
    611     free(conn);
    612     pthread_exit(0);
    613   }
    614   flags |= O_NONBLOCK;
    615   if (fcntl(conn->sockfd, F_SETFL, flags) == -1) {
    616     close(conn->sockfd);
    617     free(conn);
    618     pthread_exit(0);
    619   }
    620   http_request_t request = http_read_request(conn);
    621   if (request.method != NULL && request.url != NULL) {
    622     if (conn->http->on_request_fn != NULL) {
    623       http_response_t response = conn->http->on_request_fn(&request);
    624       http_write_response(conn, response);
    625       http_response_free(&response);
    626     }
    627   }
    628   http_request_free(&request);
    629   if (conn->ssl != NULL) {
    630     SSL_shutdown(conn->ssl);
    631     SSL_free(conn->ssl);
    632   }
    633   close(conn->sockfd);
    634   free(conn);
    635   pthread_exit(0);
    636 }
    637 
    638 void *http_handle_server(void *ptr) {
    639   http_t *http = (http_t *) ptr;
    640   struct pollfd fds[http->binds_len];
    641   for (int i = 0; i < http->binds_len; i++) {
    642     fds[i].fd = http->binds[i].sockfd;
    643     fds[i].events = POLLIN | POLLPRI;
    644   }
    645   while (!http->quit) {
    646     struct timespec sleep_req, sleep_rem;
    647     sleep_req.tv_sec = 0;
    648     sleep_req.tv_nsec = 100000000;
    649     nanosleep(&sleep_req, &sleep_rem);
    650     if (poll(fds, http->binds_len, 100)) {
    651       for (int i = 0; i < http->binds_len; i++) {
    652         if (fds[i].revents & POLLIN) {
    653           http_conn_t *conn = (http_conn_t *) malloc(sizeof(http_conn_t));
    654           conn->addr_len = sizeof(conn->addr);
    655           conn->sockfd = accept(http->binds[i].sockfd, &conn->addr, (socklen_t *) &conn->addr_len);
    656           conn->curr_bind = &http->binds[i];
    657           conn->ssl = NULL;
    658           conn->http = http;
    659           if (conn->sockfd <= 0) {
    660             free(conn);
    661           }
    662           else {
    663             pthread_t thread;
    664             pthread_attr_t thread_attr;
    665             pthread_attr_init(&thread_attr);
    666             pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
    667             pthread_create(&thread, &thread_attr, http_handle_client, (void *) conn);
    668             pthread_attr_destroy(&thread_attr);
    669           }
    670         }
    671       }
    672     }
    673   }
    674   pthread_exit(0);
    675 }
    676 
    677 int http_tls_sni_callback(SSL *ssl, int *al, void *arg) {
    678   (void)(al);
    679   http_conn_t *conn = (http_conn_t *) arg;
    680   const char *hostname = SSL_get_servername(ssl, 0);
    681   if (hostname != NULL) {
    682     for (int i = 0; i < conn->http->binds_len; i++) {
    683       for (int j = 0; j < conn->http->binds[i].hosts_len; j++) {
    684         http_host_t *http_host = &conn->http->binds[i].hosts[j];
    685         if (strcmp(http_host->hostname, hostname) == 0) {
    686           conn->curr_host = http_host;
    687           SSL_set_SSL_CTX(ssl, http_host->ssl_ctx);
    688           return SSL_TLSEXT_ERR_OK;
    689         }
    690       }
    691     }
    692   }
    693   return SSL_TLSEXT_ERR_NOACK;
    694 }
    695 
    696 http_error_t http_bind(http_t *http, char *hostname, int port, http_host_t *hosts, int hosts_len) {
    697   http->binds = (http_bind_t *) realloc(http->binds, sizeof(http_bind_t) * (http->binds_len + 1));
    698   http_bind_t *http_bind = &http->binds[http->binds_len];
    699   http_bind->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    700   http_bind->port = port;
    701   if (http_bind->sockfd <= 0) {
    702     return HTTP_ERR_NO_SOCKET;
    703   }
    704   struct hostent *host = gethostbyname(hostname);
    705   if (!host) {
    706     return HTTP_ERR_UNKNOWN_HOST;
    707   }
    708   struct sockaddr_in addr;
    709   addr.sin_family = AF_INET;
    710   memcpy(&addr.sin_addr, host->h_addr_list[0], host->h_length);
    711   addr.sin_port = htons(port);
    712   int enable = 1;
    713   if (setsockopt(http_bind->sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
    714     return HTTP_ERR_NO_ADDR_REUSE;
    715   }
    716   if (bind(http_bind->sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0) {
    717     return HTTP_ERR_ADDR_IN_USE;
    718   }
    719   if (listen(http_bind->sockfd, 5) < 0) {
    720     return HTTP_ERR_NO_LISTEN;
    721   }
    722   for (int i = 0; i < hosts_len; i++) {
    723     http_host_t *http_host = &hosts[i];
    724     http_host->ssl_ctx = NULL;
    725     if (http_host->certificate != NULL && http_host->private_key != NULL) {
    726       const SSL_METHOD *method = TLS_server_method();
    727       http_host->ssl_ctx = SSL_CTX_new(method);
    728       if (!http_host->ssl_ctx) {
    729         return HTTP_ERR_NO_SSL_CONTEXT;
    730       }
    731       if (SSL_CTX_use_certificate_chain_file(http_host->ssl_ctx, http_host->certificate) <= 0) {
    732         return HTTP_ERR_INVALID_CERTIFICATE;
    733       }
    734       if (SSL_CTX_use_PrivateKey_file(http_host->ssl_ctx, http_host->private_key, SSL_FILETYPE_PEM) <= 0) {
    735         return HTTP_ERR_INVALID_PRIVATE_KEY;
    736       }
    737     }
    738   }
    739   http_bind->hosts = hosts;
    740   http_bind->hosts_len = hosts_len;
    741   http->binds_len++;
    742   return HTTP_ERR_OK;
    743 }
    744 
    745 http_error_t http_listen(http_t *http) {
    746   signal(SIGPIPE, SIG_IGN);
    747   const SSL_METHOD *method = TLS_server_method();
    748   http->ssl_ctx = SSL_CTX_new(method);
    749   if (!http->ssl_ctx) {
    750     return HTTP_ERR_NO_SSL_CONTEXT;
    751   }
    752   SSL_CTX_set_tlsext_servername_callback(http->ssl_ctx, http_tls_sni_callback);
    753   pthread_create(&http->thread, 0, http_handle_server, (void *) http);
    754   return HTTP_ERR_OK;
    755 }
    756 
    757 void http_close(http_t *http) {
    758   http->quit = true;
    759   pthread_join(http->thread, NULL);
    760   for (int i = 0; i < http->binds_len; i++) {
    761     close(http->binds[i].sockfd);
    762     for (int j = 0; j < http->binds[i].hosts_len; j++) {
    763       if (http->binds[i].hosts[j].ssl_ctx != NULL) {
    764         SSL_CTX_free(http->binds[i].hosts[j].ssl_ctx);
    765       }
    766     }
    767   }
    768   if (http->ssl_ctx != NULL) {
    769     free(http->ssl_ctx);
    770   }
    771 }
    772 
    773 #endif /* LIB_HTTP_IMPL */
    774 #endif /* LIB_HTTP_H */