mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: remove WebSocket implementation (#961)
WebSocket implementation currently is very incomplete, lacking support in WebKit-Win and Firefox.
This commit is contained in:
parent
b0c0598510
commit
7ce49c2835
70
docs/api.md
70
docs/api.md
@ -19,7 +19,6 @@
|
||||
- [class: Request](#class-request)
|
||||
- [class: Response](#class-response)
|
||||
- [class: Selectors](#class-selectors)
|
||||
- [class: WebSocket](#class-websocket)
|
||||
- [class: TimeoutError](#class-timeouterror)
|
||||
- [class: Accessibility](#class-accessibility)
|
||||
- [class: Coverage](#class-coverage)
|
||||
@ -445,7 +444,6 @@ page.removeListener('request', logRequest);
|
||||
- [event: 'requestfailed'](#event-requestfailed)
|
||||
- [event: 'requestfinished'](#event-requestfinished)
|
||||
- [event: 'response'](#event-response)
|
||||
- [event: 'websocket'](#event-websocket)
|
||||
- [event: 'workercreated'](#event-workercreated)
|
||||
- [event: 'workerdestroyed'](#event-workerdestroyed)
|
||||
- [page.$(selector)](#pageselector)
|
||||
@ -618,11 +616,6 @@ Emitted when a request finishes successfully.
|
||||
|
||||
Emitted when a [response] is received.
|
||||
|
||||
#### event: 'websocket'
|
||||
- <[WebSocket]> websocket
|
||||
|
||||
Emitted when a <[WebSocket]> is opened.
|
||||
|
||||
#### event: 'workercreated'
|
||||
- <[Worker]>
|
||||
|
||||
@ -3171,67 +3164,6 @@ const { selectors, firefox } = require('playwright'); // Or 'chromium' or 'webk
|
||||
})();
|
||||
```
|
||||
|
||||
### class: WebSocket
|
||||
|
||||
The [WebSocket] class represents websocket connections in the page.
|
||||
|
||||
<!-- GEN:toc -->
|
||||
- [event: 'close'](#event-close-2)
|
||||
- [event: 'error'](#event-error)
|
||||
- [event: 'messagereceived'](#event-messagereceived)
|
||||
- [event: 'messagesent'](#event-messagesent)
|
||||
- [event: 'open'](#event-open)
|
||||
- [webSocket.requestHeaders()](#websocketrequestheaders)
|
||||
- [webSocket.responseHeaders()](#websocketresponseheaders)
|
||||
- [webSocket.status()](#websocketstatus)
|
||||
- [webSocket.statusText()](#websocketstatustext)
|
||||
- [webSocket.url()](#websocketurl)
|
||||
<!-- GEN:stop -->
|
||||
|
||||
#### event: 'close'
|
||||
|
||||
Fired when the websocket closes.
|
||||
|
||||
#### event: 'error'
|
||||
- <[String]> the error message
|
||||
|
||||
Fired when the websocket has an error.
|
||||
|
||||
#### event: 'messagereceived'
|
||||
- <[Buffer]|[String]> data recieved
|
||||
|
||||
Fired when the websocket recieves a message.
|
||||
|
||||
#### event: 'messagesent'
|
||||
- <[Buffer]|[String]> data recieved
|
||||
|
||||
Fired when the websocket sends a message.
|
||||
|
||||
#### event: 'open'
|
||||
|
||||
Fired when the websocket opens.
|
||||
|
||||
#### webSocket.requestHeaders()
|
||||
- returns: <[Promise]<[Object]>>
|
||||
|
||||
#### webSocket.responseHeaders()
|
||||
- returns: <[Promise]<[Object]>>
|
||||
|
||||
#### webSocket.status()
|
||||
- returns: <[number]>
|
||||
|
||||
Contains the status code of the WebSocket (e.g., 200 for a success).
|
||||
|
||||
#### webSocket.statusText()
|
||||
- returns: <[string]>
|
||||
|
||||
Contains the status text of the WebSocket (e.g. usually an "OK" for a success).
|
||||
|
||||
#### webSocket.url()
|
||||
- returns: <[string]>
|
||||
|
||||
Contains the URL of the WebSocket.
|
||||
|
||||
### class: TimeoutError
|
||||
|
||||
* extends: [Error]
|
||||
@ -3431,7 +3363,7 @@ If the function passed to the `worker.evaluateHandle` returns a [Promise], then
|
||||
### class: BrowserServer
|
||||
|
||||
<!-- GEN:toc -->
|
||||
- [event: 'close'](#event-close-3)
|
||||
- [event: 'close'](#event-close-2)
|
||||
- [browserServer.close()](#browserserverclose)
|
||||
- [browserServer.kill()](#browserserverkill)
|
||||
- [browserServer.process()](#browserserverprocess)
|
||||
|
||||
@ -24,7 +24,7 @@ export { TimeoutError } from './errors';
|
||||
export { Frame } from './frames';
|
||||
export { Keyboard, Mouse } from './input';
|
||||
export { JSHandle } from './javascript';
|
||||
export { Request, Response, WebSocket } from './network';
|
||||
export { Request, Response } from './network';
|
||||
export { Coverage, FileChooser, Page, Worker } from './page';
|
||||
export { Selectors } from './selectors';
|
||||
|
||||
|
||||
@ -52,13 +52,6 @@ export class CRNetworkManager {
|
||||
helper.addEventListener(session, 'Network.responseReceived', this._onResponseReceived.bind(this)),
|
||||
helper.addEventListener(session, 'Network.loadingFinished', this._onLoadingFinished.bind(this)),
|
||||
helper.addEventListener(session, 'Network.loadingFailed', this._onLoadingFailed.bind(this)),
|
||||
helper.addEventListener(session, 'Network.webSocketCreated', e => this._page._frameManager.onWebSocketCreated(e.requestId, e.url)),
|
||||
helper.addEventListener(session, 'Network.webSocketWillSendHandshakeRequest', e => this._page._frameManager.onWebSocketRequest(e.requestId, e.request.headers)),
|
||||
helper.addEventListener(session, 'Network.webSocketHandshakeResponseReceived', e => this._page._frameManager.onWebSocketResponse(e.requestId, e.response.status, e.response.statusText, e.response.headers)),
|
||||
helper.addEventListener(session, 'Network.webSocketFrameSent', e => e.response.payloadData && this._page._frameManager.onWebSocketFrameSent(e.requestId, e.response.opcode, e.response.payloadData)),
|
||||
helper.addEventListener(session, 'Network.webSocketFrameReceived', e => e.response.payloadData && this._page._frameManager.webSocketFrameReceived(e.requestId, e.response.opcode, e.response.payloadData)),
|
||||
helper.addEventListener(session, 'Network.webSocketClosed', e => this._page._frameManager.webSocketClosed(e.requestId)),
|
||||
helper.addEventListener(session, 'Network.webSocketFrameError', e => this._page._frameManager.webSocketError(e.requestId, e.errorMessage)),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -46,16 +46,7 @@ export const Events = {
|
||||
FrameNavigated: 'framenavigated',
|
||||
Load: 'load',
|
||||
Popup: 'popup',
|
||||
WebSocket: 'websocket',
|
||||
WorkerCreated: 'workercreated',
|
||||
WorkerDestroyed: 'workerdestroyed',
|
||||
},
|
||||
|
||||
WebSocket: {
|
||||
Close: 'close',
|
||||
Error: 'error',
|
||||
MessageReceived: 'messagereceived',
|
||||
MessageSent: 'messagesent',
|
||||
Open: 'open',
|
||||
}
|
||||
};
|
||||
|
||||
@ -58,7 +58,6 @@ type ConsoleTagHandler = () => void;
|
||||
export class FrameManager {
|
||||
private _page: Page;
|
||||
private _frames = new Map<string, Frame>();
|
||||
private _webSockets = new Map<string, network.WebSocket>();
|
||||
private _mainFrame: Frame;
|
||||
readonly _lifecycleWatchers = new Set<() => void>();
|
||||
readonly _consoleMessageTags = new Map<string, ConsoleTagHandler>();
|
||||
@ -120,7 +119,6 @@ export class FrameManager {
|
||||
for (const watcher of frame._documentWatchers)
|
||||
watcher(documentId);
|
||||
this.clearFrameLifecycle(frame);
|
||||
this.clearWebSockets(frame);
|
||||
if (!initial)
|
||||
this._page.emit(Events.Page.FrameNavigated, frame);
|
||||
}
|
||||
@ -182,13 +180,6 @@ export class FrameManager {
|
||||
this._startNetworkIdleTimer(frame, 'networkidle2');
|
||||
}
|
||||
|
||||
clearWebSockets(frame: Frame) {
|
||||
// TODO: attributet sockets to frames.
|
||||
if (frame.parentFrame())
|
||||
return;
|
||||
this._webSockets.clear();
|
||||
}
|
||||
|
||||
requestStarted(request: network.Request) {
|
||||
this._inflightRequestStarted(request);
|
||||
const frame = request.frame();
|
||||
@ -228,50 +219,6 @@ export class FrameManager {
|
||||
this._page.emit(Events.Page.RequestFailed, request);
|
||||
}
|
||||
|
||||
onWebSocketCreated(requestId: string, url: string) {
|
||||
const ws = new network.WebSocket(url);
|
||||
this._webSockets.set(requestId, ws);
|
||||
}
|
||||
|
||||
onWebSocketRequest(requestId: string, headers: network.Headers) {
|
||||
const ws = this._webSockets.get(requestId);
|
||||
if (ws) {
|
||||
ws._requestSent(headers);
|
||||
this._page.emit(Events.Page.WebSocket, ws);
|
||||
}
|
||||
}
|
||||
|
||||
onWebSocketResponse(requestId: string, status: number, statusText: string, headers: network.Headers) {
|
||||
const ws = this._webSockets.get(requestId);
|
||||
if (ws)
|
||||
ws._responseReceived(status, statusText, headers);
|
||||
}
|
||||
|
||||
onWebSocketFrameSent(requestId: string, opcode: number, data: string) {
|
||||
const ws = this._webSockets.get(requestId);
|
||||
if (ws)
|
||||
ws._frameSent(opcode, data);
|
||||
}
|
||||
|
||||
webSocketFrameReceived(requestId: string, opcode: number, data: string) {
|
||||
const ws = this._webSockets.get(requestId);
|
||||
if (ws)
|
||||
ws._frameReceived(opcode, data);
|
||||
}
|
||||
|
||||
webSocketClosed(requestId: string) {
|
||||
const ws = this._webSockets.get(requestId);
|
||||
if (ws)
|
||||
ws._closed();
|
||||
this._webSockets.delete(requestId);
|
||||
}
|
||||
|
||||
webSocketError(requestId: string, errorMessage: string): void {
|
||||
const ws = this._webSockets.get(requestId);
|
||||
if (ws)
|
||||
ws._error(errorMessage);
|
||||
}
|
||||
|
||||
provisionalLoadFailed(frame: Frame, documentId: string, error: string) {
|
||||
for (const watcher of frame._documentWatchers)
|
||||
watcher(documentId, new Error(error));
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
import * as frames from './frames';
|
||||
import { assert } from './helper';
|
||||
import * as platform from './platform';
|
||||
import { Events } from './events';
|
||||
|
||||
export type NetworkCookie = {
|
||||
name: string,
|
||||
@ -308,70 +307,6 @@ export interface RequestDelegate {
|
||||
continue(overrides: { method?: string; headers?: Headers; postData?: string; }): Promise<void>;
|
||||
}
|
||||
|
||||
export class WebSocket extends platform.EventEmitter {
|
||||
private _url: string;
|
||||
_status: number | null = null;
|
||||
_statusText: string | null = null;
|
||||
_requestHeaders: Headers | null = null;
|
||||
_responseHeaders: Headers | null = null;
|
||||
|
||||
constructor(url: string) {
|
||||
super();
|
||||
this._url = url;
|
||||
}
|
||||
|
||||
url(): string {
|
||||
return this._url;
|
||||
}
|
||||
|
||||
status(): number | null {
|
||||
return this._status;
|
||||
}
|
||||
|
||||
statusText(): string | null {
|
||||
return this._statusText;
|
||||
}
|
||||
|
||||
requestHeaders(): Headers | null {
|
||||
return this._requestHeaders;
|
||||
}
|
||||
|
||||
responseHeaders(): Headers | null {
|
||||
return this._responseHeaders;
|
||||
}
|
||||
|
||||
_requestSent(headers: Headers) {
|
||||
this._requestHeaders = {};
|
||||
for (const [name, value] of Object.entries(headers))
|
||||
this._requestHeaders[name.toLowerCase()] = value;
|
||||
}
|
||||
|
||||
_responseReceived(status: number, statusText: string, headers: Headers) {
|
||||
this._status = status;
|
||||
this._statusText = statusText;
|
||||
this._responseHeaders = {};
|
||||
for (const [name, value] of Object.entries(headers))
|
||||
this._responseHeaders[name.toLowerCase()] = value;
|
||||
this.emit(Events.WebSocket.Open);
|
||||
}
|
||||
|
||||
_frameSent(opcode: number, data: string) {
|
||||
this.emit(Events.WebSocket.MessageSent, opcode === 2 ? Buffer.from(data, 'base64') : data);
|
||||
}
|
||||
|
||||
_frameReceived(opcode: number, data: string) {
|
||||
this.emit(Events.WebSocket.MessageReceived, opcode === 2 ? Buffer.from(data, 'base64') : data);
|
||||
}
|
||||
|
||||
_error(errorMessage: string) {
|
||||
this.emit(Events.WebSocket.Error, errorMessage);
|
||||
}
|
||||
|
||||
_closed() {
|
||||
this.emit(Events.WebSocket.Close);
|
||||
}
|
||||
}
|
||||
|
||||
// List taken from https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml with extra 306 and 418 codes.
|
||||
export const STATUS_TEXTS: { [status: string]: string } = {
|
||||
'100': 'Continue',
|
||||
|
||||
@ -208,13 +208,6 @@ export class WKPage implements PageDelegate {
|
||||
helper.addEventListener(this._session, 'Network.responseReceived', e => this._onResponseReceived(e)),
|
||||
helper.addEventListener(this._session, 'Network.loadingFinished', e => this._onLoadingFinished(e)),
|
||||
helper.addEventListener(this._session, 'Network.loadingFailed', e => this._onLoadingFailed(e)),
|
||||
helper.addEventListener(this._session, 'Network.webSocketCreated', e => this._page._frameManager.onWebSocketCreated(e.requestId, e.url)),
|
||||
helper.addEventListener(this._session, 'Network.webSocketWillSendHandshakeRequest', e => this._page._frameManager.onWebSocketRequest(e.requestId, e.request.headers)),
|
||||
helper.addEventListener(this._session, 'Network.webSocketHandshakeResponseReceived', e => this._page._frameManager.onWebSocketResponse(e.requestId, e.response.status, e.response.statusText, e.response.headers)),
|
||||
helper.addEventListener(this._session, 'Network.webSocketFrameSent', e => e.response.payloadData && this._page._frameManager.onWebSocketFrameSent(e.requestId, e.response.opcode, e.response.payloadData)),
|
||||
helper.addEventListener(this._session, 'Network.webSocketFrameReceived', e => e.response.payloadData && this._page._frameManager.webSocketFrameReceived(e.requestId, e.response.opcode, e.response.payloadData)),
|
||||
helper.addEventListener(this._session, 'Network.webSocketClosed', e => this._page._frameManager.webSocketClosed(e.requestId)),
|
||||
helper.addEventListener(this._session, 'Network.webSocketFrameError', e => this._page._frameManager.webSocketError(e.requestId, e.errorMessage)),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -341,116 +341,4 @@ module.exports.describe = function({testRunner, expect, MAC, WIN, FFOX, CHROMIUM
|
||||
expect(error.message).toBe('Expected value of header "foo" to be String, but "number" is found.');
|
||||
});
|
||||
});
|
||||
|
||||
false && describe.skip(FFOX)('WebSocket', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
const value = await page.evaluate((port) => {
|
||||
let cb;
|
||||
const result = new Promise(f => cb = f);
|
||||
const ws = new WebSocket('ws://localhost:' + port + '/ws');
|
||||
ws.addEventListener('message', data => { ws.close(); cb(data.data); });
|
||||
return result;
|
||||
}, server.PORT);
|
||||
expect(value).toBe('incoming');
|
||||
});
|
||||
it('should emit open/close events', async({page, server}) => {
|
||||
let socketClosed;
|
||||
const socketClosePromise = new Promise(f => socketClosed = f);
|
||||
const log = [];
|
||||
page.on('websocket', ws => {
|
||||
ws.on('open', () => log.push(`open<${ws.url()}>`));
|
||||
ws.on('close', () => { log.push('close'); socketClosed(); });
|
||||
});
|
||||
page.evaluate((port) => {
|
||||
const ws = new WebSocket('ws://localhost:' + port + '/ws');
|
||||
ws.addEventListener('open', () => ws.close());
|
||||
}, server.PORT);
|
||||
await socketClosePromise;
|
||||
expect(log.join(':')).toBe(`open<ws://localhost:${server.PORT}/ws>:close`);
|
||||
});
|
||||
it('should expose status', async({page, server}) => {
|
||||
let callback;
|
||||
const result = new Promise(f => callback = f);
|
||||
page.on('websocket', ws => ws.on('open', () => callback(ws)));
|
||||
page.evaluate((port) => {
|
||||
const ws = new WebSocket('ws://localhost:' + port + '/ws');
|
||||
ws.addEventListener('open', () => ws.close());
|
||||
}, server.PORT);
|
||||
const ws = await result;
|
||||
expect(ws.status()).toBe(101);
|
||||
expect(ws.statusText()).toBe('Switching Protocols');
|
||||
});
|
||||
it('should emit error', async({page, server}) => {
|
||||
let callback;
|
||||
const result = new Promise(f => callback = f);
|
||||
page.on('websocket', ws => ws.on('error', callback));
|
||||
page.evaluate((port) => {
|
||||
new WebSocket('ws://localhost:' + port + '/bogus-ws');
|
||||
}, server.PORT);
|
||||
const message = await result;
|
||||
expect(message).toContain('Unexpected response code: 400');
|
||||
});
|
||||
it('should emit frame events', async({page, server}) => {
|
||||
let socketClosed;
|
||||
const socketClosePromise = new Promise(f => socketClosed = f);
|
||||
const log = [];
|
||||
page.on('websocket', ws => {
|
||||
ws.on('open', () => log.push('open'));
|
||||
ws.on('messageSent', d => log.push('sent<' + d + '>'));
|
||||
ws.on('messageReceived', d => log.push('received<' + d + '>'));
|
||||
ws.on('close', () => { log.push('close'); socketClosed(); });
|
||||
});
|
||||
page.evaluate((port) => {
|
||||
const ws = new WebSocket('ws://localhost:' + port + '/ws');
|
||||
ws.addEventListener('open', () => ws.send('outgoing'));
|
||||
ws.addEventListener('message', () => { ws.close(); });
|
||||
}, server.PORT);
|
||||
await socketClosePromise;
|
||||
expect(log.join(':')).toBe('open:sent<outgoing>:received<incoming>:close');
|
||||
});
|
||||
it('should emit binary frame events', async({page, server}) => {
|
||||
let doneCallback;
|
||||
const donePromise = new Promise(f => doneCallback = f);
|
||||
const sent = [];
|
||||
page.on('websocket', ws => {
|
||||
ws.on('close', doneCallback);
|
||||
ws.on('messageSent', d => sent.push(d));
|
||||
});
|
||||
page.evaluate((port) => {
|
||||
const ws = new WebSocket('ws://localhost:' + port + '/ws');
|
||||
ws.addEventListener('open', () => {
|
||||
const binary = new Uint8Array(5);
|
||||
for (let i = 0; i < 5; ++i)
|
||||
binary[i] = i;
|
||||
ws.send('text');
|
||||
ws.send(binary);
|
||||
ws.close();
|
||||
});
|
||||
}, server.PORT);
|
||||
await donePromise;
|
||||
expect(sent[0]).toBe('text');
|
||||
for (let i = 0; i < 5; ++i)
|
||||
expect(sent[1][i]).toBe(i);
|
||||
});
|
||||
it('should report headers', async({page, server}) => {
|
||||
let socketClosed;
|
||||
let requestHeaders;
|
||||
let responseHeaders;
|
||||
const socketClosePromise = new Promise(f => socketClosed = f);
|
||||
page.on('websocket', ws => {
|
||||
requestHeaders = ws.requestHeaders();
|
||||
ws.on('open', () => {
|
||||
responseHeaders = ws.responseHeaders();
|
||||
});
|
||||
ws.on('close', socketClosed);
|
||||
});
|
||||
page.evaluate((port) => {
|
||||
const ws = new WebSocket('ws://localhost:' + port + '/ws');
|
||||
ws.addEventListener('open', () => ws.close());
|
||||
}, server.PORT);
|
||||
await socketClosePromise;
|
||||
expect(requestHeaders['connection']).toBe('Upgrade');
|
||||
expect(responseHeaders['upgrade']).toBe('websocket');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user