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 "DefaultPolicyDelegate.h"
29
30#include <WebCore/BString.h>
31#include <WebCore/COMPtr.h>
32#include <wtf/text/WTFString.h>
33
34using namespace WebCore;
35
36// FIXME: move this enum to a separate header file when other code begins to use it.
37typedef enum WebExtraNavigationType {
38    WebNavigationTypePlugInRequest = WebNavigationTypeOther + 1
39} WebExtraNavigationType;
40
41// DefaultPolicyDelegate ----------------------------------------------------------------
42
43DefaultPolicyDelegate::DefaultPolicyDelegate()
44    : m_refCount(0)
45{
46    gClassCount++;
47    gClassNameCount.add("DefaultPolicyDelegate");
48}
49
50DefaultPolicyDelegate::~DefaultPolicyDelegate()
51{
52    gClassCount--;
53    gClassNameCount.remove("DefaultPolicyDelegate");
54}
55
56DefaultPolicyDelegate* DefaultPolicyDelegate::sharedInstance()
57{
58    static COMPtr<DefaultPolicyDelegate> shared;
59    if (!shared)
60        shared.adoptRef(DefaultPolicyDelegate::createInstance());
61    return shared.get();
62}
63
64DefaultPolicyDelegate* DefaultPolicyDelegate::createInstance()
65{
66    DefaultPolicyDelegate* instance = new DefaultPolicyDelegate();
67    instance->AddRef();
68    return instance;
69}
70
71// IUnknown -------------------------------------------------------------------
72
73HRESULT STDMETHODCALLTYPE DefaultPolicyDelegate::QueryInterface(REFIID riid, void** ppvObject)
74{
75    *ppvObject = 0;
76    if (IsEqualGUID(riid, IID_IUnknown))
77        *ppvObject = static_cast<IUnknown*>(this);
78    else if (IsEqualGUID(riid, IID_IWebPolicyDelegate))
79        *ppvObject = static_cast<IWebPolicyDelegate*>(this);
80    else
81        return E_NOINTERFACE;
82
83    AddRef();
84    return S_OK;
85}
86
87ULONG STDMETHODCALLTYPE DefaultPolicyDelegate::AddRef()
88{
89    return ++m_refCount;
90}
91
92ULONG STDMETHODCALLTYPE DefaultPolicyDelegate::Release()
93{
94    ULONG newRef = --m_refCount;
95    if (!newRef)
96        delete(this);
97
98    return newRef;
99}
100
101HRESULT STDMETHODCALLTYPE DefaultPolicyDelegate::decidePolicyForNavigationAction(
102    /*[in]*/ IWebView* webView,
103    /*[in]*/ IPropertyBag* actionInformation,
104    /*[in]*/ IWebURLRequest* request,
105    /*[in]*/ IWebFrame* /*frame*/,
106    /*[in]*/ IWebPolicyDecisionListener* listener)
107{
108    int navType = 0;
109    VARIANT var;
110    if (SUCCEEDED(actionInformation->Read(WebActionNavigationTypeKey, &var, 0))) {
111        V_VT(&var) = VT_I4;
112        navType = V_I4(&var);
113    }
114    COMPtr<IWebViewPrivate> wvPrivate(Query, webView);
115    if (wvPrivate) {
116        BOOL canHandleRequest = FALSE;
117        if (SUCCEEDED(wvPrivate->canHandleRequest(request, &canHandleRequest)) && canHandleRequest)
118            listener->use();
119        else if (navType == WebNavigationTypePlugInRequest)
120            listener->use();
121        else {
122            BString url;
123            // A file URL shouldn't fall through to here, but if it did,
124            // it would be a security risk to open it.
125            if (SUCCEEDED(request->URL(&url)) && !String(url, SysStringLen(url)).startsWith("file:")) {
126                // FIXME: Open the URL not by means of a webframe, but by handing it over to the system and letting it determine how to open that particular URL scheme.  See documentation for [NSWorkspace openURL]
127                ;
128            }
129            listener->ignore();
130        }
131    }
132    return S_OK;
133}
134
135HRESULT STDMETHODCALLTYPE DefaultPolicyDelegate::decidePolicyForNewWindowAction(
136    /*[in]*/ IWebView* /*webView*/,
137    /*[in]*/ IPropertyBag* /*actionInformation*/,
138    /*[in]*/ IWebURLRequest* /*request*/,
139    /*[in]*/ BSTR /*frameName*/,
140    /*[in]*/ IWebPolicyDecisionListener* listener)
141{
142    listener->use();
143    return S_OK;
144}
145
146HRESULT STDMETHODCALLTYPE DefaultPolicyDelegate::decidePolicyForMIMEType(
147    /*[in]*/ IWebView* webView,
148    /*[in]*/ BSTR type,
149    /*[in]*/ IWebURLRequest* request,
150    /*[in]*/ IWebFrame* /*frame*/,
151    /*[in]*/ IWebPolicyDecisionListener* listener)
152{
153    BOOL canShowMIMEType;
154    if (FAILED(webView->canShowMIMEType(type, &canShowMIMEType)))
155        canShowMIMEType = FALSE;
156
157    BString url;
158    request->URL(&url);
159
160    if (String(url, SysStringLen(url)).startsWith("file:")) {
161        BOOL isDirectory = FALSE;
162        WIN32_FILE_ATTRIBUTE_DATA attrs;
163        if (GetFileAttributesEx(url, GetFileExInfoStandard, &attrs))
164            isDirectory = !!(attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
165
166        if (isDirectory)
167            listener->ignore();
168        else if(canShowMIMEType)
169            listener->use();
170        else
171            listener->ignore();
172    } else if (canShowMIMEType)
173        listener->use();
174    else
175        listener->ignore();
176    return S_OK;
177}
178
179HRESULT STDMETHODCALLTYPE DefaultPolicyDelegate::unableToImplementPolicyWithError(
180    /*[in]*/ IWebView* /*webView*/,
181    /*[in]*/ IWebError* error,
182    /*[in]*/ IWebFrame* frame)
183{
184    BString errorStr;
185    error->localizedDescription(&errorStr);
186
187    BString frameName;
188    frame->name(&frameName);
189
190    LOG_ERROR("called unableToImplementPolicyWithError:%S inFrame:%S", errorStr ? errorStr : TEXT(""), frameName ? frameName : TEXT(""));
191
192    return S_OK;
193}
194