2020-01-07 16:15:07 -08:00
/ * *
* Copyright 2017 Google Inc . All rights reserved .
* Modifications copyright ( c ) Microsoft Corporation .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2020-01-22 17:42:10 -08:00
import { WKBrowser } from '../webkit/wkBrowser' ;
2020-05-22 07:03:42 -07:00
import { Env } from './processLauncher' ;
2020-01-07 16:15:07 -08:00
import * as path from 'path' ;
2020-01-08 13:55:38 -08:00
import { kBrowserCloseMessageId } from '../webkit/wkConnection' ;
2020-06-25 08:30:56 -07:00
import { BrowserTypeBase } from './browserType' ;
2020-06-10 16:33:27 -07:00
import { ConnectionTransport , ProtocolResponse , ProtocolRequest } from '../transport' ;
2020-01-22 17:42:10 -08:00
import * as ws from 'ws' ;
2020-06-16 17:11:19 -07:00
import { Logger } from '../logger' ;
2020-05-21 19:16:13 -07:00
import { BrowserOptions } from '../browser' ;
2020-05-22 07:03:42 -07:00
import { BrowserDescriptor } from '../install/browserPaths' ;
2020-06-10 16:33:27 -07:00
import { WebSocketServer } from './webSocketServer' ;
import { assert } from '../helper' ;
2020-06-25 08:30:56 -07:00
import { LaunchOptionsBase } from '../types' ;
2020-01-07 16:15:07 -08:00
2020-05-20 16:30:04 -07:00
export class WebKit extends BrowserTypeBase {
2020-05-22 07:03:42 -07:00
constructor ( packagePath : string , browser : BrowserDescriptor ) {
super ( packagePath , browser , null /* use pipe not websocket */ ) ;
}
2020-05-20 16:30:04 -07:00
_connectToTransport ( transport : ConnectionTransport , options : BrowserOptions ) : Promise < WKBrowser > {
return WKBrowser . connect ( transport , options ) ;
2020-02-04 19:41:38 -08:00
}
2020-05-22 07:03:42 -07:00
_amendEnvironment ( env : Env , userDataDir : string , executable : string , browserArguments : string [ ] ) : Env {
return { . . . env , CURL_COOKIE_JAR_PATH : path.join ( userDataDir , 'cookiejar.db' ) } ;
}
2020-01-08 13:55:38 -08:00
2020-05-22 07:03:42 -07:00
_attemptToGracefullyCloseBrowser ( transport : ConnectionTransport ) : void {
transport . send ( { method : 'Playwright.close' , params : { } , id : kBrowserCloseMessageId } ) ;
}
2020-01-07 16:15:07 -08:00
2020-06-16 17:11:19 -07:00
_startWebSocketServer ( transport : ConnectionTransport , logger : Logger , port : number ) : WebSocketServer {
2020-06-10 16:33:27 -07:00
return startWebSocketServer ( transport , logger , port ) ;
2020-01-07 16:15:07 -08:00
}
2020-06-08 21:45:35 -07:00
_defaultArgs ( options : LaunchOptionsBase , isPersistent : boolean , userDataDir : string ) : string [ ] {
2020-06-10 20:48:54 -07:00
const { args = [ ] , proxy , devtools , headless } = options ;
2020-01-24 14:49:47 -08:00
if ( devtools )
2020-03-24 22:42:20 +01:00
console . warn ( 'devtools parameter as a launch argument in WebKit is not supported. Also starting Web Inspector manually will terminate the execution in WebKit.' ) ;
2020-02-05 16:36:36 -08:00
const userDataDirArg = args . find ( arg = > arg . startsWith ( '--user-data-dir=' ) ) ;
if ( userDataDirArg )
throw new Error ( 'Pass userDataDir parameter instead of specifying --user-data-dir argument' ) ;
2020-05-10 15:23:53 -07:00
if ( args . find ( arg = > ! arg . startsWith ( '-' ) ) )
2020-02-27 14:09:24 -08:00
throw new Error ( 'Arguments can not specify page to be opened' ) ;
2020-01-23 12:18:41 -08:00
const webkitArguments = [ '--inspector-pipe' ] ;
if ( headless )
webkitArguments . push ( '--headless' ) ;
2020-05-22 16:06:00 -07:00
if ( isPersistent )
2020-02-26 13:02:15 -08:00
webkitArguments . push ( ` --user-data-dir= ${ userDataDir } ` ) ;
else
webkitArguments . push ( ` --no-startup-window ` ) ;
2020-06-05 13:50:15 -07:00
if ( proxy ) {
if ( process . platform === 'darwin' ) {
webkitArguments . push ( ` --proxy= ${ proxy . server } ` ) ;
if ( proxy . bypass )
webkitArguments . push ( ` --proxy-bypass-list= ${ proxy . bypass } ` ) ;
} else if ( process . platform === 'linux' ) {
webkitArguments . push ( ` --proxy= ${ proxy . server } ` ) ;
if ( proxy . bypass )
webkitArguments . push ( . . . proxy . bypass . split ( ',' ) . map ( t = > ` --ignore-host= ${ t } ` ) ) ;
} else if ( process . platform === 'win32' ) {
webkitArguments . push ( ` --curl-proxy= ${ proxy . server } ` ) ;
if ( proxy . bypass )
webkitArguments . push ( ` --curl-noproxy= ${ proxy . bypass } ` ) ;
}
}
2020-01-07 16:15:07 -08:00
webkitArguments . push ( . . . args ) ;
2020-05-22 16:06:00 -07:00
if ( isPersistent )
2020-05-10 15:23:53 -07:00
webkitArguments . push ( 'about:blank' ) ;
2020-01-07 16:15:07 -08:00
return webkitArguments ;
}
}
2020-06-16 17:11:19 -07:00
function startWebSocketServer ( transport : ConnectionTransport , logger : Logger , port : number ) : WebSocketServer {
2020-02-06 12:41:43 -08:00
const pendingBrowserContextCreations = new Set < number > ( ) ;
const pendingBrowserContextDeletions = new Map < number , string > ( ) ;
const browserContextIds = new Map < string , ws > ( ) ;
2020-01-22 17:42:10 -08:00
2020-06-10 16:33:27 -07:00
const server = new WebSocketServer ( transport , logger , port , {
onBrowserResponse ( seqNum : number , source : ws , message : ProtocolResponse ) {
if ( source . readyState === ws . CLOSED || source . readyState === ws . CLOSING ) {
if ( pendingBrowserContextCreations . has ( seqNum ) )
server . sendMessageToBrowserOneWay ( 'Playwright.deleteContext' , { browserContextId : message.result.browserContextId } ) ;
2020-02-06 12:41:43 -08:00
return ;
}
2020-06-10 16:33:27 -07:00
if ( pendingBrowserContextCreations . has ( seqNum ) ) {
2020-02-06 12:41:43 -08:00
// Browser.createContext response -> establish context attribution.
2020-06-10 16:33:27 -07:00
browserContextIds . set ( message . result . browserContextId , source ) ;
pendingBrowserContextCreations . delete ( seqNum ) ;
2020-02-06 12:41:43 -08:00
}
2020-06-10 16:33:27 -07:00
const deletedContextId = pendingBrowserContextDeletions . get ( seqNum ) ;
2020-02-06 12:41:43 -08:00
if ( deletedContextId ) {
// Browser.deleteContext response -> remove context attribution.
browserContextIds . delete ( deletedContextId ) ;
2020-06-10 16:33:27 -07:00
pendingBrowserContextDeletions . delete ( seqNum ) ;
2020-02-06 12:41:43 -08:00
}
2020-06-10 16:33:27 -07:00
source . send ( JSON . stringify ( message ) ) ;
2020-01-22 17:42:10 -08:00
return ;
2020-06-10 16:33:27 -07:00
} ,
onBrowserNotification ( message : ProtocolResponse ) {
// Process notification response.
const { params , browserContextId } = message ;
const contextId = browserContextId || params . browserContextId ;
assert ( contextId ) ;
const socket = browserContextIds . get ( contextId ) ;
if ( ! socket || socket . readyState === ws . CLOSING ) {
// Drop unattributed messages on the floor.
return ;
}
socket . send ( JSON . stringify ( message ) ) ;
} ,
2020-02-06 12:41:43 -08:00
2020-06-10 16:33:27 -07:00
onClientAttached ( socket : ws ) {
} ,
2020-02-06 12:41:43 -08:00
2020-06-10 16:33:27 -07:00
onClientRequest ( socket : ws , message : ProtocolRequest ) {
const { method , params } = message ;
const seqNum = server . sendMessageToBrowser ( message , socket ) ;
2020-03-11 21:08:22 +00:00
if ( method === 'Playwright.createContext' )
2020-02-06 12:41:43 -08:00
pendingBrowserContextCreations . add ( seqNum ) ;
2020-03-11 21:08:22 +00:00
if ( method === 'Playwright.deleteContext' )
2020-02-06 12:41:43 -08:00
pendingBrowserContextDeletions . set ( seqNum , params . browserContextId ) ;
2020-06-10 16:33:27 -07:00
} ,
2020-02-06 12:41:43 -08:00
2020-06-10 16:33:27 -07:00
onClientDetached ( socket : ws ) {
2020-02-06 12:41:43 -08:00
for ( const [ browserContextId , s ] of browserContextIds ) {
if ( s === socket ) {
2020-06-10 16:33:27 -07:00
server . sendMessageToBrowserOneWay ( 'Playwright.deleteContext' , { browserContextId } ) ;
2020-02-06 12:41:43 -08:00
browserContextIds . delete ( browserContextId ) ;
}
}
2020-06-10 16:33:27 -07:00
}
2020-01-22 17:42:10 -08:00
} ) ;
2020-06-10 16:33:27 -07:00
return server ;
2020-01-22 17:42:10 -08:00
}