• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
wstringFromBSTR(BSTR str)41 static inline wstring wstringFromBSTR(BSTR str)
42 {
43     return wstring(str, ::SysStringLen(str));
44 }
45 
wstringFromInt(int i)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 
urlMap()55 IdentifierMap& urlMap()
56 {
57     static IdentifierMap urlMap;
58 
59     return urlMap;
60 }
61 
descriptionSuitableForTestResult(unsigned long identifier)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 
descriptionSuitableForTestResult(IWebURLRequest * request)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 
descriptionSuitableForTestResult(IWebURLResponse * response)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 
descriptionSuitableForTestResult(IWebError * error,unsigned long identifier)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 
ResourceLoadDelegate()174 ResourceLoadDelegate::ResourceLoadDelegate()
175     : m_refCount(1)
176 {
177 }
178 
~ResourceLoadDelegate()179 ResourceLoadDelegate::~ResourceLoadDelegate()
180 {
181 }
182 
QueryInterface(REFIID riid,void ** ppvObject)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 
AddRef(void)197 ULONG STDMETHODCALLTYPE ResourceLoadDelegate::AddRef(void)
198 {
199     return ++m_refCount;
200 }
201 
Release(void)202 ULONG STDMETHODCALLTYPE ResourceLoadDelegate::Release(void)
203 {
204     ULONG newRef = --m_refCount;
205     if (!newRef)
206         delete(this);
207 
208     return newRef;
209 }
210 
identifierForInitialRequest(IWebView * webView,IWebURLRequest * request,IWebDataSource * dataSource,unsigned long identifier)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 
willSendRequest(IWebView * webView,unsigned long identifier,IWebURLRequest * request,IWebURLResponse * redirectResponse,IWebDataSource * dataSource,IWebURLRequest ** newRequest)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 
didReceiveResponse(IWebView * webView,unsigned long identifier,IWebURLResponse * response,IWebDataSource * dataSource)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 
didFinishLoadingFromDataSource(IWebView * webView,unsigned long identifier,IWebDataSource * dataSource)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 
didFailLoadingWithError(IWebView * webView,unsigned long identifier,IWebError * error,IWebDataSource * dataSource)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 }
316