nomen-lang 0.4.0 → 0.6.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/Arena.nm +6 -6
- package/core/System/Awaitable.nm +21 -0
- package/core/System/Buffer.nm +31 -15
- package/core/System/Channel.nm +82 -29
- package/core/System/ClassBuffer.nm +23 -9
- package/core/System/Controls/Button.nm +2 -2
- package/core/System/Controls/CheckBox.nm +2 -2
- package/core/System/Controls/Container.nm +3 -3
- package/core/System/Controls/TextBox.nm +2 -2
- package/core/System/Fiber.nm +201 -0
- package/core/System/Graph.nm +1 -1
- package/core/System/LinkedList.nm +1 -1
- package/core/System/List.nm +3 -3
- package/core/System/Map.nm +2 -2
- package/core/System/Mutex.nm +50 -54
- package/core/System/Nursery.nm +10 -8
- package/core/System/Option.nm +2 -2
- package/core/System/Random.nm +67 -0
- package/core/System/Result.nm +2 -2
- package/core/System/Set.nm +1 -1
- package/core/System/Spawnable.nm +18 -0
- package/core/System/Stream/File.nm +3 -3
- package/core/System/Stream/Http.nm +85 -436
- package/core/System/Stream/Tcp.nm +441 -0
- package/core/System/String.nm +7 -7
- package/core/System/StringBuilder.nm +1 -1
- package/core/System/Task.nm +145 -12
- package/core/System/Test.nm +20 -11
- package/core/System/Text/CharIndex.nm +8 -8
- package/core/System/Text/Chars.nm +1 -1
- package/core/System/Text/JsonTree.nm +1 -1
- package/core/System/Text/Regex.nm +122 -32
- package/core/System/Text/Utf8.nm +6 -6
- package/core/System/Thread.nm +199 -0
- package/core/System/Tree.nm +1 -1
- package/dist/index.mjs +19473 -13661
- package/package.json +1 -1
|
@@ -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
|
|
@@ -24,12 +28,13 @@
|
|
|
24
28
|
pub struct Http {
|
|
25
29
|
// HTTP status code from the most recent request (e.g. 200). 0 when the
|
|
26
30
|
// request failed (the `error` side of the get/post Result says why).
|
|
27
|
-
pub var
|
|
31
|
+
pub var 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
|
-
//
|
|
32
|
-
|
|
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.
|
|
37
|
+
var error = 0
|
|
33
38
|
|
|
34
39
|
// Maps the raw failure code to its HttpError case.
|
|
35
40
|
func error_of = (int err, out HttpError) {
|
|
@@ -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 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
|
-
|
|
107
|
-
if
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
self->error = 2;
|
|
111
|
-
return (nomen_string){ strdup(""), 0 };
|
|
80
|
+
var 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 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>) {
|