[Win] Various DumpRenderTree Fixes.
[WebKit-https.git] / Tools / DumpRenderTree / win / ResourceLoadDelegate.cpp
1 /*
2  * Copyright (C) 2007, 2014 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 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 "TestRunner.h"
34 #include <WebKit/WebKitCOMAPI.h>
35 #include <comutil.h>
36 #include <sstream>
37 #include <tchar.h>
38 #include <wtf/Vector.h>
39
40 using namespace std;
41
42 static inline wstring wstringFromBSTR(BSTR str)
43 {
44     return wstring(str, ::SysStringLen(str));
45 }
46
47 static inline wstring wstringFromInt(int i)
48 {
49     wostringstream ss;
50     ss << i;
51     return ss.str();
52 }
53
54 static inline BSTR BSTRFromString(const string& str)
55 {
56     int length = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), 0, 0);
57     BSTR result = ::SysAllocStringLen(0, length);
58     ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), result, length);
59     return result;
60 }
61
62 wstring ResourceLoadDelegate::descriptionSuitableForTestResult(unsigned long identifier) const
63 {
64     IdentifierMap::const_iterator it = m_urlMap.find(identifier);
65     
66     if (it == m_urlMap.end())
67         return L"<unknown>";
68
69     return urlSuitableForTestResult(it->value);
70 }
71
72 wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebURLRequest* request)
73 {
74     if (!request)
75         return L"(null)";
76
77     _bstr_t urlBSTR;
78     if (FAILED(request->URL(&urlBSTR.GetBSTR())))
79         return wstring();
80     
81     wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
82     
83     _bstr_t mainDocumentURLBSTR;
84     if (FAILED(request->mainDocumentURL(&mainDocumentURLBSTR.GetBSTR())))
85         return wstring();
86     
87     wstring mainDocumentURL = urlSuitableForTestResult(wstringFromBSTR(mainDocumentURLBSTR));
88     
89     _bstr_t httpMethodBSTR;
90     if (FAILED(request->HTTPMethod(&httpMethodBSTR.GetBSTR())))
91         return wstring();
92     
93     return L"<NSURLRequest URL " + url + L", main document URL " + mainDocumentURL + L", http method " + static_cast<wchar_t*>(httpMethodBSTR) + L">";
94 }
95
96 wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebURLResponse* response)
97 {
98     if (!response)
99         return L"(null)";
100
101     _bstr_t urlBSTR;
102     if (FAILED(response->URL(&urlBSTR.GetBSTR())))
103         return wstring();
104     
105     wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
106
107     int statusCode = 0;
108     COMPtr<IWebHTTPURLResponse> httpResponse;
109     if (response && SUCCEEDED(response->QueryInterface(&httpResponse)))
110         httpResponse->statusCode(&statusCode);
111     
112     return L"<NSURLResponse " + url + L", http status code " + wstringFromInt(statusCode) + L">";
113 }
114
115 wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebError* error, unsigned long identifier) const
116 {
117     wstring result = L"<NSError ";
118
119     _bstr_t domainSTR;
120     if (FAILED(error->domain(&domainSTR.GetBSTR())))
121         return wstring();
122
123     wstring domain = wstringFromBSTR(domainSTR);
124
125     int code;
126     if (FAILED(error->code(&code)))
127         return wstring();
128
129     if (domain == L"CFURLErrorDomain") {
130         domain = L"NSURLErrorDomain";
131
132         // Convert kCFURLErrorUnknown to NSURLErrorUnknown
133         if (code == -998)
134             code = -1;
135     } else if (domain == L"kCFErrorDomainWinSock") {
136         domain = L"NSURLErrorDomain";
137
138         // Convert the winsock error code to an NSURLError code.
139         if (code == WSAEADDRNOTAVAIL)
140             code = -1004; // NSURLErrorCannotConnectToHose;
141     }
142
143     result += L"domain " + domain;
144     result += L", code " + wstringFromInt(code);
145
146     _bstr_t failingURLSTR;
147     if (FAILED(error->failingURL(&failingURLSTR.GetBSTR())))
148         return wstring();
149
150     if (failingURLSTR.length())
151         result += L", failing URL \"" + urlSuitableForTestResult(wstringFromBSTR(failingURLSTR)) + L"\"";
152
153     result += L">";
154
155     return result;
156 }
157
158 ResourceLoadDelegate::ResourceLoadDelegate()
159     : m_refCount(1)
160 {
161 }
162
163 ResourceLoadDelegate::~ResourceLoadDelegate()
164 {
165 }
166
167 HRESULT ResourceLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
168 {
169     *ppvObject = 0;
170     if (IsEqualGUID(riid, IID_IUnknown))
171         *ppvObject = static_cast<IWebResourceLoadDelegate*>(this);
172     else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegate))
173         *ppvObject = static_cast<IWebResourceLoadDelegate*>(this);
174     else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegatePrivate2))
175         *ppvObject = static_cast<IWebResourceLoadDelegatePrivate2*>(this);
176     else
177         return E_NOINTERFACE;
178
179     AddRef();
180     return S_OK;
181 }
182
183 ULONG ResourceLoadDelegate::AddRef(void)
184 {
185     return ++m_refCount;
186 }
187
188 ULONG ResourceLoadDelegate::Release(void)
189 {
190     ULONG newRef = --m_refCount;
191     if (!newRef)
192         delete(this);
193
194     return newRef;
195 }
196
197 HRESULT ResourceLoadDelegate::identifierForInitialRequest(IWebView* webView, IWebURLRequest* request, IWebDataSource* dataSource, unsigned long identifier)
198
199     if (!done && gTestRunner->dumpResourceLoadCallbacks()) {
200         _bstr_t urlStr;
201         if (FAILED(request->URL(&urlStr.GetBSTR())))
202             return E_FAIL;
203
204         ASSERT(!urlMap().contains(identifier));
205         urlMap().set(identifier, wstringFromBSTR(urlStr));
206     }
207
208     return S_OK;
209 }
210
211 HRESULT ResourceLoadDelegate::removeIdentifierForRequest(
212     /* [in] */ IWebView* webView,
213     /* [in] */ unsigned long identifier)
214 {
215     urlMap().remove(identifier);
216
217     return S_OK;
218 }
219
220 HRESULT ResourceLoadDelegate::willSendRequest(IWebView* webView, unsigned long identifier, IWebURLRequest* request,
221     IWebURLResponse* redirectResponse, IWebDataSource* dataSource, IWebURLRequest** newRequest)
222 {
223     if (!done && gTestRunner->dumpResourceLoadCallbacks()) {
224         printf("%S - willSendRequest %S redirectResponse %S\n", 
225             descriptionSuitableForTestResult(identifier).c_str(),
226             descriptionSuitableForTestResult(request).c_str(),
227             descriptionSuitableForTestResult(redirectResponse).c_str());
228     }
229
230     if (!done && !gTestRunner->deferMainResourceDataLoad()) {
231         COMPtr<IWebDataSourcePrivate> dataSourcePrivate(Query, dataSource);
232         if (!dataSourcePrivate)
233             return E_FAIL;
234         dataSourcePrivate->setDeferMainResourceDataLoad(FALSE);
235     }
236
237     if (!done && gTestRunner->willSendRequestReturnsNull()) {
238         *newRequest = 0;
239         return S_OK;
240     }
241
242     if (!done && gTestRunner->willSendRequestReturnsNullOnRedirect() && redirectResponse) {
243         printf("Returning null for this redirect\n");
244         *newRequest = 0;
245         return S_OK;
246     }
247
248     IWebMutableURLRequest* requestCopy = 0;
249     request->mutableCopy(&requestCopy);
250     const set<string>& clearHeaders = gTestRunner->willSendRequestClearHeaders();
251     for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header) {
252         _bstr_t bstrHeader(header->data());
253         requestCopy->setValue(0, bstrHeader);
254     }
255
256     *newRequest = requestCopy;
257     return S_OK;
258 }
259
260 HRESULT ResourceLoadDelegate::didReceiveAuthenticationChallenge(IWebView* webView, unsigned long identifier, IWebURLAuthenticationChallenge* challenge, IWebDataSource* dataSource)
261 {
262     COMPtr<IWebURLAuthenticationChallengeSender> sender;
263     if (!challenge || FAILED(challenge->sender(&sender)))
264         return E_FAIL;
265
266     if (!gTestRunner->handlesAuthenticationChallenges()) {
267         printf("%S - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet\n", descriptionSuitableForTestResult(identifier).c_str());
268         sender->continueWithoutCredentialForAuthenticationChallenge(challenge);
269         return S_OK;
270     }
271     
272     const char* user = gTestRunner->authenticationUsername().c_str();
273     const char* password = gTestRunner->authenticationPassword().c_str();
274
275     printf("%S - didReceiveAuthenticationChallenge - Responding with %s:%s\n", descriptionSuitableForTestResult(identifier).c_str(), user, password);
276
277     COMPtr<IWebURLCredential> credential;
278     if (FAILED(WebKitCreateInstance(CLSID_WebURLCredential, 0, IID_IWebURLCredential, (void**)&credential)))
279         return E_FAIL;
280     credential->initWithUser(_bstr_t(user), _bstr_t(password), WebURLCredentialPersistenceForSession);
281
282     sender->useCredential(credential.get(), challenge);
283     return S_OK;
284 }
285
286 HRESULT ResourceLoadDelegate::didReceiveResponse(
287     /* [in] */ IWebView* webView, 
288     /* [in] */ unsigned long identifier, 
289     /* [in] */ IWebURLResponse* response, 
290     /* [in] */ IWebDataSource* dataSource)
291 {
292     if (!done && gTestRunner->dumpResourceLoadCallbacks()) {
293         printf("%S - didReceiveResponse %S\n",
294             descriptionSuitableForTestResult(identifier).c_str(),
295             descriptionSuitableForTestResult(response).c_str());
296     }
297     if (!done && gTestRunner->dumpResourceResponseMIMETypes()) {
298         _bstr_t mimeTypeBSTR;
299         if (FAILED(response->MIMEType(&mimeTypeBSTR.GetBSTR())))
300             E_FAIL;
301     
302         _bstr_t urlBSTR;
303         if (FAILED(response->URL(&urlBSTR.GetBSTR())))
304             E_FAIL;
305     
306         wstring url = wstringFromBSTR(urlBSTR);
307
308         printf("%S has MIME type %S\n", lastPathComponent(url).c_str(), static_cast<wchar_t*>(mimeTypeBSTR));
309     }
310
311     return S_OK;
312 }
313
314
315 HRESULT ResourceLoadDelegate::didFinishLoadingFromDataSource(IWebView* webView, unsigned long identifier, IWebDataSource* dataSource)
316 {
317     if (!done && gTestRunner->dumpResourceLoadCallbacks()) {
318         printf("%S - didFinishLoading\n",
319             descriptionSuitableForTestResult(identifier).c_str());
320     }
321
322     removeIdentifierForRequest(webView, identifier);
323
324     return S_OK;
325 }
326         
327 HRESULT ResourceLoadDelegate::didFailLoadingWithError(IWebView* webView, unsigned long identifier, IWebError* error, IWebDataSource* dataSource)
328 {
329     if (!done && gTestRunner->dumpResourceLoadCallbacks()) {
330         printf("%S - didFailLoadingWithError: %S\n", 
331             descriptionSuitableForTestResult(identifier).c_str(),
332             descriptionSuitableForTestResult(error, identifier).c_str());
333     }
334
335     removeIdentifierForRequest(webView, identifier);
336
337     return S_OK;
338 }