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