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