@whatwg-node/node-fetch 0.4.8 → 0.4.9-rc-20230718150124-677ae83
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/cjs/Headers.js +1 -1
- package/cjs/fetchCurl.js +72 -62
- package/esm/Headers.js +1 -1
- package/esm/fetchCurl.js +71 -61
- package/package.json +1 -1
package/cjs/Headers.js
CHANGED
@@ -24,7 +24,7 @@ class PonyfillHeaders {
|
|
24
24
|
}
|
25
25
|
const normalized = key.toLowerCase();
|
26
26
|
if (Array.isArray(this.headersInit)) {
|
27
|
-
return this.headersInit.find(header => header[0] === normalized)?.[1] || null;
|
27
|
+
return this.headersInit.find(header => header[0].toLowerCase() === normalized)?.[1] || null;
|
28
28
|
}
|
29
29
|
else if (isHeadersLike(this.headersInit)) {
|
30
30
|
return this.headersInit.get(normalized);
|
package/cjs/fetchCurl.js
CHANGED
@@ -1,82 +1,92 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.fetchCurl = void 0;
|
4
|
-
|
5
|
-
const stream_1 = require("stream");
|
6
|
-
const Headers_js_1 = require("./Headers.js");
|
4
|
+
const node_stream_1 = require("node:stream");
|
7
5
|
const Response_js_1 = require("./Response.js");
|
8
6
|
const utils_js_1 = require("./utils.js");
|
9
|
-
|
7
|
+
function fetchCurl(fetchRequest) {
|
8
|
+
const { Curl, CurlCode, CurlFeature, CurlPause, CurlProgressFunc } = globalThis['libcurl'];
|
9
|
+
const curlHandle = new Curl();
|
10
|
+
if (fetchRequest['_signal']) {
|
11
|
+
fetchRequest['_signal'].onabort = () => {
|
12
|
+
curlHandle.pause(CurlPause.Recv);
|
13
|
+
};
|
14
|
+
}
|
15
|
+
curlHandle.enable(CurlFeature.NoDataParsing);
|
16
|
+
curlHandle.setOpt('URL', fetchRequest.url);
|
17
|
+
curlHandle.setOpt('SSL_VERIFYPEER', false);
|
18
|
+
curlHandle.enable(CurlFeature.StreamResponse);
|
19
|
+
curlHandle.setStreamProgressCallback(function () {
|
20
|
+
return fetchRequest['_signal']?.aborted
|
21
|
+
? process.env.DEBUG
|
22
|
+
? CurlProgressFunc.Continue
|
23
|
+
: 1
|
24
|
+
: 0;
|
25
|
+
});
|
10
26
|
const nodeReadable = (fetchRequest.body != null
|
11
27
|
? 'pipe' in fetchRequest.body
|
12
28
|
? fetchRequest.body
|
13
|
-
:
|
29
|
+
: node_stream_1.Readable.from(fetchRequest.body)
|
14
30
|
: null);
|
31
|
+
if (nodeReadable) {
|
32
|
+
curlHandle.setOpt('UPLOAD', true);
|
33
|
+
curlHandle.setUploadStream(nodeReadable);
|
34
|
+
}
|
35
|
+
if (process.env.DEBUG) {
|
36
|
+
curlHandle.setOpt('VERBOSE', true);
|
37
|
+
}
|
38
|
+
curlHandle.setOpt('TRANSFER_ENCODING', false);
|
39
|
+
curlHandle.setOpt('HTTP_TRANSFER_DECODING', true);
|
40
|
+
curlHandle.setOpt('FOLLOWLOCATION', fetchRequest.redirect === 'follow');
|
41
|
+
curlHandle.setOpt('MAXREDIRS', 20);
|
42
|
+
curlHandle.setOpt('ACCEPT_ENCODING', '');
|
43
|
+
curlHandle.setOpt('CUSTOMREQUEST', fetchRequest.method);
|
15
44
|
const headersSerializer = fetchRequest.headersSerializer || utils_js_1.defaultHeadersSerializer;
|
16
45
|
let size;
|
17
|
-
const
|
46
|
+
const curlHeaders = headersSerializer(fetchRequest.headers, value => {
|
18
47
|
size = Number(value);
|
19
48
|
});
|
20
|
-
let easyNativeBinding;
|
21
|
-
const curlyOptions = {
|
22
|
-
sslVerifyPeer: false,
|
23
|
-
// we want the unparsed binary response to be returned as a stream to us
|
24
|
-
curlyStreamResponse: true,
|
25
|
-
curlyResponseBodyParser: false,
|
26
|
-
curlyProgressCallback() {
|
27
|
-
if (easyNativeBinding == null) {
|
28
|
-
easyNativeBinding = this;
|
29
|
-
}
|
30
|
-
return fetchRequest['_signal']?.aborted ? 1 : 0;
|
31
|
-
},
|
32
|
-
upload: nodeReadable != null,
|
33
|
-
transferEncoding: false,
|
34
|
-
httpTransferDecoding: true,
|
35
|
-
followLocation: fetchRequest.redirect === 'follow',
|
36
|
-
maxRedirs: 20,
|
37
|
-
acceptEncoding: '',
|
38
|
-
curlyStreamUpload: nodeReadable,
|
39
|
-
// this will just make libcurl use their own progress function (which is pretty neat)
|
40
|
-
// curlyProgressCallback() { return CurlProgressFunc.Continue },
|
41
|
-
// verbose: true,
|
42
|
-
httpHeader: curlyHeaders,
|
43
|
-
customRequest: fetchRequest.method,
|
44
|
-
};
|
45
49
|
if (size != null) {
|
46
|
-
|
50
|
+
curlHandle.setOpt('INFILESIZE', size);
|
47
51
|
}
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
52
|
+
curlHandle.setOpt('HTTPHEADER', curlHeaders);
|
53
|
+
curlHandle.enable(CurlFeature.NoHeaderParsing);
|
54
|
+
return new Promise(function promiseResolver(resolve, reject) {
|
55
|
+
curlHandle.once('end', function endListener() {
|
56
|
+
curlHandle.close();
|
57
|
+
});
|
58
|
+
curlHandle.once('error', function errorListener(error) {
|
59
|
+
if (error.isCurlError && error.code === CurlCode.CURLE_ABORTED_BY_CALLBACK) {
|
60
|
+
// this is expected
|
53
61
|
}
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
const responseHeaders = new Headers_js_1.PonyfillHeaders();
|
58
|
-
curlyResult.headers.forEach(headerInfo => {
|
59
|
-
for (const key in headerInfo) {
|
60
|
-
if (key === 'location' || (key === 'Location' && fetchRequest.redirect === 'error')) {
|
61
|
-
throw new Error('redirects are not allowed');
|
62
|
+
else {
|
63
|
+
// this is unexpected
|
64
|
+
reject(error);
|
62
65
|
}
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
66
|
+
curlHandle.close();
|
67
|
+
});
|
68
|
+
curlHandle.once('stream', function streamListener(stream, status, headersBuf) {
|
69
|
+
const headersFlat = headersBuf
|
70
|
+
.toString('utf8')
|
71
|
+
.split(/\r?\n|\r/g)
|
72
|
+
.filter(headerFilter => {
|
73
|
+
if (headerFilter && !headerFilter.startsWith('HTTP/')) {
|
74
|
+
if (fetchRequest.redirect === 'error' &&
|
75
|
+
(headerFilter.includes('location') || headerFilter.includes('Location'))) {
|
76
|
+
reject(new Error('redirect is not allowed'));
|
77
|
+
}
|
78
|
+
return true;
|
79
|
+
}
|
80
|
+
return false;
|
81
|
+
});
|
82
|
+
const headersInit = headersFlat.map(headerFlat => headerFlat.split(/:\s(.+)/).slice(0, 2));
|
83
|
+
resolve(new Response_js_1.PonyfillResponse(stream, {
|
84
|
+
status,
|
85
|
+
headers: headersInit,
|
86
|
+
url: fetchRequest.url,
|
87
|
+
}));
|
88
|
+
});
|
89
|
+
curlHandle.perform();
|
80
90
|
});
|
81
91
|
}
|
82
92
|
exports.fetchCurl = fetchCurl;
|
package/esm/Headers.js
CHANGED
@@ -20,7 +20,7 @@ export class PonyfillHeaders {
|
|
20
20
|
}
|
21
21
|
const normalized = key.toLowerCase();
|
22
22
|
if (Array.isArray(this.headersInit)) {
|
23
|
-
return this.headersInit.find(header => header[0] === normalized)?.[1] || null;
|
23
|
+
return this.headersInit.find(header => header[0].toLowerCase() === normalized)?.[1] || null;
|
24
24
|
}
|
25
25
|
else if (isHeadersLike(this.headersInit)) {
|
26
26
|
return this.headersInit.get(normalized);
|
package/esm/fetchCurl.js
CHANGED
@@ -1,78 +1,88 @@
|
|
1
|
-
|
2
|
-
import { Readable } from 'stream';
|
3
|
-
import { PonyfillHeaders } from './Headers.js';
|
1
|
+
import { Readable } from 'node:stream';
|
4
2
|
import { PonyfillResponse } from './Response.js';
|
5
3
|
import { defaultHeadersSerializer } from './utils.js';
|
6
|
-
export
|
4
|
+
export function fetchCurl(fetchRequest) {
|
5
|
+
const { Curl, CurlCode, CurlFeature, CurlPause, CurlProgressFunc } = globalThis['libcurl'];
|
6
|
+
const curlHandle = new Curl();
|
7
|
+
if (fetchRequest['_signal']) {
|
8
|
+
fetchRequest['_signal'].onabort = () => {
|
9
|
+
curlHandle.pause(CurlPause.Recv);
|
10
|
+
};
|
11
|
+
}
|
12
|
+
curlHandle.enable(CurlFeature.NoDataParsing);
|
13
|
+
curlHandle.setOpt('URL', fetchRequest.url);
|
14
|
+
curlHandle.setOpt('SSL_VERIFYPEER', false);
|
15
|
+
curlHandle.enable(CurlFeature.StreamResponse);
|
16
|
+
curlHandle.setStreamProgressCallback(function () {
|
17
|
+
return fetchRequest['_signal']?.aborted
|
18
|
+
? process.env.DEBUG
|
19
|
+
? CurlProgressFunc.Continue
|
20
|
+
: 1
|
21
|
+
: 0;
|
22
|
+
});
|
7
23
|
const nodeReadable = (fetchRequest.body != null
|
8
24
|
? 'pipe' in fetchRequest.body
|
9
25
|
? fetchRequest.body
|
10
26
|
: Readable.from(fetchRequest.body)
|
11
27
|
: null);
|
28
|
+
if (nodeReadable) {
|
29
|
+
curlHandle.setOpt('UPLOAD', true);
|
30
|
+
curlHandle.setUploadStream(nodeReadable);
|
31
|
+
}
|
32
|
+
if (process.env.DEBUG) {
|
33
|
+
curlHandle.setOpt('VERBOSE', true);
|
34
|
+
}
|
35
|
+
curlHandle.setOpt('TRANSFER_ENCODING', false);
|
36
|
+
curlHandle.setOpt('HTTP_TRANSFER_DECODING', true);
|
37
|
+
curlHandle.setOpt('FOLLOWLOCATION', fetchRequest.redirect === 'follow');
|
38
|
+
curlHandle.setOpt('MAXREDIRS', 20);
|
39
|
+
curlHandle.setOpt('ACCEPT_ENCODING', '');
|
40
|
+
curlHandle.setOpt('CUSTOMREQUEST', fetchRequest.method);
|
12
41
|
const headersSerializer = fetchRequest.headersSerializer || defaultHeadersSerializer;
|
13
42
|
let size;
|
14
|
-
const
|
43
|
+
const curlHeaders = headersSerializer(fetchRequest.headers, value => {
|
15
44
|
size = Number(value);
|
16
45
|
});
|
17
|
-
let easyNativeBinding;
|
18
|
-
const curlyOptions = {
|
19
|
-
sslVerifyPeer: false,
|
20
|
-
// we want the unparsed binary response to be returned as a stream to us
|
21
|
-
curlyStreamResponse: true,
|
22
|
-
curlyResponseBodyParser: false,
|
23
|
-
curlyProgressCallback() {
|
24
|
-
if (easyNativeBinding == null) {
|
25
|
-
easyNativeBinding = this;
|
26
|
-
}
|
27
|
-
return fetchRequest['_signal']?.aborted ? 1 : 0;
|
28
|
-
},
|
29
|
-
upload: nodeReadable != null,
|
30
|
-
transferEncoding: false,
|
31
|
-
httpTransferDecoding: true,
|
32
|
-
followLocation: fetchRequest.redirect === 'follow',
|
33
|
-
maxRedirs: 20,
|
34
|
-
acceptEncoding: '',
|
35
|
-
curlyStreamUpload: nodeReadable,
|
36
|
-
// this will just make libcurl use their own progress function (which is pretty neat)
|
37
|
-
// curlyProgressCallback() { return CurlProgressFunc.Continue },
|
38
|
-
// verbose: true,
|
39
|
-
httpHeader: curlyHeaders,
|
40
|
-
customRequest: fetchRequest.method,
|
41
|
-
};
|
42
46
|
if (size != null) {
|
43
|
-
|
47
|
+
curlHandle.setOpt('INFILESIZE', size);
|
44
48
|
}
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
49
|
+
curlHandle.setOpt('HTTPHEADER', curlHeaders);
|
50
|
+
curlHandle.enable(CurlFeature.NoHeaderParsing);
|
51
|
+
return new Promise(function promiseResolver(resolve, reject) {
|
52
|
+
curlHandle.once('end', function endListener() {
|
53
|
+
curlHandle.close();
|
54
|
+
});
|
55
|
+
curlHandle.once('error', function errorListener(error) {
|
56
|
+
if (error.isCurlError && error.code === CurlCode.CURLE_ABORTED_BY_CALLBACK) {
|
57
|
+
// this is expected
|
50
58
|
}
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
const responseHeaders = new PonyfillHeaders();
|
55
|
-
curlyResult.headers.forEach(headerInfo => {
|
56
|
-
for (const key in headerInfo) {
|
57
|
-
if (key === 'location' || (key === 'Location' && fetchRequest.redirect === 'error')) {
|
58
|
-
throw new Error('redirects are not allowed');
|
59
|
+
else {
|
60
|
+
// this is unexpected
|
61
|
+
reject(error);
|
59
62
|
}
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
63
|
+
curlHandle.close();
|
64
|
+
});
|
65
|
+
curlHandle.once('stream', function streamListener(stream, status, headersBuf) {
|
66
|
+
const headersFlat = headersBuf
|
67
|
+
.toString('utf8')
|
68
|
+
.split(/\r?\n|\r/g)
|
69
|
+
.filter(headerFilter => {
|
70
|
+
if (headerFilter && !headerFilter.startsWith('HTTP/')) {
|
71
|
+
if (fetchRequest.redirect === 'error' &&
|
72
|
+
(headerFilter.includes('location') || headerFilter.includes('Location'))) {
|
73
|
+
reject(new Error('redirect is not allowed'));
|
74
|
+
}
|
75
|
+
return true;
|
76
|
+
}
|
77
|
+
return false;
|
78
|
+
});
|
79
|
+
const headersInit = headersFlat.map(headerFlat => headerFlat.split(/:\s(.+)/).slice(0, 2));
|
80
|
+
resolve(new PonyfillResponse(stream, {
|
81
|
+
status,
|
82
|
+
headers: headersInit,
|
83
|
+
url: fetchRequest.url,
|
84
|
+
}));
|
85
|
+
});
|
86
|
+
curlHandle.perform();
|
77
87
|
});
|
78
88
|
}
|