@zappdev/cli 0.1.0

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 (209) hide show
  1. package/README.md +55 -0
  2. package/dist/zapp-cli.js +9471 -0
  3. package/native/src/app/app.zc +490 -0
  4. package/native/src/event/event.zc +24 -0
  5. package/native/src/event/events.zc +70 -0
  6. package/native/src/platform/darwin/backend.zc +923 -0
  7. package/native/src/platform/darwin/backend_bootstrap.zc +9 -0
  8. package/native/src/platform/darwin/bootstrap.zc +9 -0
  9. package/native/src/platform/darwin/engine_jsc.zc +86 -0
  10. package/native/src/platform/darwin/engine_qjs.zc +92 -0
  11. package/native/src/platform/darwin/platform.zc +156 -0
  12. package/native/src/platform/darwin/webview.zc +550 -0
  13. package/native/src/platform/darwin/webview_bootstrap.zc +9 -0
  14. package/native/src/platform/darwin/window.zc +1223 -0
  15. package/native/src/platform/darwin/worker/common.zc +223 -0
  16. package/native/src/platform/darwin/worker/core/base64_core.zc +29 -0
  17. package/native/src/platform/darwin/worker/core/crypto_core.zc +19 -0
  18. package/native/src/platform/darwin/worker/core/encoding_core.zc +32 -0
  19. package/native/src/platform/darwin/worker/core/fetch_core.zc +145 -0
  20. package/native/src/platform/darwin/worker/core/url_core.zc +69 -0
  21. package/native/src/platform/darwin/worker/core/websocket_core.zc +179 -0
  22. package/native/src/platform/darwin/worker/dispatch.zc +55 -0
  23. package/native/src/platform/darwin/worker/jsc/base64_jsc.zc +39 -0
  24. package/native/src/platform/darwin/worker/jsc/crypto_jsc.zc +49 -0
  25. package/native/src/platform/darwin/worker/jsc/encoding_jsc.zc +86 -0
  26. package/native/src/platform/darwin/worker/jsc/fetch_jsc.zc +149 -0
  27. package/native/src/platform/darwin/worker/jsc/url_jsc.zc +54 -0
  28. package/native/src/platform/darwin/worker/jsc/websocket_jsc.zc +127 -0
  29. package/native/src/platform/darwin/worker/jsc.zc +670 -0
  30. package/native/src/platform/darwin/worker/mod.zc +30 -0
  31. package/native/src/platform/darwin/worker/qjs/fetch_qjs.zc +233 -0
  32. package/native/src/platform/darwin/worker/qjs/qjs_macros.zc +23 -0
  33. package/native/src/platform/darwin/worker/qjs/websocket_qjs.zc +223 -0
  34. package/native/src/platform/darwin/worker/qjs.zc +1053 -0
  35. package/native/src/platform/darwin/worker/timers.zc +149 -0
  36. package/native/src/platform/darwin/worker/timers_qjs.zc +209 -0
  37. package/native/src/platform/platform.zc +64 -0
  38. package/native/src/platform/shared/log.zc +156 -0
  39. package/native/src/platform/shared/worker/qjs/base64_qjs.zc +38 -0
  40. package/native/src/platform/shared/worker/qjs/crypto_qjs.zc +44 -0
  41. package/native/src/platform/shared/worker/qjs/encoding_qjs.zc +95 -0
  42. package/native/src/platform/shared/worker/qjs/url_qjs.zc +65 -0
  43. package/native/src/platform/shared/worker_registry.zc +206 -0
  44. package/native/src/platform/window.zc +446 -0
  45. package/native/src/platform/windows/backend.zc +452 -0
  46. package/native/src/platform/windows/backend_bootstrap.zc +9 -0
  47. package/native/src/platform/windows/bootstrap.zc +9 -0
  48. package/native/src/platform/windows/engine_qjs.zc +60 -0
  49. package/native/src/platform/windows/platform.zc +387 -0
  50. package/native/src/platform/windows/webview.zc +1175 -0
  51. package/native/src/platform/windows/webview_bootstrap.zc +9 -0
  52. package/native/src/platform/windows/window.zc +1271 -0
  53. package/native/src/platform/windows/worker/common.zc +409 -0
  54. package/native/src/platform/windows/worker/core/base64_core.zc +52 -0
  55. package/native/src/platform/windows/worker/core/crypto_core.zc +34 -0
  56. package/native/src/platform/windows/worker/core/encoding_core.zc +60 -0
  57. package/native/src/platform/windows/worker/core/fetch_core.zc +274 -0
  58. package/native/src/platform/windows/worker/core/url_core.zc +216 -0
  59. package/native/src/platform/windows/worker/core/websocket_core.zc +343 -0
  60. package/native/src/platform/windows/worker/dispatch.zc +34 -0
  61. package/native/src/platform/windows/worker/mod.zc +46 -0
  62. package/native/src/platform/windows/worker/qjs/fetch_qjs.zc +255 -0
  63. package/native/src/platform/windows/worker/qjs/websocket_qjs.zc +263 -0
  64. package/native/src/platform/windows/worker/qjs.zc +1049 -0
  65. package/native/src/platform/windows/worker/timers_qjs.zc +288 -0
  66. package/native/src/platform/worker.zc +8 -0
  67. package/native/src/service/service.zc +228 -0
  68. package/native/vendor/quickjs-ng/.gitattributes +4 -0
  69. package/native/vendor/quickjs-ng/.github/dependabot.yml +7 -0
  70. package/native/vendor/quickjs-ng/.github/workflows/ci.yml +812 -0
  71. package/native/vendor/quickjs-ng/.github/workflows/docs.yml +49 -0
  72. package/native/vendor/quickjs-ng/.github/workflows/release.yml +162 -0
  73. package/native/vendor/quickjs-ng/.github/workflows/test-docs.yml +23 -0
  74. package/native/vendor/quickjs-ng/.github/workflows/tsan.yml +32 -0
  75. package/native/vendor/quickjs-ng/.github/workflows/valgrind.yml +33 -0
  76. package/native/vendor/quickjs-ng/.gitmodules +5 -0
  77. package/native/vendor/quickjs-ng/CMakeLists.txt +553 -0
  78. package/native/vendor/quickjs-ng/LICENSE +24 -0
  79. package/native/vendor/quickjs-ng/Makefile +149 -0
  80. package/native/vendor/quickjs-ng/amalgam.js +53 -0
  81. package/native/vendor/quickjs-ng/api-test.c +927 -0
  82. package/native/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
  83. package/native/vendor/quickjs-ng/builtin-array-fromasync.js +36 -0
  84. package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
  85. package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.js +194 -0
  86. package/native/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
  87. package/native/vendor/quickjs-ng/builtin-iterator-zip.js +210 -0
  88. package/native/vendor/quickjs-ng/ctest.c +17 -0
  89. package/native/vendor/quickjs-ng/cutils.h +2013 -0
  90. package/native/vendor/quickjs-ng/cxxtest.cc +2 -0
  91. package/native/vendor/quickjs-ng/dtoa.c +1619 -0
  92. package/native/vendor/quickjs-ng/dtoa.h +87 -0
  93. package/native/vendor/quickjs-ng/examples/fib.c +67 -0
  94. package/native/vendor/quickjs-ng/examples/fib_module.js +10 -0
  95. package/native/vendor/quickjs-ng/examples/hello.js +1 -0
  96. package/native/vendor/quickjs-ng/examples/hello_module.js +6 -0
  97. package/native/vendor/quickjs-ng/examples/meson.build +17 -0
  98. package/native/vendor/quickjs-ng/examples/pi_bigint.js +118 -0
  99. package/native/vendor/quickjs-ng/examples/point.c +154 -0
  100. package/native/vendor/quickjs-ng/examples/test_fib.js +8 -0
  101. package/native/vendor/quickjs-ng/examples/test_point.js +43 -0
  102. package/native/vendor/quickjs-ng/fuzz.c +51 -0
  103. package/native/vendor/quickjs-ng/gen/function_source.c +81 -0
  104. package/native/vendor/quickjs-ng/gen/hello.c +53 -0
  105. package/native/vendor/quickjs-ng/gen/hello_module.c +106 -0
  106. package/native/vendor/quickjs-ng/gen/repl.c +3053 -0
  107. package/native/vendor/quickjs-ng/gen/standalone.c +324 -0
  108. package/native/vendor/quickjs-ng/gen/test_fib.c +81 -0
  109. package/native/vendor/quickjs-ng/libregexp-opcode.h +58 -0
  110. package/native/vendor/quickjs-ng/libregexp.c +2687 -0
  111. package/native/vendor/quickjs-ng/libregexp.h +98 -0
  112. package/native/vendor/quickjs-ng/libunicode-table.h +4707 -0
  113. package/native/vendor/quickjs-ng/libunicode.c +1746 -0
  114. package/native/vendor/quickjs-ng/libunicode.h +126 -0
  115. package/native/vendor/quickjs-ng/list.h +107 -0
  116. package/native/vendor/quickjs-ng/lre-test.c +73 -0
  117. package/native/vendor/quickjs-ng/meson.build +684 -0
  118. package/native/vendor/quickjs-ng/meson_options.txt +6 -0
  119. package/native/vendor/quickjs-ng/qjs-wasi-reactor.c +208 -0
  120. package/native/vendor/quickjs-ng/qjs.c +748 -0
  121. package/native/vendor/quickjs-ng/qjsc.c +673 -0
  122. package/native/vendor/quickjs-ng/quickjs-atom.h +267 -0
  123. package/native/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
  124. package/native/vendor/quickjs-ng/quickjs-libc.c +4986 -0
  125. package/native/vendor/quickjs-ng/quickjs-libc.h +79 -0
  126. package/native/vendor/quickjs-ng/quickjs-opcode.h +369 -0
  127. package/native/vendor/quickjs-ng/quickjs.c +60259 -0
  128. package/native/vendor/quickjs-ng/quickjs.h +1419 -0
  129. package/native/vendor/quickjs-ng/repl.js +1927 -0
  130. package/native/vendor/quickjs-ng/run-test262.c +2417 -0
  131. package/native/vendor/quickjs-ng/standalone.js +129 -0
  132. package/native/vendor/quickjs-ng/tests/assert.js +49 -0
  133. package/native/vendor/quickjs-ng/tests/bug1221.js +16 -0
  134. package/native/vendor/quickjs-ng/tests/bug1296.js +12 -0
  135. package/native/vendor/quickjs-ng/tests/bug1297.js +22 -0
  136. package/native/vendor/quickjs-ng/tests/bug1301.js +21 -0
  137. package/native/vendor/quickjs-ng/tests/bug1302.js +24 -0
  138. package/native/vendor/quickjs-ng/tests/bug1305.js +26 -0
  139. package/native/vendor/quickjs-ng/tests/bug1318.js +54 -0
  140. package/native/vendor/quickjs-ng/tests/bug1352.js +8 -0
  141. package/native/vendor/quickjs-ng/tests/bug1354.js +6 -0
  142. package/native/vendor/quickjs-ng/tests/bug1355.js +58 -0
  143. package/native/vendor/quickjs-ng/tests/bug1368.js +9 -0
  144. package/native/vendor/quickjs-ng/tests/bug39/1.js +6 -0
  145. package/native/vendor/quickjs-ng/tests/bug39/2.js +6 -0
  146. package/native/vendor/quickjs-ng/tests/bug39/3.js +7 -0
  147. package/native/vendor/quickjs-ng/tests/bug488-upstream.js +7 -0
  148. package/native/vendor/quickjs-ng/tests/bug633/0.js +7 -0
  149. package/native/vendor/quickjs-ng/tests/bug633/1.js +4 -0
  150. package/native/vendor/quickjs-ng/tests/bug633/2.js +4 -0
  151. package/native/vendor/quickjs-ng/tests/bug633/3.js +4 -0
  152. package/native/vendor/quickjs-ng/tests/bug645/0.js +4 -0
  153. package/native/vendor/quickjs-ng/tests/bug645/1.js +9 -0
  154. package/native/vendor/quickjs-ng/tests/bug645/2.js +7 -0
  155. package/native/vendor/quickjs-ng/tests/bug648.js +13 -0
  156. package/native/vendor/quickjs-ng/tests/bug652.js +4 -0
  157. package/native/vendor/quickjs-ng/tests/bug741.js +19 -0
  158. package/native/vendor/quickjs-ng/tests/bug775.js +7 -0
  159. package/native/vendor/quickjs-ng/tests/bug776.js +7 -0
  160. package/native/vendor/quickjs-ng/tests/bug832.js +2 -0
  161. package/native/vendor/quickjs-ng/tests/bug858.js +26 -0
  162. package/native/vendor/quickjs-ng/tests/bug904.js +6 -0
  163. package/native/vendor/quickjs-ng/tests/bug988.js +7 -0
  164. package/native/vendor/quickjs-ng/tests/bug999.js +3 -0
  165. package/native/vendor/quickjs-ng/tests/destructured-export.js +8 -0
  166. package/native/vendor/quickjs-ng/tests/detect_module/0.js +1 -0
  167. package/native/vendor/quickjs-ng/tests/detect_module/1.js +2 -0
  168. package/native/vendor/quickjs-ng/tests/detect_module/2.js +1 -0
  169. package/native/vendor/quickjs-ng/tests/detect_module/3.js +8 -0
  170. package/native/vendor/quickjs-ng/tests/detect_module/4.js +3 -0
  171. package/native/vendor/quickjs-ng/tests/empty.js +0 -0
  172. package/native/vendor/quickjs-ng/tests/fixture_cyclic_import.js +2 -0
  173. package/native/vendor/quickjs-ng/tests/fixture_string_exports.js +12 -0
  174. package/native/vendor/quickjs-ng/tests/function_source.js +14 -0
  175. package/native/vendor/quickjs-ng/tests/microbench.js +1267 -0
  176. package/native/vendor/quickjs-ng/tests/null_or_undefined.js +38 -0
  177. package/native/vendor/quickjs-ng/tests/str-pad-leak.js +5 -0
  178. package/native/vendor/quickjs-ng/tests/test_bigint.js +107 -0
  179. package/native/vendor/quickjs-ng/tests/test_bjson.js +366 -0
  180. package/native/vendor/quickjs-ng/tests/test_builtin.js +1314 -0
  181. package/native/vendor/quickjs-ng/tests/test_closure.js +220 -0
  182. package/native/vendor/quickjs-ng/tests/test_cyclic_import.js +12 -0
  183. package/native/vendor/quickjs-ng/tests/test_domexception.js +35 -0
  184. package/native/vendor/quickjs-ng/tests/test_language.js +755 -0
  185. package/native/vendor/quickjs-ng/tests/test_loop.js +367 -0
  186. package/native/vendor/quickjs-ng/tests/test_queue_microtask.js +39 -0
  187. package/native/vendor/quickjs-ng/tests/test_std.js +340 -0
  188. package/native/vendor/quickjs-ng/tests/test_string_exports.js +25 -0
  189. package/native/vendor/quickjs-ng/tests/test_worker.js +43 -0
  190. package/native/vendor/quickjs-ng/tests/test_worker_module.js +30 -0
  191. package/native/vendor/quickjs-ng/tests.conf +14 -0
  192. package/native/vendor/quickjs-ng/unicode_download.sh +19 -0
  193. package/native/vendor/quickjs-ng/unicode_gen.c +3108 -0
  194. package/native/vendor/quickjs-ng/unicode_gen_def.h +310 -0
  195. package/native/vendor/quickjs-ng/update-version.sh +32 -0
  196. package/native/vendor/webview2/include/WebView2.h +60636 -0
  197. package/native/vendor/webview2/include/WebView2EnvironmentOptions.h +406 -0
  198. package/package.json +33 -0
  199. package/src/backend.ts +139 -0
  200. package/src/build-config.ts +87 -0
  201. package/src/build.ts +276 -0
  202. package/src/common.ts +195 -0
  203. package/src/config.ts +89 -0
  204. package/src/dev.ts +164 -0
  205. package/src/generate.ts +200 -0
  206. package/src/icons.ts +116 -0
  207. package/src/init.ts +190 -0
  208. package/src/package.ts +150 -0
  209. package/src/zapp-cli.ts +263 -0
@@ -0,0 +1,274 @@
1
+ // Win32-native HTTP fetch using WinHTTP (synchronous on background thread).
2
+
3
+ //> windows: link: -lwinhttp
4
+
5
+ raw {
6
+ #ifdef _WIN32
7
+ #include <windows.h>
8
+ #include <winhttp.h>
9
+ #include <stdio.h>
10
+ #include <stdlib.h>
11
+ #include <string.h>
12
+
13
+ typedef struct {
14
+ int status;
15
+ char* status_text;
16
+ char** header_keys;
17
+ char** header_values;
18
+ int header_count;
19
+ char* body;
20
+ char* body_base64;
21
+ } zapp_fetch_response_t;
22
+
23
+ static void zapp_core_fetch_response_free(zapp_fetch_response_t* r) {
24
+ if (!r) return;
25
+ free(r->status_text);
26
+ for (int i = 0; i < r->header_count; i++) {
27
+ free(r->header_keys[i]);
28
+ free(r->header_values[i]);
29
+ }
30
+ free(r->header_keys);
31
+ free(r->header_values);
32
+ free(r->body);
33
+ free(r->body_base64);
34
+ }
35
+
36
+ // Callback function type for fetch completion
37
+ typedef void (*zapp_fetch_callback_fn)(zapp_fetch_response_t* response, const char* error, void* userdata);
38
+
39
+ typedef struct {
40
+ char* url;
41
+ char* method;
42
+ char** header_keys;
43
+ char** header_values;
44
+ int header_count;
45
+ char* body;
46
+ size_t body_len;
47
+ char worker_id[128];
48
+ zapp_fetch_callback_fn callback;
49
+ void* userdata;
50
+ } ZappFetchRequest;
51
+
52
+ static wchar_t* zapp_fetch_utf8_to_wide(const char* utf8) {
53
+ if (!utf8) return NULL;
54
+ int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
55
+ wchar_t* wide = (wchar_t*)malloc(len * sizeof(wchar_t));
56
+ MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wide, len);
57
+ return wide;
58
+ }
59
+
60
+ static char* zapp_fetch_wide_to_utf8(const wchar_t* wide) {
61
+ if (!wide) return NULL;
62
+ int len = WideCharToMultiByte(CP_UTF8, 0, wide, -1, NULL, 0, NULL, NULL);
63
+ char* utf8 = (char*)malloc(len);
64
+ WideCharToMultiByte(CP_UTF8, 0, wide, -1, utf8, len, NULL, NULL);
65
+ return utf8;
66
+ }
67
+
68
+ static DWORD WINAPI zapp_fetch_thread_proc(LPVOID param) {
69
+ ZappFetchRequest* req = (ZappFetchRequest*)param;
70
+ zapp_fetch_response_t response;
71
+ memset(&response, 0, sizeof(response));
72
+
73
+ HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL;
74
+ char* errorMsg = NULL;
75
+
76
+ // Parse URL components
77
+ wchar_t* wUrl = zapp_fetch_utf8_to_wide(req->url);
78
+ URL_COMPONENTSW urlComp;
79
+ memset(&urlComp, 0, sizeof(urlComp));
80
+ urlComp.dwStructSize = sizeof(urlComp);
81
+ wchar_t hostBuf[256] = {0};
82
+ wchar_t pathBuf[2048] = {0};
83
+ urlComp.lpszHostName = hostBuf;
84
+ urlComp.dwHostNameLength = 256;
85
+ urlComp.lpszUrlPath = pathBuf;
86
+ urlComp.dwUrlPathLength = 2048;
87
+
88
+ if (!WinHttpCrackUrl(wUrl, 0, 0, &urlComp)) {
89
+ errorMsg = _strdup("Invalid URL");
90
+ goto cleanup;
91
+ }
92
+
93
+ hSession = WinHttpOpen(L"Zapp/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
94
+ WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
95
+ if (!hSession) { errorMsg = _strdup("Failed to create HTTP session"); goto cleanup; }
96
+
97
+ hConnect = WinHttpConnect(hSession, hostBuf, urlComp.nPort, 0);
98
+ if (!hConnect) { errorMsg = _strdup("Failed to connect"); goto cleanup; }
99
+
100
+ wchar_t* wMethod = zapp_fetch_utf8_to_wide(req->method ? req->method : "GET");
101
+ DWORD flags = (urlComp.nScheme == INTERNET_SCHEME_HTTPS) ? WINHTTP_FLAG_SECURE : 0;
102
+ hRequest = WinHttpOpenRequest(hConnect, wMethod, pathBuf, NULL,
103
+ WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, flags);
104
+ free(wMethod);
105
+ if (!hRequest) { errorMsg = _strdup("Failed to create request"); goto cleanup; }
106
+
107
+ // Add headers
108
+ for (int i = 0; i < req->header_count; i++) {
109
+ if (req->header_keys[i] && req->header_values[i]) {
110
+ wchar_t header[1024];
111
+ wchar_t* wKey = zapp_fetch_utf8_to_wide(req->header_keys[i]);
112
+ wchar_t* wVal = zapp_fetch_utf8_to_wide(req->header_values[i]);
113
+ _snwprintf(header, 1024, L"%s: %s", wKey, wVal);
114
+ WinHttpAddRequestHeaders(hRequest, header, (DWORD)-1, WINHTTP_ADDREQ_FLAG_ADD);
115
+ free(wKey);
116
+ free(wVal);
117
+ }
118
+ }
119
+
120
+ // Send request
121
+ DWORD bodyLen = req->body ? (DWORD)req->body_len : 0;
122
+ if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0,
123
+ req->body, bodyLen, bodyLen, 0)) {
124
+ errorMsg = _strdup("Failed to send request");
125
+ goto cleanup;
126
+ }
127
+
128
+ if (!WinHttpReceiveResponse(hRequest, NULL)) {
129
+ errorMsg = _strdup("Failed to receive response");
130
+ goto cleanup;
131
+ }
132
+
133
+ // Read status
134
+ DWORD statusCode = 0;
135
+ DWORD statusSize = sizeof(statusCode);
136
+ WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
137
+ WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusSize, WINHTTP_NO_HEADER_INDEX);
138
+ response.status = (int)statusCode;
139
+
140
+ // Read status text
141
+ wchar_t statusTextBuf[256] = {0};
142
+ DWORD statusTextLen = sizeof(statusTextBuf);
143
+ if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_TEXT, WINHTTP_HEADER_NAME_BY_INDEX,
144
+ statusTextBuf, &statusTextLen, WINHTTP_NO_HEADER_INDEX)) {
145
+ response.status_text = zapp_fetch_wide_to_utf8(statusTextBuf);
146
+ } else {
147
+ response.status_text = _strdup("OK");
148
+ }
149
+
150
+ // Read all headers
151
+ DWORD headerBufSize = 0;
152
+ WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF,
153
+ WINHTTP_HEADER_NAME_BY_INDEX, NULL, &headerBufSize, WINHTTP_NO_HEADER_INDEX);
154
+ if (headerBufSize > 0) {
155
+ wchar_t* headerBuf = (wchar_t*)malloc(headerBufSize);
156
+ if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF,
157
+ WINHTTP_HEADER_NAME_BY_INDEX, headerBuf, &headerBufSize, WINHTTP_NO_HEADER_INDEX)) {
158
+ char* headerUtf8 = zapp_fetch_wide_to_utf8(headerBuf);
159
+ // Count headers (skip first status line)
160
+ int count = 0;
161
+ char* line = strtok(_strdup(headerUtf8), "\r\n");
162
+ if (line) line = strtok(NULL, "\r\n"); // skip status line
163
+ while (line) { if (strchr(line, ':')) count++; line = strtok(NULL, "\r\n"); }
164
+
165
+ if (count > 0) {
166
+ response.header_keys = (char**)calloc(count, sizeof(char*));
167
+ response.header_values = (char**)calloc(count, sizeof(char*));
168
+ response.header_count = 0;
169
+
170
+ char* copy = _strdup(headerUtf8);
171
+ line = strtok(copy, "\r\n");
172
+ if (line) line = strtok(NULL, "\r\n"); // skip status line
173
+ while (line && response.header_count < count) {
174
+ char* colon = strchr(line, ':');
175
+ if (colon) {
176
+ *colon = '\0';
177
+ char* val = colon + 1;
178
+ while (*val == ' ') val++;
179
+ response.header_keys[response.header_count] = _strdup(line);
180
+ response.header_values[response.header_count] = _strdup(val);
181
+ response.header_count++;
182
+ }
183
+ line = strtok(NULL, "\r\n");
184
+ }
185
+ free(copy);
186
+ }
187
+ free(headerUtf8);
188
+ }
189
+ free(headerBuf);
190
+ }
191
+
192
+ // Read body
193
+ {
194
+ size_t totalSize = 0;
195
+ size_t bufCap = 65536;
196
+ char* bodyBuf = (char*)malloc(bufCap);
197
+ DWORD bytesRead = 0;
198
+
199
+ while (WinHttpReadData(hRequest, bodyBuf + totalSize,
200
+ (DWORD)(bufCap - totalSize - 1), &bytesRead) && bytesRead > 0) {
201
+ totalSize += bytesRead;
202
+ if (totalSize + 4096 >= bufCap) {
203
+ bufCap *= 2;
204
+ bodyBuf = (char*)realloc(bodyBuf, bufCap);
205
+ }
206
+ }
207
+ bodyBuf[totalSize] = '\0';
208
+ response.body = bodyBuf;
209
+ }
210
+
211
+ cleanup:
212
+ if (hRequest) WinHttpCloseHandle(hRequest);
213
+ if (hConnect) WinHttpCloseHandle(hConnect);
214
+ if (hSession) WinHttpCloseHandle(hSession);
215
+ free(wUrl);
216
+
217
+ if (req->callback) {
218
+ if (errorMsg) {
219
+ req->callback(NULL, errorMsg, req->userdata);
220
+ } else {
221
+ req->callback(&response, NULL, req->userdata);
222
+ }
223
+ }
224
+
225
+ zapp_core_fetch_response_free(&response);
226
+ free(errorMsg);
227
+
228
+ // Free the request
229
+ free(req->url);
230
+ free(req->method);
231
+ for (int i = 0; i < req->header_count; i++) {
232
+ free(req->header_keys[i]);
233
+ free(req->header_values[i]);
234
+ }
235
+ free(req->header_keys);
236
+ free(req->header_values);
237
+ free(req->body);
238
+ free(req);
239
+
240
+ return 0;
241
+ }
242
+
243
+ static void zapp_core_fetch_execute(
244
+ const char* url, const char* method,
245
+ const char** header_keys, const char** header_values, int header_count,
246
+ const char* body, size_t body_len,
247
+ const char* worker_id,
248
+ zapp_fetch_callback_fn callback, void* userdata
249
+ ) {
250
+ ZappFetchRequest* req = (ZappFetchRequest*)calloc(1, sizeof(ZappFetchRequest));
251
+ req->url = url ? _strdup(url) : NULL;
252
+ req->method = method ? _strdup(method) : NULL;
253
+ if (header_count > 0) {
254
+ req->header_keys = (char**)calloc(header_count, sizeof(char*));
255
+ req->header_values = (char**)calloc(header_count, sizeof(char*));
256
+ for (int i = 0; i < header_count; i++) {
257
+ req->header_keys[i] = header_keys[i] ? _strdup(header_keys[i]) : NULL;
258
+ req->header_values[i] = header_values[i] ? _strdup(header_values[i]) : NULL;
259
+ }
260
+ req->header_count = header_count;
261
+ }
262
+ if (body && body_len > 0) {
263
+ req->body = (char*)malloc(body_len);
264
+ memcpy(req->body, body, body_len);
265
+ req->body_len = body_len;
266
+ }
267
+ if (worker_id) strncpy(req->worker_id, worker_id, sizeof(req->worker_id) - 1);
268
+ req->callback = callback;
269
+ req->userdata = userdata;
270
+
271
+ CreateThread(NULL, 0, zapp_fetch_thread_proc, req, 0, NULL);
272
+ }
273
+ #endif
274
+ }
@@ -0,0 +1,216 @@
1
+ // Win32-native URL parsing.
2
+ // Uses a manual parser since CreateUri / IUri COM is overly complex for this use case.
3
+
4
+ raw {
5
+ #ifdef _WIN32
6
+ #include <windows.h>
7
+ #include <stdio.h>
8
+ #include <stdlib.h>
9
+ #include <string.h>
10
+
11
+ #ifndef ZAPP_URL_PARSED_DEFINED
12
+ #define ZAPP_URL_PARSED_DEFINED 1
13
+ typedef struct zapp_url_parsed {
14
+ char* href;
15
+ char* protocol;
16
+ char* host;
17
+ char* hostname;
18
+ char* port;
19
+ char* pathname;
20
+ char* search;
21
+ char* hash;
22
+ char* origin;
23
+ char* username;
24
+ char* password;
25
+ } zapp_url_parsed_t;
26
+ #endif
27
+
28
+ void zapp_core_url_free(zapp_url_parsed_t* c) {
29
+ if (!c) return;
30
+ free(c->href); free(c->protocol); free(c->host);
31
+ free(c->hostname); free(c->port); free(c->pathname);
32
+ free(c->search); free(c->hash); free(c->origin);
33
+ free(c->username); free(c->password);
34
+ }
35
+
36
+ int zapp_core_url_parse(const char* url_str, const char* base_str, zapp_url_parsed_t* out) {
37
+ if (!url_str || !out) return -1;
38
+ memset(out, 0, sizeof(zapp_url_parsed_t));
39
+
40
+ // Simple URL resolution: if url_str is relative and base_str given, prepend base
41
+ char resolved[2048] = {0};
42
+ if (base_str && base_str[0] && (strstr(url_str, "://") == NULL)) {
43
+ snprintf(resolved, sizeof(resolved), "%s", base_str);
44
+ // Remove trailing path from base to get base directory
45
+ char* lastSlash = strrchr(resolved, '/');
46
+ char* afterScheme = strstr(resolved, "://");
47
+ if (lastSlash && afterScheme && lastSlash > afterScheme + 2) {
48
+ *(lastSlash + 1) = '\0';
49
+ }
50
+ if (url_str[0] == '/') {
51
+ // Absolute path: keep scheme + host
52
+ char* thirdSlash = afterScheme ? strchr(afterScheme + 3, '/') : NULL;
53
+ if (thirdSlash) *thirdSlash = '\0';
54
+ strncat(resolved, url_str, sizeof(resolved) - strlen(resolved) - 1);
55
+ } else {
56
+ strncat(resolved, url_str, sizeof(resolved) - strlen(resolved) - 1);
57
+ }
58
+ } else {
59
+ strncpy(resolved, url_str, sizeof(resolved) - 1);
60
+ }
61
+
62
+ const char* p = resolved;
63
+ char scheme[64] = {0};
64
+ char userinfo[256] = {0};
65
+ char hostname[256] = {0};
66
+ char port[16] = {0};
67
+ char pathname[1024] = {0};
68
+ char search[1024] = {0};
69
+ char hash[512] = {0};
70
+
71
+ // Parse scheme
72
+ const char* schemeEnd = strstr(p, "://");
73
+ if (schemeEnd) {
74
+ size_t slen = (size_t)(schemeEnd - p);
75
+ if (slen < sizeof(scheme)) {
76
+ memcpy(scheme, p, slen);
77
+ scheme[slen] = '\0';
78
+ }
79
+ p = schemeEnd + 3;
80
+ }
81
+
82
+ // Parse userinfo (user:pass@)
83
+ const char* atSign = strchr(p, '@');
84
+ const char* firstSlash = strchr(p, '/');
85
+ if (atSign && (!firstSlash || atSign < firstSlash)) {
86
+ size_t ulen = (size_t)(atSign - p);
87
+ if (ulen < sizeof(userinfo)) {
88
+ memcpy(userinfo, p, ulen);
89
+ userinfo[ulen] = '\0';
90
+ }
91
+ p = atSign + 1;
92
+ }
93
+
94
+ // Parse host:port
95
+ firstSlash = strchr(p, '/');
96
+ const char* queryMark = strchr(p, '?');
97
+ const char* hashMark = strchr(p, '#');
98
+ const char* hostEnd = firstSlash;
99
+ if (!hostEnd || (queryMark && queryMark < hostEnd)) hostEnd = queryMark;
100
+ if (!hostEnd || (hashMark && hashMark < hostEnd)) hostEnd = hashMark;
101
+ if (!hostEnd) hostEnd = p + strlen(p);
102
+
103
+ size_t hostLen = (size_t)(hostEnd - p);
104
+ char hostPort[256] = {0};
105
+ if (hostLen < sizeof(hostPort)) {
106
+ memcpy(hostPort, p, hostLen);
107
+ hostPort[hostLen] = '\0';
108
+ }
109
+
110
+ // Split host and port
111
+ char* colonInHost = strrchr(hostPort, ':');
112
+ if (colonInHost && hostPort[0] != '[') {
113
+ *colonInHost = '\0';
114
+ strncpy(hostname, hostPort, sizeof(hostname) - 1);
115
+ strncpy(port, colonInHost + 1, sizeof(port) - 1);
116
+ } else {
117
+ strncpy(hostname, hostPort, sizeof(hostname) - 1);
118
+ }
119
+
120
+ p = hostEnd;
121
+
122
+ // Parse pathname
123
+ if (*p == '/') {
124
+ const char* pathEnd = p;
125
+ while (*pathEnd && *pathEnd != '?' && *pathEnd != '#') pathEnd++;
126
+ size_t plen = (size_t)(pathEnd - p);
127
+ if (plen < sizeof(pathname)) {
128
+ memcpy(pathname, p, plen);
129
+ pathname[plen] = '\0';
130
+ }
131
+ p = pathEnd;
132
+ } else if (*p != '?' && *p != '#' && *p) {
133
+ strcpy(pathname, "/");
134
+ }
135
+
136
+ // Parse search
137
+ if (*p == '?') {
138
+ const char* searchEnd = strchr(p, '#');
139
+ if (!searchEnd) searchEnd = p + strlen(p);
140
+ size_t slen = (size_t)(searchEnd - p);
141
+ if (slen < sizeof(search)) {
142
+ memcpy(search, p, slen);
143
+ search[slen] = '\0';
144
+ }
145
+ p = searchEnd;
146
+ }
147
+
148
+ // Parse hash
149
+ if (*p == '#') {
150
+ strncpy(hash, p, sizeof(hash) - 1);
151
+ }
152
+
153
+ // Build protocol string
154
+ char protocol[66] = {0};
155
+ if (scheme[0]) snprintf(protocol, sizeof(protocol), "%s:", scheme);
156
+
157
+ // Build host with port
158
+ char hostWithPort[280] = {0};
159
+ if (port[0]) {
160
+ snprintf(hostWithPort, sizeof(hostWithPort), "%s:%s", hostname, port);
161
+ } else {
162
+ strncpy(hostWithPort, hostname, sizeof(hostWithPort) - 1);
163
+ }
164
+
165
+ // Build origin
166
+ char origin[512] = {0};
167
+ if (strcmp(scheme, "http") == 0 || strcmp(scheme, "https") == 0 ||
168
+ strcmp(scheme, "ws") == 0 || strcmp(scheme, "wss") == 0 ||
169
+ strcmp(scheme, "ftp") == 0) {
170
+ snprintf(origin, sizeof(origin), "%s://%s", scheme, hostWithPort);
171
+ } else {
172
+ strcpy(origin, "null");
173
+ }
174
+
175
+ // Build href
176
+ char href[2048] = {0};
177
+ if (scheme[0]) {
178
+ snprintf(href, sizeof(href), "%s://%s%s%s%s%s",
179
+ scheme,
180
+ userinfo[0] ? userinfo : "",
181
+ userinfo[0] ? "@" : "",
182
+ hostWithPort, pathname, search);
183
+ } else {
184
+ snprintf(href, sizeof(href), "%s%s", pathname, search);
185
+ }
186
+ if (hash[0]) strncat(href, hash, sizeof(href) - strlen(href) - 1);
187
+
188
+ // Parse username/password from userinfo
189
+ char username[128] = {0};
190
+ char password[128] = {0};
191
+ if (userinfo[0]) {
192
+ char* colon = strchr(userinfo, ':');
193
+ if (colon) {
194
+ size_t ulen = (size_t)(colon - userinfo);
195
+ if (ulen < sizeof(username)) memcpy(username, userinfo, ulen);
196
+ strncpy(password, colon + 1, sizeof(password) - 1);
197
+ } else {
198
+ strncpy(username, userinfo, sizeof(username) - 1);
199
+ }
200
+ }
201
+
202
+ out->href = _strdup(href);
203
+ out->protocol = _strdup(protocol);
204
+ out->host = _strdup(hostWithPort);
205
+ out->hostname = _strdup(hostname);
206
+ out->port = _strdup(port);
207
+ out->pathname = _strdup(pathname[0] ? pathname : "/");
208
+ out->search = _strdup(search);
209
+ out->hash = _strdup(hash);
210
+ out->origin = _strdup(origin);
211
+ out->username = _strdup(username);
212
+ out->password = _strdup(password);
213
+ return 0;
214
+ }
215
+ #endif
216
+ }