1// Copyright 2013 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#if !defined(OS_CHROMEOS) 6 7#include "chrome/browser/ui/webui/options/advanced_options_utils.h" 8 9#include "base/bind.h" 10#include "base/environment.h" 11#include "base/files/file_path.h" 12#include "base/files/file_util.h" 13#include "base/nix/xdg_util.h" 14#include "base/process/launch.h" 15#include "base/strings/string_util.h" 16#include "chrome/browser/tab_contents/tab_util.h" 17#include "content/public/browser/browser_thread.h" 18#include "content/public/browser/render_process_host.h" 19#include "content/public/browser/render_view_host.h" 20#include "content/public/browser/web_contents.h" 21 22using content::BrowserThread; 23using content::OpenURLParams; 24using content::Referrer; 25using content::WebContents; 26 27namespace options { 28 29// Command used to configure GNOME 2 proxy settings. 30const char* kGNOME2ProxyConfigCommand[] = {"gnome-network-properties", NULL}; 31// In GNOME 3, we might need to run gnome-control-center instead. We try this 32// only after gnome-network-properties is not found, because older GNOME also 33// has this but it doesn't do the same thing. See below where we use it. 34const char* kGNOME3ProxyConfigCommand[] = {"gnome-control-center", "network", 35 NULL}; 36// KDE3 and KDE4 are only slightly different, but incompatible. Go figure. 37const char* kKDE3ProxyConfigCommand[] = {"kcmshell", "proxy", NULL}; 38const char* kKDE4ProxyConfigCommand[] = {"kcmshell4", "proxy", NULL}; 39 40// The URL for Linux proxy configuration help when not running under a 41// supported desktop environment. 42const char kLinuxProxyConfigUrl[] = "about:linux-proxy-config"; 43 44namespace { 45 46// Show the proxy config URL in the given tab. 47void ShowLinuxProxyConfigUrl(int render_process_id, int render_view_id) { 48 DCHECK_CURRENTLY_ON(BrowserThread::UI); 49 scoped_ptr<base::Environment> env(base::Environment::Create()); 50 const char* name = base::nix::GetDesktopEnvironmentName(env.get()); 51 if (name) 52 LOG(ERROR) << "Could not find " << name << " network settings in $PATH"; 53 OpenURLParams params( 54 GURL(kLinuxProxyConfigUrl), Referrer(), NEW_FOREGROUND_TAB, 55 ui::PAGE_TRANSITION_LINK, false); 56 57 WebContents* web_contents = 58 tab_util::GetWebContentsByID(render_process_id, render_view_id); 59 if (web_contents) 60 web_contents->OpenURL(params); 61} 62 63// Start the given proxy configuration utility. 64bool StartProxyConfigUtil(const char* command[]) { 65 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 66 // base::LaunchProcess() returns true ("success") if the fork() 67 // succeeds, but not necessarily the exec(). We'd like to be able to 68 // use StartProxyConfigUtil() to search possible options and stop on 69 // success, so we search $PATH first to predict whether the exec is 70 // expected to succeed. 71 // TODO(mdm): this is a useful check, and is very similar to some 72 // code in proxy_config_service_linux.cc. It should probably be in 73 // base:: somewhere. 74 scoped_ptr<base::Environment> env(base::Environment::Create()); 75 std::string path; 76 if (!env->GetVar("PATH", &path)) { 77 LOG(ERROR) << "No $PATH variable. Assuming no " << command[0] << "."; 78 return false; 79 } 80 std::vector<std::string> paths; 81 Tokenize(path, ":", &paths); 82 bool found = false; 83 for (size_t i = 0; i < paths.size(); ++i) { 84 base::FilePath file(paths[i]); 85 if (base::PathExists(file.Append(command[0]))) { 86 found = true; 87 break; 88 } 89 } 90 if (!found) 91 return false; 92 std::vector<std::string> argv; 93 for (size_t i = 0; command[i]; ++i) 94 argv.push_back(command[i]); 95 base::ProcessHandle handle; 96 if (!base::LaunchProcess(argv, base::LaunchOptions(), &handle)) { 97 LOG(ERROR) << "StartProxyConfigUtil failed to start " << command[0]; 98 return false; 99 } 100 base::EnsureProcessGetsReaped(handle); 101 return true; 102} 103 104// Detect, and if possible, start the appropriate proxy config utility. On 105// failure to do so, show the Linux proxy config URL in a new tab instead. 106void DetectAndStartProxyConfigUtil(int render_process_id, 107 int render_view_id) { 108 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 109 scoped_ptr<base::Environment> env(base::Environment::Create()); 110 111 bool launched = false; 112 switch (base::nix::GetDesktopEnvironment(env.get())) { 113 case base::nix::DESKTOP_ENVIRONMENT_GNOME: 114 case base::nix::DESKTOP_ENVIRONMENT_UNITY: { 115 launched = StartProxyConfigUtil(kGNOME2ProxyConfigCommand); 116 if (!launched) { 117 // We try this second, even though it's the newer way, because this 118 // command existed in older versions of GNOME, but it didn't do the 119 // same thing. The older command is gone though, so this should do 120 // the right thing. (Also some distributions have blurred the lines 121 // between GNOME 2 and 3, so we can't necessarily detect what the 122 // right thing is based on indications of which version we have.) 123 launched = StartProxyConfigUtil(kGNOME3ProxyConfigCommand); 124 } 125 break; 126 } 127 128 case base::nix::DESKTOP_ENVIRONMENT_KDE3: 129 launched = StartProxyConfigUtil(kKDE3ProxyConfigCommand); 130 break; 131 132 case base::nix::DESKTOP_ENVIRONMENT_KDE4: 133 launched = StartProxyConfigUtil(kKDE4ProxyConfigCommand); 134 break; 135 136 case base::nix::DESKTOP_ENVIRONMENT_XFCE: 137 case base::nix::DESKTOP_ENVIRONMENT_OTHER: 138 break; 139 } 140 141 if (launched) 142 return; 143 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 144 base::Bind(&ShowLinuxProxyConfigUrl, render_process_id, render_view_id)); 145} 146 147} // anonymous namespace 148 149void AdvancedOptionsUtilities::ShowNetworkProxySettings( 150 WebContents* web_contents) { 151 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 152 base::Bind(&DetectAndStartProxyConfigUtil, 153 web_contents->GetRenderProcessHost()->GetID(), 154 web_contents->GetRenderViewHost()->GetRoutingID())); 155} 156 157} // namespace options 158 159#endif // !defined(OS_CHROMEOS) 160