1 // Copyright (c) 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 "content/browser/browser_url_handler_impl.h" 6 7 #include "base/command_line.h" 8 #include "base/strings/string_util.h" 9 #include "content/browser/frame_host/debug_urls.h" 10 #include "content/browser/webui/web_ui_impl.h" 11 #include "content/public/browser/content_browser_client.h" 12 #include "content/public/common/content_switches.h" 13 #include "content/public/common/url_constants.h" 14 #include "url/gurl.h" 15 16 namespace content { 17 18 // Handles rewriting view-source URLs for what we'll actually load. 19 static bool HandleViewSource(GURL* url, BrowserContext* browser_context) { 20 if (url->SchemeIs(kViewSourceScheme)) { 21 // Load the inner URL instead. 22 *url = GURL(url->GetContent()); 23 24 // Bug 26129: limit view-source to view the content and not any 25 // other kind of 'active' url scheme like 'javascript' or 'data'. 26 static const char* const allowed_sub_schemes[] = { 27 kHttpScheme, kHttpsScheme, kFtpScheme, 28 chrome::kChromeDevToolsScheme, chrome::kChromeUIScheme, 29 chrome::kFileScheme, chrome::kFileSystemScheme 30 }; 31 32 bool is_sub_scheme_allowed = false; 33 for (size_t i = 0; i < arraysize(allowed_sub_schemes); i++) { 34 if (url->SchemeIs(allowed_sub_schemes[i])) { 35 is_sub_scheme_allowed = true; 36 break; 37 } 38 } 39 40 if (!is_sub_scheme_allowed) { 41 *url = GURL(kAboutBlankURL); 42 return false; 43 } 44 45 return true; 46 } 47 return false; 48 } 49 50 // Turns a non view-source URL into the corresponding view-source URL. 51 static bool ReverseViewSource(GURL* url, BrowserContext* browser_context) { 52 // No action necessary if the URL is already view-source: 53 if (url->SchemeIs(kViewSourceScheme)) 54 return false; 55 56 url_canon::Replacements<char> repl; 57 repl.SetScheme(kViewSourceScheme, 58 url_parse::Component(0, strlen(kViewSourceScheme))); 59 repl.SetPath(url->spec().c_str(), 60 url_parse::Component(0, url->spec().size())); 61 *url = url->ReplaceComponents(repl); 62 return true; 63 } 64 65 static bool DebugURLHandler(GURL* url, BrowserContext* browser_context) { 66 // If running inside the Telemetry test harness, allow automated 67 // navigations to access browser-side debug URLs. They must use the 68 // chrome:// scheme, since the about: scheme won't be rewritten in 69 // this code path. 70 if (CommandLine::ForCurrentProcess()->HasSwitch( 71 switches::kEnableGpuBenchmarking)) { 72 if (HandleDebugURL(*url, PAGE_TRANSITION_FROM_ADDRESS_BAR)) { 73 return true; 74 } 75 } 76 77 // Circumvent processing URLs that the renderer process will handle. 78 return *url == GURL(kChromeUICrashURL) || 79 *url == GURL(kChromeUIHangURL) || 80 *url == GURL(kChromeUIKillURL) || 81 *url == GURL(kChromeUIShorthangURL); 82 } 83 84 // static 85 BrowserURLHandler* BrowserURLHandler::GetInstance() { 86 return BrowserURLHandlerImpl::GetInstance(); 87 } 88 89 // static 90 BrowserURLHandler::URLHandler BrowserURLHandler::null_handler() { 91 // Required for VS2010: http://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair 92 return NULL; 93 } 94 95 // static 96 BrowserURLHandlerImpl* BrowserURLHandlerImpl::GetInstance() { 97 return Singleton<BrowserURLHandlerImpl>::get(); 98 } 99 100 BrowserURLHandlerImpl::BrowserURLHandlerImpl() { 101 AddHandlerPair(&DebugURLHandler, BrowserURLHandlerImpl::null_handler()); 102 103 GetContentClient()->browser()->BrowserURLHandlerCreated(this); 104 105 // view-source: 106 AddHandlerPair(&HandleViewSource, &ReverseViewSource); 107 } 108 109 BrowserURLHandlerImpl::~BrowserURLHandlerImpl() { 110 } 111 112 void BrowserURLHandlerImpl::AddHandlerPair(URLHandler handler, 113 URLHandler reverse_handler) { 114 url_handlers_.push_back(HandlerPair(handler, reverse_handler)); 115 } 116 117 void BrowserURLHandlerImpl::RewriteURLIfNecessary( 118 GURL* url, 119 BrowserContext* browser_context, 120 bool* reverse_on_redirect) { 121 for (size_t i = 0; i < url_handlers_.size(); ++i) { 122 URLHandler handler = *url_handlers_[i].first; 123 if (handler && handler(url, browser_context)) { 124 *reverse_on_redirect = (url_handlers_[i].second != NULL); 125 return; 126 } 127 } 128 } 129 130 bool BrowserURLHandlerImpl::ReverseURLRewrite( 131 GURL* url, const GURL& original, BrowserContext* browser_context) { 132 for (size_t i = 0; i < url_handlers_.size(); ++i) { 133 URLHandler reverse_rewriter = *url_handlers_[i].second; 134 if (reverse_rewriter) { 135 GURL test_url(original); 136 URLHandler handler = *url_handlers_[i].first; 137 if (!handler) { 138 if (reverse_rewriter(url, browser_context)) 139 return true; 140 } else if (handler(&test_url, browser_context)) { 141 return reverse_rewriter(url, browser_context); 142 } 143 } 144 } 145 return false; 146 } 147 148 } // namespace content 149