docs: move protocol-ns to protocol.md (#23883)
* docs: move protocol-ns to protocol.md * chore: fix up tests and implement missing pieces required for tests
This commit is contained in:
		
					parent
					
						
							
								edc5050a2e
							
						
					
				
			
			
				commit
				
					
						d3fa5ed1e8
					
				
			
		
					 13 changed files with 285 additions and 733 deletions
				
			
		|  | @ -1,309 +0,0 @@ | |||
| # protocol (NetworkService) (Draft) | ||||
| 
 | ||||
| This document describes the new protocol APIs based on the [NetworkService](https://www.chromium.org/servicification). | ||||
| 
 | ||||
| We don't currently have an estimate of when we will enable the `NetworkService` by | ||||
| default in Electron, but as Chromium is already removing non-`NetworkService` | ||||
| code, we will probably switch before Electron 10. | ||||
| 
 | ||||
| The content of this document should be moved to `protocol.md` after we have | ||||
| enabled the `NetworkService` by default in Electron. | ||||
| 
 | ||||
| > Register a custom protocol and intercept existing protocol requests. | ||||
| 
 | ||||
| Process: [Main](../glossary.md#main-process) | ||||
| 
 | ||||
| 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') | ||||
| 
 | ||||
| app.whenReady().then(() => { | ||||
|   protocol.registerFileProtocol('atom', (request, callback) => { | ||||
|     const url = request.url.substr(7) | ||||
|     callback({ path: path.normalize(`${__dirname}/${url}`) }) | ||||
|   }) | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
| **Note:** All methods unless specified can only be used after the `ready` event | ||||
| of the `app` module gets emitted. | ||||
| 
 | ||||
| ## Using `protocol` with a custom `partition` or `session` | ||||
| 
 | ||||
| A protocol is registered to a specific Electron [`session`](./session.md) | ||||
| object. If you don't specify a session, then your `protocol` will be applied to | ||||
| the default session that Electron uses. However, if you define a `partition` or | ||||
| `session` on your `browserWindow`'s `webPreferences`, then that window will use | ||||
| a different session and your custom protocol will not work if you just use | ||||
| `electron.protocol.XXX`. | ||||
| 
 | ||||
| To have your custom protocol work in combination with a custom session, you need | ||||
| to register it to that session explicitly. | ||||
| 
 | ||||
| ```javascript | ||||
| const { session, app, protocol } = require('electron') | ||||
| const path = require('path') | ||||
| 
 | ||||
| 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}`) }) | ||||
|   }) | ||||
| 
 | ||||
|   mainWindow = new BrowserWindow({ webPreferences: { partition } }) | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
| ## Methods | ||||
| 
 | ||||
| The `protocol` module has the following methods: | ||||
| 
 | ||||
| ### `protocol.registerSchemesAsPrivileged(customSchemes)` | ||||
| 
 | ||||
| * `customSchemes` [CustomScheme[]](structures/custom-scheme.md) | ||||
| 
 | ||||
| **Note:** This method can only be used before the `ready` event of the `app` | ||||
| module gets emitted and can be called only once. | ||||
| 
 | ||||
| Registers the `scheme` as standard, secure, bypasses content security policy for | ||||
| resources, allows registering ServiceWorker and supports fetch API. Specify a | ||||
| privilege with the value of `true` to enable the capability. | ||||
| 
 | ||||
| An example of registering a privileged scheme, that bypasses Content Security | ||||
| Policy: | ||||
| 
 | ||||
| ```javascript | ||||
| const { protocol } = require('electron') | ||||
| protocol.registerSchemesAsPrivileged([ | ||||
|   { scheme: 'foo', privileges: { bypassCSP: true } } | ||||
| ]) | ||||
| ``` | ||||
| 
 | ||||
| A standard scheme adheres to what RFC 3986 calls [generic URI | ||||
| syntax](https://tools.ietf.org/html/rfc3986#section-3). For example `http` and | ||||
| `https` are standard schemes, while `file` is not. | ||||
| 
 | ||||
| Registering a scheme as standard allows relative and absolute resources to | ||||
| be resolved correctly when served. Otherwise the scheme will behave like the | ||||
| `file` protocol, but without the ability to resolve relative URLs. | ||||
| 
 | ||||
| For example when you load following page with custom protocol without | ||||
| registering it as standard scheme, the image will not be loaded because | ||||
| non-standard schemes can not recognize relative URLs: | ||||
| 
 | ||||
| ```html | ||||
| <body> | ||||
|   <img src='test.png'> | ||||
| </body> | ||||
| ``` | ||||
| 
 | ||||
| Registering a scheme as standard will allow access to files through the | ||||
| [FileSystem API][file-system-api]. Otherwise the renderer will throw a security | ||||
| error for the scheme. | ||||
| 
 | ||||
| By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB, | ||||
| cookies) are disabled for non standard schemes. So in general if you want to | ||||
| register a custom protocol to replace the `http` protocol, you have to register | ||||
| it as a standard scheme. | ||||
| 
 | ||||
| ### `protocol.registerFileProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `response` (String | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Registers a protocol of `scheme` that will send a file as the response. The | ||||
| `handler` will be called with `request` and `callback` where `request` is | ||||
| an incoming request for the `scheme`. | ||||
| 
 | ||||
| To handle the `request`, the `callback` should be called with either the file's | ||||
| path or an object that has a `path` property, e.g. `callback(filePath)` or | ||||
| `callback({ path: filePath })`. The `filePath` must be an absolute path. | ||||
| 
 | ||||
| By default the `scheme` is treated like `http:`, which is parsed differently | ||||
| from protocols that follow the "generic URI syntax" like `file:`. | ||||
| 
 | ||||
| ### `protocol.registerBufferProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `response` (Buffer | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Registers a protocol of `scheme` that will send a `Buffer` as a response. | ||||
| 
 | ||||
| The usage is the same with `registerFileProtocol`, except that the `callback` | ||||
| should be called with either a `Buffer` object or an object that has the `data` | ||||
| property. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| ```javascript | ||||
| protocol.registerBufferProtocol('atom', (request, callback) => { | ||||
|   callback({ mimeType: 'text/html', data: Buffer.from('<h5>Response</h5>') }) | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
| ### `protocol.registerStringProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `response` (String | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Registers a protocol of `scheme` that will send a `String` as a response. | ||||
| 
 | ||||
| The usage is the same with `registerFileProtocol`, except that the `callback` | ||||
| should be called with either a `String` or an object that has the `data` | ||||
| property. | ||||
| 
 | ||||
| ### `protocol.registerHttpProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `response` ProtocolResponse | ||||
| 
 | ||||
| Registers a protocol of `scheme` that will send an HTTP request as a response. | ||||
| 
 | ||||
| The usage is the same with `registerFileProtocol`, except that the `callback` | ||||
| should be called with an object that has the `url` property. | ||||
| 
 | ||||
| ### `protocol.registerStreamProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `response` (ReadableStream | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Registers a protocol of `scheme` that will send a stream as a response. | ||||
| 
 | ||||
| The usage is the same with `registerFileProtocol`, except that the | ||||
| `callback` should be called with either a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_class_stream_readable) object or an object that | ||||
| has the `data` property. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| ```javascript | ||||
| const { protocol } = require('electron') | ||||
| const { PassThrough } = require('stream') | ||||
| 
 | ||||
| function createStream (text) { | ||||
|   const rv = new PassThrough() // PassThrough is also a Readable stream | ||||
|   rv.push(text) | ||||
|   rv.push(null) | ||||
|   return rv | ||||
| } | ||||
| 
 | ||||
| protocol.registerStreamProtocol('atom', (request, callback) => { | ||||
|   callback({ | ||||
|     statusCode: 200, | ||||
|     headers: { | ||||
|       'content-type': 'text/html' | ||||
|     }, | ||||
|     data: createStream('<h5>Response</h5>') | ||||
|   }) | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
| It is possible to pass any object that implements the readable stream API (emits | ||||
| `data`/`end`/`error` events). For example, here's how a file could be returned: | ||||
| 
 | ||||
| ```javascript | ||||
| protocol.registerStreamProtocol('atom', (request, callback) => { | ||||
|   callback(fs.createReadStream('index.html')) | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
| ### `protocol.unregisterProtocol(scheme)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| 
 | ||||
| Unregisters the custom protocol of `scheme`. | ||||
| 
 | ||||
| ### `protocol.isProtocolRegistered(scheme)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| 
 | ||||
| Returns `Boolean` - Whether `scheme` is already registered. | ||||
| 
 | ||||
| ### `protocol.interceptFileProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `response` (String | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Intercepts `scheme` protocol and uses `handler` as the protocol's new handler | ||||
| which sends a file as a response. | ||||
| 
 | ||||
| ### `protocol.interceptStringProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `response` (String | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Intercepts `scheme` protocol and uses `handler` as the protocol's new handler | ||||
| which sends a `String` as a response. | ||||
| 
 | ||||
| ### `protocol.interceptBufferProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `response` (Buffer | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Intercepts `scheme` protocol and uses `handler` as the protocol's new handler | ||||
| which sends a `Buffer` as a response. | ||||
| 
 | ||||
| ### `protocol.interceptHttpProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `response` ProtocolResponse | ||||
| 
 | ||||
| Intercepts `scheme` protocol and uses `handler` as the protocol's new handler | ||||
| which sends a new HTTP request as a response. | ||||
| 
 | ||||
| ### `protocol.interceptStreamProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `response` (ReadableStream | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Same as `protocol.registerStreamProtocol`, except that it replaces an existing | ||||
| protocol handler. | ||||
| 
 | ||||
| ### `protocol.uninterceptProtocol(scheme)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| 
 | ||||
| Remove the interceptor installed for `scheme` and restore its original handler. | ||||
| 
 | ||||
| ### `protocol.isProtocolIntercepted(scheme)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| 
 | ||||
| Returns `Boolean` - Whether `scheme` is already intercepted. | ||||
| 
 | ||||
| [file-system-api]: https://developer.mozilla.org/en-US/docs/Web/API/LocalFileSystem | ||||
|  | @ -15,8 +15,6 @@ app.whenReady().then(() => { | |||
|   protocol.registerFileProtocol('atom', (request, callback) => { | ||||
|     const url = request.url.substr(7) | ||||
|     callback({ path: path.normalize(`${__dirname}/${url}`) }) | ||||
|   }, (error) => { | ||||
|     if (error) console.error('Failed to register protocol') | ||||
|   }) | ||||
| }) | ||||
| ``` | ||||
|  | @ -26,9 +24,15 @@ of the `app` module gets emitted. | |||
| 
 | ||||
| ## Using `protocol` with a custom `partition` or `session` | ||||
| 
 | ||||
| A protocol is registered to a specific Electron [`session`](./session.md) object. If you don't specify a session, then your `protocol` will be applied to the default session that Electron uses. However, if you define a `partition` or `session` on your `browserWindow`'s `webPreferences`, then that window will use a different session and your custom protocol will not work if you just use `electron.protocol.XXX`. | ||||
| A protocol is registered to a specific Electron [`session`](./session.md) | ||||
| object. If you don't specify a session, then your `protocol` will be applied to | ||||
| the default session that Electron uses. However, if you define a `partition` or | ||||
| `session` on your `browserWindow`'s `webPreferences`, then that window will use | ||||
| a different session and your custom protocol will not work if you just use | ||||
| `electron.protocol.XXX`. | ||||
| 
 | ||||
| To have your custom protocol work in combination with a custom session, you need to register it to that session explicitly. | ||||
| To have your custom protocol work in combination with a custom session, you need | ||||
| to register it to that session explicitly. | ||||
| 
 | ||||
| ```javascript | ||||
| const { session, app, protocol } = require('electron') | ||||
|  | @ -41,17 +45,9 @@ app.whenReady().then(() => { | |||
|   ses.protocol.registerFileProtocol('atom', (request, callback) => { | ||||
|     const url = request.url.substr(7) | ||||
|     callback({ path: path.normalize(`${__dirname}/${url}`) }) | ||||
|   }, (error) => { | ||||
|     if (error) console.error('Failed to register protocol') | ||||
|   }) | ||||
| 
 | ||||
|   mainWindow = new BrowserWindow({ | ||||
|     width: 800, | ||||
|     height: 600, | ||||
|     webPreferences: { | ||||
|       partition: partition | ||||
|     } | ||||
|   }) | ||||
|   mainWindow = new BrowserWindow({ webPreferences: { partition } }) | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
|  | @ -63,15 +59,15 @@ The `protocol` module has the following methods: | |||
| 
 | ||||
| * `customSchemes` [CustomScheme[]](structures/custom-scheme.md) | ||||
| 
 | ||||
| 
 | ||||
| **Note:** This method can only be used before the `ready` event of the `app` | ||||
| module gets emitted and can be called only once. | ||||
| 
 | ||||
| Registers the `scheme` as standard, secure, bypasses content security policy for resources, | ||||
| allows registering ServiceWorker and supports fetch API. | ||||
| Registers the `scheme` as standard, secure, bypasses content security policy for | ||||
| resources, allows registering ServiceWorker and supports fetch API. Specify a | ||||
| privilege with the value of `true` to enable the capability. | ||||
| 
 | ||||
| Specify a privilege with the value of `true` to enable the capability. | ||||
| An example of registering a privileged scheme, with bypassing Content Security Policy: | ||||
| An example of registering a privileged scheme, that bypasses Content Security | ||||
| Policy: | ||||
| 
 | ||||
| ```javascript | ||||
| const { protocol } = require('electron') | ||||
|  | @ -84,7 +80,7 @@ A standard scheme adheres to what RFC 3986 calls [generic URI | |||
| syntax](https://tools.ietf.org/html/rfc3986#section-3). For example `http` and | ||||
| `https` are standard schemes, while `file` is not. | ||||
| 
 | ||||
| Registering a scheme as standard, will allow relative and absolute resources to | ||||
| Registering a scheme as standard allows relative and absolute resources to | ||||
| be resolved correctly when served. Otherwise the scheme will behave like the | ||||
| `file` protocol, but without the ability to resolve relative URLs. | ||||
| 
 | ||||
|  | @ -102,168 +98,102 @@ Registering a scheme as standard will allow access to files through the | |||
| [FileSystem API][file-system-api]. Otherwise the renderer will throw a security | ||||
| error for the scheme. | ||||
| 
 | ||||
| By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB, cookies) | ||||
| are disabled for non standard schemes. So in general if you want to register a | ||||
| custom protocol to replace the `http` protocol, you have to register it as a standard scheme. | ||||
| By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB, | ||||
| cookies) are disabled for non standard schemes. So in general if you want to | ||||
| register a custom protocol to replace the `http` protocol, you have to register | ||||
| it as a standard scheme. | ||||
| 
 | ||||
| `protocol.registerSchemesAsPrivileged` can be used to replicate the functionality of the previous `protocol.registerStandardSchemes`, `webFrame.registerURLSchemeAs*` and `protocol.registerServiceWorkerSchemes` functions that existed prior to Electron 5.0.0, for example: | ||||
| 
 | ||||
| **before (<= v4.x)** | ||||
| ```javascript | ||||
| // Main | ||||
| protocol.registerStandardSchemes(['scheme1', 'scheme2'], { secure: true }) | ||||
| // Renderer | ||||
| webFrame.registerURLSchemeAsPrivileged('scheme1', { secure: true }) | ||||
| webFrame.registerURLSchemeAsPrivileged('scheme2', { secure: true }) | ||||
| ``` | ||||
| 
 | ||||
| **after (>= v5.x)** | ||||
| ```javascript | ||||
| protocol.registerSchemesAsPrivileged([ | ||||
|   { scheme: 'scheme1', privileges: { standard: true, secure: true } }, | ||||
|   { scheme: 'scheme2', privileges: { standard: true, secure: true } } | ||||
| ]) | ||||
| ``` | ||||
| 
 | ||||
| ### `protocol.registerFileProtocol(scheme, handler[, completion])` | ||||
| ### `protocol.registerFileProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` Object | ||||
|     * `url` String | ||||
|     * `headers` Record<String, String> | ||||
|     * `referrer` String | ||||
|     * `method` String | ||||
|     * `uploadData` [UploadData[]](structures/upload-data.md) | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `filePath` String | [FilePathWithHeaders](structures/file-path-with-headers.md) (optional) | ||||
| * `completion` Function (optional) | ||||
|   * `error` Error | ||||
|     * `response` (String | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Registers a protocol of `scheme` that will send the file as a response. The | ||||
| `handler` will be called with `handler(request, callback)` when a `request` is | ||||
| going to be created with `scheme`. `completion` will be called with | ||||
| `completion(null)` when `scheme` is successfully registered or | ||||
| `completion(error)` when failed. | ||||
| Returns `Boolean` - Whether the protocol was successfully registered | ||||
| 
 | ||||
| Registers a protocol of `scheme` that will send a file as the response. The | ||||
| `handler` will be called with `request` and `callback` where `request` is | ||||
| an incoming request for the `scheme`. | ||||
| 
 | ||||
| To handle the `request`, the `callback` should be called with either the file's | ||||
| path or an object that has a `path` property, e.g. `callback(filePath)` or | ||||
| `callback({ path: filePath })`. The object may also have a `headers` property | ||||
| which gives a map of headers to values for the response headers, e.g. | ||||
| `callback({ path: filePath, headers: {"Content-Security-Policy": "default-src 'none'"]})`. | ||||
| 
 | ||||
| When `callback` is called with nothing, a number, or an object that has an | ||||
| `error` property, the `request` will fail with the `error` number you | ||||
| specified. For the available error numbers you can use, please see the | ||||
| [net error list][net-error]. | ||||
| `callback({ path: filePath })`. The `filePath` must be an absolute path. | ||||
| 
 | ||||
| By default the `scheme` is treated like `http:`, which is parsed differently | ||||
| than protocols that follow the "generic URI syntax" like `file:`. | ||||
| from protocols that follow the "generic URI syntax" like `file:`. | ||||
| 
 | ||||
| ### `protocol.registerBufferProtocol(scheme, handler[, completion])` | ||||
| ### `protocol.registerBufferProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` Object | ||||
|     * `url` String | ||||
|     * `headers` Record<String, String> | ||||
|     * `referrer` String | ||||
|     * `method` String | ||||
|     * `uploadData` [UploadData[]](structures/upload-data.md) | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `buffer` (Buffer | [MimeTypedBuffer](structures/mime-typed-buffer.md)) (optional) | ||||
| * `completion` Function (optional) | ||||
|   * `error` Error | ||||
|     * `response` (Buffer | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Returns `Boolean` - Whether the protocol was successfully registered | ||||
| 
 | ||||
| Registers a protocol of `scheme` that will send a `Buffer` as a response. | ||||
| 
 | ||||
| The usage is the same with `registerFileProtocol`, except that the `callback` | ||||
| should be called with either a `Buffer` object or an object that has the `data`, | ||||
| `mimeType`, and `charset` properties. | ||||
| should be called with either a `Buffer` object or an object that has the `data` | ||||
| property. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| ```javascript | ||||
| const { protocol } = require('electron') | ||||
| 
 | ||||
| protocol.registerBufferProtocol('atom', (request, callback) => { | ||||
|   callback({ mimeType: 'text/html', data: Buffer.from('<h5>Response</h5>') }) | ||||
| }, (error) => { | ||||
|   if (error) console.error('Failed to register protocol') | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
| ### `protocol.registerStringProtocol(scheme, handler[, completion])` | ||||
| ### `protocol.registerStringProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` Object | ||||
|     * `url` String | ||||
|     * `headers` Record<String, String> | ||||
|     * `referrer` String | ||||
|     * `method` String | ||||
|     * `uploadData` [UploadData[]](structures/upload-data.md) | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `data` (String | [StringProtocolResponse](structures/string-protocol-response.md)) (optional) | ||||
| * `completion` Function (optional) | ||||
|   * `error` Error | ||||
|     * `response` (String | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Returns `Boolean` - Whether the protocol was successfully registered | ||||
| 
 | ||||
| Registers a protocol of `scheme` that will send a `String` as a response. | ||||
| 
 | ||||
| The usage is the same with `registerFileProtocol`, except that the `callback` | ||||
| should be called with either a `String` or an object that has the `data`, | ||||
| `mimeType`, and `charset` properties. | ||||
| should be called with either a `String` or an object that has the `data` | ||||
| property. | ||||
| 
 | ||||
| ### `protocol.registerHttpProtocol(scheme, handler[, completion])` | ||||
| ### `protocol.registerHttpProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` Object | ||||
|     * `url` String | ||||
|     * `headers` Record<String, String> | ||||
|     * `referrer` String | ||||
|     * `method` String | ||||
|     * `uploadData` [UploadData[]](structures/upload-data.md) | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `redirectRequest` Object | ||||
|       * `url` String | ||||
|       * `method` String (optional) | ||||
|       * `session` Session | null (optional) | ||||
|       * `uploadData` [ProtocolResponseUploadData](structures/protocol-response-upload-data.md) (optional) | ||||
| * `completion` Function (optional) | ||||
|   * `error` Error | ||||
|     * `response` ProtocolResponse | ||||
| 
 | ||||
| Returns `Boolean` - Whether the protocol was successfully registered | ||||
| 
 | ||||
| Registers a protocol of `scheme` that will send an HTTP request as a response. | ||||
| 
 | ||||
| The usage is the same with `registerFileProtocol`, except that the `callback` | ||||
| should be called with a `redirectRequest` object that has the `url`, `method`, | ||||
| `referrer`, `uploadData` and `session` properties. | ||||
| should be called with an object that has the `url` property. | ||||
| 
 | ||||
| By default the HTTP request will reuse the current session. If you want the | ||||
| request to have a different session you should set `session` to `null`. | ||||
| 
 | ||||
| For POST requests the `uploadData` object must be provided. | ||||
| 
 | ||||
| ### `protocol.registerStreamProtocol(scheme, handler[, completion])` | ||||
| ### `protocol.registerStreamProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` Object | ||||
|     * `url` String | ||||
|     * `headers` Record<String, String> | ||||
|     * `referrer` String | ||||
|     * `method` String | ||||
|     * `uploadData` [UploadData[]](structures/upload-data.md) | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `stream` (ReadableStream | [StreamProtocolResponse](structures/stream-protocol-response.md)) (optional) | ||||
| * `completion` Function (optional) | ||||
|   * `error` Error | ||||
|     * `response` (ReadableStream | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Registers a protocol of `scheme` that will send a `Readable` as a response. | ||||
| Returns `Boolean` - Whether the protocol was successfully registered | ||||
| 
 | ||||
| The usage is similar to the other `register{Any}Protocol`, except that the | ||||
| `callback` should be called with either a `Readable` object or an object that | ||||
| has the `data`, `statusCode`, and `headers` properties. | ||||
| Registers a protocol of `scheme` that will send a stream as a response. | ||||
| 
 | ||||
| The usage is the same with `registerFileProtocol`, except that the | ||||
| `callback` should be called with either a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_class_stream_readable) object or an object that | ||||
| has the `data` property. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
|  | @ -286,8 +216,6 @@ protocol.registerStreamProtocol('atom', (request, callback) => { | |||
|     }, | ||||
|     data: createStream('<h5>Response</h5>') | ||||
|   }) | ||||
| }, (error) => { | ||||
|   if (error) console.error('Failed to register protocol') | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
|  | @ -295,132 +223,102 @@ It is possible to pass any object that implements the readable stream API (emits | |||
| `data`/`end`/`error` events). For example, here's how a file could be returned: | ||||
| 
 | ||||
| ```javascript | ||||
| const { protocol } = require('electron') | ||||
| const fs = require('fs') | ||||
| 
 | ||||
| protocol.registerStreamProtocol('atom', (request, callback) => { | ||||
|   callback(fs.createReadStream('index.html')) | ||||
| }, (error) => { | ||||
|   if (error) console.error('Failed to register protocol') | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
| ### `protocol.unregisterProtocol(scheme[, completion])` | ||||
| ### `protocol.unregisterProtocol(scheme)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `completion` Function (optional) | ||||
|   * `error` Error | ||||
| 
 | ||||
| Returns `Boolean` - Whether the protocol was successfully unregistered | ||||
| 
 | ||||
| Unregisters the custom protocol of `scheme`. | ||||
| 
 | ||||
| ### `protocol.isProtocolHandled(scheme)` | ||||
| ### `protocol.isProtocolRegistered(scheme)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| 
 | ||||
| Returns `Promise<Boolean>` - fulfilled with a boolean that indicates whether there is | ||||
| already a handler for `scheme`. | ||||
| Returns `Boolean` - Whether `scheme` is already registered. | ||||
| 
 | ||||
| ### `protocol.interceptFileProtocol(scheme, handler[, completion])` | ||||
| ### `protocol.interceptFileProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` Object | ||||
|     * `url` String | ||||
|     * `headers` Record<String, String> | ||||
|     * `referrer` String | ||||
|     * `method` String | ||||
|     * `uploadData` [UploadData[]](structures/upload-data.md) | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `filePath` String | ||||
| * `completion` Function (optional) | ||||
|   * `error` Error | ||||
|     * `response` (String | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Returns `Boolean` - Whether the protocol was successfully intercepted | ||||
| 
 | ||||
| Intercepts `scheme` protocol and uses `handler` as the protocol's new handler | ||||
| which sends a file as a response. | ||||
| 
 | ||||
| ### `protocol.interceptStringProtocol(scheme, handler[, completion])` | ||||
| ### `protocol.interceptStringProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` Object | ||||
|     * `url` String | ||||
|     * `headers` Record<String, String> | ||||
|     * `referrer` String | ||||
|     * `method` String | ||||
|     * `uploadData` [UploadData[]](structures/upload-data.md) | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `data` (String | [StringProtocolResponse](structures/string-protocol-response.md)) (optional) | ||||
| * `completion` Function (optional) | ||||
|   * `error` Error | ||||
|     * `response` (String | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Returns `Boolean` - Whether the protocol was successfully intercepted | ||||
| 
 | ||||
| Intercepts `scheme` protocol and uses `handler` as the protocol's new handler | ||||
| which sends a `String` as a response. | ||||
| 
 | ||||
| ### `protocol.interceptBufferProtocol(scheme, handler[, completion])` | ||||
| ### `protocol.interceptBufferProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` Object | ||||
|     * `url` String | ||||
|     * `headers` Record<String, String> | ||||
|     * `referrer` String | ||||
|     * `method` String | ||||
|     * `uploadData` [UploadData[]](structures/upload-data.md) | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `buffer` Buffer (optional) | ||||
| * `completion` Function (optional) | ||||
|   * `error` Error | ||||
|     * `response` (Buffer | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Returns `Boolean` - Whether the protocol was successfully intercepted | ||||
| 
 | ||||
| Intercepts `scheme` protocol and uses `handler` as the protocol's new handler | ||||
| which sends a `Buffer` as a response. | ||||
| 
 | ||||
| ### `protocol.interceptHttpProtocol(scheme, handler[, completion])` | ||||
| ### `protocol.interceptHttpProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` Object | ||||
|     * `url` String | ||||
|     * `headers` Record<String, String> | ||||
|     * `referrer` String | ||||
|     * `method` String | ||||
|     * `uploadData` [UploadData[]](structures/upload-data.md) | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `redirectRequest` Object | ||||
|       * `url` String | ||||
|       * `method` String (optional) | ||||
|       * `session` Session | null (optional) | ||||
|       * `uploadData` [ProtocolResponseUploadData](structures/protocol-response-upload-data.md) (optional) | ||||
| * `completion` Function (optional) | ||||
|   * `error` Error | ||||
|     * `response` [ProtocolResponse](structures/protocol-response.md) | ||||
| 
 | ||||
| Returns `Boolean` - Whether the protocol was successfully intercepted | ||||
| 
 | ||||
| Intercepts `scheme` protocol and uses `handler` as the protocol's new handler | ||||
| which sends a new HTTP request as a response. | ||||
| 
 | ||||
| ### `protocol.interceptStreamProtocol(scheme, handler[, completion])` | ||||
| ### `protocol.interceptStreamProtocol(scheme, handler)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `handler` Function | ||||
|   * `request` Object | ||||
|     * `url` String | ||||
|     * `headers` Record<String, String> | ||||
|     * `referrer` String | ||||
|     * `method` String | ||||
|     * `uploadData` [UploadData[]](structures/upload-data.md) | ||||
|   * `request` ProtocolRequest | ||||
|   * `callback` Function | ||||
|     * `stream` (ReadableStream | [StreamProtocolResponse](structures/stream-protocol-response.md)) (optional) | ||||
| * `completion` Function (optional) | ||||
|   * `error` Error | ||||
|     * `response` (ReadableStream | [ProtocolResponse](structures/protocol-response.md)) | ||||
| 
 | ||||
| Returns `Boolean` - Whether the protocol was successfully intercepted | ||||
| 
 | ||||
| Same as `protocol.registerStreamProtocol`, except that it replaces an existing | ||||
| protocol handler. | ||||
| 
 | ||||
| ### `protocol.uninterceptProtocol(scheme[, completion])` | ||||
| ### `protocol.uninterceptProtocol(scheme)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| * `completion` Function (optional) | ||||
|   * `error` Error | ||||
| 
 | ||||
| Returns `Boolean` - Whether the protocol was successfully unintercepted | ||||
| 
 | ||||
| Remove the interceptor installed for `scheme` and restore its original handler. | ||||
| 
 | ||||
| [net-error]: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h | ||||
| ### `protocol.isProtocolIntercepted(scheme)` | ||||
| 
 | ||||
| * `scheme` String | ||||
| 
 | ||||
| Returns `Boolean` - Whether `scheme` is already intercepted. | ||||
| 
 | ||||
| [file-system-api]: https://developer.mozilla.org/en-US/docs/Web/API/LocalFileSystem | ||||
|  |  | |||
|  | @ -4,3 +4,4 @@ | |||
| * `referrer` String | ||||
| * `method` String | ||||
| * `uploadData` [UploadData[]](upload-data.md) (optional) | ||||
| * `headers` Record<String, String> | ||||
|  |  | |||
|  | @ -43,7 +43,6 @@ auto_filenames = { | |||
|     "docs/api/power-monitor.md", | ||||
|     "docs/api/power-save-blocker.md", | ||||
|     "docs/api/process.md", | ||||
|     "docs/api/protocol-ns.md", | ||||
|     "docs/api/protocol.md", | ||||
|     "docs/api/remote.md", | ||||
|     "docs/api/sandbox-option.md", | ||||
|  |  | |||
|  | @ -176,11 +176,12 @@ ProtocolError Protocol::RegisterProtocol(ProtocolType type, | |||
|   return added ? ProtocolError::OK : ProtocolError::REGISTERED; | ||||
| } | ||||
| 
 | ||||
| void Protocol::UnregisterProtocol(const std::string& scheme, | ||||
| bool Protocol::UnregisterProtocol(const std::string& scheme, | ||||
|                                   gin::Arguments* args) { | ||||
|   bool removed = protocol_registry_->UnregisterProtocol(scheme); | ||||
|   HandleOptionalCallback( | ||||
|       args, removed ? ProtocolError::OK : ProtocolError::NOT_REGISTERED); | ||||
|   return removed; | ||||
| } | ||||
| 
 | ||||
| bool Protocol::IsProtocolRegistered(const std::string& scheme) { | ||||
|  | @ -194,11 +195,12 @@ ProtocolError Protocol::InterceptProtocol(ProtocolType type, | |||
|   return added ? ProtocolError::OK : ProtocolError::INTERCEPTED; | ||||
| } | ||||
| 
 | ||||
| void Protocol::UninterceptProtocol(const std::string& scheme, | ||||
| bool Protocol::UninterceptProtocol(const std::string& scheme, | ||||
|                                    gin::Arguments* args) { | ||||
|   bool removed = protocol_registry_->UninterceptProtocol(scheme); | ||||
|   HandleOptionalCallback( | ||||
|       args, removed ? ProtocolError::OK : ProtocolError::NOT_INTERCEPTED); | ||||
|   return removed; | ||||
| } | ||||
| 
 | ||||
| bool Protocol::IsProtocolIntercepted(const std::string& scheme) { | ||||
|  |  | |||
|  | @ -58,13 +58,13 @@ class Protocol : public gin::Wrappable<Protocol> { | |||
|   ProtocolError RegisterProtocol(ProtocolType type, | ||||
|                                  const std::string& scheme, | ||||
|                                  const ProtocolHandler& handler); | ||||
|   void UnregisterProtocol(const std::string& scheme, gin::Arguments* args); | ||||
|   bool UnregisterProtocol(const std::string& scheme, gin::Arguments* args); | ||||
|   bool IsProtocolRegistered(const std::string& scheme); | ||||
| 
 | ||||
|   ProtocolError InterceptProtocol(ProtocolType type, | ||||
|                                   const std::string& scheme, | ||||
|                                   const ProtocolHandler& handler); | ||||
|   void UninterceptProtocol(const std::string& scheme, gin::Arguments* args); | ||||
|   bool UninterceptProtocol(const std::string& scheme, gin::Arguments* args); | ||||
|   bool IsProtocolIntercepted(const std::string& scheme); | ||||
| 
 | ||||
|   // Old async version of IsProtocolRegistered.
 | ||||
|  | @ -73,16 +73,20 @@ class Protocol : public gin::Wrappable<Protocol> { | |||
| 
 | ||||
|   // Helper for converting old registration APIs to new RegisterProtocol API.
 | ||||
|   template <ProtocolType type> | ||||
|   void RegisterProtocolFor(const std::string& scheme, | ||||
|   bool RegisterProtocolFor(const std::string& scheme, | ||||
|                            const ProtocolHandler& handler, | ||||
|                            gin::Arguments* args) { | ||||
|     HandleOptionalCallback(args, RegisterProtocol(type, scheme, handler)); | ||||
|     auto result = RegisterProtocol(type, scheme, handler); | ||||
|     HandleOptionalCallback(args, result); | ||||
|     return result == ProtocolError::OK; | ||||
|   } | ||||
|   template <ProtocolType type> | ||||
|   void InterceptProtocolFor(const std::string& scheme, | ||||
|   bool InterceptProtocolFor(const std::string& scheme, | ||||
|                             const ProtocolHandler& handler, | ||||
|                             gin::Arguments* args) { | ||||
|     HandleOptionalCallback(args, InterceptProtocol(type, scheme, handler)); | ||||
|     auto result = InterceptProtocol(type, scheme, handler); | ||||
|     HandleOptionalCallback(args, result); | ||||
|     return result == ProtocolError::OK; | ||||
|   } | ||||
| 
 | ||||
|   // Be compatible with old interface, which accepts optional callback.
 | ||||
|  |  | |||
|  | @ -241,10 +241,10 @@ describe('BrowserWindow module', () => { | |||
|     let w = null as unknown as BrowserWindow; | ||||
|     const scheme = 'other'; | ||||
|     const srcPath = path.join(fixtures, 'api', 'loaded-from-dataurl.js'); | ||||
|     before((done) => { | ||||
|     before(() => { | ||||
|       protocol.registerFileProtocol(scheme, (request, callback) => { | ||||
|         callback(srcPath); | ||||
|       }, (error) => done(error)); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     after(() => { | ||||
|  | @ -2532,26 +2532,20 @@ describe('BrowserWindow module', () => { | |||
|           ['foo', path.join(fixtures, 'api', 'window-open-location-change.html')], | ||||
|           ['bar', path.join(fixtures, 'api', 'window-open-location-final.html')] | ||||
|         ]; | ||||
|         beforeEach(async () => { | ||||
|           await Promise.all(protocols.map(([scheme, path]) => new Promise((resolve, reject) => { | ||||
|         beforeEach(() => { | ||||
|           for (const [scheme, path] of protocols) { | ||||
|             protocol.registerBufferProtocol(scheme, (request, callback) => { | ||||
|               callback({ | ||||
|                 mimeType: 'text/html', | ||||
|                 data: fs.readFileSync(path) | ||||
|               }); | ||||
|             }, (error) => { | ||||
|               if (error != null) { | ||||
|                 reject(error); | ||||
|               } else { | ||||
|                 resolve(); | ||||
|               } | ||||
|             }); | ||||
|           }))); | ||||
|           } | ||||
|         }); | ||||
|         afterEach(async () => { | ||||
|           await Promise.all(protocols.map(([scheme]) => { | ||||
|             return new Promise(resolve => protocol.unregisterProtocol(scheme, () => resolve())); | ||||
|           })); | ||||
|         afterEach(() => { | ||||
|           for (const [scheme] of protocols) { | ||||
|             protocol.unregisterProtocol(scheme); | ||||
|           } | ||||
|         }); | ||||
|         it('retains the original web preferences when window.location is changed to a new origin', async () => { | ||||
|           const w = new BrowserWindow({ | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| import { expect } from 'chai'; | ||||
| import { protocol, webContents, WebContents, session, BrowserWindow, ipcMain } from 'electron/main'; | ||||
| import { promisify } from 'util'; | ||||
| import { AddressInfo } from 'net'; | ||||
| import * as ChildProcess from 'child_process'; | ||||
| import * as path from 'path'; | ||||
|  | @ -13,17 +12,17 @@ import { emittedOnce } from './events-helpers'; | |||
| 
 | ||||
| const fixturesPath = path.resolve(__dirname, '..', 'spec', 'fixtures'); | ||||
| 
 | ||||
| const registerStringProtocol = promisify(protocol.registerStringProtocol); | ||||
| const registerBufferProtocol = promisify(protocol.registerBufferProtocol); | ||||
| const registerFileProtocol = promisify(protocol.registerFileProtocol); | ||||
| const registerHttpProtocol = promisify(protocol.registerHttpProtocol); | ||||
| const registerStreamProtocol = promisify(protocol.registerStreamProtocol); | ||||
| const interceptStringProtocol = promisify(protocol.interceptStringProtocol); | ||||
| const interceptBufferProtocol = promisify(protocol.interceptBufferProtocol); | ||||
| const interceptHttpProtocol = promisify(protocol.interceptHttpProtocol); | ||||
| const interceptStreamProtocol = promisify(protocol.interceptStreamProtocol); | ||||
| const unregisterProtocol = promisify(protocol.unregisterProtocol); | ||||
| const uninterceptProtocol = promisify(protocol.uninterceptProtocol); | ||||
| const registerStringProtocol = protocol.registerStringProtocol; | ||||
| const registerBufferProtocol = protocol.registerBufferProtocol; | ||||
| const registerFileProtocol = protocol.registerFileProtocol; | ||||
| const registerHttpProtocol = protocol.registerHttpProtocol; | ||||
| const registerStreamProtocol = protocol.registerStreamProtocol; | ||||
| const interceptStringProtocol = protocol.interceptStringProtocol; | ||||
| const interceptBufferProtocol = protocol.interceptBufferProtocol; | ||||
| const interceptHttpProtocol = protocol.interceptHttpProtocol; | ||||
| const interceptStreamProtocol = protocol.interceptStreamProtocol; | ||||
| const unregisterProtocol = protocol.unregisterProtocol; | ||||
| const uninterceptProtocol = protocol.uninterceptProtocol; | ||||
| 
 | ||||
| const text = 'valar morghulis'; | ||||
| const protocolName = 'sp'; | ||||
|  | @ -87,22 +86,22 @@ describe('protocol module', () => { | |||
|     return contents.executeJavaScript(`ajax("${url}", ${JSON.stringify(options)})`); | ||||
|   } | ||||
| 
 | ||||
|   afterEach(async () => { | ||||
|     await new Promise(resolve => protocol.unregisterProtocol(protocolName, (/* ignore error */) => resolve())); | ||||
|     await new Promise(resolve => protocol.uninterceptProtocol('http', () => resolve())); | ||||
|   afterEach(() => { | ||||
|     protocol.unregisterProtocol(protocolName); | ||||
|     protocol.uninterceptProtocol('http'); | ||||
|   }); | ||||
| 
 | ||||
|   describe('protocol.register(Any)Protocol', () => { | ||||
|     it('throws error when scheme is already registered', async () => { | ||||
|       await registerStringProtocol(protocolName, (req, cb) => cb()); | ||||
|       await expect(registerBufferProtocol(protocolName, (req, cb) => cb())).to.be.eventually.rejectedWith(Error); | ||||
|     it('fails when scheme is already registered', () => { | ||||
|       expect(registerStringProtocol(protocolName, (req, cb) => cb(''))).to.equal(true); | ||||
|       expect(registerBufferProtocol(protocolName, (req, cb) => cb(Buffer.from('')))).to.equal(false); | ||||
|     }); | ||||
| 
 | ||||
|     it('does not crash when handler is called twice', async () => { | ||||
|       await registerStringProtocol(protocolName, (request, callback) => { | ||||
|       registerStringProtocol(protocolName, (request, callback) => { | ||||
|         try { | ||||
|           callback(text); | ||||
|           callback(); | ||||
|           callback(''); | ||||
|         } catch (error) { | ||||
|           // Ignore error
 | ||||
|         } | ||||
|  | @ -112,12 +111,12 @@ describe('protocol module', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('sends error when callback is called with nothing', async () => { | ||||
|       await registerBufferProtocol(protocolName, (req, cb) => cb()); | ||||
|       await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); | ||||
|       registerBufferProtocol(protocolName, (req, cb: any) => cb()); | ||||
|       await expect(ajax(protocolName + '://fake-host')).to.eventually.be.rejectedWith(Error, '404'); | ||||
|     }); | ||||
| 
 | ||||
|     it('does not crash when callback is called in next tick', async () => { | ||||
|       await registerStringProtocol(protocolName, (request, callback) => { | ||||
|       registerStringProtocol(protocolName, (request, callback) => { | ||||
|         setImmediate(() => callback(text)); | ||||
|       }); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|  | @ -126,27 +125,27 @@ describe('protocol module', () => { | |||
|   }); | ||||
| 
 | ||||
|   describe('protocol.unregisterProtocol', () => { | ||||
|     it('returns error when scheme does not exist', async () => { | ||||
|       await expect(unregisterProtocol('not-exist')).to.be.eventually.rejectedWith(Error); | ||||
|     it('returns false when scheme does not exist', () => { | ||||
|       expect(unregisterProtocol('not-exist')).to.equal(false); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('protocol.registerStringProtocol', () => { | ||||
|     it('sends string as response', async () => { | ||||
|       await registerStringProtocol(protocolName, (request, callback) => callback(text)); | ||||
|       registerStringProtocol(protocolName, (request, callback) => callback(text)); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|       expect(r.data).to.equal(text); | ||||
|     }); | ||||
| 
 | ||||
|     it('sets Access-Control-Allow-Origin', async () => { | ||||
|       await registerStringProtocol(protocolName, (request, callback) => callback(text)); | ||||
|       registerStringProtocol(protocolName, (request, callback) => callback(text)); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|       expect(r.data).to.equal(text); | ||||
|       expect(r.headers).to.include('access-control-allow-origin: *'); | ||||
|     }); | ||||
| 
 | ||||
|     it('sends object as response', async () => { | ||||
|       await registerStringProtocol(protocolName, (request, callback) => { | ||||
|       registerStringProtocol(protocolName, (request, callback) => { | ||||
|         callback({ | ||||
|           data: text, | ||||
|           mimeType: 'text/html' | ||||
|  | @ -158,7 +157,7 @@ describe('protocol module', () => { | |||
| 
 | ||||
|     it('fails when sending object other than string', async () => { | ||||
|       const notAString = () => {}; | ||||
|       await registerStringProtocol(protocolName, (request, callback) => callback(notAString as any)); | ||||
|       registerStringProtocol(protocolName, (request, callback) => callback(notAString as any)); | ||||
|       await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); | ||||
|     }); | ||||
|   }); | ||||
|  | @ -166,20 +165,20 @@ describe('protocol module', () => { | |||
|   describe('protocol.registerBufferProtocol', () => { | ||||
|     const buffer = Buffer.from(text); | ||||
|     it('sends Buffer as response', async () => { | ||||
|       await registerBufferProtocol(protocolName, (request, callback) => callback(buffer)); | ||||
|       registerBufferProtocol(protocolName, (request, callback) => callback(buffer)); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|       expect(r.data).to.equal(text); | ||||
|     }); | ||||
| 
 | ||||
|     it('sets Access-Control-Allow-Origin', async () => { | ||||
|       await registerBufferProtocol(protocolName, (request, callback) => callback(buffer)); | ||||
|       registerBufferProtocol(protocolName, (request, callback) => callback(buffer)); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|       expect(r.data).to.equal(text); | ||||
|       expect(r.headers).to.include('access-control-allow-origin: *'); | ||||
|     }); | ||||
| 
 | ||||
|     it('sends object as response', async () => { | ||||
|       await registerBufferProtocol(protocolName, (request, callback) => { | ||||
|       registerBufferProtocol(protocolName, (request, callback) => { | ||||
|         callback({ | ||||
|           data: buffer, | ||||
|           mimeType: 'text/html' | ||||
|  | @ -190,7 +189,7 @@ describe('protocol module', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('fails when sending string', async () => { | ||||
|       await registerBufferProtocol(protocolName, (request, callback) => callback(text as any)); | ||||
|       registerBufferProtocol(protocolName, (request, callback) => callback(text as any)); | ||||
|       await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); | ||||
|     }); | ||||
|   }); | ||||
|  | @ -202,20 +201,20 @@ describe('protocol module', () => { | |||
|     const normalContent = fs.readFileSync(normalPath); | ||||
| 
 | ||||
|     it('sends file path as response', async () => { | ||||
|       await registerFileProtocol(protocolName, (request, callback) => callback(filePath)); | ||||
|       registerFileProtocol(protocolName, (request, callback) => callback(filePath)); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|       expect(r.data).to.equal(String(fileContent)); | ||||
|     }); | ||||
| 
 | ||||
|     it('sets Access-Control-Allow-Origin', async () => { | ||||
|       await registerFileProtocol(protocolName, (request, callback) => callback(filePath)); | ||||
|       registerFileProtocol(protocolName, (request, callback) => callback(filePath)); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|       expect(r.data).to.equal(String(fileContent)); | ||||
|       expect(r.headers).to.include('access-control-allow-origin: *'); | ||||
|     }); | ||||
| 
 | ||||
|     it('sets custom headers', async () => { | ||||
|       await registerFileProtocol(protocolName, (request, callback) => callback({ | ||||
|       registerFileProtocol(protocolName, (request, callback) => callback({ | ||||
|         path: filePath, | ||||
|         headers: { 'X-Great-Header': 'sogreat' } | ||||
|       })); | ||||
|  | @ -231,31 +230,30 @@ describe('protocol module', () => { | |||
|           headers: { 'X-Great-Header': (42 as any) } | ||||
|         })).to.throw(Error, 'Value of \'X-Great-Header\' header has to be a string'); | ||||
|         done(); | ||||
|       }).then(() => { | ||||
|         ajax(protocolName + '://fake-host'); | ||||
|       }); | ||||
|       ajax(protocolName + '://fake-host'); | ||||
|     }); | ||||
| 
 | ||||
|     it('sends object as response', async () => { | ||||
|       await registerFileProtocol(protocolName, (request, callback) => callback({ path: filePath })); | ||||
|       registerFileProtocol(protocolName, (request, callback) => callback({ path: filePath })); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|       expect(r.data).to.equal(String(fileContent)); | ||||
|     }); | ||||
| 
 | ||||
|     it('can send normal file', async () => { | ||||
|       await registerFileProtocol(protocolName, (request, callback) => callback(normalPath)); | ||||
|       registerFileProtocol(protocolName, (request, callback) => callback(normalPath)); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|       expect(r.data).to.equal(String(normalContent)); | ||||
|     }); | ||||
| 
 | ||||
|     it('fails when sending unexist-file', async () => { | ||||
|       const fakeFilePath = path.join(fixturesPath, 'test.asar', 'a.asar', 'not-exist'); | ||||
|       await registerFileProtocol(protocolName, (request, callback) => callback(fakeFilePath)); | ||||
|       registerFileProtocol(protocolName, (request, callback) => callback(fakeFilePath)); | ||||
|       await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); | ||||
|     }); | ||||
| 
 | ||||
|     it('fails when sending unsupported content', async () => { | ||||
|       await registerFileProtocol(protocolName, (request, callback) => callback(new Date() as any)); | ||||
|       registerFileProtocol(protocolName, (request, callback) => callback(new Date() as any)); | ||||
|       await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); | ||||
|     }); | ||||
|   }); | ||||
|  | @ -267,22 +265,22 @@ describe('protocol module', () => { | |||
|         res.end(text); | ||||
|         server.close(); | ||||
|       }); | ||||
|       await server.listen(0, '127.0.0.1'); | ||||
|       await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); | ||||
| 
 | ||||
|       const port = (server.address() as AddressInfo).port; | ||||
|       const url = 'http://127.0.0.1:' + port; | ||||
|       await registerHttpProtocol(protocolName, (request, callback) => callback({ url })); | ||||
|       registerHttpProtocol(protocolName, (request, callback) => callback({ url })); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|       expect(r.data).to.equal(text); | ||||
|     }); | ||||
| 
 | ||||
|     it('fails when sending invalid url', async () => { | ||||
|       await registerHttpProtocol(protocolName, (request, callback) => callback({ url: 'url' })); | ||||
|       registerHttpProtocol(protocolName, (request, callback) => callback({ url: 'url' })); | ||||
|       await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); | ||||
|     }); | ||||
| 
 | ||||
|     it('fails when sending unsupported content', async () => { | ||||
|       await registerHttpProtocol(protocolName, (request, callback) => callback(new Date() as any)); | ||||
|       registerHttpProtocol(protocolName, (request, callback) => callback(new Date() as any)); | ||||
|       await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); | ||||
|     }); | ||||
| 
 | ||||
|  | @ -297,12 +295,12 @@ describe('protocol module', () => { | |||
|         } | ||||
|       }); | ||||
|       after(() => server.close()); | ||||
|       await server.listen(0, '127.0.0.1'); | ||||
|       await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); | ||||
| 
 | ||||
|       const port = (server.address() as AddressInfo).port; | ||||
|       const url = `${protocolName}://fake-host`; | ||||
|       const redirectURL = `http://127.0.0.1:${port}/serverRedirect`; | ||||
|       await registerHttpProtocol(protocolName, (request, callback) => callback({ url: redirectURL })); | ||||
|       registerHttpProtocol(protocolName, (request, callback) => callback({ url: redirectURL })); | ||||
| 
 | ||||
|       const r = await ajax(url); | ||||
|       expect(r.data).to.equal(text); | ||||
|  | @ -312,28 +310,27 @@ describe('protocol module', () => { | |||
|       protocol.registerHttpProtocol(protocolName, (request) => { | ||||
|         expect(request).to.have.property('headers'); | ||||
|         done(); | ||||
|       }, () => { | ||||
|         ajax(protocolName + '://fake-host'); | ||||
|       }); | ||||
|       ajax(protocolName + '://fake-host'); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('protocol.registerStreamProtocol', () => { | ||||
|     it('sends Stream as response', async () => { | ||||
|       await registerStreamProtocol(protocolName, (request, callback) => callback(getStream())); | ||||
|       registerStreamProtocol(protocolName, (request, callback) => callback(getStream())); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|       expect(r.data).to.equal(text); | ||||
|     }); | ||||
| 
 | ||||
|     it('sends object as response', async () => { | ||||
|       await registerStreamProtocol(protocolName, (request, callback) => callback({ data: getStream() })); | ||||
|       registerStreamProtocol(protocolName, (request, callback) => callback({ data: getStream() })); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|       expect(r.data).to.equal(text); | ||||
|       expect(r.status).to.equal(200); | ||||
|     }); | ||||
| 
 | ||||
|     it('sends custom response headers', async () => { | ||||
|       await registerStreamProtocol(protocolName, (request, callback) => callback({ | ||||
|       registerStreamProtocol(protocolName, (request, callback) => callback({ | ||||
|         data: getStream(3), | ||||
|         headers: { | ||||
|           'x-electron': ['a', 'b'] | ||||
|  | @ -346,9 +343,9 @@ describe('protocol module', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('sends custom status code', async () => { | ||||
|       await registerStreamProtocol(protocolName, (request, callback) => callback({ | ||||
|       registerStreamProtocol(protocolName, (request, callback) => callback({ | ||||
|         statusCode: 204, | ||||
|         data: null | ||||
|         data: null as any | ||||
|       })); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|       expect(r.data).to.be.undefined('data'); | ||||
|  | @ -356,7 +353,7 @@ describe('protocol module', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('receives request headers', async () => { | ||||
|       await registerStreamProtocol(protocolName, (request, callback) => { | ||||
|       registerStreamProtocol(protocolName, (request, callback) => { | ||||
|         callback({ | ||||
|           headers: { | ||||
|             'content-type': 'application/json' | ||||
|  | @ -369,7 +366,7 @@ describe('protocol module', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('returns response multiple response headers with the same name', async () => { | ||||
|       await registerStreamProtocol(protocolName, (request, callback) => { | ||||
|       registerStreamProtocol(protocolName, (request, callback) => { | ||||
|         callback({ | ||||
|           headers: { | ||||
|             header1: ['value1', 'value2'], | ||||
|  | @ -387,7 +384,7 @@ describe('protocol module', () => { | |||
| 
 | ||||
|     it('can handle large responses', async () => { | ||||
|       const data = Buffer.alloc(128 * 1024); | ||||
|       await registerStreamProtocol(protocolName, (request, callback) => { | ||||
|       registerStreamProtocol(protocolName, (request, callback) => { | ||||
|         callback(getStream(data.length, data)); | ||||
|       }); | ||||
|       const r = await ajax(protocolName + '://fake-host'); | ||||
|  | @ -402,7 +399,7 @@ describe('protocol module', () => { | |||
|           } | ||||
|         }); | ||||
|       } | ||||
|       await registerStreamProtocol(protocolName, (request, callback) => { | ||||
|       registerStreamProtocol(protocolName, (request, callback) => { | ||||
|         callback({ | ||||
|           statusCode: 200, | ||||
|           headers: { 'Content-Type': 'text/plain' }, | ||||
|  | @ -414,48 +411,38 @@ describe('protocol module', () => { | |||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('protocol.isProtocolHandled', () => { | ||||
|     it('returns true for built-in protocols', async () => { | ||||
|       for (const p of ['about', 'file', 'http', 'https']) { | ||||
|         const handled = await protocol.isProtocolHandled(p); | ||||
|         expect(handled).to.be.true(`${p}: is handled`); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     it('returns false when scheme is not registered', async () => { | ||||
|       const result = await protocol.isProtocolHandled('no-exist'); | ||||
|   describe('protocol.isProtocolRegistered', () => { | ||||
|     it('returns false when scheme is not registered', () => { | ||||
|       const result = protocol.isProtocolRegistered('no-exist'); | ||||
|       expect(result).to.be.false('no-exist: is handled'); | ||||
|     }); | ||||
| 
 | ||||
|     it('returns true for custom protocol', async () => { | ||||
|       await registerStringProtocol(protocolName, (request, callback) => callback()); | ||||
|       const result = await protocol.isProtocolHandled(protocolName); | ||||
|     it('returns true for custom protocol', () => { | ||||
|       registerStringProtocol(protocolName, (request, callback) => callback('')); | ||||
|       const result = protocol.isProtocolRegistered(protocolName); | ||||
|       expect(result).to.be.true('custom protocol is handled'); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|     it('returns true for intercepted protocol', async () => { | ||||
|       await interceptStringProtocol('http', (request, callback) => callback()); | ||||
|       const result = await protocol.isProtocolHandled('http'); | ||||
|   describe('protocol.isProtocolIntercepted', () => { | ||||
|     it('returns true for intercepted protocol', () => { | ||||
|       interceptStringProtocol('http', (request, callback) => callback('')); | ||||
|       const result = protocol.isProtocolIntercepted('http'); | ||||
|       expect(result).to.be.true('intercepted protocol is handled'); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('protocol.intercept(Any)Protocol', () => { | ||||
|     it('throws error when scheme is already intercepted', (done) => { | ||||
|       protocol.interceptStringProtocol('http', (request, callback) => callback(), (error) => { | ||||
|         expect(error).to.be.null('error'); | ||||
|         protocol.interceptBufferProtocol('http', (request, callback) => callback(), (error) => { | ||||
|           expect(error).to.not.be.null('error'); | ||||
|           done(); | ||||
|         }); | ||||
|       }); | ||||
|     it('returns false when scheme is already intercepted', () => { | ||||
|       expect(protocol.interceptStringProtocol('http', (request, callback) => callback(''))).to.equal(true); | ||||
|       expect(protocol.interceptBufferProtocol('http', (request, callback) => callback(Buffer.from('')))).to.equal(false); | ||||
|     }); | ||||
| 
 | ||||
|     it('does not crash when handler is called twice', async () => { | ||||
|       await interceptStringProtocol('http', (request, callback) => { | ||||
|       interceptStringProtocol('http', (request, callback) => { | ||||
|         try { | ||||
|           callback(text); | ||||
|           callback(); | ||||
|           callback(''); | ||||
|         } catch (error) { | ||||
|           // Ignore error
 | ||||
|         } | ||||
|  | @ -465,20 +452,20 @@ describe('protocol module', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('sends error when callback is called with nothing', async () => { | ||||
|       await interceptStringProtocol('http', (request, callback) => callback()); | ||||
|       interceptStringProtocol('http', (request, callback: any) => callback()); | ||||
|       await expect(ajax('http://fake-host')).to.be.eventually.rejectedWith(Error, '404'); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('protocol.interceptStringProtocol', () => { | ||||
|     it('can intercept http protocol', async () => { | ||||
|       await interceptStringProtocol('http', (request, callback) => callback(text)); | ||||
|       interceptStringProtocol('http', (request, callback) => callback(text)); | ||||
|       const r = await ajax('http://fake-host'); | ||||
|       expect(r.data).to.equal(text); | ||||
|     }); | ||||
| 
 | ||||
|     it('can set content-type', async () => { | ||||
|       await interceptStringProtocol('http', (request, callback) => { | ||||
|       interceptStringProtocol('http', (request, callback) => { | ||||
|         callback({ | ||||
|           mimeType: 'application/json', | ||||
|           data: '{"value": 1}' | ||||
|  | @ -490,7 +477,7 @@ describe('protocol module', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('can set content-type with charset', async () => { | ||||
|       await interceptStringProtocol('http', (request, callback) => { | ||||
|       interceptStringProtocol('http', (request, callback) => { | ||||
|         callback({ | ||||
|           mimeType: 'application/json; charset=UTF-8', | ||||
|           data: '{"value": 1}' | ||||
|  | @ -502,8 +489,8 @@ describe('protocol module', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('can receive post data', async () => { | ||||
|       await interceptStringProtocol('http', (request, callback) => { | ||||
|         const uploadData = request.uploadData[0].bytes.toString(); | ||||
|       interceptStringProtocol('http', (request, callback) => { | ||||
|         const uploadData = request.uploadData![0].bytes.toString(); | ||||
|         callback({ data: uploadData }); | ||||
|       }); | ||||
|       const r = await ajax('http://fake-host', { type: 'POST', data: postData }); | ||||
|  | @ -513,14 +500,14 @@ describe('protocol module', () => { | |||
| 
 | ||||
|   describe('protocol.interceptBufferProtocol', () => { | ||||
|     it('can intercept http protocol', async () => { | ||||
|       await interceptBufferProtocol('http', (request, callback) => callback(Buffer.from(text))); | ||||
|       interceptBufferProtocol('http', (request, callback) => callback(Buffer.from(text))); | ||||
|       const r = await ajax('http://fake-host'); | ||||
|       expect(r.data).to.equal(text); | ||||
|     }); | ||||
| 
 | ||||
|     it('can receive post data', async () => { | ||||
|       await interceptBufferProtocol('http', (request, callback) => { | ||||
|         const uploadData = request.uploadData[0].bytes; | ||||
|       interceptBufferProtocol('http', (request, callback) => { | ||||
|         const uploadData = request.uploadData![0].bytes; | ||||
|         callback(uploadData); | ||||
|       }); | ||||
|       const r = await ajax('http://fake-host', { type: 'POST', data: postData }); | ||||
|  | @ -544,19 +531,19 @@ describe('protocol module', () => { | |||
|         server.close(); | ||||
|       }); | ||||
|       after(() => server.close()); | ||||
|       await server.listen(0, '127.0.0.1'); | ||||
|       server.listen(0, '127.0.0.1'); | ||||
| 
 | ||||
|       const port = (server.address() as AddressInfo).port; | ||||
|       const url = `http://127.0.0.1:${port}`; | ||||
|       await interceptHttpProtocol('http', (request, callback) => { | ||||
|         const data: Electron.RedirectRequest = { | ||||
|       interceptHttpProtocol('http', (request, callback) => { | ||||
|         const data: Electron.ProtocolResponse = { | ||||
|           url: url, | ||||
|           method: 'POST', | ||||
|           uploadData: { | ||||
|             contentType: 'application/x-www-form-urlencoded', | ||||
|             data: request.uploadData[0].bytes | ||||
|             data: request.uploadData![0].bytes | ||||
|           }, | ||||
|           session: null | ||||
|           session: undefined | ||||
|         }; | ||||
|         callback(data); | ||||
|       }); | ||||
|  | @ -572,7 +559,7 @@ describe('protocol module', () => { | |||
|       }); | ||||
|       after(() => customSession.webRequest.onBeforeRequest(null)); | ||||
| 
 | ||||
|       await interceptHttpProtocol('http', (request, callback) => { | ||||
|       interceptHttpProtocol('http', (request, callback) => { | ||||
|         callback({ | ||||
|           url: request.url, | ||||
|           session: customSession | ||||
|  | @ -585,33 +572,32 @@ describe('protocol module', () => { | |||
|       protocol.interceptHttpProtocol('http', (request) => { | ||||
|         expect(request).to.have.property('headers'); | ||||
|         done(); | ||||
|       }, () => { | ||||
|         ajax('http://fake-host'); | ||||
|       }); | ||||
|       ajax('http://fake-host'); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('protocol.interceptStreamProtocol', () => { | ||||
|     it('can intercept http protocol', async () => { | ||||
|       await interceptStreamProtocol('http', (request, callback) => callback(getStream())); | ||||
|       interceptStreamProtocol('http', (request, callback) => callback(getStream())); | ||||
|       const r = await ajax('http://fake-host'); | ||||
|       expect(r.data).to.equal(text); | ||||
|     }); | ||||
| 
 | ||||
|     it('can receive post data', async () => { | ||||
|       await interceptStreamProtocol('http', (request, callback) => { | ||||
|         callback(getStream(3, request.uploadData[0].bytes.toString())); | ||||
|       interceptStreamProtocol('http', (request, callback) => { | ||||
|         callback(getStream(3, request.uploadData![0].bytes.toString())); | ||||
|       }); | ||||
|       const r = await ajax('http://fake-host', { type: 'POST', data: postData }); | ||||
|       expect({ ...qs.parse(r.data) }).to.deep.equal(postData); | ||||
|     }); | ||||
| 
 | ||||
|     it('can execute redirects', async () => { | ||||
|       await interceptStreamProtocol('http', (request, callback) => { | ||||
|       interceptStreamProtocol('http', (request, callback) => { | ||||
|         if (request.url.indexOf('http://fake-host') === 0) { | ||||
|           setTimeout(() => { | ||||
|             callback({ | ||||
|               data: null, | ||||
|               data: '', | ||||
|               statusCode: 302, | ||||
|               headers: { | ||||
|                 Location: 'http://fake-redirect' | ||||
|  | @ -629,12 +615,12 @@ describe('protocol module', () => { | |||
|   }); | ||||
| 
 | ||||
|   describe('protocol.uninterceptProtocol', () => { | ||||
|     it('returns error when scheme does not exist', async () => { | ||||
|       await expect(uninterceptProtocol('not-exist')).to.be.eventually.rejectedWith(Error); | ||||
|     it('returns false when scheme does not exist', () => { | ||||
|       expect(uninterceptProtocol('not-exist')).to.equal(false); | ||||
|     }); | ||||
| 
 | ||||
|     it('returns error when scheme is not intercepted', async () => { | ||||
|       await expect(uninterceptProtocol('http')).to.be.eventually.rejectedWith(Error); | ||||
|     it('returns false when scheme is not intercepted', () => { | ||||
|       expect(uninterceptProtocol('http')).to.equal(false); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|  | @ -677,14 +663,14 @@ describe('protocol module', () => { | |||
| 
 | ||||
|     afterEach(async () => { | ||||
|       await closeWindow(w); | ||||
|       await unregisterProtocol(standardScheme); | ||||
|       unregisterProtocol(standardScheme); | ||||
|       w = null as unknown as BrowserWindow; | ||||
|     }); | ||||
| 
 | ||||
|     it('resolves relative resources', async () => { | ||||
|       await registerFileProtocol(standardScheme, (request, callback) => { | ||||
|       registerFileProtocol(standardScheme, (request, callback) => { | ||||
|         if (request.url === imageURL) { | ||||
|           callback(); | ||||
|           callback(''); | ||||
|         } else { | ||||
|           callback(filePath); | ||||
|         } | ||||
|  | @ -693,9 +679,9 @@ describe('protocol module', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('resolves absolute resources', async () => { | ||||
|       await registerStringProtocol(standardScheme, (request, callback) => { | ||||
|       registerStringProtocol(standardScheme, (request, callback) => { | ||||
|         if (request.url === imageURL) { | ||||
|           callback(); | ||||
|           callback(''); | ||||
|         } else { | ||||
|           callback({ | ||||
|             data: fileContent, | ||||
|  | @ -716,17 +702,15 @@ describe('protocol module', () => { | |||
|       await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); | ||||
|       const port = (server.address() as AddressInfo).port; | ||||
|       const content = `<script>fetch("http://127.0.0.1:${port}")</script>`; | ||||
|       await registerStringProtocol(standardScheme, (request, callback) => callback({ data: content, mimeType: 'text/html' })); | ||||
|       registerStringProtocol(standardScheme, (request, callback) => callback({ data: content, mimeType: 'text/html' })); | ||||
|       await w.loadURL(origin); | ||||
|       await requestReceived; | ||||
|     }); | ||||
| 
 | ||||
|     it.skip('can access files through the FileSystem API', (done) => { | ||||
|       const filePath = path.join(fixturesPath, 'pages', 'filesystem.html'); | ||||
|       protocol.registerFileProtocol(standardScheme, (request, callback) => callback({ path: filePath }), (error) => { | ||||
|         if (error) return done(error); | ||||
|         w.loadURL(origin); | ||||
|       }); | ||||
|       protocol.registerFileProtocol(standardScheme, (request, callback) => callback({ path: filePath })); | ||||
|       w.loadURL(origin); | ||||
|       ipcMain.once('file-system-error', (event, err) => done(err)); | ||||
|       ipcMain.once('file-system-write-end', () => done()); | ||||
|     }); | ||||
|  | @ -735,10 +719,8 @@ describe('protocol module', () => { | |||
|       const filePath = path.join(fixturesPath, 'pages', 'cache-storage.html'); | ||||
|       ipcMain.once('success', () => done()); | ||||
|       ipcMain.once('failure', (event, err) => done(err)); | ||||
|       protocol.registerFileProtocol(standardScheme, (request, callback) => callback({ path: filePath }), (error) => { | ||||
|         if (error) return done(error); | ||||
|         w.loadURL(origin); | ||||
|       }); | ||||
|       protocol.registerFileProtocol(standardScheme, (request, callback) => callback({ path: filePath })); | ||||
|       w.loadURL(origin); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|  | @ -752,11 +734,9 @@ describe('protocol module', () => { | |||
|     afterEach(async () => { | ||||
|       await closeWindow(w); | ||||
|       w = null as unknown as BrowserWindow; | ||||
|       await Promise.all( | ||||
|         [standardScheme, 'cors', 'no-cors', 'no-fetch'].map(scheme => | ||||
|           new Promise(resolve => protocol.unregisterProtocol(scheme, (/* ignore error */) => resolve())) | ||||
|         ) | ||||
|       ); | ||||
|       for (const scheme of [standardScheme, 'cors', 'no-cors', 'no-fetch']) { | ||||
|         protocol.unregisterProtocol(scheme); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     it('supports fetch api by default', async () => { | ||||
|  | @ -818,10 +798,10 @@ describe('protocol module', () => { | |||
|     }); | ||||
| 
 | ||||
|     async function allowsCORSRequests (corsScheme: string, expected: any, expectedConsole: RegExp, content: Function) { | ||||
|       await registerStringProtocol(standardScheme, (request, callback) => { | ||||
|       registerStringProtocol(standardScheme, (request, callback) => { | ||||
|         callback({ data: `<script>(${content})()</script>`, mimeType: 'text/html' }); | ||||
|       }); | ||||
|       await registerStringProtocol(corsScheme, (request, callback) => { | ||||
|       registerStringProtocol(corsScheme, (request, callback) => { | ||||
|         callback(''); | ||||
|       }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -312,11 +312,11 @@ describe('session module', () => { | |||
|     }); | ||||
|     afterEach(closeAllWindows); | ||||
| 
 | ||||
|     it('does not affect defaultSession', async () => { | ||||
|       const result1 = await protocol.isProtocolHandled(protocolName); | ||||
|     it('does not affect defaultSession', () => { | ||||
|       const result1 = protocol.isProtocolRegistered(protocolName); | ||||
|       expect(result1).to.equal(false); | ||||
| 
 | ||||
|       const result2 = await customSession.protocol.isProtocolHandled(protocolName); | ||||
|       const result2 = customSession.protocol.isProtocolRegistered(protocolName); | ||||
|       expect(result2).to.equal(true); | ||||
|     }); | ||||
| 
 | ||||
|  | @ -424,18 +424,16 @@ describe('session module', () => { | |||
|         if (request.method === 'GET') { | ||||
|           callback({ data: content, mimeType: 'text/html' }); | ||||
|         } else if (request.method === 'POST') { | ||||
|           const uuid = request.uploadData[1].blobUUID; | ||||
|           const uuid = request.uploadData![1].blobUUID; | ||||
|           expect(uuid).to.be.a('string'); | ||||
|           session.defaultSession.getBlobData(uuid!).then(result => { | ||||
|             expect(result.toString()).to.equal(postData); | ||||
|             done(); | ||||
|           }); | ||||
|         } | ||||
|       }, (error) => { | ||||
|         if (error) return done(error); | ||||
|         const w = new BrowserWindow({ show: false }); | ||||
|         w.loadURL(url); | ||||
|       }); | ||||
|       const w = new BrowserWindow({ show: false }); | ||||
|       w.loadURL(url); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|  | @ -644,18 +642,16 @@ describe('session module', () => { | |||
|       const handler = (ignoredError: any, callback: Function) => { | ||||
|         callback({ url: `${url}:${port}` }); | ||||
|       }; | ||||
|       protocol.registerHttpProtocol(protocolName, handler, (error) => { | ||||
|         if (error) return done(error); | ||||
|         const w = new BrowserWindow({ show: false }); | ||||
|         w.webContents.session.once('will-download', function (e, item) { | ||||
|           item.savePath = downloadFilePath; | ||||
|           item.on('done', function (e, state) { | ||||
|             assertDownload(state, item, true); | ||||
|             done(); | ||||
|           }); | ||||
|       protocol.registerHttpProtocol(protocolName, handler); | ||||
|       const w = new BrowserWindow({ show: false }); | ||||
|       w.webContents.session.once('will-download', function (e, item) { | ||||
|         item.savePath = downloadFilePath; | ||||
|         item.on('done', function (e, state) { | ||||
|           assertDownload(state, item, true); | ||||
|           done(); | ||||
|         }); | ||||
|         w.webContents.downloadURL(`${protocolName}://item`); | ||||
|       }); | ||||
|       w.webContents.downloadURL(`${protocolName}://item`); | ||||
|     }); | ||||
| 
 | ||||
|     it('can download using WebView.downloadURL', async () => { | ||||
|  |  | |||
|  | @ -830,7 +830,7 @@ describe('webContents module', () => { | |||
|       host3: 0.2 | ||||
|     }; | ||||
| 
 | ||||
|     before((done) => { | ||||
|     before(() => { | ||||
|       const protocol = session.defaultSession.protocol; | ||||
|       protocol.registerStringProtocol(scheme, (request, callback) => { | ||||
|         const response = `<script>
 | ||||
|  | @ -841,12 +841,12 @@ describe('webContents module', () => { | |||
|                             }) | ||||
|                           </script>`;
 | ||||
|         callback({ data: response, mimeType: 'text/html' }); | ||||
|       }, (error) => done(error)); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     after((done) => { | ||||
|     after(() => { | ||||
|       const protocol = session.defaultSession.protocol; | ||||
|       protocol.unregisterProtocol(scheme, (error) => done(error)); | ||||
|       protocol.unregisterProtocol(scheme); | ||||
|     }); | ||||
| 
 | ||||
|     afterEach(closeAllWindows); | ||||
|  | @ -981,29 +981,25 @@ describe('webContents module', () => { | |||
|       const protocol = w2.webContents.session.protocol; | ||||
|       protocol.registerStringProtocol(scheme, (request, callback) => { | ||||
|         callback('hello'); | ||||
|       }, (error) => { | ||||
|         if (error) return done(error); | ||||
|         w2.webContents.on('did-finish-load', () => { | ||||
|           const zoomLevel1 = w.webContents.zoomLevel; | ||||
|           expect(zoomLevel1).to.equal(hostZoomMap.host3); | ||||
| 
 | ||||
|           const zoomLevel2 = w2.webContents.zoomLevel; | ||||
|           expect(zoomLevel2).to.equal(0); | ||||
|           expect(zoomLevel1).to.not.equal(zoomLevel2); | ||||
| 
 | ||||
|           protocol.unregisterProtocol(scheme, (error) => { | ||||
|             if (error) return done(error); | ||||
|             w2.setClosable(true); | ||||
|             w2.close(); | ||||
|             done(); | ||||
|           }); | ||||
|         }); | ||||
|         w.webContents.on('did-finish-load', () => { | ||||
|           w.webContents.zoomLevel = hostZoomMap.host3; | ||||
|           w2.loadURL(`${scheme}://host3`); | ||||
|         }); | ||||
|         w.loadURL(`${scheme}://host3`); | ||||
|       }); | ||||
|       w2.webContents.on('did-finish-load', () => { | ||||
|         const zoomLevel1 = w.webContents.zoomLevel; | ||||
|         expect(zoomLevel1).to.equal(hostZoomMap.host3); | ||||
| 
 | ||||
|         const zoomLevel2 = w2.webContents.zoomLevel; | ||||
|         expect(zoomLevel2).to.equal(0); | ||||
|         expect(zoomLevel1).to.not.equal(zoomLevel2); | ||||
| 
 | ||||
|         protocol.unregisterProtocol(scheme); | ||||
|         w2.setClosable(true); | ||||
|         w2.close(); | ||||
|         done(); | ||||
|       }); | ||||
|       w.webContents.on('did-finish-load', () => { | ||||
|         w.webContents.zoomLevel = hostZoomMap.host3; | ||||
|         w2.loadURL(`${scheme}://host3`); | ||||
|       }); | ||||
|       w.loadURL(`${scheme}://host3`); | ||||
|     }); | ||||
| 
 | ||||
|     it('can persist when it contains iframe', (done) => { | ||||
|  |  | |||
|  | @ -410,8 +410,6 @@ describe('chromium features', () => { | |||
| 
 | ||||
|         if (ext === '.js') type = 'application/javascript'; | ||||
|         callback({ data: content, mimeType: type } as any); | ||||
|       }, (error) => { | ||||
|         if (error) done(error); | ||||
|       }); | ||||
| 
 | ||||
|       const w = new BrowserWindow({ | ||||
|  | @ -431,7 +429,8 @@ describe('chromium features', () => { | |||
|           customSession.clearStorageData({ | ||||
|             storages: ['serviceworkers'] | ||||
|           }).then(() => { | ||||
|             customSession.protocol.uninterceptProtocol('file', error => done(error)); | ||||
|             customSession.protocol.uninterceptProtocol('file'); | ||||
|             done(); | ||||
|           }); | ||||
|         } | ||||
|       }); | ||||
|  | @ -840,8 +839,8 @@ describe('chromium features', () => { | |||
|     ]; | ||||
|     const s = (url: string) => url.startsWith('file') ? 'file://...' : url; | ||||
| 
 | ||||
|     before(async () => { | ||||
|       await promisify(protocol.registerFileProtocol)(scheme, (request, callback) => { | ||||
|     before(() => { | ||||
|       protocol.registerFileProtocol(scheme, (request, callback) => { | ||||
|         if (request.url.includes('blank')) { | ||||
|           callback(`${fixturesPath}/pages/blank.html`); | ||||
|         } else { | ||||
|  | @ -849,8 +848,8 @@ describe('chromium features', () => { | |||
|         } | ||||
|       }); | ||||
|     }); | ||||
|     after(async () => { | ||||
|       await promisify(protocol.unregisterProtocol)(scheme); | ||||
|     after(() => { | ||||
|       protocol.unregisterProtocol(scheme); | ||||
|     }); | ||||
|     afterEach(closeAllWindows); | ||||
| 
 | ||||
|  | @ -929,7 +928,7 @@ describe('chromium features', () => { | |||
|     describe('custom non standard schemes', () => { | ||||
|       const protocolName = 'storage'; | ||||
|       let contents: WebContents; | ||||
|       before((done) => { | ||||
|       before(() => { | ||||
|         protocol.registerFileProtocol(protocolName, (request, callback) => { | ||||
|           const parsedUrl = url.parse(request.url); | ||||
|           let filename; | ||||
|  | @ -942,11 +941,11 @@ describe('chromium features', () => { | |||
|             default : filename = ''; | ||||
|           } | ||||
|           callback({ path: `${fixturesPath}/pages/storage/${filename}` }); | ||||
|         }, (error) => done(error)); | ||||
|         }); | ||||
|       }); | ||||
| 
 | ||||
|       after((done) => { | ||||
|         protocol.unregisterProtocol(protocolName, () => done()); | ||||
|       after(() => { | ||||
|         protocol.unregisterProtocol(protocolName); | ||||
|       }); | ||||
| 
 | ||||
|       beforeEach(() => { | ||||
|  |  | |||
|  | @ -217,16 +217,16 @@ describe('<webview> tag', function () { | |||
|     const zoomScheme = standardScheme; | ||||
|     const webviewSession = session.fromPartition('webview-temp'); | ||||
| 
 | ||||
|     before((done) => { | ||||
|     before(() => { | ||||
|       const protocol = webviewSession.protocol; | ||||
|       protocol.registerStringProtocol(zoomScheme, (request, callback) => { | ||||
|         callback('hello'); | ||||
|       }, (error) => done(error)); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     after((done) => { | ||||
|     after(() => { | ||||
|       const protocol = webviewSession.protocol; | ||||
|       protocol.unregisterProtocol(zoomScheme, (error) => done(error)); | ||||
|       protocol.unregisterProtocol(zoomScheme); | ||||
|     }); | ||||
| 
 | ||||
|     it('inherits the zoomFactor of the parent window', async () => { | ||||
|  |  | |||
|  | @ -897,13 +897,9 @@ app.whenReady().then(() => { | |||
|     callback({ url: request.url, method: request.method }) | ||||
|   }) | ||||
| 
 | ||||
|   protocol.unregisterProtocol('atom', (error) => { | ||||
|     console.log(error ? error.message : 'ok') | ||||
|   }) | ||||
|   protocol.unregisterProtocol('atom') | ||||
| 
 | ||||
|   protocol.isProtocolHandled('atom').then(handled => { | ||||
|     console.log(handled) | ||||
|   }) | ||||
|   const registered: boolean = protocol.isProtocolRegistered('atom') | ||||
| }) | ||||
| 
 | ||||
| // tray
 | ||||
|  | @ -1195,10 +1191,6 @@ app.whenReady().then(function () { | |||
|   protocol.registerFileProtocol('atom', function (request, callback) { | ||||
|     const url = request.url.substr(7) | ||||
|     callback(path.normalize(__dirname + '/' + url)) | ||||
|   }, function (error) { | ||||
|     if (error) { | ||||
|       console.error('Failed to register protocol') | ||||
|     } | ||||
|   }) | ||||
| }) | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Samuel Attard
				Samuel Attard