xbintsc 0.2.9 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/README.md +17 -2
  2. package/README.zh-CN.md +16 -2
  3. package/bin/xbintsc.js +49 -10
  4. package/dist/src/ast/expressions.d.ts +2 -0
  5. package/dist/src/binder/binder.d.ts +24 -98
  6. package/dist/src/binder/binder.js +13 -559
  7. package/dist/src/binder/binder.js.map +1 -1
  8. package/dist/src/binder/declarations.d.ts +16 -0
  9. package/dist/src/binder/declarations.js +168 -0
  10. package/dist/src/binder/declarations.js.map +1 -0
  11. package/dist/src/binder/helpers.d.ts +11 -0
  12. package/dist/src/binder/helpers.js +46 -0
  13. package/dist/src/binder/helpers.js.map +1 -0
  14. package/dist/src/binder/references.d.ts +21 -0
  15. package/dist/src/binder/references.js +349 -0
  16. package/dist/src/binder/references.js.map +1 -0
  17. package/dist/src/binder/types.d.ts +114 -0
  18. package/dist/src/binder/types.js +27 -0
  19. package/dist/src/binder/types.js.map +1 -0
  20. package/dist/src/cli/main.d.ts +1 -0
  21. package/dist/src/cli/main.js +40 -0
  22. package/dist/src/cli/main.js.map +1 -1
  23. package/dist/src/codegen/generator/calls/access.d.ts +13 -0
  24. package/dist/src/codegen/generator/calls/access.js +115 -0
  25. package/dist/src/codegen/generator/calls/access.js.map +1 -0
  26. package/dist/src/codegen/generator/calls/closures.d.ts +11 -0
  27. package/dist/src/codegen/generator/calls/closures.js +50 -0
  28. package/dist/src/codegen/generator/calls/closures.js.map +1 -0
  29. package/dist/src/codegen/generator/calls/invocation.d.ts +18 -0
  30. package/dist/src/codegen/generator/calls/invocation.js +242 -0
  31. package/dist/src/codegen/generator/calls/invocation.js.map +1 -0
  32. package/dist/src/codegen/generator/calls/literals.d.ts +10 -0
  33. package/dist/src/codegen/generator/calls/literals.js +69 -0
  34. package/dist/src/codegen/generator/calls/literals.js.map +1 -0
  35. package/dist/src/codegen/generator/calls/super.d.ts +10 -0
  36. package/dist/src/codegen/generator/calls/super.js +47 -0
  37. package/dist/src/codegen/generator/calls/super.js.map +1 -0
  38. package/dist/src/codegen/generator/calls.d.ts +15 -24
  39. package/dist/src/codegen/generator/calls.js +15 -482
  40. package/dist/src/codegen/generator/calls.js.map +1 -1
  41. package/dist/src/codegen/generator/context.d.ts +1 -1
  42. package/dist/src/codegen/generator/context.js +2 -2
  43. package/dist/src/codegen/generator/context.js.map +1 -1
  44. package/dist/src/codegen/generator/expressions/assignment.d.ts +13 -0
  45. package/dist/src/codegen/generator/expressions/assignment.js +203 -0
  46. package/dist/src/codegen/generator/expressions/assignment.js.map +1 -0
  47. package/dist/src/codegen/generator/expressions/operators.d.ts +14 -0
  48. package/dist/src/codegen/generator/expressions/operators.js +163 -0
  49. package/dist/src/codegen/generator/expressions/operators.js.map +1 -0
  50. package/dist/src/codegen/generator/expressions/primary.d.ts +17 -0
  51. package/dist/src/codegen/generator/expressions/primary.js +260 -0
  52. package/dist/src/codegen/generator/expressions/primary.js.map +1 -0
  53. package/dist/src/codegen/generator/expressions.d.ts +11 -21
  54. package/dist/src/codegen/generator/expressions.js +11 -494
  55. package/dist/src/codegen/generator/expressions.js.map +1 -1
  56. package/dist/src/codegen/generator/module.js +16 -4
  57. package/dist/src/codegen/generator/module.js.map +1 -1
  58. package/dist/src/codegen/generator/state.js +8 -0
  59. package/dist/src/codegen/generator/state.js.map +1 -1
  60. package/dist/src/codegen/generator/statements/control-flow.d.ts +14 -0
  61. package/dist/src/codegen/generator/statements/control-flow.js +199 -0
  62. package/dist/src/codegen/generator/statements/control-flow.js.map +1 -0
  63. package/dist/src/codegen/generator/statements/dispatch.d.ts +12 -0
  64. package/dist/src/codegen/generator/statements/dispatch.js +100 -0
  65. package/dist/src/codegen/generator/statements/dispatch.js.map +1 -0
  66. package/dist/src/codegen/generator/statements/loops.d.ts +13 -0
  67. package/dist/src/codegen/generator/statements/loops.js +152 -0
  68. package/dist/src/codegen/generator/statements/loops.js.map +1 -0
  69. package/dist/src/codegen/generator/statements/variables.d.ts +13 -0
  70. package/dist/src/codegen/generator/statements/variables.js +146 -0
  71. package/dist/src/codegen/generator/statements/variables.js.map +1 -0
  72. package/dist/src/codegen/generator/statements.d.ts +13 -21
  73. package/dist/src/codegen/generator/statements.js +13 -568
  74. package/dist/src/codegen/generator/statements.js.map +1 -1
  75. package/dist/src/codegen/generator/tables.js +7 -0
  76. package/dist/src/codegen/generator/tables.js.map +1 -1
  77. package/dist/src/codegen/values.d.ts +17 -17
  78. package/dist/src/codegen/values.js +21 -57
  79. package/dist/src/codegen/values.js.map +1 -1
  80. package/dist/src/diagnostics/diagnostic.d.ts +1 -0
  81. package/dist/src/diagnostics/diagnostic.js +1 -0
  82. package/dist/src/diagnostics/diagnostic.js.map +1 -1
  83. package/dist/src/diagnostics/source.d.ts +1 -1
  84. package/dist/src/diagnostics/source.js +7 -12
  85. package/dist/src/diagnostics/source.js.map +1 -1
  86. package/dist/src/driver/compiler.d.ts +4 -0
  87. package/dist/src/driver/compiler.js +51 -16
  88. package/dist/src/driver/compiler.js.map +1 -1
  89. package/dist/src/driver/index.d.ts +5 -2
  90. package/dist/src/driver/index.js +5 -2
  91. package/dist/src/driver/index.js.map +1 -1
  92. package/dist/src/driver/paths.d.ts +20 -0
  93. package/dist/src/driver/paths.js +49 -0
  94. package/dist/src/driver/paths.js.map +1 -1
  95. package/dist/src/driver/runtime-lib.d.ts +18 -0
  96. package/dist/src/driver/runtime-lib.js +31 -0
  97. package/dist/src/driver/runtime-lib.js.map +1 -0
  98. package/dist/src/driver/toolchain-download.d.ts +50 -0
  99. package/dist/src/driver/toolchain-download.js +76 -0
  100. package/dist/src/driver/toolchain-download.js.map +1 -0
  101. package/dist/src/driver/toolchain-provider.d.ts +33 -0
  102. package/dist/src/driver/toolchain-provider.js +71 -0
  103. package/dist/src/driver/toolchain-provider.js.map +1 -0
  104. package/dist/src/driver/toolchain.d.ts +9 -4
  105. package/dist/src/driver/toolchain.js +6 -10
  106. package/dist/src/driver/toolchain.js.map +1 -1
  107. package/dist/src/extensions/node/child_process/index.d.ts +4 -2
  108. package/dist/src/extensions/node/child_process/index.js +4 -2
  109. package/dist/src/extensions/node/child_process/index.js.map +1 -1
  110. package/dist/src/extensions/node/events/index.d.ts +10 -0
  111. package/dist/src/extensions/node/events/index.js +22 -0
  112. package/dist/src/extensions/node/events/index.js.map +1 -0
  113. package/dist/src/extensions/node/index.js +6 -0
  114. package/dist/src/extensions/node/index.js.map +1 -1
  115. package/dist/src/extensions/node/querystring/index.d.ts +10 -0
  116. package/dist/src/extensions/node/querystring/index.js +25 -0
  117. package/dist/src/extensions/node/querystring/index.js.map +1 -0
  118. package/dist/src/extensions/node/util/index.d.ts +11 -0
  119. package/dist/src/extensions/node/util/index.js +41 -0
  120. package/dist/src/extensions/node/util/index.js.map +1 -0
  121. package/dist/src/extensions/registry.d.ts +6 -0
  122. package/dist/src/extensions/registry.js.map +1 -1
  123. package/dist/src/index.d.ts +1 -1
  124. package/dist/src/index.js +1 -1
  125. package/dist/src/index.js.map +1 -1
  126. package/dist/src/lexer/scanner/identifiers.d.ts +9 -0
  127. package/dist/src/lexer/scanner/identifiers.js +33 -0
  128. package/dist/src/lexer/scanner/identifiers.js.map +1 -0
  129. package/dist/src/lexer/scanner/numbers.d.ts +10 -0
  130. package/dist/src/lexer/scanner/numbers.js +89 -0
  131. package/dist/src/lexer/scanner/numbers.js.map +1 -0
  132. package/dist/src/lexer/scanner/punctuation.d.ts +9 -0
  133. package/dist/src/lexer/scanner/punctuation.js +151 -0
  134. package/dist/src/lexer/scanner/punctuation.js.map +1 -0
  135. package/dist/src/lexer/scanner/regex.d.ts +11 -0
  136. package/dist/src/lexer/scanner/regex.js +69 -0
  137. package/dist/src/lexer/scanner/regex.js.map +1 -0
  138. package/dist/src/lexer/scanner/strings.d.ts +13 -0
  139. package/dist/src/lexer/scanner/strings.js +118 -0
  140. package/dist/src/lexer/scanner/strings.js.map +1 -0
  141. package/dist/src/lexer/scanner.d.ts +20 -27
  142. package/dist/src/lexer/scanner.js +11 -415
  143. package/dist/src/lexer/scanner.js.map +1 -1
  144. package/dist/src/parser/declarations/classes.d.ts +14 -0
  145. package/dist/src/parser/declarations/classes.js +191 -0
  146. package/dist/src/parser/declarations/classes.js.map +1 -0
  147. package/dist/src/parser/declarations/functions.d.ts +17 -0
  148. package/dist/src/parser/declarations/functions.js +241 -0
  149. package/dist/src/parser/declarations/functions.js.map +1 -0
  150. package/dist/src/parser/declarations/type-members.d.ts +16 -0
  151. package/dist/src/parser/declarations/type-members.js +156 -0
  152. package/dist/src/parser/declarations/type-members.js.map +1 -0
  153. package/dist/src/parser/declarations.d.ts +13 -24
  154. package/dist/src/parser/declarations.js +13 -571
  155. package/dist/src/parser/declarations.js.map +1 -1
  156. package/dist/src/parser/helpers.js +13 -4
  157. package/dist/src/parser/helpers.js.map +1 -1
  158. package/dist/src/parser/literals.js +10 -1
  159. package/dist/src/parser/literals.js.map +1 -1
  160. package/dist/tests/codegen/llvm.test.js +24 -0
  161. package/dist/tests/codegen/llvm.test.js.map +1 -1
  162. package/dist/tests/driver/compiler.test.js +3 -0
  163. package/dist/tests/driver/compiler.test.js.map +1 -1
  164. package/dist/tests/driver/paths.test.d.ts +1 -0
  165. package/dist/tests/driver/paths.test.js +26 -0
  166. package/dist/tests/driver/paths.test.js.map +1 -0
  167. package/dist/tests/driver/toolchain-download.test.d.ts +1 -0
  168. package/dist/tests/driver/toolchain-download.test.js +38 -0
  169. package/dist/tests/driver/toolchain-download.test.js.map +1 -0
  170. package/dist/tests/driver/toolchain-provider.test.d.ts +1 -0
  171. package/dist/tests/driver/toolchain-provider.test.js +37 -0
  172. package/dist/tests/driver/toolchain-provider.test.js.map +1 -0
  173. package/dist/tests/e2e/compile-node.test.d.ts +7 -0
  174. package/dist/tests/e2e/compile-node.test.js +123 -0
  175. package/dist/tests/e2e/compile-node.test.js.map +1 -0
  176. package/dist/tests/e2e/compile.test.d.ts +4 -1
  177. package/dist/tests/e2e/compile.test.js +78 -130
  178. package/dist/tests/e2e/compile.test.js.map +1 -1
  179. package/dist/tests/e2e/harness.d.ts +36 -0
  180. package/dist/tests/e2e/harness.js +64 -0
  181. package/dist/tests/e2e/harness.js.map +1 -0
  182. package/dist/tests/e2e/node-modules.test.js +60 -0
  183. package/dist/tests/e2e/node-modules.test.js.map +1 -1
  184. package/dist/tests/extensions/registry.test.js +4 -0
  185. package/dist/tests/extensions/registry.test.js.map +1 -1
  186. package/package.json +5 -3
  187. package/runtime/ext_node/buffer/buffer.c +12 -552
  188. package/runtime/ext_node/buffer/parts/byte-access.inc +35 -0
  189. package/runtime/ext_node/buffer/parts/construction.inc +60 -0
  190. package/runtime/ext_node/buffer/parts/integer-io.inc +119 -0
  191. package/runtime/ext_node/buffer/parts/methods.inc +135 -0
  192. package/runtime/ext_node/buffer/parts/prototype.inc +54 -0
  193. package/runtime/ext_node/buffer/parts/search.inc +86 -0
  194. package/runtime/ext_node/buffer/parts/static-api.inc +58 -0
  195. package/runtime/ext_node/child_process/child_process.c +37 -3
  196. package/runtime/ext_node/events/events.c +285 -0
  197. package/runtime/ext_node/http/http.c +11 -736
  198. package/runtime/ext_node/http/parts/client.inc +290 -0
  199. package/runtime/ext_node/http/parts/helpers.inc +45 -0
  200. package/runtime/ext_node/http/parts/prototypes.inc +57 -0
  201. package/runtime/ext_node/http/parts/response.inc +149 -0
  202. package/runtime/ext_node/http/parts/server.inc +133 -0
  203. package/runtime/ext_node/http/parts/string-builder.inc +58 -0
  204. package/runtime/ext_node/net/net.c +12 -504
  205. package/runtime/ext_node/net/parts/construction.inc +22 -0
  206. package/runtime/ext_node/net/parts/platform.inc +60 -0
  207. package/runtime/ext_node/net/parts/prototypes.inc +35 -0
  208. package/runtime/ext_node/net/parts/read-loop.inc +58 -0
  209. package/runtime/ext_node/net/parts/server.inc +131 -0
  210. package/runtime/ext_node/net/parts/socket-methods.inc +100 -0
  211. package/runtime/ext_node/net/parts/static-api.inc +93 -0
  212. package/runtime/ext_node/querystring/querystring.c +251 -0
  213. package/runtime/ext_node/util/util.c +456 -0
  214. package/runtime/rt.h +8 -2
  215. package/runtime/rt_internal.h +34 -0
  216. package/runtime/xt_bigint/arithmetic.inc +135 -0
  217. package/runtime/xt_bigint/bits.inc +98 -0
  218. package/runtime/xt_bigint/bitwise.inc +103 -0
  219. package/runtime/xt_bigint/compare.inc +30 -0
  220. package/runtime/xt_bigint/conversions.inc +51 -0
  221. package/runtime/xt_bigint/division.inc +85 -0
  222. package/runtime/xt_bigint/format.inc +145 -0
  223. package/runtime/xt_bigint/helpers.inc +92 -0
  224. package/runtime/xt_bigint/magnitude.inc +88 -0
  225. package/runtime/xt_bigint/public.inc +59 -0
  226. package/runtime/xt_bigint/small-arithmetic.inc +58 -0
  227. package/runtime/xt_bigint.c +42 -0
  228. package/runtime/xt_builtins.c +1 -0
  229. package/runtime/xt_io.c +7 -0
  230. package/runtime/xt_stdlib/arrays.inc +161 -0
  231. package/runtime/xt_stdlib/dispatch.inc +116 -0
  232. package/runtime/xt_stdlib/helpers.inc +23 -0
  233. package/runtime/xt_stdlib/math.inc +72 -0
  234. package/runtime/xt_stdlib/strings.inc +178 -0
  235. package/runtime/xt_stdlib.c +10 -549
  236. package/runtime/xt_stdlib2/array-statics.inc +37 -0
  237. package/runtime/xt_stdlib2/arrays.inc +189 -0
  238. package/runtime/xt_stdlib2/container.inc +23 -0
  239. package/runtime/xt_stdlib2/date.inc +72 -0
  240. package/runtime/xt_stdlib2/error.inc +22 -0
  241. package/runtime/xt_stdlib2/helpers.inc +43 -0
  242. package/runtime/xt_stdlib2/json.inc +213 -0
  243. package/runtime/xt_stdlib2/map.inc +95 -0
  244. package/runtime/xt_stdlib2/number-string-statics.inc +73 -0
  245. package/runtime/xt_stdlib2/numbers.inc +38 -0
  246. package/runtime/xt_stdlib2/objects.inc +41 -0
  247. package/runtime/xt_stdlib2/regexp-match.inc +204 -0
  248. package/runtime/xt_stdlib2/regexp.inc +20 -0
  249. package/runtime/xt_stdlib2/set.inc +105 -0
  250. package/runtime/xt_stdlib2/strings.inc +94 -0
  251. package/runtime/xt_stdlib2.c +19 -1278
  252. package/runtime/xt_values.c +155 -12
  253. package/scripts/build-runtime.ts +109 -0
  254. package/scripts/fetch-toolchain.ts +101 -0
  255. package/scripts/package-release.ts +192 -0
  256. package/src/ast/expressions.ts +2 -0
  257. package/src/binder/binder.ts +40 -725
  258. package/src/binder/declarations.ts +203 -0
  259. package/src/binder/helpers.ts +47 -0
  260. package/src/binder/references.ts +410 -0
  261. package/src/binder/types.ts +134 -0
  262. package/src/cli/main.ts +43 -0
  263. package/src/codegen/generator/calls/access.ts +139 -0
  264. package/src/codegen/generator/calls/closures.ts +60 -0
  265. package/src/codegen/generator/calls/invocation.ts +282 -0
  266. package/src/codegen/generator/calls/literals.ts +77 -0
  267. package/src/codegen/generator/calls/super.ts +61 -0
  268. package/src/codegen/generator/calls.ts +30 -552
  269. package/src/codegen/generator/context.ts +2 -2
  270. package/src/codegen/generator/expressions/assignment.ts +226 -0
  271. package/src/codegen/generator/expressions/operators.ts +182 -0
  272. package/src/codegen/generator/expressions/primary.ts +304 -0
  273. package/src/codegen/generator/expressions.ts +22 -553
  274. package/src/codegen/generator/module.ts +14 -4
  275. package/src/codegen/generator/state.ts +8 -0
  276. package/src/codegen/generator/statements/control-flow.ts +225 -0
  277. package/src/codegen/generator/statements/dispatch.ts +122 -0
  278. package/src/codegen/generator/statements/loops.ts +173 -0
  279. package/src/codegen/generator/statements/variables.ts +152 -0
  280. package/src/codegen/generator/statements.ts +26 -612
  281. package/src/codegen/generator/tables.ts +7 -0
  282. package/src/codegen/values.ts +22 -57
  283. package/src/diagnostics/diagnostic.ts +1 -0
  284. package/src/diagnostics/source.ts +7 -12
  285. package/src/driver/compiler.ts +61 -18
  286. package/src/driver/index.ts +17 -2
  287. package/src/driver/paths.ts +54 -0
  288. package/src/driver/runtime-lib.ts +32 -0
  289. package/src/driver/toolchain-download.ts +108 -0
  290. package/src/driver/toolchain-provider.ts +91 -0
  291. package/src/driver/toolchain.ts +29 -11
  292. package/src/extensions/node/child_process/index.ts +4 -2
  293. package/src/extensions/node/events/index.ts +27 -0
  294. package/src/extensions/node/index.ts +6 -0
  295. package/src/extensions/node/querystring/index.ts +29 -0
  296. package/src/extensions/node/util/index.ts +48 -0
  297. package/src/extensions/registry.ts +6 -0
  298. package/src/index.ts +1 -0
  299. package/src/lexer/scanner/identifiers.ts +37 -0
  300. package/src/lexer/scanner/numbers.ts +84 -0
  301. package/src/lexer/scanner/punctuation.ts +132 -0
  302. package/src/lexer/scanner/regex.ts +79 -0
  303. package/src/lexer/scanner/strings.ts +128 -0
  304. package/src/lexer/scanner.ts +35 -401
  305. package/src/parser/declarations/classes.ts +215 -0
  306. package/src/parser/declarations/functions.ts +254 -0
  307. package/src/parser/declarations/type-members.ts +181 -0
  308. package/src/parser/declarations.ts +32 -609
  309. package/src/parser/helpers.ts +13 -6
  310. package/src/parser/literals.ts +10 -1
  311. package/scripts/build-runtime.mjs +0 -55
@@ -21,740 +21,15 @@ unsigned char *xt_node_buffer_bytes(xt_value value, size_t *outLength);
21
21
 
22
22
  static xt_value xt_http_client_finish(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv);
23
23
 
24
- static xt_value xt_http_noop(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
25
- (void)env;
26
- (void)argc;
27
- (void)argv;
28
- return thisValue;
29
- }
30
-
31
- static xt_value xt_http_server_proto(void);
32
- static xt_value xt_http_response_proto(void);
33
- static xt_value xt_http_request_proto(void);
34
- static xt_value xt_http_client_proto(void);
35
- static xt_value xt_http_client_response_proto(void);
36
-
37
- static const char *xt_http_status_message(int code) {
38
- switch (code) {
39
- case 100: return "Continue";
40
- case 101: return "Switching Protocols";
41
- case 200: return "OK";
42
- case 201: return "Created";
43
- case 202: return "Accepted";
44
- case 204: return "No Content";
45
- case 206: return "Partial Content";
46
- case 301: return "Moved Permanently";
47
- case 302: return "Found";
48
- case 303: return "See Other";
49
- case 304: return "Not Modified";
50
- case 307: return "Temporary Redirect";
51
- case 308: return "Permanent Redirect";
52
- case 400: return "Bad Request";
53
- case 401: return "Unauthorized";
54
- case 403: return "Forbidden";
55
- case 404: return "Not Found";
56
- case 405: return "Method Not Allowed";
57
- case 409: return "Conflict";
58
- case 410: return "Gone";
59
- case 418: return "I'm a Teapot";
60
- case 422: return "Unprocessable Entity";
61
- case 429: return "Too Many Requests";
62
- case 500: return "Internal Server Error";
63
- case 501: return "Not Implemented";
64
- case 502: return "Bad Gateway";
65
- case 503: return "Service Unavailable";
66
- default: return "OK";
67
- }
68
- }
69
-
70
- /* -- tiny string builder -------------------------------------------------- */
71
-
72
- typedef struct {
73
- char *data;
74
- size_t length;
75
- size_t capacity;
76
- } xt_http_buffer;
77
-
78
- static void xt_http_buffer_init(xt_http_buffer *buffer) {
79
- buffer->capacity = 256;
80
- buffer->length = 0;
81
- buffer->data = (char *)malloc(buffer->capacity);
82
- buffer->data[0] = '\0';
83
- }
84
-
85
- static void xt_http_buffer_append(xt_http_buffer *buffer, const char *data, size_t length) {
86
- if (buffer->length + length + 1 > buffer->capacity) {
87
- while (buffer->length + length + 1 > buffer->capacity) buffer->capacity *= 2;
88
- buffer->data = (char *)realloc(buffer->data, buffer->capacity);
89
- }
90
- memcpy(buffer->data + buffer->length, data, length);
91
- buffer->length += length;
92
- buffer->data[buffer->length] = '\0';
93
- }
94
-
95
- static void xt_http_buffer_free(xt_http_buffer *buffer) { free(buffer->data); }
96
-
97
- /* Parse `name: value` header lines into an object with lower-cased keys. */
98
- static xt_value xt_http_parse_headers(const char *headers, size_t length) {
99
- xt_value object = xt_object_new();
100
- size_t i = 0;
101
- while (i < length) {
102
- size_t lineEnd = i;
103
- while (lineEnd < length && headers[lineEnd] != '\n') lineEnd++;
104
- size_t lineLength = lineEnd - i;
105
- while (lineLength > 0 && (headers[i + lineLength - 1] == '\r' || headers[i + lineLength - 1] == ' ')) lineLength--;
106
- const char *colon = memchr(headers + i, ':', lineLength);
107
- if (colon) {
108
- size_t nameLength = (size_t)(colon - (headers + i));
109
- const char *value = colon + 1;
110
- size_t valueLength = lineLength - nameLength - 1;
111
- while (valueLength > 0 && *value == ' ') {
112
- value++;
113
- valueLength--;
114
- }
115
- char *name = (char *)malloc(nameLength + 1);
116
- for (size_t j = 0; j < nameLength; j++) {
117
- char c = headers[i + j];
118
- name[j] = (c >= 'A' && c <= 'Z') ? (char)(c + 32) : c;
119
- }
120
- name[nameLength] = '\0';
121
- xt_object_set(object, xt_string_from_cstr(name), xt_string_new(value, valueLength));
122
- free(name);
123
- }
124
- i = lineEnd + 1;
125
- }
126
- return object;
127
- }
128
-
129
- /* -- response ------------------------------------------------------------- */
130
-
131
- static xt_value xt_http_response_write_head(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
132
- (void)env;
133
- if (argc < 1) return thisValue;
134
- xt_node_set(thisValue, "__statusCode", xt_number(xt_to_number(argv[0])));
135
- if (argc > 1 && XT_IS_STRING(argv[1])) xt_node_set(thisValue, "__statusMessage", argv[1]);
136
- for (int32_t i = 1; i < argc; i++) {
137
- if (XT_IS_OBJECT(argv[i])) {
138
- xt_value headers = xt_object_get_cstr(thisValue, "__headers");
139
- xt_value keys = xt_object_keys(argv[i]);
140
- int32_t count = (int32_t)xt_to_number(xt_array_length(keys));
141
- for (int32_t k = 0; k < count; k++) {
142
- xt_value key = xt_array_get(keys, xt_number((double)k));
143
- xt_object_set(headers, key, xt_object_get(argv[i], key));
144
- }
145
- }
146
- }
147
- return thisValue;
148
- }
149
-
150
- static xt_value xt_http_response_set_header(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
151
- (void)env;
152
- xt_value headers = xt_object_get_cstr(thisValue, "__headers");
153
- xt_object_set(headers, xt_arg(argc, argv, 0), xt_arg(argc, argv, 1));
154
- return thisValue;
155
- }
156
-
157
- static xt_value xt_http_response_get_header(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
158
- (void)env;
159
- xt_value headers = xt_object_get_cstr(thisValue, "__headers");
160
- return xt_object_get(headers, xt_arg(argc, argv, 0));
161
- }
162
-
163
- static xt_value xt_http_response_remove_header(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
164
- (void)env;
165
- xt_value headers = xt_object_get_cstr(thisValue, "__headers");
166
- xt_value key = xt_arg(argc, argv, 0);
167
- xt_value kept = xt_object_new();
168
- xt_value keys = xt_object_keys(headers);
169
- int32_t count = (int32_t)xt_to_number(xt_array_length(keys));
170
- for (int32_t i = 0; i < count; i++) {
171
- xt_value item = xt_array_get(keys, xt_number((double)i));
172
- if (!xt_truthy(xt_eq(item, key))) xt_object_set(kept, item, xt_object_get(headers, item));
173
- }
174
- xt_node_set(thisValue, "__headers", kept);
175
- return thisValue;
176
- }
177
-
178
- static xt_value xt_http_response_get_headers(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
179
- (void)env;
180
- (void)argc;
181
- (void)argv;
182
- return xt_object_get_cstr(thisValue, "__headers");
183
- }
184
-
185
- static xt_value xt_http_response_write(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
186
- (void)env;
187
- xt_value chunks = xt_object_get_cstr(thisValue, "__chunks");
188
- xt_array_push(chunks, xt_arg(argc, argv, 0));
189
- return xt_bool(1);
190
- }
191
-
192
- static xt_value xt_http_response_end(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
193
- (void)env;
194
- if (argc > 0 && !xt_truthy(xt_is_nullish(argv[0]))) {
195
- xt_value chunks = xt_object_get_cstr(thisValue, "__chunks");
196
- xt_array_push(chunks, argv[0]);
197
- }
198
- if (xt_truthy(xt_object_get_cstr(thisValue, "__ended"))) return thisValue;
199
- xt_node_set(thisValue, "__ended", xt_bool(1));
200
-
201
- /* Serialise the body. */
202
- xt_http_buffer body;
203
- xt_http_buffer_init(&body);
204
- xt_value chunks = xt_object_get_cstr(thisValue, "__chunks");
205
- int32_t count = (int32_t)xt_to_number(xt_array_length(chunks));
206
- for (int32_t i = 0; i < count; i++) {
207
- xt_value chunk = xt_array_get(chunks, xt_number((double)i));
208
- if (xt_node_is_buffer(chunk)) {
209
- size_t length = 0;
210
- unsigned char *bytes = xt_node_buffer_bytes(chunk, &length);
211
- xt_http_buffer_append(&body, (const char *)bytes, length);
212
- free(bytes);
213
- } else {
214
- const char *text = xt_string_data(xt_to_string(chunk));
215
- if (text) xt_http_buffer_append(&body, text, strlen(text));
216
- }
217
- }
218
-
219
- int status = (int)xt_to_number(xt_object_get_cstr(thisValue, "__statusCode"));
220
- xt_value statusMessageValue = xt_object_get_cstr(thisValue, "__statusMessage");
221
- const char *statusMessage =
222
- XT_IS_STRING(statusMessageValue) ? xt_string_data(statusMessageValue) : xt_http_status_message(status);
223
-
224
- xt_http_buffer head;
225
- xt_http_buffer_init(&head);
226
- xt_http_buffer_append(&head, "HTTP/1.1 ", 9);
227
- char code[8];
228
- int codeLength = snprintf(code, sizeof(code), "%d", status);
229
- xt_http_buffer_append(&head, code, (size_t)codeLength);
230
- xt_http_buffer_append(&head, " ", 1);
231
- xt_http_buffer_append(&head, statusMessage, strlen(statusMessage));
232
- xt_http_buffer_append(&head, "\r\n", 2);
233
-
234
- xt_value headers = xt_object_get_cstr(thisValue, "__headers");
235
- xt_value keys = xt_object_keys(headers);
236
- int32_t keyCount = (int32_t)xt_to_number(xt_array_length(keys));
237
- int hasContentLength = 0;
238
- for (int32_t i = 0; i < keyCount; i++) {
239
- xt_value key = xt_array_get(keys, xt_number((double)i));
240
- const char *name = xt_string_data(xt_to_string(key));
241
- if (!name || strcmp(name, "__proto__") == 0) continue;
242
- if (strcmp(name, "content-length") == 0) hasContentLength = 1;
243
- xt_value value = xt_object_get(headers, key);
244
- xt_http_buffer_append(&head, name, strlen(name));
245
- xt_http_buffer_append(&head, ": ", 2);
246
- const char *text = xt_string_data(xt_to_string(value));
247
- if (text) xt_http_buffer_append(&head, text, strlen(text));
248
- xt_http_buffer_append(&head, "\r\n", 2);
249
- }
250
- if (!hasContentLength) {
251
- char length[32];
252
- int lengthLength = snprintf(length, sizeof(length), "Content-Length: %zu\r\n", body.length);
253
- xt_http_buffer_append(&head, length, (size_t)lengthLength);
254
- }
255
- xt_http_buffer_append(&head, "Connection: close\r\n\r\n", 21);
256
-
257
- xt_value socket = xt_object_get_cstr(thisValue, "__socket");
258
- if (XT_IS_OBJECT(socket)) {
259
- xt_value writeFn = xt_object_get_cstr(socket, "write");
260
- if (XT_IS_FUNCTION(writeFn)) {
261
- xt_value chunk = xt_string_new(head.data, head.length);
262
- xt_call_with_this(writeFn, socket, 1, &chunk);
263
- if (body.length > 0) {
264
- xt_value bodyValue = xt_string_new(body.data, body.length);
265
- xt_call_with_this(writeFn, socket, 1, &bodyValue);
266
- }
267
- xt_value endFn = xt_object_get_cstr(socket, "end");
268
- if (XT_IS_FUNCTION(endFn)) xt_call_with_this(endFn, socket, 0, NULL);
269
- }
270
- }
271
-
272
- xt_http_buffer_free(&head);
273
- xt_http_buffer_free(&body);
274
- xt_node_emit0(thisValue, "finish");
275
- xt_node_emit0(thisValue, "close");
276
- return thisValue;
277
- }
278
-
279
- /* -- server request handling ---------------------------------------------- */
280
-
281
- static void xt_http_serve(xt_value socket, xt_value server) {
282
- xt_value bufferValue = xt_object_get_cstr(socket, "__httpBuffer");
283
- const char *buffer = XT_IS_STRING(bufferValue) ? xt_string_data(bufferValue) : "";
284
- size_t length = buffer ? strlen(buffer) : 0;
285
- const char *headerEnd = NULL;
286
- for (size_t i = 0; i + 3 < length; i++) {
287
- if (buffer[i] == '\r' && buffer[i + 1] == '\n' && buffer[i + 2] == '\r' && buffer[i + 3] == '\n') {
288
- headerEnd = buffer + i;
289
- break;
290
- }
291
- }
292
- if (!headerEnd) return;
293
-
294
- size_t headerLength = (size_t)(headerEnd - buffer) + 4;
295
- const char *lineEnd = strstr(buffer, "\r\n");
296
- if (!lineEnd) return;
297
- const char *methodEnd = strchr(buffer, ' ');
298
- const char *urlEnd = methodEnd ? strchr(methodEnd + 1, ' ') : NULL;
299
- if (!methodEnd || !urlEnd || urlEnd > lineEnd) return;
300
-
301
- xt_value req = xt_object_new_with_proto(xt_http_request_proto());
302
- xt_node_set(req, "method", xt_string_new(buffer, (size_t)(methodEnd - buffer)));
303
- xt_node_set(req, "url", xt_string_new(methodEnd + 1, (size_t)(urlEnd - methodEnd - 1)));
304
- const char *version = urlEnd + 1;
305
- size_t versionLength = (size_t)(lineEnd - version);
306
- xt_node_set(req, "httpVersion", xt_string_new(version, versionLength));
307
-
308
- xt_value headers = xt_http_parse_headers(buffer + (lineEnd - buffer) + 2, headerLength - (size_t)(lineEnd - buffer) - 4);
309
- xt_node_set(req, "headers", headers);
310
-
311
- int contentLength = 0;
312
- xt_value contentLengthValue = xt_object_get_cstr(headers, "content-length");
313
- if (!xt_truthy(xt_is_nullish(contentLengthValue))) contentLength = (int)xt_to_number(contentLengthValue);
314
- if (length < headerLength + (size_t)contentLength) return;
315
-
316
- xt_value body = xt_string_new(buffer + headerLength, (size_t)contentLength);
317
- xt_node_set(req, "__body", body);
318
-
319
- xt_value res = xt_object_new_with_proto(xt_http_response_proto());
320
- xt_node_set(res, "__socket", socket);
321
- xt_node_set(res, "__headers", xt_object_new());
322
- xt_node_set(res, "__chunks", xt_array_new(0, NULL));
323
- xt_node_set(res, "__statusCode", xt_number(200));
324
- xt_node_set(res, "__statusMessage", xt_string_from_cstr("OK"));
325
-
326
- /* Clear the consume buffer before dispatching. */
327
- xt_node_set(socket, "__httpBuffer", xt_string_from_cstr(""));
328
-
329
- xt_node_set(req, "__ended", xt_bool(0));
330
- if (contentLength > 0) xt_node_emit1(req, "data", body);
331
- xt_node_emit0(req, "end");
332
-
333
- xt_node_emit(server, "request", 2, (xt_value[]){req, res});
334
-
335
- if (!xt_truthy(xt_object_get_cstr(res, "__ended"))) {
336
- xt_value endFn = xt_object_get_cstr(res, "end");
337
- if (XT_IS_FUNCTION(endFn)) xt_call_with_this(endFn, res, 0, NULL);
338
- }
339
- }
340
-
341
- static xt_value xt_http_server_data(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
342
- xt_value server = xt_closure_env(env, 0);
343
- xt_value chunk = xt_arg(argc, argv, 0);
344
- xt_value existing = xt_object_get_cstr(thisValue, "__httpBuffer");
345
- const char *previous = XT_IS_STRING(existing) ? xt_string_data(existing) : "";
346
- const char *addition = xt_string_data(xt_to_string(chunk));
347
- if (!addition) return xt_undefined();
348
- size_t previousLength = previous ? strlen(previous) : 0;
349
- size_t additionLength = strlen(addition);
350
- char *combined = (char *)malloc(previousLength + additionLength + 1);
351
- if (previousLength) memcpy(combined, previous, previousLength);
352
- memcpy(combined + previousLength, addition, additionLength);
353
- combined[previousLength + additionLength] = '\0';
354
- xt_value combinedValue = xt_string_new(combined, previousLength + additionLength);
355
- free(combined);
356
- xt_object_set(thisValue, xt_string_from_cstr("__httpBuffer"), combinedValue);
357
- xt_http_serve(thisValue, server);
358
- return xt_undefined();
359
- }
360
-
361
- static xt_value xt_http_server_connection(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
362
- (void)thisValue;
363
- xt_value server = xt_closure_env(env, 0);
364
- xt_value socket = xt_arg(argc, argv, 0);
365
- xt_node_set(socket, "__httpBuffer", xt_string_from_cstr(""));
366
- xt_value listener = xt_closure_new((void *)xt_http_server_data, 1, &server);
367
- xt_array_push(xt_node_listeners(socket, "data", 1), listener);
368
- return xt_undefined();
369
- }
370
-
371
- /* -- server construction / delegation to net ------------------------------ */
372
-
373
- static xt_value xt_http_server_listen(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
374
- (void)env;
375
- xt_value netServer = xt_object_get_cstr(thisValue, "__net");
376
- xt_value listenFn = xt_object_get_cstr(netServer, "listen");
377
- if (XT_IS_FUNCTION(listenFn)) xt_call_with_this(listenFn, netServer, argc, argv);
378
- return thisValue;
379
- }
380
-
381
- static xt_value xt_http_server_close(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
382
- (void)env;
383
- xt_value netServer = xt_object_get_cstr(thisValue, "__net");
384
- xt_value closeFn = xt_object_get_cstr(netServer, "close");
385
- if (XT_IS_FUNCTION(closeFn)) xt_call_with_this(closeFn, netServer, argc, argv);
386
- return thisValue;
387
- }
388
-
389
- static xt_value xt_http_server_address(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
390
- (void)env;
391
- xt_value netServer = xt_object_get_cstr(thisValue, "__net");
392
- xt_value addressFn = xt_object_get_cstr(netServer, "address");
393
- if (XT_IS_FUNCTION(addressFn)) return xt_call_with_this(addressFn, netServer, argc, argv);
394
- return xt_null();
395
- }
396
-
397
- static xt_value xt_http_create_server(int32_t argc, xt_value *argv) {
398
- xt_value server = xt_object_new_with_proto(xt_http_server_proto());
399
- xt_value netArgs[1];
400
- netArgs[0] = xt_string_from_cstr("createServer");
401
- xt_value netServer = xt_net_static(netArgs[0], 0, NULL);
402
- xt_node_set(server, "__net", netServer);
403
-
404
- xt_value listener = xt_closure_new((void *)xt_http_server_connection, 1, &server);
405
- xt_array_push(xt_node_listeners(netServer, "connection", 1), listener);
406
-
407
- for (int32_t i = 0; i < argc; i++) {
408
- if (XT_IS_FUNCTION(argv[i])) xt_array_push(xt_node_listeners(server, "request", 1), argv[i]);
409
- }
410
- return server;
411
- }
412
-
413
- /* -- client --------------------------------------------------------------- */
414
-
415
- static void xt_http_parse_url(xt_value urlValue, const char **host, int *port, const char **path) {
416
- *host = "127.0.0.1";
417
- *port = 80;
418
- *path = "/";
419
- const char *url = xt_string_data(xt_to_string(urlValue));
420
- if (!url) return;
421
- static char hostBuffer[256];
422
- static char pathBuffer[1024];
423
- const char *cursor = url;
424
- if (strncmp(cursor, "http://", 7) == 0) cursor += 7;
425
- else if (strncmp(cursor, "https://", 8) == 0) cursor += 8;
426
- const char *slash = strchr(cursor, '/');
427
- const char *hostEnd = slash ? slash : cursor + strlen(cursor);
428
- const char *colon = memchr(cursor, ':', (size_t)(hostEnd - cursor));
429
- if (colon) {
430
- size_t hostLength = (size_t)(colon - cursor);
431
- if (hostLength >= sizeof(hostBuffer)) hostLength = sizeof(hostBuffer) - 1;
432
- memcpy(hostBuffer, cursor, hostLength);
433
- hostBuffer[hostLength] = '\0';
434
- *host = hostBuffer;
435
- *port = atoi(colon + 1);
436
- } else {
437
- size_t hostLength = (size_t)(hostEnd - cursor);
438
- if (hostLength >= sizeof(hostBuffer)) hostLength = sizeof(hostBuffer) - 1;
439
- memcpy(hostBuffer, cursor, hostLength);
440
- hostBuffer[hostLength] = '\0';
441
- *host = hostBuffer;
442
- }
443
- if (slash) {
444
- size_t pathLength = strlen(slash);
445
- if (pathLength >= sizeof(pathBuffer)) pathLength = sizeof(pathBuffer) - 1;
446
- memcpy(pathBuffer, slash, pathLength);
447
- pathBuffer[pathLength] = '\0';
448
- *path = pathBuffer;
449
- }
450
- }
451
-
452
- static xt_value xt_http_client_data(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
453
- (void)env;
454
- xt_value chunk = xt_arg(argc, argv, 0);
455
- xt_value existing = xt_object_get_cstr(thisValue, "__httpBuffer");
456
- const char *previous = XT_IS_STRING(existing) ? xt_string_data(existing) : "";
457
- const char *addition = xt_string_data(xt_to_string(chunk));
458
- if (!addition) return xt_undefined();
459
- size_t previousLength = previous ? strlen(previous) : 0;
460
- size_t additionLength = strlen(addition);
461
- char *combined = (char *)malloc(previousLength + additionLength + 1);
462
- if (previousLength) memcpy(combined, previous, previousLength);
463
- memcpy(combined + previousLength, addition, additionLength);
464
- combined[previousLength + additionLength] = '\0';
465
- xt_value combinedValue = xt_string_new(combined, previousLength + additionLength);
466
- free(combined);
467
- xt_object_set(thisValue, xt_string_from_cstr("__httpBuffer"), combinedValue);
468
- return xt_undefined();
469
- }
470
-
471
- static xt_value xt_http_client_write(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
472
- (void)env;
473
- xt_array_push(xt_object_get_cstr(thisValue, "__chunks"), xt_arg(argc, argv, 0));
474
- return xt_bool(1);
475
- }
476
-
477
- static void xt_http_client_send(xt_value client) {
478
- if (xt_truthy(xt_object_get_cstr(client, "__sent"))) return;
479
- xt_node_set(client, "__sent", xt_bool(1));
480
-
481
- const char *host = "127.0.0.1";
482
- int port = 80;
483
- const char *path = "/";
484
- xt_value urlValue = xt_object_get_cstr(client, "__url");
485
- if (XT_IS_STRING(urlValue)) xt_http_parse_url(urlValue, &host, &port, &path);
486
-
487
- const char *method = "GET";
488
- xt_value methodValue = xt_object_get_cstr(client, "method");
489
- if (XT_IS_STRING(methodValue)) method = xt_string_data(methodValue);
490
-
491
- xt_http_buffer body;
492
- xt_http_buffer_init(&body);
493
- xt_value chunks = xt_object_get_cstr(client, "__chunks");
494
- int32_t count = (int32_t)xt_to_number(xt_array_length(chunks));
495
- for (int32_t i = 0; i < count; i++) {
496
- xt_value chunk = xt_array_get(chunks, xt_number((double)i));
497
- if (xt_node_is_buffer(chunk)) {
498
- size_t length = 0;
499
- unsigned char *bytes = xt_node_buffer_bytes(chunk, &length);
500
- xt_http_buffer_append(&body, (const char *)bytes, length);
501
- free(bytes);
502
- } else {
503
- const char *text = xt_string_data(xt_to_string(chunk));
504
- if (text) xt_http_buffer_append(&body, text, strlen(text));
505
- }
506
- }
507
-
508
- xt_http_buffer head;
509
- xt_http_buffer_init(&head);
510
- xt_http_buffer_append(&head, method, strlen(method));
511
- xt_http_buffer_append(&head, " ", 1);
512
- xt_http_buffer_append(&head, path, strlen(path));
513
- xt_http_buffer_append(&head, " HTTP/1.1\r\nHost: ", 17);
514
- xt_http_buffer_append(&head, host, strlen(host));
515
- char portBuffer[16];
516
- int portLength = snprintf(portBuffer, sizeof(portBuffer), ":%d", port);
517
- xt_http_buffer_append(&head, portBuffer, (size_t)portLength);
518
- xt_http_buffer_append(&head, "\r\n", 2);
519
-
520
- xt_value headers = xt_object_get_cstr(client, "__headers");
521
- xt_value keys = xt_object_keys(headers);
522
- int32_t keyCount = (int32_t)xt_to_number(xt_array_length(keys));
523
- for (int32_t i = 0; i < keyCount; i++) {
524
- xt_value key = xt_array_get(keys, xt_number((double)i));
525
- const char *name = xt_string_data(xt_to_string(key));
526
- if (!name) continue;
527
- xt_http_buffer_append(&head, name, strlen(name));
528
- xt_http_buffer_append(&head, ": ", 2);
529
- const char *text = xt_string_data(xt_to_string(xt_object_get(headers, key)));
530
- if (text) xt_http_buffer_append(&head, text, strlen(text));
531
- xt_http_buffer_append(&head, "\r\n", 2);
532
- }
533
- char lengthBuffer[128];
534
- int lengthLength = snprintf(lengthBuffer, sizeof(lengthBuffer), "Content-Length: %zu\r\nConnection: close\r\n\r\n", body.length);
535
- xt_http_buffer_append(&head, lengthBuffer, (size_t)lengthLength);
536
- if (body.length > 0) xt_http_buffer_append(&head, body.data, body.length);
537
-
538
- xt_value connectArgs[2];
539
- connectArgs[0] = xt_number((double)port);
540
- connectArgs[1] = xt_string_from_cstr(host);
541
- xt_value socket = xt_net_static(xt_string_from_cstr("connect"), 2, connectArgs);
542
- xt_node_set(client, "__socket", socket);
543
- xt_node_set(socket, "__httpBuffer", xt_string_from_cstr(""));
544
-
545
- xt_value listener = xt_closure_new((void *)xt_http_client_data, 1, &client);
546
- xt_array_push(xt_node_listeners(socket, "data", 1), listener);
547
- xt_array_push(xt_node_listeners(socket, "end", 1), xt_closure_new((void *)xt_http_client_finish, 1, &client));
548
-
549
- xt_value writeFn = xt_object_get_cstr(socket, "write");
550
- if (XT_IS_FUNCTION(writeFn)) {
551
- xt_value payload = xt_string_new(head.data, head.length);
552
- xt_call_with_this(writeFn, socket, 1, &payload);
553
- }
554
-
555
- xt_http_buffer_free(&head);
556
- xt_http_buffer_free(&body);
557
- }
558
-
559
- static xt_value xt_http_client_end(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
560
- (void)env;
561
- if (argc > 0 && !xt_truthy(xt_is_nullish(argv[0]))) {
562
- xt_array_push(xt_object_get_cstr(thisValue, "__chunks"), argv[0]);
563
- }
564
- xt_http_client_send(thisValue);
565
- return thisValue;
566
- }
567
-
568
- static xt_value xt_http_client_set_header(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
569
- (void)env;
570
- xt_object_set(xt_object_get_cstr(thisValue, "__headers"), xt_arg(argc, argv, 0), xt_arg(argc, argv, 1));
571
- return thisValue;
572
- }
573
-
574
- static xt_value xt_http_client_abort(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
575
- (void)env;
576
- (void)argc;
577
- (void)argv;
578
- xt_value socket = xt_object_get_cstr(thisValue, "__socket");
579
- if (XT_IS_OBJECT(socket)) {
580
- xt_value destroyFn = xt_object_get_cstr(socket, "destroy");
581
- if (XT_IS_FUNCTION(destroyFn)) xt_call_with_this(destroyFn, socket, 0, NULL);
582
- }
583
- return thisValue;
584
- }
585
-
586
- /* Called when the response socket closes: parse the buffered response. */
587
- static xt_value xt_http_client_finish(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
588
- (void)thisValue;
589
- (void)argc;
590
- (void)argv;
591
- xt_value client = xt_closure_env(env, 0);
592
- xt_value socket = xt_object_get_cstr(client, "__socket");
593
- xt_value bufferValue = xt_object_get_cstr(socket, "__httpBuffer");
594
- const char *buffer = XT_IS_STRING(bufferValue) ? xt_string_data(bufferValue) : "";
595
- size_t length = buffer ? strlen(buffer) : 0;
596
-
597
- xt_value res = xt_object_new_with_proto(xt_http_client_response_proto());
598
- int status = 0;
599
- size_t headerLength = 0;
600
- const char *headerEnd = NULL;
601
- for (size_t i = 0; i + 3 < length; i++) {
602
- if (buffer[i] == '\r' && buffer[i + 1] == '\n' && buffer[i + 2] == '\r' && buffer[i + 3] == '\n') {
603
- headerEnd = buffer + i;
604
- headerLength = i + 4;
605
- break;
606
- }
607
- }
608
-
609
- xt_value headers = xt_object_new();
610
- const char *body = "";
611
- size_t bodyLength = 0;
612
- if (headerEnd) {
613
- const char *lineEnd = strstr(buffer, "\r\n");
614
- if (lineEnd) {
615
- const char *firstSpace = memchr(buffer, ' ', (size_t)(lineEnd - buffer));
616
- if (firstSpace) status = atoi(firstSpace + 1);
617
- }
618
- headers = xt_http_parse_headers(buffer + (lineEnd ? (lineEnd - buffer) + 2 : 0),
619
- headerLength - (size_t)((lineEnd ? (lineEnd - buffer) : 0) + 2) - 2);
620
- body = buffer + headerLength;
621
- bodyLength = length - headerLength;
622
- } else {
623
- body = buffer;
624
- bodyLength = length;
625
- }
626
-
627
- xt_node_set(res, "statusCode", xt_number((double)status));
628
- xt_node_set(res, "statusMessage", xt_string_from_cstr(xt_http_status_message(status)));
629
- xt_node_set(res, "httpVersion", xt_string_from_cstr("1.1"));
630
- xt_node_set(res, "headers", headers);
631
- xt_node_set(res, "rawHeaders", xt_array_new(0, NULL));
632
- xt_node_set(res, "complete", xt_bool(1));
633
- xt_value bodyValue = xt_string_new(body, bodyLength);
634
- xt_node_set(res, "__body", bodyValue);
635
-
636
- xt_node_emit1(client, "response", res);
637
- if (bodyLength > 0) xt_node_emit1(res, "data", bodyValue);
638
- xt_node_emit0(res, "end");
639
- xt_node_emit0(res, "close");
640
- return xt_undefined();
641
- }
642
-
643
- static xt_value xt_http_create_client_request(int32_t argc, xt_value *argv) {
644
- xt_value client = xt_object_new_with_proto(xt_http_client_proto());
645
- xt_node_set(client, "__headers", xt_object_new());
646
- xt_node_set(client, "__chunks", xt_array_new(0, NULL));
647
-
648
- const char *method = "GET";
649
- const char *host = "127.0.0.1";
650
- int port = 80;
651
- const char *path = "/";
652
-
653
- int index = 0;
654
- if (argc > 0 && XT_IS_STRING(argv[0])) {
655
- xt_value urlValue = argv[0];
656
- xt_node_set(client, "__url", urlValue);
657
- xt_http_parse_url(urlValue, &host, &port, &path);
658
- index = 1;
659
- } else if (argc > 0 && XT_IS_OBJECT(argv[0])) {
660
- xt_value options = argv[0];
661
- xt_value hostValue = xt_object_get_cstr(options, "hostname");
662
- if (!XT_IS_STRING(hostValue)) hostValue = xt_object_get_cstr(options, "host");
663
- if (XT_IS_STRING(hostValue)) host = xt_string_data(hostValue);
664
- xt_value portValue = xt_object_get_cstr(options, "port");
665
- if (!xt_truthy(xt_is_nullish(portValue))) port = (int)xt_to_number(portValue);
666
- xt_value pathValue = xt_object_get_cstr(options, "path");
667
- if (XT_IS_STRING(pathValue)) path = xt_string_data(pathValue);
668
- xt_value methodValue = xt_object_get_cstr(options, "method");
669
- if (XT_IS_STRING(methodValue)) method = xt_string_data(methodValue);
670
- xt_value headers = xt_object_get_cstr(options, "headers");
671
- if (XT_IS_OBJECT(headers)) xt_node_set(client, "__headers", headers);
672
- index = 1;
673
- }
674
-
675
- for (int32_t i = index; i < argc; i++) {
676
- if (XT_IS_FUNCTION(argv[i])) xt_array_push(xt_node_listeners(client, "response", 1), argv[i]);
677
- }
678
-
679
- /* Give the parser a synthetic URL when only an options object was supplied. */
680
- if (xt_truthy(xt_is_nullish(xt_object_get_cstr(client, "__url")))) {
681
- char url[512];
682
- snprintf(url, sizeof(url), "http://%s:%d%s", host, port, path);
683
- xt_node_set(client, "__url", xt_string_from_cstr(url));
684
- }
685
- xt_node_set(client, "method", xt_string_from_cstr(method));
686
- xt_node_set(client, "path", xt_string_from_cstr(path));
687
- return client;
688
- }
689
-
690
- xt_value xt_http_static(xt_value name, int32_t argc, xt_value *argv) {
691
- const char *fn = xt_string_data(name);
692
- if (!fn) return xt_undefined();
693
- if (strcmp(fn, "createServer") == 0) return xt_http_create_server(argc, argv);
694
- if (strcmp(fn, "request") == 0) return xt_http_create_client_request(argc, argv);
695
- if (strcmp(fn, "get") == 0) {
696
- xt_value client = xt_http_create_client_request(argc, argv);
697
- xt_value endFn = xt_object_get_cstr(client, "end");
698
- if (XT_IS_FUNCTION(endFn)) xt_call_with_this(endFn, client, 0, NULL);
699
- return client;
700
- }
701
- return xt_undefined();
702
- }
703
-
704
- /* -- prototypes ----------------------------------------------------------- */
705
-
706
- static xt_value xt_http_server_proto(void) {
707
- static xt_value proto = 0;
708
- if (proto) return proto;
709
- proto = xt_object_new();
710
- xt_node_install_emitter(proto);
711
- xt_node_define_method(proto, "listen", (void *)xt_http_server_listen);
712
- xt_node_define_method(proto, "close", (void *)xt_http_server_close);
713
- xt_node_define_method(proto, "address", (void *)xt_http_server_address);
714
- return proto;
715
- }
716
-
717
- static xt_value xt_http_response_proto(void) {
718
- static xt_value proto = 0;
719
- if (proto) return proto;
720
- proto = xt_object_new();
721
- xt_node_install_emitter(proto);
722
- xt_node_define_method(proto, "writeHead", (void *)xt_http_response_write_head);
723
- xt_node_define_method(proto, "setHeader", (void *)xt_http_response_set_header);
724
- xt_node_define_method(proto, "getHeader", (void *)xt_http_response_get_header);
725
- xt_node_define_method(proto, "removeHeader", (void *)xt_http_response_remove_header);
726
- xt_node_define_method(proto, "getHeaders", (void *)xt_http_response_get_headers);
727
- xt_node_define_method(proto, "write", (void *)xt_http_response_write);
728
- xt_node_define_method(proto, "end", (void *)xt_http_response_end);
729
- return proto;
730
- }
731
-
732
- static xt_value xt_http_request_proto(void) {
733
- static xt_value proto = 0;
734
- if (proto) return proto;
735
- proto = xt_object_new();
736
- xt_node_install_emitter(proto);
737
- xt_node_define_method(proto, "setEncoding", (void *)xt_http_noop);
738
- return proto;
739
- }
740
-
741
- static xt_value xt_http_client_proto(void) {
742
- static xt_value proto = 0;
743
- if (proto) return proto;
744
- proto = xt_object_new();
745
- xt_node_install_emitter(proto);
746
- xt_node_define_method(proto, "write", (void *)xt_http_client_write);
747
- xt_node_define_method(proto, "end", (void *)xt_http_client_end);
748
- xt_node_define_method(proto, "setHeader", (void *)xt_http_client_set_header);
749
- xt_node_define_method(proto, "abort", (void *)xt_http_client_abort);
750
- return proto;
751
- }
24
+ /*
25
+ * The implementation is grouped by functional area under `http/parts/` and
26
+ * `#include`d here as a single translation unit so the section helpers stay
27
+ * `static` while each file stays focused on one area.
28
+ */
752
29
 
753
- static xt_value xt_http_client_response_proto(void) {
754
- static xt_value proto = 0;
755
- if (proto) return proto;
756
- proto = xt_object_new();
757
- xt_node_install_emitter(proto);
758
- xt_node_define_method(proto, "setEncoding", (void *)xt_http_noop);
759
- return proto;
760
- }
30
+ #include "parts/helpers.inc"
31
+ #include "parts/string-builder.inc"
32
+ #include "parts/response.inc"
33
+ #include "parts/server.inc"
34
+ #include "parts/client.inc"
35
+ #include "parts/prototypes.inc"