172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_url_handler.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_about_handler.h"
972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/extensions/extension_web_ui.h"
1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/webui/chrome_web_ui_factory.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/webui/web_ui.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Handles rewriting view-source URLs for what we'll actually load.
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool HandleViewSource(GURL* url, Profile* profile) {
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (url->SchemeIs(chrome::kViewSourceScheme)) {
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Load the inner URL instead.
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *url = GURL(url->path());
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Bug 26129: limit view-source to view the content and not any
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // other kind of 'active' url scheme like 'javascript' or 'data'.
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    static const char* const allowed_sub_schemes[] = {
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chrome::kHttpScheme, chrome::kHttpsScheme, chrome::kFtpScheme,
26513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      chrome::kChromeDevToolsScheme, chrome::kChromeUIScheme,
27513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      chrome::kFileScheme
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool is_sub_scheme_allowed = false;
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < arraysize(allowed_sub_schemes); i++) {
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (url->SchemeIs(allowed_sub_schemes[i])) {
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        is_sub_scheme_allowed = true;
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!is_sub_scheme_allowed) {
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *url = GURL(chrome::kAboutBlankURL);
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Turns a non view-source URL into the corresponding view-source URL.
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool ReverseViewSource(GURL* url, Profile* profile) {
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // No action necessary if the URL is already view-source:
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (url->SchemeIs(chrome::kViewSourceScheme))
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  url_canon::Replacements<char> repl;
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  repl.SetScheme(chrome::kViewSourceScheme,
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_parse::Component(0, strlen(chrome::kViewSourceScheme)));
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  repl.SetPath(url->spec().c_str(),
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_parse::Component(0, url->spec().size()));
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *url = url->ReplaceComponents(repl);
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
6372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Handles rewriting Web UI URLs.
6472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstatic bool HandleWebUI(GURL* url, Profile* profile) {
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!ChromeWebUIFactory::GetInstance()->UseWebUIForURL(profile, *url))
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Special case the new tab page. In older versions of Chrome, the new tab
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // page was hosted at chrome-internal:<blah>. This might be in people's saved
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // sessions or bookmarks, so we say any URL with that scheme triggers the new
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // tab page.
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (url->SchemeIs(chrome::kChromeInternalScheme)) {
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Rewrite it with the proper new tab URL.
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *url = GURL(chrome::kChromeUINewTabURL);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::vector<BrowserURLHandler::HandlerPair> BrowserURLHandler::url_handlers_;
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserURLHandler::InitURLHandlers() {
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!url_handlers_.empty())
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Visual Studio 2010 has problems converting NULL to the null pointer for
8872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // std::pair.  See http://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair
8972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // It will work if we pass nullptr.
9072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(_MSC_VER) && _MSC_VER >= 1600
9172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  URLHandler null_handler = nullptr;
9272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#else
9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  URLHandler null_handler = NULL;
9472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif
9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add the default URL handlers.
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  url_handlers_.push_back(
9872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      HandlerPair(&ExtensionWebUI::HandleChromeURLOverride, null_handler));
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // about:
10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  url_handlers_.push_back(HandlerPair(&WillHandleBrowserAboutURL,
10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                      null_handler));
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // chrome: & friends.
10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  url_handlers_.push_back(HandlerPair(&HandleWebUI, null_handler));
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // view-source:
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  url_handlers_.push_back(HandlerPair(&HandleViewSource, &ReverseViewSource));
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserURLHandler::RewriteURLIfNecessary(GURL* url, Profile* profile,
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                              bool* reverse_on_redirect) {
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (url_handlers_.empty())
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    InitURLHandlers();
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < url_handlers_.size(); ++i) {
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((*url_handlers_[i].first)(url, profile)) {
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *reverse_on_redirect = (url_handlers_[i].second != NULL);
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BrowserURLHandler::ReverseURLRewrite(
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL* url, const GURL& original, Profile* profile) {
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < url_handlers_.size(); ++i) {
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL test_url(original);
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((*url_handlers_[i].first)(&test_url, profile)) {
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (url_handlers_[i].second)
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return (*url_handlers_[i].second)(url, profile);
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      else
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
135