Commit 682eaa50 authored by David Jean's avatar David Jean Committed by Commit Bot

Reland "[ios] extract JS injection from web controller"

This is a reland of 950edae3

Original change's description:
> [ios] extract JS injection from web controller
> 
> Moved JS injection relative code to a new class in crw_js_injector.
> Updated CRWJSInjectionEvaluator to have a executeUserJavaScript that
> seemed to logicaly have been there already.
> 
> Bug: 954137
> Change-Id: I3a80c995de82329f22532d791c20d84b9ecbfe46
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1571703
> Commit-Queue: David Jean <djean@chromium.org>
> Reviewed-by: Eugene But <eugenebut@chromium.org>
> Reviewed-by: Mike Dougherty <michaeldo@chromium.org>
> Reviewed-by: Mark Cogan <marq@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#657195}

Bug: 954137
Change-Id: I1b4950cc3bf5c7ebe0f38b82c080324bd42c845f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1601051
Commit-Queue: David Jean <djean@chromium.org>
Reviewed-by: default avatarMike Dougherty <michaeldo@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#661292}
parent dcad7439
...@@ -37,6 +37,11 @@ ...@@ -37,6 +37,11 @@
web::ExecuteJavaScript(_webView, script, completionHandler); web::ExecuteJavaScript(_webView, script, completionHandler);
} }
- (void)executeUserJavaScript:(NSString*)script
completionHandler:(void (^)(id, NSError*))completionHandler {
web::ExecuteJavaScript(_webView, script, completionHandler);
}
- (BOOL)scriptHasBeenInjectedForClass:(Class)injectionManagerClass { - (BOOL)scriptHasBeenInjectedForClass:(Class)injectionManagerClass {
return [_injectedScriptManagers containsObject:injectionManagerClass]; return [_injectedScriptManagers containsObject:injectionManagerClass];
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#import "ios/web/public/web_client.h" #import "ios/web/public/web_client.h"
#include "ios/web/public/web_state/url_verification_constants.h" #include "ios/web/public/web_state/url_verification_constants.h"
#include "ios/web/public/web_state/web_state_observer.h" #include "ios/web/public/web_state/web_state_observer.h"
#import "ios/web/web_state/ui/crw_js_injector.h"
#import "ios/web/web_state/ui/crw_web_controller.h" #import "ios/web/web_state/ui/crw_web_controller.h"
#import "ios/web/web_state/ui/wk_web_view_configuration_provider.h" #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
#import "ios/web/web_state/web_state_impl.h" #import "ios/web/web_state/web_state_impl.h"
...@@ -207,7 +208,7 @@ id WebTestWithWebState::ExecuteJavaScript(NSString* script) { ...@@ -207,7 +208,7 @@ id WebTestWithWebState::ExecuteJavaScript(NSString* script) {
__block id execution_result = nil; __block id execution_result = nil;
__block bool execution_completed = false; __block bool execution_completed = false;
SCOPED_TRACE(base::SysNSStringToUTF8(script)); SCOPED_TRACE(base::SysNSStringToUTF8(script));
[GetWebController(web_state()) [GetWebController(web_state()).jsInjector
executeJavaScript:script executeJavaScript:script
completionHandler:^(id result, NSError* error) { completionHandler:^(id result, NSError* error) {
// Most of executed JS does not return the result, and there is no need // Most of executed JS does not return the result, and there is no need
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#import "base/test/ios/wait_util.h" #import "base/test/ios/wait_util.h"
#import "ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h" #import "ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h"
#import "ios/web/web_state/ui/crw_js_injector.h"
#import "ios/web/web_state/ui/crw_web_controller.h" #import "ios/web/web_state/ui/crw_web_controller.h"
#import "ios/web/web_state/ui/crw_web_view_proxy_impl.h" #import "ios/web/web_state/ui/crw_web_view_proxy_impl.h"
#import "ios/web/web_state/web_state_impl.h" #import "ios/web/web_state/web_state_impl.h"
...@@ -184,7 +185,7 @@ bool RunActionOnWebViewElementWithScript(web::WebState* web_state, ...@@ -184,7 +185,7 @@ bool RunActionOnWebViewElementWithScript(web::WebState* web_state,
// |executeUserJavaScript:completionHandler:| is no-op for app-specific URLs, // |executeUserJavaScript:completionHandler:| is no-op for app-specific URLs,
// so simulate a user gesture by calling TouchTracking method. // so simulate a user gesture by calling TouchTracking method.
[web_controller touched:YES]; [web_controller touched:YES];
[web_controller executeJavaScript:script [web_controller.jsInjector executeJavaScript:script
completionHandler:^(id result, NSError* error) { completionHandler:^(id result, NSError* error) {
did_complete = true; did_complete = true;
element_found = [result boolValue]; element_found = [result boolValue];
......
...@@ -16,6 +16,12 @@ ...@@ -16,6 +16,12 @@
- (void)executeJavaScript:(NSString*)script - (void)executeJavaScript:(NSString*)script
completionHandler:(void (^)(id, NSError*))completionHandler; completionHandler:(void (^)(id, NSError*))completionHandler;
// Asynchronously executes |javaScript| in the main frame's context,
// registering user interaction. For security reasons, some implementations may
// reject the request if the page has some elevated privileges.
- (void)executeUserJavaScript:(NSString*)script
completionHandler:(void (^)(id, NSError*))completionHandler;
// Checks to see if the script for a class has been injected into the // Checks to see if the script for a class has been injected into the
// current page already. // current page already.
- (BOOL)scriptHasBeenInjectedForClass:(Class)injectionManagerClass; - (BOOL)scriptHasBeenInjectedForClass:(Class)injectionManagerClass;
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#endif #endif
@implementation CRWJSInjectionReceiver { @implementation CRWJSInjectionReceiver {
// Used to evaluate JavaScripts. // Used to evaluate JavaScript.
__weak id<CRWJSInjectionEvaluator> _evaluator; __weak id<CRWJSInjectionEvaluator> _evaluator;
// Map from a CRWJSInjectionManager class to its instance created for this // Map from a CRWJSInjectionManager class to its instance created for this
...@@ -39,6 +39,11 @@ ...@@ -39,6 +39,11 @@
[_evaluator executeJavaScript:script completionHandler:completionHandler]; [_evaluator executeJavaScript:script completionHandler:completionHandler];
} }
- (void)executeUserJavaScript:(NSString*)script
completionHandler:(void (^)(id, NSError*))completionHandler {
[_evaluator executeUserJavaScript:script completionHandler:completionHandler];
}
- (BOOL)scriptHasBeenInjectedForClass:(Class)injectionManagerClass { - (BOOL)scriptHasBeenInjectedForClass:(Class)injectionManagerClass {
return [_evaluator scriptHasBeenInjectedForClass:injectionManagerClass]; return [_evaluator scriptHasBeenInjectedForClass:injectionManagerClass];
} }
......
...@@ -44,6 +44,8 @@ source_set("ui") { ...@@ -44,6 +44,8 @@ source_set("ui") {
] ]
sources = [ sources = [
"crw_js_injector.h",
"crw_js_injector.mm",
"crw_swipe_recognizer_provider.h", "crw_swipe_recognizer_provider.h",
"crw_touch_tracking_recognizer.h", "crw_touch_tracking_recognizer.h",
"crw_touch_tracking_recognizer.mm", "crw_touch_tracking_recognizer.mm",
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_WEB_WEB_STATE_UI_CRW_JS_INJECTOR_H_
#define IOS_WEB_WEB_STATE_UI_CRW_JS_INJECTOR_H_
#import <UIKit/UIKit.h>
#import "ios/web/public/web_state/js/crw_js_injection_evaluator.h"
#include "url/gurl.h"
@class CRWJSInjectionReceiver;
@class WKWebView;
@class CRWJSInjector;
@protocol CRWJSInjectorDelegate <NSObject>
// Tells delegate that user script is about to be executed.
- (void)willExecuteUserScriptForJSInjector:(CRWJSInjector*)injector;
// Returns the last committed URL by the delegate.
- (GURL)lastCommittedURLForJSInjector:(CRWJSInjector*)injector;
@end
// TODO(crbug.com/954137): This class is responsible for both "injection" and
// "execution" and probably should be split into separate classes (f.e.
// CRWJSExecutor and CRWLegacyInjector) when we get to the next phase of
// refactoring. CRWLegacyInjector would be removed at some point, while
// CRWJSExecutor would always stay around to support omnibox.
@interface CRWJSInjector : NSObject <CRWJSInjectionEvaluator>
@property(strong, nonatomic, readonly)
CRWJSInjectionReceiver* JSInjectionReceiver;
// Contains a web view, if one is associated.
@property(weak, nonatomic) WKWebView* webView;
// Designated initializer. Initializes with |delegate|.
- (instancetype)initWithDelegate:(id<CRWJSInjectorDelegate>)delegate;
// Resets list of all scripts injected with |injectScript|. Affects only results
// returned by |scriptHasBeenInjectedForClass|.
- (void)resetInjectedScriptSet;
// Injects windowId in the web page.
- (void)injectWindowID;
@end
#endif // IOS_WEB_WEB_STATE_UI_CRW_JS_INJECTOR_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/web/web_state/ui/crw_js_injector.h"
#import <WebKit/WebKit.h>
#include "base/logging.h"
#import "ios/web/public/web_client.h"
#import "ios/web/public/web_state/js/crw_js_injection_manager.h"
#import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
#import "ios/web/web_state/js/crw_js_window_id_manager.h"
#import "ios/web/web_state/ui/web_view_js_utils.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface CRWJSInjector () {
__weak id<CRWJSInjectorDelegate> _delegate;
// Script manager for setting the windowID.
CRWJSWindowIDManager* _windowIDJSManager;
// A set of script managers whose scripts have been injected into the current
// page.
NSMutableSet* _injectedScriptManagers;
}
@end
@implementation CRWJSInjector
- (instancetype)initWithDelegate:(id<CRWJSInjectorDelegate>)delegate {
self = [super init];
if (self) {
_delegate = delegate;
_JSInjectionReceiver =
[[CRWJSInjectionReceiver alloc] initWithEvaluator:self];
_injectedScriptManagers = [[NSMutableSet alloc] init];
}
return self;
}
- (void)resetInjectedScriptSet {
[_injectedScriptManagers removeAllObjects];
}
- (void)setWebView:(WKWebView*)webView {
_webView = webView;
if (webView) {
_windowIDJSManager = [[CRWJSWindowIDManager alloc] initWithWebView:webView];
} else {
_windowIDJSManager = nil;
}
}
- (void)injectWindowID {
[_windowIDJSManager inject];
}
#pragma mark - CRWJSInjectionEvaluator
- (void)executeJavaScript:(NSString*)script
completionHandler:(void (^)(id, NSError*))completionHandler {
NSString* safeScript = [self scriptByAddingWindowIDCheckForScript:script];
web::ExecuteJavaScript(self.webView, safeScript, completionHandler);
}
- (void)executeUserJavaScript:(NSString*)script
completionHandler:(void (^)(id, NSError*))completionHandler {
// For security reasons, executing JavaScript on pages with app-specific URLs
// is not allowed, because those pages may have elevated privileges.
GURL lastCommittedURL = [_delegate lastCommittedURLForJSInjector:self];
if (web::GetWebClient()->IsAppSpecificURL(lastCommittedURL)) {
if (completionHandler) {
dispatch_async(dispatch_get_main_queue(), ^{
NSError* error = [[NSError alloc]
initWithDomain:web::kJSEvaluationErrorDomain
code:web::JS_EVALUATION_ERROR_CODE_REJECTED
userInfo:nil];
completionHandler(nil, error);
});
}
return;
}
[_delegate willExecuteUserScriptForJSInjector:self];
[self executeJavaScript:script completionHandler:completionHandler];
}
- (BOOL)scriptHasBeenInjectedForClass:(Class)injectionManagerClass {
return [_injectedScriptManagers containsObject:injectionManagerClass];
}
- (void)injectScript:(NSString*)script forClass:(Class)JSInjectionManagerClass {
DCHECK(script.length);
// Script execution is an asynchronous operation which may pass sensitive
// data to the page. executeJavaScript:completionHandler makes sure that
// receiver page did not change by checking its window id.
// |[self.webView executeJavaScript:completionHandler:]| is not used here
// because it does not check that page is the same.
[self executeJavaScript:script completionHandler:nil];
[_injectedScriptManagers addObject:JSInjectionManagerClass];
}
#pragma mark - JavaScript Helpers (Private)
// Returns a new script which wraps |script| with windowID check so |script| is
// not evaluated on windowID mismatch.
- (NSString*)scriptByAddingWindowIDCheckForScript:(NSString*)script {
NSString* kTemplate = @"if (__gCrWeb['windowId'] === '%@') { %@; }";
return [NSString
stringWithFormat:kTemplate, [_windowIDJSManager windowID], script];
}
@end
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "ios/web/navigation/crw_session_controller.h" #import "ios/web/navigation/crw_session_controller.h"
#import "ios/web/public/web_state/js/crw_js_injection_evaluator.h"
#include "ios/web/public/web_state/url_verification_constants.h" #include "ios/web/public/web_state/url_verification_constants.h"
#import "ios/web/public/web_state/web_state.h" #import "ios/web/public/web_state/web_state.h"
#import "ios/web/web_state/ui/crw_touch_tracking_recognizer.h" #import "ios/web/web_state/ui/crw_touch_tracking_recognizer.h"
...@@ -21,7 +20,7 @@ enum class WKNavigationState; ...@@ -21,7 +20,7 @@ enum class WKNavigationState;
} // namespace web } // namespace web
@class CRWJSInjectionReceiver; @class CRWJSInjector;
@protocol CRWNativeContent; @protocol CRWNativeContent;
@protocol CRWNativeContentProvider; @protocol CRWNativeContentProvider;
@protocol CRWSwipeRecognizerProvider; @protocol CRWSwipeRecognizerProvider;
...@@ -41,9 +40,8 @@ class WebStateImpl; ...@@ -41,9 +40,8 @@ class WebStateImpl;
// web view. // web view.
// This is an abstract class which must not be instantiated directly. // This is an abstract class which must not be instantiated directly.
// TODO(stuartmorgan): Move all of the navigation APIs out of this class. // TODO(stuartmorgan): Move all of the navigation APIs out of this class.
@interface CRWWebController : NSObject <CRWJSInjectionEvaluator, @interface CRWWebController
CRWSessionControllerDelegate, : NSObject <CRWSessionControllerDelegate, CRWTouchTrackingDelegate>
CRWTouchTrackingDelegate>
// Whether or not a UIWebView is allowed to exist in this CRWWebController. // Whether or not a UIWebView is allowed to exist in this CRWWebController.
// Defaults to NO; this should be enabled before attempting to access the view. // Defaults to NO; this should be enabled before attempting to access the view.
...@@ -86,9 +84,8 @@ class WebStateImpl; ...@@ -86,9 +84,8 @@ class WebStateImpl;
// back-forward list navigations. // back-forward list navigations.
@property(nonatomic) BOOL allowsBackForwardNavigationGestures; @property(nonatomic) BOOL allowsBackForwardNavigationGestures;
// The receiver of JavaScripts. // JavaScript injector.
@property(nonatomic, strong, readonly) @property(nonatomic, strong, readonly) CRWJSInjector* jsInjector;
CRWJSInjectionReceiver* jsInjectionReceiver;
// Whether the WebController should attempt to keep the render process alive. // Whether the WebController should attempt to keep the render process alive.
@property(nonatomic, assign, getter=shouldKeepRenderProcessAlive) @property(nonatomic, assign, getter=shouldKeepRenderProcessAlive)
...@@ -166,13 +163,6 @@ class WebStateImpl; ...@@ -166,13 +163,6 @@ class WebStateImpl;
// Stops loading the page. // Stops loading the page.
- (void)stopLoading; - (void)stopLoading;
// Executes |script| in the web view, registering user interaction.
// |result| will be backed up by different classes depending on resulting JS
// type: NSString (string), NSNumber (number or boolean), NSDictionary (object),
// NSArray (array), NSNull (null), NSDate (Date), nil (undefined).
- (void)executeUserJavaScript:(NSString*)script
completionHandler:(void (^)(id result, NSError*))completion;
// Requires that the next load rebuild the web view. This is expensive, and // Requires that the next load rebuild the web view. This is expensive, and
// should be used only in the case where something has changed that the web view // should be used only in the case where something has changed that the web view
// only checks on creation, such that the whole object needs to be rebuilt. // only checks on creation, such that the whole object needs to be rebuilt.
......
...@@ -78,8 +78,6 @@ ...@@ -78,8 +78,6 @@
#import "ios/web/public/url_scheme_util.h" #import "ios/web/public/url_scheme_util.h"
#import "ios/web/public/web_client.h" #import "ios/web/public/web_client.h"
#import "ios/web/public/web_state/context_menu_params.h" #import "ios/web/public/web_state/context_menu_params.h"
#import "ios/web/public/web_state/js/crw_js_injection_manager.h"
#import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
#import "ios/web/public/web_state/page_display_state.h" #import "ios/web/public/web_state/page_display_state.h"
#import "ios/web/public/web_state/ui/crw_context_menu_delegate.h" #import "ios/web/public/web_state/ui/crw_context_menu_delegate.h"
#import "ios/web/public/web_state/ui/crw_native_content.h" #import "ios/web/public/web_state/ui/crw_native_content.h"
...@@ -93,10 +91,10 @@ ...@@ -93,10 +91,10 @@
#import "ios/web/public/web_state/web_state_policy_decider.h" #import "ios/web/public/web_state/web_state_policy_decider.h"
#include "ios/web/public/webui/web_ui_ios.h" #include "ios/web/public/webui/web_ui_ios.h"
#import "ios/web/web_state/error_translation_util.h" #import "ios/web/web_state/error_translation_util.h"
#import "ios/web/web_state/js/crw_js_window_id_manager.h"
#import "ios/web/web_state/page_viewport_state.h" #import "ios/web/web_state/page_viewport_state.h"
#import "ios/web/web_state/session_certificate_policy_cache_impl.h" #import "ios/web/web_state/session_certificate_policy_cache_impl.h"
#import "ios/web/web_state/ui/crw_context_menu_controller.h" #import "ios/web/web_state/ui/crw_context_menu_controller.h"
#import "ios/web/web_state/ui/crw_js_injector.h"
#import "ios/web/web_state/ui/crw_swipe_recognizer_provider.h" #import "ios/web/web_state/ui/crw_swipe_recognizer_provider.h"
#import "ios/web/web_state/ui/crw_web_controller.h" #import "ios/web/web_state/ui/crw_web_controller.h"
#import "ios/web/web_state/ui/crw_web_controller_container_view.h" #import "ios/web/web_state/ui/crw_web_controller_container_view.h"
...@@ -218,6 +216,7 @@ bool RequiresContentFilterBlockingWorkaround() { ...@@ -218,6 +216,7 @@ bool RequiresContentFilterBlockingWorkaround() {
@interface CRWWebController () <BrowsingDataRemoverObserver, @interface CRWWebController () <BrowsingDataRemoverObserver,
CRWWKNavigationHandlerDelegate, CRWWKNavigationHandlerDelegate,
CRWContextMenuDelegate, CRWContextMenuDelegate,
CRWJSInjectorDelegate,
CRWNativeContentDelegate, CRWNativeContentDelegate,
CRWSSLStatusUpdaterDataSource, CRWSSLStatusUpdaterDataSource,
CRWSSLStatusUpdaterDelegate, CRWSSLStatusUpdaterDelegate,
...@@ -264,19 +263,6 @@ bool RequiresContentFilterBlockingWorkaround() { ...@@ -264,19 +263,6 @@ bool RequiresContentFilterBlockingWorkaround() {
// history navigations. // history navigations.
BOOL _dispatchingSameDocumentHashChangeEvent; BOOL _dispatchingSameDocumentHashChangeEvent;
// A set of script managers whose scripts have been injected into the current
// page.
// TODO(stuartmorgan): Revisit this approach; it's intended only as a stopgap
// measure to make all the existing script managers work. Longer term, there
// should probably be a couple of points where managers can register to have
// things happen automatically based on page lifecycle, and if they don't want
// to use one of those fixed points, they should make their scripts internally
// idempotent.
NSMutableSet* _injectedScriptManagers;
// Script manager for setting the windowID.
CRWJSWindowIDManager* _windowIDJSManager;
// Backs up property with the same name. // Backs up property with the same name.
std::unique_ptr<web::MojoFacade> _mojoFacade; std::unique_ptr<web::MojoFacade> _mojoFacade;
...@@ -441,9 +427,6 @@ bool RequiresContentFilterBlockingWorkaround() { ...@@ -441,9 +427,6 @@ bool RequiresContentFilterBlockingWorkaround() {
senderFrame:(web::WebFrame*)senderFrame; senderFrame:(web::WebFrame*)senderFrame;
// Called when web controller receives a new message from the web page. // Called when web controller receives a new message from the web page.
- (void)didReceiveScriptMessage:(WKScriptMessage*)message; - (void)didReceiveScriptMessage:(WKScriptMessage*)message;
// Returns a new script which wraps |script| with windowID check so |script| is
// not evaluated on windowID mismatch.
- (NSString*)scriptByAddingWindowIDCheckForScript:(NSString*)script;
// Attempts to handle a script message. Returns YES on success, NO otherwise. // Attempts to handle a script message. Returns YES on success, NO otherwise.
- (BOOL)respondToWKScriptMessage:(WKScriptMessage*)scriptMessage; - (BOOL)respondToWKScriptMessage:(WKScriptMessage*)scriptMessage;
// Handles frame became available message. // Handles frame became available message.
...@@ -568,8 +551,7 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -568,8 +551,7 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
_navigationState = web::WKNavigationState::FINISHED; _navigationState = web::WKNavigationState::FINISHED;
// Content area is lazily instantiated. // Content area is lazily instantiated.
_defaultURL = GURL(url::kAboutBlankURL); _defaultURL = GURL(url::kAboutBlankURL);
_jsInjectionReceiver = _jsInjector = [[CRWJSInjector alloc] initWithDelegate:self];
[[CRWJSInjectionReceiver alloc] initWithEvaluator:self];
_webViewProxy = [[CRWWebViewProxyImpl alloc] initWithWebController:self]; _webViewProxy = [[CRWWebViewProxyImpl alloc] initWithWebController:self];
[[_webViewProxy scrollViewProxy] addObserver:self]; [[_webViewProxy scrollViewProxy] addObserver:self];
_pendingLoadCompleteActions = [[NSMutableArray alloc] init]; _pendingLoadCompleteActions = [[NSMutableArray alloc] init];
...@@ -703,11 +685,8 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -703,11 +685,8 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
} }
name:kFrameBecameUnavailableMessageName name:kFrameBecameUnavailableMessageName
webView:webView]; webView:webView];
_windowIDJSManager = [[CRWJSWindowIDManager alloc] initWithWebView:webView];
} else {
_windowIDJSManager = nil;
} }
[_jsInjector setWebView:webView];
[_webView setNavigationDelegate:self]; [_webView setNavigationDelegate:self];
[_webView setUIDelegate:self]; [_webView setUIDelegate:self];
for (NSString* keyPath in self.WKWebViewObservers) { for (NSString* keyPath in self.WKWebViewObservers) {
...@@ -715,7 +694,6 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -715,7 +694,6 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
} }
_webView.allowsBackForwardNavigationGestures = _webView.allowsBackForwardNavigationGestures =
_allowsBackForwardNavigationGestures; _allowsBackForwardNavigationGestures;
_injectedScriptManagers = [[NSMutableSet alloc] init];
[self setDocumentURL:_defaultURL context:nullptr]; [self setDocumentURL:_defaultURL context:nullptr];
} }
...@@ -1289,28 +1267,6 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -1289,28 +1267,6 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
forNavigation:navigation]; forNavigation:navigation];
} }
- (void)executeUserJavaScript:(NSString*)script
completionHandler:(void (^)(id, NSError*))completion {
// For security reasons, executing JavaScript on pages with app-specific URLs
// is not allowed, because those pages may have elevated privileges.
GURL lastCommittedURL = self.webState->GetLastCommittedURL();
if (web::GetWebClient()->IsAppSpecificURL(lastCommittedURL)) {
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
NSError* error = [[NSError alloc]
initWithDomain:web::kJSEvaluationErrorDomain
code:web::JS_EVALUATION_ERROR_CODE_NO_WEB_VIEW
userInfo:nil];
completion(nil, error);
});
}
return;
}
[self touched:YES];
[self executeJavaScript:script completionHandler:completion];
}
- (void)requirePageReconstruction { - (void)requirePageReconstruction {
// TODO(crbug.com/736103): Removing web view will destroy session history for // TODO(crbug.com/736103): Removing web view will destroy session history for
// WKBasedNavigationManager. // WKBasedNavigationManager.
...@@ -1462,29 +1418,6 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -1462,29 +1418,6 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
}]; }];
} }
#pragma mark - CRWJSInjectionEvaluator (Public)
- (void)executeJavaScript:(NSString*)script
completionHandler:(void (^)(id, NSError*))completionHandler {
NSString* safeScript = [self scriptByAddingWindowIDCheckForScript:script];
web::ExecuteJavaScript(self.webView, safeScript, completionHandler);
}
- (BOOL)scriptHasBeenInjectedForClass:(Class)injectionManagerClass {
return [_injectedScriptManagers containsObject:injectionManagerClass];
}
- (void)injectScript:(NSString*)script forClass:(Class)JSInjectionManagerClass {
DCHECK(script.length);
// Script execution is an asynchronous operation which may pass sensitive
// data to the page. executeJavaScript:completionHandler makes sure that
// receiver page did not change by checking its window id.
// |[self.webView executeJavaScript:completionHandler:]| is not used here
// because it does not check that page is the same.
[self executeJavaScript:script completionHandler:nil];
[_injectedScriptManagers addObject:JSInjectionManagerClass];
}
#pragma mark - CRWSessionControllerDelegate (Public) #pragma mark - CRWSessionControllerDelegate (Public)
- (web::NavigationItemImpl*)pendingItemForSessionController: - (web::NavigationItemImpl*)pendingItemForSessionController:
...@@ -2475,7 +2408,7 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -2475,7 +2408,7 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
[script appendString:[self javaScriptToDispatchHashChangeWithOldURL:oldURL [script appendString:[self javaScriptToDispatchHashChangeWithOldURL:oldURL
newURL:URL]]; newURL:URL]];
} }
[self executeJavaScript:script completionHandler:nil]; [_jsInjector executeJavaScript:script completionHandler:nil];
} }
#pragma mark - Native Content #pragma mark - Native Content
...@@ -2702,12 +2635,6 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -2702,12 +2635,6 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
} }
} }
- (NSString*)scriptByAddingWindowIDCheckForScript:(NSString*)script {
NSString* kTemplate = @"if (__gCrWeb['windowId'] === '%@') { %@; }";
return [NSString
stringWithFormat:kTemplate, [_windowIDJSManager windowID], script];
}
- (BOOL)respondToWKScriptMessage:(WKScriptMessage*)scriptMessage { - (BOOL)respondToWKScriptMessage:(WKScriptMessage*)scriptMessage {
if (![scriptMessage.name isEqualToString:kScriptMessageName]) { if (![scriptMessage.name isEqualToString:kScriptMessageName]) {
return NO; return NO;
...@@ -3021,7 +2948,7 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -3021,7 +2948,7 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
NSString* replaceWebViewJS = [self javaScriptToReplaceWebViewURL:pushURL NSString* replaceWebViewJS = [self javaScriptToReplaceWebViewURL:pushURL
stateObjectJSON:stateObject]; stateObjectJSON:stateObject];
__weak CRWWebController* weakSelf = self; __weak CRWWebController* weakSelf = self;
[self executeJavaScript:replaceWebViewJS [_jsInjector executeJavaScript:replaceWebViewJS
completionHandler:^(id, NSError*) { completionHandler:^(id, NSError*) {
CRWWebController* strongSelf = weakSelf; CRWWebController* strongSelf = weakSelf;
if (strongSelf && !strongSelf->_isBeingDestroyed) { if (strongSelf && !strongSelf->_isBeingDestroyed) {
...@@ -3081,7 +3008,7 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -3081,7 +3008,7 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
NSString* replaceStateJS = [self javaScriptToReplaceWebViewURL:replaceURL NSString* replaceStateJS = [self javaScriptToReplaceWebViewURL:replaceURL
stateObjectJSON:stateObject]; stateObjectJSON:stateObject];
__weak CRWWebController* weakSelf = self; __weak CRWWebController* weakSelf = self;
[self executeJavaScript:replaceStateJS [_jsInjector executeJavaScript:replaceStateJS
completionHandler:^(id, NSError*) { completionHandler:^(id, NSError*) {
CRWWebController* strongSelf = weakSelf; CRWWebController* strongSelf = weakSelf;
if (!strongSelf || strongSelf->_isBeingDestroyed) if (!strongSelf || strongSelf->_isBeingDestroyed)
...@@ -3313,14 +3240,16 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -3313,14 +3240,16 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
// window.scrollTo while user is scrolling. See crbug.com/554257 // window.scrollTo while user is scrolling. See crbug.com/554257
- (void)webViewScrollViewWillBeginDragging: - (void)webViewScrollViewWillBeginDragging:
(CRWWebViewScrollViewProxy*)webViewScrollViewProxy { (CRWWebViewScrollViewProxy*)webViewScrollViewProxy {
[self executeJavaScript:@"__gCrWeb.setWebViewScrollViewIsDragging(true)" [_jsInjector
executeJavaScript:@"__gCrWeb.setWebViewScrollViewIsDragging(true)"
completionHandler:nil]; completionHandler:nil];
} }
- (void)webViewScrollViewDidEndDragging: - (void)webViewScrollViewDidEndDragging:
(CRWWebViewScrollViewProxy*)webViewScrollViewProxy (CRWWebViewScrollViewProxy*)webViewScrollViewProxy
willDecelerate:(BOOL)decelerate { willDecelerate:(BOOL)decelerate {
[self executeJavaScript:@"__gCrWeb.setWebViewScrollViewIsDragging(false)" [_jsInjector
executeJavaScript:@"__gCrWeb.setWebViewScrollViewIsDragging(false)"
completionHandler:nil]; completionHandler:nil];
} }
...@@ -3344,7 +3273,7 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -3344,7 +3273,7 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
"viewport ? viewport.content : '';"; "viewport ? viewport.content : '';";
__weak CRWWebController* weakSelf = self; __weak CRWWebController* weakSelf = self;
int itemID = currentItem->GetUniqueID(); int itemID = currentItem->GetUniqueID();
[self executeJavaScript:kViewportContentQuery [_jsInjector executeJavaScript:kViewportContentQuery
completionHandler:^(id viewportContent, NSError*) { completionHandler:^(id viewportContent, NSError*) {
web::NavigationItem* item = [weakSelf currentNavItem]; web::NavigationItem* item = [weakSelf currentNavItem];
if (item && item->GetUniqueID() == itemID) { if (item && item->GetUniqueID() == itemID) {
...@@ -4691,13 +4620,13 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -4691,13 +4620,13 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
// |loadHTMLString:baseURL| navigation is committed. // |loadHTMLString:baseURL| navigation is committed.
if (!web::GetWebClient()->IsSlimNavigationManagerEnabled() || if (!web::GetWebClient()->IsSlimNavigationManagerEnabled() ||
!IsPlaceholderUrl(webViewURL)) { !IsPlaceholderUrl(webViewURL)) {
_injectedScriptManagers = [[NSMutableSet alloc] init]; [_jsInjector resetInjectedScriptSet];
if ([self contentIsHTML] || [self contentIsImage] || if ([self contentIsHTML] || [self contentIsImage] ||
self.webState->GetContentsMimeType().empty()) { self.webState->GetContentsMimeType().empty()) {
// In unit tests MIME type will be empty, because loadHTML:forURL: does // In unit tests MIME type will be empty, because loadHTML:forURL: does
// not notify web view delegate about received response, so web controller // not notify web view delegate about received response, so web controller
// does not get a chance to properly update MIME type. // does not get a chance to properly update MIME type.
[_windowIDJSManager inject]; [_jsInjector injectWindowID];
web::WebFramesManagerImpl::FromWebState(self.webState) web::WebFramesManagerImpl::FromWebState(self.webState)
->RegisterExistingFrames(); ->RegisterExistingFrames();
} }
...@@ -5596,7 +5525,18 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -5596,7 +5525,18 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
- (void)webView:(WKWebView*)webView - (void)webView:(WKWebView*)webView
executeJavaScript:(NSString*)javaScript executeJavaScript:(NSString*)javaScript
completionHandler:(void (^)(id, NSError*))completionHandler { completionHandler:(void (^)(id, NSError*))completionHandler {
[self executeJavaScript:javaScript completionHandler:completionHandler]; [_jsInjector executeJavaScript:javaScript
completionHandler:completionHandler];
}
#pragma mark - CRWJSInjectorDelegate methods
- (GURL)lastCommittedURLForJSInjector:(CRWJSInjector*)injector {
return self.webState->GetLastCommittedURL();
}
- (void)willExecuteUserScriptForJSInjector:(CRWJSInjector*)injector {
[self touched:YES];
} }
#pragma mark - CRWNativeContentDelegate methods #pragma mark - CRWNativeContentDelegate methods
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include "ios/web/test/test_url_constants.h" #include "ios/web/test/test_url_constants.h"
#import "ios/web/test/web_test_with_web_controller.h" #import "ios/web/test/web_test_with_web_controller.h"
#import "ios/web/test/wk_web_view_crash_utils.h" #import "ios/web/test/wk_web_view_crash_utils.h"
#import "ios/web/web_state/ui/crw_js_injector.h"
#import "ios/web/web_state/ui/crw_web_controller.h" #import "ios/web/web_state/ui/crw_web_controller.h"
#import "ios/web/web_state/ui/crw_web_controller_container_view.h" #import "ios/web/web_state/ui/crw_web_controller_container_view.h"
#import "ios/web/web_state/ui/web_view_js_utils.h" #import "ios/web/web_state/ui/web_view_js_utils.h"
...@@ -1224,7 +1225,7 @@ class ScriptExecutionTest : public ProgrammaticWebTestWithWebController { ...@@ -1224,7 +1225,7 @@ class ScriptExecutionTest : public ProgrammaticWebTestWithWebController {
__block id script_result = nil; __block id script_result = nil;
__block NSError* script_error = nil; __block NSError* script_error = nil;
__block bool script_executed = false; __block bool script_executed = false;
[web_controller() [web_controller().jsInjector
executeUserJavaScript:java_script executeUserJavaScript:java_script
completionHandler:^(id local_result, NSError* local_error) { completionHandler:^(id local_result, NSError* local_error) {
script_result = local_result; script_result = local_result;
...@@ -1272,7 +1273,7 @@ TEST_P(ScriptExecutionTest, UserScriptOnAppSpecificPage) { ...@@ -1272,7 +1273,7 @@ TEST_P(ScriptExecutionTest, UserScriptOnAppSpecificPage) {
EXPECT_FALSE(ExecuteUserJavaScript(@"window.w = 0;", &error)); EXPECT_FALSE(ExecuteUserJavaScript(@"window.w = 0;", &error));
ASSERT_TRUE(error); ASSERT_TRUE(error);
EXPECT_NSEQ(kJSEvaluationErrorDomain, error.domain); EXPECT_NSEQ(kJSEvaluationErrorDomain, error.domain);
EXPECT_EQ(JS_EVALUATION_ERROR_CODE_NO_WEB_VIEW, error.code); EXPECT_EQ(JS_EVALUATION_ERROR_CODE_REJECTED, error.code);
EXPECT_FALSE(ExecuteJavaScript(@"window.w")); EXPECT_FALSE(ExecuteJavaScript(@"window.w"));
} }
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "ios/web/public/webui/web_ui_ios_controller.h" #include "ios/web/public/webui/web_ui_ios_controller.h"
#include "ios/web/web_state/global_web_state_event_tracker.h" #include "ios/web/web_state/global_web_state_event_tracker.h"
#import "ios/web/web_state/session_certificate_policy_cache_impl.h" #import "ios/web/web_state/session_certificate_policy_cache_impl.h"
#import "ios/web/web_state/ui/crw_js_injector.h"
#import "ios/web/web_state/ui/crw_web_controller.h" #import "ios/web/web_state/ui/crw_web_controller.h"
#import "ios/web/web_state/ui/crw_web_controller_container_view.h" #import "ios/web/web_state/ui/crw_web_controller_container_view.h"
#import "ios/web/web_state/ui/crw_web_view_navigation_proxy.h" #import "ios/web/web_state/ui/crw_web_view_navigation_proxy.h"
...@@ -647,32 +648,33 @@ void WebStateImpl::LoadData(NSData* data, ...@@ -647,32 +648,33 @@ void WebStateImpl::LoadData(NSData* data,
} }
CRWJSInjectionReceiver* WebStateImpl::GetJSInjectionReceiver() const { CRWJSInjectionReceiver* WebStateImpl::GetJSInjectionReceiver() const {
return [web_controller_ jsInjectionReceiver]; return [web_controller_.jsInjector JSInjectionReceiver];
} }
void WebStateImpl::ExecuteJavaScript(const base::string16& javascript) { void WebStateImpl::ExecuteJavaScript(const base::string16& javascript) {
[web_controller_ executeJavaScript:base::SysUTF16ToNSString(javascript) [web_controller_.jsInjector
executeJavaScript:base::SysUTF16ToNSString(javascript)
completionHandler:nil]; completionHandler:nil];
} }
void WebStateImpl::ExecuteJavaScript(const base::string16& javascript, void WebStateImpl::ExecuteJavaScript(const base::string16& javascript,
JavaScriptResultCallback callback) { JavaScriptResultCallback callback) {
__block JavaScriptResultCallback stack_callback = std::move(callback); __block JavaScriptResultCallback stack_callback = std::move(callback);
[web_controller_ executeJavaScript:base::SysUTF16ToNSString(javascript) [web_controller_.jsInjector
executeJavaScript:base::SysUTF16ToNSString(javascript)
completionHandler:^(id value, NSError* error) { completionHandler:^(id value, NSError* error) {
if (error) { if (error) {
DLOG(WARNING) DLOG(WARNING) << "Script execution has failed: "
<< "Script execution has failed: "
<< base::SysNSStringToUTF16( << base::SysNSStringToUTF16(
error.userInfo[NSLocalizedDescriptionKey]); error.userInfo[NSLocalizedDescriptionKey]);
} }
std::move(stack_callback) std::move(stack_callback).Run(ValueResultFromWKResult(value).get());
.Run(ValueResultFromWKResult(value).get());
}]; }];
} }
void WebStateImpl::ExecuteUserJavaScript(NSString* javaScript) { void WebStateImpl::ExecuteUserJavaScript(NSString* javaScript) {
[web_controller_ executeUserJavaScript:javaScript completionHandler:nil]; [web_controller_.jsInjector executeUserJavaScript:javaScript
completionHandler:nil];
} }
const std::string& WebStateImpl::GetContentsMimeType() const { const std::string& WebStateImpl::GetContentsMimeType() const {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment