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