cwv_web_view.mm 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #import "ios/web_view/internal/cwv_web_view_internal.h"
  5. #include <memory>
  6. #include <unordered_map>
  7. #include <utility>
  8. #import <WebKit/WebKit.h>
  9. #include "base/bind.h"
  10. #include "base/json/json_writer.h"
  11. #include "base/mac/foundation_util.h"
  12. #include "base/strings/sys_string_conversions.h"
  13. #import "components/autofill/ios/browser/autofill_agent.h"
  14. #include "components/autofill/ios/form_util/unique_id_data_tab_helper.h"
  15. #include "components/language/ios/browser/ios_language_detection_tab_helper.h"
  16. #include "components/password_manager/core/browser/password_manager.h"
  17. #import "components/password_manager/ios/ios_password_manager_driver.h"
  18. #import "components/password_manager/ios/shared_password_controller.h"
  19. #import "components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h"
  20. #include "components/url_formatter/elide_url.h"
  21. #include "google_apis/google_api_keys.h"
  22. #import "ios/components/security_interstitials/lookalikes/lookalike_url_container.h"
  23. #import "ios/components/security_interstitials/lookalikes/lookalike_url_tab_allow_list.h"
  24. #import "ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper.h"
  25. #import "ios/components/security_interstitials/safe_browsing/safe_browsing_client.h"
  26. #import "ios/components/security_interstitials/safe_browsing/safe_browsing_query_manager.h"
  27. #import "ios/components/security_interstitials/safe_browsing/safe_browsing_tab_helper.h"
  28. #import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
  29. #import "ios/web/public/deprecated/crw_js_injection_receiver.h"
  30. #include "ios/web/public/favicon/favicon_url.h"
  31. #include "ios/web/public/js_messaging/web_frame.h"
  32. #import "ios/web/public/js_messaging/web_frame_util.h"
  33. #import "ios/web/public/js_messaging/web_frames_manager.h"
  34. #import "ios/web/public/navigation/navigation_context.h"
  35. #import "ios/web/public/navigation/navigation_item.h"
  36. #import "ios/web/public/navigation/navigation_manager.h"
  37. #include "ios/web/public/navigation/referrer.h"
  38. #include "ios/web/public/navigation/reload_type.h"
  39. #import "ios/web/public/ui/context_menu_params.h"
  40. #import "ios/web/public/ui/crw_web_view_proxy.h"
  41. #import "ios/web/public/ui/crw_web_view_scroll_view_proxy.h"
  42. #import "ios/web/public/web_client.h"
  43. #import "ios/web/public/web_state.h"
  44. #import "ios/web/public/web_view_only/wk_web_view_configuration_util.h"
  45. #include "ios/web_view/internal/app/application_context.h"
  46. #import "ios/web_view/internal/autofill/cwv_autofill_controller_internal.h"
  47. #import "ios/web_view/internal/autofill/web_view_autofill_client_ios.h"
  48. #import "ios/web_view/internal/cwv_back_forward_list_internal.h"
  49. #import "ios/web_view/internal/cwv_favicon_internal.h"
  50. #import "ios/web_view/internal/cwv_html_element_internal.h"
  51. #import "ios/web_view/internal/cwv_navigation_action_internal.h"
  52. #import "ios/web_view/internal/cwv_script_command_internal.h"
  53. #import "ios/web_view/internal/cwv_ssl_status_internal.h"
  54. #import "ios/web_view/internal/cwv_web_view_configuration_internal.h"
  55. #import "ios/web_view/internal/language/web_view_url_language_histogram_factory.h"
  56. #import "ios/web_view/internal/passwords/web_view_password_manager_client.h"
  57. #import "ios/web_view/internal/safe_browsing/web_view_safe_browsing_client_factory.h"
  58. #import "ios/web_view/internal/translate/cwv_translation_controller_internal.h"
  59. #import "ios/web_view/internal/translate/web_view_translate_client.h"
  60. #include "ios/web_view/internal/web_view_browser_state.h"
  61. #include "ios/web_view/internal/web_view_global_state_util.h"
  62. #import "ios/web_view/internal/web_view_java_script_dialog_presenter.h"
  63. #import "ios/web_view/internal/web_view_message_handler_java_script_feature.h"
  64. #import "ios/web_view/internal/web_view_web_state_policy_decider.h"
  65. #import "ios/web_view/public/cwv_navigation_delegate.h"
  66. #import "ios/web_view/public/cwv_preview_element_info.h"
  67. #import "ios/web_view/public/cwv_ui_delegate.h"
  68. #import "ios/web_view/public/cwv_web_view_configuration.h"
  69. #import "net/base/mac/url_conversions.h"
  70. #include "ui/base/page_transition_types.h"
  71. #include "url/gurl.h"
  72. #if !defined(__has_feature) || !__has_feature(objc_arc)
  73. #error "This file requires ARC support."
  74. #endif
  75. namespace {
  76. // A key used in NSCoder to store the session storage object.
  77. NSString* const kSessionStorageKey = @"sessionStorage";
  78. // Converts base::Value expected to be a dictionary or list to NSDictionary or
  79. // NSArray, respectively.
  80. id NSObjectFromCollectionValue(const base::Value* value) {
  81. DCHECK(value->is_dict() || value->is_list())
  82. << "Incorrect value type: " << value->type();
  83. std::string json;
  84. const bool success = base::JSONWriter::Write(*value, &json);
  85. DCHECK(success) << "Failed to convert base::Value to JSON";
  86. NSData* json_data = [NSData dataWithBytes:json.c_str() length:json.length()];
  87. id ns_object = [NSJSONSerialization JSONObjectWithData:json_data
  88. options:kNilOptions
  89. error:nil];
  90. DCHECK(ns_object) << "Failed to convert JSON to Collection";
  91. return ns_object;
  92. }
  93. // Converts base::Value to an appropriate Obj-C object.
  94. // |value| must not be null.
  95. id NSObjectFromValue(const base::Value* value) {
  96. switch (value->type()) {
  97. case base::Value::Type::NONE:
  98. return nil;
  99. case base::Value::Type::BOOLEAN:
  100. return @(value->GetBool());
  101. case base::Value::Type::INTEGER:
  102. return @(value->GetInt());
  103. case base::Value::Type::DOUBLE:
  104. return @(value->GetDouble());
  105. case base::Value::Type::STRING:
  106. return base::SysUTF8ToNSString(value->GetString());
  107. case base::Value::Type::BINARY:
  108. // Unsupported.
  109. return nil;
  110. case base::Value::Type::DICT:
  111. case base::Value::Type::LIST:
  112. return NSObjectFromCollectionValue(value);
  113. }
  114. return nil;
  115. }
  116. // Converts base::Value expected to be a dictionary to NSDictionary.
  117. NSDictionary* NSDictionaryFromDictionaryValue(const base::Value& value) {
  118. DCHECK(value.is_dict()) << "Incorrect value type: " << value.type();
  119. NSDictionary* ns_dictionary = base::mac::ObjCCastStrict<NSDictionary>(
  120. NSObjectFromCollectionValue(&value));
  121. DCHECK(ns_dictionary) << "Failed to convert JSON to NSDictionary";
  122. return ns_dictionary;
  123. }
  124. // Converts base::Value::Dict to NSDictionary.
  125. NSDictionary* NSDictionaryFromDictValue(const base::Value::Dict& value) {
  126. std::string json;
  127. const bool success = base::JSONWriter::Write(value, &json);
  128. DCHECK(success) << "Failed to convert base::Value to JSON";
  129. NSData* json_data = [NSData dataWithBytes:json.c_str() length:json.length()];
  130. NSDictionary* ns_dictionary = base::mac::ObjCCastStrict<NSDictionary>(
  131. [NSJSONSerialization JSONObjectWithData:json_data
  132. options:kNilOptions
  133. error:nil]);
  134. DCHECK(ns_dictionary) << "Failed to convert JSON to NSDictionary";
  135. return ns_dictionary;
  136. }
  137. // A WebStateUserData to hold a reference to a corresponding CWVWebView.
  138. class WebViewHolder : public web::WebStateUserData<WebViewHolder> {
  139. public:
  140. explicit WebViewHolder(web::WebState* web_state) {}
  141. CWVWebView* web_view() const { return web_view_; }
  142. void set_web_view(CWVWebView* web_view) { web_view_ = web_view; }
  143. private:
  144. friend class web::WebStateUserData<WebViewHolder>;
  145. __weak CWVWebView* web_view_ = nil;
  146. WEB_STATE_USER_DATA_KEY_DECL();
  147. };
  148. WEB_STATE_USER_DATA_KEY_IMPL(WebViewHolder)
  149. } // namespace
  150. @interface CWVWebView () {
  151. CWVWebViewConfiguration* _configuration;
  152. std::unique_ptr<web::WebState> _webState;
  153. std::unique_ptr<web::WebStateDelegateBridge> _webStateDelegate;
  154. std::unique_ptr<web::WebStateObserverBridge> _webStateObserver;
  155. std::unique_ptr<ios_web_view::WebViewWebStatePolicyDecider>
  156. _webStatePolicyDecider;
  157. double _estimatedProgress;
  158. // Handles presentation of JavaScript dialogs.
  159. std::unique_ptr<ios_web_view::WebViewJavaScriptDialogPresenter>
  160. _javaScriptDialogPresenter;
  161. // Stores the script command callbacks with subscriptions.
  162. std::unordered_map<std::string,
  163. std::pair<web::WebState::ScriptCommandCallback,
  164. base::CallbackListSubscription>>
  165. _scriptCommandCallbacks;
  166. CRWSessionStorage* _cachedSessionStorage;
  167. // Stores the last NavigationContext::IsSameDocument() value from
  168. // |webState:didFinishNavigation:|.
  169. BOOL _lastDidFinishNavigationContextIsSameDocument;
  170. }
  171. // Redefine these properties as readwrite to define setters, which send KVO
  172. // notifications.
  173. @property(nonatomic, readwrite) double estimatedProgress;
  174. @property(nonatomic, readwrite) BOOL canGoBack;
  175. @property(nonatomic, readwrite) BOOL canGoForward;
  176. @property(nonatomic, readwrite) NSURL* lastCommittedURL;
  177. @property(nonatomic, readwrite) BOOL loading;
  178. @property(nonatomic, readwrite, copy) NSString* title;
  179. @property(nonatomic, readwrite) NSURL* visibleURL;
  180. @property(nonatomic, readwrite) NSString* visibleLocationString;
  181. @property(nonatomic, readwrite) CWVSSLStatus* visibleSSLStatus;
  182. // Updates the availability of the back/forward navigation properties exposed
  183. // through |canGoBack| and |canGoForward|, and also updates |backForwardList|.
  184. - (void)updateNavigationAvailability;
  185. // Updates the URLs exposed through |lastCommittedURL| and |visibleURL|.
  186. - (void)updateCurrentURLs;
  187. // Updates |title| property.
  188. - (void)updateTitle;
  189. // Returns a new CWVAutofillController created from |_webState|.
  190. - (CWVAutofillController*)newAutofillController;
  191. // Returns a new CWVTranslationController created from |_webState|.
  192. - (CWVTranslationController*)newTranslationController;
  193. // Updates |_webState| visiblity.
  194. - (void)updateWebStateVisibility;
  195. @end
  196. namespace {
  197. NSString* gCustomUserAgent = nil;
  198. NSString* gUserAgentProduct = nil;
  199. BOOL gChromeContextMenuEnabled = NO;
  200. } // namespace
  201. @implementation CWVWebView
  202. @synthesize autofillController = _autofillController;
  203. @synthesize backForwardList = _backForwardList;
  204. @synthesize canGoBack = _canGoBack;
  205. @synthesize canGoForward = _canGoForward;
  206. @synthesize configuration = _configuration;
  207. @synthesize estimatedProgress = _estimatedProgress;
  208. @synthesize lastCommittedURL = _lastCommittedURL;
  209. @synthesize loading = _loading;
  210. @synthesize navigationDelegate = _navigationDelegate;
  211. @synthesize title = _title;
  212. @synthesize translationController = _translationController;
  213. @synthesize UIDelegate = _UIDelegate;
  214. @synthesize visibleURL = _visibleURL;
  215. @synthesize visibleSSLStatus = _visibleSSLStatus;
  216. + (void)initialize {
  217. if (self != [CWVWebView class]) {
  218. return;
  219. }
  220. ios_web_view::InitializeGlobalState();
  221. }
  222. + (BOOL)chromeContextMenuEnabled {
  223. return gChromeContextMenuEnabled;
  224. }
  225. + (void)setChromeContextMenuEnabled:(BOOL)newValue {
  226. gChromeContextMenuEnabled = newValue;
  227. }
  228. + (NSString*)customUserAgent {
  229. return gCustomUserAgent;
  230. }
  231. + (void)setCustomUserAgent:(NSString*)customUserAgent {
  232. gCustomUserAgent = [customUserAgent copy];
  233. }
  234. + (NSString*)userAgentProduct {
  235. return gUserAgentProduct;
  236. }
  237. + (void)setUserAgentProduct:(NSString*)product {
  238. gUserAgentProduct = [product copy];
  239. }
  240. + (void)setGoogleAPIKey:(NSString*)googleAPIKey
  241. clientID:(NSString*)clientID
  242. clientSecret:(NSString*)clientSecret {
  243. google_apis::SetAPIKey(base::SysNSStringToUTF8(googleAPIKey));
  244. std::string clientIDString = base::SysNSStringToUTF8(clientID);
  245. std::string clientSecretString = base::SysNSStringToUTF8(clientSecret);
  246. for (size_t i = 0; i < google_apis::CLIENT_NUM_ITEMS; ++i) {
  247. google_apis::OAuth2Client client =
  248. static_cast<google_apis::OAuth2Client>(i);
  249. google_apis::SetOAuth2ClientID(client, clientIDString);
  250. google_apis::SetOAuth2ClientSecret(client, clientSecretString);
  251. }
  252. }
  253. + (CWVWebView*)webViewForWebState:(web::WebState*)webState {
  254. WebViewHolder* holder = WebViewHolder::FromWebState(webState);
  255. CWVWebView* webView = holder->web_view();
  256. DCHECK(webView);
  257. return webView;
  258. }
  259. - (instancetype)initWithFrame:(CGRect)frame
  260. configuration:(CWVWebViewConfiguration*)configuration {
  261. return [self initWithFrame:frame
  262. configuration:configuration
  263. WKConfiguration:nil
  264. createdWKWebView:nil];
  265. }
  266. - (instancetype)initWithFrame:(CGRect)frame
  267. configuration:(CWVWebViewConfiguration*)configuration
  268. WKConfiguration:(WKWebViewConfiguration*)wkConfiguration
  269. createdWKWebView:(WKWebView**)createdWebView {
  270. self = [super initWithFrame:frame];
  271. if (self) {
  272. _configuration = configuration;
  273. [_configuration registerWebView:self];
  274. [self resetWebStateWithSessionStorage:nil
  275. WKConfiguration:wkConfiguration
  276. createdWKWebView:createdWebView];
  277. }
  278. return self;
  279. }
  280. - (UIScrollView*)scrollView {
  281. return [_webState->GetWebViewProxy().scrollViewProxy asUIScrollView];
  282. }
  283. - (BOOL)allowsBackForwardNavigationGestures {
  284. return _webState->GetWebViewProxy().allowsBackForwardNavigationGestures;
  285. }
  286. - (void)setAllowsBackForwardNavigationGestures:
  287. (BOOL)allowsBackForwardNavigationGestures {
  288. _webState->GetWebViewProxy().allowsBackForwardNavigationGestures =
  289. allowsBackForwardNavigationGestures;
  290. }
  291. - (void)dealloc {
  292. if (_webState) {
  293. if (_webStateObserver) {
  294. _webState->RemoveObserver(_webStateObserver.get());
  295. _webStateObserver.reset();
  296. }
  297. WebViewHolder::RemoveFromWebState(_webState.get());
  298. }
  299. }
  300. - (void)goBack {
  301. if (_webState->GetNavigationManager())
  302. _webState->GetNavigationManager()->GoBack();
  303. }
  304. - (void)goForward {
  305. if (_webState->GetNavigationManager())
  306. _webState->GetNavigationManager()->GoForward();
  307. }
  308. - (BOOL)goToBackForwardListItem:(CWVBackForwardListItem*)item {
  309. if (!_backForwardList) {
  310. return NO; // Do nothing if |_backForwardList| is not generated yet.
  311. }
  312. if ([item isEqual:_backForwardList.currentItem]) {
  313. return NO;
  314. }
  315. int index = [_backForwardList internalIndexOfItem:item];
  316. if (index == -1) {
  317. return NO;
  318. }
  319. DCHECK(_webState);
  320. web::NavigationManager* navigationManager = _webState->GetNavigationManager();
  321. navigationManager->GoToIndex(index);
  322. return YES;
  323. }
  324. - (void)reload {
  325. // |check_for_repost| is false because CWVWebView does not support repost form
  326. // dialogs.
  327. _webState->GetNavigationManager()->Reload(web::ReloadType::NORMAL,
  328. false /* check_for_repost */);
  329. }
  330. - (void)stopLoading {
  331. _webState->Stop();
  332. }
  333. - (void)loadRequest:(NSURLRequest*)request {
  334. DCHECK_EQ(nil, request.HTTPBodyStream)
  335. << "request.HTTPBodyStream is not supported.";
  336. web::NavigationManager::WebLoadParams params(net::GURLWithNSURL(request.URL));
  337. params.transition_type = ui::PAGE_TRANSITION_TYPED;
  338. params.extra_headers = [request.allHTTPHeaderFields copy];
  339. params.post_data = [request.HTTPBody copy];
  340. _webState->GetNavigationManager()->LoadURLWithParams(params);
  341. [self updateCurrentURLs];
  342. }
  343. - (void)evaluateJavaScript:(NSString*)javaScriptString
  344. completionHandler:(void (^)(id, NSError*))completionHandler {
  345. [_webState->GetJSInjectionReceiver() executeJavaScript:javaScriptString
  346. completionHandler:completionHandler];
  347. }
  348. - (void)evaluateJavaScript:(NSString*)javaScriptString
  349. completion:(void (^)(id, BOOL))completion {
  350. web::WebFrame* mainFrame = web::GetMainFrame(_webState.get());
  351. if (!mainFrame) {
  352. if (completion) {
  353. completion(nil, NO);
  354. }
  355. return;
  356. }
  357. if (!completion) {
  358. mainFrame->ExecuteJavaScript(base::SysNSStringToUTF16(javaScriptString));
  359. return;
  360. }
  361. mainFrame->ExecuteJavaScript(
  362. base::SysNSStringToUTF16(javaScriptString),
  363. base::BindOnce(^(const base::Value* result, bool error) {
  364. id jsResult;
  365. if (!error && result) {
  366. jsResult = NSObjectFromValue(result);
  367. }
  368. completion(jsResult, !error);
  369. }));
  370. }
  371. - (void)setUIDelegate:(id<CWVUIDelegate>)UIDelegate {
  372. _UIDelegate = UIDelegate;
  373. _javaScriptDialogPresenter->SetUIDelegate(_UIDelegate);
  374. }
  375. - (void)setNavigationDelegate:(id<CWVNavigationDelegate>)navigationDelegate {
  376. _navigationDelegate = navigationDelegate;
  377. [self attachSecurityInterstitialHelpersToWebStateIfNecessary];
  378. }
  379. #pragma mark - UIResponder
  380. - (BOOL)becomeFirstResponder {
  381. if (_webState) {
  382. return [_webState->GetWebViewProxy() becomeFirstResponder];
  383. } else {
  384. return [super becomeFirstResponder];
  385. }
  386. }
  387. #pragma mark - UIView
  388. - (void)didMoveToSuperview {
  389. [super didMoveToSuperview];
  390. [self updateWebStateVisibility];
  391. }
  392. #pragma mark - CRWWebStateObserver
  393. - (void)webStateDestroyed:(web::WebState*)webState {
  394. webState->RemoveObserver(_webStateObserver.get());
  395. _webStateObserver.reset();
  396. }
  397. - (void)webState:(web::WebState*)webState
  398. didStartNavigation:(web::NavigationContext*)navigation {
  399. [self updateNavigationAvailability];
  400. if (!navigation->IsSameDocument()) {
  401. SEL oldSelector = @selector(webViewDidStartProvisionalNavigation:);
  402. if ([_navigationDelegate respondsToSelector:oldSelector]) {
  403. [_navigationDelegate webViewDidStartProvisionalNavigation:self];
  404. }
  405. SEL newSelector = @selector(webViewDidStartNavigation:);
  406. if ([_navigationDelegate respondsToSelector:newSelector]) {
  407. [_navigationDelegate webViewDidStartNavigation:self];
  408. }
  409. }
  410. }
  411. - (void)webState:(web::WebState*)webState
  412. didFinishNavigation:(web::NavigationContext*)navigation {
  413. [self updateNavigationAvailability];
  414. [self updateCurrentURLs];
  415. // TODO(crbug.com/898357): Remove this once crbug.com/898357 is fixed.
  416. [self updateVisibleSSLStatus];
  417. // Store NavigationContext::IsSameDocument() for later use in
  418. // |webState:didLoadPageWithSuccess:|.
  419. _lastDidFinishNavigationContextIsSameDocument = navigation->IsSameDocument();
  420. if (navigation->HasCommitted() && !navigation->IsSameDocument() &&
  421. [_navigationDelegate
  422. respondsToSelector:@selector(webViewDidCommitNavigation:)]) {
  423. [_navigationDelegate webViewDidCommitNavigation:self];
  424. }
  425. NSError* error = navigation->GetError();
  426. SEL selector = @selector(webView:didFailNavigationWithError:);
  427. if (error && [_navigationDelegate respondsToSelector:selector]) {
  428. [_navigationDelegate webView:self didFailNavigationWithError:error];
  429. }
  430. }
  431. - (void)webState:(web::WebState*)webState didLoadPageWithSuccess:(BOOL)success {
  432. DCHECK_EQ(_webState.get(), webState);
  433. if (!success) {
  434. // Failure callbacks will be handled inside |webState:didFinishNavigation:|.
  435. return;
  436. }
  437. // We do not want to call -[CWVNavigationDelegate webViewDidFinishNavigation:]
  438. // for same document navigations because we also exclude them for others like
  439. // -[CWVNavigationDelegate webViewDidStartNavigation:] and
  440. // -[CWVNavigationDelegate webViewDidCommitNavigation:].
  441. // It is guaranteed that |webState:didLoadPageWithSuccess:| is only called
  442. // after |webState:didFinishNavigation:|, so we will always have an up to date
  443. // value to use here.
  444. // TODO(crbug.com/1196799): Remove this work around once a NavigationContext
  445. // is passed in to this method.
  446. SEL selector = @selector(webViewDidFinishNavigation:);
  447. if (!_lastDidFinishNavigationContextIsSameDocument &&
  448. [_navigationDelegate respondsToSelector:selector]) {
  449. [_navigationDelegate webViewDidFinishNavigation:self];
  450. }
  451. }
  452. - (void)webState:(web::WebState*)webState
  453. didChangeLoadingProgress:(double)progress {
  454. self.estimatedProgress = progress;
  455. }
  456. - (void)webStateDidChangeBackForwardState:(web::WebState*)webState {
  457. [self updateNavigationAvailability];
  458. }
  459. - (void)webStateDidStopLoading:(web::WebState*)webState {
  460. self.loading = _webState->IsLoading();
  461. }
  462. - (void)webStateDidStartLoading:(web::WebState*)webState {
  463. self.loading = _webState->IsLoading();
  464. }
  465. - (void)webStateDidChangeTitle:(web::WebState*)webState {
  466. [self updateTitle];
  467. }
  468. - (void)webStateDidChangeVisibleSecurityState:(web::WebState*)webState {
  469. [self updateVisibleSSLStatus];
  470. }
  471. - (void)renderProcessGoneForWebState:(web::WebState*)webState {
  472. SEL selector = @selector(webViewWebContentProcessDidTerminate:);
  473. if ([_navigationDelegate respondsToSelector:selector]) {
  474. [_navigationDelegate webViewWebContentProcessDidTerminate:self];
  475. }
  476. }
  477. #pragma mark - CRWWebStateDelegate
  478. - (web::WebState*)webState:(web::WebState*)webState
  479. createNewWebStateForURL:(const GURL&)URL
  480. openerURL:(const GURL&)openerURL
  481. initiatedByUser:(BOOL)initiatedByUser {
  482. SEL selector =
  483. @selector(webView:createWebViewWithConfiguration:forNavigationAction:);
  484. if (![_UIDelegate respondsToSelector:selector]) {
  485. return nullptr;
  486. }
  487. NSURLRequest* request =
  488. [[NSURLRequest alloc] initWithURL:net::NSURLWithGURL(URL)];
  489. CWVNavigationAction* navigationAction =
  490. [[CWVNavigationAction alloc] initWithRequest:request
  491. userInitiated:initiatedByUser];
  492. CWVWebView* webView = [_UIDelegate webView:self
  493. createWebViewWithConfiguration:_configuration
  494. forNavigationAction:navigationAction];
  495. if (!webView) {
  496. return nullptr;
  497. }
  498. web::WebState* webViewWebState = webView->_webState.get();
  499. webViewWebState->SetHasOpener(true);
  500. return webViewWebState;
  501. }
  502. - (void)closeWebState:(web::WebState*)webState {
  503. SEL selector = @selector(webViewDidClose:);
  504. if ([_UIDelegate respondsToSelector:selector]) {
  505. [_UIDelegate webViewDidClose:self];
  506. }
  507. }
  508. - (web::WebState*)webState:(web::WebState*)webState
  509. openURLWithParams:(const web::WebState::OpenURLParams&)params {
  510. web::NavigationManager::WebLoadParams load_params(params.url);
  511. load_params.referrer = params.referrer;
  512. load_params.transition_type = params.transition;
  513. load_params.is_renderer_initiated = params.is_renderer_initiated;
  514. load_params.virtual_url = params.virtual_url;
  515. _webState->GetNavigationManager()->LoadURLWithParams(load_params);
  516. [self updateCurrentURLs];
  517. return _webState.get();
  518. }
  519. - (web::JavaScriptDialogPresenter*)javaScriptDialogPresenterForWebState:
  520. (web::WebState*)webState {
  521. return _javaScriptDialogPresenter.get();
  522. }
  523. - (void)webState:(web::WebState*)webState
  524. contextMenuConfigurationForParams:(const web::ContextMenuParams&)params
  525. completionHandler:(void (^)(UIContextMenuConfiguration*))
  526. completionHandler {
  527. SEL selector = @selector(webView:
  528. contextMenuConfigurationForElement:completionHandler:);
  529. if ([_UIDelegate respondsToSelector:selector]) {
  530. NSURL* hyperlink = net::NSURLWithGURL(params.link_url);
  531. NSURL* mediaSource = net::NSURLWithGURL(params.src_url);
  532. CWVHTMLElement* HTMLElement =
  533. [[CWVHTMLElement alloc] initWithHyperlink:hyperlink
  534. mediaSource:mediaSource
  535. text:params.text];
  536. [_UIDelegate webView:self
  537. contextMenuConfigurationForElement:HTMLElement
  538. completionHandler:completionHandler];
  539. } else {
  540. completionHandler(nil);
  541. }
  542. }
  543. - (void)webState:(web::WebState*)webState
  544. contextMenuWillCommitWithAnimator:
  545. (id<UIContextMenuInteractionCommitAnimating>)animator {
  546. SEL selector = @selector(webView:contextMenuWillCommitWithAnimator:);
  547. if ([_UIDelegate respondsToSelector:selector]) {
  548. [_UIDelegate webView:self contextMenuWillCommitWithAnimator:animator];
  549. }
  550. }
  551. - (void)webState:(web::WebState*)webState
  552. didUpdateFaviconURLCandidates:
  553. (const std::vector<web::FaviconURL>&)candidates {
  554. if ([_UIDelegate respondsToSelector:@selector(webView:didLoadFavicons:)]) {
  555. [_UIDelegate webView:self
  556. didLoadFavicons:[CWVFavicon faviconsFromFaviconURLs:candidates]];
  557. }
  558. }
  559. - (id<CRWResponderInputView>)webStateInputViewProvider:
  560. (web::WebState*)webState {
  561. if (self.inputAccessoryView != nil) {
  562. return self;
  563. } else {
  564. return nil;
  565. }
  566. }
  567. - (void)addScriptCommandHandler:(id<CWVScriptCommandHandler>)handler
  568. commandPrefix:(NSString*)commandPrefix {
  569. CWVWebView* __weak weakSelf = self;
  570. const web::WebState::ScriptCommandCallback callback = base::BindRepeating(
  571. ^(const base::Value& content, const GURL& mainDocumentURL,
  572. bool userInteracting, web::WebFrame* senderFrame) {
  573. NSDictionary* nsContent = NSDictionaryFromDictionaryValue(content);
  574. CWVScriptCommand* command = [[CWVScriptCommand alloc]
  575. initWithContent:nsContent
  576. mainDocumentURL:net::NSURLWithGURL(mainDocumentURL)
  577. userInteracting:userInteracting];
  578. [handler webView:weakSelf
  579. handleScriptCommand:command
  580. fromMainFrame:senderFrame->IsMainFrame()];
  581. });
  582. std::string stdCommandPrefix = base::SysNSStringToUTF8(commandPrefix);
  583. auto subscription =
  584. _webState->AddScriptCommandCallback(callback, stdCommandPrefix);
  585. _scriptCommandCallbacks[stdCommandPrefix] = {callback,
  586. std::move(subscription)};
  587. }
  588. - (void)removeScriptCommandHandlerForCommandPrefix:(NSString*)commandPrefix {
  589. std::string stdCommandPrefix = base::SysNSStringToUTF8(commandPrefix);
  590. _scriptCommandCallbacks.erase(stdCommandPrefix);
  591. }
  592. - (void)addMessageHandler:(void (^)(NSDictionary* payload))handler
  593. forCommand:(NSString*)nsCommand {
  594. DCHECK(handler);
  595. std::string command = base::SysNSStringToUTF8(nsCommand);
  596. WebViewMessageHandlerJavaScriptFeature::GetInstance()->RegisterHandler(
  597. command, base::BindRepeating(^(const base::Value::Dict& payload) {
  598. handler(NSDictionaryFromDictValue(payload));
  599. }));
  600. }
  601. - (void)removeMessageHandlerForCommand:(NSString*)nsCommand {
  602. std::string command = base::SysNSStringToUTF8(nsCommand);
  603. WebViewMessageHandlerJavaScriptFeature::GetInstance()->UnregisterHandler(
  604. command);
  605. }
  606. #pragma mark - Translation
  607. - (CWVTranslationController*)translationController {
  608. if (!_translationController) {
  609. _translationController = [self newTranslationController];
  610. }
  611. return _translationController;
  612. }
  613. - (CWVTranslationController*)newTranslationController {
  614. ios_web_view::WebViewBrowserState* browserState =
  615. ios_web_view::WebViewBrowserState::FromBrowserState(
  616. _webState->GetBrowserState());
  617. language::IOSLanguageDetectionTabHelper::CreateForWebState(
  618. _webState.get(),
  619. ios_web_view::WebViewUrlLanguageHistogramFactory::GetForBrowserState(
  620. browserState));
  621. auto translateClient = ios_web_view::WebViewTranslateClient::Create(
  622. browserState, _webState.get());
  623. return [[CWVTranslationController alloc]
  624. initWithWebState:_webState.get()
  625. translateClient:std::move(translateClient)];
  626. }
  627. #pragma mark - Autofill
  628. - (CWVAutofillController*)autofillController {
  629. if (!_autofillController) {
  630. _autofillController = [self newAutofillController];
  631. }
  632. return _autofillController;
  633. }
  634. - (CWVAutofillController*)newAutofillController {
  635. UniqueIDDataTabHelper::CreateForWebState(_webState.get());
  636. auto autofillClient = autofill::WebViewAutofillClientIOS::Create(
  637. _webState.get(), _configuration.browserState);
  638. AutofillAgent* autofillAgent = [[AutofillAgent alloc]
  639. initWithPrefService:_configuration.browserState->GetPrefs()
  640. webState:_webState.get()];
  641. auto passwordManagerClient =
  642. ios_web_view::WebViewPasswordManagerClient::Create(
  643. _webState.get(), _configuration.browserState);
  644. auto passwordManager = std::make_unique<password_manager::PasswordManager>(
  645. passwordManagerClient.get());
  646. PasswordFormHelper* formHelper =
  647. [[PasswordFormHelper alloc] initWithWebState:_webState.get()];
  648. PasswordSuggestionHelper* suggestionHelper =
  649. [[PasswordSuggestionHelper alloc] init];
  650. SharedPasswordController* passwordController =
  651. [[SharedPasswordController alloc] initWithWebState:_webState.get()
  652. manager:passwordManager.get()
  653. formHelper:formHelper
  654. suggestionHelper:suggestionHelper];
  655. auto passwordManagerDriver = std::make_unique<IOSPasswordManagerDriver>(
  656. passwordController, passwordManager.get());
  657. return [[CWVAutofillController alloc]
  658. initWithWebState:_webState.get()
  659. autofillClient:std::move(autofillClient)
  660. autofillAgent:autofillAgent
  661. passwordManager:std::move(passwordManager)
  662. passwordManagerClient:std::move(passwordManagerClient)
  663. passwordManagerDriver:std::move(passwordManagerDriver)
  664. passwordController:passwordController
  665. applicationLocale:ios_web_view::ApplicationContext::GetInstance()
  666. ->GetApplicationLocale()];
  667. }
  668. #pragma mark - Preserving and Restoring State
  669. - (void)encodeRestorableStateWithCoder:(NSCoder*)coder {
  670. [super encodeRestorableStateWithCoder:coder];
  671. // It is possible for this instance to be encoded when the |_webState| is a
  672. // nullptr, i.e. when this method is called after |shutDown| has occurred.
  673. CRWSessionStorage* sessionStorage;
  674. if (_webState) {
  675. sessionStorage = _webState->BuildSessionStorage();
  676. } else if (_cachedSessionStorage) {
  677. sessionStorage = _cachedSessionStorage;
  678. } else {
  679. return;
  680. }
  681. [coder encodeObject:sessionStorage forKey:kSessionStorageKey];
  682. }
  683. - (void)decodeRestorableStateWithCoder:(NSCoder*)coder {
  684. [super decodeRestorableStateWithCoder:coder];
  685. CRWSessionStorage* sessionStorage =
  686. [coder decodeObjectForKey:kSessionStorageKey];
  687. [self resetWebStateWithSessionStorage:sessionStorage
  688. WKConfiguration:nil
  689. createdWKWebView:nil];
  690. }
  691. #pragma mark - Private methods
  692. - (void)updateWebStateVisibility {
  693. if (_webState == nullptr) {
  694. return;
  695. }
  696. if (self.superview) {
  697. _webState->WasShown();
  698. } else {
  699. _webState->WasHidden();
  700. }
  701. }
  702. // Creates a WebState instance and assigns it to |_webState|.
  703. // It replaces the old |_webState| if any.
  704. // The WebState is restored from |sessionStorage| if provided.
  705. //
  706. // If |wkConfiguration| is provided, the underlying WKWebView is
  707. // initialized with |wkConfiguration|, and assigned to
  708. // |*createdWKWebView| if |createdWKWebView| is not nil.
  709. // |*createdWKWebView| will be provided only if |wkConfiguration| is provided,
  710. // otherwise it will always be reset to nil.
  711. - (void)resetWebStateWithSessionStorage:(CRWSessionStorage*)sessionStorage
  712. WKConfiguration:(WKWebViewConfiguration*)wkConfiguration
  713. createdWKWebView:(WKWebView**)createdWebView {
  714. if (_webState) {
  715. if (_webStateObserver) {
  716. _webState->RemoveObserver(_webStateObserver.get());
  717. }
  718. WebViewHolder::RemoveFromWebState(_webState.get());
  719. if (_webState->GetView().superview == self) {
  720. // The web view provided by the old |_webState| has been added as a
  721. // subview. It must be removed and replaced with a new |_webState|'s web
  722. // view, which is added later.
  723. [_webState->GetView() removeFromSuperview];
  724. }
  725. }
  726. BOOL allowsBackForwardNavigationGestures =
  727. _webState &&
  728. _webState->GetWebViewProxy().allowsBackForwardNavigationGestures;
  729. web::WebState::CreateParams webStateCreateParams(_configuration.browserState);
  730. if (sessionStorage) {
  731. _webState = web::WebState::CreateWithStorageSession(webStateCreateParams,
  732. sessionStorage);
  733. } else {
  734. _webState = web::WebState::Create(webStateCreateParams);
  735. }
  736. // WARNING: NOTHING should be here between |web::WebState::Create()| and
  737. // |web::EnsureWebViewCreatedWithConfiguration()|, as this is the requirement
  738. // of |web::EnsureWebViewCreatedWithConfiguration()|
  739. WKWebView* webView = nil;
  740. if (wkConfiguration) {
  741. // When |wkConfiguration| is nil, |self| could be a newly opened web view
  742. // e.g., triggered by JavaScript "window.open()" function. In that case, if
  743. // |self| is not created by the WKWebViewConfiguration provided by WebKit's
  744. // delegate method
  745. // (https://cs.chromium.org/chromium/src/ios/web/web_state/ui/crw_wk_ui_handler.mm?q=crw_wk_ui_handler&sq=package:chromium&dr=C&l=61)
  746. // then calling |web::EnsureWebViewCreatedWithConfiguration()| here would
  747. // result in a crash (https://crbug.com/1054276). Now, we lazily create the
  748. // WKWebView inside |_webState| when |wkConfiguration| is not nil, and the
  749. // correct WKWebViewConfiguration will be passed inside //ios/web.
  750. webView = web::EnsureWebViewCreatedWithConfiguration(_webState.get(),
  751. wkConfiguration);
  752. }
  753. if (createdWebView) {
  754. // If the created webView is needed, returns it by the out variable way.
  755. *createdWebView = webView;
  756. }
  757. [self attachSecurityInterstitialHelpersToWebStateIfNecessary];
  758. WebViewHolder::CreateForWebState(_webState.get());
  759. WebViewHolder::FromWebState(_webState.get())->set_web_view(self);
  760. if (!_webStateObserver) {
  761. _webStateObserver = std::make_unique<web::WebStateObserverBridge>(self);
  762. }
  763. _webState->AddObserver(_webStateObserver.get());
  764. if (_backForwardList) {
  765. _backForwardList.navigationManager = _webState->GetNavigationManager();
  766. }
  767. [self updateWebStateVisibility];
  768. _webStateDelegate = std::make_unique<web::WebStateDelegateBridge>(self);
  769. _webState->SetDelegate(_webStateDelegate.get());
  770. _webStatePolicyDecider =
  771. std::make_unique<ios_web_view::WebViewWebStatePolicyDecider>(
  772. _webState.get(), self);
  773. _javaScriptDialogPresenter =
  774. std::make_unique<ios_web_view::WebViewJavaScriptDialogPresenter>(self,
  775. nullptr);
  776. for (auto& pair : _scriptCommandCallbacks) {
  777. pair.second.second =
  778. _webState->AddScriptCommandCallback(pair.second.first, pair.first);
  779. }
  780. _webState->GetWebViewProxy().allowsBackForwardNavigationGestures =
  781. allowsBackForwardNavigationGestures;
  782. if (_translationController) {
  783. id<CWVTranslationControllerDelegate> delegate =
  784. _translationController.delegate;
  785. _translationController = [self newTranslationController];
  786. _translationController.delegate = delegate;
  787. }
  788. // Recreate and restore the delegate only if previously lazily loaded.
  789. if (_autofillController) {
  790. id<CWVAutofillControllerDelegate> delegate = _autofillController.delegate;
  791. _autofillController = [self newAutofillController];
  792. _autofillController.delegate = delegate;
  793. }
  794. [self addInternalWebViewAsSubview];
  795. [self updateNavigationAvailability];
  796. [self updateCurrentURLs];
  797. [self updateTitle];
  798. [self updateVisibleSSLStatus];
  799. self.loading = NO;
  800. self.estimatedProgress = 0.0;
  801. // TODO(crbug.com/873729): The session will not be restored until
  802. // LoadIfNecessary call. Fix the bug and remove extra call.
  803. if (sessionStorage) {
  804. _webState->GetNavigationManager()->LoadIfNecessary();
  805. }
  806. }
  807. // Adds the web view provided by |_webState| as a subview unless it has already.
  808. - (void)addInternalWebViewAsSubview {
  809. UIView* subview = _webState->GetView();
  810. if (subview.superview == self) {
  811. return;
  812. }
  813. subview.frame = self.bounds;
  814. subview.autoresizingMask =
  815. UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  816. [self addSubview:subview];
  817. }
  818. - (CWVBackForwardList*)backForwardList {
  819. if (!_backForwardList) {
  820. _backForwardList = [[CWVBackForwardList alloc]
  821. initWithNavigationManager:_webState->GetNavigationManager()];
  822. }
  823. return _backForwardList;
  824. }
  825. - (void)updateNavigationAvailability {
  826. self.canGoBack = _webState && _webState->GetNavigationManager()->CanGoBack();
  827. self.canGoForward =
  828. _webState && _webState->GetNavigationManager()->CanGoForward();
  829. self.backForwardList.navigationManager = _webState->GetNavigationManager();
  830. }
  831. - (void)updateCurrentURLs {
  832. self.lastCommittedURL = net::NSURLWithGURL(_webState->GetLastCommittedURL());
  833. self.visibleURL = net::NSURLWithGURL(_webState->GetVisibleURL());
  834. self.visibleLocationString = base::SysUTF16ToNSString(
  835. url_formatter::FormatUrlForSecurityDisplay(_webState->GetVisibleURL()));
  836. }
  837. - (void)updateTitle {
  838. self.title = base::SysUTF16ToNSString(_webState->GetTitle());
  839. }
  840. - (void)updateVisibleSSLStatus {
  841. web::NavigationItem* visibleItem =
  842. _webState->GetNavigationManager()->GetVisibleItem();
  843. if (visibleItem) {
  844. self.visibleSSLStatus =
  845. [[CWVSSLStatus alloc] initWithInternalStatus:visibleItem->GetSSL()];
  846. } else {
  847. self.visibleSSLStatus = nil;
  848. }
  849. }
  850. - (void)attachSecurityInterstitialHelpersToWebStateIfNecessary {
  851. if (!_webState) {
  852. return;
  853. }
  854. // Lookalike URLs should only be intercepted if handled by the delegate.
  855. if ([_navigationDelegate respondsToSelector:@selector
  856. (webView:handleLookalikeURLWithHandler:)]) {
  857. LookalikeUrlTabHelper::CreateForWebState(_webState.get());
  858. LookalikeUrlTabAllowList::CreateForWebState(_webState.get());
  859. LookalikeUrlContainer::CreateForWebState(_webState.get());
  860. } else {
  861. LookalikeUrlTabHelper::RemoveFromWebState(_webState.get());
  862. LookalikeUrlTabAllowList::RemoveFromWebState(_webState.get());
  863. LookalikeUrlContainer::RemoveFromWebState(_webState.get());
  864. }
  865. // Unsafe URLs should only be intercepted if handled by the delegate.
  866. if ([_navigationDelegate
  867. respondsToSelector:@selector(webView:handleUnsafeURLWithHandler:)]) {
  868. SafeBrowsingClient* client =
  869. ios_web_view::WebViewSafeBrowsingClientFactory::GetForBrowserState(
  870. _webState->GetBrowserState());
  871. SafeBrowsingQueryManager::CreateForWebState(_webState.get(), client);
  872. SafeBrowsingTabHelper::CreateForWebState(_webState.get(), client);
  873. SafeBrowsingUrlAllowList::CreateForWebState(_webState.get());
  874. SafeBrowsingUnsafeResourceContainer::CreateForWebState(_webState.get());
  875. } else {
  876. SafeBrowsingQueryManager::RemoveFromWebState(_webState.get());
  877. SafeBrowsingTabHelper::RemoveFromWebState(_webState.get());
  878. SafeBrowsingUrlAllowList::RemoveFromWebState(_webState.get());
  879. SafeBrowsingUnsafeResourceContainer::RemoveFromWebState(_webState.get());
  880. }
  881. }
  882. #pragma mark - Internal Methods
  883. - (void)shutDown {
  884. if (_webState) {
  885. // To handle the case where -[CWVWebView encodeRestorableStateWithCoder:] is
  886. // called after this method, precompute the session storage so it may be
  887. // used during encoding later.
  888. _cachedSessionStorage = _webState->BuildSessionStorage();
  889. if (_webStateObserver) {
  890. _webState->RemoveObserver(_webStateObserver.get());
  891. _webStateObserver.reset();
  892. }
  893. WebViewHolder::RemoveFromWebState(_webState.get());
  894. _webState.reset();
  895. }
  896. }
  897. @end