1 // Copyright 2012 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 5 #include "android_webview/renderer/aw_content_renderer_client.h" 6 7 #include "android_webview/common/aw_resource.h" 8 #include "android_webview/common/render_view_messages.h" 9 #include "android_webview/common/url_constants.h" 10 #include "android_webview/renderer/aw_render_view_ext.h" 11 // START: Printing fork b/10190508 12 #include "android_webview/renderer/print_web_view_helper.h" 13 // END: Printing fork b/10190508 14 #include "base/command_line.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/strings/utf_string_conversions.h" 17 #include "components/autofill/content/renderer/autofill_agent.h" 18 #include "components/autofill/content/renderer/password_autofill_agent.h" 19 #include "components/visitedlink/renderer/visitedlink_slave.h" 20 #include "content/public/common/url_constants.h" 21 #include "content/public/renderer/document_state.h" 22 #include "content/public/renderer/navigation_state.h" 23 #include "content/public/renderer/render_thread.h" 24 #include "content/public/renderer/render_view.h" 25 #include "net/base/net_errors.h" 26 #include "third_party/WebKit/public/platform/WebString.h" 27 #include "third_party/WebKit/public/web/WebFrame.h" 28 #include "third_party/WebKit/public/web/WebHistoryItem.h" 29 #include "third_party/WebKit/public/web/WebView.h" 30 #include "third_party/WebKit/public/platform/WebURL.h" 31 #include "third_party/WebKit/public/platform/WebURLError.h" 32 #include "third_party/WebKit/public/platform/WebURLRequest.h" 33 #include "third_party/WebKit/public/web/WebNavigationType.h" 34 #include "third_party/WebKit/public/web/WebSecurityPolicy.h" 35 #include "url/gurl.h" 36 37 using content::RenderThread; 38 39 namespace android_webview { 40 41 AwContentRendererClient::AwContentRendererClient() { 42 } 43 44 AwContentRendererClient::~AwContentRendererClient() { 45 } 46 47 void AwContentRendererClient::RenderThreadStarted() { 48 WebKit::WebString content_scheme( 49 ASCIIToUTF16(android_webview::kContentScheme)); 50 WebKit::WebSecurityPolicy::registerURLSchemeAsLocal(content_scheme); 51 52 RenderThread* thread = content::RenderThread::Get(); 53 54 aw_render_process_observer_.reset(new AwRenderProcessObserver); 55 thread->AddObserver(aw_render_process_observer_.get()); 56 57 visited_link_slave_.reset(new visitedlink::VisitedLinkSlave); 58 thread->AddObserver(visited_link_slave_.get()); 59 } 60 61 bool AwContentRendererClient::HandleNavigation( 62 content::RenderView* view, 63 content::DocumentState* document_state, 64 int opener_id, 65 WebKit::WebFrame* frame, 66 const WebKit::WebURLRequest& request, 67 WebKit::WebNavigationType type, 68 WebKit::WebNavigationPolicy default_policy, 69 bool is_redirect) { 70 71 // Only GETs can be overridden. 72 if (!request.httpMethod().equals("GET")) 73 return false; 74 75 // Any navigation from loadUrl, and goBack/Forward are considered application- 76 // initiated and hence will not yield a shouldOverrideUrlLoading() callback. 77 // Webview classic does not consider reload application-initiated so we 78 // continue the same behavior. 79 bool application_initiated = 80 !document_state->navigation_state()->is_content_initiated() 81 || type == WebKit::WebNavigationTypeBackForward; 82 83 // Don't offer application-initiated navigations unless it's a redirect. 84 if (application_initiated && !is_redirect) 85 return false; 86 87 const GURL& gurl = request.url(); 88 // We allow intercepting navigations within subframes, but only if the 89 // scheme other than http or https. This is because the embedder 90 // can't distinguish main frame and subframe callbacks (which could lead 91 // to broken content if the embedder decides to not ignore the main frame 92 // navigation, but ignores the subframe navigation). 93 // The reason this is supported at all is that certain JavaScript-based 94 // frameworks use iframe navigation as a form of communication with the 95 // embedder. 96 // HandleNavigation receives about:blank navigations, (for example for 97 // empty iframes), however webview classic does not pass these to the 98 // app using shouldoverrideurlloading, so we filter them out here. We 99 // do not filter out top level about:blanks since they are allowed in 100 // Webview classic. The about:blank behavior for child frames is covered 101 // by testCalledOnJavaScriptLocationImmediateAssignRedirect(). 102 // TODO(sgurun) Need to write a test for allowing about:blank for top 103 // navigations. 104 if (frame->parent() && (gurl.SchemeIs(chrome::kHttpScheme) || 105 gurl.SchemeIs(chrome::kHttpsScheme) || 106 gurl.SchemeIs(chrome::kAboutScheme))) 107 return false; 108 109 // use NavigationInterception throttle to handle the call as that can 110 // be deferred until after the java side has been constructed. 111 if (opener_id != MSG_ROUTING_NONE) 112 return false; 113 114 bool ignore_navigation = false; 115 base::string16 url = request.url().string(); 116 117 int routing_id = view->GetRoutingID(); 118 RenderThread::Get()->Send(new AwViewHostMsg_ShouldOverrideUrlLoading( 119 routing_id, url, &ignore_navigation)); 120 return ignore_navigation; 121 } 122 123 bool AwContentRendererClient::ShouldAbortNavigationAfterUrlResolve( 124 content::RenderView* view, 125 const GURL& base, 126 const base::string16& fragment, 127 const GURL& result) { 128 if (!CommandLine::ForCurrentProcess()->HasSwitch( 129 "enable-webview-classic-workarounds")) { 130 return false; 131 } 132 if (!base.is_valid()) 133 return false; 134 135 if (result.is_valid()) { 136 // Workaround for http://b/11118423 -- some apps put "|" into an <a href> 137 // and expect it to resolve. 138 if (fragment.empty() || fragment[0] != '|') 139 return false; 140 } 141 int routing_id = view->GetRoutingID(); 142 bool ignore_navigation = false; 143 RenderThread::Get()->Send(new AwViewHostMsg_ShouldOverrideUrlLoading( 144 routing_id, fragment, &ignore_navigation)); 145 if (ignore_navigation) { 146 LOG(WARNING) << "Invalid URL resolve in navigation:\n" 147 " relative link: " << fragment << "\n" 148 " against base: " << base.spec() << "]\n" 149 "^^^ THIS WILL BREAK IN FUTURE ANDROID WEBVIEW VERSIONS."; 150 } 151 return ignore_navigation; 152 } 153 154 void AwContentRendererClient::RenderViewCreated( 155 content::RenderView* render_view) { 156 AwRenderViewExt::RenderViewCreated(render_view); 157 158 // START: Printing fork b/10190508 159 printing::PrintWebViewHelper* print_helper = 160 new printing::PrintWebViewHelper(render_view); 161 print_helper->SetScriptedPrintBlocked(true); 162 // END: Printing fork b/10190508 163 // TODO(sgurun) do not create a password autofill agent (change 164 // autofill agent to store a weakptr). 165 autofill::PasswordAutofillAgent* password_autofill_agent = 166 new autofill::PasswordAutofillAgent(render_view); 167 new autofill::AutofillAgent(render_view, password_autofill_agent); 168 } 169 170 std::string AwContentRendererClient::GetDefaultEncoding() { 171 return AwResource::GetDefaultTextEncoding(); 172 } 173 174 bool AwContentRendererClient::HasErrorPage(int http_status_code, 175 std::string* error_domain) { 176 return http_status_code >= 400; 177 } 178 179 void AwContentRendererClient::GetNavigationErrorStrings( 180 WebKit::WebFrame* /* frame */, 181 const WebKit::WebURLRequest& failed_request, 182 const WebKit::WebURLError& error, 183 std::string* error_html, 184 string16* error_description) { 185 if (error_html) { 186 GURL error_url(failed_request.url()); 187 std::string err = UTF16ToUTF8(error.localizedDescription); 188 std::string contents; 189 if (err.empty()) { 190 contents = AwResource::GetNoDomainPageContent(); 191 } else { 192 contents = AwResource::GetLoadErrorPageContent(); 193 ReplaceSubstringsAfterOffset(&contents, 0, "%e", err); 194 } 195 196 ReplaceSubstringsAfterOffset(&contents, 0, "%s", 197 error_url.possibly_invalid_spec()); 198 *error_html = contents; 199 } 200 if (error_description) { 201 if (error.localizedDescription.isEmpty()) 202 *error_description = ASCIIToUTF16(net::ErrorToString(error.reason)); 203 else 204 *error_description = error.localizedDescription; 205 } 206 } 207 208 unsigned long long AwContentRendererClient::VisitedLinkHash( 209 const char* canonical_url, 210 size_t length) { 211 return visited_link_slave_->ComputeURLFingerprint(canonical_url, length); 212 } 213 214 bool AwContentRendererClient::IsLinkVisited(unsigned long long link_hash) { 215 return visited_link_slave_->IsVisited(link_hash); 216 } 217 218 } // namespace android_webview 219