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 "KURL.h"
     28 #include "ResourceError.h"
     29 
     30 #if USE(CFNETWORK)
     31 
     32 // FIXME: Once <rdar://problem/5050881> is fixed in open source we
     33 // can remove this extern "C"
     34 extern "C" {
     35 #include <CFNetwork/CFNetworkErrors.h>
     36 }
     37 
     38 #include <CoreFoundation/CFError.h>
     39 #include <WTF/RetainPtr.h>
     40 
     41 namespace WebCore {
     42 
     43 const CFStringRef failingURLStringKey = CFSTR("NSErrorFailingURLStringKey");
     44 const CFStringRef failingURLKey = CFSTR("NSErrorFailingURLKey");
     45 
     46 // FIXME: Once <rdar://problem/5050841> is fixed we can remove this constructor.
     47 ResourceError::ResourceError(CFStreamError error)
     48     : m_dataIsUpToDate(true)
     49 {
     50     m_isNull = false;
     51     m_errorCode = error.error;
     52 
     53     switch(error.domain) {
     54     case kCFStreamErrorDomainCustom:
     55         m_domain ="NSCustomErrorDomain";
     56         break;
     57     case kCFStreamErrorDomainPOSIX:
     58         m_domain = "NSPOSIXErrorDomain";
     59         break;
     60     case kCFStreamErrorDomainMacOSStatus:
     61         m_domain = "NSOSStatusErrorDomain";
     62         break;
     63     }
     64 }
     65 
     66 void ResourceError::platformLazyInit()
     67 {
     68     if (m_dataIsUpToDate)
     69         return;
     70 
     71     if (!m_platformError)
     72         return;
     73 
     74     CFStringRef domain = CFErrorGetDomain(m_platformError.get());
     75     if (domain == kCFErrorDomainMach || domain == kCFErrorDomainCocoa)
     76         m_domain ="NSCustomErrorDomain";
     77     else if (domain == kCFErrorDomainCFNetwork)
     78         m_domain = "CFURLErrorDomain";
     79     else if (domain == kCFErrorDomainPOSIX)
     80         m_domain = "NSPOSIXErrorDomain";
     81     else if (domain == kCFErrorDomainOSStatus)
     82         m_domain = "NSOSStatusErrorDomain";
     83     else if (domain == kCFErrorDomainWinSock)
     84         m_domain = "kCFErrorDomainWinSock";
     85 
     86     m_errorCode = CFErrorGetCode(m_platformError.get());
     87 
     88     RetainPtr<CFDictionaryRef> userInfo(AdoptCF, CFErrorCopyUserInfo(m_platformError.get()));
     89     if (userInfo.get()) {
     90         CFStringRef failingURLString = (CFStringRef) CFDictionaryGetValue(userInfo.get(), failingURLStringKey);
     91         if (failingURLString)
     92             m_failingURL = String(failingURLString);
     93         else {
     94             CFURLRef failingURL = (CFURLRef) CFDictionaryGetValue(userInfo.get(), failingURLKey);
     95             if (failingURL) {
     96                 RetainPtr<CFURLRef> absoluteURLRef(AdoptCF, CFURLCopyAbsoluteURL(failingURL));
     97                 if (absoluteURLRef.get()) {
     98                     failingURLString = CFURLGetString(absoluteURLRef.get());
     99                     m_failingURL = String(failingURLString);
    100                 }
    101             }
    102         }
    103         m_localizedDescription = (CFStringRef) CFDictionaryGetValue(userInfo.get(), kCFErrorLocalizedDescriptionKey);
    104     }
    105 
    106     m_dataIsUpToDate = true;
    107 }
    108 
    109 bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b)
    110 {
    111     return (CFErrorRef)a == (CFErrorRef)b;
    112 }
    113 
    114 ResourceError::operator CFErrorRef() const
    115 {
    116     if (m_isNull) {
    117         ASSERT(!m_platformError);
    118         return nil;
    119     }
    120 
    121     if (!m_platformError) {
    122         RetainPtr<CFMutableDictionaryRef> userInfo(AdoptCF, CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
    123 
    124         if (!m_localizedDescription.isEmpty()) {
    125             RetainPtr<CFStringRef> localizedDescriptionString(AdoptCF, m_localizedDescription.createCFString());
    126             CFDictionarySetValue(userInfo.get(), kCFErrorLocalizedDescriptionKey, localizedDescriptionString.get());
    127         }
    128 
    129         if (!m_failingURL.isEmpty()) {
    130             RetainPtr<CFStringRef> failingURLString(AdoptCF, m_failingURL.createCFString());
    131             CFDictionarySetValue(userInfo.get(), failingURLStringKey, failingURLString.get());
    132             RetainPtr<CFURLRef> url(AdoptCF, KURL(ParsedURLString, m_failingURL).createCFURL());
    133             CFDictionarySetValue(userInfo.get(), failingURLKey, url.get());
    134         }
    135 
    136         RetainPtr<CFStringRef> domainString(AdoptCF, m_domain.createCFString());
    137         m_platformError.adoptCF(CFErrorCreate(0, domainString.get(), m_errorCode, userInfo.get()));
    138     }
    139 
    140     return m_platformError.get();
    141 }
    142 
    143 ResourceError::operator CFStreamError() const
    144 {
    145     lazyInit();
    146 
    147     CFStreamError result;
    148     result.error = m_errorCode;
    149 
    150     if (m_domain == "NSCustomErrorDomain")
    151         result.domain = kCFStreamErrorDomainCustom;
    152     else if (m_domain == "NSPOSIXErrorDomain")
    153         result.domain = kCFStreamErrorDomainPOSIX;
    154     else if (m_domain == "NSOSStatusErrorDomain")
    155         result.domain = kCFStreamErrorDomainMacOSStatus;
    156     else
    157         ASSERT_NOT_REACHED();
    158 
    159     return result;
    160 }
    161 
    162 } // namespace WebCore
    163 
    164 #endif // USE(CFNETWORK)
    165