1/* 2 * Copyright (C) 2008 Collin Jackson <collinj@webkit.org> 3 * Copyright (C) 2009 Apple Inc. All Rights Reserved. 4 * Copyright (C) 2012 Igalia S.L. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "config.h" 29#include "DNS.h" 30#include "DNSResolveQueue.h" 31 32#include "URL.h" 33#include "Timer.h" 34#include <wtf/HashSet.h> 35#include <wtf/MainThread.h> 36#include <wtf/RetainPtr.h> 37#include <wtf/StdLibExtras.h> 38#include <wtf/text/StringHash.h> 39 40#if PLATFORM(IOS) 41#include <CFNetwork/CFNetwork.h> 42#endif 43 44#if PLATFORM(WIN) 45#include "LoaderRunLoopCF.h" 46#include <CFNetwork/CFNetwork.h> 47#endif 48 49namespace WebCore { 50 51bool DNSResolveQueue::platformProxyIsEnabledInSystemPreferences() 52{ 53 // Don't do DNS prefetch if proxies are involved. For many proxy types, the user agent is never exposed 54 // to the IP address during normal operation. Querying an internal DNS server may not help performance, 55 // as it doesn't necessarily look up the actual external IP. Also, if DNS returns a fake internal address, 56 // local caches may keep it even after re-connecting to another network. 57 58 RetainPtr<CFDictionaryRef> proxySettings = adoptCF(CFNetworkCopySystemProxySettings()); 59 if (!proxySettings) 60 return false; 61 62 RetainPtr<CFURLRef> httpCFURL = URL(ParsedURLString, "http://example.com/").createCFURL(); 63 RetainPtr<CFURLRef> httpsCFURL = URL(ParsedURLString, "https://example.com/").createCFURL(); 64 65 RetainPtr<CFArrayRef> httpProxyArray = adoptCF(CFNetworkCopyProxiesForURL(httpCFURL.get(), proxySettings.get())); 66 RetainPtr<CFArrayRef> httpsProxyArray = adoptCF(CFNetworkCopyProxiesForURL(httpsCFURL.get(), proxySettings.get())); 67 68 CFIndex httpProxyCount = CFArrayGetCount(httpProxyArray.get()); 69 CFIndex httpsProxyCount = CFArrayGetCount(httpsProxyArray.get()); 70 if (httpProxyCount == 1 && CFEqual(CFDictionaryGetValue(static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(httpProxyArray.get(), 0)), kCFProxyTypeKey), kCFProxyTypeNone)) 71 httpProxyCount = 0; 72 if (httpsProxyCount == 1 && CFEqual(CFDictionaryGetValue(static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(httpsProxyArray.get(), 0)), kCFProxyTypeKey), kCFProxyTypeNone)) 73 httpsProxyCount = 0; 74 75 return httpProxyCount || httpsProxyCount; 76} 77 78static void clientCallback(CFHostRef theHost, CFHostInfoType, const CFStreamError*, void*) 79{ 80 DNSResolveQueue::shared().decrementRequestCount(); // It's ok to call shared() from a secondary thread, the static variable has already been initialized by now. 81 CFRelease(theHost); 82} 83 84void DNSResolveQueue::platformResolve(const String& hostname) 85{ 86 ASSERT(isMainThread()); 87 88 RetainPtr<CFHostRef> host = adoptCF(CFHostCreateWithName(0, hostname.createCFString().get())); 89 if (!host) { 90 decrementRequestCount(); 91 return; 92 } 93 94 CFHostClientContext context = { 0, 0, 0, 0, 0 }; 95 CFHostRef leakedHost = host.leakRef(); // The host will be released from clientCallback(). 96 Boolean result = CFHostSetClient(leakedHost, clientCallback, &context); 97 ASSERT_UNUSED(result, result); 98#if !PLATFORM(WIN) 99 CFHostScheduleWithRunLoop(leakedHost, CFRunLoopGetMain(), kCFRunLoopCommonModes); 100#else 101 // On Windows, we run a separate thread with CFRunLoop, which is where clientCallback will be called. 102 CFHostScheduleWithRunLoop(leakedHost, loaderRunLoop(), kCFRunLoopDefaultMode); 103#endif 104 CFHostStartInfoResolution(leakedHost, kCFHostAddresses, 0); 105} 106 107void prefetchDNS(const String& hostname) 108{ 109 ASSERT(isMainThread()); 110 if (hostname.isEmpty()) 111 return; 112 DNSResolveQueue::shared().add(hostname); 113} 114 115} 116