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.

add the brand new server.c!!!

thank god finally that old one is gone

+2017 -151
+16 -12
examples/demo/ephemeral_server.js
··· 3 3 4 4 console.log('starting on http://localhost:3000'); 5 5 6 - Ant.serve(3000, (ctx, server) => { 7 - if (ctx.req.uri.includes('favicon')) return; 6 + export default { 7 + fetch(req, server) { 8 + if (new URL(req.url).pathname.includes('favicon')) { 9 + return new Response(null, { status: 404 }); 10 + } 8 11 9 - count++; 10 - ctx.res.json({ 11 - request: count, 12 - remaining: Math.max(0, MAX_REQUESTS - count), 13 - port: server.port 14 - }); 12 + count++; 15 13 16 - if (count === MAX_REQUESTS) { 17 - console.log('10 requests served, stopping'); 18 - server.stop(); 14 + if (count === MAX_REQUESTS) { 15 + console.log('10 requests served, stopping'); 16 + server.stop(); 17 + } 18 + 19 + return Response.json({ 20 + request: count, 21 + remaining: Math.max(0, MAX_REQUESTS - count) 22 + }); 19 23 } 20 - }); 24 + };
+5 -3
examples/npm/hono/src/index.ts
··· 1 1 import { Hono } from 'hono'; 2 + import { logger } from 'hono/logger'; 2 3 3 4 const app = new Hono(); 4 5 5 - app.get('/', c => { 6 - return c.text('Hello ๐Ÿœ!'); 7 - }); 6 + app.use(logger()); 7 + app.get('/', c => c.text('Hello ๐Ÿœ!')); 8 + 9 + console.log('started on http://localhost:3000'); 8 10 9 11 export default app;
-1
examples/spec/ant.js
··· 48 48 test('stats is function', typeof Ant.stats, 'function'); 49 49 test('raw is object', typeof Ant.raw, 'object'); 50 50 test('raw.typeof is function', typeof Ant.raw.typeof, 'function'); 51 - test('serve is function', typeof Ant.serve, 'function'); 52 51 test('sleep is function', typeof Ant.sleep, 'function'); 53 52 test('msleep is function', typeof Ant.msleep, 'function'); 54 53 test('usleep is function', typeof Ant.usleep, 'function');
+37
include/http/http1_parser.h
··· 1 + #ifndef ANT_HTTP1_PARSER_H 2 + #define ANT_HTTP1_PARSER_H 3 + 4 + #include <stdbool.h> 5 + #include <stddef.h> 6 + #include <stdint.h> 7 + #include "modules/http.h" 8 + 9 + typedef struct { 10 + char *method; 11 + char *target; 12 + char *host; 13 + char *content_type; 14 + ant_http_header_t *headers; 15 + uint8_t *body; 16 + size_t body_len; 17 + size_t content_length; 18 + bool absolute_target; 19 + bool keep_alive; 20 + } ant_http1_parsed_request_t; 21 + 22 + typedef enum { 23 + ANT_HTTP1_PARSE_INCOMPLETE = 0, 24 + ANT_HTTP1_PARSE_OK, 25 + ANT_HTTP1_PARSE_ERROR, 26 + } ant_http1_parse_result_t; 27 + 28 + ant_http1_parse_result_t ant_http1_parse_request( 29 + const char *data, 30 + size_t len, 31 + ant_http1_parsed_request_t *out, 32 + const char **error_reason 33 + ); 34 + 35 + void ant_http1_free_parsed_request(ant_http1_parsed_request_t *req); 36 + 37 + #endif
+51
include/http/http1_writer.h
··· 1 + #ifndef ANT_HTTP1_WRITER_H 2 + #define ANT_HTTP1_WRITER_H 3 + 4 + #include <stdarg.h> 5 + #include <stdbool.h> 6 + #include <stddef.h> 7 + #include <stdint.h> 8 + #include "types.h" 9 + 10 + typedef struct { 11 + char *data; 12 + size_t len; 13 + size_t cap; 14 + bool failed; 15 + } ant_http1_buffer_t; 16 + 17 + void ant_http1_buffer_init(ant_http1_buffer_t *buf); 18 + void ant_http1_buffer_free(ant_http1_buffer_t *buf); 19 + 20 + __attribute__((format(printf, 2, 3))) 21 + bool ant_http1_buffer_appendf(ant_http1_buffer_t *buf, const char *fmt, ...); 22 + bool ant_http1_buffer_reserve(ant_http1_buffer_t *buf, size_t extra); 23 + bool ant_http1_buffer_append(ant_http1_buffer_t *buf, const void *data, size_t len); 24 + bool ant_http1_buffer_append_cstr(ant_http1_buffer_t *buf, const char *str); 25 + bool ant_http1_buffer_appendfv(ant_http1_buffer_t *buf, const char *fmt, va_list ap); 26 + 27 + const char *ant_http1_default_status_text(int status); 28 + char *ant_http1_buffer_take(ant_http1_buffer_t *buf, size_t *len_out); 29 + 30 + bool ant_http1_write_basic_response( 31 + ant_http1_buffer_t *buf, 32 + int status, 33 + const char *status_text, 34 + const char *content_type, 35 + const uint8_t *body, 36 + size_t body_len 37 + ); 38 + 39 + bool ant_http1_write_response_head( 40 + ant_http1_buffer_t *buf, 41 + int status, 42 + const char *status_text, 43 + ant_value_t headers, 44 + bool body_is_stream, 45 + size_t body_size 46 + ); 47 + 48 + bool ant_http1_write_final_chunk(ant_http1_buffer_t *buf); 49 + bool ant_http1_write_chunk(ant_http1_buffer_t *buf, const uint8_t *chunk, size_t len); 50 + 51 + #endif
+5 -1
include/modules/server.h
··· 1 1 #ifndef SERVER_H 2 2 #define SERVER_H 3 3 4 - void init_server_module(void); 4 + #include <stdbool.h> 5 + #include "types.h" 6 + 7 + ant_value_t server_start_from_export(ant_t *js, ant_value_t default_export); 8 + bool server_export_has_fetch_handler(ant_t *js, ant_value_t default_export, bool *looks_like_config); 5 9 6 10 #endif
+32
include/net/connection.h
··· 1 + #ifndef ANT_NET_CONNECTION_H 2 + #define ANT_NET_CONNECTION_H 3 + 4 + #include <stdbool.h> 5 + #include <stddef.h> 6 + #include <uv.h> 7 + 8 + typedef struct ant_listener_s ant_listener_t; 9 + typedef struct ant_conn_s ant_conn_t; 10 + 11 + struct ant_conn_s { 12 + uv_tcp_t handle; 13 + uv_timer_t timer; 14 + ant_listener_t *listener; 15 + void *user_data; 16 + char *buffer; 17 + size_t buffer_len; 18 + size_t buffer_cap; 19 + int timeout_secs; 20 + int close_handles; 21 + bool closing; 22 + bool has_remote_addr; 23 + char remote_addr[64]; 24 + int remote_port; 25 + struct ant_conn_s *next; 26 + }; 27 + 28 + void ant_conn_start(ant_conn_t *conn); 29 + int ant_conn_accept(ant_conn_t *conn, uv_stream_t *server_stream); 30 + ant_conn_t *ant_conn_create_tcp(ant_listener_t *listener, int timeout_secs); 31 + 32 + #endif
+74
include/net/listener.h
··· 1 + #ifndef ANT_NET_LISTENER_H 2 + #define ANT_NET_LISTENER_H 3 + 4 + #include <stdbool.h> 5 + #include <stddef.h> 6 + #include <uv.h> 7 + 8 + typedef struct ant_listener_s ant_listener_t; 9 + typedef struct ant_conn_s ant_conn_t; 10 + 11 + typedef void (*ant_conn_write_cb)( 12 + ant_conn_t *conn, 13 + int status, 14 + void *user_data 15 + ); 16 + 17 + typedef struct { 18 + void (*on_accept)(ant_listener_t *listener, ant_conn_t *conn, void *user_data); 19 + void (*on_read)(ant_conn_t *conn, ssize_t nread, void *user_data); 20 + void (*on_conn_close)(ant_conn_t *conn, void *user_data); 21 + void (*on_listener_close)(ant_listener_t *listener, void *user_data); 22 + } ant_listener_callbacks_t; 23 + 24 + struct ant_listener_s { 25 + uv_loop_t *loop; 26 + uv_tcp_t handle; 27 + ant_conn_t *connections; 28 + ant_listener_callbacks_t callbacks; 29 + void *user_data; 30 + int idle_timeout_secs; 31 + int port; 32 + int backlog; 33 + bool started; 34 + bool closing; 35 + bool closed; 36 + }; 37 + 38 + int ant_listener_listen_tcp( 39 + ant_listener_t *listener, 40 + uv_loop_t *loop, 41 + const char *hostname, 42 + int port, 43 + int backlog, 44 + int idle_timeout_secs, 45 + const ant_listener_callbacks_t *callbacks, 46 + void *user_data 47 + ); 48 + 49 + void ant_listener_stop(ant_listener_t *listener, bool force); 50 + void *ant_listener_get_user_data(const ant_listener_t *listener); 51 + 52 + int ant_listener_port(const ant_listener_t *listener); 53 + int ant_conn_timeout(const ant_conn_t *conn); 54 + int ant_conn_remote_port(const ant_conn_t *conn); 55 + int ant_conn_write(ant_conn_t *conn, char *data, size_t len, ant_conn_write_cb cb, void *user_data); 56 + 57 + bool ant_listener_has_connections(const ant_listener_t *listener); 58 + bool ant_listener_is_closed(const ant_listener_t *listener); 59 + bool ant_conn_is_closing(const ant_conn_t *conn); 60 + bool ant_conn_has_remote_addr(const ant_conn_t *conn); 61 + 62 + void ant_conn_set_user_data(ant_conn_t *conn, void *user_data); 63 + void *ant_conn_get_user_data(const ant_conn_t *conn); 64 + void ant_conn_pause_read(ant_conn_t *conn); 65 + void ant_conn_close(ant_conn_t *conn); 66 + void ant_conn_set_timeout(ant_conn_t *conn, int timeout_secs); 67 + 68 + const char *ant_conn_buffer(const ant_conn_t *conn); 69 + const char *ant_conn_remote_addr(const ant_conn_t *conn); 70 + 71 + size_t ant_conn_buffer_len(const ant_conn_t *conn); 72 + ant_listener_t *ant_conn_listener(const ant_conn_t *conn); 73 + 74 + #endif
+5
include/object.h
··· 49 49 struct ant_object *gc_pending_next; 50 50 void (*finalizer)(ant_t *, struct ant_object *); 51 51 ant_value_t inobj[ANT_INOBJ_MAX_SLOTS]; 52 + 53 + struct { 54 + void *ptr; 55 + uint32_t tag; 56 + } native; 52 57 53 58 union { 54 59 struct { ant_value_t *data; uint32_t len; uint32_t cap; } array;
+34
include/ptr.h
··· 1 + #ifndef ANT_PTR_H 2 + #define ANT_PTR_H 3 + 4 + #include "types.h" 5 + #include "internal.h" // IWYU pragma: keep 6 + 7 + static inline void js_set_native_ptr(ant_value_t obj, void *ptr) { 8 + ant_object_t *o = js_obj_ptr(obj); 9 + if (!o) return; 10 + o->native.ptr = ptr; 11 + } 12 + 13 + static inline void *js_get_native_ptr(ant_value_t obj) { 14 + ant_object_t *o = js_obj_ptr(obj); 15 + return o ? o->native.ptr : NULL; 16 + } 17 + 18 + static inline void js_set_native_tag(ant_value_t obj, uint32_t tag) { 19 + ant_object_t *o = js_obj_ptr(obj); 20 + if (!o) return; 21 + o->native.tag = tag; 22 + } 23 + 24 + static inline uint32_t js_get_native_tag(ant_value_t obj) { 25 + ant_object_t *o = js_obj_ptr(obj); 26 + return o ? o->native.tag : 0; 27 + } 28 + 29 + 30 + static inline bool js_check_native_tag(ant_value_t obj, uint32_t tag) { 31 + return js_get_native_tag(obj) == tag; 32 + } 33 + 34 + #endif
+2 -2
sources.json
··· 1 1 { 2 2 "engine": { 3 - "patterns": ["src/*.c", "src/gc/*.c", "src/highlight/*.c", "src/esm/*.c", "src/cli/*.c", "src/modules/*.c", "src/streams/*.c", "src/silver/*.c"], 3 + "patterns": ["src/*.c", "src/gc/*.c", "src/highlight/*.c", "src/esm/*.c", "src/cli/*.c", "src/modules/*.c", "src/streams/*.c", "src/silver/*.c", "src/http/*.c", "src/net/*.c"], 4 4 "exclude": ["src/main.c", "src/watch.c"] 5 5 }, 6 6 "library": { 7 - "patterns": ["src/*.c", "src/gc/*.c", "src/highlight/*.c", "src/esm/*.c", "src/modules/*.c", "src/streams/*.c", "src/silver/*.c"], 7 + "patterns": ["src/*.c", "src/gc/*.c", "src/highlight/*.c", "src/esm/*.c", "src/modules/*.c", "src/streams/*.c", "src/silver/*.c", "src/http/*.c", "src/net/*.c"], 8 8 "exclude": ["src/main.c", "src/watch.c"] 9 9 }, 10 10 "core": {
+182
src/http/http1_parser.c
··· 1 + #include <compat.h> // IWYU pragma: keep 2 + 3 + #include <stdlib.h> 4 + #include <string.h> 5 + #include <strings.h> 6 + #include <llhttp.h> 7 + 8 + #include "http/http1_parser.h" 9 + #include "http/http1_writer.h" 10 + 11 + typedef struct { 12 + ant_http1_parsed_request_t req; 13 + ant_http1_buffer_t method; 14 + ant_http1_buffer_t target; 15 + ant_http1_buffer_t header_field; 16 + ant_http1_buffer_t header_value; 17 + ant_http1_buffer_t body; 18 + bool message_complete; 19 + } parser_ctx_t; 20 + 21 + static void parser_ctx_free(parser_ctx_t *ctx) { 22 + if (!ctx) return; 23 + free(ctx->req.method); 24 + free(ctx->req.target); 25 + free(ctx->req.host); 26 + free(ctx->req.content_type); 27 + free(ctx->req.body); 28 + ant_http_headers_free(ctx->req.headers); 29 + ant_http1_buffer_free(&ctx->method); 30 + ant_http1_buffer_free(&ctx->target); 31 + ant_http1_buffer_free(&ctx->header_field); 32 + ant_http1_buffer_free(&ctx->header_value); 33 + ant_http1_buffer_free(&ctx->body); 34 + memset(ctx, 0, sizeof(*ctx)); 35 + } 36 + 37 + static bool parser_copy_header(parser_ctx_t *ctx) { 38 + ant_http_header_t *hdr = calloc(1, sizeof(*hdr)); 39 + if (!hdr) return false; 40 + 41 + hdr->name = ant_http1_buffer_take(&ctx->header_field, NULL); 42 + hdr->value = ant_http1_buffer_take(&ctx->header_value, NULL); 43 + if (!hdr->name || !hdr->value) { 44 + free(hdr->name); 45 + free(hdr->value); 46 + free(hdr); 47 + return false; 48 + } 49 + 50 + hdr->next = ctx->req.headers; 51 + ctx->req.headers = hdr; 52 + 53 + if (strcasecmp(hdr->name, "host") == 0) { 54 + free(ctx->req.host); 55 + ctx->req.host = strdup(hdr->value); 56 + if (!ctx->req.host) return false; 57 + } else if (strcasecmp(hdr->name, "content-type") == 0) { 58 + free(ctx->req.content_type); 59 + ctx->req.content_type = strdup(hdr->value); 60 + if (!ctx->req.content_type) return false; 61 + } else if (strcasecmp(hdr->name, "content-length") == 0) { 62 + ctx->req.content_length = (size_t)strtoull(hdr->value, NULL, 10); 63 + } 64 + 65 + return true; 66 + } 67 + 68 + static int parser_on_method(llhttp_t *parser, const char *at, size_t length) { 69 + parser_ctx_t *ctx = (parser_ctx_t *)parser->data; 70 + return ant_http1_buffer_append(&ctx->method, at, length) ? 0 : -1; 71 + } 72 + 73 + static int parser_on_url(llhttp_t *parser, const char *at, size_t length) { 74 + parser_ctx_t *ctx = (parser_ctx_t *)parser->data; 75 + return ant_http1_buffer_append(&ctx->target, at, length) ? 0 : -1; 76 + } 77 + 78 + static int parser_on_header_field(llhttp_t *parser, const char *at, size_t length) { 79 + parser_ctx_t *ctx = (parser_ctx_t *)parser->data; 80 + if (ctx->header_value.len > 0) { 81 + if (!parser_copy_header(ctx)) return -1; 82 + } 83 + return ant_http1_buffer_append(&ctx->header_field, at, length) ? 0 : -1; 84 + } 85 + 86 + static int parser_on_header_value(llhttp_t *parser, const char *at, size_t length) { 87 + parser_ctx_t *ctx = (parser_ctx_t *)parser->data; 88 + return ant_http1_buffer_append(&ctx->header_value, at, length) ? 0 : -1; 89 + } 90 + 91 + static int parser_on_headers_complete(llhttp_t *parser) { 92 + parser_ctx_t *ctx = (parser_ctx_t *)parser->data; 93 + if (ctx->header_field.len > 0 || ctx->header_value.len > 0) { 94 + if (!parser_copy_header(ctx)) return -1; 95 + } 96 + return 0; 97 + } 98 + 99 + static int parser_on_body(llhttp_t *parser, const char *at, size_t length) { 100 + parser_ctx_t *ctx = (parser_ctx_t *)parser->data; 101 + return ant_http1_buffer_append(&ctx->body, at, length) ? 0 : -1; 102 + } 103 + 104 + static int parser_on_message_complete(llhttp_t *parser) { 105 + parser_ctx_t *ctx = (parser_ctx_t *)parser->data; 106 + ctx->message_complete = true; 107 + return HPE_PAUSED; 108 + } 109 + 110 + ant_http1_parse_result_t ant_http1_parse_request( 111 + const char *data, 112 + size_t len, 113 + ant_http1_parsed_request_t *out, 114 + const char **error_reason 115 + ) { 116 + llhttp_t parser; 117 + llhttp_settings_t settings; 118 + llhttp_errno_t err = HPE_OK; 119 + parser_ctx_t ctx = {0}; 120 + 121 + if (error_reason) *error_reason = NULL; 122 + memset(out, 0, sizeof(*out)); 123 + 124 + ant_http1_buffer_init(&ctx.method); 125 + ant_http1_buffer_init(&ctx.target); 126 + ant_http1_buffer_init(&ctx.header_field); 127 + ant_http1_buffer_init(&ctx.header_value); 128 + ant_http1_buffer_init(&ctx.body); 129 + 130 + llhttp_settings_init(&settings); 131 + settings.on_method = parser_on_method; 132 + settings.on_url = parser_on_url; 133 + settings.on_header_field = parser_on_header_field; 134 + settings.on_header_value = parser_on_header_value; 135 + settings.on_headers_complete = parser_on_headers_complete; 136 + settings.on_body = parser_on_body; 137 + settings.on_message_complete = parser_on_message_complete; 138 + 139 + llhttp_init(&parser, HTTP_REQUEST, &settings); 140 + parser.data = &ctx; 141 + err = llhttp_execute(&parser, data, len); 142 + 143 + if (err != HPE_OK && err != HPE_PAUSED) { 144 + if (error_reason) *error_reason = llhttp_get_error_reason(&parser); 145 + parser_ctx_free(&ctx); 146 + return ANT_HTTP1_PARSE_ERROR; 147 + } 148 + 149 + if (!ctx.message_complete) { 150 + parser_ctx_free(&ctx); 151 + return ANT_HTTP1_PARSE_INCOMPLETE; 152 + } 153 + 154 + ctx.req.method = ant_http1_buffer_take(&ctx.method, NULL); 155 + ctx.req.target = ant_http1_buffer_take(&ctx.target, NULL); 156 + ctx.req.body = (uint8_t *)ant_http1_buffer_take(&ctx.body, &ctx.req.body_len); 157 + if (!ctx.req.method || !ctx.req.target) { 158 + parser_ctx_free(&ctx); 159 + return ANT_HTTP1_PARSE_ERROR; 160 + } 161 + 162 + ctx.req.absolute_target = 163 + strncmp(ctx.req.target, "http://", 7) == 0 || 164 + strncmp(ctx.req.target, "https://", 8) == 0; 165 + ctx.req.keep_alive = llhttp_should_keep_alive(&parser) == 1; 166 + 167 + *out = ctx.req; 168 + memset(&ctx.req, 0, sizeof(ctx.req)); 169 + parser_ctx_free(&ctx); 170 + return ANT_HTTP1_PARSE_OK; 171 + } 172 + 173 + void ant_http1_free_parsed_request(ant_http1_parsed_request_t *req) { 174 + if (!req) return; 175 + free(req->method); 176 + free(req->target); 177 + free(req->host); 178 + free(req->content_type); 179 + free(req->body); 180 + ant_http_headers_free(req->headers); 181 + memset(req, 0, sizeof(*req)); 182 + }
+209
src/http/http1_writer.c
··· 1 + #include <compat.h> // IWYU pragma: keep 2 + 3 + #include <stdarg.h> 4 + #include <stdio.h> 5 + #include <stdlib.h> 6 + #include <string.h> 7 + #include <strings.h> 8 + 9 + #include "http/http1_writer.h" 10 + #include "modules/headers.h" 11 + 12 + void ant_http1_buffer_init(ant_http1_buffer_t *buf) { 13 + memset(buf, 0, sizeof(*buf)); 14 + } 15 + 16 + bool ant_http1_buffer_reserve(ant_http1_buffer_t *buf, size_t extra) { 17 + size_t need = buf->len + extra; 18 + size_t next_cap = 0; 19 + char *next = NULL; 20 + 21 + if (buf->failed) return false; 22 + if (need <= buf->cap) return true; 23 + 24 + next_cap = buf->cap ? buf->cap * 2 : 256; 25 + while (next_cap < need) next_cap *= 2; 26 + next = realloc(buf->data, next_cap); 27 + if (!next) { 28 + buf->failed = true; 29 + return false; 30 + } 31 + 32 + buf->data = next; 33 + buf->cap = next_cap; 34 + return true; 35 + } 36 + 37 + bool ant_http1_buffer_append(ant_http1_buffer_t *buf, const void *data, size_t len) { 38 + if (!ant_http1_buffer_reserve(buf, len)) return false; 39 + if (len > 0) memcpy(buf->data + buf->len, data, len); 40 + buf->len += len; 41 + return true; 42 + } 43 + 44 + bool ant_http1_buffer_append_cstr(ant_http1_buffer_t *buf, const char *str) { 45 + return ant_http1_buffer_append(buf, str, strlen(str)); 46 + } 47 + 48 + #pragma GCC diagnostic push 49 + #pragma GCC diagnostic ignored "-Wformat-nonliteral" 50 + 51 + bool ant_http1_buffer_appendfv(ant_http1_buffer_t *buf, const char *fmt, va_list ap) { 52 + va_list ap_copy; 53 + int written; 54 + 55 + if (!buf || buf->failed) return false; 56 + 57 + va_copy(ap_copy, ap); 58 + written = vsnprintf(NULL, 0, fmt, ap_copy); 59 + va_end(ap_copy); 60 + if (written < 0) { 61 + buf->failed = true; 62 + return false; 63 + } 64 + 65 + if (!ant_http1_buffer_reserve(buf, (size_t)written)) return false; 66 + written = vsnprintf(buf->data + buf->len, buf->cap - buf->len, fmt, ap); 67 + if (written < 0) { 68 + buf->failed = true; 69 + return false; 70 + } 71 + 72 + buf->len += (size_t)written; 73 + return true; 74 + } 75 + 76 + bool ant_http1_buffer_appendf(ant_http1_buffer_t *buf, const char *fmt, ...) { 77 + va_list ap; 78 + bool ok; 79 + 80 + va_start(ap, fmt); 81 + ok = ant_http1_buffer_appendfv(buf, fmt, ap); 82 + va_end(ap); 83 + return ok; 84 + } 85 + 86 + #pragma GCC diagnostic pop 87 + 88 + char *ant_http1_buffer_take(ant_http1_buffer_t *buf, size_t *len_out) { 89 + char *data = buf->data; 90 + if (len_out) *len_out = buf->len; 91 + buf->data = NULL; 92 + buf->len = 0; 93 + buf->cap = 0; 94 + buf->failed = false; 95 + return data; 96 + } 97 + 98 + void ant_http1_buffer_free(ant_http1_buffer_t *buf) { 99 + free(buf->data); 100 + buf->data = NULL; 101 + buf->len = 0; 102 + buf->cap = 0; 103 + buf->failed = false; 104 + } 105 + 106 + const char *ant_http1_default_status_text(int status) { 107 + switch (status) { 108 + case 200: return "OK"; 109 + case 201: return "Created"; 110 + case 202: return "Accepted"; 111 + case 204: return "No Content"; 112 + case 301: return "Moved Permanently"; 113 + case 302: return "Found"; 114 + case 303: return "See Other"; 115 + case 304: return "Not Modified"; 116 + case 307: return "Temporary Redirect"; 117 + case 308: return "Permanent Redirect"; 118 + case 400: return "Bad Request"; 119 + case 401: return "Unauthorized"; 120 + case 403: return "Forbidden"; 121 + case 404: return "Not Found"; 122 + case 405: return "Method Not Allowed"; 123 + case 408: return "Request Timeout"; 124 + case 409: return "Conflict"; 125 + case 410: return "Gone"; 126 + case 413: return "Payload Too Large"; 127 + case 415: return "Unsupported Media Type"; 128 + case 421: return "Misdirected Request"; 129 + case 429: return "Too Many Requests"; 130 + case 500: return "Internal Server Error"; 131 + case 501: return "Not Implemented"; 132 + case 502: return "Bad Gateway"; 133 + case 503: return "Service Unavailable"; 134 + case 504: return "Gateway Timeout"; 135 + default: return "OK"; 136 + }} 137 + 138 + typedef struct { 139 + ant_http1_buffer_t *buf; 140 + } response_header_ctx_t; 141 + 142 + static void ant_http1_append_response_header(const char *name, const char *value, void *ctx) { 143 + response_header_ctx_t *state = (response_header_ctx_t *)ctx; 144 + if (!state || state->buf->failed) return; 145 + 146 + if (strcasecmp(name, "connection") == 0) return; 147 + if (strcasecmp(name, "content-length") == 0) return; 148 + if (strcasecmp(name, "transfer-encoding") == 0) return; 149 + ant_http1_buffer_appendf(state->buf, "%s: %s\r\n", name, value); 150 + } 151 + 152 + bool ant_http1_write_basic_response( 153 + ant_http1_buffer_t *buf, 154 + int status, 155 + const char *status_text, 156 + const char *content_type, 157 + const uint8_t *body, 158 + size_t body_len 159 + ) { 160 + ant_http1_buffer_appendf(buf, "HTTP/1.1 %d %s\r\n", status, status_text 161 + ? status_text 162 + : ant_http1_default_status_text(status) 163 + ); 164 + 165 + ant_http1_buffer_appendf(buf, "Content-Type: %s\r\n", content_type 166 + ? content_type 167 + : "text/plain;charset=UTF-8" 168 + ); 169 + 170 + ant_http1_buffer_appendf(buf, "Content-Length: %zu\r\n", body_len); 171 + ant_http1_buffer_append_cstr(buf, "Connection: close\r\n\r\n"); 172 + if (body_len > 0) ant_http1_buffer_append(buf, body, body_len); 173 + 174 + return !buf->failed; 175 + } 176 + 177 + bool ant_http1_write_response_head( 178 + ant_http1_buffer_t *buf, 179 + int status, 180 + const char *status_text, 181 + ant_value_t headers, 182 + bool body_is_stream, 183 + size_t body_size 184 + ) { 185 + response_header_ctx_t ctx = { .buf = buf }; 186 + 187 + ant_http1_buffer_appendf(buf, "HTTP/1.1 %d %s\r\n", status, status_text 188 + ? status_text 189 + : ant_http1_default_status_text(status) 190 + ); 191 + 192 + headers_for_each(headers, ant_http1_append_response_header, &ctx); 193 + if (body_is_stream) ant_http1_buffer_append_cstr(buf, "Transfer-Encoding: chunked\r\n"); 194 + else ant_http1_buffer_appendf(buf, "Content-Length: %zu\r\n", body_size); 195 + ant_http1_buffer_append_cstr(buf, "Connection: close\r\n\r\n"); 196 + 197 + return !buf->failed; 198 + } 199 + 200 + bool ant_http1_write_chunk(ant_http1_buffer_t *buf, const uint8_t *chunk, size_t len) { 201 + ant_http1_buffer_appendf(buf, "%zx\r\n", len); 202 + if (len > 0) ant_http1_buffer_append(buf, chunk, len); 203 + ant_http1_buffer_append_cstr(buf, "\r\n"); 204 + return !buf->failed; 205 + } 206 + 207 + bool ant_http1_write_final_chunk(ant_http1_buffer_t *buf) { 208 + return ant_http1_buffer_append_cstr(buf, "0\r\n\r\n"); 209 + }
+27 -38
src/main.c
··· 311 311 } 312 312 313 313 static int execute_module(ant_t *js, const char *filename) { 314 - char *buffer = NULL; 315 - size_t len = 0; 314 + bool looks_like_server = false; 316 315 317 316 char *use_path_owned = NULL; 318 317 const char *use_path = filename; 318 + 319 + ant_value_t ns = 0; 320 + ant_value_t specifier = 0; 321 + ant_value_t default_export = 0; 322 + ant_value_t server_result = 0; 319 323 320 324 if (esm_is_url(filename)) { 321 - char *error = NULL; 322 - buffer = esm_fetch_url(filename, &len, &error); 323 - 324 - if (!buffer) { 325 - crfprintf(stderr, msg.failed_to_fetch, filename, error ? error : "unknown error"); 326 - free(error); return EXIT_FAILURE; 327 - } 328 - 329 325 js_set(js, js_glob(js), "__dirname", js_mkundef()); 326 + specifier = js_mkstr(js, filename, strlen(filename)); 330 327 } else { 331 - buffer = read_file(filename, &len); 332 - if (!buffer) { 333 - crfprintf(stderr, msg.module_not_found, filename); 334 - return EXIT_FAILURE; 335 - } 336 - 337 328 char *file_path = strdup(filename); 338 329 char *dir = dirname(file_path); 339 330 js_set(js, js_glob(js), "__dirname", js_mkstr(js, dir, strlen(dir))); ··· 341 332 342 333 use_path_owned = realpath(filename, NULL); 343 334 if (use_path_owned) use_path = use_path_owned; 344 - } 345 - 346 - size_t js_len = len; 347 - const char *strip_detail = NULL; 348 - 349 - int strip_result = strip_typescript_inplace( 350 - &buffer, len, filename, &js_len, &strip_detail 351 - ); 352 - 353 - if (strip_result < 0) { 354 - crfprintf(stderr, msg.type_strip_failed, strip_result, strip_detail); 355 - free(buffer); free(use_path_owned); 356 - return EXIT_FAILURE; 335 + specifier = js_esm_make_file_url(js, use_path); 357 336 } 358 337 359 - char *js_code = buffer; 360 338 js_set(js, js_glob(js), 361 339 "__filename", 362 340 js_mkstr(js, filename, strlen(filename)) ··· 364 342 365 343 js_set_filename(js, use_path); 366 344 js_setup_import_meta(js, use_path); 345 + ns = js_esm_import_sync(js, specifier); 367 346 368 - ant_value_t result = js_esm_eval_module_source( 369 - js, use_path, js_code, 370 - js_len, mkobj(js, 0) 371 - ); 347 + free(use_path_owned); 348 + if (print_uncaught_throw(js)) return EXIT_FAILURE; 372 349 373 - free(js_code); 350 + if (vtype(ns) == T_ERR) { 351 + fprintf(stderr, "%s\n", js_str(js, ns)); 352 + return EXIT_FAILURE; 353 + } 354 + 355 + default_export = js_get(js, ns, "default"); 374 356 375 - if (print_uncaught_throw(js)) return EXIT_FAILURE; 376 - if (vtype(result) == T_ERR) fprintf(stderr, "%s\n", js_str(js, result)); 357 + if (server_export_has_fetch_handler(js, default_export, &looks_like_server)) { 358 + server_result = server_start_from_export(js, default_export); 359 + if (is_err(server_result)) { 360 + fprintf(stderr, "%s\n", js_str(js, server_result)); 361 + return EXIT_FAILURE; 362 + } 363 + } else if (looks_like_server) { 364 + fprintf(stderr, "Module does not export a fetch handler\n"); 365 + return EXIT_FAILURE; 366 + } 377 367 378 368 return EXIT_SUCCESS; 379 369 } ··· 619 609 init_fetch_module(); 620 610 init_console_module(); 621 611 init_json_module(); 622 - init_server_module(); 623 612 init_process_module(); 624 613 init_tty_module(); 625 614 init_events_module();
+858
src/modules/server.c
··· 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 + 15 + #include "gc/modules.h" 16 + #include "net/listener.h" 17 + #include "streams/readable.h" 18 + 19 + #include "http/http1_parser.h" 20 + #include "http/http1_writer.h" 21 + 22 + #include "modules/assert.h" 23 + #include "modules/buffer.h" 24 + #include "modules/headers.h" 25 + #include "modules/request.h" 26 + #include "modules/response.h" 27 + #include "modules/server.h" 28 + 29 + typedef struct server_runtime_s server_runtime_t; 30 + typedef struct server_request_s server_request_t; 31 + 32 + static server_runtime_t *g_server = NULL; 33 + 34 + typedef struct stop_waiter_s { 35 + ant_value_t promise; 36 + struct stop_waiter_s *next; 37 + } stop_waiter_t; 38 + 39 + typedef enum { 40 + SERVER_WRITE_NONE = 0, 41 + SERVER_WRITE_CLOSE_CLIENT, 42 + SERVER_WRITE_STREAM_READ, 43 + } server_write_action_t; 44 + 45 + typedef struct { 46 + server_request_t *request; 47 + ant_conn_t *conn; 48 + server_write_action_t action; 49 + } server_write_req_t; 50 + 51 + struct server_request_s { 52 + server_runtime_t *server; 53 + ant_conn_t *conn; 54 + ant_value_t request_obj; 55 + ant_value_t response_obj; 56 + ant_value_t response_promise; 57 + ant_value_t response_reader; 58 + ant_value_t response_read_promise; 59 + int refs; 60 + bool response_started; 61 + struct server_request_s *next; 62 + }; 63 + 64 + struct server_runtime_s { 65 + ant_t *js; 66 + ant_value_t export_obj; 67 + ant_value_t fetch_fn; 68 + ant_value_t server_ctx; 69 + uv_loop_t *loop; 70 + ant_listener_t listener; 71 + uv_signal_t sigint_handle; 72 + uv_signal_t sigterm_handle; 73 + stop_waiter_t *stop_waiters; 74 + server_request_t *requests; 75 + char *hostname; 76 + int port; 77 + int idle_timeout_secs; 78 + bool sigint_closed; 79 + bool sigterm_closed; 80 + bool stopping; 81 + bool force_stop; 82 + }; 83 + 84 + static inline void server_request_retain(server_request_t *req) { 85 + if (req) req->refs++; 86 + } 87 + 88 + static ant_value_t server_exception_reason(ant_t *js, ant_value_t value) { 89 + if (!is_err(value)) return value; 90 + if (!js->thrown_exists) return value; 91 + 92 + value = js->thrown_value; 93 + js->thrown_exists = false; 94 + js->thrown_value = js_mkundef(); 95 + js->thrown_stack = js_mkundef(); 96 + return value; 97 + } 98 + 99 + static void server_remove_request(server_runtime_t *server, server_request_t *req) { 100 + server_request_t **it = NULL; 101 + if (!server || !req) return; 102 + 103 + for (it = &server->requests; *it; it = &(*it)->next) { 104 + if (*it == req) { 105 + *it = req->next; 106 + return; 107 + }} 108 + } 109 + 110 + 111 + static void server_request_release(server_request_t *req) { 112 + if (!req) return; 113 + if (--req->refs > 0) return; 114 + 115 + server_remove_request(req->server, req); 116 + free(req); 117 + } 118 + 119 + static server_request_t *server_find_request(server_runtime_t *server, ant_value_t request_obj) { 120 + server_request_t *req = NULL; 121 + if (!server || !is_object_type(request_obj)) return NULL; 122 + 123 + for (req = server->requests; req; req = req->next) { 124 + if (req->request_obj == request_obj) return req; 125 + } 126 + return NULL; 127 + } 128 + static void stop_waiters_resolve(server_runtime_t *server) { 129 + stop_waiter_t *waiter = server->stop_waiters; 130 + server->stop_waiters = NULL; 131 + 132 + while (waiter) { 133 + stop_waiter_t *next = waiter->next; 134 + js_resolve_promise(server->js, waiter->promise, js_mkundef()); 135 + free(waiter); 136 + waiter = next; 137 + } 138 + } 139 + 140 + static void server_maybe_finish_stop(server_runtime_t *server) { 141 + if (!server || !server->stopping) return; 142 + if (ant_listener_has_connections(&server->listener)) return; 143 + if (!ant_listener_is_closed(&server->listener) || !server->sigint_closed || !server->sigterm_closed) return; 144 + 145 + stop_waiters_resolve(server); 146 + } 147 + 148 + static void server_signal_close_cb(uv_handle_t *handle) { 149 + server_runtime_t *server = (server_runtime_t *)handle->data; 150 + if (!server) return; 151 + 152 + if (handle == (uv_handle_t *)&server->sigint_handle) server->sigint_closed = true; 153 + if (handle == (uv_handle_t *)&server->sigterm_handle) server->sigterm_closed = true; 154 + server_maybe_finish_stop(server); 155 + } 156 + 157 + static void server_begin_stop(server_runtime_t *server, bool force) { 158 + if (!server) return; 159 + if (force) server->force_stop = true; 160 + 161 + server->stopping = true; 162 + ant_listener_stop(&server->listener, server->force_stop); 163 + 164 + if (!uv_is_closing((uv_handle_t *)&server->sigint_handle)) 165 + uv_close((uv_handle_t *)&server->sigint_handle, server_signal_close_cb); 166 + else server->sigint_closed = true; 167 + 168 + if (!uv_is_closing((uv_handle_t *)&server->sigterm_handle)) 169 + uv_close((uv_handle_t *)&server->sigterm_handle, server_signal_close_cb); 170 + else server->sigterm_closed = true; 171 + 172 + server_maybe_finish_stop(server); 173 + } 174 + 175 + static void server_signal_cb(uv_signal_t *handle, int signum) { 176 + server_runtime_t *server = (server_runtime_t *)handle->data; 177 + server_begin_stop(server, false); 178 + } 179 + 180 + static char *server_build_request_url(server_runtime_t *server, const ant_http1_parsed_request_t *req) { 181 + ant_http1_buffer_t url; 182 + ant_http1_buffer_init(&url); 183 + 184 + if (req->absolute_target) return strdup(req->target); 185 + if (!ant_http1_buffer_append_cstr(&url, "http://")) goto oom; 186 + if (req->host && req->host[0]) { 187 + if (!ant_http1_buffer_append_cstr(&url, req->host)) goto oom; 188 + } else { 189 + if (!ant_http1_buffer_append_cstr(&url, server->hostname)) goto oom; 190 + if (server->port != 80 && server->port > 0) { 191 + if (!ant_http1_buffer_appendf(&url, ":%d", server->port)) goto oom; 192 + } 193 + } 194 + 195 + if (!ant_http1_buffer_append_cstr(&url, req->target)) goto oom; 196 + return ant_http1_buffer_take(&url, NULL); 197 + 198 + oom: 199 + ant_http1_buffer_free(&url); 200 + return NULL; 201 + } 202 + 203 + static ant_value_t server_headers_from_parsed(ant_t *js, const ant_http1_parsed_request_t *parsed) { 204 + ant_value_t headers = headers_create_empty(js); 205 + const ant_http_header_t *hdr = NULL; 206 + 207 + if (is_err(headers)) return headers; 208 + for (hdr = parsed->headers; hdr; hdr = hdr->next) { 209 + ant_value_t step = headers_append_value( 210 + js, 211 + headers, 212 + js_mkstr(js, hdr->name, strlen(hdr->name)), 213 + js_mkstr(js, hdr->value, strlen(hdr->value)) 214 + ); 215 + if (is_err(step)) return step; 216 + } 217 + return headers; 218 + } 219 + 220 + static ant_value_t server_call_fetch(server_runtime_t *server, ant_value_t request_obj) { 221 + ant_t *js = server->js; 222 + ant_value_t args[2] = { request_obj, server->server_ctx }; 223 + ant_value_t saved_this = js->this_val; 224 + ant_value_t result = js_mkundef(); 225 + 226 + js->this_val = server->export_obj; 227 + if (vtype(server->fetch_fn) == T_CFUNC) 228 + result = ((ant_value_t (*)(ant_t *, ant_value_t *, int))vdata(server->fetch_fn))(js, args, 2); 229 + else result = sv_vm_call(js->vm, js, server->fetch_fn, server->export_obj, args, 2, NULL, false); 230 + js->this_val = saved_this; 231 + return result; 232 + } 233 + 234 + static bool server_response_chunk(server_request_t *req, ant_value_t value, const uint8_t **out, size_t *len) { 235 + ant_value_t slot = js_get_slot(value, SLOT_BUFFER); 236 + TypedArrayData *ta = (TypedArrayData *)js_gettypedarray(slot); 237 + 238 + if (!ta || ta->type != TYPED_ARRAY_UINT8) return false; 239 + if (!ta->buffer || ta->buffer->is_detached) { 240 + *out = NULL; 241 + *len = 0; 242 + return true; 243 + } 244 + 245 + *out = ta->buffer->data + ta->byte_offset; 246 + *len = ta->byte_length; 247 + return true; 248 + } 249 + 250 + static void server_start_stream_read(server_request_t *req); 251 + static void server_write_cb(ant_conn_t *conn, int status, void *user_data); 252 + 253 + static bool server_queue_write(ant_conn_t *conn, server_request_t *req, char *data, size_t len, server_write_action_t action) { 254 + server_write_req_t *wr = calloc(1, sizeof(*wr)); 255 + int rc = 0; 256 + 257 + if (!conn || ant_conn_is_closing(conn)) { 258 + free(data); 259 + return false; 260 + } 261 + 262 + if (!wr) { 263 + free(data); 264 + return false; 265 + } 266 + 267 + wr->request = req; 268 + wr->conn = conn; 269 + wr->action = action; 270 + if (req) server_request_retain(req); 271 + 272 + rc = ant_conn_write(conn, data, len, server_write_cb, wr); 273 + if (rc != 0) { 274 + if (req) server_request_release(req); 275 + free(wr); 276 + ant_conn_close(conn); 277 + return false; 278 + } 279 + 280 + return true; 281 + } 282 + 283 + static void server_send_basic_response( 284 + ant_conn_t *conn, int status, const char *status_text, 285 + const char *content_type, const uint8_t *body, size_t body_len 286 + ) { 287 + ant_http1_buffer_t buf; 288 + char *out = NULL; 289 + size_t out_len = 0; 290 + 291 + ant_http1_buffer_init(&buf); 292 + if (!ant_http1_write_basic_response(&buf, status, status_text, content_type, body, body_len)) { 293 + ant_http1_buffer_free(&buf); 294 + ant_conn_close(conn); 295 + return; 296 + } 297 + 298 + out = ant_http1_buffer_take(&buf, &out_len); 299 + server_queue_write(conn, NULL, out, out_len, SERVER_WRITE_CLOSE_CLIENT); 300 + } 301 + 302 + static void server_finish_with_response(server_request_t *req, ant_value_t response_obj) { 303 + response_data_t *resp = response_get_data(response_obj); 304 + ant_value_t headers = response_get_headers(response_obj); 305 + 306 + ant_value_t stream = js_get_slot(response_obj, SLOT_RESPONSE_BODY_STREAM); 307 + bool body_is_stream = resp && resp->body_is_stream && rs_is_stream(stream); 308 + bool head_only = false; 309 + 310 + const char *status_text = NULL; 311 + ant_http1_buffer_t buf; 312 + 313 + char *out = NULL; 314 + size_t out_len = 0; 315 + 316 + if (!req->conn || ant_conn_is_closing(req->conn)) return; 317 + if (!resp) { 318 + server_send_basic_response(req->conn, 500, "Internal Server Error", "text/plain;charset=UTF-8", (const uint8_t *)"Invalid Response", 16); 319 + return; 320 + } 321 + 322 + req->response_obj = response_obj; 323 + req->response_started = true; 324 + head_only = strcasecmp(request_get_data(req->request_obj)->method, "HEAD") == 0; 325 + status_text = (resp->status_text && resp->status_text[0]) ? resp->status_text : ant_http1_default_status_text(resp->status); 326 + 327 + ant_http1_buffer_init(&buf); 328 + if (!ant_http1_write_response_head(&buf, resp->status, status_text, headers, body_is_stream, resp->body_size)) { 329 + ant_http1_buffer_free(&buf); 330 + ant_conn_close(req->conn); 331 + return; 332 + } 333 + if (!body_is_stream && !head_only && resp->body_size > 0) ant_http1_buffer_append(&buf, resp->body_data, resp->body_size); 334 + if (buf.failed) { 335 + ant_http1_buffer_free(&buf); 336 + ant_conn_close(req->conn); 337 + return; 338 + } 339 + 340 + out = ant_http1_buffer_take(&buf, &out_len); 341 + if (!server_queue_write(req->conn, req, out, out_len, body_is_stream ? SERVER_WRITE_STREAM_READ : SERVER_WRITE_CLOSE_CLIENT)) 342 + return; 343 + 344 + if (body_is_stream && head_only) ant_conn_close(req->conn); 345 + } 346 + 347 + static ant_value_t server_on_response_reject(ant_t *js, ant_value_t *args, int nargs) { 348 + server_request_t *req = (server_request_t *)(uintptr_t)(size_t)js_getnum(js_get_slot(js->current_func, SLOT_DATA)); 349 + ant_value_t reason = (nargs > 0) ? args[0] : js_mkundef(); 350 + const char *msg = NULL; 351 + 352 + if (!req) return js_mkundef(); 353 + req->response_promise = js_mkundef(); 354 + 355 + if (req->conn && !ant_conn_is_closing(req->conn)) { 356 + msg = js_str(js, reason); 357 + server_send_basic_response(req->conn, 500, "Internal Server Error", "text/plain;charset=UTF-8", (const uint8_t *)(msg ? msg : "Internal Server Error"), strlen(msg ? msg : "Internal Server Error")); 358 + } 359 + 360 + server_request_release(req); 361 + return js_mkundef(); 362 + } 363 + 364 + static ant_value_t server_on_response_fulfill(ant_t *js, ant_value_t *args, int nargs) { 365 + server_request_t *req = (server_request_t *)(uintptr_t)(size_t)js_getnum(js_get_slot(js->current_func, SLOT_DATA)); 366 + ant_value_t value = (nargs > 0) ? args[0] : js_mkundef(); 367 + 368 + if (!req) return js_mkundef(); 369 + req->response_promise = js_mkundef(); 370 + 371 + if (!response_get_data(value)) { 372 + if (req->conn && !ant_conn_is_closing(req->conn)) 373 + server_send_basic_response(req->conn, 500, "Internal Server Error", "text/plain;charset=UTF-8", (const uint8_t *)"fetch handler must return a Response", 35); 374 + } else if (req->conn && !ant_conn_is_closing(req->conn)) { 375 + server_finish_with_response(req, value); 376 + } 377 + 378 + server_request_release(req); 379 + return js_mkundef(); 380 + } 381 + 382 + static void server_handle_fetch_result(server_request_t *req, ant_value_t result) { 383 + ant_t *js = req->server->js; 384 + 385 + if (is_err(result)) { 386 + ant_value_t reason = server_exception_reason(js, result); 387 + const char *msg = js_str(js, reason); 388 + server_send_basic_response(req->conn, 500, "Internal Server Error", "text/plain;charset=UTF-8", (const uint8_t *)(msg ? msg : "Internal Server Error"), strlen(msg ? msg : "Internal Server Error")); 389 + return; 390 + } 391 + 392 + if (vtype(result) == T_PROMISE) { 393 + ant_value_t fulfill = js_heavy_mkfun(js, server_on_response_fulfill, ANT_PTR(req)); 394 + ant_value_t reject = js_heavy_mkfun(js, server_on_response_reject, ANT_PTR(req)); 395 + ant_value_t then_result = 0; 396 + 397 + req->response_promise = result; 398 + server_request_retain(req); 399 + then_result = js_promise_then(js, result, fulfill, reject); 400 + promise_mark_handled(then_result); 401 + return; 402 + } 403 + 404 + if (!response_get_data(result)) { 405 + server_send_basic_response(req->conn, 500, "Internal Server Error", "text/plain;charset=UTF-8", (const uint8_t *)"fetch handler must return a Response", 35); 406 + return; 407 + } 408 + 409 + server_finish_with_response(req, result); 410 + } 411 + 412 + static ant_value_t server_stream_read_reject(ant_t *js, ant_value_t *args, int nargs) { 413 + server_request_t *req = (server_request_t *)(uintptr_t)(size_t)js_getnum(js_get_slot(js->current_func, SLOT_DATA)); 414 + (void)args; 415 + (void)nargs; 416 + 417 + if (!req) return js_mkundef(); 418 + req->response_read_promise = js_mkundef(); 419 + if (req->conn && !ant_conn_is_closing(req->conn)) ant_conn_close(req->conn); 420 + server_request_release(req); 421 + return js_mkundef(); 422 + } 423 + 424 + static ant_value_t server_stream_read_fulfill(ant_t *js, ant_value_t *args, int nargs) { 425 + server_request_t *req = (server_request_t *)(uintptr_t)(size_t)js_getnum(js_get_slot(js->current_func, SLOT_DATA)); 426 + ant_value_t result = (nargs > 0) ? args[0] : js_mkundef(); 427 + ant_value_t done = 0; 428 + ant_value_t value = 0; 429 + const uint8_t *chunk = NULL; 430 + size_t chunk_len = 0; 431 + ant_http1_buffer_t buf; 432 + char *out = NULL; 433 + size_t out_len = 0; 434 + 435 + if (!req) return js_mkundef(); 436 + req->response_read_promise = js_mkundef(); 437 + 438 + if (!req->conn || ant_conn_is_closing(req->conn)) { 439 + server_request_release(req); 440 + return js_mkundef(); 441 + } 442 + 443 + done = js_get(js, result, "done"); 444 + if (done == js_true) { 445 + ant_http1_buffer_init(&buf); 446 + if (!ant_http1_write_final_chunk(&buf)) { 447 + ant_http1_buffer_free(&buf); 448 + ant_conn_close(req->conn); 449 + server_request_release(req); 450 + return js_mkundef(); 451 + } 452 + out = ant_http1_buffer_take(&buf, &out_len); 453 + server_queue_write(req->conn, req, out, out_len, SERVER_WRITE_CLOSE_CLIENT); 454 + server_request_release(req); 455 + return js_mkundef(); 456 + } 457 + 458 + value = js_get(js, result, "value"); 459 + if (!server_response_chunk(req, value, &chunk, &chunk_len)) { 460 + ant_conn_close(req->conn); 461 + server_request_release(req); 462 + return js_mkundef(); 463 + } 464 + 465 + ant_http1_buffer_init(&buf); 466 + if (!ant_http1_write_chunk(&buf, chunk, chunk_len)) { 467 + ant_http1_buffer_free(&buf); 468 + ant_conn_close(req->conn); 469 + server_request_release(req); 470 + return js_mkundef(); 471 + } 472 + 473 + out = ant_http1_buffer_take(&buf, &out_len); 474 + server_queue_write(req->conn, req, out, out_len, SERVER_WRITE_STREAM_READ); 475 + server_request_release(req); 476 + return js_mkundef(); 477 + } 478 + 479 + static void server_start_stream_read(server_request_t *req) { 480 + ant_t *js = req->server->js; 481 + ant_value_t next_p = 0; 482 + ant_value_t fulfill = 0; 483 + ant_value_t reject = 0; 484 + ant_value_t then_result = 0; 485 + 486 + if (!req->conn || ant_conn_is_closing(req->conn)) return; 487 + if (!is_object_type(req->response_reader)) return; 488 + 489 + next_p = rs_default_reader_read(js, req->response_reader); 490 + req->response_read_promise = next_p; 491 + fulfill = js_heavy_mkfun(js, server_stream_read_fulfill, ANT_PTR(req)); 492 + reject = js_heavy_mkfun(js, server_stream_read_reject, ANT_PTR(req)); 493 + 494 + server_request_retain(req); 495 + then_result = js_promise_then(js, next_p, fulfill, reject); 496 + promise_mark_handled(then_result); 497 + } 498 + 499 + static bool server_request_ensure_reader(server_request_t *req) { 500 + ant_t *js; 501 + ant_value_t reader_args[1]; 502 + ant_value_t saved; 503 + 504 + if (!req || !is_object_type(req->response_obj)) return false; 505 + if (vtype(req->response_reader) != T_UNDEF) return true; 506 + 507 + js = req->server->js; 508 + reader_args[0] = js_get_slot(req->response_obj, SLOT_RESPONSE_BODY_STREAM); 509 + 510 + saved = js->new_target; 511 + js->new_target = g_reader_proto; 512 + req->response_reader = js_rs_reader_ctor(js, reader_args, 1); 513 + js->new_target = saved; 514 + 515 + return !is_err(req->response_reader); 516 + } 517 + 518 + 519 + static void server_write_cb(ant_conn_t *conn, int status, void *user_data) { 520 + server_write_req_t *wr = (server_write_req_t *)user_data; 521 + server_request_t *req = wr->request; 522 + 523 + if (status < 0 && conn && !ant_conn_is_closing(conn)) 524 + ant_conn_close(conn); 525 + 526 + if (status == 0 && conn && !ant_conn_is_closing(conn)) { 527 + switch (wr->action) { 528 + case SERVER_WRITE_STREAM_READ: 529 + if (!server_request_ensure_reader(req)) { 530 + ant_conn_close(conn); 531 + break; 532 + } 533 + server_start_stream_read(req); 534 + break; 535 + 536 + case SERVER_WRITE_CLOSE_CLIENT: 537 + ant_conn_close(conn); 538 + break; 539 + 540 + default: break; 541 + }} 542 + 543 + if (req) server_request_release(req); 544 + free(wr); 545 + } 546 + 547 + static ant_value_t server_request_ip(ant_t *js, ant_value_t *args, int nargs) { 548 + server_runtime_t *server = (server_runtime_t *)(uintptr_t)(size_t)js_getnum(js_get_slot(js->current_func, SLOT_DATA)); 549 + server_request_t *req = NULL; 550 + ant_value_t out = 0; 551 + 552 + if (!server || nargs < 1) return js_mknull(); 553 + req = server_find_request(server, args[0]); 554 + if (!req || !req->conn || !ant_conn_has_remote_addr(req->conn)) return js_mknull(); 555 + 556 + out = js_mkobj(js); 557 + js_set(js, out, "address", js_mkstr(js, ant_conn_remote_addr(req->conn), strlen(ant_conn_remote_addr(req->conn)))); 558 + js_set(js, out, "port", js_mknum(ant_conn_remote_port(req->conn))); 559 + return out; 560 + } 561 + 562 + static ant_value_t server_timeout(ant_t *js, ant_value_t *args, int nargs) { 563 + server_runtime_t *server = (server_runtime_t *)(uintptr_t)(size_t)js_getnum(js_get_slot(js->current_func, SLOT_DATA)); 564 + server_request_t *req = NULL; 565 + int timeout = 0; 566 + 567 + if (!server || nargs < 2) return js_mkundef(); 568 + req = server_find_request(server, args[0]); 569 + if (!req || !req->conn) return js_mkundef(); 570 + 571 + timeout = (int)js_getnum(args[1]); 572 + ant_conn_set_timeout(req->conn, timeout); 573 + return js_mkundef(); 574 + } 575 + 576 + static ant_value_t server_stop(ant_t *js, ant_value_t *args, int nargs) { 577 + server_runtime_t *server = (server_runtime_t *)(uintptr_t)(size_t)js_getnum(js_get_slot(js->current_func, SLOT_DATA)); 578 + stop_waiter_t *waiter = NULL; 579 + ant_value_t promise = js_mkpromise(js); 580 + bool force = (nargs > 0 && js_truthy(js, args[0])); 581 + 582 + if (!server) { 583 + js_resolve_promise(js, promise, js_mkundef()); 584 + return promise; 585 + } 586 + 587 + waiter = calloc(1, sizeof(*waiter)); 588 + if (!waiter) { 589 + js_reject_promise(js, promise, js_mkerr(js, "out of memory")); 590 + return promise; 591 + } 592 + 593 + waiter->promise = promise; 594 + waiter->next = server->stop_waiters; 595 + server->stop_waiters = waiter; 596 + server_begin_stop(server, force); 597 + return promise; 598 + } 599 + 600 + static void server_process_client_request(ant_conn_t *conn, ant_http1_parsed_request_t *parsed) { 601 + server_runtime_t *server = (server_runtime_t *)ant_listener_get_user_data(ant_conn_listener(conn)); 602 + ant_t *js = server->js; 603 + ant_value_t headers = 0; 604 + ant_value_t request_obj = 0; 605 + ant_value_t result = 0; 606 + char *url = NULL; 607 + server_request_t *req = NULL; 608 + 609 + url = server_build_request_url(server, parsed); 610 + if (!url) { 611 + ant_http1_free_parsed_request(parsed); 612 + server_send_basic_response(conn, 500, "Internal Server Error", "text/plain;charset=UTF-8", (const uint8_t *)"Internal Server Error", 21); 613 + return; 614 + } 615 + 616 + headers = server_headers_from_parsed(js, parsed); 617 + if (is_err(headers)) { 618 + free(url); 619 + ant_http1_free_parsed_request(parsed); 620 + server_send_basic_response(conn, 500, "Internal Server Error", "text/plain;charset=UTF-8", (const uint8_t *)"Internal Server Error", 21); 621 + return; 622 + } 623 + 624 + request_obj = request_create(js, parsed->method, url, headers, parsed->body, parsed->body_len, parsed->content_type); 625 + free(url); 626 + ant_http1_free_parsed_request(parsed); 627 + 628 + if (is_err(request_obj)) { 629 + server_send_basic_response(conn, 500, "Internal Server Error", "text/plain;charset=UTF-8", (const uint8_t *)"Internal Server Error", 21); 630 + return; 631 + } 632 + 633 + req = calloc(1, sizeof(*req)); 634 + if (!req) { 635 + server_send_basic_response(conn, 500, "Internal Server Error", "text/plain;charset=UTF-8", (const uint8_t *)"Internal Server Error", 21); 636 + return; 637 + } 638 + 639 + req->server = server; 640 + req->conn = conn; 641 + req->request_obj = request_obj; 642 + req->response_obj = js_mkundef(); 643 + req->response_promise = js_mkundef(); 644 + req->response_reader = js_mkundef(); 645 + req->response_read_promise = js_mkundef(); 646 + req->refs = 1; 647 + req->next = server->requests; 648 + server->requests = req; 649 + ant_conn_set_user_data(conn, req); 650 + 651 + result = server_call_fetch(server, request_obj); 652 + server_handle_fetch_result(req, result); 653 + } 654 + 655 + static void server_on_read(ant_conn_t *conn, ssize_t nread, void *user_data) { 656 + ant_http1_parsed_request_t parsed = {0}; 657 + ant_http1_parse_result_t parse_result = ANT_HTTP1_PARSE_INCOMPLETE; 658 + if (!conn) return; 659 + 660 + parse_result = ant_http1_parse_request(ant_conn_buffer(conn), ant_conn_buffer_len(conn), &parsed, NULL); 661 + if (parse_result == ANT_HTTP1_PARSE_ERROR) { 662 + ant_http1_free_parsed_request(&parsed); 663 + server_send_basic_response(conn, 400, "Bad Request", "text/plain;charset=UTF-8", (const uint8_t *)"Bad Request", 11); 664 + return; 665 + } 666 + 667 + if (parse_result == ANT_HTTP1_PARSE_OK) { 668 + ant_conn_pause_read(conn); 669 + server_process_client_request(conn, &parsed); 670 + } 671 + } 672 + 673 + static void server_on_conn_close(ant_conn_t *conn, void *user_data) { 674 + server_runtime_t *server = (server_runtime_t *)user_data; 675 + server_request_t *req = (server_request_t *)ant_conn_get_user_data(conn); 676 + 677 + if (req) { 678 + req->conn = NULL; 679 + ant_conn_set_user_data(conn, NULL); 680 + server_request_release(req); 681 + } 682 + 683 + server_maybe_finish_stop(server); 684 + } 685 + 686 + static void server_on_listener_close(ant_listener_t *listener, void *user_data) { 687 + (void)listener; 688 + server_maybe_finish_stop((server_runtime_t *)user_data); 689 + } 690 + 691 + bool server_export_has_fetch_handler(ant_t *js, ant_value_t default_export, bool *looks_like_config) { 692 + ant_value_t fetch = 0; 693 + if (looks_like_config) *looks_like_config = false; 694 + if (!is_object_type(default_export)) return false; 695 + 696 + fetch = js_get(js, default_export, "fetch"); 697 + if (is_callable(fetch)) return true; 698 + 699 + if (looks_like_config) { 700 + ant_value_t port = js_get(js, default_export, "port"); 701 + ant_value_t hostname = js_get(js, default_export, "hostname"); 702 + ant_value_t idle_timeout = js_get(js, default_export, "idleTimeout"); 703 + ant_value_t unix_path = js_get(js, default_export, "unix"); 704 + ant_value_t tls = js_get(js, default_export, "tls"); 705 + 706 + *looks_like_config = 707 + vtype(fetch) != T_UNDEF || 708 + vtype(port) != T_UNDEF || 709 + vtype(hostname) != T_UNDEF || 710 + vtype(idle_timeout) != T_UNDEF || 711 + vtype(unix_path) != T_UNDEF || 712 + vtype(tls) != T_UNDEF; 713 + } 714 + 715 + return false; 716 + } 717 + 718 + ant_value_t server_start_from_export(ant_t *js, ant_value_t default_export) { 719 + server_runtime_t *server = NULL; 720 + ant_value_t port_v = 0; 721 + ant_value_t hostname_v = 0; 722 + ant_value_t timeout_v = 0; 723 + ant_value_t unix_v = 0; 724 + ant_value_t tls_v = 0; 725 + ant_listener_callbacks_t callbacks = {0}; 726 + int rc = 0; 727 + 728 + if (g_server) return js_mkerr(js, "server is already running"); 729 + if (!is_object_type(default_export)) return js_mkerr_typed(js, JS_ERR_TYPE, "Module does not export a fetch handler"); 730 + 731 + server = calloc(1, sizeof(*server)); 732 + if (!server) return js_mkerr(js, "out of memory"); 733 + 734 + server->js = js; 735 + server->export_obj = default_export; 736 + server->fetch_fn = js_get(js, default_export, "fetch"); 737 + server->hostname = strdup("0.0.0.0"); 738 + server->port = 3000; 739 + server->idle_timeout_secs = 10; 740 + server->loop = uv_default_loop(); 741 + 742 + if (!server->hostname) { 743 + free(server); 744 + return js_mkerr(js, "out of memory"); 745 + } 746 + 747 + unix_v = js_get(js, default_export, "unix"); 748 + tls_v = js_get(js, default_export, "tls"); 749 + if (vtype(unix_v) != T_UNDEF && vtype(unix_v) != T_NULL) { 750 + free(server->hostname); 751 + free(server); 752 + return js_mkerr_typed(js, JS_ERR_TYPE, "unix sockets are not implemented yet"); 753 + } 754 + if (vtype(tls_v) != T_UNDEF && vtype(tls_v) != T_NULL) { 755 + free(server->hostname); 756 + free(server); 757 + return js_mkerr_typed(js, JS_ERR_TYPE, "tls server config is not implemented yet"); 758 + } 759 + 760 + port_v = js_get(js, default_export, "port"); 761 + hostname_v = js_get(js, default_export, "hostname"); 762 + timeout_v = js_get(js, default_export, "idleTimeout"); 763 + 764 + if (vtype(port_v) != T_UNDEF && vtype(port_v) != T_NULL) { 765 + if (vtype(port_v) != T_NUM) { 766 + free(server->hostname); 767 + free(server); 768 + return js_mkerr_typed(js, JS_ERR_TYPE, "server port must be a number"); 769 + } 770 + server->port = (int)js_getnum(port_v); 771 + if (server->port < 0 || server->port > 65535) { 772 + free(server->hostname); 773 + free(server); 774 + return js_mkerr_typed(js, JS_ERR_RANGE, "server port must be between 0 and 65535"); 775 + } 776 + } 777 + 778 + if (vtype(hostname_v) != T_UNDEF && vtype(hostname_v) != T_NULL) { 779 + char *next_hostname = NULL; 780 + if (vtype(hostname_v) != T_STR) { 781 + free(server->hostname); 782 + free(server); 783 + return js_mkerr_typed(js, JS_ERR_TYPE, "server hostname must be a string"); 784 + } 785 + next_hostname = strdup(js_getstr(js, hostname_v, NULL)); 786 + if (!next_hostname) { 787 + free(server->hostname); 788 + free(server); 789 + return js_mkerr(js, "out of memory"); 790 + } 791 + free(server->hostname); 792 + server->hostname = next_hostname; 793 + } 794 + 795 + if (vtype(timeout_v) != T_UNDEF && vtype(timeout_v) != T_NULL) { 796 + if (vtype(timeout_v) != T_NUM) { 797 + free(server->hostname); 798 + free(server); 799 + return js_mkerr_typed(js, JS_ERR_TYPE, "server idleTimeout must be a number"); 800 + } 801 + server->idle_timeout_secs = (int)js_getnum(timeout_v); 802 + if (server->idle_timeout_secs < 0) { 803 + free(server->hostname); 804 + free(server); 805 + return js_mkerr_typed(js, JS_ERR_RANGE, "server idleTimeout must be >= 0"); 806 + } 807 + } 808 + 809 + uv_signal_init(server->loop, &server->sigint_handle); 810 + uv_signal_init(server->loop, &server->sigterm_handle); 811 + server->sigint_handle.data = server; 812 + server->sigterm_handle.data = server; 813 + 814 + callbacks.on_read = server_on_read; 815 + callbacks.on_conn_close = server_on_conn_close; 816 + callbacks.on_listener_close = server_on_listener_close; 817 + 818 + rc = ant_listener_listen_tcp(&server->listener, server->loop, server->hostname, server->port, 128, server->idle_timeout_secs, &callbacks, server); 819 + if (rc != 0) { 820 + free(server->hostname); 821 + free(server); 822 + return js_mkerr_typed(js, JS_ERR_TYPE, "%s", uv_strerror(rc)); 823 + } 824 + 825 + server->port = ant_listener_port(&server->listener); 826 + 827 + uv_signal_start(&server->sigint_handle, server_signal_cb, SIGINT); 828 + uv_signal_start(&server->sigterm_handle, server_signal_cb, SIGTERM); 829 + 830 + server->server_ctx = js_mkobj(js); 831 + js_set(js, server->server_ctx, "requestIP", js_heavy_mkfun(js, server_request_ip, ANT_PTR(server))); 832 + js_set(js, server->server_ctx, "timeout", js_heavy_mkfun(js, server_timeout, ANT_PTR(server))); 833 + js_set(js, server->server_ctx, "stop", js_heavy_mkfun(js, server_stop, ANT_PTR(server))); 834 + 835 + g_server = server; 836 + return js_mkundef(); 837 + } 838 + 839 + void gc_mark_server(ant_t *js, gc_mark_fn mark) { 840 + server_request_t *req = NULL; 841 + stop_waiter_t *waiter = NULL; 842 + 843 + if (!g_server) return; 844 + mark(js, g_server->export_obj); 845 + mark(js, g_server->fetch_fn); 846 + mark(js, g_server->server_ctx); 847 + 848 + for (req = g_server->requests; req; req = req->next) { 849 + mark(js, req->request_obj); 850 + mark(js, req->response_obj); 851 + mark(js, req->response_promise); 852 + mark(js, req->response_reader); 853 + mark(js, req->response_read_promise); 854 + } 855 + 856 + for (waiter = g_server->stop_waiters; waiter; waiter = waiter->next) 857 + mark(js, waiter->promise); 858 + }
+6 -1
src/modules/url.c
··· 74 74 strcmp(proto, "wss:") == 0; 75 75 } 76 76 77 + static bool uses_authority_syntax(const char *proto) { 78 + if (!proto) return false; 79 + return is_special_scheme(proto) || strcmp(proto, "file:") == 0; 80 + } 81 + 77 82 char *form_urlencode_n(const char *str, size_t len) { 78 83 if (!str) return strdup(""); 79 84 char *out = malloc(len * 3 + 1); ··· 322 327 (s->password && *s->password) || 323 328 (s->port && *s->port); 324 329 325 - bool opaque_like = !has_authority && !is_special_scheme(s->protocol); 330 + bool opaque_like = !has_authority && !uses_authority_syntax(s->protocol); 326 331 const char *pathname = s->pathname ? s->pathname : ""; 327 332 size_t len = strlen(s->protocol) + strlen(pathname) + strlen(s->search) + strlen(s->hash) + 32; 328 333
+286
src/net/connection.c
··· 1 + #include <compat.h> // IWYU pragma: keep 2 + 3 + #include <arpa/inet.h> 4 + #include <netinet/in.h> 5 + #include <stdlib.h> 6 + #include <string.h> 7 + 8 + #include "net/connection.h" 9 + #include "net/listener.h" 10 + 11 + #define ANT_CONN_READ_BUFFER_SIZE (16 * 1024) 12 + 13 + typedef struct { 14 + uv_write_t req; 15 + uv_buf_t buf; 16 + ant_conn_t *conn; 17 + ant_conn_write_cb cb; 18 + void *user_data; 19 + } ant_conn_write_req_t; 20 + 21 + static void ant_conn_restart_timer(ant_conn_t *conn); 22 + static void ant_conn_close_cb(uv_handle_t *handle); 23 + 24 + static void ant_listener_remove_conn(ant_listener_t *listener, ant_conn_t *conn) { 25 + ant_conn_t **it = NULL; 26 + if (!listener || !conn) return; 27 + 28 + for (it = &listener->connections; *it; it = &(*it)->next) { 29 + if (*it == conn) { 30 + *it = conn->next; 31 + return; 32 + }} 33 + } 34 + 35 + static bool ant_conn_store_peer_addr(ant_conn_t *conn) { 36 + struct sockaddr_storage addr; 37 + int len = sizeof(addr); 38 + 39 + if (uv_tcp_getpeername(&conn->handle, (struct sockaddr *)&addr, &len) != 0) return false; 40 + if (addr.ss_family == AF_INET) { 41 + struct sockaddr_in *in = (struct sockaddr_in *)&addr; 42 + uv_ip4_name(in, conn->remote_addr, sizeof(conn->remote_addr)); 43 + conn->remote_port = ntohs(in->sin_port); 44 + conn->has_remote_addr = true; 45 + return true; 46 + } 47 + if (addr.ss_family == AF_INET6) { 48 + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr; 49 + uv_ip6_name(in6, conn->remote_addr, sizeof(conn->remote_addr)); 50 + conn->remote_port = ntohs(in6->sin6_port); 51 + conn->has_remote_addr = true; 52 + return true; 53 + } 54 + return false; 55 + } 56 + 57 + static void ant_conn_timeout_cb(uv_timer_t *handle) { 58 + ant_conn_t *conn = (ant_conn_t *)handle->data; 59 + ant_conn_close(conn); 60 + } 61 + 62 + static void ant_conn_restart_timer(ant_conn_t *conn) { 63 + uint64_t timeout_ms = 0; 64 + 65 + if (!conn || conn->closing) return; 66 + uv_timer_stop(&conn->timer); 67 + if (conn->timeout_secs <= 0) return; 68 + 69 + timeout_ms = (uint64_t)conn->timeout_secs * 1000ULL; 70 + uv_timer_start(&conn->timer, ant_conn_timeout_cb, timeout_ms, 0); 71 + } 72 + 73 + static void ant_conn_alloc_cb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { 74 + ant_conn_t *conn = (ant_conn_t *)handle->data; 75 + size_t need = 0; 76 + size_t next_cap = 0; 77 + char *next = NULL; 78 + 79 + if (!conn) { 80 + buf->base = NULL; 81 + buf->len = 0; 82 + return; 83 + } 84 + 85 + need = conn->buffer_len + suggested_size; 86 + if (need > conn->buffer_cap) { 87 + next_cap = conn->buffer_cap ? conn->buffer_cap * 2 : ANT_CONN_READ_BUFFER_SIZE; 88 + while (next_cap < need) next_cap *= 2; 89 + next = realloc(conn->buffer, next_cap); 90 + if (!next) { 91 + buf->base = NULL; 92 + buf->len = 0; 93 + return; 94 + } 95 + conn->buffer = next; 96 + conn->buffer_cap = next_cap; 97 + } 98 + 99 + buf->base = conn->buffer + conn->buffer_len; 100 + buf->len = conn->buffer_cap - conn->buffer_len; 101 + } 102 + 103 + static void ant_conn_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { 104 + ant_conn_t *conn = (ant_conn_t *)stream->data; 105 + ant_listener_t *listener = conn ? conn->listener : NULL; 106 + (void)buf; 107 + 108 + if (!conn || !listener) return; 109 + if (nread < 0) { 110 + ant_conn_close(conn); 111 + return; 112 + } 113 + if (nread == 0) return; 114 + 115 + conn->buffer_len += (size_t)nread; 116 + ant_conn_restart_timer(conn); 117 + 118 + if (listener->callbacks.on_read) 119 + listener->callbacks.on_read(conn, nread, listener->user_data); 120 + } 121 + 122 + static void ant_conn_write_cb_impl(uv_write_t *req, int status) { 123 + ant_conn_write_req_t *wr = (ant_conn_write_req_t *)req; 124 + 125 + if (wr->cb) wr->cb(wr->conn, status, wr->user_data); 126 + free(wr->buf.base); 127 + free(wr); 128 + } 129 + 130 + static void ant_conn_close_cb(uv_handle_t *handle) { 131 + ant_conn_t *conn = (ant_conn_t *)handle->data; 132 + ant_listener_t *listener = conn ? conn->listener : NULL; 133 + if (!conn || !listener) return; 134 + 135 + if (--conn->close_handles > 0) return; 136 + 137 + ant_listener_remove_conn(listener, conn); 138 + if (listener->callbacks.on_conn_close) 139 + listener->callbacks.on_conn_close(conn, listener->user_data); 140 + 141 + free(conn->buffer); 142 + free(conn); 143 + } 144 + 145 + ant_conn_t *ant_conn_create_tcp(ant_listener_t *listener, int timeout_secs) { 146 + ant_conn_t *conn = NULL; 147 + 148 + if (!listener || !listener->loop) return NULL; 149 + 150 + conn = calloc(1, sizeof(*conn)); 151 + if (!conn) return NULL; 152 + 153 + conn->listener = listener; 154 + conn->timeout_secs = timeout_secs; 155 + conn->buffer_cap = ANT_CONN_READ_BUFFER_SIZE; 156 + conn->buffer = malloc(conn->buffer_cap); 157 + if (!conn->buffer) { 158 + free(conn); 159 + return NULL; 160 + } 161 + 162 + uv_tcp_init(listener->loop, &conn->handle); 163 + uv_timer_init(listener->loop, &conn->timer); 164 + conn->handle.data = conn; 165 + conn->timer.data = conn; 166 + return conn; 167 + } 168 + 169 + int ant_conn_accept(ant_conn_t *conn, uv_stream_t *server_stream) { 170 + if (!conn || !server_stream) return UV_EINVAL; 171 + 172 + if (uv_accept(server_stream, (uv_stream_t *)&conn->handle) != 0) 173 + return UV_ECONNABORTED; 174 + 175 + ant_conn_store_peer_addr(conn); 176 + conn->next = conn->listener->connections; 177 + conn->listener->connections = conn; 178 + return 0; 179 + } 180 + 181 + void ant_conn_start(ant_conn_t *conn) { 182 + if (!conn || conn->closing) return; 183 + ant_conn_restart_timer(conn); 184 + uv_read_start((uv_stream_t *)&conn->handle, ant_conn_alloc_cb, ant_conn_read_cb); 185 + } 186 + 187 + void ant_conn_set_user_data(ant_conn_t *conn, void *user_data) { 188 + if (conn) conn->user_data = user_data; 189 + } 190 + 191 + void *ant_conn_get_user_data(const ant_conn_t *conn) { 192 + return conn ? conn->user_data : NULL; 193 + } 194 + 195 + ant_listener_t *ant_conn_listener(const ant_conn_t *conn) { 196 + return conn ? conn->listener : NULL; 197 + } 198 + 199 + const char *ant_conn_buffer(const ant_conn_t *conn) { 200 + return conn ? conn->buffer : NULL; 201 + } 202 + 203 + size_t ant_conn_buffer_len(const ant_conn_t *conn) { 204 + return conn ? conn->buffer_len : 0; 205 + } 206 + 207 + void ant_conn_set_timeout(ant_conn_t *conn, int timeout_secs) { 208 + if (!conn) return; 209 + conn->timeout_secs = timeout_secs < 0 ? 0 : timeout_secs; 210 + ant_conn_restart_timer(conn); 211 + } 212 + 213 + int ant_conn_timeout(const ant_conn_t *conn) { 214 + return conn ? conn->timeout_secs : 0; 215 + } 216 + 217 + bool ant_conn_is_closing(const ant_conn_t *conn) { 218 + return !conn || conn->closing; 219 + } 220 + 221 + bool ant_conn_has_remote_addr(const ant_conn_t *conn) { 222 + return conn && conn->has_remote_addr; 223 + } 224 + 225 + const char *ant_conn_remote_addr(const ant_conn_t *conn) { 226 + return conn ? conn->remote_addr : NULL; 227 + } 228 + 229 + int ant_conn_remote_port(const ant_conn_t *conn) { 230 + return conn ? conn->remote_port : 0; 231 + } 232 + 233 + void ant_conn_pause_read(ant_conn_t *conn) { 234 + if (!conn || conn->closing) return; 235 + uv_read_stop((uv_stream_t *)&conn->handle); 236 + } 237 + 238 + void ant_conn_close(ant_conn_t *conn) { 239 + if (!conn || conn->closing) return; 240 + conn->closing = true; 241 + 242 + conn->close_handles = 0; 243 + if (!uv_is_closing((uv_handle_t *)&conn->timer)) { 244 + uv_timer_stop(&conn->timer); 245 + uv_close((uv_handle_t *)&conn->timer, ant_conn_close_cb); 246 + conn->close_handles++; 247 + } 248 + 249 + if (!uv_is_closing((uv_handle_t *)&conn->handle)) { 250 + uv_close((uv_handle_t *)&conn->handle, ant_conn_close_cb); 251 + conn->close_handles++; 252 + } 253 + 254 + if (conn->close_handles == 0) ant_conn_close_cb((uv_handle_t *)&conn->handle); 255 + } 256 + 257 + int ant_conn_write(ant_conn_t *conn, char *data, size_t len, ant_conn_write_cb cb, void *user_data) { 258 + ant_conn_write_req_t *wr = NULL; 259 + int rc = 0; 260 + 261 + if (!conn || conn->closing) { 262 + free(data); 263 + return UV_EPIPE; 264 + } 265 + 266 + wr = calloc(1, sizeof(*wr)); 267 + if (!wr) { 268 + free(data); 269 + return UV_ENOMEM; 270 + } 271 + 272 + wr->buf = uv_buf_init(data, (unsigned int)len); 273 + wr->conn = conn; 274 + wr->cb = cb; 275 + wr->user_data = user_data; 276 + 277 + ant_conn_restart_timer(conn); 278 + rc = uv_write(&wr->req, (uv_stream_t *)&conn->handle, &wr->buf, 1, ant_conn_write_cb_impl); 279 + if (rc != 0) { 280 + free(wr->buf.base); 281 + free(wr); 282 + return rc; 283 + } 284 + 285 + return 0; 286 + }
+114
src/net/listener.c
··· 1 + #include <compat.h> // IWYU pragma: keep 2 + 3 + #include <arpa/inet.h> 4 + #include <netinet/in.h> 5 + #include <stdlib.h> 6 + #include <string.h> 7 + 8 + #include "net/connection.h" 9 + #include "net/listener.h" 10 + 11 + static void ant_listener_close_cb(uv_handle_t *handle) { 12 + ant_listener_t *listener = (ant_listener_t *)handle->data; 13 + if (!listener) return; 14 + listener->closed = true; 15 + if (listener->callbacks.on_listener_close) 16 + listener->callbacks.on_listener_close(listener, listener->user_data); 17 + } 18 + 19 + static void ant_listener_accept_cb(uv_stream_t *server_stream, int status) { 20 + ant_listener_t *listener = (ant_listener_t *)server_stream->data; 21 + ant_conn_t *conn = NULL; 22 + 23 + if (status < 0 || !listener || listener->closing) return; 24 + 25 + conn = ant_conn_create_tcp(listener, listener->idle_timeout_secs); 26 + if (!conn) return; 27 + 28 + if (ant_conn_accept(conn, server_stream) != 0) { 29 + ant_conn_close(conn); 30 + return; 31 + } 32 + 33 + if (listener->callbacks.on_accept) 34 + listener->callbacks.on_accept(listener, conn, listener->user_data); 35 + 36 + ant_conn_start(conn); 37 + } 38 + 39 + int ant_listener_listen_tcp( 40 + ant_listener_t *listener, 41 + uv_loop_t *loop, 42 + const char *hostname, 43 + int port, 44 + int backlog, 45 + int idle_timeout_secs, 46 + const ant_listener_callbacks_t *callbacks, 47 + void *user_data 48 + ) { 49 + struct sockaddr_in addr; 50 + int rc = 0; 51 + int addr_len = sizeof(addr); 52 + 53 + if (!listener || !loop || !hostname) return UV_EINVAL; 54 + memset(listener, 0, sizeof(*listener)); 55 + 56 + listener->loop = loop; 57 + listener->user_data = user_data; 58 + listener->idle_timeout_secs = idle_timeout_secs; 59 + listener->port = port; 60 + listener->backlog = backlog > 0 ? backlog : 128; 61 + if (callbacks) listener->callbacks = *callbacks; 62 + 63 + uv_tcp_init(loop, &listener->handle); 64 + listener->handle.data = listener; 65 + 66 + rc = uv_ip4_addr(hostname, port, &addr); 67 + if (rc != 0) return rc; 68 + 69 + rc = uv_tcp_bind(&listener->handle, (const struct sockaddr *)&addr, 0); 70 + if (rc != 0) return rc; 71 + 72 + rc = uv_listen((uv_stream_t *)&listener->handle, listener->backlog, ant_listener_accept_cb); 73 + if (rc != 0) return rc; 74 + 75 + listener->started = true; 76 + if (port == 0 && uv_tcp_getsockname(&listener->handle, (struct sockaddr *)&addr, &addr_len) == 0) 77 + listener->port = ntohs(addr.sin_port); 78 + 79 + return 0; 80 + } 81 + 82 + void ant_listener_stop(ant_listener_t *listener, bool force) { 83 + ant_conn_t *conn = NULL; 84 + ant_conn_t *next = NULL; 85 + 86 + if (!listener) return; 87 + listener->closing = true; 88 + 89 + if (listener->started && !uv_is_closing((uv_handle_t *)&listener->handle)) 90 + uv_close((uv_handle_t *)&listener->handle, ant_listener_close_cb); 91 + else if (!listener->started) listener->closed = true; 92 + 93 + if (force) { 94 + for (conn = listener->connections; conn; conn = next) { 95 + next = conn->next; 96 + ant_conn_close(conn); 97 + }} 98 + } 99 + 100 + bool ant_listener_has_connections(const ant_listener_t *listener) { 101 + return listener && listener->connections != NULL; 102 + } 103 + 104 + bool ant_listener_is_closed(const ant_listener_t *listener) { 105 + return !listener || listener->closed; 106 + } 107 + 108 + int ant_listener_port(const ant_listener_t *listener) { 109 + return listener ? listener->port : 0; 110 + } 111 + 112 + void *ant_listener_get_user_data(const ant_listener_t *listener) { 113 + return listener ? listener->user_data : NULL; 114 + }
+9 -5
src/silver/ast.c
··· 192 192 return tok == TOK_IDENTIFIER || tok == TOK_DEFAULT || is_contextual_ident_tok(tok); 193 193 } 194 194 195 + static inline bool is_private_ident_like_tok(uint8_t tok) { 196 + return tok >= TOK_IDENTIFIER && tok < TOK_IDENT_LIKE_END; 197 + } 198 + 195 199 static inline bool sv_strict_forbidden_binding_ident(const char *s, uint32_t len) { 196 200 return is_eval_or_arguments_name(s, len) || is_strict_reserved_name(s, len); 197 201 } ··· 810 814 l_private_name: { 811 815 CONSUME(); 812 816 NEXT(); 813 - if (!is_ident_like_tok(TOK)) { 817 + if (!is_private_ident_like_tok(TOK)) { 814 818 SV_MKERR_TYPED(JS, JS_ERR_SYNTAX, "private field name expected"); 815 819 return mk(N_EMPTY); 816 820 } ··· 1019 1023 if (TOK == TOK_HASH) { 1020 1024 CONSUME(); 1021 1025 NEXT(); 1022 - if (!is_ident_like_tok(TOK)) { 1026 + if (!is_private_ident_like_tok(TOK)) { 1023 1027 SV_MKERR_TYPED(JS, JS_ERR_SYNTAX, "private field name expected"); 1024 1028 return mk(N_EMPTY); 1025 1029 } ··· 1062 1066 } else if (TOK == TOK_HASH) { 1063 1067 CONSUME(); 1064 1068 NEXT(); 1065 - if (!is_ident_like_tok(TOK)) { 1069 + if (!is_private_ident_like_tok(TOK)) { 1066 1070 SV_MKERR_TYPED(JS, JS_ERR_SYNTAX, "private field name expected"); 1067 1071 return mk(N_EMPTY); 1068 1072 } ··· 1342 1346 if ((TLEN == 3 && memcmp(tok_str(p), "get", 3) == 0) || 1343 1347 (TLEN == 3 && memcmp(tok_str(p), "set", 3) == 0)) { 1344 1348 uint8_t la = LA(); 1345 - if (la != TOK_LPAREN) { 1349 + if (la != TOK_LPAREN && la != TOK_ASSIGN && la != TOK_SEMICOLON && la != TOK_RBRACE) { 1346 1350 flags |= (tok_str(p)[0] == 'g') ? FN_GETTER : FN_SETTER; 1347 1351 CONSUME(); 1348 1352 NEXT(); ··· 1357 1361 } else if (TOK == TOK_HASH) { 1358 1362 CONSUME(); 1359 1363 NEXT(); 1360 - if (!is_ident_like_tok(TOK)) { 1364 + if (!is_private_ident_like_tok(TOK)) { 1361 1365 SV_MKERR_TYPED(JS, JS_ERR_SYNTAX, "private field name expected"); 1362 1366 return mk(N_EMPTY); 1363 1367 }
+25 -15
src/silver/compiler.c
··· 3773 3773 return NULL; 3774 3774 } 3775 3775 3776 - static void compile_class_method(sv_compiler_t *c, sv_ast_t *m, 3777 - int ctor_local, int proto_local, 3778 - int preeval_key) { 3776 + static inline bool is_class_method_def(const sv_ast_t *m) { 3777 + return 3778 + m && m->right && m->right->type == N_FUNC && 3779 + (m->right->flags & FN_METHOD); 3780 + } 3781 + 3782 + static void compile_class_method( 3783 + sv_compiler_t *c, sv_ast_t *m, 3784 + int ctor_local, int proto_local, 3785 + int preeval_key 3786 + ) { 3779 3787 bool is_static = !!(m->flags & FN_STATIC); 3780 3788 int home_local = is_static ? ctor_local : proto_local; 3781 - bool is_fn = (m->right && m->right->type == N_FUNC); 3789 + bool is_fn = is_class_method_def(m); 3782 3790 3783 3791 if (is_fn) { 3784 3792 compile_func_expr(c, m->right); ··· 3824 3832 if (m->type != N_METHOD) continue; 3825 3833 if (m == ctor_method) continue; 3826 3834 if (m->flags & FN_STATIC) continue; 3827 - bool is_fn = (m->right && m->right->type == N_FUNC); 3835 + bool is_fn = is_class_method_def(m); 3828 3836 if (!is_fn) field_count++; 3829 3837 } 3830 3838 ··· 3839 3847 if (m->type != N_METHOD) continue; 3840 3848 if (m == ctor_method) continue; 3841 3849 if (m->flags & FN_STATIC) continue; 3842 - bool is_fn = (m->right && m->right->type == N_FUNC); 3850 + bool is_fn = is_class_method_def(m); 3843 3851 if (!is_fn) { 3844 3852 field_inits[fi] = m; 3845 3853 if (m->flags & FN_COMPUTED) { ··· 3847 3855 int loc = add_local(c, "", 0, false, c->scope_depth); 3848 3856 emit_put_local(c, loc); 3849 3857 computed_key_locals[fi] = loc; 3850 - } else { 3851 - computed_key_locals[fi] = -1; 3852 - } 3858 + } else computed_key_locals[fi] = -1; 3853 3859 fi++; 3854 3860 } 3855 3861 } ··· 3861 3867 sv_ast_t *m = node->args.items[i]; 3862 3868 if (m->type != N_METHOD || !(m->flags & FN_COMPUTED)) continue; 3863 3869 if (m == ctor_method) continue; 3864 - bool is_fn = (m->right && m->right->type == N_FUNC); 3870 + bool is_fn = is_class_method_def(m); 3865 3871 if (!is_fn && !(m->flags & FN_STATIC)) continue; 3866 3872 if (!method_comp_keys) { 3867 3873 method_comp_keys = malloc(sizeof(int) * node->args.count); ··· 4002 4008 end_scope(c); 4003 4009 continue; 4004 4010 } 4011 + 4005 4012 if (m->type != N_METHOD) continue; 4006 4013 if (m == ctor_method) continue; 4007 - bool is_fn = (m->right && m->right->type == N_FUNC); 4014 + 4015 + bool is_fn = is_class_method_def(m); 4008 4016 if (!is_fn && !(m->flags & FN_STATIC)) continue; 4009 - compile_class_method(c, m, ctor_local, proto_local, 4010 - method_comp_keys ? method_comp_keys[i] : -1); 4017 + 4018 + compile_class_method( 4019 + c, m, ctor_local, proto_local, 4020 + method_comp_keys ? method_comp_keys[i] : -1 4021 + ); 4011 4022 } 4012 4023 4013 4024 free(method_comp_keys); ··· 4027 4038 c->locals[outer_name_local].is_tdz = false; 4028 4039 } 4029 4040 4030 - if (node->str) 4031 - end_scope(c); 4041 + if (node->str) end_scope(c); 4032 4042 } 4033 4043 4034 4044 static sv_func_t *compile_function_body(
+1 -1
src/streams/brotli.c
··· 11 11 #include "streams/brotli.h" 12 12 #include "streams/transform.h" 13 13 14 - #define BROTLI_CHUNK_SIZE (1024 * 32) 14 + #define BROTLI_CHUNK_SIZE (32 * 1024) 15 15 16 16 struct brotli_stream_state { 17 17 bool decompress;
+3 -5
tests/bench_server.js
··· 1 - function meow(c) {} 2 - 3 - function server(c) { 4 - c.res.body('meow'); 1 + function server() { 2 + return new Response('meow'); 5 3 } 6 4 7 - Ant.serve(8000, server); 5 + export default { fetch: server };
-16
tests/multi_server.cjs
··· 1 - // Example: Running multiple HTTP servers on different ports 2 - 3 - function handler8000(c) { 4 - c.res.body("Server on port 8000\nURI: " + c.req.uri); 5 - } 6 - 7 - function handler8001(c) { 8 - c.res.body("Server on port 8001\nURI: " + c.req.uri); 9 - } 10 - 11 - console.log("Starting multiple HTTP servers..."); 12 - 13 - // Note: Currently Ant.serve() is blocking, so you can only run one server 14 - // In the future, we could make it non-blocking to support truly concurrent servers 15 - console.log("Starting server on port 8000..."); 16 - Ant.serve(8000, handler8000);
+30
tests/private_fields.js
··· 124 124 } 125 125 console.assert(fast.get() === 1000, "FastCounter should reach 1000"); 126 126 127 + // Private fields may use keyword-like names 128 + class KeywordPrivate { 129 + #var = 7; 130 + #default = 9; 131 + 132 + sum() { 133 + return this.#var + this.#default; 134 + } 135 + } 136 + 137 + const keywordPrivate = new KeywordPrivate(); 138 + console.assert(keywordPrivate.sum() === 16, "Keyword-named private fields should parse and work"); 139 + 140 + // Class fields named get/set should remain fields, not accessors 141 + class FieldNamedAccessor { 142 + #value = 0; 143 + 144 + set = (value) => { 145 + this.#value = value; 146 + }; 147 + 148 + get = () => { 149 + return this.#value; 150 + }; 151 + } 152 + 153 + const fieldNamedAccessor = new FieldNamedAccessor(); 154 + fieldNamedAccessor.set(23); 155 + console.assert(fieldNamedAccessor.get() === 23, "Field names get/set should support arrow initializers"); 156 + 127 157 console.log("All private fields tests passed!");
+6 -6
tests/server.async.js
··· 1 1 let count = 0; 2 2 3 - async function meow(c) { 3 + async function meow() { 4 4 count++; 5 - c.res.body(`count is ${count}`); 5 + return new Response(`count is ${count}`); 6 6 } 7 7 8 - async function server(c) { 9 - return await meow(c); 8 + async function server() { 9 + return await meow(); 10 10 } 11 11 12 - console.log('server on http://localhost:8000'); 13 - Ant.serve(8000, server); 12 + console.log('server on http://localhost:3000'); 13 + export default { fetch: server };
-16
tests/server_example.cjs
··· 1 - // Example HTTP server using Ant.serve 2 - 3 - // Define a request handler 4 - function handleRequest(c) { 5 - console.log('Received request:', c.req.method, c.req.uri); 6 - 7 - const userAgent = c.req.header('User-Agent'); 8 - c.res.header('X-Message', 'My custom message'); 9 - 10 - // Return a response 11 - c.res.body('Hello from Ant HTTP Server!\nMethod: ' + c.req.method + '\nURI: ' + c.req.uri + '\nUser-Agent: ' + userAgent); 12 - } 13 - 14 - // Start the server on port 8000 15 - console.log('Starting HTTP server...'); 16 - Ant.serve(8000, handleRequest);
-29
tests/server_routes.cjs
··· 1 - // Example HTTP server with basic routing 2 - 3 - function handleRequest(c) { 4 - console.log("Request:", c.req.method, c.req.uri); 5 - 6 - // Simple routing based on URI 7 - if (c.req.uri === "/") { 8 - c.res.body("Welcome to Ant HTTP Server!\n\nAvailable routes:\n GET /\n GET /hello\n GET /status\n GET /echo"); 9 - } 10 - else if (c.req.uri === "/hello") { 11 - c.res.body("Hello, World!"); 12 - } 13 - else if (c.req.uri === "/status") { 14 - c.res.header('X-Server', 'Ant'); 15 - c.res.body("Server is running!"); 16 - } 17 - else if (c.req.uri === "/echo") { 18 - const userAgent = c.req.header('User-Agent') || 'Unknown'; 19 - c.res.body("Method: " + c.req.method + "\nURI: " + c.req.uri + "\nQuery: " + c.req.query + "\nBody: " + c.req.body + "\nUser-Agent: " + userAgent); 20 - } 21 - else { 22 - // 404 for unknown routes 23 - c.res.status(404); 24 - c.res.body("Not Found: " + c.req.uri); 25 - } 26 - } 27 - 28 - console.log("Starting HTTP server on port 8000..."); 29 - Ant.serve(8000, handleRequest);