blob: dbf9d04dc340b592dd3ddbac9d90ad439e57c22c [file] [log] [blame]
// Copyright 2018 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/chrome/browser/url_loading/url_loading_util.h"
#include "base/strings/sys_string_conversions.h"
#include "components/sessions/core/tab_restore_service_helper.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/chrome_url_constants.h"
#import "ios/chrome/browser/geolocation/omnibox_geolocation_controller.h"
#import "ios/chrome/browser/metrics/new_tab_page_uma.h"
#import "ios/chrome/browser/ntp/new_tab_page_tab_helper.h"
#import "ios/chrome/browser/prerender/prerender_service.h"
#import "ios/chrome/browser/prerender/prerender_service_factory.h"
#include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h"
#include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios.h"
#include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios_factory.h"
#import "ios/chrome/browser/tabs/tab_model.h"
#import "ios/chrome/browser/voice/voice_search_navigations_tab_helper.h"
#import "ios/chrome/browser/web/load_timing_tab_helper.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h"
#import "ios/web/public/web_state/web_state.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Helper method for inducing intentional crashes, in a separate function so
// it will show up in stack traces.
void InduceBrowserCrash() {
// Induce an intentional crash in the browser process.
CHECK(false);
// Call another function, so that the above CHECK can't be tail-call
// optimized. This ensures that this method's name will show up in the stack
// for easier identification.
CHECK(true);
}
}
bool IsURLAllowedInIncognito(const GURL& url) {
// Most URLs are allowed in incognito; the following is an exception.
return !(url.SchemeIs(kChromeUIScheme) && url.host() == kChromeUIHistoryHost);
}
void LoadJavaScriptURL(const GURL& url,
ios::ChromeBrowserState* browser_state,
web::WebState* webState) {
DCHECK(url.SchemeIs(url::kJavaScriptScheme));
DCHECK(webState);
PrerenderService* prerenderService =
PrerenderServiceFactory::GetForBrowserState(browser_state);
if (prerenderService) {
prerenderService->CancelPrerender();
}
NSString* jsToEval = [base::SysUTF8ToNSString(url.GetContent())
stringByRemovingPercentEncoding];
if (webState)
webState->ExecuteUserJavaScript(jsToEval);
}
void RestoreTab(const SessionID session_id,
WindowOpenDisposition disposition,
ios::ChromeBrowserState* browser_state) {
TabRestoreServiceDelegateImplIOS* delegate =
TabRestoreServiceDelegateImplIOSFactory::GetForBrowserState(
browser_state);
sessions::TabRestoreService* restoreService =
IOSChromeTabRestoreServiceFactory::GetForBrowserState(
browser_state->GetOriginalChromeBrowserState());
restoreService->RestoreEntryById(delegate, session_id, disposition);
}
URLLoadResult LoadURL(const ChromeLoadParams& chrome_params,
ios::ChromeBrowserState* browser_state,
TabModel* tab_model) {
web::NavigationManager::WebLoadParams params = chrome_params.web_params;
if (chrome_params.disposition == WindowOpenDisposition::SWITCH_TO_TAB) {
return URLLoadResult::SWITCH_TO_TAB;
}
[[OmniboxGeolocationController sharedInstance]
locationBarDidSubmitURL:params.url
transition:params.transition_type
browserState:browser_state];
WebStateList* webStateList = tab_model.webStateList;
web::WebState* current_web_state = webStateList->GetActiveWebState();
DCHECK(current_web_state);
if (params.transition_type & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) {
bool isExpectingVoiceSearch =
VoiceSearchNavigationTabHelper::FromWebState(current_web_state)
->IsExpectingVoiceSearch();
new_tab_page_uma::RecordActionFromOmnibox(browser_state, params.url,
params.transition_type,
isExpectingVoiceSearch);
}
// NOTE: This check for the Crash Host URL is here to avoid the URL from
// ending up in the history causing the app to crash at every subsequent
// restart.
if (params.url.host() == kChromeUIBrowserCrashHost) {
InduceBrowserCrash();
// Under a debugger, the app can continue working even after the CHECK.
// Adding a return avoids adding the crash url to history.
return URLLoadResult::INDUCED_CRASH;
}
// Ask the prerender service to load this URL if it can, and return if it does
// so.
PrerenderService* prerenderService =
PrerenderServiceFactory::GetForBrowserState(browser_state);
if (prerenderService && prerenderService->MaybeLoadPrerenderedURL(
params.url, params.transition_type, tab_model)) {
return URLLoadResult::LOADED_PRERENDER;
}
// Some URLs are not allowed while in incognito. If we are in incognito and
// load a disallowed URL, instead create a new tab not in the incognito state.
if (browser_state->IsOffTheRecord() && !IsURLAllowedInIncognito(params.url)) {
return URLLoadResult::DISALLOWED_IN_INCOGNITO;
}
BOOL typedOrGeneratedTransition =
PageTransitionCoreTypeIs(params.transition_type,
ui::PAGE_TRANSITION_TYPED) ||
PageTransitionCoreTypeIs(params.transition_type,
ui::PAGE_TRANSITION_GENERATED);
if (typedOrGeneratedTransition) {
LoadTimingTabHelper::FromWebState(current_web_state)->DidInitiatePageLoad();
}
// If this is a reload initiated from the omnibox.
// TODO(crbug.com/730192): Add DCHECK to verify that whenever urlToLoad is the
// same as the old url, the transition type is ui::PAGE_TRANSITION_RELOAD.
if (PageTransitionCoreTypeIs(params.transition_type,
ui::PAGE_TRANSITION_RELOAD)) {
current_web_state->GetNavigationManager()->Reload(
web::ReloadType::NORMAL, true /* check_for_repost */);
return URLLoadResult::RELOADED;
}
current_web_state->GetNavigationManager()->LoadURLWithParams(params);
// Deactivate the NTP immediately on a load to hide the NTP quickly, but after
// calling -LoadURLWithParams. Otherwise, if the webState has never been
// visible (such as during startup with an NTP), it's possible the webView can
// trigger a unnecessary load for chrome://newtab.
if (params.url.GetOrigin() != kChromeUINewTabURL) {
NewTabPageTabHelper* NTPHelper =
NewTabPageTabHelper::FromWebState(current_web_state);
if (NTPHelper && NTPHelper->IsActive()) {
NTPHelper->Deactivate();
}
}
return URLLoadResult::NORMAL_LOAD;
}