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 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 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 "URL.h" 32#include <CoreFoundation/CFError.h> 33#include <CFNetwork/CFNetworkErrors.h> 34#include <wtf/RetainPtr.h> 35 36#if PLATFORM(WIN) 37#include <WebKitSystemInterface/WebKitSystemInterface.h> 38#endif 39 40namespace WebCore { 41 42ResourceError::ResourceError(CFErrorRef cfError) 43 : m_dataIsUpToDate(false) 44 , m_platformError(cfError) 45{ 46 m_isNull = !cfError; 47 if (!m_isNull) 48 m_isTimeout = CFErrorGetCode(m_platformError.get()) == kCFURLErrorTimedOut; 49} 50 51#if PLATFORM(WIN) 52ResourceError::ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription, CFDataRef certificate) 53 : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription) 54 , m_dataIsUpToDate(true) 55 , m_certificate(certificate) 56{ 57} 58 59PCCERT_CONTEXT ResourceError::certificate() const 60{ 61 if (!m_certificate) 62 return 0; 63 64 return reinterpret_cast<PCCERT_CONTEXT>(CFDataGetBytePtr(m_certificate.get())); 65} 66 67void ResourceError::setCertificate(CFDataRef certificate) 68{ 69 m_certificate = certificate; 70} 71#endif // PLATFORM(WIN) 72 73const CFStringRef failingURLStringKey = CFSTR("NSErrorFailingURLStringKey"); 74const CFStringRef failingURLKey = CFSTR("NSErrorFailingURLKey"); 75 76void ResourceError::platformLazyInit() 77{ 78 if (m_dataIsUpToDate) 79 return; 80 81 if (!m_platformError) 82 return; 83 84 CFStringRef domain = CFErrorGetDomain(m_platformError.get()); 85 if (domain == kCFErrorDomainMach || domain == kCFErrorDomainCocoa) 86 m_domain ="NSCustomErrorDomain"; 87 else if (domain == kCFErrorDomainCFNetwork) 88 m_domain = "CFURLErrorDomain"; 89 else if (domain == kCFErrorDomainPOSIX) 90 m_domain = "NSPOSIXErrorDomain"; 91 else if (domain == kCFErrorDomainOSStatus) 92 m_domain = "NSOSStatusErrorDomain"; 93 else if (domain == kCFErrorDomainWinSock) 94 m_domain = "kCFErrorDomainWinSock"; 95 else 96 m_domain = domain; 97 98 m_errorCode = CFErrorGetCode(m_platformError.get()); 99 100 RetainPtr<CFDictionaryRef> userInfo = adoptCF(CFErrorCopyUserInfo(m_platformError.get())); 101 if (userInfo.get()) { 102 CFStringRef failingURLString = (CFStringRef) CFDictionaryGetValue(userInfo.get(), failingURLStringKey); 103 if (failingURLString) 104 m_failingURL = String(failingURLString); 105 else { 106 CFURLRef failingURL = (CFURLRef) CFDictionaryGetValue(userInfo.get(), failingURLKey); 107 if (failingURL) { 108 RetainPtr<CFURLRef> absoluteURLRef = adoptCF(CFURLCopyAbsoluteURL(failingURL)); 109 if (absoluteURLRef.get()) { 110 // FIXME: CFURLGetString returns a normalized URL which is different from what is actually used by CFNetwork. 111 // We should use CFURLGetBytes instead. 112 failingURLString = CFURLGetString(absoluteURLRef.get()); 113 m_failingURL = String(failingURLString); 114 } 115 } 116 } 117 m_localizedDescription = (CFStringRef) CFDictionaryGetValue(userInfo.get(), kCFErrorLocalizedDescriptionKey); 118 119#if PLATFORM(WIN) 120 m_certificate = wkGetSSLPeerCertificateData(userInfo.get()); 121#endif 122 } 123 124 m_dataIsUpToDate = true; 125} 126 127void ResourceError::platformCopy(ResourceError& errorCopy) const 128{ 129#if PLATFORM(WIN) 130 errorCopy.m_certificate = m_certificate; 131#else 132 UNUSED_PARAM(errorCopy); 133#endif 134} 135 136bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b) 137{ 138 return a.cfError() == b.cfError(); 139} 140 141CFErrorRef ResourceError::cfError() const 142{ 143 if (m_isNull) { 144 ASSERT(!m_platformError); 145 return 0; 146 } 147 148 if (!m_platformError) { 149 RetainPtr<CFMutableDictionaryRef> userInfo = adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); 150 151 if (!m_localizedDescription.isEmpty()) 152 CFDictionarySetValue(userInfo.get(), kCFErrorLocalizedDescriptionKey, m_localizedDescription.createCFString().get()); 153 154 if (!m_failingURL.isEmpty()) { 155 RetainPtr<CFStringRef> failingURLString = m_failingURL.createCFString(); 156 CFDictionarySetValue(userInfo.get(), failingURLStringKey, failingURLString.get()); 157 RetainPtr<CFURLRef> url = adoptCF(CFURLCreateWithString(0, failingURLString.get(), 0)); 158 CFDictionarySetValue(userInfo.get(), failingURLKey, url.get()); 159 } 160 161#if PLATFORM(WIN) 162 if (m_certificate) 163 wkSetSSLPeerCertificateData(userInfo.get(), m_certificate.get()); 164#endif 165 166 m_platformError = adoptCF(CFErrorCreate(0, m_domain.createCFString().get(), m_errorCode, userInfo.get())); 167 } 168 169 return m_platformError.get(); 170} 171 172ResourceError::operator CFErrorRef() const 173{ 174 return cfError(); 175} 176 177// FIXME: Once <rdar://problem/5050841> is fixed we can remove this constructor. 178ResourceError::ResourceError(CFStreamError error) 179 : m_dataIsUpToDate(true) 180{ 181 m_isNull = false; 182 m_errorCode = error.error; 183 184 switch(error.domain) { 185 case kCFStreamErrorDomainCustom: 186 m_domain ="NSCustomErrorDomain"; 187 break; 188 case kCFStreamErrorDomainPOSIX: 189 m_domain = "NSPOSIXErrorDomain"; 190 break; 191 case kCFStreamErrorDomainMacOSStatus: 192 m_domain = "NSOSStatusErrorDomain"; 193 break; 194 } 195} 196 197CFStreamError ResourceError::cfStreamError() const 198{ 199 lazyInit(); 200 201 CFStreamError result; 202 result.error = m_errorCode; 203 204 if (m_domain == "NSCustomErrorDomain") 205 result.domain = kCFStreamErrorDomainCustom; 206 else if (m_domain == "NSPOSIXErrorDomain") 207 result.domain = kCFStreamErrorDomainPOSIX; 208 else if (m_domain == "NSOSStatusErrorDomain") 209 result.domain = kCFStreamErrorDomainMacOSStatus; 210 else { 211 result.domain = kCFStreamErrorDomainCustom; 212 ASSERT_NOT_REACHED(); 213 } 214 215 return result; 216} 217 218ResourceError::operator CFStreamError() const 219{ 220 return cfStreamError(); 221} 222 223} // namespace WebCore 224 225#endif // USE(CFNETWORK) 226