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 */