MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at mir/inline-method 1264 lines 37 kB view raw
1#include <compat.h> // IWYU pragma: keep 2 3#include <stdbool.h> 4#include <stdint.h> 5#include <stdio.h> 6#include <stdlib.h> 7#include <string.h> 8#include <strings.h> 9#include <signal.h> 10#include <uv.h> 11 12#include "ant.h" 13#include "internal.h" 14#include "ptr.h" 15 16#include "gc/modules.h" 17#include "net/listener.h" 18#include "streams/readable.h" 19 20#include "http/http1_parser.h" 21#include "http/http1_writer.h" 22 23#include "modules/assert.h" 24#include "modules/abort.h" 25#include "modules/blob.h" 26#include "modules/buffer.h" 27#include "modules/headers.h" 28#include "modules/request.h" 29#include "modules/response.h" 30#include "modules/server.h" 31#include "modules/timer.h" 32#include "modules/domexception.h" 33 34typedef struct server_runtime_s server_runtime_t; 35typedef struct server_request_s server_request_t; 36typedef struct server_conn_state_s server_conn_state_t; 37 38static server_runtime_t *g_server = NULL; 39 40typedef struct stop_waiter_s { 41 ant_value_t promise; 42 struct stop_waiter_s *next; 43} stop_waiter_t; 44 45typedef enum { 46 SERVER_WRITE_NONE = 0, 47 SERVER_WRITE_CLOSE_CLIENT, 48 SERVER_WRITE_STREAM_READ, 49 SERVER_WRITE_KEEP_ALIVE, 50} server_write_action_t; 51 52typedef struct { 53 server_request_t *request; 54 ant_conn_t *conn; 55 server_write_action_t action; 56} server_write_req_t; 57 58struct server_request_s { 59 server_runtime_t *server; 60 server_conn_state_t *conn_state; 61 ant_conn_t *conn; 62 63 ant_value_t request_obj; 64 ant_value_t response_obj; 65 ant_value_t response_promise; 66 ant_value_t response_reader; 67 ant_value_t response_read_promise; 68 69 struct server_request_s *next; 70 size_t consumed_len; 71 72 int refs; 73 bool keep_alive; 74 bool response_started; 75}; 76 77struct server_conn_state_s { 78 server_runtime_t *server; 79 ant_conn_t *conn; 80 81 ant_http1_conn_parser_t parser; 82 uv_timer_t drain_timer; 83 server_request_t request; 84 server_request_t *active_req; 85 86 bool drain_timer_closed; 87 bool drain_scheduled; 88}; 89 90struct server_runtime_s { 91 ant_t *js; 92 93 ant_value_t export_obj; 94 ant_value_t fetch_fn; 95 ant_value_t server_ctx; 96 uv_loop_t *loop; 97 98 ant_listener_t listener; 99 uv_signal_t sigint_handle; 100 uv_signal_t sigterm_handle; 101 stop_waiter_t *stop_waiters; 102 server_request_t *requests; 103 104 char *hostname; 105 char *unix_path; 106 107 uint64_t request_timeout_ms; 108 uint64_t idle_timeout_ms; 109 110 int port; 111 bool sigint_closed; 112 bool sigterm_closed; 113 bool stopping; 114 bool force_stop; 115}; 116 117static inline void server_request_retain(server_request_t *req) { 118 if (req) req->refs++; 119} 120 121static inline server_request_t *server_current_request(ant_t *js) { 122 return (server_request_t *)js_get_native_ptr(js->current_func); 123} 124 125static inline server_runtime_t *server_current_runtime(ant_t *js) { 126 return (server_runtime_t *)js_get_native_ptr(js->current_func); 127} 128 129static ant_value_t server_mkreqfun( 130 ant_t *js, 131 ant_value_t (*fn)(ant_t *, ant_value_t *, int), 132 server_request_t *req 133) { 134 ant_value_t func = js_heavy_mkfun(js, fn, js_mkundef()); 135 js_set_native_ptr(func, req); 136 return func; 137} 138 139static ant_value_t server_mkruntimefun( 140 ant_t *js, 141 ant_value_t (*fn)(ant_t *, ant_value_t *, int), 142 server_runtime_t *server 143) { 144 ant_value_t func = js_heavy_mkfun(js, fn, js_mkundef()); 145 js_set_native_ptr(func, server); 146 return func; 147} 148 149static ant_value_t server_exception_reason(ant_t *js, ant_value_t value) { 150 if (!is_err(value)) return value; 151 if (!js->thrown_exists) return value; 152 153 value = js->thrown_value; 154 js->thrown_exists = false; 155 js->thrown_value = js_mkundef(); 156 js->thrown_stack = js_mkundef(); 157 return value; 158} 159 160static void server_remove_request(server_runtime_t *server, server_request_t *req) { 161 server_request_t **it = NULL; 162 if (!server || !req) return; 163 164 for (it = &server->requests; *it; it = &(*it)->next) { 165 if (*it == req) { 166 *it = req->next; 167 return; 168 }} 169} 170 171static void server_request_reset(server_request_t *req) { 172 server_runtime_t *server = NULL; 173 server_conn_state_t *conn_state = NULL; 174 175 if (!req) return; 176 server = req->server; 177 conn_state = req->conn_state; 178 179 *req = (server_request_t){ 180 .server = server, 181 .conn_state = conn_state, 182 .conn = conn_state ? conn_state->conn : NULL, 183 .request_obj = js_mkundef(), 184 .response_obj = js_mkundef(), 185 .response_promise = js_mkundef(), 186 .response_reader = js_mkundef(), 187 .response_read_promise = js_mkundef(), 188 }; 189} 190 191static void server_conn_state_maybe_free(server_conn_state_t *cs) { 192 if (!cs) return; 193 if (cs->conn) return; 194 if (cs->active_req) return; 195 if (cs->request.refs > 0) return; 196 if (!cs->drain_timer_closed) return; 197 free(cs); 198} 199 200static void server_request_release(server_request_t *req) { 201 if (!req) return; 202 if (--req->refs > 0) return; 203 204 server_remove_request(req->server, req); 205 server_request_reset(req); 206 server_conn_state_maybe_free(req->conn_state); 207} 208 209static server_request_t *server_find_request(server_runtime_t *server, ant_value_t request_obj) { 210 server_request_t *req = NULL; 211 if (!server || !is_object_type(request_obj)) return NULL; 212 213 for (req = server->requests; req; req = req->next) { 214 if (req->request_obj == request_obj) return req; 215 } 216 return NULL; 217} 218static void stop_waiters_resolve(server_runtime_t *server) { 219 stop_waiter_t *waiter = server->stop_waiters; 220 server->stop_waiters = NULL; 221 222 while (waiter) { 223 stop_waiter_t *next = waiter->next; 224 js_resolve_promise(server->js, waiter->promise, js_mkundef()); 225 free(waiter); 226 waiter = next; 227 } 228} 229 230static void server_maybe_finish_stop(server_runtime_t *server) { 231 if (!server || !server->stopping) return; 232 if (ant_listener_has_connections(&server->listener)) return; 233 if (!ant_listener_is_closed(&server->listener) || !server->sigint_closed || !server->sigterm_closed) return; 234 235 stop_waiters_resolve(server); 236} 237 238static void server_signal_close_cb(uv_handle_t *handle) { 239 server_runtime_t *server = (server_runtime_t *)handle->data; 240 if (!server) return; 241 242 if (handle == (uv_handle_t *)&server->sigint_handle) server->sigint_closed = true; 243 if (handle == (uv_handle_t *)&server->sigterm_handle) server->sigterm_closed = true; 244 server_maybe_finish_stop(server); 245} 246 247static void server_begin_stop(server_runtime_t *server, bool force) { 248 if (!server) return; 249 if (force) server->force_stop = true; 250 251 server->stopping = true; 252 ant_listener_stop(&server->listener, server->force_stop); 253 254 if (!uv_is_closing((uv_handle_t *)&server->sigint_handle)) 255 uv_close((uv_handle_t *)&server->sigint_handle, server_signal_close_cb); 256 else server->sigint_closed = true; 257 258 if (!uv_is_closing((uv_handle_t *)&server->sigterm_handle)) 259 uv_close((uv_handle_t *)&server->sigterm_handle, server_signal_close_cb); 260 else server->sigterm_closed = true; 261 262 server_maybe_finish_stop(server); 263} 264 265static void server_signal_cb(uv_signal_t *handle, int signum) { 266 server_runtime_t *server = (server_runtime_t *)handle->data; 267 server_begin_stop(server, false); 268} 269 270static ant_value_t server_headers_from_parsed(ant_t *js, const ant_http1_parsed_request_t *parsed) { 271 ant_value_t headers = headers_create_empty(js); 272 const ant_http_header_t *hdr = NULL; 273 274 if (is_err(headers)) return headers; 275 for (hdr = parsed->headers; hdr; hdr = hdr->next) { 276 ant_value_t step = headers_append_literal(js, headers, hdr->name, hdr->value); 277 if (is_err(step)) return step; 278 } 279 return headers; 280} 281 282static ant_value_t server_call_fetch(server_runtime_t *server, ant_value_t request_obj) { 283 ant_t *js = server->js; 284 ant_value_t args[2] = { request_obj, server->server_ctx }; 285 ant_value_t saved_this = js->this_val; 286 ant_value_t result = js_mkundef(); 287 288 js->this_val = server->export_obj; 289 if (vtype(server->fetch_fn) == T_CFUNC) result = js_as_cfunc(server->fetch_fn)(js, args, 2); 290 else result = sv_vm_call(js->vm, js, server->fetch_fn, server->export_obj, args, 2, NULL, false); 291 js->this_val = saved_this; 292 293 return result; 294} 295 296static ant_value_t server_abort_signal_task(ant_t *js, ant_value_t *args, int nargs) { 297 ant_value_t payload = js_get_slot(js->current_func, SLOT_DATA); 298 ant_value_t signal = 0; ant_value_t reason = 0; 299 if (vtype(payload) != T_OBJ) return js_mkundef(); 300 301 signal = js_get(js, payload, "signal"); 302 reason = js_get(js, payload, "reason"); 303 304 if (abort_signal_is_signal(signal) && !abort_signal_is_aborted(signal)) 305 signal_do_abort(js, signal, reason); 306 307 return js_mkundef(); 308} 309 310static void server_queue_abort_signal(ant_t *js, ant_value_t signal, ant_value_t reason) { 311 ant_value_t callback = 0; 312 ant_value_t payload = 0; 313 314 if (!abort_signal_is_signal(signal) || abort_signal_is_aborted(signal)) return; 315 payload = js_mkobj(js); 316 if (is_err(payload)) return; 317 318 js_set(js, payload, "signal", signal); 319 js_set(js, payload, "reason", reason); 320 callback = js_heavy_mkfun(js, server_abort_signal_task, payload); 321 322 queue_microtask(js, callback); 323} 324 325static void server_abort_request(server_request_t *req, const char *message) { 326 ant_t *js = NULL; 327 328 ant_value_t signal = 0; ant_value_t reason = 0; ant_value_t abort_reason = 0; 329 if (!req || !req->server || !is_object_type(req->request_obj)) return; 330 331 js = req->server->js; 332 abort_reason = js_get_slot(req->request_obj, SLOT_REQUEST_ABORT_REASON); 333 if (vtype(abort_reason) != T_UNDEF) return; 334 335 reason = make_dom_exception(js, 336 message ? message : "The request was aborted", "AbortError" 337 ); 338 339 js_set_slot_wb(js, req->request_obj, SLOT_REQUEST_ABORT_REASON, reason); 340 signal = js_get_slot(req->request_obj, SLOT_REQUEST_SIGNAL); 341 342 if (!abort_signal_is_signal(signal) || abort_signal_is_aborted(signal)) return; 343 server_queue_abort_signal(js, signal, reason); 344} 345 346static bool server_response_chunk(server_request_t *req, ant_value_t value, const uint8_t **out, size_t *len) { 347 blob_data_t *blob = NULL; 348 349 if (vtype(value) == T_STR) { 350 *out = (const uint8_t *)js_getstr(req->server->js, value, len); 351 if (!*out) *len = 0; 352 return true; 353 } 354 355 if (is_object_type(value) && blob_is_blob(req->server->js, value)) { 356 blob = blob_get_data(value); 357 *out = blob ? blob->data : NULL; 358 *len = blob ? blob->size : 0; 359 return true; 360 } 361 362 return buffer_source_get_bytes(req->server->js, value, out, len); 363} 364 365static void server_cancel_response_body(server_request_t *req, const char *message) { 366 ant_t *js = NULL; 367 368 ant_value_t stream = 0; 369 ant_value_t reason = 0; 370 ant_value_t result = 0; 371 372 if (!req || !req->server || !is_object_type(req->response_obj)) return; 373 374 js = req->server->js; 375 stream = js_get_slot(req->response_obj, SLOT_RESPONSE_BODY_STREAM); 376 if (!rs_is_stream(stream)) return; 377 378 reason = make_dom_exception( 379 js, message ? message : "The response body was canceled", 380 "AbortError" 381 ); 382 383 result = readable_stream_cancel(js, stream, reason); 384 if (vtype(result) == T_PROMISE) promise_mark_handled(result); 385} 386 387static void server_start_stream_read(server_request_t *req); 388static void server_on_read(ant_conn_t *conn, ssize_t nread, void *user_data); 389static void server_write_cb(ant_conn_t *conn, int status, void *user_data); 390 391static void server_on_deferred_drain(uv_timer_t *handle) { 392 server_conn_state_t *cs = handle ? (server_conn_state_t *)handle->data : NULL; 393 394 if (!cs) return; 395 cs->drain_scheduled = false; 396 397 if (!cs->conn || cs->active_req) return; 398 if (ant_conn_is_closing(cs->conn)) return; 399 if (ant_conn_buffer_len(cs->conn) == 0) return; 400 401 server_on_read(cs->conn, (ssize_t)ant_conn_buffer_len(cs->conn), cs->server); 402} 403 404static void server_on_drain_timer_close(uv_handle_t *handle) { 405 server_conn_state_t *cs = handle ? (server_conn_state_t *)handle->data : NULL; 406 407 if (!cs) return; 408 cs->drain_timer_closed = true; 409 cs->drain_scheduled = false; 410 server_conn_state_maybe_free(cs); 411} 412 413static void server_schedule_drain(server_conn_state_t *cs) { 414 if (!cs || !cs->conn) return; 415 if (cs->drain_scheduled) return; 416 417 cs->drain_scheduled = true; 418 if (uv_timer_start(&cs->drain_timer, server_on_deferred_drain, 0, 0) != 0) 419 cs->drain_scheduled = false; 420} 421 422static bool server_queue_write(ant_conn_t *conn, server_request_t *req, char *data, size_t len, server_write_action_t action) { 423 server_write_req_t *wr = calloc(1, sizeof(*wr)); 424 int rc = 0; 425 426 if (!conn || ant_conn_is_closing(conn)) { 427 free(data); 428 return false; 429 } 430 431 if (!wr) { 432 free(data); 433 return false; 434 } 435 436 wr->request = req; 437 wr->conn = conn; 438 wr->action = action; 439 if (req) server_request_retain(req); 440 441 rc = ant_conn_write(conn, data, len, server_write_cb, wr); 442 if (rc != 0) { 443 if (req) server_request_release(req); 444 free(wr); 445 ant_conn_close(conn); 446 return false; 447 } 448 449 return true; 450} 451 452static bool server_queue_final_chunk(server_request_t *req, server_write_action_t action) { 453 ant_http1_buffer_t buf; 454 char *out = NULL; 455 size_t out_len = 0; 456 457 if (!req || !req->conn || ant_conn_is_closing(req->conn)) return false; 458 459 ant_http1_buffer_init(&buf); 460 if (!ant_http1_write_final_chunk(&buf)) { 461 ant_http1_buffer_free(&buf); 462 ant_conn_close(req->conn); 463 return false; 464 } 465 466 out = ant_http1_buffer_take(&buf, &out_len); 467 return server_queue_write(req->conn, req, out, out_len, action); 468} 469 470static void server_send_basic_response( 471 ant_conn_t *conn, int status, const char *status_text, 472 const char *content_type, const uint8_t *body, size_t body_len 473) { 474 ant_http1_buffer_t buf; 475 char *out = NULL; 476 size_t out_len = 0; 477 478 ant_http1_buffer_init(&buf); 479 if (!ant_http1_write_basic_response(&buf, status, status_text, content_type, body, body_len, false)) { 480 ant_http1_buffer_free(&buf); 481 ant_conn_close(conn); 482 return; 483 } 484 485 out = ant_http1_buffer_take(&buf, &out_len); 486 server_queue_write(conn, NULL, out, out_len, SERVER_WRITE_CLOSE_CLIENT); 487} 488 489static inline void server_send_text_response( 490 ant_conn_t *conn, 491 int status, 492 const char *status_text, 493 const char *body 494) { 495 if (!body) body = ""; 496 server_send_basic_response( 497 conn, status, 498 status_text, 499 "text/plain;charset=UTF-8", 500 (const uint8_t *)body, 501 strlen(body) 502 ); 503} 504 505static inline void server_send_internal_error(ant_conn_t *conn, const char *body) { 506 server_send_text_response( 507 conn, 500, 508 "Internal Server Error", 509 body ? body : "Internal Server Error" 510 ); 511} 512 513static void server_finish_with_response(server_request_t *req, ant_value_t response_obj) { 514 response_data_t *resp = response_get_data(response_obj); 515 ant_value_t headers = response_get_headers(response_obj); 516 517 ant_value_t stream = js_get_slot(response_obj, SLOT_RESPONSE_BODY_STREAM); 518 bool body_is_stream = resp && resp->body_is_stream && rs_is_stream(stream); 519 bool head_only = false; 520 521 const char *status_text = NULL; 522 ant_http1_buffer_t buf; 523 524 char *out = NULL; 525 size_t out_len = 0; 526 527 if (!req->conn || ant_conn_is_closing(req->conn)) return; 528 if (!resp) { 529 server_send_internal_error(req->conn, "Invalid Response"); 530 return; 531 } 532 533 req->response_obj = response_obj; 534 req->response_started = true; 535 head_only = strcasecmp(request_get_data(req->request_obj)->method, "HEAD") == 0; 536 status_text = (resp->status_text && resp->status_text[0]) ? resp->status_text : ant_http1_default_status_text(resp->status); 537 538 ant_http1_buffer_init(&buf); 539 if (!ant_http1_write_response_head(&buf, resp->status, status_text, headers, body_is_stream, resp->body_size, req->keep_alive)) { 540 ant_http1_buffer_free(&buf); 541 ant_conn_close(req->conn); 542 return; 543 } 544 545 if (!body_is_stream && !head_only && resp->body_size > 0) 546 ant_http1_buffer_append(&buf, resp->body_data, resp->body_size); 547 548 if (buf.failed) { 549 ant_http1_buffer_free(&buf); 550 ant_conn_close(req->conn); 551 return; 552 } 553 554 out = ant_http1_buffer_take(&buf, &out_len); 555 ant_conn_set_timeout_ms(req->conn, req->server->idle_timeout_ms); 556 557 if (body_is_stream && head_only) server_cancel_response_body( 558 req, "The response body was canceled for a HEAD request" 559 ); 560 561 server_queue_write( 562 req->conn, 563 req, out, out_len, 564 body_is_stream && !head_only 565 ? SERVER_WRITE_STREAM_READ 566 : (req->keep_alive ? SERVER_WRITE_KEEP_ALIVE : SERVER_WRITE_CLOSE_CLIENT) 567 ); 568} 569 570static ant_value_t server_on_response_reject(ant_t *js, ant_value_t *args, int nargs) { 571 server_request_t *req = server_current_request(js); 572 ant_value_t reason = (nargs > 0) ? args[0] : js_mkundef(); 573 const char *msg = NULL; 574 575 if (!req) return js_mkundef(); 576 req->response_promise = js_mkundef(); 577 578 if (req->conn && !ant_conn_is_closing(req->conn)) { 579 msg = js_str(js, reason); 580 server_send_internal_error(req->conn, msg); 581 } 582 583 server_request_release(req); 584 return js_mkundef(); 585} 586 587static ant_value_t server_on_response_fulfill(ant_t *js, ant_value_t *args, int nargs) { 588 server_request_t *req = server_current_request(js); 589 ant_value_t value = (nargs > 0) ? args[0] : js_mkundef(); 590 591 if (!req) return js_mkundef(); 592 req->response_promise = js_mkundef(); 593 594 if (!response_get_data(value)) { 595 if (req->conn && !ant_conn_is_closing(req->conn)) 596 server_send_internal_error(req->conn, "fetch handler must return a Response"); 597 } else if (req->conn && !ant_conn_is_closing(req->conn)) { 598 server_finish_with_response(req, value); 599 } 600 601 server_request_release(req); 602 return js_mkundef(); 603} 604 605static void server_handle_fetch_result(server_request_t *req, ant_value_t result) { 606 ant_t *js = req->server->js; 607 608 if (is_err(result)) { 609 ant_value_t reason = server_exception_reason(js, result); 610 const char *msg = js_str(js, reason); 611 server_send_internal_error(req->conn, msg); 612 return; 613 } 614 615 if (vtype(result) == T_PROMISE) { 616 ant_value_t fulfill = server_mkreqfun(js, server_on_response_fulfill, req); 617 ant_value_t reject = server_mkreqfun(js, server_on_response_reject, req); 618 ant_value_t then_result = 0; 619 620 req->response_promise = result; 621 server_request_retain(req); 622 then_result = js_promise_then(js, result, fulfill, reject); 623 promise_mark_handled(then_result); 624 return; 625 } 626 627 if (!response_get_data(result)) { 628 server_send_internal_error(req->conn, "fetch handler must return a Response"); 629 return; 630 } 631 632 server_finish_with_response(req, result); 633} 634 635static ant_value_t server_stream_read_reject(ant_t *js, ant_value_t *args, int nargs) { 636 server_request_t *req = server_current_request(js); 637 if (!req) return js_mkundef(); 638 639 req->response_read_promise = js_mkundef(); 640 server_queue_final_chunk(req, SERVER_WRITE_CLOSE_CLIENT); 641 server_request_release(req); 642 643 return js_mkundef(); 644} 645 646static ant_value_t server_stream_read_fulfill(ant_t *js, ant_value_t *args, int nargs) { 647 server_request_t *req = server_current_request(js); 648 ant_value_t result = (nargs > 0) ? args[0] : js_mkundef(); 649 650 ant_value_t done = 0; 651 ant_value_t value = 0; 652 653 const uint8_t *chunk = NULL; 654 size_t chunk_len = 0; 655 656 ant_http1_buffer_t buf; 657 char *out = NULL; 658 size_t out_len = 0; 659 660 if (!req) return js_mkundef(); 661 req->response_read_promise = js_mkundef(); 662 663 if (!req->conn || ant_conn_is_closing(req->conn)) { 664 server_request_release(req); 665 return js_mkundef(); 666 } 667 668 done = js_get(js, result, "done"); 669 if (done == js_true) { 670 ant_conn_set_timeout_ms(req->conn, req->server->idle_timeout_ms); 671 server_queue_final_chunk( 672 req, req->keep_alive 673 ? SERVER_WRITE_KEEP_ALIVE 674 : SERVER_WRITE_CLOSE_CLIENT 675 ); 676 677 server_request_release(req); 678 return js_mkundef(); 679 } 680 681 value = js_get(js, result, "value"); 682 if (!server_response_chunk(req, value, &chunk, &chunk_len)) { 683 fprintf(stderr, "Response body stream chunk must be a string, Blob, ArrayBuffer, DataView, or TypedArray\n"); 684 server_cancel_response_body(req, "Invalid response body chunk"); 685 server_queue_final_chunk(req, SERVER_WRITE_CLOSE_CLIENT); 686 server_request_release(req); 687 return js_mkundef(); 688 } 689 690 ant_http1_buffer_init(&buf); 691 if (!ant_http1_write_chunk(&buf, chunk, chunk_len)) { 692 ant_http1_buffer_free(&buf); 693 ant_conn_close(req->conn); 694 server_request_release(req); 695 return js_mkundef(); 696 } 697 698 out = ant_http1_buffer_take(&buf, &out_len); 699 ant_conn_set_timeout_ms(req->conn, req->server->idle_timeout_ms); 700 701 server_queue_write(req->conn, req, out, out_len, SERVER_WRITE_STREAM_READ); 702 server_request_release(req); 703 704 return js_mkundef(); 705} 706 707static void server_start_stream_read(server_request_t *req) { 708 ant_t *js = req->server->js; 709 710 ant_value_t next_p = 0; 711 ant_value_t fulfill = 0; 712 ant_value_t reject = 0; 713 ant_value_t then_result = 0; 714 715 if (!req->conn || ant_conn_is_closing(req->conn)) return; 716 if (!is_object_type(req->response_reader)) return; 717 718 next_p = rs_default_reader_read(js, req->response_reader); 719 req->response_read_promise = next_p; 720 fulfill = server_mkreqfun(js, server_stream_read_fulfill, req); 721 reject = server_mkreqfun(js, server_stream_read_reject, req); 722 723 server_request_retain(req); 724 then_result = js_promise_then(js, next_p, fulfill, reject); 725 promise_mark_handled(then_result); 726} 727 728static bool server_request_ensure_reader(server_request_t *req) { 729 ant_t *js; 730 ant_value_t reader_args[1]; 731 ant_value_t saved; 732 733 if (!req || !is_object_type(req->response_obj)) return false; 734 if (vtype(req->response_reader) != T_UNDEF) return true; 735 736 js = req->server->js; 737 reader_args[0] = js_get_slot(req->response_obj, SLOT_RESPONSE_BODY_STREAM); 738 739 saved = js->new_target; 740 js->new_target = g_reader_proto; 741 req->response_reader = js_rs_reader_ctor(js, reader_args, 1); 742 js->new_target = saved; 743 744 return !is_err(req->response_reader); 745} 746 747 748static void server_write_cb(ant_conn_t *conn, int status, void *user_data) { 749 server_write_req_t *wr = (server_write_req_t *)user_data; 750 server_request_t *req = wr->request; 751 server_conn_state_t *cs = conn ? (server_conn_state_t *)ant_conn_get_user_data(conn) : NULL; 752 753 if (status < 0 && conn && !ant_conn_is_closing(conn)) 754 ant_conn_close(conn); 755 756 if (status == 0 && conn && !ant_conn_is_closing(conn)) { 757 switch (wr->action) { 758 case SERVER_WRITE_STREAM_READ: 759 if (!server_request_ensure_reader(req)) { 760 ant_conn_close(conn); 761 break; 762 } 763 server_start_stream_read(req); 764 break; 765 766 case SERVER_WRITE_KEEP_ALIVE: 767 if (cs && req) { 768 ant_conn_consume(conn, req->consumed_len); 769 ant_http1_conn_parser_reset(&cs->parser); 770 cs->active_req = NULL; 771 ant_conn_set_timeout_ms(conn, cs->server->idle_timeout_ms); 772 ant_conn_resume_read(conn); 773 server_request_release(req); 774 if (ant_conn_buffer_len(conn) > 0) server_schedule_drain(cs); 775 } 776 break; 777 778 case SERVER_WRITE_CLOSE_CLIENT: 779 ant_conn_close(conn); 780 break; 781 782 default: break; 783 }} 784 785 if (req) server_request_release(req); 786 free(wr); 787} 788 789static ant_value_t server_request_ip(ant_t *js, ant_value_t *args, int nargs) { 790 server_runtime_t *server = server_current_runtime(js); 791 server_request_t *req = NULL; 792 ant_value_t out = 0; 793 794 if (!server || nargs < 1) return js_mknull(); 795 req = server_find_request(server, args[0]); 796 if (!req || !req->conn || !ant_conn_has_remote_addr(req->conn)) return js_mknull(); 797 798 out = js_mkobj(js); 799 js_set(js, out, "address", js_mkstr(js, ant_conn_remote_addr(req->conn), strlen(ant_conn_remote_addr(req->conn)))); 800 js_set(js, out, "port", js_mknum(ant_conn_remote_port(req->conn))); 801 return out; 802} 803 804static ant_value_t server_timeout(ant_t *js, ant_value_t *args, int nargs) { 805 server_runtime_t *server = server_current_runtime(js); 806 server_request_t *req = NULL; 807 int timeout = 0; 808 809 if (!server || nargs < 2) return js_mkundef(); 810 req = server_find_request(server, args[0]); 811 if (!req || !req->conn) return js_mkundef(); 812 813 timeout = (int)js_getnum(args[1]); 814 ant_conn_set_timeout_ms(req->conn, (uint64_t)timeout * 1000ULL); 815 816 return js_mkundef(); 817} 818 819static ant_value_t server_stop(ant_t *js, ant_value_t *args, int nargs) { 820 server_runtime_t *server = server_current_runtime(js); 821 stop_waiter_t *waiter = NULL; 822 ant_value_t promise = js_mkpromise(js); 823 bool force = (nargs > 0 && js_truthy(js, args[0])); 824 825 if (!server) { 826 js_resolve_promise(js, promise, js_mkundef()); 827 return promise; 828 } 829 830 waiter = calloc(1, sizeof(*waiter)); 831 if (!waiter) { 832 js_reject_promise(js, promise, js_mkerr(js, "out of memory")); 833 return promise; 834 } 835 836 waiter->promise = promise; 837 waiter->next = server->stop_waiters; 838 server->stop_waiters = waiter; 839 server_begin_stop(server, force); 840 return promise; 841} 842 843static void server_process_client_request( 844 ant_conn_t *conn, 845 ant_http1_parsed_request_t *parsed, 846 size_t consumed_len 847) { 848 server_conn_state_t *cs = (server_conn_state_t *)ant_conn_get_user_data(conn); 849 server_runtime_t *server = cs ? cs->server : NULL; 850 server_request_t *req = NULL; 851 852 ant_t *js = NULL; 853 ant_value_t headers = 0; 854 ant_value_t request_obj = 0; 855 ant_value_t result = 0; 856 bool keep_alive = false; 857 858 if (!server || !cs) { 859 ant_http1_free_parsed_request(parsed); 860 ant_conn_close(conn); 861 return; 862 } 863 864 js = server->js; 865 req = &cs->request; 866 keep_alive = parsed->keep_alive; 867 headers = server_headers_from_parsed(js, parsed); 868 869 if (is_err(headers)) { 870 ant_http1_free_parsed_request(parsed); 871 server_send_internal_error(conn, NULL); 872 return; 873 } 874 875 request_obj = request_create_server( 876 js, 877 parsed->method, 878 parsed->target, 879 parsed->absolute_target, 880 parsed->host, 881 server->hostname, 882 server->port, 883 headers, 884 parsed->body, 885 parsed->body_len, 886 parsed->content_type 887 ); 888 ant_http1_free_parsed_request(parsed); 889 890 if (is_err(request_obj)) { 891 server_send_internal_error(conn, NULL); 892 return; 893 } 894 895 server_request_reset(req); 896 req->server = server; 897 req->conn_state = cs; 898 req->conn = conn; 899 req->request_obj = request_obj; 900 req->consumed_len = consumed_len; 901 req->keep_alive = keep_alive; 902 req->refs = 1; 903 req->next = server->requests; 904 server->requests = req; 905 cs->active_req = req; 906 ant_conn_pause_read(conn); 907 ant_conn_set_timeout_ms(conn, server->request_timeout_ms); 908 909 result = server_call_fetch(server, request_obj); 910 server_handle_fetch_result(req, result); 911} 912 913static void server_on_read(ant_conn_t *conn, ssize_t nread, void *user_data) { 914 server_conn_state_t *cs = (server_conn_state_t *)ant_conn_get_user_data(conn); 915 ant_http1_parsed_request_t parsed = {0}; 916 ant_http1_parse_result_t parse_result = ANT_HTTP1_PARSE_INCOMPLETE; 917 size_t consumed = 0; 918 919 if (!conn || !cs) return; 920 if (cs->active_req) return; 921 if (ant_conn_buffer_len(conn) == 0) return; 922 923 ant_conn_set_timeout_ms(conn, cs->server->request_timeout_ms); 924 parse_result = ant_http1_conn_parser_execute( 925 &cs->parser, 926 ant_conn_buffer(conn), 927 ant_conn_buffer_len(conn), 928 &parsed, 929 &consumed 930 ); 931 932 if (parse_result == ANT_HTTP1_PARSE_ERROR) { 933 ant_http1_free_parsed_request(&parsed); 934 server_send_text_response(conn, 400, "Bad Request", "Bad Request"); 935 return; 936 } 937 938 if (parse_result != ANT_HTTP1_PARSE_OK) return; 939 server_process_client_request(conn, &parsed, consumed); 940} 941 942static void server_on_end(ant_conn_t *conn, void *user_data) { 943 if (conn) ant_conn_close(conn); 944} 945 946static void server_on_conn_close(ant_conn_t *conn, void *user_data) { 947 server_runtime_t *server = (server_runtime_t *)user_data; 948 server_conn_state_t *cs = (server_conn_state_t *)ant_conn_get_user_data(conn); 949 950 if (cs) { 951 ant_conn_set_user_data(conn, NULL); 952 cs->conn = NULL; 953 ant_http1_conn_parser_free(&cs->parser); 954 if (!uv_is_closing((uv_handle_t *)&cs->drain_timer)) 955 uv_close((uv_handle_t *)&cs->drain_timer, server_on_drain_timer_close); 956 if (cs->active_req) { 957 server_abort_request(cs->active_req, "Client disconnected"); 958 server_cancel_response_body(cs->active_req, "Client disconnected"); 959 cs->active_req->conn = NULL; 960 cs->active_req = NULL; 961 server_request_release(&cs->request); 962 cs = NULL; 963 } 964 if (cs) server_conn_state_maybe_free(cs); 965 } 966 967 server_maybe_finish_stop(server); 968} 969 970static void server_on_listener_close(ant_listener_t *listener, void *user_data) { 971 server_maybe_finish_stop((server_runtime_t *)user_data); 972} 973 974static void server_on_accept(ant_listener_t *listener, ant_conn_t *conn, void *user_data) { 975 server_runtime_t *server = (server_runtime_t *)user_data; 976 server_conn_state_t *cs = NULL; 977 978 (void)listener; 979 if (!conn || !server) return; 980 981 cs = calloc(1, sizeof(*cs)); 982 if (!cs) { 983 ant_conn_close(conn); 984 return; 985 } 986 987 cs->server = server; 988 cs->conn = conn; 989 cs->drain_timer_closed = true; 990 cs->request.server = server; 991 cs->request.conn_state = cs; 992 server_request_reset(&cs->request); 993 994 if (uv_timer_init(server->loop, &cs->drain_timer) != 0) { 995 free(cs); 996 ant_conn_close(conn); 997 return; 998 } 999 1000 cs->drain_timer.data = cs; 1001 cs->drain_timer_closed = false; 1002 ant_http1_conn_parser_init(&cs->parser); 1003 ant_conn_set_user_data(conn, cs); 1004 ant_conn_set_no_delay(conn, true); 1005} 1006 1007static bool server_export_has_fetch_handler(ant_t *js, ant_value_t default_export, bool *looks_like_config) { 1008 ant_value_t fetch = 0; 1009 1010 if (looks_like_config) *looks_like_config = false; 1011 if (!is_object_type(default_export)) return false; 1012 1013 fetch = js_get(js, default_export, "fetch"); 1014 if (is_callable(fetch)) return true; 1015 1016 if (looks_like_config) { 1017 ant_value_t port = js_get(js, default_export, "port"); 1018 ant_value_t hostname = js_get(js, default_export, "hostname"); 1019 ant_value_t idle_timeout = js_get(js, default_export, "idleTimeout"); 1020 ant_value_t request_timeout = js_get(js, default_export, "requestTimeout"); 1021 ant_value_t unix_path = js_get(js, default_export, "unix"); 1022 ant_value_t tls = js_get(js, default_export, "tls"); 1023 1024 *looks_like_config = 1025 vtype(fetch) != T_UNDEF || 1026 vtype(port) != T_UNDEF || 1027 vtype(hostname) != T_UNDEF || 1028 vtype(idle_timeout) != T_UNDEF || 1029 vtype(request_timeout) != T_UNDEF || 1030 vtype(unix_path) != T_UNDEF || 1031 vtype(tls) != T_UNDEF; 1032 } 1033 1034 return false; 1035} 1036 1037int server_maybe_start_from_export(ant_t *js, ant_value_t default_export) { 1038 bool looks_like_server = false; 1039 ant_value_t server_result = 0; 1040 const char *error = NULL; 1041 1042 if (!server_export_has_fetch_handler(js, default_export, &looks_like_server)) { 1043 if (!looks_like_server) return EXIT_SUCCESS; 1044 error = "Module does not export a fetch handler"; 1045 goto fail; 1046 } 1047 1048 server_result = server_start_from_export(js, default_export); 1049 if (is_err(server_result)) { 1050 error = js_str(js, server_result); 1051 goto fail; 1052 } 1053 1054 return EXIT_SUCCESS; 1055 1056fail: 1057 fprintf(stderr, "%s\n", error); 1058 return EXIT_FAILURE; 1059} 1060 1061ant_value_t server_start_from_export(ant_t *js, ant_value_t default_export) { 1062 server_runtime_t *server = NULL; 1063 1064 ant_value_t port_v = 0; 1065 ant_value_t hostname_v = 0; 1066 ant_value_t idle_timeout_v = 0; 1067 ant_value_t request_timeout_v = 0; 1068 ant_value_t unix_v = 0; 1069 ant_value_t tls_v = 0; 1070 1071 ant_listener_callbacks_t callbacks = {0}; 1072 int rc = 0; 1073 1074 if (g_server) return js_mkerr(js, "server is already running"); 1075 if (!is_object_type(default_export)) return js_mkerr_typed(js, JS_ERR_TYPE, "Module does not export a fetch handler"); 1076 1077 server = malloc(sizeof(*server)); 1078 if (!server) return js_mkerr(js, "out of memory"); 1079 1080 *server = (server_runtime_t){ 1081 .js = js, 1082 .export_obj = default_export, 1083 .fetch_fn = js_get(js, default_export, "fetch"), 1084 .hostname = strdup("0.0.0.0"), 1085 .unix_path = NULL, 1086 .port = 3000, 1087 .request_timeout_ms = 30000, 1088 .idle_timeout_ms = 30000, 1089 .loop = uv_default_loop(), 1090 }; 1091 1092 if (!server->hostname) { 1093 free(server); 1094 return js_mkerr(js, "out of memory"); 1095 } 1096 1097 unix_v = js_get(js, default_export, "unix"); 1098 tls_v = js_get(js, default_export, "tls"); 1099 1100 if (vtype(unix_v) != T_UNDEF && vtype(unix_v) != T_NULL) { 1101 if (vtype(unix_v) != T_STR) { 1102 free(server->hostname); 1103 free(server); 1104 return js_mkerr_typed(js, JS_ERR_TYPE, "server unix must be a string"); 1105 } 1106 1107 server->unix_path = strdup(js_getstr(js, unix_v, NULL)); 1108 if (!server->unix_path) { 1109 free(server->hostname); 1110 free(server); 1111 return js_mkerr(js, "out of memory"); 1112 } 1113 } 1114 1115 if (vtype(tls_v) != T_UNDEF && vtype(tls_v) != T_NULL) { 1116 free(server->unix_path); 1117 free(server->hostname); 1118 free(server); 1119 return js_mkerr_typed(js, JS_ERR_TYPE, "tls server config is not implemented yet"); 1120 } 1121 1122 port_v = js_get(js, default_export, "port"); 1123 hostname_v = js_get(js, default_export, "hostname"); 1124 idle_timeout_v = js_get(js, default_export, "idleTimeout"); 1125 request_timeout_v = js_get(js, default_export, "requestTimeout"); 1126 1127 if (vtype(port_v) != T_UNDEF && vtype(port_v) != T_NULL) { 1128 if (vtype(port_v) != T_NUM) { 1129 free(server->unix_path); 1130 free(server->hostname); 1131 free(server); 1132 return js_mkerr_typed(js, JS_ERR_TYPE, "server port must be a number"); 1133 } 1134 server->port = (int)js_getnum(port_v); 1135 if (server->port < 0 || server->port > 65535) { 1136 free(server->unix_path); 1137 free(server->hostname); 1138 free(server); 1139 return js_mkerr_typed(js, JS_ERR_RANGE, "server port must be between 0 and 65535"); 1140 } 1141 } 1142 1143 if (vtype(hostname_v) != T_UNDEF && vtype(hostname_v) != T_NULL) { 1144 char *next_hostname = NULL; 1145 if (vtype(hostname_v) != T_STR) { 1146 free(server->unix_path); 1147 free(server->hostname); 1148 free(server); 1149 return js_mkerr_typed(js, JS_ERR_TYPE, "server hostname must be a string"); 1150 } 1151 next_hostname = strdup(js_getstr(js, hostname_v, NULL)); 1152 if (!next_hostname) { 1153 free(server->unix_path); 1154 free(server->hostname); 1155 free(server); 1156 return js_mkerr(js, "out of memory"); 1157 } 1158 free(server->hostname); 1159 server->hostname = next_hostname; 1160 } 1161 1162 if (vtype(idle_timeout_v) != T_UNDEF && vtype(idle_timeout_v) != T_NULL) { 1163 double timeout = 0; 1164 if (vtype(idle_timeout_v) != T_NUM) { 1165 free(server->unix_path); 1166 free(server->hostname); 1167 free(server); 1168 return js_mkerr_typed(js, JS_ERR_TYPE, "server idleTimeout must be a number"); 1169 } 1170 timeout = js_getnum(idle_timeout_v); 1171 if (timeout < 0) { 1172 free(server->unix_path); 1173 free(server->hostname); 1174 free(server); 1175 return js_mkerr_typed(js, JS_ERR_RANGE, "server idleTimeout must be >= 0"); 1176 } 1177 server->idle_timeout_ms = (uint64_t)(timeout * 1000.0); 1178 } 1179 1180 if (vtype(request_timeout_v) != T_UNDEF && vtype(request_timeout_v) != T_NULL) { 1181 double timeout = 0; 1182 if (vtype(request_timeout_v) != T_NUM) { 1183 free(server->unix_path); 1184 free(server->hostname); 1185 free(server); 1186 return js_mkerr_typed(js, JS_ERR_TYPE, "server requestTimeout must be a number"); 1187 } 1188 1189 timeout = js_getnum(request_timeout_v); 1190 if (timeout < 0) { 1191 free(server->unix_path); 1192 free(server->hostname); 1193 free(server); 1194 return js_mkerr_typed(js, JS_ERR_RANGE, "server requestTimeout must be >= 0"); 1195 } 1196 1197 server->request_timeout_ms = (uint64_t)(timeout * 1000.0); 1198 } 1199 1200 uv_signal_init(server->loop, &server->sigint_handle); 1201 uv_signal_init(server->loop, &server->sigterm_handle); 1202 server->sigint_handle.data = server; 1203 server->sigterm_handle.data = server; 1204 1205 callbacks.on_accept = server_on_accept; 1206 callbacks.on_read = server_on_read; 1207 callbacks.on_end = server_on_end; 1208 callbacks.on_conn_close = server_on_conn_close; 1209 callbacks.on_listener_close = server_on_listener_close; 1210 1211 if (server->unix_path) { 1212 rc = ant_listener_listen_pipe( 1213 &server->listener, server->loop, 1214 server->unix_path, 1215 128, server->idle_timeout_ms, &callbacks, server 1216 ); 1217 } else { 1218 rc = ant_listener_listen_tcp( 1219 &server->listener, server->loop, 1220 server->hostname, server->port, 1221 128, server->idle_timeout_ms, &callbacks, server 1222 ); 1223 } 1224 1225 if (rc != 0) { 1226 free(server->unix_path); 1227 free(server->hostname); 1228 free(server); 1229 return js_mkerr_typed(js, JS_ERR_TYPE, "%s", uv_strerror(rc)); 1230 } 1231 1232 server->port = ant_listener_port(&server->listener); 1233 uv_signal_start(&server->sigint_handle, server_signal_cb, SIGINT); 1234 uv_signal_start(&server->sigterm_handle, server_signal_cb, SIGTERM); 1235 1236 server->server_ctx = js_mkobj(js); 1237 js_set(js, server->server_ctx, "requestIP", server_mkruntimefun(js, server_request_ip, server)); 1238 js_set(js, server->server_ctx, "timeout", server_mkruntimefun(js, server_timeout, server)); 1239 js_set(js, server->server_ctx, "stop", server_mkruntimefun(js, server_stop, server)); 1240 1241 g_server = server; 1242 return js_mkundef(); 1243} 1244 1245void gc_mark_server(ant_t *js, gc_mark_fn mark) { 1246 server_request_t *req = NULL; 1247 stop_waiter_t *waiter = NULL; 1248 1249 if (!g_server) return; 1250 mark(js, g_server->export_obj); 1251 mark(js, g_server->fetch_fn); 1252 mark(js, g_server->server_ctx); 1253 1254 for (req = g_server->requests; req; req = req->next) { 1255 mark(js, req->request_obj); 1256 mark(js, req->response_obj); 1257 mark(js, req->response_promise); 1258 mark(js, req->response_reader); 1259 mark(js, req->response_read_promise); 1260 } 1261 1262 for (waiter = g_server->stop_waiters; waiter; waiter = waiter->next) 1263 mark(js, waiter->promise); 1264}