1 /*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "talk/base/proxydetect.h"
29
30 #ifdef WIN32
31 #include "talk/base/win32.h"
32 #include <shlobj.h>
33 #endif // WIN32
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #ifdef OSX
40 #include <SystemConfiguration/SystemConfiguration.h>
41 #include <CoreFoundation/CoreFoundation.h>
42 #include <CoreServices/CoreServices.h>
43 #include <Security/Security.h>
44 #include "macconversion.h"
45 #endif
46
47 #include <map>
48
49 #include "talk/base/fileutils.h"
50 #include "talk/base/httpcommon.h"
51 #include "talk/base/httpcommon-inl.h"
52 #include "talk/base/pathutils.h"
53 #include "talk/base/stringutils.h"
54
55 #ifdef WIN32
56 #define _TRY_WINHTTP 1
57 #define _TRY_JSPROXY 0
58 #define _TRY_WM_FINDPROXY 0
59 #define _TRY_IE_LAN_SETTINGS 1
60 #endif // WIN32
61
62 // For all platforms try Firefox.
63 #define _TRY_FIREFOX 1
64
65 // Use profiles.ini to find the correct profile for this user.
66 // If not set, we'll just look for the default one.
67 #define USE_FIREFOX_PROFILES_INI 1
68
69 static const size_t kMaxLineLength = 1024;
70 static const char kFirefoxPattern[] = "Firefox";
71 static const char kInternetExplorerPattern[] = "MSIE";
72
73 struct StringMap {
74 public:
AddStringMap75 void Add(const char * name, const char * value) { map_[name] = value; }
GetStringMap76 const std::string& Get(const char * name, const char * def = "") const {
77 std::map<std::string, std::string>::const_iterator it =
78 map_.find(name);
79 if (it != map_.end())
80 return it->second;
81 def_ = def;
82 return def_;
83 }
IsSetStringMap84 bool IsSet(const char * name) const {
85 return (map_.find(name) != map_.end());
86 }
87 private:
88 std::map<std::string, std::string> map_;
89 mutable std::string def_;
90 };
91
92 enum UserAgent {
93 UA_FIREFOX,
94 UA_INTERNETEXPLORER,
95 UA_OTHER,
96 UA_UNKNOWN
97 };
98
99 #if _TRY_WINHTTP
100 //#include <winhttp.h>
101 // Note: From winhttp.h
102
103 const char WINHTTP[] = "winhttp";
104
105 typedef LPVOID HINTERNET;
106
107 typedef struct {
108 DWORD dwAccessType; // see WINHTTP_ACCESS_* types below
109 LPWSTR lpszProxy; // proxy server list
110 LPWSTR lpszProxyBypass; // proxy bypass list
111 } WINHTTP_PROXY_INFO, * LPWINHTTP_PROXY_INFO;
112
113 typedef struct {
114 DWORD dwFlags;
115 DWORD dwAutoDetectFlags;
116 LPCWSTR lpszAutoConfigUrl;
117 LPVOID lpvReserved;
118 DWORD dwReserved;
119 BOOL fAutoLogonIfChallenged;
120 } WINHTTP_AUTOPROXY_OPTIONS;
121
122 typedef struct {
123 BOOL fAutoDetect;
124 LPWSTR lpszAutoConfigUrl;
125 LPWSTR lpszProxy;
126 LPWSTR lpszProxyBypass;
127 } WINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
128
129 extern "C" {
130 typedef HINTERNET (WINAPI * pfnWinHttpOpen)
131 (
132 IN LPCWSTR pwszUserAgent,
133 IN DWORD dwAccessType,
134 IN LPCWSTR pwszProxyName OPTIONAL,
135 IN LPCWSTR pwszProxyBypass OPTIONAL,
136 IN DWORD dwFlags
137 );
138 typedef BOOL (STDAPICALLTYPE * pfnWinHttpCloseHandle)
139 (
140 IN HINTERNET hInternet
141 );
142 typedef BOOL (STDAPICALLTYPE * pfnWinHttpGetProxyForUrl)
143 (
144 IN HINTERNET hSession,
145 IN LPCWSTR lpcwszUrl,
146 IN WINHTTP_AUTOPROXY_OPTIONS * pAutoProxyOptions,
147 OUT WINHTTP_PROXY_INFO * pProxyInfo
148 );
149 typedef BOOL (STDAPICALLTYPE * pfnWinHttpGetIEProxyConfig)
150 (
151 IN OUT WINHTTP_CURRENT_USER_IE_PROXY_CONFIG * pProxyConfig
152 );
153
154 } // extern "C"
155
156 #define WINHTTP_AUTOPROXY_AUTO_DETECT 0x00000001
157 #define WINHTTP_AUTOPROXY_CONFIG_URL 0x00000002
158 #define WINHTTP_AUTOPROXY_RUN_INPROCESS 0x00010000
159 #define WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY 0x00020000
160 #define WINHTTP_AUTO_DETECT_TYPE_DHCP 0x00000001
161 #define WINHTTP_AUTO_DETECT_TYPE_DNS_A 0x00000002
162 #define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0
163 #define WINHTTP_ACCESS_TYPE_NO_PROXY 1
164 #define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3
165 #define WINHTTP_NO_PROXY_NAME NULL
166 #define WINHTTP_NO_PROXY_BYPASS NULL
167
168 #endif // _TRY_WINHTTP
169
170 #if _TRY_JSPROXY
171 extern "C" {
172 typedef BOOL (STDAPICALLTYPE * pfnInternetGetProxyInfo)
173 (
174 LPCSTR lpszUrl,
175 DWORD dwUrlLength,
176 LPSTR lpszUrlHostName,
177 DWORD dwUrlHostNameLength,
178 LPSTR * lplpszProxyHostName,
179 LPDWORD lpdwProxyHostNameLength
180 );
181 } // extern "C"
182 #endif // _TRY_JSPROXY
183
184 #if _TRY_WM_FINDPROXY
185 #include <comutil.h>
186 #include <wmnetsourcecreator.h>
187 #include <wmsinternaladminnetsource.h>
188 #endif // _TRY_WM_FINDPROXY
189
190 #if _TRY_IE_LAN_SETTINGS
191 #include <wininet.h>
192 #include <string>
193 #endif // _TRY_IE_LAN_SETTINGS
194
195 namespace talk_base {
196
197 //////////////////////////////////////////////////////////////////////
198 // Utility Functions
199 //////////////////////////////////////////////////////////////////////
200
201 #ifdef WIN32
202 #ifdef _UNICODE
203
204 typedef std::wstring tstring;
Utf8String(const tstring & str)205 std::string Utf8String(const tstring& str) { return ToUtf8(str); }
206
207 #else // !_UNICODE
208
209 typedef std::string tstring;
210 std::string Utf8String(const tstring& str) { return str; }
211
212 #endif // !_UNICODE
213 #endif // WIN32
214
ProxyItemMatch(const Url<char> & url,char * item,size_t len)215 bool ProxyItemMatch(const Url<char>& url, char * item, size_t len) {
216 // hostname:443
217 if (char * port = ::strchr(item, ':')) {
218 *port++ = '\0';
219 if (url.port() != atol(port)) {
220 return false;
221 }
222 }
223
224 // A.B.C.D or A.B.C.D/24
225 int a, b, c, d, m;
226 int match = sscanf(item, "%d.%d.%d.%d/%d", &a, &b, &c, &d, &m);
227 if (match >= 4) {
228 uint32 ip = ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) |
229 (d & 0xFF);
230 if ((match < 5) || (m > 32))
231 m = 32;
232 else if (m < 0)
233 m = 0;
234 uint32 mask = (m == 0) ? 0 : (~0UL) << (32 - m);
235 SocketAddress addr(url.host(), 0);
236 return !addr.IsUnresolved() && ((addr.ip() & mask) == (ip & mask));
237 }
238
239 // .foo.com
240 if (*item == '.') {
241 size_t hostlen = url.host().length();
242 return (hostlen > len)
243 && (stricmp(url.host().c_str() + (hostlen - len), item) == 0);
244 }
245
246 // localhost or www.*.com
247 if (!string_match(url.host().c_str(), item))
248 return false;
249
250 return true;
251 }
252
ProxyListMatch(const Url<char> & url,const std::string & proxy_list,char sep)253 bool ProxyListMatch(const Url<char>& url, const std::string& proxy_list,
254 char sep) {
255 const size_t BUFSIZE = 256;
256 char buffer[BUFSIZE];
257 const char* list = proxy_list.c_str();
258 while (*list) {
259 // Remove leading space
260 if (isspace(*list)) {
261 ++list;
262 continue;
263 }
264 // Break on separator
265 size_t len;
266 const char * start = list;
267 if (const char * end = ::strchr(list, sep)) {
268 len = (end - list);
269 list += len + 1;
270 } else {
271 len = strlen(list);
272 list += len;
273 }
274 // Remove trailing space
275 while ((len > 0) && isspace(start[len-1]))
276 --len;
277 // Check for oversized entry
278 if (len >= BUFSIZE)
279 continue;
280 memcpy(buffer, start, len);
281 buffer[len] = 0;
282 if (!ProxyItemMatch(url, buffer, len))
283 continue;
284 return true;
285 }
286 return false;
287 }
288
Better(ProxyType lhs,const ProxyType rhs)289 bool Better(ProxyType lhs, const ProxyType rhs) {
290 // PROXY_NONE, PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN
291 const int PROXY_VALUE[5] = { 0, 2, 3, 1 };
292 return (PROXY_VALUE[lhs] > PROXY_VALUE[rhs]);
293 }
294
ParseProxy(const std::string & saddress,ProxyInfo * proxy)295 bool ParseProxy(const std::string& saddress, ProxyInfo* proxy) {
296 const size_t kMaxAddressLength = 1024;
297 // Allow semicolon, space, or tab as an address separator
298 const char* const kAddressSeparator = " ;\t";
299
300 ProxyType ptype;
301 std::string host;
302 uint16 port;
303
304 const char* address = saddress.c_str();
305 while (*address) {
306 size_t len;
307 const char * start = address;
308 if (const char * sep = strchr(address, kAddressSeparator)) {
309 len = (sep - address);
310 address += len + 1;
311 while (*address != '\0' && ::strchr(kAddressSeparator, *address)) {
312 address += 1;
313 }
314 } else {
315 len = strlen(address);
316 address += len;
317 }
318
319 if (len > kMaxAddressLength - 1) {
320 LOG(LS_WARNING) << "Proxy address too long [" << start << "]";
321 continue;
322 }
323
324 char buffer[kMaxAddressLength];
325 memcpy(buffer, start, len);
326 buffer[len] = 0;
327
328 char * colon = ::strchr(buffer, ':');
329 if (!colon) {
330 LOG(LS_WARNING) << "Proxy address without port [" << buffer << "]";
331 continue;
332 }
333
334 *colon = 0;
335 char * endptr;
336 port = static_cast<uint16>(strtol(colon + 1, &endptr, 0));
337 if (*endptr != 0) {
338 LOG(LS_WARNING) << "Proxy address with invalid port [" << buffer << "]";
339 continue;
340 }
341
342 if (char * equals = ::strchr(buffer, '=')) {
343 *equals = 0;
344 host = equals + 1;
345 if (_stricmp(buffer, "socks") == 0) {
346 ptype = PROXY_SOCKS5;
347 } else if (_stricmp(buffer, "https") == 0) {
348 ptype = PROXY_HTTPS;
349 } else {
350 LOG(LS_WARNING) << "Proxy address with unknown protocol ["
351 << buffer << "]";
352 ptype = PROXY_UNKNOWN;
353 }
354 } else {
355 host = buffer;
356 ptype = PROXY_UNKNOWN;
357 }
358
359 if (Better(ptype, proxy->type)) {
360 proxy->type = ptype;
361 proxy->address.SetIP(host);
362 proxy->address.SetPort(port);
363 }
364 }
365
366 return proxy->type != PROXY_NONE;
367 }
368
GetAgent(const char * agent)369 UserAgent GetAgent(const char* agent) {
370 if (agent) {
371 std::string agent_str(agent);
372 if (agent_str.find(kFirefoxPattern) != std::string::npos) {
373 return UA_FIREFOX;
374 } else if (agent_str.find(kInternetExplorerPattern) != std::string::npos) {
375 return UA_INTERNETEXPLORER;
376 } else if (agent_str.empty()) {
377 return UA_UNKNOWN;
378 }
379 }
380 return UA_OTHER;
381 }
382
EndsWith(const std::string & a,const std::string & b)383 bool EndsWith(const std::string& a, const std::string& b) {
384 if (b.size() > a.size()) {
385 return false;
386 }
387 int result = a.compare(a.size() - b.size(), b.size(), b);
388 return result == 0;
389 }
390
GetFirefoxProfilePath(Pathname * path)391 bool GetFirefoxProfilePath(Pathname* path) {
392 #ifdef WIN32
393 wchar_t w_path[MAX_PATH];
394 if (SHGetFolderPath(0, CSIDL_APPDATA, 0, SHGFP_TYPE_CURRENT, w_path) !=
395 S_OK) {
396 LOG(LS_ERROR) << "SHGetFolderPath failed";
397 return false;
398 }
399 path->SetFolder(ToUtf8(w_path, wcslen(w_path)));
400 path->AppendFolder("Mozilla");
401 path->AppendFolder("Firefox");
402 #elif OSX
403 FSRef fr;
404 if (0 != FSFindFolder(kUserDomain, kApplicationSupportFolderType,
405 kCreateFolder, &fr)) {
406 LOG(LS_ERROR) << "FSFindFolder failed";
407 return false;
408 }
409 char buffer[NAME_MAX + 1];
410 if (0 != FSRefMakePath(&fr, reinterpret_cast<uint8*>(buffer),
411 ARRAY_SIZE(buffer))) {
412 LOG(LS_ERROR) << "FSRefMakePath failed";
413 return false;
414 }
415 path->SetFolder(std::string(buffer));
416 path->AppendFolder("Firefox");
417 #else
418 char* user_home = getenv("HOME");
419 if (user_home == NULL) {
420 return false;
421 }
422 path->SetFolder(std::string(user_home));
423 path->AppendFolder(".mozilla");
424 path->AppendFolder("firefox");
425 #endif // WIN32
426 return true;
427 }
428
GetDefaultFirefoxProfile(Pathname * profile_path)429 bool GetDefaultFirefoxProfile(Pathname* profile_path) {
430 ASSERT(NULL != profile_path);
431 Pathname path;
432 if (!GetFirefoxProfilePath(&path)) {
433 return false;
434 }
435
436 #if USE_FIREFOX_PROFILES_INI
437 // [Profile0]
438 // Name=default
439 // IsRelative=1
440 // Path=Profiles/2de53ejb.default
441 // Default=1
442
443 // Note: we are looking for the first entry with "Default=1", or the last
444 // entry in the file
445 path.SetFilename("profiles.ini");
446 FileStream* fs = Filesystem::OpenFile(path, "r");
447 if (!fs) {
448 return false;
449 }
450 Pathname candidate;
451 bool relative = true;
452 std::string line;
453 while (fs->ReadLine(&line) == SR_SUCCESS) {
454 if (line.length() == 0) {
455 continue;
456 }
457 if (line.at(0) == '[') {
458 relative = true;
459 candidate.clear();
460 } else if (line.find("IsRelative=") == 0 &&
461 line.length() >= 12) {
462 // TODO: The initial Linux public launch revealed a fairly
463 // high number of machines where IsRelative= did not have anything after
464 // it. Perhaps that is legal profiles.ini syntax?
465 relative = (line.at(11) != '0');
466 } else if (line.find("Path=") == 0 &&
467 line.length() >= 6) {
468 if (relative) {
469 candidate = path;
470 } else {
471 candidate.clear();
472 }
473 candidate.AppendFolder(line.substr(5));
474 } else if (line.find("Default=") == 0 &&
475 line.length() >= 9) {
476 if ((line.at(8) != '0') && !candidate.empty()) {
477 break;
478 }
479 }
480 }
481 fs->Close();
482 if (candidate.empty()) {
483 return false;
484 }
485 profile_path->SetPathname(candidate.pathname());
486
487 #else // !USE_FIREFOX_PROFILES_INI
488 path.AppendFolder("Profiles");
489 DirectoryIterator* it = Filesystem::IterateDirectory();
490 it->Iterate(path);
491 std::string extension(".default");
492 while (!EndsWith(it->Name(), extension)) {
493 if (!it->Next()) {
494 return false;
495 }
496 }
497
498 profile_path->SetPathname(path);
499 profile->AppendFolder("Profiles");
500 profile->AppendFolder(it->Name());
501 delete it;
502
503 #endif // !USE_FIREFOX_PROFILES_INI
504
505 return true;
506 }
507
ReadFirefoxPrefs(const Pathname & filename,const char * prefix,StringMap * settings)508 bool ReadFirefoxPrefs(const Pathname& filename,
509 const char * prefix,
510 StringMap* settings) {
511 FileStream* fs = Filesystem::OpenFile(filename, "r");
512 if (!fs) {
513 LOG(LS_ERROR) << "Failed to open file: " << filename.pathname();
514 return false;
515 }
516
517 std::string line;
518 while (fs->ReadLine(&line) == SR_SUCCESS) {
519 size_t prefix_len = strlen(prefix);
520
521 // Skip blank lines and too long lines.
522 if ((line.length() == 0) || (line.length() > kMaxLineLength)
523 || (line.at(0) == '#') || line.compare(0, 2, "/*") == 0
524 || line.compare(0, 2, " *") == 0) {
525 continue;
526 }
527
528 char buffer[kMaxLineLength];
529 strcpyn(buffer, sizeof(buffer), line.c_str());
530 int nstart = 0, nend = 0, vstart = 0, vend = 0;
531 sscanf(buffer, "user_pref(\"%n%*[^\"]%n\", %n%*[^)]%n);",
532 &nstart, &nend, &vstart, &vend);
533 if (vend > 0) {
534 char* name = buffer + nstart;
535 name[nend - nstart] = 0;
536 if ((vend - vstart >= 2) && (buffer[vstart] == '"')) {
537 vstart += 1;
538 vend -= 1;
539 }
540 char* value = buffer + vstart;
541 value[vend - vstart] = 0;
542 if ((strncmp(name, prefix, prefix_len) == 0) && *value) {
543 settings->Add(name + prefix_len, value);
544 }
545 } else {
546 LOG_F(LS_WARNING) << "Unparsed pref [" << buffer << "]";
547 }
548 }
549 fs->Close();
550 return true;
551 }
552
GetFirefoxProxySettings(const char * url,ProxyInfo * proxy)553 bool GetFirefoxProxySettings(const char* url, ProxyInfo* proxy) {
554 Url<char> purl(url);
555 Pathname path;
556 bool success = false;
557 if (GetDefaultFirefoxProfile(&path)) {
558 StringMap settings;
559 path.SetFilename("prefs.js");
560 if (ReadFirefoxPrefs(path, "network.proxy.", &settings)) {
561 success = true;
562 proxy->bypass_list =
563 settings.Get("no_proxies_on", "localhost, 127.0.0.1");
564 if (settings.Get("type") == "1") {
565 // User has manually specified a proxy, try to figure out what
566 // type it is.
567 if (ProxyListMatch(purl, proxy->bypass_list.c_str(), ',')) {
568 // Our url is in the list of url's to bypass proxy.
569 } else if (settings.Get("share_proxy_settings") == "true") {
570 proxy->type = PROXY_UNKNOWN;
571 proxy->address.SetIP(settings.Get("http"));
572 proxy->address.SetPort(atoi(settings.Get("http_port").c_str()));
573 } else if (settings.IsSet("socks")) {
574 proxy->type = PROXY_SOCKS5;
575 proxy->address.SetIP(settings.Get("socks"));
576 proxy->address.SetPort(atoi(settings.Get("socks_port").c_str()));
577 } else if (settings.IsSet("ssl")) {
578 proxy->type = PROXY_HTTPS;
579 proxy->address.SetIP(settings.Get("ssl"));
580 proxy->address.SetPort(atoi(settings.Get("ssl_port").c_str()));
581 } else if (settings.IsSet("http")) {
582 proxy->type = PROXY_HTTPS;
583 proxy->address.SetIP(settings.Get("http"));
584 proxy->address.SetPort(atoi(settings.Get("http_port").c_str()));
585 }
586 } else if (settings.Get("type") == "2") {
587 // Browser is configured to get proxy settings from a given url.
588 proxy->autoconfig_url = settings.Get("autoconfig_url").c_str();
589 } else if (settings.Get("type") == "4") {
590 // Browser is configured to auto detect proxy config.
591 proxy->autodetect = true;
592 } else {
593 // No proxy set.
594 }
595 }
596 }
597 return success;
598 }
599
600 #ifdef WIN32 // Windows specific implementation for reading Internet
601 // Explorer proxy settings.
602
LogGetProxyFault()603 void LogGetProxyFault() {
604 LOG_GLEM(LERROR, WINHTTP) << "WinHttpGetProxyForUrl faulted!!";
605 }
606
MyWinHttpGetProxyForUrl(pfnWinHttpGetProxyForUrl pWHGPFU,HINTERNET hWinHttp,LPCWSTR url,WINHTTP_AUTOPROXY_OPTIONS * options,WINHTTP_PROXY_INFO * info)607 BOOL MyWinHttpGetProxyForUrl(pfnWinHttpGetProxyForUrl pWHGPFU,
608 HINTERNET hWinHttp, LPCWSTR url,
609 WINHTTP_AUTOPROXY_OPTIONS *options,
610 WINHTTP_PROXY_INFO *info) {
611 // WinHttpGetProxyForUrl() can call plugins which can crash.
612 // In the case of McAfee scriptproxy.dll, it does crash in
613 // older versions. Try to catch crashes here and treat as an
614 // error.
615 BOOL success = FALSE;
616
617 #if (_HAS_EXCEPTIONS == 0)
618 __try {
619 success = pWHGPFU(hWinHttp, url, options, info);
620 } __except(EXCEPTION_EXECUTE_HANDLER) {
621 // This is a separate function to avoid
622 // Visual C++ error 2712 when compiling with C++ EH
623 LogGetProxyFault();
624 }
625 #else
626 success = pWHGPFU(hWinHttp, url, options, info);
627 #endif // (_HAS_EXCEPTIONS == 0)
628
629 return success;
630 }
631
IsDefaultBrowserFirefox()632 bool IsDefaultBrowserFirefox() {
633 HKEY key;
634 LONG result = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"http\\shell\\open\\command",
635 0, KEY_READ, &key);
636 if (ERROR_SUCCESS != result)
637 return false;
638
639 wchar_t* value = NULL;
640 DWORD size, type;
641 result = RegQueryValueEx(key, L"", 0, &type, NULL, &size);
642 if (REG_SZ != type) {
643 result = ERROR_ACCESS_DENIED; // Any error is fine
644 } else if (ERROR_SUCCESS == result) {
645 value = new wchar_t[size+1];
646 BYTE* buffer = reinterpret_cast<BYTE*>(value);
647 result = RegQueryValueEx(key, L"", 0, &type, buffer, &size);
648 }
649 RegCloseKey(key);
650
651 bool success = false;
652 if (ERROR_SUCCESS == result) {
653 value[size] = L'\0';
654 for (size_t i = 0; i < size; ++i) {
655 value[i] = tolowercase(value[i]);
656 }
657 success = (NULL != strstr(value, L"firefox.exe"));
658 }
659 delete [] value;
660 return success;
661 }
662
GetWinHttpProxySettings(const char * url,ProxyInfo * proxy)663 bool GetWinHttpProxySettings(const char* url, ProxyInfo* proxy) {
664 HMODULE winhttp_handle = LoadLibrary(L"winhttp.dll");
665 if (winhttp_handle == NULL) {
666 LOG(LS_ERROR) << "Failed to load winhttp.dll.";
667 return false;
668 }
669 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG iecfg;
670 memset(&iecfg, 0, sizeof(iecfg));
671 Url<char> purl(url);
672 pfnWinHttpGetIEProxyConfig pWHGIEPC =
673 reinterpret_cast<pfnWinHttpGetIEProxyConfig>(
674 GetProcAddress(winhttp_handle,
675 "WinHttpGetIEProxyConfigForCurrentUser"));
676 bool success = false;
677 if (pWHGIEPC && pWHGIEPC(&iecfg)) {
678 // We were read proxy config successfully.
679 success = true;
680 if (iecfg.fAutoDetect) {
681 proxy->autodetect = true;
682 }
683 if (iecfg.lpszAutoConfigUrl) {
684 proxy->autoconfig_url = ToUtf8(iecfg.lpszAutoConfigUrl);
685 GlobalFree(iecfg.lpszAutoConfigUrl);
686 }
687 if (iecfg.lpszProxyBypass) {
688 proxy->bypass_list = ToUtf8(iecfg.lpszProxyBypass);
689 GlobalFree(iecfg.lpszProxyBypass);
690 }
691 if (iecfg.lpszProxy) {
692 if (!ProxyListMatch(purl, proxy->bypass_list, ';')) {
693 ParseProxy(ToUtf8(iecfg.lpszProxy), proxy);
694 }
695 GlobalFree(iecfg.lpszProxy);
696 }
697 }
698 FreeLibrary(winhttp_handle);
699 return success;
700 }
701
702 // Uses the WinHTTP API to auto detect proxy for the given url. Firefox and IE
703 // have slightly different option dialogs for proxy settings. In Firefox,
704 // either a location of a proxy configuration file can be specified or auto
705 // detection can be selected. In IE theese two options can be independently
706 // selected. For the case where both options are selected (only IE) we try to
707 // fetch the config file first, and if that fails we'll perform an auto
708 // detection.
709 //
710 // Returns true if we successfully performed an auto detection not depending on
711 // whether we found a proxy or not. Returns false on error.
WinHttpAutoDetectProxyForUrl(const char * agent,const char * url,ProxyInfo * proxy)712 bool WinHttpAutoDetectProxyForUrl(const char* agent, const char* url,
713 ProxyInfo* proxy) {
714 Url<char> purl(url);
715 bool success = true;
716 HMODULE winhttp_handle = LoadLibrary(L"winhttp.dll");
717 if (winhttp_handle == NULL) {
718 LOG(LS_ERROR) << "Failed to load winhttp.dll.";
719 return false;
720 }
721 pfnWinHttpOpen pWHO =
722 reinterpret_cast<pfnWinHttpOpen>(GetProcAddress(winhttp_handle,
723 "WinHttpOpen"));
724 pfnWinHttpCloseHandle pWHCH =
725 reinterpret_cast<pfnWinHttpCloseHandle>(
726 GetProcAddress(winhttp_handle, "WinHttpCloseHandle"));
727 pfnWinHttpGetProxyForUrl pWHGPFU =
728 reinterpret_cast<pfnWinHttpGetProxyForUrl>(
729 GetProcAddress(winhttp_handle, "WinHttpGetProxyForUrl"));
730 if (pWHO && pWHCH && pWHGPFU) {
731 if (HINTERNET hWinHttp = pWHO(ToUtf16(agent).c_str(),
732 WINHTTP_ACCESS_TYPE_NO_PROXY,
733 WINHTTP_NO_PROXY_NAME,
734 WINHTTP_NO_PROXY_BYPASS,
735 0)) {
736 BOOL result = FALSE;
737 WINHTTP_PROXY_INFO info;
738 memset(&info, 0, sizeof(info));
739 if (proxy->autodetect) {
740 // Use DHCP and DNS to try to find any proxy to use.
741 WINHTTP_AUTOPROXY_OPTIONS options;
742 memset(&options, 0, sizeof(options));
743 options.fAutoLogonIfChallenged = TRUE;
744
745 options.dwFlags |= WINHTTP_AUTOPROXY_AUTO_DETECT;
746 options.dwAutoDetectFlags |= WINHTTP_AUTO_DETECT_TYPE_DHCP
747 | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
748 result = MyWinHttpGetProxyForUrl(
749 pWHGPFU, hWinHttp, ToUtf16(url).c_str(), &options, &info);
750 }
751 if (!result && !proxy->autoconfig_url.empty()) {
752 // We have the location of a proxy config file. Download it and
753 // execute it to find proxy settings for our url.
754 WINHTTP_AUTOPROXY_OPTIONS options;
755 memset(&options, 0, sizeof(options));
756 memset(&info, 0, sizeof(info));
757 options.fAutoLogonIfChallenged = TRUE;
758
759 std::wstring autoconfig_url16((ToUtf16)(proxy->autoconfig_url));
760 options.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
761 options.lpszAutoConfigUrl = autoconfig_url16.c_str();
762
763 result = MyWinHttpGetProxyForUrl(
764 pWHGPFU, hWinHttp, ToUtf16(url).c_str(), &options, &info);
765 }
766 if (result) {
767 // Either the given auto config url was valid or auto
768 // detection found a proxy on this network.
769 if (info.lpszProxy) {
770 // TODO: Does this bypass list differ from the list
771 // retreived from GetWinHttpProxySettings earlier?
772 if (info.lpszProxyBypass) {
773 proxy->bypass_list = ToUtf8(info.lpszProxyBypass);
774 GlobalFree(info.lpszProxyBypass);
775 } else {
776 proxy->bypass_list.clear();
777 }
778 if (!ProxyListMatch(purl, proxy->bypass_list, ';')) {
779 // Found proxy for this URL. If parsing the address turns
780 // out ok then we are successful.
781 success = ParseProxy(ToUtf8(info.lpszProxy), proxy);
782 }
783 GlobalFree(info.lpszProxy);
784 }
785 } else {
786 // We could not find any proxy for this url.
787 LOG(LS_INFO) << "No proxy detected for " << url;
788 }
789 pWHCH(hWinHttp);
790 }
791 } else {
792 LOG(LS_ERROR) << "Failed loading WinHTTP functions.";
793 success = false;
794 }
795 FreeLibrary(winhttp_handle);
796 return success;
797 }
798
799 #if 0 // Below functions currently not used.
800
801 bool GetJsProxySettings(const char* url, ProxyInfo* proxy) {
802 Url<char> purl(url);
803 bool success = false;
804
805 if (HMODULE hModJS = LoadLibrary(_T("jsproxy.dll"))) {
806 pfnInternetGetProxyInfo pIGPI =
807 reinterpret_cast<pfnInternetGetProxyInfo>(
808 GetProcAddress(hModJS, "InternetGetProxyInfo"));
809 if (pIGPI) {
810 char proxy[256], host[256];
811 memset(proxy, 0, sizeof(proxy));
812 char * ptr = proxy;
813 DWORD proxylen = sizeof(proxy);
814 std::string surl = Utf8String(url);
815 DWORD hostlen = _snprintf(host, sizeof(host), "http%s://%S",
816 purl.secure() ? "s" : "", purl.server());
817 if (pIGPI(surl.data(), surl.size(), host, hostlen, &ptr, &proxylen)) {
818 LOG(INFO) << "Proxy: " << proxy;
819 } else {
820 LOG_GLE(INFO) << "InternetGetProxyInfo";
821 }
822 }
823 FreeLibrary(hModJS);
824 }
825 return success;
826 }
827
828 bool GetWmProxySettings(const char* url, ProxyInfo* proxy) {
829 Url<char> purl(url);
830 bool success = false;
831
832 INSNetSourceCreator * nsc = 0;
833 HRESULT hr = CoCreateInstance(CLSID_ClientNetManager, 0, CLSCTX_ALL,
834 IID_INSNetSourceCreator, (LPVOID *) &nsc);
835 if (SUCCEEDED(hr)) {
836 if (SUCCEEDED(hr = nsc->Initialize())) {
837 VARIANT dispatch;
838 VariantInit(&dispatch);
839 if (SUCCEEDED(hr = nsc->GetNetSourceAdminInterface(L"http", &dispatch))) {
840 IWMSInternalAdminNetSource * ians = 0;
841 if (SUCCEEDED(hr = dispatch.pdispVal->QueryInterface(
842 IID_IWMSInternalAdminNetSource, (LPVOID *) &ians))) {
843 _bstr_t host(purl.server());
844 BSTR proxy = 0;
845 BOOL bProxyEnabled = FALSE;
846 DWORD port, context = 0;
847 if (SUCCEEDED(hr = ians->FindProxyForURL(
848 L"http", host, &bProxyEnabled, &proxy, &port, &context))) {
849 success = true;
850 if (bProxyEnabled) {
851 _bstr_t sproxy = proxy;
852 proxy->ptype = PT_HTTPS;
853 proxy->host = sproxy;
854 proxy->port = port;
855 }
856 }
857 SysFreeString(proxy);
858 if (FAILED(hr = ians->ShutdownProxyContext(context))) {
859 LOG(LS_INFO) << "IWMSInternalAdminNetSource::ShutdownProxyContext"
860 << "failed: " << hr;
861 }
862 ians->Release();
863 }
864 }
865 VariantClear(&dispatch);
866 if (FAILED(hr = nsc->Shutdown())) {
867 LOG(LS_INFO) << "INSNetSourceCreator::Shutdown failed: " << hr;
868 }
869 }
870 nsc->Release();
871 }
872 return success;
873 }
874
875 bool GetIePerConnectionProxySettings(const char* url, ProxyInfo* proxy) {
876 Url<char> purl(url);
877 bool success = false;
878
879 INTERNET_PER_CONN_OPTION_LIST list;
880 INTERNET_PER_CONN_OPTION options[3];
881 memset(&list, 0, sizeof(list));
882 memset(&options, 0, sizeof(options));
883
884 list.dwSize = sizeof(list);
885 list.dwOptionCount = 3;
886 list.pOptions = options;
887 options[0].dwOption = INTERNET_PER_CONN_FLAGS;
888 options[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
889 options[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
890 DWORD dwSize = sizeof(list);
891
892 if (!InternetQueryOption(0, INTERNET_OPTION_PER_CONNECTION_OPTION, &list,
893 &dwSize)) {
894 LOG(LS_INFO) << "InternetQueryOption failed: " << GetLastError();
895 } else if ((options[0].Value.dwValue & PROXY_TYPE_PROXY) != 0) {
896 success = true;
897 if (!ProxyListMatch(purl, nonnull(options[2].Value.pszValue), _T(';'))) {
898 ParseProxy(nonnull(options[1].Value.pszValue), proxy);
899 }
900 } else if ((options[0].Value.dwValue & PROXY_TYPE_DIRECT) != 0) {
901 success = true;
902 } else {
903 LOG(LS_INFO) << "unknown internet access type: "
904 << options[0].Value.dwValue;
905 }
906 if (options[1].Value.pszValue) {
907 GlobalFree(options[1].Value.pszValue);
908 }
909 if (options[2].Value.pszValue) {
910 GlobalFree(options[2].Value.pszValue);
911 }
912 return success;
913 }
914
915 #endif // 0
916
917 // Uses the InternetQueryOption function to retrieve proxy settings
918 // from the registry. This will only give us the 'static' settings,
919 // ie, not any information about auto config etc.
GetIeLanProxySettings(const char * url,ProxyInfo * proxy)920 bool GetIeLanProxySettings(const char* url, ProxyInfo* proxy) {
921 Url<char> purl(url);
922 bool success = false;
923
924 wchar_t buffer[1024];
925 memset(buffer, 0, sizeof(buffer));
926 INTERNET_PROXY_INFO * info = reinterpret_cast<INTERNET_PROXY_INFO *>(buffer);
927 DWORD dwSize = sizeof(buffer);
928
929 if (!InternetQueryOption(0, INTERNET_OPTION_PROXY, info, &dwSize)) {
930 LOG(LS_INFO) << "InternetQueryOption failed: " << GetLastError();
931 } else if (info->dwAccessType == INTERNET_OPEN_TYPE_DIRECT) {
932 success = true;
933 } else if (info->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
934 success = true;
935 if (!ProxyListMatch(purl, nonnull(reinterpret_cast<const char*>(
936 info->lpszProxyBypass)), ' ')) {
937 ParseProxy(nonnull(reinterpret_cast<const char*>(info->lpszProxy)),
938 proxy);
939 }
940 } else {
941 LOG(LS_INFO) << "unknown internet access type: " << info->dwAccessType;
942 }
943 return success;
944 }
945
GetIeProxySettings(const char * agent,const char * url,ProxyInfo * proxy)946 bool GetIeProxySettings(const char* agent, const char* url, ProxyInfo* proxy) {
947 bool success = GetWinHttpProxySettings(url, proxy);
948 if (!success) {
949 // TODO: Should always call this if no proxy were detected by
950 // GetWinHttpProxySettings?
951 // WinHttp failed. Try using the InternetOptionQuery method instead.
952 return GetIeLanProxySettings(url, proxy);
953 }
954 return true;
955 }
956
957 #endif // WIN32
958
959 #ifdef OSX // OSX specific implementation for reading system wide
960 // proxy settings.
961
p_getProxyInfoForTypeFromDictWithKeys(ProxyInfo * proxy,ProxyType type,const CFDictionaryRef proxyDict,const CFStringRef enabledKey,const CFStringRef hostKey,const CFStringRef portKey)962 bool p_getProxyInfoForTypeFromDictWithKeys(ProxyInfo* proxy,
963 ProxyType type,
964 const CFDictionaryRef proxyDict,
965 const CFStringRef enabledKey,
966 const CFStringRef hostKey,
967 const CFStringRef portKey) {
968 // whether or not we set up the proxy info.
969 bool result = false;
970
971 // we use this as a scratch variable for determining if operations
972 // succeeded.
973 bool converted = false;
974
975 // the data we need to construct the SocketAddress for the proxy.
976 std::string hostname;
977 int port;
978
979 if ((proxyDict != NULL) &&
980 (CFGetTypeID(proxyDict) == CFDictionaryGetTypeID())) {
981 // CoreFoundation stuff that we'll have to get from
982 // the dictionaries and interpret or convert into more usable formats.
983 CFNumberRef enabledCFNum;
984 CFNumberRef portCFNum;
985 CFStringRef hostCFStr;
986
987 enabledCFNum = (CFNumberRef)CFDictionaryGetValue(proxyDict, enabledKey);
988
989 if (p_isCFNumberTrue(enabledCFNum)) {
990 // let's see if we can get the address and port.
991 hostCFStr = (CFStringRef)CFDictionaryGetValue(proxyDict, hostKey);
992 converted = p_convertHostCFStringRefToCPPString(hostCFStr, hostname);
993 if (converted) {
994 portCFNum = (CFNumberRef)CFDictionaryGetValue(proxyDict, portKey);
995 converted = p_convertCFNumberToInt(portCFNum, &port);
996 if (converted) {
997 // we have something enabled, with a hostname and a port.
998 // That's sufficient to set up the proxy info.
999 proxy->type = type;
1000 proxy->address.SetIP(hostname);
1001 proxy->address.SetPort(port);
1002 result = true;
1003 }
1004 }
1005 }
1006 }
1007
1008 return result;
1009 }
1010
1011 // Looks for proxy information in the given dictionary,
1012 // return true if it found sufficient information to define one,
1013 // false otherwise. This is guaranteed to not change the values in proxy
1014 // unless a full-fledged proxy description was discovered in the dictionary.
1015 // However, at the present time this does not support username or password.
1016 // Checks first for a SOCKS proxy, then for HTTPS, then HTTP.
GetMacProxySettingsFromDictionary(ProxyInfo * proxy,const CFDictionaryRef proxyDict)1017 bool GetMacProxySettingsFromDictionary(ProxyInfo* proxy,
1018 const CFDictionaryRef proxyDict) {
1019 // the function result.
1020 bool gotProxy = false;
1021
1022
1023 // first we see if there's a SOCKS proxy in place.
1024 gotProxy = p_getProxyInfoForTypeFromDictWithKeys(proxy,
1025 PROXY_SOCKS5,
1026 proxyDict,
1027 kSCPropNetProxiesSOCKSEnable,
1028 kSCPropNetProxiesSOCKSProxy,
1029 kSCPropNetProxiesSOCKSPort);
1030
1031 if (!gotProxy) {
1032 // okay, no SOCKS proxy, let's look for https.
1033 gotProxy = p_getProxyInfoForTypeFromDictWithKeys(proxy,
1034 PROXY_HTTPS,
1035 proxyDict,
1036 kSCPropNetProxiesHTTPSEnable,
1037 kSCPropNetProxiesHTTPSProxy,
1038 kSCPropNetProxiesHTTPSPort);
1039 if (!gotProxy) {
1040 // Finally, try HTTP proxy. Note that flute doesn't
1041 // differentiate between HTTPS and HTTP, hence we are using the
1042 // same flute type here, ie. PROXY_HTTPS.
1043 gotProxy = p_getProxyInfoForTypeFromDictWithKeys(
1044 proxy, PROXY_HTTPS, proxyDict, kSCPropNetProxiesHTTPEnable,
1045 kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort);
1046 }
1047 }
1048 return gotProxy;
1049 }
1050
p_putPasswordInProxyInfo(ProxyInfo * proxy)1051 bool p_putPasswordInProxyInfo(ProxyInfo* proxy) {
1052 bool result = true; // by default we assume we're good.
1053 // for all we know there isn't any password. We'll set to false
1054 // if we find a problem.
1055
1056 // Ask the keychain for an internet password search for the given protocol.
1057 OSStatus oss = 0;
1058 SecKeychainAttributeList attrList;
1059 attrList.count = 3;
1060 SecKeychainAttribute attributes[3];
1061 attrList.attr = attributes;
1062
1063 attributes[0].tag = kSecProtocolItemAttr;
1064 attributes[0].length = sizeof(SecProtocolType);
1065 SecProtocolType protocol;
1066 switch (proxy->type) {
1067 case PROXY_HTTPS :
1068 protocol = kSecProtocolTypeHTTPS;
1069 break;
1070 case PROXY_SOCKS5 :
1071 protocol = kSecProtocolTypeSOCKS;
1072 break;
1073 default :
1074 LOG(LS_ERROR) << "asked for proxy password for unknown proxy type.";
1075 result = false;
1076 break;
1077 }
1078 attributes[0].data = &protocol;
1079
1080 UInt32 port = proxy->address.port();
1081 attributes[1].tag = kSecPortItemAttr;
1082 attributes[1].length = sizeof(UInt32);
1083 attributes[1].data = &port;
1084
1085 std::string ip = proxy->address.IPAsString();
1086 attributes[2].tag = kSecServerItemAttr;
1087 attributes[2].length = ip.length();
1088 attributes[2].data = const_cast<char*>(ip.c_str());
1089
1090 if (result) {
1091 LOG(LS_INFO) << "trying to get proxy username/password";
1092 SecKeychainSearchRef sref;
1093 oss = SecKeychainSearchCreateFromAttributes(NULL,
1094 kSecInternetPasswordItemClass,
1095 &attrList, &sref);
1096 if (0 == oss) {
1097 LOG(LS_INFO) << "SecKeychainSearchCreateFromAttributes was good";
1098 // Get the first item, if there is one.
1099 SecKeychainItemRef iref;
1100 oss = SecKeychainSearchCopyNext(sref, &iref);
1101 if (0 == oss) {
1102 LOG(LS_INFO) << "...looks like we have the username/password data";
1103 // If there is, get the username and the password.
1104
1105 SecKeychainAttributeInfo attribsToGet;
1106 attribsToGet.count = 1;
1107 UInt32 tag = kSecAccountItemAttr;
1108 UInt32 format = CSSM_DB_ATTRIBUTE_FORMAT_STRING;
1109 void *data;
1110 UInt32 length;
1111 SecKeychainAttributeList *localList;
1112
1113 attribsToGet.tag = &tag;
1114 attribsToGet.format = &format;
1115 OSStatus copyres = SecKeychainItemCopyAttributesAndData(iref,
1116 &attribsToGet,
1117 NULL,
1118 &localList,
1119 &length,
1120 &data);
1121 if (0 == copyres) {
1122 LOG(LS_INFO) << "...and we can pull it out.";
1123 // now, we know from experimentation (sadly not from docs)
1124 // that the username is in the local attribute list,
1125 // and the password in the data,
1126 // both without null termination but with info on their length.
1127 // grab the password from the data.
1128 std::string password;
1129 password.append(static_cast<const char*>(data), length);
1130
1131 // make the password into a CryptString
1132 // huh, at the time of writing, you can't.
1133 // so we'll skip that for now and come back to it later.
1134
1135 // now put the username in the proxy.
1136 if (1 <= localList->attr->length) {
1137 proxy->username.append(
1138 static_cast<const char*>(localList->attr->data),
1139 localList->attr->length);
1140 LOG(LS_INFO) << "username is " << proxy->username;
1141 } else {
1142 LOG(LS_ERROR) << "got keychain entry with no username";
1143 result = false;
1144 }
1145 } else {
1146 LOG(LS_ERROR) << "couldn't copy info from keychain.";
1147 result = false;
1148 }
1149 SecKeychainItemFreeAttributesAndData(localList, data);
1150 } else if (errSecItemNotFound == oss) {
1151 LOG(LS_INFO) << "...username/password info not found";
1152 } else {
1153 // oooh, neither 0 nor itemNotFound.
1154 LOG(LS_ERROR) << "Couldn't get keychain information, error code" << oss;
1155 result = false;
1156 }
1157 } else if (errSecItemNotFound == oss) { // noop
1158 } else {
1159 // oooh, neither 0 nor itemNotFound.
1160 LOG(LS_ERROR) << "Couldn't get keychain information, error code" << oss;
1161 result = false;
1162 }
1163 }
1164
1165 return result;
1166 }
1167
GetMacProxySettings(ProxyInfo * proxy)1168 bool GetMacProxySettings(ProxyInfo* proxy) {
1169 // based on the Apple Technical Q&A QA1234
1170 // http://developer.apple.com/qa/qa2001/qa1234.html
1171 CFDictionaryRef proxyDict = SCDynamicStoreCopyProxies(NULL);
1172 bool result = false;
1173
1174 if (proxyDict != NULL) {
1175 // sending it off to another function makes it easier to unit test
1176 // since we can make our own dictionary to hand to that function.
1177 result = GetMacProxySettingsFromDictionary(proxy, proxyDict);
1178
1179 if (result) {
1180 result = p_putPasswordInProxyInfo(proxy);
1181 }
1182
1183 // We created the dictionary with something that had the
1184 // word 'copy' in it, so we have to release it, according
1185 // to the Carbon memory management standards.
1186 CFRelease(proxyDict);
1187 } else {
1188 LOG(LS_ERROR) << "SCDynamicStoreCopyProxies failed";
1189 }
1190
1191 return result;
1192 }
1193 #endif // OSX
1194
AutoDetectProxySettings(const char * agent,const char * url,ProxyInfo * proxy)1195 bool AutoDetectProxySettings(const char* agent, const char* url,
1196 ProxyInfo* proxy) {
1197 #ifdef WIN32
1198 return WinHttpAutoDetectProxyForUrl(agent, url, proxy);
1199 #else
1200 LOG(LS_WARNING) << "Proxy auto-detection not implemented for this platform";
1201 return false;
1202 #endif
1203 }
1204
GetSystemDefaultProxySettings(const char * agent,const char * url,ProxyInfo * proxy)1205 bool GetSystemDefaultProxySettings(const char* agent, const char* url,
1206 ProxyInfo* proxy) {
1207 #ifdef WIN32
1208 return GetIeProxySettings(agent, url, proxy);
1209 #elif OSX
1210 return GetMacProxySettings(proxy);
1211 #else
1212 // TODO: Get System settings if browser is not firefox.
1213 return GetFirefoxProxySettings(url, proxy);
1214 #endif
1215 }
1216
GetProxySettingsForUrl(const char * agent,const char * url,ProxyInfo & proxy,bool long_operation)1217 bool GetProxySettingsForUrl(const char* agent, const char* url,
1218 ProxyInfo& proxy, bool long_operation) {
1219 UserAgent a = GetAgent(agent);
1220 bool result;
1221 switch (a) {
1222 case UA_FIREFOX: {
1223 result = GetFirefoxProxySettings(url, &proxy);
1224 break;
1225 }
1226 #ifdef WIN32
1227 case UA_INTERNETEXPLORER:
1228 result = GetIeProxySettings(agent, url, &proxy);
1229 break;
1230 case UA_UNKNOWN:
1231 // Agent not defined, check default browser.
1232 if (IsDefaultBrowserFirefox()) {
1233 result = GetFirefoxProxySettings(url, &proxy);
1234 } else {
1235 result = GetIeProxySettings(agent, url, &proxy);
1236 }
1237 break;
1238 #endif // WIN32
1239 default:
1240 result = GetSystemDefaultProxySettings(agent, url, &proxy);
1241 break;
1242 }
1243
1244 // TODO: Consider using the 'long_operation' parameter to
1245 // decide whether to do the auto detection.
1246 if (result && (proxy.autodetect ||
1247 !proxy.autoconfig_url.empty())) {
1248 // Use WinHTTP to auto detect proxy for us.
1249 result = AutoDetectProxySettings(agent, url, &proxy);
1250 if (!result) {
1251 // Either auto detection is not supported or we simply didn't
1252 // find any proxy, reset type.
1253 proxy.type = talk_base::PROXY_NONE;
1254 }
1255 }
1256 return result;
1257 }
1258
1259 } // namespace talk_base
1260