1 /* 2 * Copyright (C) 2007 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "ResourceError.h" 28 29 #if USE(CFNETWORK) 30 31 #include "KURL.h" 32 #include <CoreFoundation/CFError.h> 33 #include <CFNetwork/CFNetworkErrors.h> 34 #if PLATFORM(WIN) 35 #include <WebKitSystemInterface/WebKitSystemInterface.h> 36 #endif 37 #include <WTF/RetainPtr.h> 38 39 namespace WebCore { 40 41 ResourceError::ResourceError(CFErrorRef cfError) 42 : m_dataIsUpToDate(false) 43 , m_platformError(cfError) 44 { 45 m_isNull = !cfError; 46 } 47 48 #if PLATFORM(WIN) 49 ResourceError::ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription, CFDataRef certificate) 50 : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription) 51 , m_dataIsUpToDate(true) 52 , m_certificate(certificate) 53 { 54 } 55 56 PCCERT_CONTEXT ResourceError::certificate() const 57 { 58 if (!m_certificate) 59 return 0; 60 61 return reinterpret_cast<PCCERT_CONTEXT>(CFDataGetBytePtr(m_certificate.get())); 62 } 63 #endif // PLATFORM(WIN) 64 65 const CFStringRef failingURLStringKey = CFSTR("NSErrorFailingURLStringKey"); 66 const CFStringRef failingURLKey = CFSTR("NSErrorFailingURLKey"); 67 68 void ResourceError::platformLazyInit() 69 { 70 if (m_dataIsUpToDate) 71 return; 72 73 if (!m_platformError) 74 return; 75 76 CFStringRef domain = CFErrorGetDomain(m_platformError.get()); 77 if (domain == kCFErrorDomainMach || domain == kCFErrorDomainCocoa) 78 m_domain ="NSCustomErrorDomain"; 79 else if (domain == kCFErrorDomainCFNetwork) 80 m_domain = "CFURLErrorDomain"; 81 else if (domain == kCFErrorDomainPOSIX) 82 m_domain = "NSPOSIXErrorDomain"; 83 else if (domain == kCFErrorDomainOSStatus) 84 m_domain = "NSOSStatusErrorDomain"; 85 else if (domain == kCFErrorDomainWinSock) 86 m_domain = "kCFErrorDomainWinSock"; 87 88 m_errorCode = CFErrorGetCode(m_platformError.get()); 89 90 RetainPtr<CFDictionaryRef> userInfo(AdoptCF, CFErrorCopyUserInfo(m_platformError.get())); 91 if (userInfo.get()) { 92 CFStringRef failingURLString = (CFStringRef) CFDictionaryGetValue(userInfo.get(), failingURLStringKey); 93 if (failingURLString) 94 m_failingURL = String(failingURLString); 95 else { 96 CFURLRef failingURL = (CFURLRef) CFDictionaryGetValue(userInfo.get(), failingURLKey); 97 if (failingURL) { 98 RetainPtr<CFURLRef> absoluteURLRef(AdoptCF, CFURLCopyAbsoluteURL(failingURL)); 99 if (absoluteURLRef.get()) { 100 failingURLString = CFURLGetString(absoluteURLRef.get()); 101 m_failingURL = String(failingURLString); 102 } 103 } 104 } 105 m_localizedDescription = (CFStringRef) CFDictionaryGetValue(userInfo.get(), kCFErrorLocalizedDescriptionKey); 106 107 #if PLATFORM(WIN) 108 m_certificate = wkGetSSLPeerCertificateData(userInfo.get()); 109 #endif 110 } 111 112 m_dataIsUpToDate = true; 113 } 114 115 void ResourceError::platformCopy(ResourceError& errorCopy) const 116 { 117 #if PLATFORM(WIN) 118 errorCopy.m_certificate = m_certificate; 119 #endif 120 } 121 122 bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b) 123 { 124 return a.cfError() == b.cfError(); 125 } 126 127 CFErrorRef ResourceError::cfError() const 128 { 129 if (m_isNull) { 130 ASSERT(!m_platformError); 131 return 0; 132 } 133 134 if (!m_platformError) { 135 RetainPtr<CFMutableDictionaryRef> userInfo(AdoptCF, CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); 136 137 if (!m_localizedDescription.isEmpty()) { 138 RetainPtr<CFStringRef> localizedDescriptionString(AdoptCF, m_localizedDescription.createCFString()); 139 CFDictionarySetValue(userInfo.get(), kCFErrorLocalizedDescriptionKey, localizedDescriptionString.get()); 140 } 141 142 if (!m_failingURL.isEmpty()) { 143 RetainPtr<CFStringRef> failingURLString(AdoptCF, m_failingURL.createCFString()); 144 CFDictionarySetValue(userInfo.get(), failingURLStringKey, failingURLString.get()); 145 RetainPtr<CFURLRef> url(AdoptCF, KURL(ParsedURLString, m_failingURL).createCFURL()); 146 CFDictionarySetValue(userInfo.get(), failingURLKey, url.get()); 147 } 148 149 #if PLATFORM(WIN) 150 if (m_certificate) 151 wkSetSSLPeerCertificateData(userInfo.get(), m_certificate.get()); 152 #endif 153 154 RetainPtr<CFStringRef> domainString(AdoptCF, m_domain.createCFString()); 155 m_platformError.adoptCF(CFErrorCreate(0, domainString.get(), m_errorCode, userInfo.get())); 156 } 157 158 return m_platformError.get(); 159 } 160 161 ResourceError::operator CFErrorRef() const 162 { 163 return cfError(); 164 } 165 166 // FIXME: Once <rdar://problem/5050841> is fixed we can remove this constructor. 167 ResourceError::ResourceError(CFStreamError error) 168 : m_dataIsUpToDate(true) 169 { 170 m_isNull = false; 171 m_errorCode = error.error; 172 173 switch(error.domain) { 174 case kCFStreamErrorDomainCustom: 175 m_domain ="NSCustomErrorDomain"; 176 break; 177 case kCFStreamErrorDomainPOSIX: 178 m_domain = "NSPOSIXErrorDomain"; 179 break; 180 case kCFStreamErrorDomainMacOSStatus: 181 m_domain = "NSOSStatusErrorDomain"; 182 break; 183 } 184 } 185 186 CFStreamError ResourceError::cfStreamError() const 187 { 188 lazyInit(); 189 190 CFStreamError result; 191 result.error = m_errorCode; 192 193 if (m_domain == "NSCustomErrorDomain") 194 result.domain = kCFStreamErrorDomainCustom; 195 else if (m_domain == "NSPOSIXErrorDomain") 196 result.domain = kCFStreamErrorDomainPOSIX; 197 else if (m_domain == "NSOSStatusErrorDomain") 198 result.domain = kCFStreamErrorDomainMacOSStatus; 199 else 200 ASSERT_NOT_REACHED(); 201 202 return result; 203 } 204 205 ResourceError::operator CFStreamError() const 206 { 207 return cfStreamError(); 208 } 209 210 } // namespace WebCore 211 212 #endif // USE(CFNETWORK) 213