7cbfd065266cc926d28ca01bdd522a2142f77e81
[WebKit-https.git] / Source / WebCore / platform / network / cf / ResourceErrorCF.cpp
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(CFURLCONNECTION)
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
40 namespace WebCore {
41
42 ResourceError::ResourceError(CFErrorRef cfError)
43     : ResourceErrorBase(Type::Null)
44     , m_dataIsUpToDate(false)
45     , m_platformError(cfError)
46 {
47     if (cfError)
48         setType((CFErrorGetCode(m_platformError.get()) == kCFURLErrorTimedOut) ? Type::Timeout : Type::General);
49 }
50
51 #if PLATFORM(WIN)
52 ResourceError::ResourceError(const String& domain, int errorCode, const URL& failingURL, const String& localizedDescription, CFDataRef certificate)
53     : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription, Type::General)
54     , m_dataIsUpToDate(true)
55     , m_certificate(certificate)
56 {
57 }
58
59 PCCERT_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
67 void ResourceError::setCertificate(CFDataRef certificate)
68 {
69     m_certificate = certificate;
70 }
71 #endif // PLATFORM(WIN)
72
73 const CFStringRef failingURLStringKey = CFSTR("NSErrorFailingURLStringKey");
74 const CFStringRef failingURLKey = CFSTR("NSErrorFailingURLKey");
75
76 void 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 = URL(URL(), failingURLString);
105         else {
106             CFURLRef failingURL = (CFURLRef) CFDictionaryGetValue(userInfo.get(), failingURLKey);
107             if (failingURL) {
108                 if (RetainPtr<CFURLRef> absoluteURLRef = adoptCF(CFURLCopyAbsoluteURL(failingURL)))
109                     m_failingURL = URL(absoluteURLRef.get());
110             }
111         }
112         m_localizedDescription = (CFStringRef) CFDictionaryGetValue(userInfo.get(), kCFErrorLocalizedDescriptionKey);
113         
114 #if PLATFORM(WIN)
115         m_certificate = wkGetSSLPeerCertificateData(userInfo.get());
116 #endif
117     }
118
119     m_dataIsUpToDate = true;
120 }
121
122
123 void ResourceError::doPlatformIsolatedCopy(const ResourceError& other)
124 {
125 #if PLATFORM(WIN)
126     m_certificate = other.m_certificate;
127 #else
128     UNUSED_PARAM(other);
129 #endif
130 }
131
132 bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b)
133 {
134     return a.cfError() == b.cfError();
135 }
136
137 CFErrorRef ResourceError::cfError() const
138 {
139     if (isNull()) {
140         ASSERT(!m_platformError);
141         return 0;
142     }
143
144     if (!m_platformError) {
145         RetainPtr<CFMutableDictionaryRef> userInfo = adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
146
147         if (!m_localizedDescription.isEmpty())
148             CFDictionarySetValue(userInfo.get(), kCFErrorLocalizedDescriptionKey, m_localizedDescription.createCFString().get());
149
150         if (!m_failingURL.isEmpty()) {
151             RetainPtr<CFStringRef> failingURLString = m_failingURL.string().createCFString();
152             CFDictionarySetValue(userInfo.get(), failingURLStringKey, failingURLString.get());
153             if (RetainPtr<CFURLRef> url = m_failingURL.createCFURL())
154                 CFDictionarySetValue(userInfo.get(), failingURLKey, url.get());
155         }
156
157 #if PLATFORM(WIN)
158         if (m_certificate)
159             wkSetSSLPeerCertificateData(userInfo.get(), m_certificate.get());
160 #endif
161         
162         m_platformError = adoptCF(CFErrorCreate(0, m_domain.createCFString().get(), m_errorCode, userInfo.get()));
163     }
164
165     return m_platformError.get();
166 }
167
168 ResourceError::operator CFErrorRef() const
169 {
170     return cfError();
171 }
172
173 // FIXME: Once <rdar://problem/5050841> is fixed we can remove this constructor.
174 ResourceError::ResourceError(CFStreamError error)
175     : ResourceErrorBase(Type::General)
176     , m_dataIsUpToDate(true)
177 {
178     m_errorCode = error.error;
179
180     switch(error.domain) {
181     case kCFStreamErrorDomainCustom:
182         m_domain ="NSCustomErrorDomain";
183         break;
184     case kCFStreamErrorDomainPOSIX:
185         m_domain = "NSPOSIXErrorDomain";
186         break;
187     case kCFStreamErrorDomainMacOSStatus:
188         m_domain = "NSOSStatusErrorDomain";
189         break;
190     }
191 }
192
193 CFStreamError ResourceError::cfStreamError() const
194 {
195     lazyInit();
196
197     CFStreamError result;
198     result.error = m_errorCode;
199
200     if (m_domain == "NSCustomErrorDomain")
201         result.domain = kCFStreamErrorDomainCustom;
202     else if (m_domain == "NSPOSIXErrorDomain")
203         result.domain = kCFStreamErrorDomainPOSIX;
204     else if (m_domain == "NSOSStatusErrorDomain")
205         result.domain = kCFStreamErrorDomainMacOSStatus;
206     else {
207         result.domain = kCFStreamErrorDomainCustom;
208         ASSERT_NOT_REACHED();
209     }
210
211     return result;
212 }
213
214 ResourceError::operator CFStreamError() const
215 {
216     return cfStreamError();
217 }
218
219 } // namespace WebCore
220
221 #endif // USE(CFURLCONNECTION)