06476e759be5904f4a3339ec9281edc9348c7d75
[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     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 static wstring 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 static wstring descriptionSuitableForTestResult(IWebError* error, unsigned long identifier)
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     wstring failingURL;
158     
159     // If the error doesn't have a failing URL, we fake one by using the URL the resource had 
160     // at creation time. This seems to work fine for now.
161     // See <rdar://problem/5064234> CFErrors should have failingURL key.
162     if (failingURLSTR)
163         failingURL = wstringFromBSTR(failingURLSTR);
164     else
165         failingURL = descriptionSuitableForTestResult(identifier);
166
167     ::SysFreeString(failingURLSTR);
168
169     result += L", failing URL \"" + urlSuitableForTestResult(failingURL) + L"\">";
170
171     return result;
172 }
173
174 ResourceLoadDelegate::ResourceLoadDelegate()
175     : m_refCount(1)
176 {
177 }
178
179 ResourceLoadDelegate::~ResourceLoadDelegate()
180 {
181 }
182
183 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
184 {
185     *ppvObject = 0;
186     if (IsEqualGUID(riid, IID_IUnknown))
187         *ppvObject = static_cast<IWebResourceLoadDelegate*>(this);
188     else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegate))
189         *ppvObject = static_cast<IWebResourceLoadDelegate*>(this);
190     else
191         return E_NOINTERFACE;
192
193     AddRef();
194     return S_OK;
195 }
196
197 ULONG STDMETHODCALLTYPE ResourceLoadDelegate::AddRef(void)
198 {
199     return ++m_refCount;
200 }
201
202 ULONG STDMETHODCALLTYPE ResourceLoadDelegate::Release(void)
203 {
204     ULONG newRef = --m_refCount;
205     if (!newRef)
206         delete(this);
207
208     return newRef;
209 }
210
211 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::identifierForInitialRequest( 
212     /* [in] */ IWebView* webView,
213     /* [in] */ IWebURLRequest* request,
214     /* [in] */ IWebDataSource* dataSource,
215     /* [in] */ unsigned long identifier)
216
217     if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
218         BSTR urlStr;
219         if (FAILED(request->URL(&urlStr)))
220             return E_FAIL;
221
222         urlMap().set(identifier, wstringFromBSTR(urlStr));
223     }
224
225     return S_OK;
226 }
227
228 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::willSendRequest( 
229     /* [in] */ IWebView* webView,
230     /* [in] */ unsigned long identifier,
231     /* [in] */ IWebURLRequest* request,
232     /* [in] */ IWebURLResponse* redirectResponse,
233     /* [in] */ IWebDataSource* dataSource,
234     /* [retval][out] */ IWebURLRequest **newRequest)
235 {
236     if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
237         printf("%S - willSendRequest %S redirectResponse %S\n", 
238             descriptionSuitableForTestResult(identifier).c_str(),
239             descriptionSuitableForTestResult(request).c_str(),
240             descriptionSuitableForTestResult(redirectResponse).c_str());
241     }
242
243     if (!done && gLayoutTestController->willSendRequestReturnsNullOnRedirect() && redirectResponse) {
244         printf("Returning null for this redirect\n");
245         *newRequest = 0;
246         return S_OK;
247     }
248
249     request->AddRef();
250     *newRequest = request;
251     return S_OK;
252 }
253
254 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didReceiveResponse(
255     /* [in] */ IWebView* webView, 
256     /* [in] */ unsigned long identifier, 
257     /* [in] */ IWebURLResponse* response, 
258     /* [in] */ IWebDataSource* dataSource)
259 {
260     if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
261         printf("%S - didReceiveResponse %S\n",
262             descriptionSuitableForTestResult(identifier).c_str(),
263             descriptionSuitableForTestResult(response).c_str());
264     }
265     if (!done && gLayoutTestController->dumpResourceResponseMIMETypes()) {
266         BSTR mimeTypeBSTR;
267         if (FAILED(response->MIMEType(&mimeTypeBSTR)))
268             E_FAIL;
269     
270         wstring mimeType = wstringFromBSTR(mimeTypeBSTR);
271         ::SysFreeString(mimeTypeBSTR);
272
273         BSTR urlBSTR;
274         if (FAILED(response->URL(&urlBSTR)))
275             E_FAIL;
276     
277         wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
278         ::SysFreeString(urlBSTR);
279
280         printf("%S has MIME type %S\n", url.c_str(), mimeType.c_str());
281     }
282
283     return S_OK;
284 }
285
286
287 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFinishLoadingFromDataSource( 
288     /* [in] */ IWebView* webView,
289     /* [in] */ unsigned long identifier,
290     /* [in] */ IWebDataSource* dataSource)
291 {
292     if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
293         printf("%S - didFinishLoading\n",
294             descriptionSuitableForTestResult(identifier).c_str()),
295        urlMap().remove(identifier);
296     }
297
298    return S_OK;
299 }
300         
301 HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFailLoadingWithError( 
302     /* [in] */ IWebView* webView,
303     /* [in] */ unsigned long identifier,
304     /* [in] */ IWebError* error,
305     /* [in] */ IWebDataSource* dataSource)
306 {
307     if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
308         printf("%S - didFailLoadingWithError: %S\n", 
309             descriptionSuitableForTestResult(identifier).c_str(),
310             descriptionSuitableForTestResult(error, identifier).c_str());
311         urlMap().remove(identifier);
312     }
313
314     return S_OK;
315 }