zuzu-js 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +5 -0
- package/README.md +113 -0
- package/bin/zuzu +17 -0
- package/bin/zuzu-build-browser-bundle +57 -0
- package/bin/zuzu-generate-browser-stdlib +584 -0
- package/bin/zuzu-js +23 -0
- package/bin/zuzu-js-compile +152 -0
- package/bin/zuzu-js-electron +19 -0
- package/dist/zuzu-browser-worker.js +45574 -0
- package/dist/zuzu-browser.js +45362 -0
- package/lib/browser-bundle-entry.js +160 -0
- package/lib/browser-gui-renderer.js +387 -0
- package/lib/browser-runtime.js +167 -0
- package/lib/browser-worker-entry.js +413 -0
- package/lib/browser-ztests/runner.html +103 -0
- package/lib/browser-ztests/runner.js +369 -0
- package/lib/cli.js +350 -0
- package/lib/collections.js +367 -0
- package/lib/compiler.js +303 -0
- package/lib/electron/launcher.js +70 -0
- package/lib/electron/main.js +956 -0
- package/lib/electron/preload.js +80 -0
- package/lib/electron/renderer.html +122 -0
- package/lib/electron/renderer.js +24 -0
- package/lib/execution-metadata.js +18 -0
- package/lib/gui/dom-renderer.js +778 -0
- package/lib/host/browser-host.js +278 -0
- package/lib/host/capabilities.js +47 -0
- package/lib/host/electron-host.js +15 -0
- package/lib/host/node-host.js +74 -0
- package/lib/paths.js +150 -0
- package/lib/runtime-entrypoints.js +60 -0
- package/lib/runtime-helpers.js +886 -0
- package/lib/runtime.js +3529 -0
- package/lib/tap.js +37 -0
- package/lib/transpiler-new/ast.js +23 -0
- package/lib/transpiler-new/codegen.js +2455 -0
- package/lib/transpiler-new/errors.js +28 -0
- package/lib/transpiler-new/index.js +26 -0
- package/lib/transpiler-new/lexer.js +834 -0
- package/lib/transpiler-new/parser.js +2332 -0
- package/lib/transpiler-new/validate-bindings.js +326 -0
- package/lib/transpiler-utils.js +95 -0
- package/lib/transpiler.js +33 -0
- package/lib/zuzu.js +53 -0
- package/modules/javascript.js +193 -0
- package/modules/std/archive.js +603 -0
- package/modules/std/clib.js +338 -0
- package/modules/std/data/csv.js +1331 -0
- package/modules/std/data/json.js +531 -0
- package/modules/std/data/xml.js +441 -0
- package/modules/std/data/yaml.js +256 -0
- package/modules/std/db-worker.js +250 -0
- package/modules/std/db.js +664 -0
- package/modules/std/digest/_hash.js +443 -0
- package/modules/std/digest/md5.js +26 -0
- package/modules/std/digest/sha.js +72 -0
- package/modules/std/eval.js +10 -0
- package/modules/std/gui/objects.js +1519 -0
- package/modules/std/internals.js +571 -0
- package/modules/std/io/socks-worker.js +318 -0
- package/modules/std/io/socks.js +186 -0
- package/modules/std/io.js +475 -0
- package/modules/std/marshal/cbor.js +463 -0
- package/modules/std/marshal/graph.js +1624 -0
- package/modules/std/marshal.js +87 -0
- package/modules/std/math/bignum.js +91 -0
- package/modules/std/math.js +79 -0
- package/modules/std/net/dns.js +306 -0
- package/modules/std/net/http.js +820 -0
- package/modules/std/net/smtp.js +943 -0
- package/modules/std/net/url.js +109 -0
- package/modules/std/proc.js +602 -0
- package/modules/std/secure.js +3724 -0
- package/modules/std/string/base64.js +138 -0
- package/modules/std/string.js +299 -0
- package/modules/std/task.js +914 -0
- package/modules/std/time.js +579 -0
- package/modules/std/tui.js +188 -0
- package/modules/std/worker-thread.js +246 -0
- package/modules/std/worker.js +790 -0
- package/package.json +67 -0
- package/stdlib/modules/javascript.zzm +99 -0
- package/stdlib/modules/perl.zzm +105 -0
- package/stdlib/modules/std/archive.zzm +132 -0
- package/stdlib/modules/std/cache/lru.zzm +174 -0
- package/stdlib/modules/std/clib.zzm +112 -0
- package/stdlib/modules/std/colour.zzm +220 -0
- package/stdlib/modules/std/config.zzm +818 -0
- package/stdlib/modules/std/data/cbor.zzm +497 -0
- package/stdlib/modules/std/data/csv.zzm +285 -0
- package/stdlib/modules/std/data/ini.zzm +472 -0
- package/stdlib/modules/std/data/json/schema/core.zzm +573 -0
- package/stdlib/modules/std/data/json/schema/format.zzm +581 -0
- package/stdlib/modules/std/data/json/schema/model.zzm +255 -0
- package/stdlib/modules/std/data/json/schema/output.zzm +272 -0
- package/stdlib/modules/std/data/json/schema/relative_pointer.zzm +299 -0
- package/stdlib/modules/std/data/json/schema/validation.zzm +1503 -0
- package/stdlib/modules/std/data/json/schema.zzm +306 -0
- package/stdlib/modules/std/data/json.zzm +102 -0
- package/stdlib/modules/std/data/kdl/json.zzm +460 -0
- package/stdlib/modules/std/data/kdl/xml.zzm +387 -0
- package/stdlib/modules/std/data/kdl.zzm +1631 -0
- package/stdlib/modules/std/data/toml.zzm +756 -0
- package/stdlib/modules/std/data/toon.zzm +1017 -0
- package/stdlib/modules/std/data/xml/escape.zzm +156 -0
- package/stdlib/modules/std/data/xml.zzm +276 -0
- package/stdlib/modules/std/data/yaml.zzm +94 -0
- package/stdlib/modules/std/db.zzm +173 -0
- package/stdlib/modules/std/defer.zzm +75 -0
- package/stdlib/modules/std/digest/crc32.zzm +196 -0
- package/stdlib/modules/std/digest/md5.zzm +54 -0
- package/stdlib/modules/std/digest/sha.zzm +83 -0
- package/stdlib/modules/std/dump.zzm +317 -0
- package/stdlib/modules/std/eval.zzm +63 -0
- package/stdlib/modules/std/getopt.zzm +432 -0
- package/stdlib/modules/std/gui/dialogue.zzm +592 -0
- package/stdlib/modules/std/gui/objects.zzm +123 -0
- package/stdlib/modules/std/gui.zzm +1914 -0
- package/stdlib/modules/std/internals.zzm +139 -0
- package/stdlib/modules/std/io/socks.zzm +139 -0
- package/stdlib/modules/std/io.zzm +157 -0
- package/stdlib/modules/std/lingua/en.zzm +347 -0
- package/stdlib/modules/std/log.zzm +169 -0
- package/stdlib/modules/std/mail.zzm +2726 -0
- package/stdlib/modules/std/marshal.zzm +138 -0
- package/stdlib/modules/std/math/bignum.zzm +98 -0
- package/stdlib/modules/std/math/range.zzm +116 -0
- package/stdlib/modules/std/math/roman.zzm +156 -0
- package/stdlib/modules/std/math.zzm +141 -0
- package/stdlib/modules/std/net/dns.zzm +93 -0
- package/stdlib/modules/std/net/http.zzm +278 -0
- package/stdlib/modules/std/net/smtp.zzm +257 -0
- package/stdlib/modules/std/net/url.zzm +69 -0
- package/stdlib/modules/std/path/jsonpointer.zzm +526 -0
- package/stdlib/modules/std/path/kdl.zzm +1003 -0
- package/stdlib/modules/std/path/simple.zzm +520 -0
- package/stdlib/modules/std/path/z/context.zzm +147 -0
- package/stdlib/modules/std/path/z/evaluate.zzm +549 -0
- package/stdlib/modules/std/path/z/functions.zzm +874 -0
- package/stdlib/modules/std/path/z/lexer.zzm +490 -0
- package/stdlib/modules/std/path/z/node.zzm +1455 -0
- package/stdlib/modules/std/path/z/operators.zzm +445 -0
- package/stdlib/modules/std/path/z/parser.zzm +359 -0
- package/stdlib/modules/std/path/z.zzm +403 -0
- package/stdlib/modules/std/path/zz/functions.zzm +828 -0
- package/stdlib/modules/std/path/zz/operators.zzm +1036 -0
- package/stdlib/modules/std/path/zz.zzm +100 -0
- package/stdlib/modules/std/proc.zzm +155 -0
- package/stdlib/modules/std/result.zzm +149 -0
- package/stdlib/modules/std/secure.zzm +606 -0
- package/stdlib/modules/std/string/base64.zzm +66 -0
- package/stdlib/modules/std/string/quoted_printable.zzm +485 -0
- package/stdlib/modules/std/string.zzm +179 -0
- package/stdlib/modules/std/task.zzm +221 -0
- package/stdlib/modules/std/template/z.zzm +531 -0
- package/stdlib/modules/std/template/zz.zzm +62 -0
- package/stdlib/modules/std/time.zzm +188 -0
- package/stdlib/modules/std/tui.zzm +89 -0
- package/stdlib/modules/std/uuid.zzm +223 -0
- package/stdlib/modules/std/web/session.zzm +388 -0
- package/stdlib/modules/std/web/static.zzm +329 -0
- package/stdlib/modules/std/web.zzm +1942 -0
- package/stdlib/modules/std/worker.zzm +202 -0
- package/stdlib/modules/std/zuzuzoo.zzm +3960 -0
- package/stdlib/modules/test/more.zzm +528 -0
- package/stdlib/modules/test/parser.zzm +209 -0
|
@@ -0,0 +1,820 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
let nodeSpawnSync;
|
|
4
|
+
let nodeSpawnLoaded = false;
|
|
5
|
+
let nodeFs;
|
|
6
|
+
let nodeHttps;
|
|
7
|
+
let nodeOs;
|
|
8
|
+
let nodePath;
|
|
9
|
+
let hostName = null;
|
|
10
|
+
const { Task, traceBlockingOperation } = require( '../task' );
|
|
11
|
+
|
|
12
|
+
function _nodeSpawnSync() {
|
|
13
|
+
if ( nodeSpawnLoaded ) {
|
|
14
|
+
return nodeSpawnSync;
|
|
15
|
+
}
|
|
16
|
+
nodeSpawnLoaded = true;
|
|
17
|
+
if ( typeof require !== 'function' ) {
|
|
18
|
+
nodeSpawnSync = null;
|
|
19
|
+
return nodeSpawnSync;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
nodeSpawnSync = require( 'node:child_process' ).spawnSync;
|
|
23
|
+
}
|
|
24
|
+
catch ( _err ) {
|
|
25
|
+
nodeSpawnSync = null;
|
|
26
|
+
}
|
|
27
|
+
return nodeSpawnSync;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function _nodeModule( name ) {
|
|
31
|
+
if ( typeof require !== 'function' ) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
return require( name );
|
|
36
|
+
}
|
|
37
|
+
catch ( _err ) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function _nodeFs() {
|
|
43
|
+
nodeFs = nodeFs || _nodeModule( 'node:fs' );
|
|
44
|
+
return nodeFs;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function _nodeHttps() {
|
|
48
|
+
nodeHttps = nodeHttps || _nodeModule( 'node:https' );
|
|
49
|
+
return nodeHttps;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function _nodeOs() {
|
|
53
|
+
nodeOs = nodeOs || _nodeModule( 'node:os' );
|
|
54
|
+
return nodeOs;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function _nodePath() {
|
|
58
|
+
nodePath = nodePath || _nodeModule( 'node:path' );
|
|
59
|
+
return nodePath;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function _toDict( value ) {
|
|
63
|
+
if ( value == null ) {
|
|
64
|
+
return {};
|
|
65
|
+
}
|
|
66
|
+
if ( value && Array.isArray( value.list ) ) {
|
|
67
|
+
const out = {};
|
|
68
|
+
for ( const pair of value.list ) {
|
|
69
|
+
if ( Array.isArray( pair ) && pair.length >= 2 ) {
|
|
70
|
+
out[String( pair[0] )] = pair[1];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
if ( typeof value !== 'object' || Array.isArray( value ) ) {
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
return { ...value };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function _decorateDict( value ) {
|
|
82
|
+
if ( value == null || typeof value !== 'object' || Array.isArray( value ) ) {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
if ( !Object.prototype.hasOwnProperty.call( value, 'get' ) ) {
|
|
86
|
+
Object.defineProperty( value, 'get', {
|
|
87
|
+
value( key, fallback = null ) {
|
|
88
|
+
return Object.prototype.hasOwnProperty.call( this, String( key ) )
|
|
89
|
+
? this[String( key )]
|
|
90
|
+
: fallback;
|
|
91
|
+
},
|
|
92
|
+
enumerable: false,
|
|
93
|
+
configurable: true,
|
|
94
|
+
writable: true,
|
|
95
|
+
} );
|
|
96
|
+
}
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function _syncUnsupportedResponse( spec ) {
|
|
101
|
+
return new Response( {
|
|
102
|
+
status: 599,
|
|
103
|
+
reason: 'Synchronous HTTP is unsupported on JS/Browser',
|
|
104
|
+
url: _urlWithQuery( spec.url, spec.query ),
|
|
105
|
+
content: '',
|
|
106
|
+
headers: {},
|
|
107
|
+
success: false,
|
|
108
|
+
} );
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function _urlWithQuery( url, query ) {
|
|
112
|
+
const queryMap = _toDict( query );
|
|
113
|
+
const keys = Object.keys( queryMap );
|
|
114
|
+
if ( keys.length === 0 ) {
|
|
115
|
+
return String( url );
|
|
116
|
+
}
|
|
117
|
+
const usp = new URLSearchParams();
|
|
118
|
+
for ( const key of keys.sort() ) {
|
|
119
|
+
usp.set( key, queryMap[key] == null ? '' : String( queryMap[key] ) );
|
|
120
|
+
}
|
|
121
|
+
const base = String( url );
|
|
122
|
+
return `${base}${base.includes( '?' ) ? '&' : '?'}${usp.toString()}`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function _maxRedirect( spec, uaConfig ) {
|
|
126
|
+
const value = spec.max_redirect ?? uaConfig.max_redirect ?? 10;
|
|
127
|
+
const number = Number( value );
|
|
128
|
+
return Number.isFinite( number ) && number >= 0 ? Math.floor( number ) : 10;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function _writeDownload( spec, content ) {
|
|
132
|
+
if ( spec.download_to === undefined ) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const fs = _nodeFs();
|
|
136
|
+
if ( !fs ) {
|
|
137
|
+
throw new Error( 'Exception: download_to filesystem support is unavailable' );
|
|
138
|
+
}
|
|
139
|
+
fs.writeFileSync( String( spec.download_to ), content, 'utf8' );
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
class CookieJar {
|
|
143
|
+
constructor() {
|
|
144
|
+
this._cookies = new Map();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
add( url, setCookie ) {
|
|
148
|
+
this._cookies.set( String( url ?? '' ), String( setCookie ?? '' ) );
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
cookie_header( url ) {
|
|
153
|
+
return this._cookies.get( String( url ?? '' ) ) ?? null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
clear() {
|
|
157
|
+
this._cookies.clear();
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
class Response {
|
|
163
|
+
constructor( payload ) {
|
|
164
|
+
this._payload = payload;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
status() { return this._payload.status; }
|
|
168
|
+
reason() { return this._payload.reason; }
|
|
169
|
+
url() { return this._payload.url; }
|
|
170
|
+
content() { return this._payload.content; }
|
|
171
|
+
headers() { return { ...this._payload.headers }; }
|
|
172
|
+
header( name ) {
|
|
173
|
+
return this._payload.headers[String( name ).toLowerCase()] ?? null;
|
|
174
|
+
}
|
|
175
|
+
success() { return this._payload.success ? 1 : 0; }
|
|
176
|
+
json() { return JSON.parse( this._payload.content || '' ); }
|
|
177
|
+
expect_success() {
|
|
178
|
+
if ( this.success() ) {
|
|
179
|
+
return this;
|
|
180
|
+
}
|
|
181
|
+
throw new Error( `HTTP request failed with status ${this.status()}` );
|
|
182
|
+
}
|
|
183
|
+
to_Dict() {
|
|
184
|
+
return _decorateDict( {
|
|
185
|
+
status: this.status(),
|
|
186
|
+
reason: this.reason(),
|
|
187
|
+
url: this.url(),
|
|
188
|
+
content: this.content(),
|
|
189
|
+
headers: _decorateDict( this.headers() ),
|
|
190
|
+
success: this.success(),
|
|
191
|
+
} );
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
class Request {
|
|
196
|
+
constructor( method, url ) {
|
|
197
|
+
this._spec = {
|
|
198
|
+
method: String( method || 'GET' ).toUpperCase(),
|
|
199
|
+
url: String( url || '' ),
|
|
200
|
+
headers: {},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
method( value ) { this._spec.method = String( value ).toUpperCase(); return this; }
|
|
205
|
+
url( value ) { this._spec.url = String( value ); return this; }
|
|
206
|
+
header( name, value ) { this._spec.headers[String( name ).toLowerCase()] = String( value ); return this; }
|
|
207
|
+
headers( value ) {
|
|
208
|
+
for ( const [ key, item ] of Object.entries( _toDict( value ) ) ) {
|
|
209
|
+
this.header( key, item );
|
|
210
|
+
}
|
|
211
|
+
return this;
|
|
212
|
+
}
|
|
213
|
+
query( value ) { this._spec.query = _toDict( value ); return this; }
|
|
214
|
+
body( value ) { this._spec.body = value == null ? '' : String( value ); return this; }
|
|
215
|
+
json( value ) {
|
|
216
|
+
this._spec.json = value;
|
|
217
|
+
this._spec.headers['content-type'] = this._spec.headers['content-type'] || 'application/json';
|
|
218
|
+
return this;
|
|
219
|
+
}
|
|
220
|
+
auth_bearer( token ) { return this.header( 'authorization', `Bearer ${token}` ); }
|
|
221
|
+
timeout( value ) { this._spec.timeout = Number( value ); return this; }
|
|
222
|
+
retries( value ) { this._spec.retries = Number( value ); return this; }
|
|
223
|
+
max_redirect( value ) { this._spec.max_redirect = Number( value ); return this; }
|
|
224
|
+
download_to( value ) { this._spec.download_to = String( value ); return this; }
|
|
225
|
+
upload_from( value ) { this._spec.upload_from = String( value ); return this; }
|
|
226
|
+
tls_identity( value ) { this._spec.tls_identity = value ?? null; return this; }
|
|
227
|
+
multipart( value ) { this._spec.multipart = _toDict( value ); return this; }
|
|
228
|
+
send( ua ) {
|
|
229
|
+
if ( !( ua instanceof UserAgent ) ) {
|
|
230
|
+
throw new Error( 'Request.send expects a UserAgent' );
|
|
231
|
+
}
|
|
232
|
+
return ua.send( this );
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
send_async( ua ) {
|
|
236
|
+
if ( !( ua instanceof UserAgent ) ) {
|
|
237
|
+
throw new Error( 'Request.send_async expects a UserAgent' );
|
|
238
|
+
}
|
|
239
|
+
return ua.send_async( this );
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function _derToPem( label, der ) {
|
|
244
|
+
const bytes = der instanceof Uint8Array
|
|
245
|
+
? der
|
|
246
|
+
: der && der.bytes instanceof Uint8Array
|
|
247
|
+
? der.bytes
|
|
248
|
+
: Uint8Array.from( der || [] );
|
|
249
|
+
const base64 = Buffer.from( bytes ).toString( 'base64' );
|
|
250
|
+
const lines = base64.match( /.{1,64}/gu ) || [];
|
|
251
|
+
return `-----BEGIN ${label}-----\n${lines.join( '\n' )}\n-----END ${label}-----\n`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function _certificatePem( value, label ) {
|
|
255
|
+
if ( value == null ) {
|
|
256
|
+
return '';
|
|
257
|
+
}
|
|
258
|
+
if ( typeof value === 'string' ) {
|
|
259
|
+
if ( !value.includes( '-----BEGIN CERTIFICATE-----' ) ) {
|
|
260
|
+
throw new Error( `${label} expects PEM certificate text` );
|
|
261
|
+
}
|
|
262
|
+
return value;
|
|
263
|
+
}
|
|
264
|
+
if ( value && value.__secureCertificate ) {
|
|
265
|
+
return _derToPem( 'CERTIFICATE', value.__secureCertificate.der );
|
|
266
|
+
}
|
|
267
|
+
throw new Error( `TypeException: ${label} expects Certificate, String PEM, or Array` );
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function _caPem( value, label ) {
|
|
271
|
+
if ( value == null ) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
if ( Array.isArray( value ) ) {
|
|
275
|
+
return value.map( ( item ) => _certificatePem( item, label ) ).join( '' );
|
|
276
|
+
}
|
|
277
|
+
return _certificatePem( value, label );
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function _tlsPolicy( spec, uaConfig ) {
|
|
281
|
+
const config = _toDict( uaConfig );
|
|
282
|
+
const policy = {
|
|
283
|
+
tls_identity: Object.prototype.hasOwnProperty.call( spec, 'tls_identity' )
|
|
284
|
+
? spec.tls_identity
|
|
285
|
+
: config.tls_identity ?? null,
|
|
286
|
+
tls_ca: config.tls_ca ?? null,
|
|
287
|
+
tls_verify: Object.prototype.hasOwnProperty.call( config, 'tls_verify' )
|
|
288
|
+
? Boolean( config.tls_verify )
|
|
289
|
+
: true,
|
|
290
|
+
tls_server_name: config.tls_server_name ?? null,
|
|
291
|
+
tls_min_version: config.tls_min_version ?? null,
|
|
292
|
+
tls_ciphers: config.tls_ciphers ?? null,
|
|
293
|
+
};
|
|
294
|
+
policy.active = Boolean(
|
|
295
|
+
policy.tls_identity
|
|
296
|
+
|| policy.tls_ca
|
|
297
|
+
|| policy.tls_verify === false
|
|
298
|
+
|| policy.tls_server_name
|
|
299
|
+
|| policy.tls_min_version
|
|
300
|
+
|| policy.tls_ciphers
|
|
301
|
+
);
|
|
302
|
+
return policy;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function _assertBrowserTlsSupported( policy ) {
|
|
306
|
+
if ( hostName === 'browser' && policy.active ) {
|
|
307
|
+
throw new Error(
|
|
308
|
+
'std/net/http TLS client configuration is not supported on JS/Browser'
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function _identityState( identity, label ) {
|
|
314
|
+
if ( !identity || !identity.__secureTlsIdentity ) {
|
|
315
|
+
throw new Error( `TypeException: ${label} expects TlsIdentity` );
|
|
316
|
+
}
|
|
317
|
+
return identity.__secureTlsIdentity;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function _tlsMinVersion( value ) {
|
|
321
|
+
if ( value == null ) {
|
|
322
|
+
return undefined;
|
|
323
|
+
}
|
|
324
|
+
const text = String( value ).toLowerCase();
|
|
325
|
+
if ( text === 'tls1.2' ) {
|
|
326
|
+
return 'TLSv1.2';
|
|
327
|
+
}
|
|
328
|
+
if ( text === 'tls1.3' ) {
|
|
329
|
+
return 'TLSv1.3';
|
|
330
|
+
}
|
|
331
|
+
throw new Error( "std/net/http tls_min_version must be 'tls1.2' or 'tls1.3'" );
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function _writeTempFile( content, files ) {
|
|
335
|
+
const fs = _nodeFs();
|
|
336
|
+
const os = _nodeOs();
|
|
337
|
+
const path = _nodePath();
|
|
338
|
+
if ( !fs || !os || !path ) {
|
|
339
|
+
throw new Error( 'Exception: temporary TLS file support is unavailable' );
|
|
340
|
+
}
|
|
341
|
+
const dir = fs.mkdtempSync( path.join( os.tmpdir(), 'zuzu-http-tls-' ) );
|
|
342
|
+
const file = path.join( dir, 'material.pem' );
|
|
343
|
+
fs.writeFileSync( file, content );
|
|
344
|
+
files.push( file, dir );
|
|
345
|
+
return file;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function _cleanupTempFiles( files ) {
|
|
349
|
+
const fs = _nodeFs();
|
|
350
|
+
if ( !fs ) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
for ( const file of files ) {
|
|
354
|
+
try {
|
|
355
|
+
if ( fs.statSync( file ).isDirectory() ) {
|
|
356
|
+
fs.rmdirSync( file );
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
fs.unlinkSync( file );
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
catch ( _err ) {}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function _curlRequest( spec, uaConfig ) {
|
|
367
|
+
const spawnSync = _nodeSpawnSync();
|
|
368
|
+
if ( !spawnSync ) {
|
|
369
|
+
throw new Error( 'Exception: curl transport is unavailable' );
|
|
370
|
+
}
|
|
371
|
+
const policy = _tlsPolicy( spec, uaConfig );
|
|
372
|
+
if ( policy.tls_server_name ) {
|
|
373
|
+
throw new Error(
|
|
374
|
+
'std/net/http tls_server_name is not supported by the synchronous JS/Node HTTP backend'
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
const method = String( spec.method || 'GET' ).toUpperCase();
|
|
378
|
+
const target = _urlWithQuery( spec.url, spec.query );
|
|
379
|
+
const args = [
|
|
380
|
+
'-sS',
|
|
381
|
+
'-i',
|
|
382
|
+
'-L',
|
|
383
|
+
'--max-redirs',
|
|
384
|
+
String( _maxRedirect( spec, uaConfig ) ),
|
|
385
|
+
'-w',
|
|
386
|
+
'\n\n__ZUZU_EFFECTIVE_URL:%{url_effective}',
|
|
387
|
+
'-X',
|
|
388
|
+
method,
|
|
389
|
+
target,
|
|
390
|
+
];
|
|
391
|
+
const tempFiles = [];
|
|
392
|
+
const headers = { ..._toDict( uaConfig.default_headers ), ..._toDict( spec.headers ) };
|
|
393
|
+
if ( uaConfig.agent ) {
|
|
394
|
+
headers['user-agent'] = String( uaConfig.agent );
|
|
395
|
+
}
|
|
396
|
+
if ( uaConfig.cookie_jar && typeof uaConfig.cookie_jar.cookie_header === 'function' ) {
|
|
397
|
+
const cookie = uaConfig.cookie_jar.cookie_header( target );
|
|
398
|
+
if ( cookie ) {
|
|
399
|
+
headers.cookie = cookie;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
for ( const [ name, value ] of Object.entries( headers ) ) {
|
|
403
|
+
args.push( '-H', `${name}: ${String( value )}` );
|
|
404
|
+
}
|
|
405
|
+
if ( spec.json !== undefined ) {
|
|
406
|
+
args.push( '--data', JSON.stringify( spec.json ) );
|
|
407
|
+
}
|
|
408
|
+
else if ( spec.upload_from !== undefined ) {
|
|
409
|
+
args.push( '--data-binary', `@${String( spec.upload_from )}` );
|
|
410
|
+
}
|
|
411
|
+
else if ( spec.body !== undefined ) {
|
|
412
|
+
args.push( '--data', String( spec.body ) );
|
|
413
|
+
}
|
|
414
|
+
if ( policy.tls_identity ) {
|
|
415
|
+
const identity = _identityState(
|
|
416
|
+
policy.tls_identity,
|
|
417
|
+
'std/net/http tls_identity'
|
|
418
|
+
);
|
|
419
|
+
args.push( '--cert', _writeTempFile(
|
|
420
|
+
identity.certPem,
|
|
421
|
+
tempFiles,
|
|
422
|
+
) );
|
|
423
|
+
args.push( '--key', _writeTempFile( identity.keyPem, tempFiles ) );
|
|
424
|
+
}
|
|
425
|
+
if ( policy.tls_ca ) {
|
|
426
|
+
args.push( '--cacert', _writeTempFile(
|
|
427
|
+
_caPem( policy.tls_ca, 'std/net/http tls_ca' ),
|
|
428
|
+
tempFiles,
|
|
429
|
+
) );
|
|
430
|
+
}
|
|
431
|
+
if ( policy.tls_verify === false ) {
|
|
432
|
+
args.push( '--insecure' );
|
|
433
|
+
}
|
|
434
|
+
if ( policy.tls_min_version ) {
|
|
435
|
+
args.push(
|
|
436
|
+
String( policy.tls_min_version ).toLowerCase() === 'tls1.3'
|
|
437
|
+
? '--tlsv1.3'
|
|
438
|
+
: '--tlsv1.2'
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
if ( policy.tls_ciphers ) {
|
|
442
|
+
args.push( '--ciphers', String( policy.tls_ciphers ) );
|
|
443
|
+
}
|
|
444
|
+
let spawned;
|
|
445
|
+
try {
|
|
446
|
+
spawned = spawnSync( 'curl', args, { encoding: 'utf8' } );
|
|
447
|
+
}
|
|
448
|
+
finally {
|
|
449
|
+
_cleanupTempFiles( tempFiles );
|
|
450
|
+
}
|
|
451
|
+
if ( spawned.error ) {
|
|
452
|
+
throw spawned.error;
|
|
453
|
+
}
|
|
454
|
+
let raw = String( spawned.stdout || '' );
|
|
455
|
+
let effectiveUrl = target;
|
|
456
|
+
const effectiveMatch = raw.match( /\n\n__ZUZU_EFFECTIVE_URL:([^\n\r]*)\s*$/u );
|
|
457
|
+
if ( effectiveMatch ) {
|
|
458
|
+
effectiveUrl = effectiveMatch[1] || target;
|
|
459
|
+
raw = raw.slice( 0, effectiveMatch.index );
|
|
460
|
+
}
|
|
461
|
+
const split = raw.split( /\r?\n\r?\n/u );
|
|
462
|
+
let headerIndex = 0;
|
|
463
|
+
for ( let i = 0; i < split.length; i++ ) {
|
|
464
|
+
if ( /^HTTP\/\d(?:\.\d)?\s+\d+/u.test( split[i] || '' ) ) {
|
|
465
|
+
headerIndex = i;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
const headerText = split[headerIndex] || '';
|
|
469
|
+
const body = split.slice( headerIndex + 1 ).join( '\n\n' );
|
|
470
|
+
const headerLines = headerText.split( /\r?\n/u );
|
|
471
|
+
const statusLine = headerLines.shift() || 'HTTP/1.1 599 Request Failed';
|
|
472
|
+
const statusMatch = statusLine.match( /^HTTP\/\d(?:\.\d)?\s+(\d+)(?:\s+(.*))?$/u );
|
|
473
|
+
const status = statusMatch ? Number( statusMatch[1] ) : 599;
|
|
474
|
+
const reason = statusMatch ? ( statusMatch[2] || '' ) : 'Request Failed';
|
|
475
|
+
const outHeaders = {};
|
|
476
|
+
for ( const line of headerLines ) {
|
|
477
|
+
const idx = line.indexOf( ':' );
|
|
478
|
+
if ( idx < 0 ) {
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
outHeaders[line.slice( 0, idx ).trim().toLowerCase()] = line.slice( idx + 1 ).trim();
|
|
482
|
+
}
|
|
483
|
+
if ( outHeaders['set-cookie'] && uaConfig.cookie_jar && typeof uaConfig.cookie_jar.add === 'function' ) {
|
|
484
|
+
uaConfig.cookie_jar.add( effectiveUrl, outHeaders['set-cookie'] );
|
|
485
|
+
}
|
|
486
|
+
_writeDownload( spec, body );
|
|
487
|
+
return new Response( {
|
|
488
|
+
status,
|
|
489
|
+
reason,
|
|
490
|
+
url: effectiveUrl,
|
|
491
|
+
content: body,
|
|
492
|
+
headers: outHeaders,
|
|
493
|
+
success: status >= 200 && status < 300,
|
|
494
|
+
} );
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function _nodeHttpsRequest( spec, uaConfig, signal = null ) {
|
|
498
|
+
const https = _nodeHttps();
|
|
499
|
+
if ( !https ) {
|
|
500
|
+
throw new Error( 'Exception: https transport is unavailable' );
|
|
501
|
+
}
|
|
502
|
+
const policy = _tlsPolicy( spec, uaConfig );
|
|
503
|
+
const method = String( spec.method || 'GET' ).toUpperCase();
|
|
504
|
+
const target = _urlWithQuery( spec.url, spec.query );
|
|
505
|
+
const url = new URL( target );
|
|
506
|
+
if ( url.protocol !== 'https:' ) {
|
|
507
|
+
throw new Error( 'std/net/http TLS configuration requires an https URL' );
|
|
508
|
+
}
|
|
509
|
+
const headers = { ..._toDict( uaConfig.default_headers ), ..._toDict( spec.headers ) };
|
|
510
|
+
if ( uaConfig.agent ) {
|
|
511
|
+
headers['user-agent'] = String( uaConfig.agent );
|
|
512
|
+
}
|
|
513
|
+
if ( uaConfig.cookie_jar && typeof uaConfig.cookie_jar.cookie_header === 'function' ) {
|
|
514
|
+
const cookie = uaConfig.cookie_jar.cookie_header( target );
|
|
515
|
+
if ( cookie ) {
|
|
516
|
+
headers.cookie = cookie;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
const body = spec.json !== undefined
|
|
520
|
+
? JSON.stringify( spec.json )
|
|
521
|
+
: spec.body !== undefined
|
|
522
|
+
? String( spec.body )
|
|
523
|
+
: null;
|
|
524
|
+
if ( spec.json !== undefined ) {
|
|
525
|
+
headers['content-type'] = headers['content-type'] || 'application/json';
|
|
526
|
+
}
|
|
527
|
+
const options = {
|
|
528
|
+
method,
|
|
529
|
+
headers,
|
|
530
|
+
rejectUnauthorized: policy.tls_verify !== false,
|
|
531
|
+
};
|
|
532
|
+
if ( policy.tls_identity ) {
|
|
533
|
+
const identity = _identityState(
|
|
534
|
+
policy.tls_identity,
|
|
535
|
+
'std/net/http tls_identity'
|
|
536
|
+
);
|
|
537
|
+
options.cert = identity.chainPem || identity.certPem;
|
|
538
|
+
options.key = identity.keyPem;
|
|
539
|
+
if ( identity.password ) {
|
|
540
|
+
options.passphrase = identity.password;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
if ( policy.tls_ca ) {
|
|
544
|
+
options.ca = _caPem( policy.tls_ca, 'std/net/http tls_ca' );
|
|
545
|
+
}
|
|
546
|
+
if ( policy.tls_server_name ) {
|
|
547
|
+
options.servername = String( policy.tls_server_name );
|
|
548
|
+
}
|
|
549
|
+
if ( policy.tls_min_version ) {
|
|
550
|
+
options.minVersion = _tlsMinVersion( policy.tls_min_version );
|
|
551
|
+
}
|
|
552
|
+
if ( policy.tls_ciphers ) {
|
|
553
|
+
options.ciphers = String( policy.tls_ciphers );
|
|
554
|
+
}
|
|
555
|
+
return new Promise( ( resolve, reject ) => {
|
|
556
|
+
const req = https.request( url, options, ( response ) => {
|
|
557
|
+
const chunks = [];
|
|
558
|
+
response.on( 'data', ( chunk ) => chunks.push( chunk ) );
|
|
559
|
+
response.on( 'end', () => {
|
|
560
|
+
const outHeaders = {};
|
|
561
|
+
for ( const [ name, value ] of Object.entries( response.headers ) ) {
|
|
562
|
+
outHeaders[String( name ).toLowerCase()] = Array.isArray( value )
|
|
563
|
+
? value.join( ', ' )
|
|
564
|
+
: String( value ?? '' );
|
|
565
|
+
}
|
|
566
|
+
if (
|
|
567
|
+
outHeaders['set-cookie']
|
|
568
|
+
&& uaConfig.cookie_jar
|
|
569
|
+
&& typeof uaConfig.cookie_jar.add === 'function'
|
|
570
|
+
) {
|
|
571
|
+
uaConfig.cookie_jar.add( target, outHeaders['set-cookie'] );
|
|
572
|
+
}
|
|
573
|
+
const content = Buffer.concat( chunks ).toString( 'utf8' );
|
|
574
|
+
_writeDownload( spec, content );
|
|
575
|
+
resolve( new Response( {
|
|
576
|
+
status: response.statusCode || 599,
|
|
577
|
+
reason: response.statusMessage || '',
|
|
578
|
+
url: target,
|
|
579
|
+
content,
|
|
580
|
+
headers: outHeaders,
|
|
581
|
+
success: ( response.statusCode || 0 ) >= 200
|
|
582
|
+
&& ( response.statusCode || 0 ) < 300,
|
|
583
|
+
} ) );
|
|
584
|
+
} );
|
|
585
|
+
} );
|
|
586
|
+
req.on( 'error', reject );
|
|
587
|
+
if ( signal ) {
|
|
588
|
+
signal.addEventListener( 'abort', () => req.destroy(
|
|
589
|
+
new Error( 'HTTP request cancelled' )
|
|
590
|
+
) );
|
|
591
|
+
}
|
|
592
|
+
if ( body != null ) {
|
|
593
|
+
req.write( body );
|
|
594
|
+
}
|
|
595
|
+
req.end();
|
|
596
|
+
} );
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
async function _fetchRequest( spec, uaConfig, signal = null ) {
|
|
600
|
+
if ( typeof fetch !== 'function' ) {
|
|
601
|
+
throw new Error( 'Exception: fetch transport is unavailable' );
|
|
602
|
+
}
|
|
603
|
+
const method = String( spec.method || 'GET' ).toUpperCase();
|
|
604
|
+
const target = _urlWithQuery( spec.url, spec.query );
|
|
605
|
+
const headers = { ..._toDict( uaConfig.default_headers ), ..._toDict( spec.headers ) };
|
|
606
|
+
if ( uaConfig.agent ) {
|
|
607
|
+
headers['user-agent'] = String( uaConfig.agent );
|
|
608
|
+
}
|
|
609
|
+
if ( uaConfig.cookie_jar && typeof uaConfig.cookie_jar.cookie_header === 'function' ) {
|
|
610
|
+
const cookie = uaConfig.cookie_jar.cookie_header( target );
|
|
611
|
+
if ( cookie ) {
|
|
612
|
+
headers.cookie = cookie;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
const fetchOptions = {
|
|
616
|
+
method,
|
|
617
|
+
headers,
|
|
618
|
+
};
|
|
619
|
+
if ( signal ) {
|
|
620
|
+
fetchOptions.signal = signal;
|
|
621
|
+
}
|
|
622
|
+
if ( spec.json !== undefined ) {
|
|
623
|
+
headers['content-type'] = headers['content-type'] || 'application/json';
|
|
624
|
+
fetchOptions.body = JSON.stringify( spec.json );
|
|
625
|
+
}
|
|
626
|
+
else if ( spec.body !== undefined ) {
|
|
627
|
+
fetchOptions.body = String( spec.body );
|
|
628
|
+
}
|
|
629
|
+
const response = await fetch( target, {
|
|
630
|
+
...fetchOptions,
|
|
631
|
+
redirect: _maxRedirect( spec, uaConfig ) === 0 ? 'manual' : 'follow',
|
|
632
|
+
} );
|
|
633
|
+
const outHeaders = {};
|
|
634
|
+
if ( response.headers && typeof response.headers.forEach === 'function' ) {
|
|
635
|
+
response.headers.forEach( ( value, key ) => {
|
|
636
|
+
outHeaders[String( key ).toLowerCase()] = String( value );
|
|
637
|
+
} );
|
|
638
|
+
}
|
|
639
|
+
if ( outHeaders['set-cookie'] && uaConfig.cookie_jar && typeof uaConfig.cookie_jar.add === 'function' ) {
|
|
640
|
+
uaConfig.cookie_jar.add( target, outHeaders['set-cookie'] );
|
|
641
|
+
}
|
|
642
|
+
const content = await response.text();
|
|
643
|
+
_writeDownload( spec, content );
|
|
644
|
+
return new Response( {
|
|
645
|
+
status: response.status,
|
|
646
|
+
reason: response.statusText || '',
|
|
647
|
+
url: response.url || target,
|
|
648
|
+
content,
|
|
649
|
+
headers: outHeaders,
|
|
650
|
+
success: response.ok,
|
|
651
|
+
} );
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
async function _asyncRequest( spec, uaConfig, signal = null ) {
|
|
655
|
+
try {
|
|
656
|
+
const policy = _tlsPolicy( spec, uaConfig );
|
|
657
|
+
_assertBrowserTlsSupported( policy );
|
|
658
|
+
if ( hostName !== 'browser' && policy.active ) {
|
|
659
|
+
return await _nodeHttpsRequest( spec, uaConfig, signal );
|
|
660
|
+
}
|
|
661
|
+
if ( typeof fetch === 'function' ) {
|
|
662
|
+
return await _fetchRequest( spec, uaConfig, signal );
|
|
663
|
+
}
|
|
664
|
+
if (
|
|
665
|
+
hostName !== 'browser'
|
|
666
|
+
&& String( _urlWithQuery( spec.url, spec.query ) ).startsWith( 'https:' )
|
|
667
|
+
&& _nodeHttps()
|
|
668
|
+
) {
|
|
669
|
+
return await _nodeHttpsRequest( spec, uaConfig, signal );
|
|
670
|
+
}
|
|
671
|
+
return _curlRequest( spec, uaConfig );
|
|
672
|
+
}
|
|
673
|
+
catch ( err ) {
|
|
674
|
+
return new Response( {
|
|
675
|
+
status: 599,
|
|
676
|
+
reason: err && err.message ? err.message : String( err || 'Request Failed' ),
|
|
677
|
+
url: _urlWithQuery( spec.url, spec.query ),
|
|
678
|
+
content: '',
|
|
679
|
+
headers: {},
|
|
680
|
+
success: false,
|
|
681
|
+
} );
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
class UserAgent {
|
|
686
|
+
constructor( options = {}, named = {} ) {
|
|
687
|
+
this._config = { ..._toDict( options ), ..._toDict( named ) };
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
build_request( method, url ) {
|
|
691
|
+
return new Request( method, url );
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
send( request ) {
|
|
695
|
+
if ( !( request instanceof Request ) ) {
|
|
696
|
+
throw new Error( 'UserAgent.send expects a Request' );
|
|
697
|
+
}
|
|
698
|
+
traceBlockingOperation( 'std/net/http UserAgent.send' );
|
|
699
|
+
const policy = _tlsPolicy( request._spec, this._config );
|
|
700
|
+
_assertBrowserTlsSupported( policy );
|
|
701
|
+
if ( hostName === 'browser' ) {
|
|
702
|
+
return _syncUnsupportedResponse( request._spec );
|
|
703
|
+
}
|
|
704
|
+
if ( !_nodeSpawnSync() && typeof fetch === 'function' ) {
|
|
705
|
+
return _fetchRequest( request._spec, this._config );
|
|
706
|
+
}
|
|
707
|
+
return _curlRequest( request._spec, this._config );
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
send_async( request ) {
|
|
711
|
+
if ( !( request instanceof Request ) ) {
|
|
712
|
+
throw new Error( 'UserAgent.send_async expects a Request' );
|
|
713
|
+
}
|
|
714
|
+
const timeoutSeconds = Number(
|
|
715
|
+
request._spec.timeout
|
|
716
|
+
|| this._config.timeout
|
|
717
|
+
|| 0
|
|
718
|
+
);
|
|
719
|
+
const controller = typeof AbortController === 'function'
|
|
720
|
+
? new AbortController()
|
|
721
|
+
: null;
|
|
722
|
+
let timer = null;
|
|
723
|
+
const task = new Task(
|
|
724
|
+
() => _asyncRequest(
|
|
725
|
+
request._spec,
|
|
726
|
+
this._config,
|
|
727
|
+
controller ? controller.signal : null,
|
|
728
|
+
),
|
|
729
|
+
{
|
|
730
|
+
name: 'http.request',
|
|
731
|
+
cancel() {
|
|
732
|
+
if ( timer != null ) {
|
|
733
|
+
clearTimeout( timer );
|
|
734
|
+
timer = null;
|
|
735
|
+
}
|
|
736
|
+
if ( controller ) {
|
|
737
|
+
controller.abort();
|
|
738
|
+
}
|
|
739
|
+
},
|
|
740
|
+
},
|
|
741
|
+
);
|
|
742
|
+
if ( timeoutSeconds > 0 && controller ) {
|
|
743
|
+
timer = setTimeout( () => {
|
|
744
|
+
controller.abort();
|
|
745
|
+
}, Math.floor( timeoutSeconds * 1000 ) );
|
|
746
|
+
task.finally( () => {
|
|
747
|
+
if ( timer != null ) {
|
|
748
|
+
clearTimeout( timer );
|
|
749
|
+
timer = null;
|
|
750
|
+
}
|
|
751
|
+
} );
|
|
752
|
+
}
|
|
753
|
+
return task;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
request( method, url, data, headers ) {
|
|
757
|
+
const req = this.build_request( method, url );
|
|
758
|
+
if ( method === 'POST' || method === 'PUT' || method === 'PATCH' ) {
|
|
759
|
+
if ( data !== undefined ) {
|
|
760
|
+
req.body( data );
|
|
761
|
+
}
|
|
762
|
+
if ( headers !== undefined ) {
|
|
763
|
+
req.headers( headers );
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
if ( data !== undefined ) {
|
|
768
|
+
req.headers( data );
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
return this.send( req );
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
request_async( method, url, data, headers ) {
|
|
775
|
+
const req = this.build_request( method, url );
|
|
776
|
+
if ( method === 'POST' || method === 'PUT' || method === 'PATCH' ) {
|
|
777
|
+
if ( data !== undefined ) {
|
|
778
|
+
req.body( data );
|
|
779
|
+
}
|
|
780
|
+
if ( headers !== undefined ) {
|
|
781
|
+
req.headers( headers );
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
else if ( data !== undefined ) {
|
|
785
|
+
req.headers( data );
|
|
786
|
+
}
|
|
787
|
+
return this.send_async( req );
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
get( url, headers ) { return this.request( 'GET', url, headers ); }
|
|
791
|
+
get_async( url, headers ) { return this.request_async( 'GET', url, headers ); }
|
|
792
|
+
head( url, headers ) { return this.request( 'HEAD', url, headers ); }
|
|
793
|
+
head_async( url, headers ) { return this.request_async( 'HEAD', url, headers ); }
|
|
794
|
+
delete( url, headers ) { return this.request( 'DELETE', url, headers ); }
|
|
795
|
+
delete_async( url, headers ) { return this.request_async( 'DELETE', url, headers ); }
|
|
796
|
+
options( url, headers ) { return this.request( 'OPTIONS', url, headers ); }
|
|
797
|
+
options_async( url, headers ) { return this.request_async( 'OPTIONS', url, headers ); }
|
|
798
|
+
post( url, data, headers ) { return this.request( 'POST', url, data, headers ); }
|
|
799
|
+
post_async( url, data, headers ) { return this.request_async( 'POST', url, data, headers ); }
|
|
800
|
+
put( url, data, headers ) { return this.request( 'PUT', url, data, headers ); }
|
|
801
|
+
put_async( url, data, headers ) { return this.request_async( 'PUT', url, data, headers ); }
|
|
802
|
+
patch( url, data, headers ) { return this.request( 'PATCH', url, data, headers ); }
|
|
803
|
+
patch_async( url, data, headers ) { return this.request_async( 'PATCH', url, data, headers ); }
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
const api = {
|
|
807
|
+
CookieJar,
|
|
808
|
+
Request,
|
|
809
|
+
Response,
|
|
810
|
+
UserAgent,
|
|
811
|
+
};
|
|
812
|
+
|
|
813
|
+
Object.defineProperty( api, '__zuzu_set_runtime_policy', {
|
|
814
|
+
value( policy = {} ) {
|
|
815
|
+
hostName = policy.host_name || null;
|
|
816
|
+
},
|
|
817
|
+
enumerable: false,
|
|
818
|
+
} );
|
|
819
|
+
|
|
820
|
+
module.exports = api;
|