nomen-lang 0.3.0 → 0.5.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/NOMEN_AGENTS.md +7 -1
- package/core/System/Arena.nm +7 -7
- package/core/System/Awaitable.nm +21 -0
- package/core/System/BigInt.nm +5 -15
- package/core/System/Buffer.nm +140 -33
- package/core/System/Channel.nm +80 -29
- package/core/System/ClassBuffer.nm +89 -32
- package/core/System/Console.nm +4 -2
- package/core/System/Controls/Button.nm +4 -4
- package/core/System/Controls/CheckBox.nm +1 -1
- package/core/System/Controls/Text.nm +2 -2
- package/core/System/Controls/TextBox.nm +6 -6
- package/core/System/Controls/Window.nm +2 -2
- package/core/System/Fiber.nm +121 -0
- package/core/System/Graph.nm +4 -4
- package/core/System/LinkedList.nm +4 -4
- package/core/System/List.nm +6 -6
- package/core/System/Map.nm +30 -30
- package/core/System/Mutex.nm +57 -61
- package/core/System/Nursery.nm +10 -8
- package/core/System/Set.nm +24 -24
- package/core/System/Stream/Directory.nm +4 -4
- package/core/System/Stream/File.nm +19 -12
- package/core/System/Stream/Http.nm +83 -434
- package/core/System/Stream/Tcp.nm +441 -0
- package/core/System/String.nm +47 -18
- package/core/System/Task.nm +103 -4
- package/core/System/Text/JsonTree.nm +15 -15
- package/core/System/Thread.nm +83 -0
- package/core/System/bool.nm +2 -1
- package/core/System/char.nm +2 -1
- package/core/System/float.nm +2 -1
- package/core/System/float32.nm +2 -1
- package/core/System/float64.nm +2 -1
- package/core/System/int.nm +4 -2
- package/core/System/int16.nm +2 -1
- package/core/System/int32.nm +2 -1
- package/core/System/int64.nm +2 -1
- package/core/System/int8.nm +2 -1
- package/core/System/ufloat.nm +2 -1
- package/core/System/ufloat32.nm +2 -1
- package/core/System/ufloat64.nm +2 -1
- package/core/System/uint.nm +2 -1
- package/core/System/uint16.nm +2 -1
- package/core/System/uint32.nm +2 -1
- package/core/System/uint64.nm +2 -1
- package/core/System/uint8.nm +2 -1
- package/core/docs/System/BigInt.md +0 -1
- package/dist/index.mjs +20401 -13796
- package/package.json +1 -1
|
@@ -43,7 +43,7 @@ pub struct Directory {
|
|
|
43
43
|
```
|
|
44
44
|
```
|
|
45
45
|
#arch: c
|
|
46
|
-
if (mkdir(path, 0777)) return errno;
|
|
46
|
+
if (mkdir(path.ptr, 0777)) return errno;
|
|
47
47
|
return 0;
|
|
48
48
|
```
|
|
49
49
|
```
|
|
@@ -76,7 +76,7 @@ pub struct Directory {
|
|
|
76
76
|
func raw_remove = (string path, out int) {
|
|
77
77
|
```
|
|
78
78
|
#arch: c
|
|
79
|
-
if (rmdir(path)) return errno;
|
|
79
|
+
if (rmdir(path.ptr)) return errno;
|
|
80
80
|
return 0;
|
|
81
81
|
```
|
|
82
82
|
```
|
|
@@ -109,7 +109,7 @@ pub struct Directory {
|
|
|
109
109
|
```
|
|
110
110
|
#arch: c
|
|
111
111
|
struct stat st;
|
|
112
|
-
return stat(path, &st) == 0 ? 1 : 0;
|
|
112
|
+
return stat(path.ptr, &st) == 0 ? 1 : 0;
|
|
113
113
|
```
|
|
114
114
|
```
|
|
115
115
|
#arch: aarch64
|
|
@@ -147,7 +147,7 @@ pub struct Directory {
|
|
|
147
147
|
```
|
|
148
148
|
#arch: c
|
|
149
149
|
Result_string_DirectoryError r;
|
|
150
|
-
DIR *d = opendir(path);
|
|
150
|
+
DIR *d = opendir(path.ptr);
|
|
151
151
|
if (!d) {
|
|
152
152
|
int e = errno;
|
|
153
153
|
long de = 4;
|
|
@@ -72,7 +72,8 @@ pub struct File {
|
|
|
72
72
|
```
|
|
73
73
|
```
|
|
74
74
|
#arch: c
|
|
75
|
-
|
|
75
|
+
// Fat-string ABI: strings pass their ptr half at FFI boundaries.
|
|
76
|
+
self->handle = (unsigned long long)fopen(path.ptr, mode.ptr);
|
|
76
77
|
if (self->handle) {
|
|
77
78
|
self->error = 0;
|
|
78
79
|
} else {
|
|
@@ -236,21 +237,24 @@ pub struct File {
|
|
|
236
237
|
#arch: c
|
|
237
238
|
FILE *f = (FILE*)(unsigned long long)self->handle;
|
|
238
239
|
if (!f) { self->error = 9; return; }
|
|
239
|
-
fputs
|
|
240
|
+
// Byte-exact write of the tracked length (fputs stopped at the
|
|
241
|
+
// first embedded NUL).
|
|
242
|
+
fwrite(data.ptr, 1, data.len, f);
|
|
240
243
|
self->error = 0;
|
|
241
244
|
```
|
|
242
245
|
```
|
|
243
246
|
#arch: aarch64
|
|
244
|
-
// Fat-string ABI: data = (x1, x2).
|
|
247
|
+
// Fat-string ABI: data = (x1 ptr, x2 len).
|
|
245
248
|
ldr x3, [x19, #8]
|
|
246
249
|
cbnz x3, .Lfile_write_all_go
|
|
247
250
|
mov x0, #9
|
|
248
251
|
str x0, [x19, #24]
|
|
249
252
|
b .return_File_raw_write_all
|
|
250
253
|
.Lfile_write_all_go:
|
|
254
|
+
// fwrite(ptr, 1, len, f) — byte-exact (fputs truncated at NUL)
|
|
251
255
|
mov x0, x1
|
|
252
|
-
mov x1,
|
|
253
|
-
bl
|
|
256
|
+
mov x1, #1
|
|
257
|
+
bl _fwrite
|
|
254
258
|
str xzr, [x19, #24]
|
|
255
259
|
```
|
|
256
260
|
}
|
|
@@ -375,22 +379,25 @@ pub struct File {
|
|
|
375
379
|
#arch: c
|
|
376
380
|
FILE *f = (FILE*)(unsigned long long)self->handle;
|
|
377
381
|
if (!f) { self->error = 9; return; }
|
|
378
|
-
fputs
|
|
382
|
+
// Byte-exact write of the tracked length (fputs stopped at the
|
|
383
|
+
// first embedded NUL).
|
|
384
|
+
fwrite(data.ptr, 1, data.len, f);
|
|
379
385
|
fputc('\n', f);
|
|
380
386
|
self->error = 0;
|
|
381
387
|
```
|
|
382
388
|
```
|
|
383
389
|
#arch: aarch64
|
|
384
|
-
// Fat-string ABI: data = (x1, x2).
|
|
390
|
+
// Fat-string ABI: data = (x1 ptr, x2 len).
|
|
385
391
|
ldr x3, [x19, #8]
|
|
386
392
|
cbnz x3, .Lfile_write_line_go
|
|
387
393
|
mov x0, #9
|
|
388
394
|
str x0, [x19, #24]
|
|
389
395
|
b .return_File_raw_write_line
|
|
390
396
|
.Lfile_write_line_go:
|
|
397
|
+
// fwrite(ptr, 1, len, f) — byte-exact (fputs truncated at NUL)
|
|
391
398
|
mov x0, x1
|
|
392
|
-
mov x1,
|
|
393
|
-
bl
|
|
399
|
+
mov x1, #1
|
|
400
|
+
bl _fwrite
|
|
394
401
|
mov w0, #10
|
|
395
402
|
ldr x1, [x19, #8]
|
|
396
403
|
bl _fputc
|
|
@@ -476,7 +483,7 @@ pub struct File {
|
|
|
476
483
|
#arch: c
|
|
477
484
|
FILE *f = (FILE*)(unsigned long long)self->handle;
|
|
478
485
|
if (!f) { self->error = 9; return; }
|
|
479
|
-
fwrite(data, 1, size, f);
|
|
486
|
+
fwrite(data.ptr, 1, size, f);
|
|
480
487
|
self->error = 0;
|
|
481
488
|
```
|
|
482
489
|
```
|
|
@@ -513,7 +520,7 @@ pub struct File {
|
|
|
513
520
|
```
|
|
514
521
|
#arch: c
|
|
515
522
|
struct stat st;
|
|
516
|
-
return stat(path, &st) == 0 ? 1 : 0;
|
|
523
|
+
return stat(path.ptr, &st) == 0 ? 1 : 0;
|
|
517
524
|
```
|
|
518
525
|
```
|
|
519
526
|
#arch: aarch64
|
|
@@ -532,7 +539,7 @@ pub struct File {
|
|
|
532
539
|
func raw_delete = (string path, out int) {
|
|
533
540
|
```
|
|
534
541
|
#arch: c
|
|
535
|
-
if (remove(path)) return errno;
|
|
542
|
+
if (remove(path.ptr)) return errno;
|
|
536
543
|
return 0;
|
|
537
544
|
```
|
|
538
545
|
```
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A minimal
|
|
2
|
+
* A minimal HTTP/1.1 client built on Tcp.
|
|
3
3
|
*
|
|
4
4
|
* Plain `http://` only — no TLS (an `https://` URL cannot be served; use a
|
|
5
5
|
* TLS proxy or wait for a TLS-capable transport). Construct an instance,
|
|
6
|
-
* call `get`/`post
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* call `get`/`post`, then read the `status` field for the response's status
|
|
7
|
+
* code. Fallible calls return a `Result` whose error side is an `HttpError`;
|
|
8
|
+
* `status` is 0 when DNS resolution or the connection fails.
|
|
9
|
+
*
|
|
10
|
+
* Every wait rides Tcp's netpoller hook: inside a Fiber the request parks
|
|
11
|
+
* (freeing its worker) instead of blocking — the same `Http` code scales
|
|
12
|
+
* from one call to thousands of concurrent fibers. See ASYNC.md
|
|
13
|
+
* Phase 3.
|
|
10
14
|
*
|
|
11
15
|
* URLs may carry an explicit port (`http://host:8080/path`); the default is
|
|
12
16
|
* 80 and the default path is `/`. `post` sends `body` with a
|
|
@@ -27,8 +31,9 @@ pub struct Http {
|
|
|
27
31
|
pub var int status = 0
|
|
28
32
|
|
|
29
33
|
// Internal failure code from the most recent request: 0 = success,
|
|
30
|
-
// 1 = DNS resolution, 2 = socket creation, 3 = connect
|
|
31
|
-
//
|
|
34
|
+
// 1 = DNS resolution, 2 = socket creation, 3 = connect, 6 = send failed.
|
|
35
|
+
// Mirrors Tcp's codes on the connect path; the Result-returning wrappers
|
|
36
|
+
// map it to HttpError.
|
|
32
37
|
var int error = 0
|
|
33
38
|
|
|
34
39
|
// Maps the raw failure code to its HttpError case.
|
|
@@ -53,449 +58,93 @@ pub struct Http {
|
|
|
53
58
|
// method string ("GET" / "POST"); a leading 'P' selects POST semantics
|
|
54
59
|
// (sends `body` and the Content-* headers). Sets self->status (0 on
|
|
55
60
|
// failure) and self->error, and returns the response body (empty string
|
|
56
|
-
// on failure).
|
|
57
|
-
// transfers ownership to the caller.
|
|
61
|
+
// on failure).
|
|
58
62
|
func raw_exchange = (ref self, string method, string url, string body, move out string) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
#include <netdb.h>
|
|
64
|
-
#include <unistd.h>
|
|
65
|
-
#include <string.h>
|
|
66
|
-
#include <stdlib.h>
|
|
67
|
-
```
|
|
68
|
-
```
|
|
69
|
-
#arch: c
|
|
70
|
-
// Fat-string ABI: params are (ptr, len) pairs; consume the .ptr
|
|
71
|
-
// halves at each FFI boundary.
|
|
72
|
-
const char *scheme = strstr(url.ptr, "://");
|
|
73
|
-
const char *hp = scheme ? scheme + 3 : url.ptr;
|
|
74
|
-
const char *colon = strchr(hp, ':');
|
|
75
|
-
const char *slash = strchr(hp, '/');
|
|
76
|
-
char host[256];
|
|
77
|
-
int port = 80;
|
|
78
|
-
const char *path = "/";
|
|
79
|
-
|
|
80
|
-
if (colon && (!slash || colon < slash)) {
|
|
81
|
-
int hlen = (int)(colon - hp);
|
|
82
|
-
if (hlen > 255) hlen = 255;
|
|
83
|
-
memcpy(host, hp, hlen);
|
|
84
|
-
host[hlen] = 0;
|
|
85
|
-
port = atoi(colon + 1);
|
|
86
|
-
} else {
|
|
87
|
-
const char *end = slash ? slash : hp + strlen(hp);
|
|
88
|
-
int hlen = (int)(end - hp);
|
|
89
|
-
if (hlen > 255) hlen = 255;
|
|
90
|
-
memcpy(host, hp, hlen);
|
|
91
|
-
host[hlen] = 0;
|
|
63
|
+
// Parse the URL: [http://]host[:port][/path]
|
|
64
|
+
var int host_start = 0
|
|
65
|
+
if url.starts_with("http://") {
|
|
66
|
+
host_start = 7
|
|
92
67
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return (nomen_string){ strdup(""), 0 };
|
|
68
|
+
var int slash = url.index_of_from("/", host_start)
|
|
69
|
+
var int colon = url.index_of_from(":", host_start)
|
|
70
|
+
var int host_end = url.length
|
|
71
|
+
if slash >= 0 {
|
|
72
|
+
host_end = slash
|
|
73
|
+
}
|
|
74
|
+
var int name_end = host_end
|
|
75
|
+
if colon >= 0 {
|
|
76
|
+
if colon < host_end {
|
|
77
|
+
name_end = colon
|
|
78
|
+
}
|
|
105
79
|
}
|
|
106
|
-
int
|
|
107
|
-
if
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
self->error = 2;
|
|
111
|
-
return (nomen_string){ strdup(""), 0 };
|
|
80
|
+
var int port = 80
|
|
81
|
+
if name_end != host_end {
|
|
82
|
+
var string port_text = url.substring(name_end + 1, host_end)
|
|
83
|
+
port = int.parse(port_text)
|
|
112
84
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
self->error = 3;
|
|
118
|
-
return (nomen_string){ strdup(""), 0 };
|
|
85
|
+
var string host = url.substring(host_start, name_end)
|
|
86
|
+
var string path = "/"
|
|
87
|
+
if slash >= 0 {
|
|
88
|
+
path = url.substring(slash, url.length)
|
|
119
89
|
}
|
|
120
|
-
freeaddrinfo(res);
|
|
121
90
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
91
|
+
// Connect — parks a fiber while the handshake completes.
|
|
92
|
+
var Tcp conn = Tcp.connect(host, port)
|
|
93
|
+
if conn.fd < 0 {
|
|
94
|
+
self.status = 0
|
|
95
|
+
self.error = conn.error
|
|
96
|
+
return ""
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Build the request head.
|
|
100
|
+
var string request = method + " " + path + " HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n"
|
|
101
|
+
if method.starts_with("P") {
|
|
102
|
+
request = request + "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: \{body.length}\r\n\r\n"
|
|
133
103
|
} else {
|
|
134
|
-
|
|
135
|
-
send(sock, req, off, 0);
|
|
104
|
+
request = request + "\r\n"
|
|
136
105
|
}
|
|
137
106
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (len + 1 >= cap) {
|
|
144
|
-
cap *= 2;
|
|
145
|
-
buf = (char*)realloc(buf, cap);
|
|
107
|
+
// Send — parks while the socket back-pressures.
|
|
108
|
+
var bool sent = conn.send(request)
|
|
109
|
+
if sent {
|
|
110
|
+
if method.starts_with("P") {
|
|
111
|
+
sent = conn.send(body)
|
|
146
112
|
}
|
|
147
113
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
code = atoi(buf + 9);
|
|
114
|
+
if !sent {
|
|
115
|
+
conn.close()
|
|
116
|
+
self.status = 0
|
|
117
|
+
self.error = 6
|
|
118
|
+
return ""
|
|
154
119
|
}
|
|
155
|
-
self->status = code;
|
|
156
|
-
self->error = 0;
|
|
157
120
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
121
|
+
// Receive until the peer closes (how Connection: close HTTP works).
|
|
122
|
+
// (Named `wire`, not `response`: the aarch64 build-global moved-set is
|
|
123
|
+
// name-keyed, and a bare `return response` here would suppress the
|
|
124
|
+
// return-path free of get/post's own `response` local — see the
|
|
125
|
+
// FOLLOWUP.md entry.)
|
|
126
|
+
var string wire = conn.recv_all()
|
|
127
|
+
conn.close()
|
|
128
|
+
|
|
129
|
+
self.error = 0
|
|
130
|
+
// Status line: "HTTP/1.x NNN ..." — the code lives at bytes 9..12.
|
|
131
|
+
if wire.starts_with("HTTP/") && wire.length >= 12 {
|
|
132
|
+
var string code_text = wire.substring(9, 12)
|
|
133
|
+
self.status = int.parse(code_text)
|
|
134
|
+
} else {
|
|
135
|
+
self.status = 0
|
|
164
136
|
}
|
|
165
|
-
return (nomen_string){ buf, len };
|
|
166
|
-
```
|
|
167
|
-
```
|
|
168
|
-
#arch: aarch64
|
|
169
|
-
// Fat-string ABI: x0=self(->x19); method=(x1,x2), url=(x3,x4),
|
|
170
|
-
// body=(x5,x6) — only the ptr halves are consumed below, plus
|
|
171
|
-
// body.len (stashed at #200) for Content-Length/send.
|
|
172
|
-
// Struct layout: self->status at [x19, #8], self->error at
|
|
173
|
-
// [x19, #16] (1 = dns, 2 = socket, 3 = connect; cleared on success).
|
|
174
|
-
// macOS arm64 passes variadic args on the caller stack at [sp+0..], so
|
|
175
|
-
// [sp+0..47] is reserved scratch for snprintf variadic args and the
|
|
176
|
-
// addrinfo hints live above it. Stack frame (2048 bytes):
|
|
177
|
-
// #0 variadic scratch (snprintf args)
|
|
178
|
-
// #48 hints (struct addrinfo, 48 bytes)
|
|
179
|
-
// #96 res* #104 sock fd
|
|
180
|
-
// #112 port #120 hp (host start)
|
|
181
|
-
// #128 method #136 url
|
|
182
|
-
// #144 body #152 path
|
|
183
|
-
// #160 colon/blen/buf #168 slash/cap
|
|
184
|
-
// #176 hostlen/req_off #184 portstr (16)
|
|
185
|
-
// #208 host buffer (256) #464 request buffer (1584)
|
|
186
|
-
sub sp, sp, #2048
|
|
187
|
-
str x1, [sp, #128]
|
|
188
|
-
str x3, [sp, #136]
|
|
189
|
-
str x5, [sp, #144]
|
|
190
|
-
str x6, [sp, #200] // body len
|
|
191
|
-
mov x0, #80
|
|
192
|
-
str x0, [sp, #112]
|
|
193
|
-
adr x0, .Lhttp_slash
|
|
194
|
-
str x0, [sp, #152]
|
|
195
|
-
|
|
196
|
-
// hp = (strstr(url, "://") ?: url) + 3 when scheme present
|
|
197
|
-
ldr x0, [sp, #136]
|
|
198
|
-
adr x1, .Lhttp_scheme
|
|
199
|
-
bl _strstr
|
|
200
|
-
cbz x0, .Lhttp_sethp
|
|
201
|
-
add x0, x0, #3
|
|
202
|
-
.Lhttp_sethp:
|
|
203
|
-
str x0, [sp, #120]
|
|
204
|
-
|
|
205
|
-
// colon = strchr(hp, ':'); slash = strchr(hp, '/')
|
|
206
|
-
ldr x0, [sp, #120]
|
|
207
|
-
mov x1, #0x3A
|
|
208
|
-
bl _strchr
|
|
209
|
-
str x0, [sp, #160]
|
|
210
|
-
ldr x0, [sp, #120]
|
|
211
|
-
mov x1, #0x2F
|
|
212
|
-
bl _strchr
|
|
213
|
-
str x0, [sp, #168]
|
|
214
137
|
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
b.lo .Lhttp_port
|
|
222
|
-
.Lhttp_np:
|
|
223
|
-
// hostlen = slash ? (slash - hp) : strlen(hp); path = slash
|
|
224
|
-
ldr x0, [sp, #168]
|
|
225
|
-
cbz x0, .Lhttp_np_strlen
|
|
226
|
-
ldr x1, [sp, #120]
|
|
227
|
-
sub x0, x0, x1
|
|
228
|
-
str x0, [sp, #176]
|
|
229
|
-
ldr x0, [sp, #168]
|
|
230
|
-
str x0, [sp, #152]
|
|
231
|
-
b .Lhttp_cph
|
|
232
|
-
.Lhttp_np_strlen:
|
|
233
|
-
ldr x0, [sp, #120]
|
|
234
|
-
bl _strlen
|
|
235
|
-
str x0, [sp, #176]
|
|
236
|
-
b .Lhttp_cph
|
|
237
|
-
.Lhttp_port:
|
|
238
|
-
// hostlen = colon - hp; port = atoi(colon + 1)
|
|
239
|
-
ldr x0, [sp, #120]
|
|
240
|
-
ldr x1, [sp, #160]
|
|
241
|
-
sub x0, x1, x0
|
|
242
|
-
str x0, [sp, #176]
|
|
243
|
-
ldr x0, [sp, #160]
|
|
244
|
-
add x0, x0, #1
|
|
245
|
-
bl _atoi
|
|
246
|
-
str x0, [sp, #112]
|
|
247
|
-
ldr x0, [sp, #168]
|
|
248
|
-
cbz x0, .Lhttp_cph
|
|
249
|
-
str x0, [sp, #152]
|
|
250
|
-
|
|
251
|
-
// hostlen = min(hostlen, 255); memcpy(hostbuf, hp, hostlen); hostbuf[hostlen]=0
|
|
252
|
-
.Lhttp_cph:
|
|
253
|
-
ldr x0, [sp, #176]
|
|
254
|
-
mov x9, #255
|
|
255
|
-
cmp x0, x9
|
|
256
|
-
csel x0, x0, x9, ls
|
|
257
|
-
str x0, [sp, #176]
|
|
258
|
-
add x0, sp, #208
|
|
259
|
-
ldr x1, [sp, #120]
|
|
260
|
-
ldr x2, [sp, #176]
|
|
261
|
-
bl _memcpy
|
|
262
|
-
add x0, sp, #208
|
|
263
|
-
ldr x1, [sp, #176]
|
|
264
|
-
strb wzr, [x0, x1]
|
|
265
|
-
|
|
266
|
-
// memset(&hints, 0, 48); hints.ai_family=AF_INET(2); hints.ai_socktype=SOCK_STREAM(1)
|
|
267
|
-
add x0, sp, #48
|
|
268
|
-
mov x1, xzr
|
|
269
|
-
mov x2, #48
|
|
270
|
-
bl _memset
|
|
271
|
-
mov w0, #2
|
|
272
|
-
str w0, [sp, #52]
|
|
273
|
-
mov w0, #1
|
|
274
|
-
str w0, [sp, #56]
|
|
275
|
-
// snprintf(portstr, 16, "%ld", port) — variadic arg on stack at [sp+0]
|
|
276
|
-
ldr x9, [sp, #112]
|
|
277
|
-
str x9, [sp, #0]
|
|
278
|
-
add x0, sp, #184
|
|
279
|
-
mov x1, #16
|
|
280
|
-
adr x2, .Lhttp_fmt_ld
|
|
281
|
-
bl _snprintf
|
|
282
|
-
// getaddrinfo(host, portstr, &hints, &res)
|
|
283
|
-
add x0, sp, #208
|
|
284
|
-
add x1, sp, #184
|
|
285
|
-
add x2, sp, #48
|
|
286
|
-
add x3, sp, #96
|
|
287
|
-
bl _getaddrinfo
|
|
288
|
-
cbnz w0, .Lhttp_dnsfail
|
|
289
|
-
|
|
290
|
-
// sock = socket(AF_INET, SOCK_STREAM, 0)
|
|
291
|
-
mov x0, #2
|
|
292
|
-
mov x1, #1
|
|
293
|
-
mov x2, xzr
|
|
294
|
-
bl _socket
|
|
295
|
-
cmp w0, #0
|
|
296
|
-
b.ge .Lhttp_sockok
|
|
297
|
-
ldr x0, [sp, #96]
|
|
298
|
-
bl _freeaddrinfo
|
|
299
|
-
mov x9, #2
|
|
300
|
-
str x9, [x19, #16]
|
|
301
|
-
b .Lhttp_fail
|
|
302
|
-
.Lhttp_sockok:
|
|
303
|
-
str w0, [sp, #104]
|
|
304
|
-
// connect(sock, res->ai_addr (off 32), res->ai_addrlen (off 16))
|
|
305
|
-
ldr x9, [sp, #96]
|
|
306
|
-
ldr x1, [x9, #32]
|
|
307
|
-
ldr w2, [x9, #16]
|
|
308
|
-
ldr w0, [sp, #104]
|
|
309
|
-
bl _connect
|
|
310
|
-
cmp w0, #0
|
|
311
|
-
b.ge .Lhttp_connected
|
|
312
|
-
ldr x0, [sp, #96]
|
|
313
|
-
bl _freeaddrinfo
|
|
314
|
-
ldr w0, [sp, #104]
|
|
315
|
-
bl _close
|
|
316
|
-
mov x9, #3
|
|
317
|
-
str x9, [x19, #16]
|
|
318
|
-
b .Lhttp_fail
|
|
319
|
-
.Lhttp_connected:
|
|
320
|
-
ldr x0, [sp, #96]
|
|
321
|
-
bl _freeaddrinfo
|
|
322
|
-
|
|
323
|
-
// off = snprintf(req, 1584, common_fmt, method, path, host)
|
|
324
|
-
// variadic args on stack: method@[0], path@[8], host@[16]
|
|
325
|
-
ldr x9, [sp, #128]
|
|
326
|
-
str x9, [sp, #0]
|
|
327
|
-
ldr x9, [sp, #152]
|
|
328
|
-
str x9, [sp, #8]
|
|
329
|
-
add x9, sp, #208
|
|
330
|
-
str x9, [sp, #16]
|
|
331
|
-
add x0, sp, #464
|
|
332
|
-
mov x1, #1584
|
|
333
|
-
adr x2, .Lhttp_reqcommon
|
|
334
|
-
bl _snprintf
|
|
335
|
-
sxtw x0, w0
|
|
336
|
-
str x0, [sp, #176]
|
|
337
|
-
|
|
338
|
-
// if method[0] == 'P' (0x50) -> POST
|
|
339
|
-
ldr x0, [sp, #128]
|
|
340
|
-
ldrb w0, [x0]
|
|
341
|
-
cmp w0, #0x50
|
|
342
|
-
b.ne .Lhttp_getsend
|
|
343
|
-
|
|
344
|
-
// POST: blen = body.len (fat half); append Content-Length; send both
|
|
345
|
-
ldr x9, [sp, #200]
|
|
346
|
-
str x9, [sp, #160]
|
|
347
|
-
// snprintf(req+off, 1584-off, reqpost, blen) — blen on stack at [sp+0]
|
|
348
|
-
ldr x9, [sp, #160]
|
|
349
|
-
str x9, [sp, #0]
|
|
350
|
-
add x0, sp, #464
|
|
351
|
-
ldr x1, [sp, #176]
|
|
352
|
-
add x0, x0, x1
|
|
353
|
-
mov x1, #1584
|
|
354
|
-
ldr x2, [sp, #176]
|
|
355
|
-
sub x1, x1, x2
|
|
356
|
-
adr x2, .Lhttp_reqpost
|
|
357
|
-
bl _snprintf
|
|
358
|
-
sxtw x0, w0
|
|
359
|
-
ldr x1, [sp, #176]
|
|
360
|
-
add x1, x1, x0
|
|
361
|
-
str x1, [sp, #176]
|
|
362
|
-
ldr w0, [sp, #104]
|
|
363
|
-
add x1, sp, #464
|
|
364
|
-
ldr x2, [sp, #176]
|
|
365
|
-
mov x3, xzr
|
|
366
|
-
bl _send
|
|
367
|
-
ldr w0, [sp, #104]
|
|
368
|
-
ldr x1, [sp, #144]
|
|
369
|
-
ldr x2, [sp, #200]
|
|
370
|
-
mov x3, xzr
|
|
371
|
-
bl _send
|
|
372
|
-
b .Lhttp_recv
|
|
373
|
-
|
|
374
|
-
.Lhttp_getsend:
|
|
375
|
-
// GET: append trailing "\r\n" (no variadic) and send
|
|
376
|
-
add x0, sp, #464
|
|
377
|
-
ldr x1, [sp, #176]
|
|
378
|
-
add x0, x0, x1
|
|
379
|
-
mov x1, #1584
|
|
380
|
-
ldr x2, [sp, #176]
|
|
381
|
-
sub x1, x1, x2
|
|
382
|
-
adr x2, .Lhttp_crlf
|
|
383
|
-
bl _snprintf
|
|
384
|
-
sxtw x0, w0
|
|
385
|
-
ldr x1, [sp, #176]
|
|
386
|
-
add x1, x1, x0
|
|
387
|
-
str x1, [sp, #176]
|
|
388
|
-
ldr w0, [sp, #104]
|
|
389
|
-
add x1, sp, #464
|
|
390
|
-
ldr x2, [sp, #176]
|
|
391
|
-
mov x3, xzr
|
|
392
|
-
bl _send
|
|
393
|
-
|
|
394
|
-
// recv loop: buf = malloc(4096); grow as needed
|
|
395
|
-
.Lhttp_recv:
|
|
396
|
-
mov x0, #4096
|
|
397
|
-
bl _malloc
|
|
398
|
-
str x0, [sp, #160]
|
|
399
|
-
mov x0, #4096
|
|
400
|
-
str x0, [sp, #168]
|
|
401
|
-
str xzr, [sp, #96]
|
|
402
|
-
.Lhttp_recvloop:
|
|
403
|
-
ldr w0, [sp, #104]
|
|
404
|
-
ldr x1, [sp, #160]
|
|
405
|
-
ldr x2, [sp, #96]
|
|
406
|
-
add x1, x1, x2
|
|
407
|
-
ldr x2, [sp, #168]
|
|
408
|
-
ldr x3, [sp, #96]
|
|
409
|
-
sub x2, x2, x3
|
|
410
|
-
sub x2, x2, #1
|
|
411
|
-
mov x3, xzr
|
|
412
|
-
bl _recv
|
|
413
|
-
cmp x0, #0
|
|
414
|
-
ble .Lhttp_recvdone
|
|
415
|
-
ldr x1, [sp, #96]
|
|
416
|
-
add x1, x1, x0
|
|
417
|
-
str x1, [sp, #96]
|
|
418
|
-
add x2, x1, #1
|
|
419
|
-
ldr x3, [sp, #168]
|
|
420
|
-
cmp x2, x3
|
|
421
|
-
blt .Lhttp_recvloop
|
|
422
|
-
ldr x0, [sp, #168]
|
|
423
|
-
lsl x0, x0, #1
|
|
424
|
-
str x0, [sp, #168]
|
|
425
|
-
mov x1, x0
|
|
426
|
-
ldr x0, [sp, #160]
|
|
427
|
-
bl _realloc
|
|
428
|
-
str x0, [sp, #160]
|
|
429
|
-
b .Lhttp_recvloop
|
|
430
|
-
|
|
431
|
-
.Lhttp_recvdone:
|
|
432
|
-
// buf[len] = 0; close(sock)
|
|
433
|
-
ldr x0, [sp, #160]
|
|
434
|
-
ldr x1, [sp, #96]
|
|
435
|
-
strb wzr, [x0, x1]
|
|
436
|
-
ldr w0, [sp, #104]
|
|
437
|
-
bl _close
|
|
438
|
-
// success: clear error before storing the status code
|
|
439
|
-
str xzr, [x19, #16]
|
|
440
|
-
// self->status = atoi(buf + 9)
|
|
441
|
-
ldr x0, [sp, #160]
|
|
442
|
-
add x0, x0, #9
|
|
443
|
-
bl _atoi
|
|
444
|
-
sxtw x0, w0
|
|
445
|
-
str x0, [x19, #8]
|
|
446
|
-
// body_start = strstr(buf, "\r\n\r\n"); fat returns carry lens.
|
|
447
|
-
ldr x0, [sp, #160]
|
|
448
|
-
adr x1, .Lhttp_hdrsep
|
|
449
|
-
bl _strstr
|
|
450
|
-
cbz x0, .Lhttp_retbuf
|
|
451
|
-
// result = strdup(body_start + 4); rlen = len - (body_start+4-buf)
|
|
452
|
-
add x9, x0, #4
|
|
453
|
-
ldr x10, [sp, #160]
|
|
454
|
-
sub x9, x9, x10
|
|
455
|
-
ldr x10, [sp, #96]
|
|
456
|
-
sub x9, x10, x9 // rlen
|
|
457
|
-
str x9, [sp, #168]
|
|
458
|
-
add x0, x0, #4
|
|
459
|
-
bl _strdup
|
|
460
|
-
ldr x1, [sp, #168]
|
|
461
|
-
str x0, [sp, #112]
|
|
462
|
-
ldr x0, [sp, #160]
|
|
463
|
-
bl _free
|
|
464
|
-
ldr x0, [sp, #112]
|
|
465
|
-
add sp, sp, #2048
|
|
466
|
-
b .return_Http_raw_exchange
|
|
467
|
-
.Lhttp_retbuf:
|
|
468
|
-
ldr x0, [sp, #160]
|
|
469
|
-
ldr x1, [sp, #96]
|
|
470
|
-
add sp, sp, #2048
|
|
471
|
-
b .return_Http_raw_exchange
|
|
472
|
-
.Lhttp_dnsfail:
|
|
473
|
-
mov x9, #1
|
|
474
|
-
str x9, [x19, #16]
|
|
475
|
-
b .Lhttp_fail
|
|
476
|
-
.Lhttp_fail:
|
|
477
|
-
str xzr, [x19, #8]
|
|
478
|
-
adr x0, .Lhttp_empty
|
|
479
|
-
bl _strdup
|
|
480
|
-
mov x1, #0
|
|
481
|
-
add sp, sp, #2048
|
|
482
|
-
b .return_Http_raw_exchange
|
|
483
|
-
|
|
484
|
-
.Lhttp_scheme: .asciz "://"
|
|
485
|
-
.Lhttp_slash: .asciz "/"
|
|
486
|
-
.Lhttp_fmt_ld: .asciz "%ld"
|
|
487
|
-
.Lhttp_crlf: .asciz "\r\n"
|
|
488
|
-
.Lhttp_hdrsep: .asciz "\r\n\r\n"
|
|
489
|
-
.Lhttp_empty: .asciz ""
|
|
490
|
-
.Lhttp_reqcommon: .asciz "%s %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n"
|
|
491
|
-
.Lhttp_reqpost: .asciz "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: %ld\r\n\r\n"
|
|
492
|
-
.p2align 2
|
|
493
|
-
```
|
|
494
|
-
return ""
|
|
138
|
+
// Body starts after the blank header/body separator line.
|
|
139
|
+
var int sep = wire.index_of("\r\n\r\n")
|
|
140
|
+
if sep >= 0 {
|
|
141
|
+
return wire.substring(sep + 4, wire.length)
|
|
142
|
+
}
|
|
143
|
+
return wire
|
|
495
144
|
}
|
|
496
145
|
|
|
497
|
-
// Issue a
|
|
498
|
-
//
|
|
146
|
+
// Issue a GET request to `url`. `.ok(body)` with the response body and
|
|
147
|
+
// `self.status` set to the response's status code, or
|
|
499
148
|
// `.error(HttpError)` (`status` is 0).
|
|
500
149
|
pub func get = (ref self, string url, out Result<string, HttpError>) {
|
|
501
150
|
const string response = self.raw_exchange("GET", url, "")
|
|
@@ -505,7 +154,7 @@ pub struct Http {
|
|
|
505
154
|
return Result.error(Http.error_of(self.error))
|
|
506
155
|
}
|
|
507
156
|
|
|
508
|
-
// Issue a
|
|
157
|
+
// Issue a POST request to `url` with `body` as the payload.
|
|
509
158
|
// `.ok(body)` with the response body and `self.status` set to the
|
|
510
159
|
// response's status code, or `.error(HttpError)` (`status` is 0).
|
|
511
160
|
pub func post = (ref self, string url, string body, out Result<string, HttpError>) {
|