Home | History | Annotate | Download | only in cf
      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