navigation_impl.cc 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. // Copyright 2019 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. #include "weblayer/browser/navigation_impl.h"
  5. #include "build/build_config.h"
  6. #include "content/public/browser/navigation_entry.h"
  7. #include "content/public/browser/navigation_handle.h"
  8. #include "content/public/browser/web_contents.h"
  9. #include "net/base/net_errors.h"
  10. #include "net/http/http_response_headers.h"
  11. #include "net/http/http_util.h"
  12. #include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
  13. #include "third_party/blink/public/mojom/loader/referrer.mojom.h"
  14. #include "weblayer/browser/navigation_ui_data_impl.h"
  15. #include "weblayer/browser/page_impl.h"
  16. #if BUILDFLAG(IS_ANDROID)
  17. #include "base/android/jni_array.h"
  18. #include "base/android/jni_string.h"
  19. #include "components/embedder_support/android/util/web_resource_response.h"
  20. #include "weblayer/browser/java/jni/NavigationImpl_jni.h"
  21. #endif
  22. #if BUILDFLAG(IS_ANDROID)
  23. using base::android::AttachCurrentThread;
  24. using base::android::ScopedJavaLocalRef;
  25. #endif
  26. namespace weblayer {
  27. NavigationImpl::NavigationImpl(content::NavigationHandle* navigation_handle)
  28. : navigation_handle_(navigation_handle) {
  29. auto* navigation_entry = navigation_handle->GetNavigationEntry();
  30. if (navigation_entry &&
  31. navigation_entry->GetURL() == navigation_handle->GetURL()) {
  32. navigation_entry_unique_id_ = navigation_entry->GetUniqueID();
  33. }
  34. }
  35. NavigationImpl::~NavigationImpl() {
  36. #if BUILDFLAG(IS_ANDROID)
  37. if (java_navigation_) {
  38. Java_NavigationImpl_onNativeDestroyed(AttachCurrentThread(),
  39. java_navigation_);
  40. }
  41. #endif
  42. }
  43. #if BUILDFLAG(IS_ANDROID)
  44. ScopedJavaLocalRef<jstring> NavigationImpl::GetUri(JNIEnv* env) {
  45. return ScopedJavaLocalRef<jstring>(
  46. base::android::ConvertUTF8ToJavaString(env, GetURL().spec()));
  47. }
  48. ScopedJavaLocalRef<jobjectArray> NavigationImpl::GetRedirectChain(JNIEnv* env) {
  49. std::vector<std::string> jni_redirects;
  50. for (const GURL& redirect : GetRedirectChain())
  51. jni_redirects.push_back(redirect.spec());
  52. return base::android::ToJavaArrayOfStrings(env, jni_redirects);
  53. }
  54. ScopedJavaLocalRef<jobjectArray> NavigationImpl::GetResponseHeaders(
  55. JNIEnv* env) {
  56. std::vector<std::string> jni_headers;
  57. auto* headers = GetResponseHeaders();
  58. if (headers) {
  59. size_t iterator = 0;
  60. std::string name;
  61. std::string value;
  62. while (headers->EnumerateHeaderLines(&iterator, &name, &value)) {
  63. jni_headers.push_back(name);
  64. jni_headers.push_back(value);
  65. }
  66. }
  67. return base::android::ToJavaArrayOfStrings(env, jni_headers);
  68. }
  69. jboolean NavigationImpl::SetRequestHeader(
  70. JNIEnv* env,
  71. const base::android::JavaParamRef<jstring>& name,
  72. const base::android::JavaParamRef<jstring>& value) {
  73. if (!safe_to_set_request_headers_)
  74. return false;
  75. SetRequestHeader(ConvertJavaStringToUTF8(name),
  76. ConvertJavaStringToUTF8(value));
  77. return true;
  78. }
  79. jboolean NavigationImpl::SetUserAgentString(
  80. JNIEnv* env,
  81. const base::android::JavaParamRef<jstring>& value) {
  82. if (!safe_to_set_user_agent_)
  83. return false;
  84. SetUserAgentString(ConvertJavaStringToUTF8(value));
  85. return true;
  86. }
  87. jboolean NavigationImpl::DisableNetworkErrorAutoReload(JNIEnv* env) {
  88. if (!safe_to_disable_network_error_auto_reload_)
  89. return false;
  90. DisableNetworkErrorAutoReload();
  91. return true;
  92. }
  93. jboolean NavigationImpl::DisableIntentProcessing(JNIEnv* env) {
  94. if (!safe_to_disable_intent_processing_)
  95. return false;
  96. disable_intent_processing_ = true;
  97. return true;
  98. }
  99. jboolean NavigationImpl::AreIntentLaunchesAllowedInBackground(JNIEnv* env) {
  100. NavigationUIDataImpl* navigation_ui_data = static_cast<NavigationUIDataImpl*>(
  101. navigation_handle_->GetNavigationUIData());
  102. if (!navigation_ui_data)
  103. return false;
  104. return navigation_ui_data->are_intent_launches_allowed_in_background();
  105. }
  106. base::android::ScopedJavaLocalRef<jstring> NavigationImpl::GetReferrer(
  107. JNIEnv* env) {
  108. return ScopedJavaLocalRef<jstring>(
  109. base::android::ConvertUTF8ToJavaString(env, GetReferrer().spec()));
  110. }
  111. jlong NavigationImpl::GetPage(JNIEnv* env) {
  112. if (!safe_to_get_page_)
  113. return -1;
  114. return reinterpret_cast<intptr_t>(GetPage());
  115. }
  116. jint NavigationImpl::GetNavigationEntryOffset(JNIEnv* env) {
  117. return GetNavigationEntryOffset();
  118. }
  119. jboolean NavigationImpl::WasFetchedFromCache(JNIEnv* env) {
  120. return WasFetchedFromCache();
  121. }
  122. void NavigationImpl::SetResponse(
  123. std::unique_ptr<embedder_support::WebResourceResponse> response) {
  124. response_ = std::move(response);
  125. }
  126. std::unique_ptr<embedder_support::WebResourceResponse>
  127. NavigationImpl::TakeResponse() {
  128. return std::move(response_);
  129. }
  130. void NavigationImpl::SetJavaNavigation(
  131. const base::android::ScopedJavaGlobalRef<jobject>& java_navigation) {
  132. // SetJavaNavigation() should only be called once.
  133. DCHECK(!java_navigation_);
  134. java_navigation_ = java_navigation;
  135. }
  136. #endif
  137. bool NavigationImpl::IsPageInitiated() {
  138. return navigation_handle_->IsRendererInitiated();
  139. }
  140. bool NavigationImpl::IsReload() {
  141. return navigation_handle_->GetReloadType() != content::ReloadType::NONE;
  142. }
  143. bool NavigationImpl::IsServedFromBackForwardCache() {
  144. return navigation_handle_->IsServedFromBackForwardCache();
  145. }
  146. Page* NavigationImpl::GetPage() {
  147. if (!safe_to_get_page_)
  148. return nullptr;
  149. return PageImpl::GetForPage(
  150. navigation_handle_->GetRenderFrameHost()->GetPage());
  151. }
  152. int NavigationImpl::GetNavigationEntryOffset() {
  153. return navigation_handle_->GetNavigationEntryOffset();
  154. }
  155. bool NavigationImpl::WasFetchedFromCache() {
  156. return navigation_handle_->WasResponseCached();
  157. }
  158. GURL NavigationImpl::GetURL() {
  159. return navigation_handle_->GetURL();
  160. }
  161. const std::vector<GURL>& NavigationImpl::GetRedirectChain() {
  162. return navigation_handle_->GetRedirectChain();
  163. }
  164. NavigationState NavigationImpl::GetState() {
  165. if (navigation_handle_->IsErrorPage() || navigation_handle_->IsDownload() ||
  166. (finished_ && !navigation_handle_->HasCommitted()))
  167. return NavigationState::kFailed;
  168. if (navigation_handle_->HasCommitted())
  169. return NavigationState::kComplete;
  170. if (navigation_handle_->GetResponseHeaders())
  171. return NavigationState::kReceivingBytes;
  172. return NavigationState::kWaitingResponse;
  173. }
  174. int NavigationImpl::GetHttpStatusCode() {
  175. auto* response_headers = navigation_handle_->GetResponseHeaders();
  176. return response_headers ? response_headers->response_code() : 0;
  177. }
  178. const net::HttpResponseHeaders* NavigationImpl::GetResponseHeaders() {
  179. return navigation_handle_->GetResponseHeaders();
  180. }
  181. bool NavigationImpl::IsSameDocument() {
  182. return navigation_handle_->IsSameDocument();
  183. }
  184. bool NavigationImpl::IsErrorPage() {
  185. return navigation_handle_->IsErrorPage();
  186. }
  187. bool NavigationImpl::IsDownload() {
  188. return navigation_handle_->IsDownload();
  189. }
  190. bool NavigationImpl::IsKnownProtocol() {
  191. return !navigation_handle_->IsExternalProtocol();
  192. }
  193. bool NavigationImpl::WasStopCalled() {
  194. return was_stopped_;
  195. }
  196. Navigation::LoadError NavigationImpl::GetLoadError() {
  197. auto error_code = navigation_handle_->GetNetErrorCode();
  198. if (auto* response_headers = navigation_handle_->GetResponseHeaders()) {
  199. auto response_code = response_headers->response_code();
  200. if (response_code >= 400 && response_code < 500)
  201. return kHttpClientError;
  202. if (response_code >= 500 && response_code < 600)
  203. return kHttpServerError;
  204. }
  205. if (error_code == net::OK)
  206. return kNoError;
  207. // The safe browsing navigation throttle fails navigations with
  208. // ERR_BLOCKED_BY_CLIENT when showing safe browsing interstitials.
  209. if (error_code == net::ERR_BLOCKED_BY_CLIENT)
  210. return kSafeBrowsingError;
  211. if (net::IsCertificateError(error_code))
  212. return kSSLError;
  213. if (error_code <= -100 && error_code > -200)
  214. return kConnectivityError;
  215. return kOtherError;
  216. }
  217. void NavigationImpl::SetRequestHeader(const std::string& name,
  218. const std::string& value) {
  219. if (base::ToLowerASCII(name) == "referer") {
  220. // The referrer needs to be special cased as content maintains it
  221. // separately.
  222. auto referrer = blink::mojom::Referrer::New();
  223. referrer->url = GURL(value);
  224. referrer->policy = network::mojom::ReferrerPolicy::kDefault;
  225. navigation_handle_->SetReferrer(std::move(referrer));
  226. } else {
  227. // Any headers coming from the client should be exempt from CORS checks.
  228. navigation_handle_->SetCorsExemptRequestHeader(name, value);
  229. }
  230. }
  231. void NavigationImpl::SetUserAgentString(const std::string& value) {
  232. DCHECK(safe_to_set_user_agent_);
  233. // By default renderer initiated navigations inherit the user-agent override
  234. // of the current NavigationEntry. But we don't want this per-navigation UA to
  235. // be inherited.
  236. navigation_handle_->GetWebContents()
  237. ->SetRendererInitiatedUserAgentOverrideOption(
  238. content::NavigationController::UA_OVERRIDE_FALSE);
  239. navigation_handle_->GetWebContents()->SetUserAgentOverride(
  240. blink::UserAgentOverride::UserAgentOnly(value),
  241. /* override_in_new_tabs */ false);
  242. navigation_handle_->SetIsOverridingUserAgent(!value.empty());
  243. set_user_agent_string_called_ = true;
  244. }
  245. void NavigationImpl::DisableNetworkErrorAutoReload() {
  246. DCHECK(safe_to_disable_network_error_auto_reload_);
  247. disable_network_error_auto_reload_ = true;
  248. }
  249. bool NavigationImpl::IsFormSubmission() {
  250. return navigation_handle_->IsFormSubmission();
  251. }
  252. GURL NavigationImpl::GetReferrer() {
  253. return navigation_handle_->GetReferrer().url;
  254. }
  255. #if BUILDFLAG(IS_ANDROID)
  256. static jboolean JNI_NavigationImpl_IsValidRequestHeaderName(
  257. JNIEnv* env,
  258. const base::android::JavaParamRef<jstring>& name) {
  259. return net::HttpUtil::IsValidHeaderName(ConvertJavaStringToUTF8(name));
  260. }
  261. static jboolean JNI_NavigationImpl_IsValidRequestHeaderValue(
  262. JNIEnv* env,
  263. const base::android::JavaParamRef<jstring>& value) {
  264. return net::HttpUtil::IsValidHeaderValue(ConvertJavaStringToUTF8(value));
  265. }
  266. #endif
  267. } // namespace weblayer