@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.
- package/README.md +55 -0
- package/dist/zapp-cli.js +9471 -0
- package/native/src/app/app.zc +490 -0
- package/native/src/event/event.zc +24 -0
- package/native/src/event/events.zc +70 -0
- package/native/src/platform/darwin/backend.zc +923 -0
- package/native/src/platform/darwin/backend_bootstrap.zc +9 -0
- package/native/src/platform/darwin/bootstrap.zc +9 -0
- package/native/src/platform/darwin/engine_jsc.zc +86 -0
- package/native/src/platform/darwin/engine_qjs.zc +92 -0
- package/native/src/platform/darwin/platform.zc +156 -0
- package/native/src/platform/darwin/webview.zc +550 -0
- package/native/src/platform/darwin/webview_bootstrap.zc +9 -0
- package/native/src/platform/darwin/window.zc +1223 -0
- package/native/src/platform/darwin/worker/common.zc +223 -0
- package/native/src/platform/darwin/worker/core/base64_core.zc +29 -0
- package/native/src/platform/darwin/worker/core/crypto_core.zc +19 -0
- package/native/src/platform/darwin/worker/core/encoding_core.zc +32 -0
- package/native/src/platform/darwin/worker/core/fetch_core.zc +145 -0
- package/native/src/platform/darwin/worker/core/url_core.zc +69 -0
- package/native/src/platform/darwin/worker/core/websocket_core.zc +179 -0
- package/native/src/platform/darwin/worker/dispatch.zc +55 -0
- package/native/src/platform/darwin/worker/jsc/base64_jsc.zc +39 -0
- package/native/src/platform/darwin/worker/jsc/crypto_jsc.zc +49 -0
- package/native/src/platform/darwin/worker/jsc/encoding_jsc.zc +86 -0
- package/native/src/platform/darwin/worker/jsc/fetch_jsc.zc +149 -0
- package/native/src/platform/darwin/worker/jsc/url_jsc.zc +54 -0
- package/native/src/platform/darwin/worker/jsc/websocket_jsc.zc +127 -0
- package/native/src/platform/darwin/worker/jsc.zc +670 -0
- package/native/src/platform/darwin/worker/mod.zc +30 -0
- package/native/src/platform/darwin/worker/qjs/fetch_qjs.zc +233 -0
- package/native/src/platform/darwin/worker/qjs/qjs_macros.zc +23 -0
- package/native/src/platform/darwin/worker/qjs/websocket_qjs.zc +223 -0
- package/native/src/platform/darwin/worker/qjs.zc +1053 -0
- package/native/src/platform/darwin/worker/timers.zc +149 -0
- package/native/src/platform/darwin/worker/timers_qjs.zc +209 -0
- package/native/src/platform/platform.zc +64 -0
- package/native/src/platform/shared/log.zc +156 -0
- package/native/src/platform/shared/worker/qjs/base64_qjs.zc +38 -0
- package/native/src/platform/shared/worker/qjs/crypto_qjs.zc +44 -0
- package/native/src/platform/shared/worker/qjs/encoding_qjs.zc +95 -0
- package/native/src/platform/shared/worker/qjs/url_qjs.zc +65 -0
- package/native/src/platform/shared/worker_registry.zc +206 -0
- package/native/src/platform/window.zc +446 -0
- package/native/src/platform/windows/backend.zc +452 -0
- package/native/src/platform/windows/backend_bootstrap.zc +9 -0
- package/native/src/platform/windows/bootstrap.zc +9 -0
- package/native/src/platform/windows/engine_qjs.zc +60 -0
- package/native/src/platform/windows/platform.zc +387 -0
- package/native/src/platform/windows/webview.zc +1175 -0
- package/native/src/platform/windows/webview_bootstrap.zc +9 -0
- package/native/src/platform/windows/window.zc +1271 -0
- package/native/src/platform/windows/worker/common.zc +409 -0
- package/native/src/platform/windows/worker/core/base64_core.zc +52 -0
- package/native/src/platform/windows/worker/core/crypto_core.zc +34 -0
- package/native/src/platform/windows/worker/core/encoding_core.zc +60 -0
- package/native/src/platform/windows/worker/core/fetch_core.zc +274 -0
- package/native/src/platform/windows/worker/core/url_core.zc +216 -0
- package/native/src/platform/windows/worker/core/websocket_core.zc +343 -0
- package/native/src/platform/windows/worker/dispatch.zc +34 -0
- package/native/src/platform/windows/worker/mod.zc +46 -0
- package/native/src/platform/windows/worker/qjs/fetch_qjs.zc +255 -0
- package/native/src/platform/windows/worker/qjs/websocket_qjs.zc +263 -0
- package/native/src/platform/windows/worker/qjs.zc +1049 -0
- package/native/src/platform/windows/worker/timers_qjs.zc +288 -0
- package/native/src/platform/worker.zc +8 -0
- package/native/src/service/service.zc +228 -0
- package/native/vendor/quickjs-ng/.gitattributes +4 -0
- package/native/vendor/quickjs-ng/.github/dependabot.yml +7 -0
- package/native/vendor/quickjs-ng/.github/workflows/ci.yml +812 -0
- package/native/vendor/quickjs-ng/.github/workflows/docs.yml +49 -0
- package/native/vendor/quickjs-ng/.github/workflows/release.yml +162 -0
- package/native/vendor/quickjs-ng/.github/workflows/test-docs.yml +23 -0
- package/native/vendor/quickjs-ng/.github/workflows/tsan.yml +32 -0
- package/native/vendor/quickjs-ng/.github/workflows/valgrind.yml +33 -0
- package/native/vendor/quickjs-ng/.gitmodules +5 -0
- package/native/vendor/quickjs-ng/CMakeLists.txt +553 -0
- package/native/vendor/quickjs-ng/LICENSE +24 -0
- package/native/vendor/quickjs-ng/Makefile +149 -0
- package/native/vendor/quickjs-ng/amalgam.js +53 -0
- package/native/vendor/quickjs-ng/api-test.c +927 -0
- package/native/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
- package/native/vendor/quickjs-ng/builtin-array-fromasync.js +36 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.js +194 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip.js +210 -0
- package/native/vendor/quickjs-ng/ctest.c +17 -0
- package/native/vendor/quickjs-ng/cutils.h +2013 -0
- package/native/vendor/quickjs-ng/cxxtest.cc +2 -0
- package/native/vendor/quickjs-ng/dtoa.c +1619 -0
- package/native/vendor/quickjs-ng/dtoa.h +87 -0
- package/native/vendor/quickjs-ng/examples/fib.c +67 -0
- package/native/vendor/quickjs-ng/examples/fib_module.js +10 -0
- package/native/vendor/quickjs-ng/examples/hello.js +1 -0
- package/native/vendor/quickjs-ng/examples/hello_module.js +6 -0
- package/native/vendor/quickjs-ng/examples/meson.build +17 -0
- package/native/vendor/quickjs-ng/examples/pi_bigint.js +118 -0
- package/native/vendor/quickjs-ng/examples/point.c +154 -0
- package/native/vendor/quickjs-ng/examples/test_fib.js +8 -0
- package/native/vendor/quickjs-ng/examples/test_point.js +43 -0
- package/native/vendor/quickjs-ng/fuzz.c +51 -0
- package/native/vendor/quickjs-ng/gen/function_source.c +81 -0
- package/native/vendor/quickjs-ng/gen/hello.c +53 -0
- package/native/vendor/quickjs-ng/gen/hello_module.c +106 -0
- package/native/vendor/quickjs-ng/gen/repl.c +3053 -0
- package/native/vendor/quickjs-ng/gen/standalone.c +324 -0
- package/native/vendor/quickjs-ng/gen/test_fib.c +81 -0
- package/native/vendor/quickjs-ng/libregexp-opcode.h +58 -0
- package/native/vendor/quickjs-ng/libregexp.c +2687 -0
- package/native/vendor/quickjs-ng/libregexp.h +98 -0
- package/native/vendor/quickjs-ng/libunicode-table.h +4707 -0
- package/native/vendor/quickjs-ng/libunicode.c +1746 -0
- package/native/vendor/quickjs-ng/libunicode.h +126 -0
- package/native/vendor/quickjs-ng/list.h +107 -0
- package/native/vendor/quickjs-ng/lre-test.c +73 -0
- package/native/vendor/quickjs-ng/meson.build +684 -0
- package/native/vendor/quickjs-ng/meson_options.txt +6 -0
- package/native/vendor/quickjs-ng/qjs-wasi-reactor.c +208 -0
- package/native/vendor/quickjs-ng/qjs.c +748 -0
- package/native/vendor/quickjs-ng/qjsc.c +673 -0
- package/native/vendor/quickjs-ng/quickjs-atom.h +267 -0
- package/native/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
- package/native/vendor/quickjs-ng/quickjs-libc.c +4986 -0
- package/native/vendor/quickjs-ng/quickjs-libc.h +79 -0
- package/native/vendor/quickjs-ng/quickjs-opcode.h +369 -0
- package/native/vendor/quickjs-ng/quickjs.c +60259 -0
- package/native/vendor/quickjs-ng/quickjs.h +1419 -0
- package/native/vendor/quickjs-ng/repl.js +1927 -0
- package/native/vendor/quickjs-ng/run-test262.c +2417 -0
- package/native/vendor/quickjs-ng/standalone.js +129 -0
- package/native/vendor/quickjs-ng/tests/assert.js +49 -0
- package/native/vendor/quickjs-ng/tests/bug1221.js +16 -0
- package/native/vendor/quickjs-ng/tests/bug1296.js +12 -0
- package/native/vendor/quickjs-ng/tests/bug1297.js +22 -0
- package/native/vendor/quickjs-ng/tests/bug1301.js +21 -0
- package/native/vendor/quickjs-ng/tests/bug1302.js +24 -0
- package/native/vendor/quickjs-ng/tests/bug1305.js +26 -0
- package/native/vendor/quickjs-ng/tests/bug1318.js +54 -0
- package/native/vendor/quickjs-ng/tests/bug1352.js +8 -0
- package/native/vendor/quickjs-ng/tests/bug1354.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug1355.js +58 -0
- package/native/vendor/quickjs-ng/tests/bug1368.js +9 -0
- package/native/vendor/quickjs-ng/tests/bug39/1.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug39/2.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug39/3.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug488-upstream.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug633/0.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug633/1.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug633/2.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug633/3.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug645/0.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug645/1.js +9 -0
- package/native/vendor/quickjs-ng/tests/bug645/2.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug648.js +13 -0
- package/native/vendor/quickjs-ng/tests/bug652.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug741.js +19 -0
- package/native/vendor/quickjs-ng/tests/bug775.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug776.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug832.js +2 -0
- package/native/vendor/quickjs-ng/tests/bug858.js +26 -0
- package/native/vendor/quickjs-ng/tests/bug904.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug988.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug999.js +3 -0
- package/native/vendor/quickjs-ng/tests/destructured-export.js +8 -0
- package/native/vendor/quickjs-ng/tests/detect_module/0.js +1 -0
- package/native/vendor/quickjs-ng/tests/detect_module/1.js +2 -0
- package/native/vendor/quickjs-ng/tests/detect_module/2.js +1 -0
- package/native/vendor/quickjs-ng/tests/detect_module/3.js +8 -0
- package/native/vendor/quickjs-ng/tests/detect_module/4.js +3 -0
- package/native/vendor/quickjs-ng/tests/empty.js +0 -0
- package/native/vendor/quickjs-ng/tests/fixture_cyclic_import.js +2 -0
- package/native/vendor/quickjs-ng/tests/fixture_string_exports.js +12 -0
- package/native/vendor/quickjs-ng/tests/function_source.js +14 -0
- package/native/vendor/quickjs-ng/tests/microbench.js +1267 -0
- package/native/vendor/quickjs-ng/tests/null_or_undefined.js +38 -0
- package/native/vendor/quickjs-ng/tests/str-pad-leak.js +5 -0
- package/native/vendor/quickjs-ng/tests/test_bigint.js +107 -0
- package/native/vendor/quickjs-ng/tests/test_bjson.js +366 -0
- package/native/vendor/quickjs-ng/tests/test_builtin.js +1314 -0
- package/native/vendor/quickjs-ng/tests/test_closure.js +220 -0
- package/native/vendor/quickjs-ng/tests/test_cyclic_import.js +12 -0
- package/native/vendor/quickjs-ng/tests/test_domexception.js +35 -0
- package/native/vendor/quickjs-ng/tests/test_language.js +755 -0
- package/native/vendor/quickjs-ng/tests/test_loop.js +367 -0
- package/native/vendor/quickjs-ng/tests/test_queue_microtask.js +39 -0
- package/native/vendor/quickjs-ng/tests/test_std.js +340 -0
- package/native/vendor/quickjs-ng/tests/test_string_exports.js +25 -0
- package/native/vendor/quickjs-ng/tests/test_worker.js +43 -0
- package/native/vendor/quickjs-ng/tests/test_worker_module.js +30 -0
- package/native/vendor/quickjs-ng/tests.conf +14 -0
- package/native/vendor/quickjs-ng/unicode_download.sh +19 -0
- package/native/vendor/quickjs-ng/unicode_gen.c +3108 -0
- package/native/vendor/quickjs-ng/unicode_gen_def.h +310 -0
- package/native/vendor/quickjs-ng/update-version.sh +32 -0
- package/native/vendor/webview2/include/WebView2.h +60636 -0
- package/native/vendor/webview2/include/WebView2EnvironmentOptions.h +406 -0
- package/package.json +33 -0
- package/src/backend.ts +139 -0
- package/src/build-config.ts +87 -0
- package/src/build.ts +276 -0
- package/src/common.ts +195 -0
- package/src/config.ts +89 -0
- package/src/dev.ts +164 -0
- package/src/generate.ts +200 -0
- package/src/icons.ts +116 -0
- package/src/init.ts +190 -0
- package/src/package.ts +150 -0
- 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
|
+
}
|