From fda8ea9277983836a7f96a979ca07dbcf5eec14c Mon Sep 17 00:00:00 2001 From: Jeremy Rose Date: Mon, 27 Mar 2023 10:00:55 -0700 Subject: [PATCH] feat: add protocol.handle (#36674) --- docs/api/client-request.md | 2 + docs/api/net.md | 24 +- docs/api/protocol.md | 112 ++++- docs/api/session.md | 20 +- docs/api/structures/upload-file.md | 8 +- docs/breaking-changes.md | 49 ++ lib/browser/api/net-fetch.ts | 5 +- lib/browser/api/protocol.ts | 143 +++++- patches/chromium/.patches | 1 + ...onverter_support_for_arraybufferview.patch | 60 +++ shell/browser/api/electron_api_protocol.cc | 18 +- shell/browser/api/electron_api_protocol.h | 11 +- shell/browser/api/electron_api_url_loader.cc | 21 +- shell/browser/net/node_stream_loader.cc | 7 +- shell/browser/net/node_stream_loader.h | 2 + .../net/proxying_url_loader_factory.cc | 27 +- .../browser/net/proxying_url_loader_factory.h | 2 + shell/common/gin_converters/net_converter.cc | 260 +++++++++++ shell/common/gin_helper/promise.cc | 2 + shell/common/gin_helper/promise.h | 1 + spec/api-net-spec.ts | 12 + spec/api-protocol-spec.ts | 434 +++++++++++++++++- spec/api-web-request-spec.ts | 116 ++++- typings/internal-ambient.d.ts | 1 + typings/internal-electron.d.ts | 5 + 25 files changed, 1254 insertions(+), 89 deletions(-) create mode 100644 patches/chromium/add_gin_converter_support_for_arraybufferview.patch diff --git a/docs/api/client-request.md b/docs/api/client-request.md index f1cb4ef2c2..fc14e20bb5 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -243,6 +243,8 @@ it is not allowed to add or remove a custom header. * `encoding` string (optional) * `callback` Function (optional) +Returns `this`. + Sends the last chunk of the request data. Subsequent write or end operations will not be allowed. The `finish` event is emitted just after the end operation. diff --git a/docs/api/net.md b/docs/api/net.md index a1199150b7..590c74f7e3 100644 --- a/docs/api/net.md +++ b/docs/api/net.md @@ -65,8 +65,8 @@ requests according to the specified protocol scheme in the `options` object. ### `net.fetch(input[, init])` -* `input` string | [Request](https://nodejs.org/api/globals.html#request) -* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) (optional) +* `input` string | [GlobalRequest](https://nodejs.org/api/globals.html#request) +* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) & { bypassCustomProtocolHandlers?: boolean } (optional) Returns `Promise` - see [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response). @@ -101,9 +101,23 @@ Limitations: * The `.type` and `.url` values of the returned `Response` object are incorrect. -Requests made with `net.fetch` can be made to [custom protocols](protocol.md) -as well as `file:`, and will trigger [webRequest](web-request.md) handlers if -present. +By default, requests made with `net.fetch` can be made to [custom +protocols](protocol.md) as well as `file:`, and will trigger +[webRequest](web-request.md) handlers if present. When the non-standard +`bypassCustomProtocolHandlers` option is set in RequestInit, custom protocol +handlers will not be called for this request. This allows forwarding an +intercepted request to the built-in handler. [webRequest](web-request.md) +handlers will still be triggered when bypassing custom protocols. + +```js +protocol.handle('https', (req) => { + if (req.url === 'https://my-app.com') { + return new Response('my app') + } else { + return net.fetch(req, { bypassCustomProtocolHandlers: true }) + } +}) +``` ### `net.isOnline()` diff --git a/docs/api/protocol.md b/docs/api/protocol.md index 8b0d2fbc89..4ca6b5ebb0 100644 --- a/docs/api/protocol.md +++ b/docs/api/protocol.md @@ -8,15 +8,11 @@ An example of implementing a protocol that has the same effect as the `file://` protocol: ```javascript -const { app, protocol } = require('electron') -const path = require('path') -const url = require('url') +const { app, protocol, net } = require('electron') app.whenReady().then(() => { - protocol.registerFileProtocol('atom', (request, callback) => { - const filePath = url.fileURLToPath('file://' + request.url.slice('atom://'.length)) - callback(filePath) - }) + protocol.handle('atom', (request) => + net.fetch('file://' + request.url.slice('atom://'.length))) }) ``` @@ -38,14 +34,15 @@ to register it to that session explicitly. ```javascript const { session, app, protocol } = require('electron') const path = require('path') +const url = require('url') app.whenReady().then(() => { const partition = 'persist:example' const ses = session.fromPartition(partition) - ses.protocol.registerFileProtocol('atom', (request, callback) => { - const url = request.url.substr(7) - callback({ path: path.normalize(`${__dirname}/${url}`) }) + ses.protocol.handle('atom', (request) => { + const path = request.url.slice('atom://'.length) + return net.fetch(url.pathToFileURL(path.join(__dirname, path))) }) mainWindow = new BrowserWindow({ webPreferences: { partition } }) @@ -109,7 +106,74 @@ The `