nomen-lang 0.4.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/core/System/Awaitable.nm +21 -0
- package/core/System/Buffer.nm +16 -9
- package/core/System/Channel.nm +80 -29
- package/core/System/ClassBuffer.nm +9 -4
- package/core/System/Fiber.nm +121 -0
- package/core/System/Mutex.nm +57 -61
- package/core/System/Nursery.nm +10 -8
- package/core/System/Stream/Http.nm +83 -434
- package/core/System/Stream/Tcp.nm +441 -0
- package/core/System/Task.nm +103 -4
- package/core/System/Thread.nm +83 -0
- package/dist/index.mjs +19224 -13481
- package/package.json +1 -1
package/core/System/Nursery.nm
CHANGED
|
@@ -5,18 +5,19 @@
|
|
|
5
5
|
// An `async` block names its nursery (`async pool { }`), binding a Nursery
|
|
6
6
|
// variable in scope. That variable is passed to helper functions with `ref`
|
|
7
7
|
// and is the receiver of `pool.spawn(fn(args))`. The Nursery wraps the
|
|
8
|
-
// per-invocation tracking state of the `async { }` block —
|
|
9
|
-
// futures
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
8
|
+
// per-invocation tracking state of the `async { }` block — pointers to the
|
|
9
|
+
// futures list's storage slot, the registered count, and the capacity (the
|
|
10
|
+
// list starts empty and grows by realloc; the compiler's registration helper
|
|
11
|
+
// writes through these pointers) — so it is only valid for the lifetime of
|
|
12
|
+
// its enclosing block (which is exactly the structured-concurrency
|
|
13
|
+
// invariant: the block cannot exit until every spawned task, including those
|
|
14
|
+
// spawned through a passed Nursery, has finished).
|
|
14
15
|
//
|
|
15
16
|
// Config rides on the declaration: `async pool = Nursery(timeout: 2000) { }`.
|
|
16
17
|
//
|
|
17
18
|
// `name.spawn(fn(args))` is special-cased by the compiler (it needs the spawn
|
|
18
|
-
// trampoline machinery), so it is NOT a regular method declared here. The
|
|
19
|
-
// fields are the full runtime contract.
|
|
19
|
+
// trampoline machinery), so it is NOT a regular method declared here. The
|
|
20
|
+
// three fields are the full runtime contract.
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* The capability for spawning into a caller's `async` block; owns and tracks its tasks
|
|
@@ -24,4 +25,5 @@
|
|
|
24
25
|
pub struct Nursery: Sendable {
|
|
25
26
|
pub var uint64 futures_ptr = 0
|
|
26
27
|
pub var uint64 count_ptr = 0
|
|
28
|
+
pub var uint64 cap_ptr = 0
|
|
27
29
|
}
|
|
@@ -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>) {
|