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
ResourceError(CFErrorRef cfError)41 ResourceError::ResourceError(CFErrorRef cfError)
42 : m_dataIsUpToDate(false)
43 , m_platformError(cfError)
44 {
45 m_isNull = !cfError;
46 }
47
48 #if PLATFORM(WIN)
ResourceError(const String & domain,int errorCode,const String & failingURL,const String & localizedDescription,CFDataRef certificate)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
certificate() const56 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
platformLazyInit()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
platformCopy(ResourceError & errorCopy) const115 void ResourceError::platformCopy(ResourceError& errorCopy) const
116 {
117 #if PLATFORM(WIN)
118 errorCopy.m_certificate = m_certificate;
119 #endif
120 }
121
platformCompare(const ResourceError & a,const ResourceError & b)122 bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b)
123 {
124 return a.cfError() == b.cfError();
125 }
126
cfError() const127 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
operator CFErrorRef() const161 ResourceError::operator CFErrorRef() const
162 {
163 return cfError();
164 }
165
166 // FIXME: Once <rdar://problem/5050841> is fixed we can remove this constructor.
ResourceError(CFStreamError error)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
cfStreamError() const186 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
operator CFStreamError() const205 ResourceError::operator CFStreamError() const
206 {
207 return cfStreamError();
208 }
209
210 } // namespace WebCore
211
212 #endif // USE(CFNETWORK)
213