* docs: NetworkService-based protocol module * docs: separate ProtocolRequest * docs: separate ProtocolResponse * docs: fix lint warning * docs: fix electron.d.ts * fix: print deprecation warnings for protocol module * docs: fix links * Apply suggestions from code review Co-Authored-By: Felix Rieseberg <felix@felixrieseberg.com> * Apply suggestions from code review Co-Authored-By: Samuel Attard <samuel.r.attard@gmail.com> * Do not publish NetworkService changes draft * Apply suggestions from code review Co-Authored-By: Samuel Attard <samuel.r.attard@gmail.com> * docs: filePath must be absolute
		
			
				
	
	
		
			309 lines
		
	
	
	
		
			9.7 KiB
			
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
	
		
			9.7 KiB
			
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# 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.on('ready', () => {
 | 
						|
  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.on('ready', () => {
 | 
						|
  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
 |