|
8 | 8 | /**
|
9 | 9 | * Experimental fetch API shim backed by Java 11 HttpClient.
|
10 | 10 | */
|
11 |
| - |
12 |
| -(class Fetch { |
| 11 | +class Fetch { |
13 | 12 | #private;
|
14 | 13 |
|
15 | 14 | static {
|
|
26 | 25 | const ByteBuffer = Java.type('java.nio.ByteBuffer');
|
27 | 26 | const Base64 = Java.type('java.util.Base64');
|
28 | 27 | const StandardCharsets = Java.type('java.nio.charset.StandardCharsets');
|
| 28 | + const specialHttp2Headers = new Set(); |
| 29 | + specialHttp2Headers.add(':authority'); |
| 30 | + specialHttp2Headers.add(':method'); |
| 31 | + specialHttp2Headers.add(':path'); |
| 32 | + specialHttp2Headers.add(':scheme'); |
| 33 | + specialHttp2Headers.add(':status'); |
29 | 34 |
|
30 | 35 | function parseAndValidateURL(url) {
|
31 | 36 | try {
|
|
41 | 46 | throw new TypeError("Invalid URL: " + e.message);
|
42 | 47 | }
|
43 | 48 | }
|
44 |
| - |
45 | 49 | function validateHeaderName(name) {
|
46 | 50 | const validHttpToken = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/;
|
47 |
| - if (!validHttpToken.test(name)) { |
| 51 | + if (!specialHttp2Headers.has(name) && !validHttpToken.test(name)) { |
48 | 52 | throw new TypeError(`Header name must be a valid HTTP token: [${name}]`);
|
49 | 53 | }
|
50 | 54 | return name;
|
51 | 55 | }
|
52 |
| - |
53 | 56 | function validateHeaderValue(name, value) {
|
54 | 57 | const invalidFieldValueChar = /[^\t\x20-\x7e\x80-\xff]/;
|
55 | 58 | if (invalidFieldValueChar.exec(value) !== null) {
|
|
63 | 66 | function defineToStringTag(constructor) {
|
64 | 67 | Object.defineProperty(constructor.prototype, Symbol.toStringTag, {value: constructor.name, configurable: true, writable: true, enumerable: false});
|
65 | 68 | }
|
66 |
| - |
67 | 69 | // Wraps a byte[] to facilitate type checking in Blob constructor.
|
68 | 70 | class ByteArrayWrapper extends Fetch {
|
69 | 71 | constructor(byteArray) {
|
70 | 72 | super();
|
71 | 73 | this.#private = byteArray;
|
72 | 74 | }
|
73 | 75 | }
|
74 |
| - |
75 | 76 | class Blob {
|
76 | 77 | #size = 0;
|
77 | 78 | #byteArray;
|
|
148 | 149 | function asBlob(body) {
|
149 | 150 | return body instanceof Blob ? body : new Blob(body);
|
150 | 151 | }
|
151 |
| - |
152 | 152 | function fillHeaders(headers, init) {
|
153 | 153 | if (init instanceof Headers) {
|
154 | 154 | init = init.entries();
|
|
284 | 284 | return method;
|
285 | 285 | }
|
286 | 286 | }
|
287 |
| - |
288 | 287 | function makeRequest(init, uri, url, source) {
|
289 | 288 | // https://fetch.spec.whatwg.org/#requests
|
290 | 289 | let referrer = init.referrer;
|
|
722 | 721 | httpRequestBuilder.method(request.method, bodyPublisher);
|
723 | 722 | httpRequestBuilder.setHeader("Accept", "*/*");
|
724 | 723 | httpRequestBuilder.setHeader("Accept-Encoding", ""); // compression not supported
|
725 |
| - httpRequestBuilder.setHeader("User-Agent", "graaljs-fetch"); |
| 724 | + httpRequestBuilder.setHeader("User-Agent", `${navigator.userAgent}/graaljs-fetch/Node.js`); |
726 | 725 | if (requestPrivate.referrer !== 'client') {
|
727 | 726 | httpRequestBuilder.setHeader("Referer", requestPrivate.referrer); // [sic]
|
728 | 727 | }
|
|
921 | 920 | default: return "";
|
922 | 921 | };
|
923 | 922 | }
|
924 |
| - |
925 | 923 | Object.entries({"fetch": fetch, "Headers": Headers, "Request": Request, "Response": Response}).forEach((entry) => {
|
926 | 924 | const [name, fn] = entry;
|
927 | 925 | Object.defineProperty(globalThis, name, {value: fn, configurable: true, writable: true, enumerable: false});
|
928 | 926 | });
|
929 | 927 | }
|
930 |
| -}); |
| 928 | +}; |
| 929 | + |
| 930 | +globalThis['Fetch'] = Fetch; |
0 commit comments