| 
									
										
										
										
											2020-04-23 01:52:17 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (C) 2010-2016 Apple Inc. All rights reserved.
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without
 | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions
 | 
					
						
							|  |  |  |  * are met:
 | 
					
						
							|  |  |  |  * 1. Redistributions of source code must retain the above copyright
 | 
					
						
							|  |  |  |  *    notice, this list of conditions and the following disclaimer.
 | 
					
						
							|  |  |  |  * 2. Redistributions in binary form must reproduce the above copyright
 | 
					
						
							|  |  |  |  *    notice, this list of conditions and the following disclaimer in the
 | 
					
						
							|  |  |  |  *    documentation and/or other materials provided with the distribution.
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 | 
					
						
							|  |  |  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 | 
					
						
							|  |  |  |  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
					
						
							|  |  |  |  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 | 
					
						
							|  |  |  |  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
					
						
							|  |  |  |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
					
						
							|  |  |  |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
					
						
							|  |  |  |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
					
						
							|  |  |  |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
					
						
							|  |  |  |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 | 
					
						
							|  |  |  |  * THE POSSIBILITY OF SUCH DAMAGE.
 | 
					
						
							|  |  |  |  */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #import "AppDelegate.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #import "BrowserWindowController.h"
 | 
					
						
							|  |  |  | #import <WebKit/WKNavigationActionPrivate.h>
 | 
					
						
							|  |  |  | #import <WebKit/WKNavigationDelegatePrivate.h>
 | 
					
						
							|  |  |  | #import <WebKit/WKPreferencesPrivate.h>
 | 
					
						
							|  |  |  | #import <WebKit/WKProcessPoolPrivate.h>
 | 
					
						
							|  |  |  | #import <WebKit/WKUserContentControllerPrivate.h>
 | 
					
						
							|  |  |  | #import <WebKit/WKWebViewConfigurationPrivate.h>
 | 
					
						
							|  |  |  | #import <WebKit/WKWebViewPrivate.h>
 | 
					
						
							|  |  |  | #import <WebKit/WKWebsiteDataStorePrivate.h>
 | 
					
						
							|  |  |  | #import <WebKit/WebNSURLExtras.h>
 | 
					
						
							|  |  |  | #import <WebKit/WebKit.h>
 | 
					
						
							|  |  |  | #import <WebKit/_WKDownload.h>
 | 
					
						
							|  |  |  | #import <WebKit/_WKExperimentalFeature.h>
 | 
					
						
							|  |  |  | #import <WebKit/_WKInternalDebugFeature.h>
 | 
					
						
							|  |  |  | #import <WebKit/_WKProcessPoolConfiguration.h>
 | 
					
						
							|  |  |  | #import <WebKit/_WKWebsiteDataStoreConfiguration.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @implementation NSApplication (PlaywrightApplicationExtensions)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (BrowserAppDelegate *)browserAppDelegate
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     return (BrowserAppDelegate *)[self delegate];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @end
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @interface NSApplication (TouchBar)
 | 
					
						
							|  |  |  | @property (getter=isAutomaticCustomizeTouchBarMenuItemEnabled) BOOL automaticCustomizeTouchBarMenuItemEnabled;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @property (readonly, nonatomic) WKWebViewConfiguration *defaultConfiguration;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @end
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @implementation WebViewDialog
 | 
					
						
							|  |  |  | - (void)dealloc
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     [_webView release];
 | 
					
						
							|  |  |  |     _webView = nil;
 | 
					
						
							|  |  |  |     [super dealloc];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | @end
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum {
 | 
					
						
							|  |  |  |     _NSBackingStoreUnbuffered = 3
 | 
					
						
							|  |  |  | };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NSString* const ActivityReason = @"Batch headless process";
 | 
					
						
							|  |  |  | const NSActivityOptions ActivityOptions =
 | 
					
						
							|  |  |  |     (NSActivityUserInitiatedAllowingIdleSystemSleep |
 | 
					
						
							|  |  |  |      NSActivityLatencyCritical) &
 | 
					
						
							|  |  |  |     ~(NSActivitySuddenTerminationDisabled |
 | 
					
						
							|  |  |  |     NSActivityAutomaticTerminationDisabled);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @implementation BrowserAppDelegate
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (id)init
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     self = [super init];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!self)
 | 
					
						
							|  |  |  |         return nil;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _initialURL = nil;
 | 
					
						
							|  |  |  |     _userDataDir = nil;
 | 
					
						
							| 
									
										
										
										
											2020-06-03 23:41:43 +08:00
										 |  |  |     _proxyServer = nil;
 | 
					
						
							| 
									
										
										
										
											2020-06-05 12:01:38 +08:00
										 |  |  |     _proxyBypassList = nil;
 | 
					
						
							| 
									
										
										
										
											2020-04-23 01:52:17 +08:00
										 |  |  |     NSArray *arguments = [[NSProcessInfo processInfo] arguments];
 | 
					
						
							|  |  |  |     NSRange subargs = NSMakeRange(1, [arguments count] - 1);
 | 
					
						
							|  |  |  |     NSArray *subArray = [arguments subarrayWithRange:subargs];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (NSString *argument in subArray) {
 | 
					
						
							|  |  |  |         if (![argument hasPrefix:@"--"])
 | 
					
						
							|  |  |  |             _initialURL = argument;
 | 
					
						
							|  |  |  |         if ([argument hasPrefix:@"--user-data-dir="]) {
 | 
					
						
							|  |  |  |             NSRange range = NSMakeRange(16, [argument length] - 16);
 | 
					
						
							|  |  |  |             _userDataDir = [[argument substringWithRange:range] copy];
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-06-03 23:41:43 +08:00
										 |  |  |         if ([argument hasPrefix:@"--proxy="]) {
 | 
					
						
							|  |  |  |             NSRange range = NSMakeRange(8, [argument length] - 8);
 | 
					
						
							|  |  |  |             _proxyServer = [[argument substringWithRange:range] copy];
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-06-05 12:01:38 +08:00
										 |  |  |         if ([argument hasPrefix:@"--proxy-bypass-list="]) {
 | 
					
						
							|  |  |  |             NSRange range = NSMakeRange(20, [argument length] - 20);
 | 
					
						
							|  |  |  |             _proxyBypassList = [[argument substringWithRange:range] copy];
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-04-23 01:52:17 +08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _headless = [arguments containsObject: @"--headless"];
 | 
					
						
							|  |  |  |     _noStartupWindow = [arguments containsObject: @"--no-startup-window"];
 | 
					
						
							|  |  |  |     _browserContexts = [[NSMutableSet alloc] init];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (_headless) {
 | 
					
						
							|  |  |  |         _headlessWindows = [[NSMutableSet alloc] init];
 | 
					
						
							|  |  |  |         [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
 | 
					
						
							|  |  |  |         [[NSProcessInfo processInfo] beginActivityWithOptions:ActivityOptions
 | 
					
						
							|  |  |  |                                                        reason:ActivityReason];
 | 
					
						
							|  |  |  |         _dialogs = [[NSMutableSet alloc] init];
 | 
					
						
							|  |  |  |     } else {
 | 
					
						
							|  |  |  |         [NSApp activateIgnoringOtherApps:YES];
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     if ([arguments containsObject: @"--inspector-pipe"])
 | 
					
						
							|  |  |  |         [_WKBrowserInspector initializeRemoteInspectorPipe:self headless:_headless];
 | 
					
						
							|  |  |  |     return self;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)awakeFromNib
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     if ([NSApp respondsToSelector:@selector(setAutomaticCustomizeTouchBarMenuItemEnabled:)])
 | 
					
						
							|  |  |  |         [NSApp setAutomaticCustomizeTouchBarMenuItemEnabled:YES];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 23:41:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-05 12:01:38 +08:00
										 |  |  | - (NSDictionary *)proxyConfiguration:(NSString *)proxyServer WithBypassList:(NSString *)proxyBypassList
 | 
					
						
							| 
									
										
										
										
											2020-06-03 23:41:43 +08:00
										 |  |  | {
 | 
					
						
							| 
									
										
										
										
											2020-06-05 12:01:38 +08:00
										 |  |  |     if (!proxyServer || ![proxyServer length])
 | 
					
						
							| 
									
										
										
										
											2020-06-03 23:41:43 +08:00
										 |  |  |         return nil;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma clang diagnostic push
 | 
					
						
							|  |  |  | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSMutableDictionary *dictionary = [[[NSMutableDictionary alloc] init] autorelease];
 | 
					
						
							| 
									
										
										
										
											2020-06-04 06:11:50 +08:00
										 |  |  |     NSURL *proxyURL = [NSURL URLWithString:proxyServer];
 | 
					
						
							|  |  |  |     NSString *host = [proxyURL host];
 | 
					
						
							|  |  |  |     NSNumber *port = [proxyURL port];
 | 
					
						
							| 
									
										
										
										
											2020-06-03 23:41:43 +08:00
										 |  |  |     if ([proxyServer hasPrefix:@"socks5://"]) {
 | 
					
						
							| 
									
										
										
										
											2020-06-04 06:11:50 +08:00
										 |  |  |         [dictionary setObject:host forKey:(NSString *)kCFStreamPropertySOCKSProxyHost];
 | 
					
						
							| 
									
										
										
										
											2020-06-03 23:41:43 +08:00
										 |  |  |         if (port)
 | 
					
						
							|  |  |  |             [dictionary setObject:port forKey:(NSString *)kCFStreamPropertySOCKSProxyPort];
 | 
					
						
							|  |  |  |     } else {
 | 
					
						
							| 
									
										
										
										
											2020-06-05 04:56:51 +08:00
										 |  |  |         [dictionary setObject:host forKey:(NSString *)kCFStreamPropertyHTTPSProxyHost];
 | 
					
						
							| 
									
										
										
										
											2020-06-03 23:41:43 +08:00
										 |  |  |         [dictionary setObject:host forKey:(NSString *)kCFStreamPropertyHTTPProxyHost];
 | 
					
						
							| 
									
										
										
										
											2020-06-05 04:56:51 +08:00
										 |  |  |         if (port) {
 | 
					
						
							|  |  |  |             [dictionary setObject:port forKey:(NSString *)kCFStreamPropertyHTTPSProxyPort];
 | 
					
						
							| 
									
										
										
										
											2020-06-03 23:41:43 +08:00
										 |  |  |             [dictionary setObject:port forKey:(NSString *)kCFStreamPropertyHTTPProxyPort];
 | 
					
						
							| 
									
										
										
										
											2020-06-05 04:56:51 +08:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-06-03 23:41:43 +08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-05 12:01:38 +08:00
										 |  |  |     if (proxyBypassList && [proxyBypassList length]) {
 | 
					
						
							|  |  |  |         NSArray* bypassList = [proxyBypassList componentsSeparatedByString:@","];
 | 
					
						
							|  |  |  |         [dictionary setObject:bypassList forKey:@"ExceptionsList"];
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 23:41:43 +08:00
										 |  |  | #pragma clang diagnostic pop
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return dictionary;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-23 01:52:17 +08:00
										 |  |  | - (WKWebsiteDataStore *)persistentDataStore
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     static WKWebsiteDataStore *dataStore;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!dataStore) {
 | 
					
						
							|  |  |  |         _WKWebsiteDataStoreConfiguration *configuration = [[[_WKWebsiteDataStoreConfiguration alloc] init] autorelease];
 | 
					
						
							|  |  |  |         if (_userDataDir) {
 | 
					
						
							|  |  |  |             NSURL *cookieFile = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/cookie.db", _userDataDir]];
 | 
					
						
							|  |  |  |             [configuration _setCookieStorageFile:cookieFile];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             NSURL *applicationCacheDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/ApplicationCache", _userDataDir]];
 | 
					
						
							|  |  |  |             [configuration setApplicationCacheDirectory:applicationCacheDirectory];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             NSURL *cacheStorageDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/CacheStorage", _userDataDir]];
 | 
					
						
							|  |  |  |             [configuration _setCacheStorageDirectory:cacheStorageDirectory];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             NSURL *indexedDBDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/IndexedDB", _userDataDir]];
 | 
					
						
							|  |  |  |             [configuration _setIndexedDBDatabaseDirectory:indexedDBDirectory];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             NSURL *localStorageDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/LocalStorage", _userDataDir]];
 | 
					
						
							|  |  |  |             [configuration _setWebStorageDirectory:localStorageDirectory];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             NSURL *mediaCacheDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/MediaCache", _userDataDir]];
 | 
					
						
							|  |  |  |             [configuration setMediaCacheDirectory:mediaCacheDirectory];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             NSURL *mediaKeysDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/MediaKeys", _userDataDir]];
 | 
					
						
							|  |  |  |             [configuration setMediaKeysStorageDirectory:mediaKeysDirectory];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             NSURL *networkCacheDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/NetworkCache", _userDataDir]];
 | 
					
						
							|  |  |  |             [configuration setNetworkCacheDirectory:networkCacheDirectory];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             NSURL *loadStatsDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/ResourceLoadStatistics", _userDataDir]];
 | 
					
						
							|  |  |  |             [configuration _setResourceLoadStatisticsDirectory:loadStatsDirectory];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             NSURL *serviceWorkersDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/ServiceWorkers", _userDataDir]];
 | 
					
						
							|  |  |  |             [configuration _setServiceWorkerRegistrationDirectory:serviceWorkersDirectory];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             NSURL *webSqlDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/WebSQL", _userDataDir]];
 | 
					
						
							|  |  |  |             [configuration _setWebSQLDatabaseDirectory:webSqlDirectory];
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-06-05 12:01:38 +08:00
										 |  |  |         [configuration setProxyConfiguration:[self proxyConfiguration:_proxyServer WithBypassList:_proxyBypassList]];
 | 
					
						
							| 
									
										
										
										
											2020-04-23 01:52:17 +08:00
										 |  |  |         dataStore = [[WKWebsiteDataStore alloc] _initWithConfiguration:configuration];
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return dataStore;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (WKWebViewConfiguration *)defaultConfiguration
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     static WKWebViewConfiguration *configuration;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!configuration) {
 | 
					
						
							|  |  |  |         configuration = [[WKWebViewConfiguration alloc] init];
 | 
					
						
							|  |  |  |         configuration.websiteDataStore = [self persistentDataStore];
 | 
					
						
							|  |  |  |         configuration.preferences._fullScreenEnabled = YES;
 | 
					
						
							|  |  |  |         configuration.preferences._developerExtrasEnabled = YES;
 | 
					
						
							|  |  |  |         configuration.preferences._mediaDevicesEnabled = YES;
 | 
					
						
							|  |  |  |         configuration.preferences._mockCaptureDevicesEnabled = YES;
 | 
					
						
							|  |  |  |         configuration.preferences._hiddenPageDOMTimerThrottlingEnabled = NO;
 | 
					
						
							|  |  |  |         configuration.preferences._hiddenPageDOMTimerThrottlingAutoIncreases = NO;
 | 
					
						
							|  |  |  |         configuration.preferences._pageVisibilityBasedProcessSuppressionEnabled = NO;
 | 
					
						
							|  |  |  |         configuration.preferences._domTimersThrottlingEnabled = NO;
 | 
					
						
							|  |  |  |         configuration.preferences._requestAnimationFrameEnabled = YES;
 | 
					
						
							|  |  |  |         _WKProcessPoolConfiguration *processConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease];
 | 
					
						
							|  |  |  |         processConfiguration.forceOverlayScrollbars = YES;
 | 
					
						
							| 
									
										
										
										
											2020-10-10 07:11:50 +08:00
										 |  |  |         configuration.processPool = [[[WKProcessPool alloc] _initWithConfiguration:processConfiguration] autorelease];
 | 
					
						
							| 
									
										
										
										
											2020-04-23 01:52:17 +08:00
										 |  |  |     }
 | 
					
						
							|  |  |  |     return configuration;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     if (!_headless)
 | 
					
						
							|  |  |  |         [self _updateNewWindowKeyEquivalents];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (_noStartupWindow)
 | 
					
						
							|  |  |  |         return;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     [self createNewPage:0];
 | 
					
						
							|  |  |  |     _initialURL = nil;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)_updateNewWindowKeyEquivalents
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     NSString *normalWindowEquivalent = @"n";
 | 
					
						
							|  |  |  |     _newWebKit2WindowItem.keyEquivalentModifierMask = NSEventModifierFlagCommand;
 | 
					
						
							|  |  |  |     _newWebKit2WindowItem.keyEquivalent = normalWindowEquivalent;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma mark WKBrowserInspectorDelegate
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (WKWebViewConfiguration *) sessionConfiguration:(uint64_t)sessionID
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     for (_WKBrowserContext *browserContext in _browserContexts) {
 | 
					
						
							|  |  |  |         if ([[browserContext dataStore] sessionID] != sessionID)
 | 
					
						
							|  |  |  |             continue;
 | 
					
						
							|  |  |  |         WKWebViewConfiguration *configuration = [[[self defaultConfiguration] copy] autorelease];
 | 
					
						
							|  |  |  |         configuration.websiteDataStore = [browserContext dataStore];
 | 
					
						
							|  |  |  |         configuration.processPool = [browserContext processPool];
 | 
					
						
							|  |  |  |         return configuration;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     return [self defaultConfiguration];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (WKWebView *)createNewPage:(uint64_t)sessionID
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     NSString* urlString = _initialURL ? _initialURL : @"about:blank";
 | 
					
						
							|  |  |  |     WKWebViewConfiguration *configuration = [self sessionConfiguration:sessionID];
 | 
					
						
							|  |  |  |     if (_headless)
 | 
					
						
							|  |  |  |         return [self createHeadlessPage:configuration withURL:urlString];
 | 
					
						
							|  |  |  |     return [self createHeadfulPage:configuration withURL:urlString];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (WKWebView *)createHeadfulPage:(WKWebViewConfiguration *)configuration withURL:(NSString*)urlString
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     // WebView lifecycle will control the BrowserWindowController life times.
 | 
					
						
							|  |  |  |     BrowserWindowController *controller = [[BrowserWindowController alloc] initWithConfiguration:configuration];
 | 
					
						
							|  |  |  |     if (!controller)
 | 
					
						
							|  |  |  |         return nil;
 | 
					
						
							|  |  |  |     [controller loadURLString:urlString];
 | 
					
						
							| 
									
										
										
										
											2020-05-05 03:08:30 +08:00
										 |  |  |     NSWindow *window = controller.window;
 | 
					
						
							|  |  |  |     [window setIsVisible:YES];
 | 
					
						
							| 
									
										
										
										
											2020-04-23 01:52:17 +08:00
										 |  |  |     return [controller webView];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (WKWebView *)createHeadlessPage:(WKWebViewConfiguration *)configuration withURL:(NSString*)urlString
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     NSRect rect = NSMakeRect(0, 0, 1280, 720);
 | 
					
						
							|  |  |  |     NSScreen *firstScreen = [[NSScreen screens] objectAtIndex:0];
 | 
					
						
							|  |  |  |     NSRect windowRect = NSOffsetRect(rect, -10000, [firstScreen frame].size.height - rect.size.height + 10000);
 | 
					
						
							|  |  |  |     NSWindow* window = [[NSWindow alloc] initWithContentRect:windowRect styleMask:NSWindowStyleMaskBorderless backing:(NSBackingStoreType)_NSBackingStoreUnbuffered defer:YES];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     WKWebView* webView = [[WKWebView alloc] initWithFrame:[window.contentView bounds] configuration:configuration];
 | 
					
						
							|  |  |  |     webView._windowOcclusionDetectionEnabled = NO;
 | 
					
						
							|  |  |  |     if (!webView)
 | 
					
						
							|  |  |  |         return nil;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     webView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
 | 
					
						
							|  |  |  |     [window.contentView addSubview:webView];
 | 
					
						
							| 
									
										
										
										
											2020-05-05 03:08:30 +08:00
										 |  |  |     [window setIsVisible:YES];
 | 
					
						
							| 
									
										
										
										
											2020-04-23 01:52:17 +08:00
										 |  |  |     if (urlString) {
 | 
					
						
							|  |  |  |         NSURL *url = [NSURL _webkit_URLWithUserTypedString:urlString];
 | 
					
						
							|  |  |  |         [webView loadRequest:[NSURLRequest requestWithURL:url]];
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     [_headlessWindows addObject:window];
 | 
					
						
							|  |  |  |     webView.navigationDelegate = self;
 | 
					
						
							|  |  |  |     webView.UIDelegate = self;
 | 
					
						
							|  |  |  |     return [webView autorelease];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-05 12:01:38 +08:00
										 |  |  | - (_WKBrowserContext *)createBrowserContext:(NSString *)proxyServer WithBypassList:(NSString *) proxyBypassList
 | 
					
						
							| 
									
										
										
										
											2020-04-23 01:52:17 +08:00
										 |  |  | {
 | 
					
						
							|  |  |  |     _WKBrowserContext *browserContext = [[_WKBrowserContext alloc] init];
 | 
					
						
							|  |  |  |     _WKProcessPoolConfiguration *processConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease];
 | 
					
						
							|  |  |  |     processConfiguration.forceOverlayScrollbars = YES;
 | 
					
						
							| 
									
										
										
										
											2020-06-03 23:41:43 +08:00
										 |  |  |     _WKWebsiteDataStoreConfiguration *dataStoreConfiguration = [[[_WKWebsiteDataStoreConfiguration alloc] initNonPersistentConfiguration] autorelease];
 | 
					
						
							|  |  |  |     if (!proxyServer || ![proxyServer length])
 | 
					
						
							|  |  |  |         proxyServer = _proxyServer;
 | 
					
						
							| 
									
										
										
										
											2020-06-05 12:01:38 +08:00
										 |  |  |     if (!proxyBypassList || ![proxyBypassList length])
 | 
					
						
							|  |  |  |         proxyBypassList = _proxyBypassList;
 | 
					
						
							|  |  |  |     [dataStoreConfiguration setProxyConfiguration:[self proxyConfiguration:proxyServer WithBypassList:proxyBypassList]];
 | 
					
						
							| 
									
										
										
										
											2020-08-24 23:56:33 +08:00
										 |  |  |     browserContext.dataStore = [[WKWebsiteDataStore alloc] _initWithConfiguration:dataStoreConfiguration];
 | 
					
						
							|  |  |  |     browserContext.processPool = [[[WKProcessPool alloc] _initWithConfiguration:processConfiguration] autorelease];
 | 
					
						
							|  |  |  |     [browserContext.processPool _setDownloadDelegate:self];
 | 
					
						
							| 
									
										
										
										
											2020-04-23 01:52:17 +08:00
										 |  |  |     [_browserContexts addObject:browserContext];
 | 
					
						
							|  |  |  |     return browserContext;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)deleteBrowserContext:(uint64_t)sessionID
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     for (_WKBrowserContext *browserContext in _browserContexts) {
 | 
					
						
							|  |  |  |         if ([[browserContext dataStore] sessionID] != sessionID)
 | 
					
						
							|  |  |  |             continue;
 | 
					
						
							|  |  |  |         [_browserContexts removeObject:browserContext];
 | 
					
						
							|  |  |  |         return;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)quit
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma mark WKUIDelegate
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)webViewDidClose:(WKWebView *)webView {
 | 
					
						
							|  |  |  |     for (NSWindow *window in _headlessWindows) {
 | 
					
						
							|  |  |  |         if (webView.window != window)
 | 
					
						
							|  |  |  |             continue;
 | 
					
						
							|  |  |  |         [webView removeFromSuperview];
 | 
					
						
							|  |  |  |         [window close];
 | 
					
						
							|  |  |  |         [_headlessWindows removeObject:window];
 | 
					
						
							|  |  |  |         break;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-24 07:16:31 +08:00
										 |  |  | - (void)_webView:(WKWebView *)webView getWindowFrameWithCompletionHandler:(void (^)(CGRect))completionHandler
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     completionHandler([webView.window frame]);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-23 01:52:17 +08:00
										 |  |  | - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     WebViewDialog* dialog = [[WebViewDialog alloc] autorelease];
 | 
					
						
							|  |  |  |     dialog.webView = webView;
 | 
					
						
							|  |  |  |     dialog.completionHandler = ^void (BOOL accept, NSString* value) {
 | 
					
						
							|  |  |  |         completionHandler();
 | 
					
						
							|  |  |  |     };
 | 
					
						
							|  |  |  |     [_dialogs addObject:dialog];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     WebViewDialog* dialog = [[WebViewDialog alloc] autorelease];
 | 
					
						
							|  |  |  |     dialog.webView = webView;
 | 
					
						
							|  |  |  |     dialog.completionHandler = ^void (BOOL accept, NSString* value) {
 | 
					
						
							|  |  |  |         completionHandler(accept);
 | 
					
						
							|  |  |  |     };
 | 
					
						
							|  |  |  |     [_dialogs addObject:dialog];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *result))completionHandler
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     WebViewDialog* dialog = [[WebViewDialog alloc] autorelease];
 | 
					
						
							|  |  |  |     dialog.webView = webView;
 | 
					
						
							|  |  |  |     dialog.completionHandler = ^void (BOOL accept, NSString* value) {
 | 
					
						
							|  |  |  |         completionHandler(accept && value ? value : nil);
 | 
					
						
							|  |  |  |     };
 | 
					
						
							|  |  |  |     [_dialogs addObject:dialog];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)_webView:(WKWebView *)webView runBeforeUnloadConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     WebViewDialog* dialog = [[WebViewDialog alloc] autorelease];
 | 
					
						
							|  |  |  |     dialog.webView = webView;
 | 
					
						
							|  |  |  |     dialog.completionHandler = ^void (BOOL accept, NSString* value) {
 | 
					
						
							|  |  |  |         completionHandler(accept);
 | 
					
						
							|  |  |  |     };
 | 
					
						
							|  |  |  |     [_dialogs addObject:dialog];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)webView:(WKWebView *)webView handleJavaScriptDialog:(BOOL)accept value:(NSString *)value
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     for (WebViewDialog *dialog in _dialogs) {
 | 
					
						
							|  |  |  |         if (dialog.webView != webView)
 | 
					
						
							|  |  |  |             continue;
 | 
					
						
							|  |  |  |         dialog.completionHandler(accept, value);
 | 
					
						
							|  |  |  |         [_dialogs removeObject:dialog];
 | 
					
						
							|  |  |  |         break;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     return [self createHeadlessPage:configuration withURL:nil];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     LOG(@"decidePolicyForNavigationAction");
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 07:53:25 +08:00
										 |  |  |     if (navigationAction._shouldPerformDownload) {
 | 
					
						
							|  |  |  |         decisionHandler(_WKNavigationActionPolicyDownload);
 | 
					
						
							|  |  |  |         return;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-04-23 01:52:17 +08:00
										 |  |  |     if (navigationAction._canHandleRequest) {
 | 
					
						
							|  |  |  |         decisionHandler(WKNavigationActionPolicyAllow);
 | 
					
						
							|  |  |  |         return;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     decisionHandler(WKNavigationActionPolicyCancel);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     if (![navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
 | 
					
						
							|  |  |  |       decisionHandler(WKNavigationResponsePolicyAllow);
 | 
					
						
							|  |  |  |       return;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)navigationResponse.response;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSString *disposition = [[httpResponse allHeaderFields] objectForKey:@"Content-Disposition"];
 | 
					
						
							|  |  |  |     if (disposition && [disposition hasPrefix:@"attachment"]) {
 | 
					
						
							|  |  |  |         decisionHandler(_WKNavigationResponsePolicyBecomeDownload);
 | 
					
						
							|  |  |  |         return;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     decisionHandler(WKNavigationResponsePolicyAllow);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma mark _WKDownloadDelegate
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)_download:(_WKDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename completionHandler:(void (^)(BOOL allowOverwrite, NSString *destination))completionHandler
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |     completionHandler(NO, @"");
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @end
 |