NEWS: Welcome to my new homepage! <3

libhttp.h - libhttp - A basic HTTP Framework

libhttp

A basic HTTP Framework
git clone git://192.168.2.2/libhttp
Log | Files | Refs | README

libhttp.h (24644B)


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