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