electron/lib/browser/api/net-fetch.ts

124 lines
3.9 KiB
TypeScript
Raw Normal View History

feat: add net module to utility process (#40017) * chore: initial prototype of net api from utility process * chore: update url loader to work on both browser and utility processes * chore: add net files to utility process bundle * chore: re-add app ready check but only on main process * chore: replace browser thread dcheck's with sequence checker * refactor: move url loader from browser to common * refactor: move net-client-request.ts from browser to common * docs: add utility process to net api docs * refactor: move net module app ready check to browser only * refactor: switch import from main to common after moving to common * test: add basic net module test for utility process * refactor: switch browser pid with utility pid * refactor: move electron_api_net from browser to common * chore: add fetch to utility net module * chore: add isOnline and online to utility net module * refactor: move net spec helpers into helper file * refactor: break apart net module tests Adds two additional net module test files: `api-net-session-spec.ts` for tests that depend on a session being available (aka depend on running on the main process) and `api-net-custom-protocols-spec.ts` for custom protocol tests. This enables running `api-net-spec.ts` in the utility process. * test: add utility process mocha runner to run net module tests * docs: add utility process to net module classes * refactor: update imports in lib/utility to use electron/utility * chore: check browser context before using in main process Since the browser context supplied to the SimpleURLLoaderWrapper can now be null for use in the UtilityProcess, adding a null check for the main process before use to get a more sensible error if something goes wrong. Co-authored-by: Cheng Zhao <github@zcbenz.com> * chore: remove test debugging * chore: remove unnecessary header include * docs: add utility process net module limitations * test: run net module tests in utility process individually * refactor: clean up prior utility process net tests * chore: add resolveHost to utility process net module * chore: replace resolve host dcheck with sequence checker * test: add net module tests for net.resolveHost * docs: remove utility process limitation for resolveHost --------- Co-authored-by: deepak1556 <hop2deep@gmail.com> Co-authored-by: Cheng Zhao <github@zcbenz.com>
2024-01-04 21:20:37 +00:00
import { ClientRequestConstructorOptions, ClientRequest, IncomingMessage, Session as SessionT } from 'electron/main';
2023-02-20 20:57:38 +00:00
import { Readable, Writable, isReadable } from 'stream';
feat: add net module to utility process (#40017) * chore: initial prototype of net api from utility process * chore: update url loader to work on both browser and utility processes * chore: add net files to utility process bundle * chore: re-add app ready check but only on main process * chore: replace browser thread dcheck's with sequence checker * refactor: move url loader from browser to common * refactor: move net-client-request.ts from browser to common * docs: add utility process to net api docs * refactor: move net module app ready check to browser only * refactor: switch import from main to common after moving to common * test: add basic net module test for utility process * refactor: switch browser pid with utility pid * refactor: move electron_api_net from browser to common * chore: add fetch to utility net module * chore: add isOnline and online to utility net module * refactor: move net spec helpers into helper file * refactor: break apart net module tests Adds two additional net module test files: `api-net-session-spec.ts` for tests that depend on a session being available (aka depend on running on the main process) and `api-net-custom-protocols-spec.ts` for custom protocol tests. This enables running `api-net-spec.ts` in the utility process. * test: add utility process mocha runner to run net module tests * docs: add utility process to net module classes * refactor: update imports in lib/utility to use electron/utility * chore: check browser context before using in main process Since the browser context supplied to the SimpleURLLoaderWrapper can now be null for use in the UtilityProcess, adding a null check for the main process before use to get a more sensible error if something goes wrong. Co-authored-by: Cheng Zhao <github@zcbenz.com> * chore: remove test debugging * chore: remove unnecessary header include * docs: add utility process net module limitations * test: run net module tests in utility process individually * refactor: clean up prior utility process net tests * chore: add resolveHost to utility process net module * chore: replace resolve host dcheck with sequence checker * test: add net module tests for net.resolveHost * docs: remove utility process limitation for resolveHost --------- Co-authored-by: deepak1556 <hop2deep@gmail.com> Co-authored-by: Cheng Zhao <github@zcbenz.com>
2024-01-04 21:20:37 +00:00
import { allowAnyProtocol } from '@electron/internal/common/api/net-client-request';
2023-02-20 20:57:38 +00:00
function createDeferredPromise<T, E extends Error = Error> (): { promise: Promise<T>; resolve: (x: T) => void; reject: (e: E) => void; } {
let res: (x: T) => void;
let rej: (e: E) => void;
const promise = new Promise<T>((resolve, reject) => {
res = resolve;
rej = reject;
});
return { promise, resolve: res!, reject: rej! };
}
feat: add net module to utility process (#40017) * chore: initial prototype of net api from utility process * chore: update url loader to work on both browser and utility processes * chore: add net files to utility process bundle * chore: re-add app ready check but only on main process * chore: replace browser thread dcheck's with sequence checker * refactor: move url loader from browser to common * refactor: move net-client-request.ts from browser to common * docs: add utility process to net api docs * refactor: move net module app ready check to browser only * refactor: switch import from main to common after moving to common * test: add basic net module test for utility process * refactor: switch browser pid with utility pid * refactor: move electron_api_net from browser to common * chore: add fetch to utility net module * chore: add isOnline and online to utility net module * refactor: move net spec helpers into helper file * refactor: break apart net module tests Adds two additional net module test files: `api-net-session-spec.ts` for tests that depend on a session being available (aka depend on running on the main process) and `api-net-custom-protocols-spec.ts` for custom protocol tests. This enables running `api-net-spec.ts` in the utility process. * test: add utility process mocha runner to run net module tests * docs: add utility process to net module classes * refactor: update imports in lib/utility to use electron/utility * chore: check browser context before using in main process Since the browser context supplied to the SimpleURLLoaderWrapper can now be null for use in the UtilityProcess, adding a null check for the main process before use to get a more sensible error if something goes wrong. Co-authored-by: Cheng Zhao <github@zcbenz.com> * chore: remove test debugging * chore: remove unnecessary header include * docs: add utility process net module limitations * test: run net module tests in utility process individually * refactor: clean up prior utility process net tests * chore: add resolveHost to utility process net module * chore: replace resolve host dcheck with sequence checker * test: add net module tests for net.resolveHost * docs: remove utility process limitation for resolveHost --------- Co-authored-by: deepak1556 <hop2deep@gmail.com> Co-authored-by: Cheng Zhao <github@zcbenz.com>
2024-01-04 21:20:37 +00:00
export function fetchWithSession (input: RequestInfo, init: (RequestInit & {bypassCustomProtocolHandlers?: boolean}) | undefined, session: SessionT | undefined,
request: (options: ClientRequestConstructorOptions | string) => ClientRequest) {
2023-02-20 20:57:38 +00:00
const p = createDeferredPromise<Response>();
let req: Request;
try {
req = new Request(input, init);
} catch (e: any) {
p.reject(e);
return p.promise;
}
if (req.signal.aborted) {
// 1. Abort the fetch() call with p, request, null, and
// requestObjects signals abort reason.
const error = (req.signal as any).reason ?? new DOMException('The operation was aborted.', 'AbortError');
p.reject(error);
if (req.body != null && isReadable(req.body as unknown as NodeJS.ReadableStream)) {
req.body.cancel(error).catch((err) => {
if (err.code === 'ERR_INVALID_STATE') {
// Node bug?
return;
}
throw err;
});
}
// 2. Return p.
return p.promise;
}
let locallyAborted = false;
req.signal.addEventListener(
'abort',
() => {
// 1. Set locallyAborted to true.
locallyAborted = true;
// 2. Abort the fetch() call with p, request, responseObject,
// and requestObjects signals abort reason.
const error = (req.signal as any).reason ?? new DOMException('The operation was aborted.', 'AbortError');
p.reject(error);
if (req.body != null && isReadable(req.body as unknown as NodeJS.ReadableStream)) {
req.body.cancel(error).catch((err) => {
if (err.code === 'ERR_INVALID_STATE') {
// Node bug?
return;
}
throw err;
});
}
r.abort();
},
{ once: true }
);
const origin = req.headers.get('origin') ?? undefined;
// We can't set credentials to same-origin unless there's an origin set.
const credentials = req.credentials === 'same-origin' && !origin ? 'include' : req.credentials;
feat: add net module to utility process (#40017) * chore: initial prototype of net api from utility process * chore: update url loader to work on both browser and utility processes * chore: add net files to utility process bundle * chore: re-add app ready check but only on main process * chore: replace browser thread dcheck's with sequence checker * refactor: move url loader from browser to common * refactor: move net-client-request.ts from browser to common * docs: add utility process to net api docs * refactor: move net module app ready check to browser only * refactor: switch import from main to common after moving to common * test: add basic net module test for utility process * refactor: switch browser pid with utility pid * refactor: move electron_api_net from browser to common * chore: add fetch to utility net module * chore: add isOnline and online to utility net module * refactor: move net spec helpers into helper file * refactor: break apart net module tests Adds two additional net module test files: `api-net-session-spec.ts` for tests that depend on a session being available (aka depend on running on the main process) and `api-net-custom-protocols-spec.ts` for custom protocol tests. This enables running `api-net-spec.ts` in the utility process. * test: add utility process mocha runner to run net module tests * docs: add utility process to net module classes * refactor: update imports in lib/utility to use electron/utility * chore: check browser context before using in main process Since the browser context supplied to the SimpleURLLoaderWrapper can now be null for use in the UtilityProcess, adding a null check for the main process before use to get a more sensible error if something goes wrong. Co-authored-by: Cheng Zhao <github@zcbenz.com> * chore: remove test debugging * chore: remove unnecessary header include * docs: add utility process net module limitations * test: run net module tests in utility process individually * refactor: clean up prior utility process net tests * chore: add resolveHost to utility process net module * chore: replace resolve host dcheck with sequence checker * test: add net module tests for net.resolveHost * docs: remove utility process limitation for resolveHost --------- Co-authored-by: deepak1556 <hop2deep@gmail.com> Co-authored-by: Cheng Zhao <github@zcbenz.com>
2024-01-04 21:20:37 +00:00
const r = request(allowAnyProtocol({
2023-02-20 20:57:38 +00:00
session,
method: req.method,
url: req.url,
origin,
credentials,
cache: req.cache,
referrerPolicy: req.referrerPolicy,
redirect: req.redirect
}));
2023-02-20 20:57:38 +00:00
2023-03-27 17:00:55 +00:00
(r as any)._urlLoaderOptions.bypassCustomProtocolHandlers = !!init?.bypassCustomProtocolHandlers;
2023-02-20 20:57:38 +00:00
// cors is the default mode, but we can't set mode=cors without an origin.
if (req.mode && (req.mode !== 'cors' || origin)) {
r.setHeader('Sec-Fetch-Mode', req.mode);
}
for (const [k, v] of req.headers) {
r.setHeader(k, v);
}
r.on('response', (resp: IncomingMessage) => {
if (locallyAborted) return;
const headers = new Headers();
for (const [k, v] of Object.entries(resp.headers)) {
headers.set(k, Array.isArray(v) ? v.join(', ') : v);
}
2023-02-20 20:57:38 +00:00
const nullBodyStatus = [101, 204, 205, 304];
const body = nullBodyStatus.includes(resp.statusCode) || req.method === 'HEAD' ? null : Readable.toWeb(resp as unknown as Readable) as ReadableStream;
const rResp = new Response(body, {
headers,
status: resp.statusCode,
statusText: resp.statusMessage
});
2023-03-27 17:00:55 +00:00
(rResp as any).__original_resp = resp;
2023-02-20 20:57:38 +00:00
p.resolve(rResp);
});
r.on('error', (err) => {
p.reject(err);
});
if (!req.body?.pipeTo(Writable.toWeb(r as unknown as Writable)).then(() => r.end())) { r.end(); }
return p.promise;
}