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.
Files changed (50) hide show
  1. package/NOMEN_AGENTS.md +7 -1
  2. package/core/System/Arena.nm +7 -7
  3. package/core/System/Awaitable.nm +21 -0
  4. package/core/System/BigInt.nm +5 -15
  5. package/core/System/Buffer.nm +140 -33
  6. package/core/System/Channel.nm +80 -29
  7. package/core/System/ClassBuffer.nm +89 -32
  8. package/core/System/Console.nm +4 -2
  9. package/core/System/Controls/Button.nm +4 -4
  10. package/core/System/Controls/CheckBox.nm +1 -1
  11. package/core/System/Controls/Text.nm +2 -2
  12. package/core/System/Controls/TextBox.nm +6 -6
  13. package/core/System/Controls/Window.nm +2 -2
  14. package/core/System/Fiber.nm +121 -0
  15. package/core/System/Graph.nm +4 -4
  16. package/core/System/LinkedList.nm +4 -4
  17. package/core/System/List.nm +6 -6
  18. package/core/System/Map.nm +30 -30
  19. package/core/System/Mutex.nm +57 -61
  20. package/core/System/Nursery.nm +10 -8
  21. package/core/System/Set.nm +24 -24
  22. package/core/System/Stream/Directory.nm +4 -4
  23. package/core/System/Stream/File.nm +19 -12
  24. package/core/System/Stream/Http.nm +83 -434
  25. package/core/System/Stream/Tcp.nm +441 -0
  26. package/core/System/String.nm +47 -18
  27. package/core/System/Task.nm +103 -4
  28. package/core/System/Text/JsonTree.nm +15 -15
  29. package/core/System/Thread.nm +83 -0
  30. package/core/System/bool.nm +2 -1
  31. package/core/System/char.nm +2 -1
  32. package/core/System/float.nm +2 -1
  33. package/core/System/float32.nm +2 -1
  34. package/core/System/float64.nm +2 -1
  35. package/core/System/int.nm +4 -2
  36. package/core/System/int16.nm +2 -1
  37. package/core/System/int32.nm +2 -1
  38. package/core/System/int64.nm +2 -1
  39. package/core/System/int8.nm +2 -1
  40. package/core/System/ufloat.nm +2 -1
  41. package/core/System/ufloat32.nm +2 -1
  42. package/core/System/ufloat64.nm +2 -1
  43. package/core/System/uint.nm +2 -1
  44. package/core/System/uint16.nm +2 -1
  45. package/core/System/uint32.nm +2 -1
  46. package/core/System/uint64.nm +2 -1
  47. package/core/System/uint8.nm +2 -1
  48. package/core/docs/System/BigInt.md +0 -1
  49. package/dist/index.mjs +20401 -13796
  50. 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
- self->handle = (unsigned long long)fopen(path, mode);
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(data, f);
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, x3
253
- bl _fputs
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(data, f);
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, x3
393
- bl _fputs
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 blocking HTTP/1.1 client.
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` (which block until the full response is received), then
7
- * read the `status` field for the response's status code. Fallible calls
8
- * return a `Result` whose error side is an `HttpError`; `status` is 0 when
9
- * DNS resolution or the connection fails.
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. Raw #arch bodies
31
- // set it, the Result-returning wrappers map it to HttpError.
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). The raw body mallocs the response — `move out string`
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
- #arch: c
61
- #scope: file
62
- #include <sys/socket.h>
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
- if (slash) path = slash;
94
-
95
- struct addrinfo hints, *res;
96
- memset(&hints, 0, sizeof(hints));
97
- hints.ai_family = AF_INET;
98
- hints.ai_socktype = SOCK_STREAM;
99
- char portstr[16];
100
- snprintf(portstr, sizeof(portstr), "%d", port);
101
- if (getaddrinfo(host, portstr, &hints, &res) != 0) {
102
- self->status = 0;
103
- self->error = 1;
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 sock = socket(AF_INET, SOCK_STREAM, 0);
107
- if (sock < 0) {
108
- freeaddrinfo(res);
109
- self->status = 0;
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
- if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
114
- freeaddrinfo(res);
115
- close(sock);
116
- self->status = 0;
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
- char req[1600];
123
- int off = snprintf(req, sizeof(req),
124
- "%s %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n",
125
- method.ptr, path, host);
126
- if (method.ptr[0] == 'P') {
127
- int blen = (int)body.len;
128
- off += snprintf(req + off, sizeof(req) - off,
129
- "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\n\r\n",
130
- blen);
131
- send(sock, req, off, 0);
132
- send(sock, body.ptr, blen, 0);
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
- off += snprintf(req + off, sizeof(req) - off, "\r\n");
135
- send(sock, req, off, 0);
104
+ request = request + "\r\n"
136
105
  }
137
106
 
138
- int cap = 4096, len = 0;
139
- char *buf = (char*)malloc(cap);
140
- int n;
141
- while ((n = recv(sock, buf + len, cap - len - 1, 0)) > 0) {
142
- len += n;
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
- buf[len] = 0;
149
- close(sock);
150
-
151
- int code = 0;
152
- if (len >= 12 && strncmp(buf, "HTTP/", 5) == 0) {
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
- char *body_start = strstr(buf, "\r\n\r\n");
159
- if (body_start) {
160
- char *result = strdup(body_start + 4);
161
- long rlen = (long)len - (long)(body_start + 4 - buf);
162
- free(buf);
163
- return (nomen_string){ result, rlen };
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
- // if (colon && (!slash || colon < slash)) -> port branch
216
- ldr x0, [sp, #160]
217
- cbz x0, .Lhttp_np
218
- ldr x1, [sp, #168]
219
- cbz x1, .Lhttp_port
220
- cmp x0, x1
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 blocking GET request to `url`. `.ok(body)` with the response
498
- // body and `self.status` set to the response's status code, or
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 blocking POST request to `url` with `body` as the payload.
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>) {