1e77edacf82ec0a173e13a3956b648487b9f545f
[WebKit-https.git] / WebKitTools / DumpRenderTree / win / ResourceLoadDelegate.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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "ResourceLoadDelegate.h"
31
32 #include "DumpRenderTree.h"
33 #include "LayoutTestController.h"
34 #include <wtf/HashMap.h>
35 #include <wtf/Vector.h>
36 #include <sstream>
37
38 using std::wstring;
39 using std::wiostream;
40
41 static inline wstring wstringFromBSTR(BSTR str)
42 {
43     return wstring(str, ::SysStringLen(str));
44 }
45
46 wstring wstringFromInt(int i)
47 {
48     std::wostringstream ss;
49     ss << i;
50     return ss.str();
51 }
52
53 typedef HashMap<unsigned long, wstring> IdentifierMap;
54
55 IdentifierMap& urlMap()
56 {
57     static IdentifierMap urlMap;
58
59     return urlMap;
60 }
61
62 static wstring descriptionSuitableForTestResult(unsigned long identifier)
63 {
64     IdentifierMap::iterator it = urlMap().find(identifier);
65     
66     if (it == urlMap().end())
67         return L"<unknown>";
68
69     return urlSuitableForTestResult(it->second);
70 }
71
72 static wstring descriptionSuitableForTestResult(IWebURLRequest* request)
73 {
74     if (!request)
75         return L"(null)";
76
77     BSTR urlBSTR;
78     if (FAILED(request->URL(&urlBSTR)))
79         return wstring();
80     
81     wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
82     ::SysFreeString(urlBSTR);
83
84     return L"<NSURLRequest " + url + L">";
85 }
86
87 static wstring descriptionSuitableForTestResult(IWebURLResponse* response)
88 {
89     if (!response)
90         return L"(null)";
91
92     BSTR urlBSTR;
93     if (FAILED(response->URL(&urlBSTR)))
94         return wstring();
95     
96     wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
97     ::SysFreeString(urlBSTR);
98
99     return L"<NSURLResponse " + url + L">";
100 }
101
102 static wstring descriptionSuitableForTestResult(IWebError* error, unsigned long identifier)
103 {
104     wstring result = L"<NSError ";
105
106     BSTR domainSTR;
107     if (FAILED(error->domain(&domainSTR)))
108         return wstring();
109
110     wstring domain = wstringFromBSTR(domainSTR);
111     ::SysFreeString(domainSTR);
112
113     int code;
114     if (FAILED(error->code(&code)))
115         return wstring();
116
117     if (domain == L"CFURLErrorDomain") {
118         domain = L"NSURLErrorDomain";
119
120         // Convert kCFURLErrorUnknown to NSURLErrorUnknown
121         if (code == -998)
122             code = -1;
123     } else if (domain == L"kCFErrorDomainWinSock") {
124         domain = L"NSURLErrorDomain";
125
126         // Convert the winsock error code to an NSURLError code.
127         if (code == WSAEADDRNOTAVAIL)
128             code = -1004; // NSURLErrorCannotConnectToHose;
129     }
130
131     result += L"domain " + domain;
132     result += L", code " + wstringFromInt(code);
133
134     BSTR failingURLSTR;
135     if (FAILED(error->failingURL(&failingURLSTR)))
136         return wstring();
137
138     wstring failingURL;
139     
140     // If the error doesn't have a failing URL, we fake one by using the URL the resource had 
141     // at creation time. This seems to work fine for now.
142     // See <rdar://problem/5064234> CFErrors should have failingURL key.
143     if (failingURLSTR)
144         failingURL = wstringFromBSTR(failingURLSTR);
145     else
146         failingURL = descriptionSuitableForTestResult(identifier);
147
148     ::SysFreeString(failingURLSTR);
149
150     result += L", failing URL \"" + urlSuitableForTestResult(failingURL) + L"\">";
151
152     return result;
153 }
154
155 ResourceLoadDelegate::ResourceLoadDelegate()
156     : m_refCount(1)
157 {
158 }
159
160 ResourceLoadDelegate::~ResourceLoadDelegate()
161 {
162 }
163
164 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
165 {
166     *ppvObject = 0;
167     if (IsEqualGUID(riid, IID_IUnknown))
168         *ppvObject = static_cast<IWebResourceLoadDelegate*>(this);
169     else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegate))
170         *ppvObject = static_cast<IWebResourceLoadDelegate*>(this);
171     else
172         return E_NOINTERFACE;
173
174     AddRef();
175     return S_OK;
176 }
177
178 ULONG STDMETHODCALLTYPE ResourceLoadDelegate::AddRef(void)
179 {
180     return ++m_refCount;
181 }
182
183 ULONG STDMETHODCALLTYPE ResourceLoadDelegate::Release(void)
184 {
185     ULONG newRef = --m_refCount;
186     if (!newRef)
187         delete(this);
188
189     return newRef;
190 }
191
192 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::identifierForInitialRequest( 
193     /* [in] */ IWebView* webView,
194     /* [in] */ IWebURLRequest* request,
195     /* [in] */ IWebDataSource* dataSource,
196     /* [in] */ unsigned long identifier)
197
198     if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
199         BSTR urlStr;
200         if (FAILED(request->URL(&urlStr)))
201             return E_FAIL;
202
203         urlMap().set(identifier, wstringFromBSTR(urlStr));
204     }
205
206     return S_OK;
207 }
208
209 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::willSendRequest( 
210     /* [in] */ IWebView* webView,
211     /* [in] */ unsigned long identifier,
212     /* [in] */ IWebURLRequest* request,
213     /* [in] */ IWebURLResponse* redirectResponse,
214     /* [in] */ IWebDataSource* dataSource,
215     /* [retval][out] */ IWebURLRequest **newRequest)
216 {
217     if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
218         printf("%S - willSendRequest %S redirectResponse %S\n", 
219             descriptionSuitableForTestResult(identifier).c_str(),
220             descriptionSuitableForTestResult(request).c_str(),
221             descriptionSuitableForTestResult(redirectResponse).c_str());
222     }
223
224     request->AddRef();
225     *newRequest = request;
226     return S_OK;
227 }
228
229 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFinishLoadingFromDataSource( 
230     /* [in] */ IWebView* webView,
231     /* [in] */ unsigned long identifier,
232     /* [in] */ IWebDataSource* dataSource)
233 {
234     if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
235         printf("%S - didFinishLoading\n",
236             descriptionSuitableForTestResult(identifier).c_str()),
237        urlMap().remove(identifier);
238     }
239
240    return S_OK;
241 }
242         
243 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFailLoadingWithError( 
244     /* [in] */ IWebView* webView,
245     /* [in] */ unsigned long identifier,
246     /* [in] */ IWebError* error,
247     /* [in] */ IWebDataSource* dataSource)
248 {
249     if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
250         printf("%S - didFailLoadingWithError: %S\n", 
251             descriptionSuitableForTestResult(identifier).c_str(),
252             descriptionSuitableForTestResult(error, identifier).c_str());
253         urlMap().remove(identifier);
254     }
255
256     return S_OK;
257 }