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 "WebKitDLL.h"
28#include "WebError.h"
29#include "WebKit.h"
30
31#include <WebCore/BString.h>
32
33#if USE(CFNETWORK)
34#include <WebKitSystemInterface/WebKitSystemInterface.h>
35#endif
36
37using namespace WebCore;
38
39// WebError ---------------------------------------------------------------------
40
41WebError::WebError(const ResourceError& error, IPropertyBag* userInfo)
42    : m_refCount(0)
43    , m_error(error)
44    , m_userInfo(userInfo)
45{
46    gClassCount++;
47    gClassNameCount.add("WebError");
48}
49
50WebError::~WebError()
51{
52    gClassCount--;
53    gClassNameCount.remove("WebError");
54}
55
56WebError* WebError::createInstance(const ResourceError& error, IPropertyBag* userInfo)
57{
58    WebError* instance = new WebError(error, userInfo);
59    instance->AddRef();
60    return instance;
61}
62
63WebError* WebError::createInstance()
64{
65    return createInstance(ResourceError());
66}
67
68// IUnknown -------------------------------------------------------------------
69
70HRESULT STDMETHODCALLTYPE WebError::QueryInterface(REFIID riid, void** ppvObject)
71{
72    *ppvObject = 0;
73    if (IsEqualGUID(riid, IID_IUnknown))
74        *ppvObject = static_cast<IWebError*>(this);
75    else if (IsEqualGUID(riid, CLSID_WebError))
76        *ppvObject = static_cast<WebError*>(this);
77    else if (IsEqualGUID(riid, IID_IWebError))
78        *ppvObject = static_cast<IWebError*>(this);
79    else if (IsEqualGUID(riid, IID_IWebErrorPrivate))
80        *ppvObject = static_cast<IWebErrorPrivate*>(this);
81    else
82        return E_NOINTERFACE;
83
84    AddRef();
85    return S_OK;
86}
87
88ULONG STDMETHODCALLTYPE WebError::AddRef(void)
89{
90    return ++m_refCount;
91}
92
93ULONG STDMETHODCALLTYPE WebError::Release(void)
94{
95    ULONG newRef = --m_refCount;
96    if (!newRef)
97        delete(this);
98
99    return newRef;
100}
101
102// IWebError ------------------------------------------------------------------
103
104HRESULT STDMETHODCALLTYPE WebError::init(
105    /* [in] */ BSTR domain,
106    /* [in] */ int code,
107    /* [in] */ BSTR url)
108{
109    m_error = ResourceError(String(domain, SysStringLen(domain)), code, String(url, SysStringLen(url)), String());
110    return S_OK;
111}
112
113HRESULT STDMETHODCALLTYPE WebError::code(
114    /* [retval][out] */ int* result)
115{
116    *result = m_error.errorCode();
117    return S_OK;
118}
119
120HRESULT STDMETHODCALLTYPE WebError::domain(
121    /* [retval][out] */ BSTR* result)
122{
123    if (!result)
124        return E_POINTER;
125
126    *result = BString(m_error.domain()).release();
127    return S_OK;
128}
129
130HRESULT STDMETHODCALLTYPE WebError::localizedDescription(
131    /* [retval][out] */ BSTR* result)
132{
133    if (!result)
134        return E_POINTER;
135
136    *result = BString(m_error.localizedDescription()).release();
137
138#if USE(CFNETWORK)
139    if (!*result) {
140        if (int code = m_error.errorCode())
141            *result = BString(wkCFNetworkErrorGetLocalizedDescription(code)).release();
142    }
143#endif
144
145    return S_OK;
146}
147
148
149HRESULT STDMETHODCALLTYPE WebError::localizedFailureReason(
150    /* [retval][out] */ BSTR* /*result*/)
151{
152    ASSERT_NOT_REACHED();
153    return E_NOTIMPL;
154}
155
156HRESULT STDMETHODCALLTYPE WebError::localizedRecoveryOptions(
157    /* [retval][out] */ IEnumVARIANT** /*result*/)
158{
159    ASSERT_NOT_REACHED();
160    return E_NOTIMPL;
161}
162
163HRESULT STDMETHODCALLTYPE WebError::localizedRecoverySuggestion(
164    /* [retval][out] */ BSTR* /*result*/)
165{
166    ASSERT_NOT_REACHED();
167    return E_NOTIMPL;
168}
169
170HRESULT STDMETHODCALLTYPE WebError::recoverAttempter(
171    /* [retval][out] */ IUnknown** /*result*/)
172{
173    ASSERT_NOT_REACHED();
174    return E_NOTIMPL;
175}
176
177HRESULT STDMETHODCALLTYPE WebError::userInfo(
178    /* [retval][out] */ IPropertyBag** result)
179{
180    if (!result)
181        return E_POINTER;
182    *result = 0;
183
184    if (!m_userInfo)
185        return E_FAIL;
186
187    return m_userInfo.copyRefTo(result);
188}
189
190HRESULT STDMETHODCALLTYPE WebError::failingURL(
191    /* [retval][out] */ BSTR* result)
192{
193    if (!result)
194        return E_POINTER;
195
196    *result = BString(m_error.failingURL()).release();
197    return S_OK;
198}
199
200HRESULT STDMETHODCALLTYPE WebError::isPolicyChangeError(
201    /* [retval][out] */ BOOL *result)
202{
203    if (!result)
204        return E_POINTER;
205
206    *result = m_error.domain() == String(WebKitErrorDomain)
207        && m_error.errorCode() == WebKitErrorFrameLoadInterruptedByPolicyChange;
208    return S_OK;
209}
210
211HRESULT WebError::sslPeerCertificate(/* [retval][out] */ ULONG_PTR* result)
212{
213    if (!result)
214        return E_POINTER;
215    *result = 0;
216
217#if USE(CFNETWORK)
218    if (!m_cfErrorUserInfoDict) {
219        // copy userinfo from CFErrorRef
220        CFErrorRef cfError = m_error;
221        m_cfErrorUserInfoDict = adoptCF(CFErrorCopyUserInfo(cfError));
222    }
223
224    if (!m_cfErrorUserInfoDict)
225        return E_FAIL;
226
227    void* data = wkGetSSLPeerCertificateDataBytePtr(m_cfErrorUserInfoDict.get());
228    if (!data)
229        return E_FAIL;
230    *result = reinterpret_cast<ULONG_PTR>(data);
231#endif
232    return *result ? S_OK : E_FAIL;
233}
234
235const ResourceError& WebError::resourceError() const
236{
237    return m_error;
238}
239