1/*
2 * Copyright (C) 2009 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 "HistoryDelegate.h"
28
29#include "DumpRenderTree.h"
30#include "DumpRenderTreeWin.h"
31#include "LayoutTestController.h"
32#include <string>
33#include <WebKit/WebKit.h>
34
35using std::wstring;
36
37static inline wstring wstringFromBSTR(BSTR str)
38{
39    return wstring(str, ::SysStringLen(str));
40}
41
42HistoryDelegate::HistoryDelegate()
43    : m_refCount(1)
44{
45}
46
47HistoryDelegate::~HistoryDelegate()
48{
49}
50
51    // IUnknown
52HRESULT HistoryDelegate::QueryInterface(REFIID riid, void** ppvObject)
53{
54    *ppvObject = 0;
55    if (IsEqualGUID(riid, IID_IUnknown))
56        *ppvObject = static_cast<IWebHistoryDelegate*>(this);
57    else if (IsEqualGUID(riid, IID_IWebHistoryDelegate))
58        *ppvObject = static_cast<IWebHistoryDelegate*>(this);
59    else
60        return E_NOINTERFACE;
61
62    AddRef();
63    return S_OK;
64}
65
66ULONG HistoryDelegate::AddRef(void)
67{
68    return ++m_refCount;
69}
70
71ULONG HistoryDelegate::Release(void)
72{
73    ULONG newRef = --m_refCount;
74    if (!newRef)
75        delete(this);
76
77    return newRef;
78}
79
80// IWebHistoryDelegate
81HRESULT HistoryDelegate::didNavigateWithNavigationData(IWebView* webView, IWebNavigationData* navigationData, IWebFrame* webFrame)
82{
83    if (!gLayoutTestController->dumpHistoryDelegateCallbacks())
84        return S_OK;
85
86    BSTR urlBSTR;
87    if (FAILED(navigationData->url(&urlBSTR)))
88        return E_FAIL;
89    wstring url;
90    if (urlBSTR)
91        url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
92    SysFreeString(urlBSTR);
93
94    BSTR titleBSTR;
95    if (FAILED(navigationData->title(&titleBSTR)))
96        return E_FAIL;
97    wstring title;
98    if (titleBSTR)
99        title = wstringFromBSTR(titleBSTR);
100    SysFreeString(titleBSTR);
101
102    COMPtr<IWebURLRequest> request;
103    if (FAILED(navigationData->originalRequest(&request)))
104        return E_FAIL;
105
106    BSTR httpMethodBSTR;
107    if (FAILED(request->HTTPMethod(&httpMethodBSTR)))
108        return E_FAIL;
109    wstring httpMethod;
110    if (httpMethodBSTR)
111        httpMethod = wstringFromBSTR(httpMethodBSTR);
112    SysFreeString(httpMethodBSTR);
113
114    COMPtr<IWebURLResponse> response;
115    if (FAILED(navigationData->response(&response)))
116        return E_FAIL;
117
118    COMPtr<IWebHTTPURLResponse> httpResponse;
119    if (FAILED(response->QueryInterface(&httpResponse)))
120        return E_FAIL;
121
122    int statusCode = 0;
123    if (FAILED(httpResponse->statusCode(&statusCode)))
124        return E_FAIL;
125
126    BOOL hasSubstituteData;
127    if (FAILED(navigationData->hasSubstituteData(&hasSubstituteData)))
128        return E_FAIL;
129
130    BSTR clientRedirectSourceBSTR;
131    if (FAILED(navigationData->clientRedirectSource(&clientRedirectSourceBSTR)))
132        return E_FAIL;
133    bool hasClientRedirect = clientRedirectSourceBSTR && SysStringLen(clientRedirectSourceBSTR);
134    wstring redirectSource;
135    if (clientRedirectSourceBSTR)
136        redirectSource = urlSuitableForTestResult(wstringFromBSTR(clientRedirectSourceBSTR));
137    SysFreeString(clientRedirectSourceBSTR);
138
139    bool wasFailure = hasSubstituteData || (httpResponse && statusCode >= 400);
140
141    printf("WebView navigated to url \"%S\" with title \"%S\" with HTTP equivalent method \"%S\".  The navigation was %s and was %s%S.\n",
142        url.c_str(),
143        title.c_str(),
144        httpMethod.c_str(),
145        wasFailure ? "a failure" : "successful",
146        hasClientRedirect ? "a client redirect from " : "not a client redirect",
147        redirectSource.c_str());
148
149    return S_OK;
150}
151
152HRESULT HistoryDelegate::didPerformClientRedirectFromURL(IWebView*, BSTR sourceURL, BSTR destinationURL, IWebFrame*)
153{
154    if (!gLayoutTestController->dumpHistoryDelegateCallbacks())
155        return S_OK;
156
157    wstring source;
158    if (sourceURL)
159        source = urlSuitableForTestResult(wstringFromBSTR(sourceURL));
160
161    wstring destination;
162    if (destinationURL)
163        destination = urlSuitableForTestResult(wstringFromBSTR(destinationURL));
164
165    printf("WebView performed a client redirect from \"%S\" to \"%S\".\n", source.c_str(), destination.c_str());
166    return S_OK;
167}
168
169HRESULT HistoryDelegate::didPerformServerRedirectFromURL(IWebView* webView, BSTR sourceURL, BSTR destinationURL, IWebFrame* webFrame)
170{
171    if (!gLayoutTestController->dumpHistoryDelegateCallbacks())
172        return S_OK;
173
174    wstring source;
175    if (sourceURL)
176        source = urlSuitableForTestResult(wstringFromBSTR(sourceURL));
177
178    wstring destination;
179    if (destinationURL)
180        destination = urlSuitableForTestResult(wstringFromBSTR(destinationURL));
181
182    printf("WebView performed a server redirect from \"%S\" to \"%S\".\n", source.c_str(), destination.c_str());
183    return S_OK;
184}
185
186HRESULT HistoryDelegate::updateHistoryTitle(IWebView* webView, BSTR titleBSTR, BSTR urlBSTR)
187{
188    if (!gLayoutTestController->dumpHistoryDelegateCallbacks())
189        return S_OK;
190
191    wstring url;
192    if (urlBSTR)
193        url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
194
195    wstring title;
196    if (titleBSTR)
197        title = wstringFromBSTR(titleBSTR);
198
199    printf("WebView updated the title for history URL \"%S\" to \"%S\".\n", url.c_str(), title.c_str());
200    return S_OK;
201}
202
203HRESULT HistoryDelegate::populateVisitedLinksForWebView(IWebView* webView)
204{
205    if (!gLayoutTestController->dumpHistoryDelegateCallbacks())
206        return S_OK;
207
208    BSTR urlBSTR;
209    if (FAILED(webView->mainFrameURL(&urlBSTR)))
210        return E_FAIL;
211
212    wstring url;
213    if (urlBSTR)
214        url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
215    SysFreeString(urlBSTR);
216
217    if (gLayoutTestController->dumpVisitedLinksCallback())
218        printf("Asked to populate visited links for WebView \"%S\"\n", url.c_str());
219
220    return S_OK;
221}
222