@whatwg-node/node-fetch 0.5.25 → 0.5.26-alpha-20240901110918-327f9be5bc93784c6bf7017b1bf1a4106ac31cfb
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/fetchCurl.js +88 -72
- package/cjs/utils.js +18 -0
- package/esm/fetchCurl.js +89 -73
- package/esm/utils.js +17 -0
- package/package.json +1 -1
- package/typings/utils.d.cts +6 -0
- package/typings/utils.d.ts +6 -0
package/cjs/fetchCurl.js
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.fetchCurl = fetchCurl;
|
4
4
|
const stream_1 = require("stream");
|
5
|
+
const tls_1 = require("tls");
|
5
6
|
const Response_js_1 = require("./Response.js");
|
6
7
|
const utils_js_1 = require("./utils.js");
|
7
8
|
function fetchCurl(fetchRequest) {
|
@@ -15,6 +16,9 @@ function fetchCurl(fetchRequest) {
|
|
15
16
|
if (process.env.NODE_EXTRA_CA_CERTS) {
|
16
17
|
curlHandle.setOpt('CAINFO', process.env.NODE_EXTRA_CA_CERTS);
|
17
18
|
}
|
19
|
+
else {
|
20
|
+
curlHandle.setOpt('CAINFO_BLOB', tls_1.rootCertificates.join('\n'));
|
21
|
+
}
|
18
22
|
curlHandle.enable(CurlFeature.StreamResponse);
|
19
23
|
curlHandle.setStreamProgressCallback(function () {
|
20
24
|
return fetchRequest['_signal']?.aborted
|
@@ -56,85 +60,97 @@ function fetchCurl(fetchRequest) {
|
|
56
60
|
}
|
57
61
|
curlHandle.setOpt('HTTPHEADER', curlHeaders);
|
58
62
|
curlHandle.enable(CurlFeature.NoHeaderParsing);
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
}
|
67
|
-
catch (e) {
|
68
|
-
reject(e);
|
69
|
-
}
|
63
|
+
const deferredPromise = (0, utils_js_1.createDeferredPromise)();
|
64
|
+
let streamResolved;
|
65
|
+
if (fetchRequest['_signal']) {
|
66
|
+
fetchRequest['_signal'].onabort = () => {
|
67
|
+
if (curlHandle.isOpen) {
|
68
|
+
try {
|
69
|
+
curlHandle.pause(CurlPause.Recv);
|
70
70
|
}
|
71
|
-
|
72
|
-
|
73
|
-
curlHandle.once('end', function endListener() {
|
74
|
-
try {
|
75
|
-
curlHandle.close();
|
76
|
-
}
|
77
|
-
catch (e) {
|
78
|
-
reject(e);
|
79
|
-
}
|
80
|
-
});
|
81
|
-
curlHandle.once('error', function errorListener(error) {
|
82
|
-
if (streamResolved && !streamResolved.closed && !streamResolved.destroyed) {
|
83
|
-
streamResolved.destroy(error);
|
84
|
-
}
|
85
|
-
else {
|
86
|
-
if (error.message === 'Operation was aborted by an application callback') {
|
87
|
-
error.message = 'The operation was aborted.';
|
71
|
+
catch (e) {
|
72
|
+
deferredPromise.reject(e);
|
88
73
|
}
|
89
|
-
reject(error);
|
90
74
|
}
|
91
|
-
|
92
|
-
|
75
|
+
};
|
76
|
+
}
|
77
|
+
curlHandle.once('end', function endListener() {
|
78
|
+
try {
|
79
|
+
curlHandle.close();
|
80
|
+
}
|
81
|
+
catch (e) {
|
82
|
+
deferredPromise.reject(e);
|
83
|
+
}
|
84
|
+
});
|
85
|
+
curlHandle.once('error', function errorListener(error) {
|
86
|
+
if (streamResolved && !streamResolved.closed && !streamResolved.destroyed) {
|
87
|
+
streamResolved.destroy(error);
|
88
|
+
}
|
89
|
+
else {
|
90
|
+
if (error.message === 'Operation was aborted by an application callback') {
|
91
|
+
error.message = 'The operation was aborted.';
|
93
92
|
}
|
94
|
-
|
95
|
-
|
93
|
+
deferredPromise.reject(error);
|
94
|
+
}
|
95
|
+
try {
|
96
|
+
curlHandle.close();
|
97
|
+
}
|
98
|
+
catch (e) {
|
99
|
+
deferredPromise.reject(e);
|
100
|
+
}
|
101
|
+
});
|
102
|
+
curlHandle.once('stream', function streamListener(stream, status, headersBuf) {
|
103
|
+
const outputStream = new stream_1.PassThrough();
|
104
|
+
stream_1.promises
|
105
|
+
.pipeline(stream, outputStream, {
|
106
|
+
end: true,
|
107
|
+
signal: fetchRequest['_signal'] ?? undefined,
|
108
|
+
})
|
109
|
+
.then(() => {
|
110
|
+
if (!stream.destroyed) {
|
111
|
+
stream.resume();
|
96
112
|
}
|
97
|
-
})
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
}
|
109
|
-
})
|
110
|
-
.catch(reject);
|
111
|
-
const headersFlat = headersBuf
|
112
|
-
.toString('utf8')
|
113
|
-
.split(/\r?\n|\r/g)
|
114
|
-
.filter(headerFilter => {
|
115
|
-
if (headerFilter && !headerFilter.startsWith('HTTP/')) {
|
116
|
-
if (fetchRequest.redirect === 'error' &&
|
117
|
-
(headerFilter.includes('location') || headerFilter.includes('Location'))) {
|
118
|
-
if (!stream.destroyed) {
|
119
|
-
stream.resume();
|
120
|
-
}
|
121
|
-
outputStream.destroy();
|
122
|
-
reject(new Error('redirect is not allowed'));
|
113
|
+
})
|
114
|
+
.catch(deferredPromise.reject);
|
115
|
+
const headersFlat = headersBuf
|
116
|
+
.toString('utf8')
|
117
|
+
.split(/\r?\n|\r/g)
|
118
|
+
.filter(headerFilter => {
|
119
|
+
if (headerFilter && !headerFilter.startsWith('HTTP/')) {
|
120
|
+
if (fetchRequest.redirect === 'error' &&
|
121
|
+
(headerFilter.includes('location') || headerFilter.includes('Location'))) {
|
122
|
+
if (!stream.destroyed) {
|
123
|
+
stream.resume();
|
123
124
|
}
|
124
|
-
|
125
|
+
outputStream.destroy();
|
126
|
+
deferredPromise.reject(new Error('redirect is not allowed'));
|
125
127
|
}
|
126
|
-
return
|
127
|
-
}
|
128
|
-
|
129
|
-
const ponyfillResponse = new Response_js_1.PonyfillResponse(outputStream, {
|
130
|
-
status,
|
131
|
-
headers: headersInit,
|
132
|
-
url: curlHandle.getInfo(Curl.info.REDIRECT_URL)?.toString() || fetchRequest.url,
|
133
|
-
redirected: Number(curlHandle.getInfo(Curl.info.REDIRECT_COUNT)) > 0,
|
134
|
-
});
|
135
|
-
resolve(ponyfillResponse);
|
136
|
-
streamResolved = outputStream;
|
128
|
+
return true;
|
129
|
+
}
|
130
|
+
return false;
|
137
131
|
});
|
138
|
-
|
132
|
+
const headersInit = headersFlat.map(headerFlat => headerFlat.split(/:\s(.+)/).slice(0, 2));
|
133
|
+
const ponyfillResponse = new Response_js_1.PonyfillResponse(outputStream, {
|
134
|
+
status,
|
135
|
+
headers: headersInit,
|
136
|
+
url: curlHandle.getInfo(Curl.info.REDIRECT_URL)?.toString() || fetchRequest.url,
|
137
|
+
redirected: Number(curlHandle.getInfo(Curl.info.REDIRECT_COUNT)) > 0,
|
138
|
+
});
|
139
|
+
deferredPromise.resolve(ponyfillResponse);
|
140
|
+
streamResolved = outputStream;
|
139
141
|
});
|
142
|
+
let count = 0;
|
143
|
+
try {
|
144
|
+
count = Curl.getCount();
|
145
|
+
}
|
146
|
+
catch { }
|
147
|
+
if (count > 0) {
|
148
|
+
setImmediate(() => {
|
149
|
+
curlHandle.perform();
|
150
|
+
});
|
151
|
+
}
|
152
|
+
else {
|
153
|
+
curlHandle.perform();
|
154
|
+
}
|
155
|
+
return deferredPromise.promise;
|
140
156
|
}
|
package/cjs/utils.js
CHANGED
@@ -5,6 +5,7 @@ exports.defaultHeadersSerializer = defaultHeadersSerializer;
|
|
5
5
|
exports.fakePromise = fakePromise;
|
6
6
|
exports.isArrayBufferView = isArrayBufferView;
|
7
7
|
exports.isNodeReadable = isNodeReadable;
|
8
|
+
exports.createDeferredPromise = createDeferredPromise;
|
8
9
|
function isHeadersInstance(obj) {
|
9
10
|
return obj?.forEach != null;
|
10
11
|
}
|
@@ -70,3 +71,20 @@ function isArrayBufferView(obj) {
|
|
70
71
|
function isNodeReadable(obj) {
|
71
72
|
return obj != null && obj.pipe != null;
|
72
73
|
}
|
74
|
+
function createDeferredPromise() {
|
75
|
+
let resolveFn;
|
76
|
+
let rejectFn;
|
77
|
+
const promise = new Promise(function deferredPromiseExecutor(resolve, reject) {
|
78
|
+
resolveFn = resolve;
|
79
|
+
rejectFn = reject;
|
80
|
+
});
|
81
|
+
return {
|
82
|
+
promise,
|
83
|
+
get resolve() {
|
84
|
+
return resolveFn;
|
85
|
+
},
|
86
|
+
get reject() {
|
87
|
+
return rejectFn;
|
88
|
+
},
|
89
|
+
};
|
90
|
+
}
|
package/esm/fetchCurl.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import { PassThrough, Readable, promises as streamPromises } from 'stream';
|
2
|
+
import { rootCertificates } from 'tls';
|
2
3
|
import { PonyfillResponse } from './Response.js';
|
3
|
-
import { defaultHeadersSerializer, isNodeReadable } from './utils.js';
|
4
|
+
import { createDeferredPromise, defaultHeadersSerializer, isNodeReadable } from './utils.js';
|
4
5
|
export function fetchCurl(fetchRequest) {
|
5
6
|
const { Curl, CurlFeature, CurlPause, CurlProgressFunc } = globalThis['libcurl'];
|
6
7
|
const curlHandle = new Curl();
|
@@ -12,6 +13,9 @@ export function fetchCurl(fetchRequest) {
|
|
12
13
|
if (process.env.NODE_EXTRA_CA_CERTS) {
|
13
14
|
curlHandle.setOpt('CAINFO', process.env.NODE_EXTRA_CA_CERTS);
|
14
15
|
}
|
16
|
+
else {
|
17
|
+
curlHandle.setOpt('CAINFO_BLOB', rootCertificates.join('\n'));
|
18
|
+
}
|
15
19
|
curlHandle.enable(CurlFeature.StreamResponse);
|
16
20
|
curlHandle.setStreamProgressCallback(function () {
|
17
21
|
return fetchRequest['_signal']?.aborted
|
@@ -53,85 +57,97 @@ export function fetchCurl(fetchRequest) {
|
|
53
57
|
}
|
54
58
|
curlHandle.setOpt('HTTPHEADER', curlHeaders);
|
55
59
|
curlHandle.enable(CurlFeature.NoHeaderParsing);
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
}
|
64
|
-
catch (e) {
|
65
|
-
reject(e);
|
66
|
-
}
|
60
|
+
const deferredPromise = createDeferredPromise();
|
61
|
+
let streamResolved;
|
62
|
+
if (fetchRequest['_signal']) {
|
63
|
+
fetchRequest['_signal'].onabort = () => {
|
64
|
+
if (curlHandle.isOpen) {
|
65
|
+
try {
|
66
|
+
curlHandle.pause(CurlPause.Recv);
|
67
67
|
}
|
68
|
-
|
69
|
-
|
70
|
-
curlHandle.once('end', function endListener() {
|
71
|
-
try {
|
72
|
-
curlHandle.close();
|
73
|
-
}
|
74
|
-
catch (e) {
|
75
|
-
reject(e);
|
76
|
-
}
|
77
|
-
});
|
78
|
-
curlHandle.once('error', function errorListener(error) {
|
79
|
-
if (streamResolved && !streamResolved.closed && !streamResolved.destroyed) {
|
80
|
-
streamResolved.destroy(error);
|
81
|
-
}
|
82
|
-
else {
|
83
|
-
if (error.message === 'Operation was aborted by an application callback') {
|
84
|
-
error.message = 'The operation was aborted.';
|
68
|
+
catch (e) {
|
69
|
+
deferredPromise.reject(e);
|
85
70
|
}
|
86
|
-
reject(error);
|
87
71
|
}
|
88
|
-
|
89
|
-
|
72
|
+
};
|
73
|
+
}
|
74
|
+
curlHandle.once('end', function endListener() {
|
75
|
+
try {
|
76
|
+
curlHandle.close();
|
77
|
+
}
|
78
|
+
catch (e) {
|
79
|
+
deferredPromise.reject(e);
|
80
|
+
}
|
81
|
+
});
|
82
|
+
curlHandle.once('error', function errorListener(error) {
|
83
|
+
if (streamResolved && !streamResolved.closed && !streamResolved.destroyed) {
|
84
|
+
streamResolved.destroy(error);
|
85
|
+
}
|
86
|
+
else {
|
87
|
+
if (error.message === 'Operation was aborted by an application callback') {
|
88
|
+
error.message = 'The operation was aborted.';
|
90
89
|
}
|
91
|
-
|
92
|
-
|
90
|
+
deferredPromise.reject(error);
|
91
|
+
}
|
92
|
+
try {
|
93
|
+
curlHandle.close();
|
94
|
+
}
|
95
|
+
catch (e) {
|
96
|
+
deferredPromise.reject(e);
|
97
|
+
}
|
98
|
+
});
|
99
|
+
curlHandle.once('stream', function streamListener(stream, status, headersBuf) {
|
100
|
+
const outputStream = new PassThrough();
|
101
|
+
streamPromises
|
102
|
+
.pipeline(stream, outputStream, {
|
103
|
+
end: true,
|
104
|
+
signal: fetchRequest['_signal'] ?? undefined,
|
105
|
+
})
|
106
|
+
.then(() => {
|
107
|
+
if (!stream.destroyed) {
|
108
|
+
stream.resume();
|
93
109
|
}
|
94
|
-
})
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
}
|
106
|
-
})
|
107
|
-
.catch(reject);
|
108
|
-
const headersFlat = headersBuf
|
109
|
-
.toString('utf8')
|
110
|
-
.split(/\r?\n|\r/g)
|
111
|
-
.filter(headerFilter => {
|
112
|
-
if (headerFilter && !headerFilter.startsWith('HTTP/')) {
|
113
|
-
if (fetchRequest.redirect === 'error' &&
|
114
|
-
(headerFilter.includes('location') || headerFilter.includes('Location'))) {
|
115
|
-
if (!stream.destroyed) {
|
116
|
-
stream.resume();
|
117
|
-
}
|
118
|
-
outputStream.destroy();
|
119
|
-
reject(new Error('redirect is not allowed'));
|
110
|
+
})
|
111
|
+
.catch(deferredPromise.reject);
|
112
|
+
const headersFlat = headersBuf
|
113
|
+
.toString('utf8')
|
114
|
+
.split(/\r?\n|\r/g)
|
115
|
+
.filter(headerFilter => {
|
116
|
+
if (headerFilter && !headerFilter.startsWith('HTTP/')) {
|
117
|
+
if (fetchRequest.redirect === 'error' &&
|
118
|
+
(headerFilter.includes('location') || headerFilter.includes('Location'))) {
|
119
|
+
if (!stream.destroyed) {
|
120
|
+
stream.resume();
|
120
121
|
}
|
121
|
-
|
122
|
+
outputStream.destroy();
|
123
|
+
deferredPromise.reject(new Error('redirect is not allowed'));
|
122
124
|
}
|
123
|
-
return
|
124
|
-
}
|
125
|
-
|
126
|
-
const ponyfillResponse = new PonyfillResponse(outputStream, {
|
127
|
-
status,
|
128
|
-
headers: headersInit,
|
129
|
-
url: curlHandle.getInfo(Curl.info.REDIRECT_URL)?.toString() || fetchRequest.url,
|
130
|
-
redirected: Number(curlHandle.getInfo(Curl.info.REDIRECT_COUNT)) > 0,
|
131
|
-
});
|
132
|
-
resolve(ponyfillResponse);
|
133
|
-
streamResolved = outputStream;
|
125
|
+
return true;
|
126
|
+
}
|
127
|
+
return false;
|
134
128
|
});
|
135
|
-
|
129
|
+
const headersInit = headersFlat.map(headerFlat => headerFlat.split(/:\s(.+)/).slice(0, 2));
|
130
|
+
const ponyfillResponse = new PonyfillResponse(outputStream, {
|
131
|
+
status,
|
132
|
+
headers: headersInit,
|
133
|
+
url: curlHandle.getInfo(Curl.info.REDIRECT_URL)?.toString() || fetchRequest.url,
|
134
|
+
redirected: Number(curlHandle.getInfo(Curl.info.REDIRECT_COUNT)) > 0,
|
135
|
+
});
|
136
|
+
deferredPromise.resolve(ponyfillResponse);
|
137
|
+
streamResolved = outputStream;
|
136
138
|
});
|
139
|
+
let count = 0;
|
140
|
+
try {
|
141
|
+
count = Curl.getCount();
|
142
|
+
}
|
143
|
+
catch { }
|
144
|
+
if (count > 0) {
|
145
|
+
setImmediate(() => {
|
146
|
+
curlHandle.perform();
|
147
|
+
});
|
148
|
+
}
|
149
|
+
else {
|
150
|
+
curlHandle.perform();
|
151
|
+
}
|
152
|
+
return deferredPromise.promise;
|
137
153
|
}
|
package/esm/utils.js
CHANGED
@@ -63,3 +63,20 @@ export function isArrayBufferView(obj) {
|
|
63
63
|
export function isNodeReadable(obj) {
|
64
64
|
return obj != null && obj.pipe != null;
|
65
65
|
}
|
66
|
+
export function createDeferredPromise() {
|
67
|
+
let resolveFn;
|
68
|
+
let rejectFn;
|
69
|
+
const promise = new Promise(function deferredPromiseExecutor(resolve, reject) {
|
70
|
+
resolveFn = resolve;
|
71
|
+
rejectFn = reject;
|
72
|
+
});
|
73
|
+
return {
|
74
|
+
promise,
|
75
|
+
get resolve() {
|
76
|
+
return resolveFn;
|
77
|
+
},
|
78
|
+
get reject() {
|
79
|
+
return rejectFn;
|
80
|
+
},
|
81
|
+
};
|
82
|
+
}
|
package/package.json
CHANGED
package/typings/utils.d.cts
CHANGED
@@ -4,3 +4,9 @@ export declare function defaultHeadersSerializer(headers: Headers, onContentLeng
|
|
4
4
|
export declare function fakePromise<T>(value: T): Promise<T>;
|
5
5
|
export declare function isArrayBufferView(obj: any): obj is ArrayBufferView;
|
6
6
|
export declare function isNodeReadable(obj: any): obj is Readable;
|
7
|
+
export interface DeferredPromise<T = void> {
|
8
|
+
promise: Promise<T>;
|
9
|
+
resolve: (value: T) => void;
|
10
|
+
reject: (reason: any) => void;
|
11
|
+
}
|
12
|
+
export declare function createDeferredPromise<T = void>(): DeferredPromise<T>;
|
package/typings/utils.d.ts
CHANGED
@@ -4,3 +4,9 @@ export declare function defaultHeadersSerializer(headers: Headers, onContentLeng
|
|
4
4
|
export declare function fakePromise<T>(value: T): Promise<T>;
|
5
5
|
export declare function isArrayBufferView(obj: any): obj is ArrayBufferView;
|
6
6
|
export declare function isNodeReadable(obj: any): obj is Readable;
|
7
|
+
export interface DeferredPromise<T = void> {
|
8
|
+
promise: Promise<T>;
|
9
|
+
resolve: (value: T) => void;
|
10
|
+
reject: (reason: any) => void;
|
11
|
+
}
|
12
|
+
export declare function createDeferredPromise<T = void>(): DeferredPromise<T>;
|