2acfbbb904c866037f4003df9c429e13af4ecf54
[WebKit-https.git] / Tools / 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 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 urlBSTR;
78     if (FAILED(request->URL(&urlBSTR)))
79         return wstring();
80     
81     wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
82     ::SysFreeString(urlBSTR);
83     
84     BSTR mainDocumentURLBSTR;
85     if (FAILED(request->mainDocumentURL(&mainDocumentURLBSTR)))
86         return wstring();
87     
88     wstring mainDocumentURL = urlSuitableForTestResult(wstringFromBSTR(mainDocumentURLBSTR));
89     ::SysFreeString(mainDocumentURLBSTR);
90     
91     BSTR httpMethodBSTR;
92     if (FAILED(request->HTTPMethod(&httpMethodBSTR)))
93         return wstring();
94     
95     wstring httpMethod = wstringFromBSTR(httpMethodBSTR);
96     ::SysFreeString(httpMethodBSTR);
97
98     return L"<NSURLRequest URL " + url + L", main document URL " + mainDocumentURL + L", http method " + httpMethod + L">";
99 }
100
101 wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebURLResponse* response)
102 {
103     if (!response)
104         return L"(null)";
105
106     BSTR urlBSTR;
107     if (FAILED(response->URL(&urlBSTR)))
108         return wstring();
109     
110     wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
111     ::SysFreeString(urlBSTR);
112
113     int statusCode = 0;
114     COMPtr<IWebHTTPURLResponse> httpResponse;
115     if (response && SUCCEEDED(response->QueryInterface(&httpResponse)))
116         httpResponse->statusCode(&statusCode);
117     
118     return L"<NSURLResponse " + url + L", http status code " + wstringFromInt(statusCode) + L">";
119 }
120
121 wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebError* error, unsigned long identifier) const
122 {
123     wstring result = L"<NSError ";
124
125     BSTR domainSTR;
126     if (FAILED(error->domain(&domainSTR)))
127         return wstring();
128
129     wstring domain = wstringFromBSTR(domainSTR);
130     ::SysFreeString(domainSTR);
131
132     int code;
133     if (FAILED(error->code(&code)))
134         return wstring();
135
136     if (domain == L"CFURLErrorDomain") {
137         domain = L"NSURLErrorDomain";
138
139         // Convert kCFURLErrorUnknown to NSURLErrorUnknown
140         if (code == -998)
141             code = -1;
142     } else if (domain == L"kCFErrorDomainWinSock") {
143         domain = L"NSURLErrorDomain";
144
145         // Convert the winsock error code to an NSURLError code.
146         if (code == WSAEADDRNOTAVAIL)
147             code = -1004; // NSURLErrorCannotConnectToHose;
148     }
149
150     result += L"domain " + domain;
151     result += L", code " + wstringFromInt(code);
152
153     BSTR failingURLSTR;
154     if (FAILED(error->failingURL(&failingURLSTR)))
155         return wstring();
156
157     if (failingURLSTR) {
158         result += L", failing URL \"" + urlSuitableForTestResult(wstringFromBSTR(failingURLSTR)) + L"\"";
159         ::SysFreeString(failingURLSTR);
160     }
161
162     result += L">";
163
164     return result;
165 }
166
167 ResourceLoadDelegate::ResourceLoadDelegate()
168     : m_refCount(1)
169 {
170 }
171
172 ResourceLoadDelegate::~ResourceLoadDelegate()
173 {
174 }
175
176 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
177 {
178     *ppvObject = 0;
179     if (IsEqualGUID(riid, IID_IUnknown))
180         *ppvObject = static_cast<IWebResourceLoadDelegate*>(this);
181     else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegate))
182         *ppvObject = static_cast<IWebResourceLoadDelegate*>(this);
183     else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegatePrivate2))
184         *ppvObject = static_cast<IWebResourceLoadDelegatePrivate2*>(this);
185     else
186         return E_NOINTERFACE;
187
188     AddRef();
189     return S_OK;
190 }
191
192 ULONG STDMETHODCALLTYPE ResourceLoadDelegate::AddRef(void)
193 {
194     return ++m_refCount;
195 }
196
197 ULONG STDMETHODCALLTYPE ResourceLoadDelegate::Release(void)
198 {
199     ULONG newRef = --m_refCount;
200     if (!newRef)
201         delete(this);
202
203     return newRef;
204 }
205
206 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::identifierForInitialRequest( 
207     /* [in] */ IWebView* webView,
208     /* [in] */ IWebURLRequest* request,
209     /* [in] */ IWebDataSource* dataSource,
210     /* [in] */ unsigned long identifier)
211
212     if (!done && gTestRunner->dumpResourceLoadCallbacks()) {
213         BSTR urlStr;
214         if (FAILED(request->URL(&urlStr)))
215             return E_FAIL;
216
217         ASSERT(!urlMap().contains(identifier));
218         urlMap().set(identifier, wstringFromBSTR(urlStr));
219     }
220
221     return S_OK;
222 }
223
224 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::removeIdentifierForRequest(
225     /* [in] */ IWebView* webView,
226     /* [in] */ unsigned long identifier)
227 {
228     urlMap().remove(identifier);
229
230     return S_OK;
231 }
232
233 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::willSendRequest( 
234     /* [in] */ IWebView* webView,
235     /* [in] */ unsigned long identifier,
236     /* [in] */ IWebURLRequest* request,
237     /* [in] */ IWebURLResponse* redirectResponse,
238     /* [in] */ IWebDataSource* dataSource,
239     /* [retval][out] */ IWebURLRequest **newRequest)
240 {
241     if (!done && gTestRunner->dumpResourceLoadCallbacks()) {
242         printf("%S - willSendRequest %S redirectResponse %S\n", 
243             descriptionSuitableForTestResult(identifier).c_str(),
244             descriptionSuitableForTestResult(request).c_str(),
245             descriptionSuitableForTestResult(redirectResponse).c_str());
246     }
247
248     if (!done && !gTestRunner->deferMainResourceDataLoad()) {
249         COMPtr<IWebDataSourcePrivate> dataSourcePrivate(Query, dataSource);
250         if (!dataSourcePrivate)
251             return E_FAIL;
252         dataSourcePrivate->setDeferMainResourceDataLoad(FALSE);
253     }
254
255     if (!done && gTestRunner->willSendRequestReturnsNull()) {
256         *newRequest = 0;
257         return S_OK;
258     }
259
260     if (!done && gTestRunner->willSendRequestReturnsNullOnRedirect() && redirectResponse) {
261         printf("Returning null for this redirect\n");
262         *newRequest = 0;
263         return S_OK;
264     }
265
266     IWebMutableURLRequest* requestCopy = 0;
267     request->mutableCopy(&requestCopy);
268     const set<string>& clearHeaders = gTestRunner->willSendRequestClearHeaders();
269     for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header) {
270       BSTR bstrHeader = BSTRFromString(*header);
271       requestCopy->setValue(0, bstrHeader);
272       SysFreeString(bstrHeader);
273     }
274
275     *newRequest = requestCopy;
276     return S_OK;
277 }
278
279 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didReceiveAuthenticationChallenge( 
280     /* [in] */ IWebView *webView,
281     /* [in] */ unsigned long identifier,
282     /* [in] */ IWebURLAuthenticationChallenge *challenge,
283     /* [in] */ IWebDataSource *dataSource)
284 {
285     COMPtr<IWebURLAuthenticationChallengeSender> sender;
286     if (!challenge || FAILED(challenge->sender(&sender)))
287         return E_FAIL;
288
289     if (!gTestRunner->handlesAuthenticationChallenges()) {
290         printf("%S - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet\n", descriptionSuitableForTestResult(identifier).c_str());
291         sender->continueWithoutCredentialForAuthenticationChallenge(challenge);
292         return S_OK;
293     }
294     
295     const char* user = gTestRunner->authenticationUsername().c_str();
296     const char* password = gTestRunner->authenticationPassword().c_str();
297
298     printf("%S - didReceiveAuthenticationChallenge - Responding with %s:%s\n", descriptionSuitableForTestResult(identifier).c_str(), user, password);
299
300     COMPtr<IWebURLCredential> credential;
301     if (FAILED(WebKitCreateInstance(CLSID_WebURLCredential, 0, IID_IWebURLCredential, (void**)&credential)))
302         return E_FAIL;
303     credential->initWithUser(_bstr_t(user), _bstr_t(password), WebURLCredentialPersistenceForSession);
304
305     sender->useCredential(credential.get(), challenge);
306     return S_OK;
307 }
308
309 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didReceiveResponse(
310     /* [in] */ IWebView* webView, 
311     /* [in] */ unsigned long identifier, 
312     /* [in] */ IWebURLResponse* response, 
313     /* [in] */ IWebDataSource* dataSource)
314 {
315     if (!done && gTestRunner->dumpResourceLoadCallbacks()) {
316         printf("%S - didReceiveResponse %S\n",
317             descriptionSuitableForTestResult(identifier).c_str(),
318             descriptionSuitableForTestResult(response).c_str());
319     }
320     if (!done && gTestRunner->dumpResourceResponseMIMETypes()) {
321         BSTR mimeTypeBSTR;
322         if (FAILED(response->MIMEType(&mimeTypeBSTR)))
323             E_FAIL;
324     
325         wstring mimeType = wstringFromBSTR(mimeTypeBSTR);
326         ::SysFreeString(mimeTypeBSTR);
327
328         BSTR urlBSTR;
329         if (FAILED(response->URL(&urlBSTR)))
330             E_FAIL;
331     
332         wstring url = wstringFromBSTR(urlBSTR);
333         ::SysFreeString(urlBSTR);
334
335         printf("%S has MIME type %S\n", lastPathComponent(url).c_str(), mimeType.c_str());
336     }
337
338     return S_OK;
339 }
340
341
342 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFinishLoadingFromDataSource( 
343     /* [in] */ IWebView* webView,
344     /* [in] */ unsigned long identifier,
345     /* [in] */ IWebDataSource* dataSource)
346 {
347     if (!done && gTestRunner->dumpResourceLoadCallbacks()) {
348         printf("%S - didFinishLoading\n",
349             descriptionSuitableForTestResult(identifier).c_str());
350     }
351
352     removeIdentifierForRequest(webView, identifier);
353
354     return S_OK;
355 }
356         
357 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFailLoadingWithError( 
358     /* [in] */ IWebView* webView,
359     /* [in] */ unsigned long identifier,
360     /* [in] */ IWebError* error,
361     /* [in] */ IWebDataSource* dataSource)
362 {
363     if (!done && gTestRunner->dumpResourceLoadCallbacks()) {
364         printf("%S - didFailLoadingWithError: %S\n", 
365             descriptionSuitableForTestResult(identifier).c_str(),
366             descriptionSuitableForTestResult(error, identifier).c_str());
367     }
368
369     removeIdentifierForRequest(webView, identifier);
370
371     return S_OK;
372 }