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