diff options
Diffstat (limited to 'Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp')
-rw-r--r-- | Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp | 379 |
1 files changed, 379 insertions, 0 deletions
diff --git a/Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp b/Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp new file mode 100644 index 0000000..09b07d6 --- /dev/null +++ b/Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ResourceLoadDelegate.h" + +#include "DumpRenderTree.h" +#include "LayoutTestController.h" +#include <WebKit/WebKitCOMAPI.h> +#include <comutil.h> +#include <sstream> +#include <tchar.h> +#include <wtf/Vector.h> + +using namespace std; + +static inline wstring wstringFromBSTR(BSTR str) +{ + return wstring(str, ::SysStringLen(str)); +} + +static inline wstring wstringFromInt(int i) +{ + wostringstream ss; + ss << i; + return ss.str(); +} + +static inline BSTR BSTRFromString(const string& str) +{ + int length = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), 0, 0); + BSTR result = ::SysAllocStringLen(0, length); + ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), result, length); + return result; +} + +wstring ResourceLoadDelegate::descriptionSuitableForTestResult(unsigned long identifier) const +{ + IdentifierMap::const_iterator it = m_urlMap.find(identifier); + + if (it == m_urlMap.end()) + return L"<unknown>"; + + return urlSuitableForTestResult(it->second); +} + +wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebURLRequest* request) +{ + if (!request) + return L"(null)"; + + BSTR urlBSTR; + if (FAILED(request->URL(&urlBSTR))) + return wstring(); + + wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR)); + ::SysFreeString(urlBSTR); + + BSTR mainDocumentURLBSTR; + if (FAILED(request->mainDocumentURL(&mainDocumentURLBSTR))) + return wstring(); + + wstring mainDocumentURL = urlSuitableForTestResult(wstringFromBSTR(mainDocumentURLBSTR)); + ::SysFreeString(mainDocumentURLBSTR); + + BSTR httpMethodBSTR; + if (FAILED(request->HTTPMethod(&httpMethodBSTR))) + return wstring(); + + wstring httpMethod = wstringFromBSTR(httpMethodBSTR); + ::SysFreeString(httpMethodBSTR); + + return L"<NSURLRequest URL " + url + L", main document URL " + mainDocumentURL + L", http method " + httpMethod + L">"; +} + +wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebURLResponse* response) +{ + if (!response) + return L"(null)"; + + BSTR urlBSTR; + if (FAILED(response->URL(&urlBSTR))) + return wstring(); + + wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR)); + ::SysFreeString(urlBSTR); + + int statusCode = 0; + COMPtr<IWebHTTPURLResponse> httpResponse; + if (response && SUCCEEDED(response->QueryInterface(&httpResponse))) + httpResponse->statusCode(&statusCode); + + return L"<NSURLResponse " + url + L", http status code " + wstringFromInt(statusCode) + L">"; +} + +wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebError* error, unsigned long identifier) const +{ + wstring result = L"<NSError "; + + BSTR domainSTR; + if (FAILED(error->domain(&domainSTR))) + return wstring(); + + wstring domain = wstringFromBSTR(domainSTR); + ::SysFreeString(domainSTR); + + int code; + if (FAILED(error->code(&code))) + return wstring(); + + if (domain == L"CFURLErrorDomain") { + domain = L"NSURLErrorDomain"; + + // Convert kCFURLErrorUnknown to NSURLErrorUnknown + if (code == -998) + code = -1; + } else if (domain == L"kCFErrorDomainWinSock") { + domain = L"NSURLErrorDomain"; + + // Convert the winsock error code to an NSURLError code. + if (code == WSAEADDRNOTAVAIL) + code = -1004; // NSURLErrorCannotConnectToHose; + } + + result += L"domain " + domain; + result += L", code " + wstringFromInt(code); + + BSTR failingURLSTR; + if (FAILED(error->failingURL(&failingURLSTR))) + return wstring(); + + wstring failingURL; + + // If the error doesn't have a failing URL, we fake one by using the URL the resource had + // at creation time. This seems to work fine for now. + // See <rdar://problem/5064234> CFErrors should have failingURL key. + if (failingURLSTR) + failingURL = wstringFromBSTR(failingURLSTR); + else + failingURL = descriptionSuitableForTestResult(identifier); + + ::SysFreeString(failingURLSTR); + + result += L", failing URL \"" + urlSuitableForTestResult(failingURL) + L"\">"; + + return result; +} + +ResourceLoadDelegate::ResourceLoadDelegate() + : m_refCount(1) +{ +} + +ResourceLoadDelegate::~ResourceLoadDelegate() +{ +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::QueryInterface(REFIID riid, void** ppvObject) +{ + *ppvObject = 0; + if (IsEqualGUID(riid, IID_IUnknown)) + *ppvObject = static_cast<IWebResourceLoadDelegate*>(this); + else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegate)) + *ppvObject = static_cast<IWebResourceLoadDelegate*>(this); + else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegatePrivate2)) + *ppvObject = static_cast<IWebResourceLoadDelegatePrivate2*>(this); + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} + +ULONG STDMETHODCALLTYPE ResourceLoadDelegate::AddRef(void) +{ + return ++m_refCount; +} + +ULONG STDMETHODCALLTYPE ResourceLoadDelegate::Release(void) +{ + ULONG newRef = --m_refCount; + if (!newRef) + delete(this); + + return newRef; +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::identifierForInitialRequest( + /* [in] */ IWebView* webView, + /* [in] */ IWebURLRequest* request, + /* [in] */ IWebDataSource* dataSource, + /* [in] */ unsigned long identifier) +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + BSTR urlStr; + if (FAILED(request->URL(&urlStr))) + return E_FAIL; + + ASSERT(!urlMap().contains(identifier)); + urlMap().set(identifier, wstringFromBSTR(urlStr)); + } + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::removeIdentifierForRequest( + /* [in] */ IWebView* webView, + /* [in] */ unsigned long identifier) +{ + urlMap().remove(identifier); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::willSendRequest( + /* [in] */ IWebView* webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebURLRequest* request, + /* [in] */ IWebURLResponse* redirectResponse, + /* [in] */ IWebDataSource* dataSource, + /* [retval][out] */ IWebURLRequest **newRequest) +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + printf("%S - willSendRequest %S redirectResponse %S\n", + descriptionSuitableForTestResult(identifier).c_str(), + descriptionSuitableForTestResult(request).c_str(), + descriptionSuitableForTestResult(redirectResponse).c_str()); + } + + if (!done && !gLayoutTestController->deferMainResourceDataLoad()) { + COMPtr<IWebDataSourcePrivate> dataSourcePrivate(Query, dataSource); + if (!dataSourcePrivate) + return E_FAIL; + dataSourcePrivate->setDeferMainResourceDataLoad(FALSE); + } + + if (!done && gLayoutTestController->willSendRequestReturnsNull()) { + *newRequest = 0; + return S_OK; + } + + if (!done && gLayoutTestController->willSendRequestReturnsNullOnRedirect() && redirectResponse) { + printf("Returning null for this redirect\n"); + *newRequest = 0; + return S_OK; + } + + IWebMutableURLRequest* requestCopy = 0; + request->mutableCopy(&requestCopy); + const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders(); + for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header) { + BSTR bstrHeader = BSTRFromString(*header); + requestCopy->setValue(0, bstrHeader); + SysFreeString(bstrHeader); + } + + *newRequest = requestCopy; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didReceiveAuthenticationChallenge( + /* [in] */ IWebView *webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebURLAuthenticationChallenge *challenge, + /* [in] */ IWebDataSource *dataSource) +{ + COMPtr<IWebURLAuthenticationChallengeSender> sender; + if (!challenge || FAILED(challenge->sender(&sender))) + return E_FAIL; + + if (!gLayoutTestController->handlesAuthenticationChallenges()) { + printf("%S - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet\n", descriptionSuitableForTestResult(identifier).c_str()); + sender->continueWithoutCredentialForAuthenticationChallenge(challenge); + return S_OK; + } + + const char* user = gLayoutTestController->authenticationUsername().c_str(); + const char* password = gLayoutTestController->authenticationPassword().c_str(); + + printf("%S - didReceiveAuthenticationChallenge - Responding with %s:%s\n", descriptionSuitableForTestResult(identifier).c_str(), user, password); + + COMPtr<IWebURLCredential> credential; + if (FAILED(WebKitCreateInstance(CLSID_WebURLCredential, 0, IID_IWebURLCredential, (void**)&credential))) + return E_FAIL; + credential->initWithUser(_bstr_t(user), _bstr_t(password), WebURLCredentialPersistenceForSession); + + sender->useCredential(credential.get(), challenge); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didReceiveResponse( + /* [in] */ IWebView* webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebURLResponse* response, + /* [in] */ IWebDataSource* dataSource) +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + printf("%S - didReceiveResponse %S\n", + descriptionSuitableForTestResult(identifier).c_str(), + descriptionSuitableForTestResult(response).c_str()); + } + if (!done && gLayoutTestController->dumpResourceResponseMIMETypes()) { + BSTR mimeTypeBSTR; + if (FAILED(response->MIMEType(&mimeTypeBSTR))) + E_FAIL; + + wstring mimeType = wstringFromBSTR(mimeTypeBSTR); + ::SysFreeString(mimeTypeBSTR); + + BSTR urlBSTR; + if (FAILED(response->URL(&urlBSTR))) + E_FAIL; + + wstring url = wstringFromBSTR(urlBSTR); + ::SysFreeString(urlBSTR); + + printf("%S has MIME type %S\n", lastPathComponent(url).c_str(), mimeType.c_str()); + } + + return S_OK; +} + + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFinishLoadingFromDataSource( + /* [in] */ IWebView* webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebDataSource* dataSource) +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + printf("%S - didFinishLoading\n", + descriptionSuitableForTestResult(identifier).c_str()); + } + + removeIdentifierForRequest(webView, identifier); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFailLoadingWithError( + /* [in] */ IWebView* webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebError* error, + /* [in] */ IWebDataSource* dataSource) +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + printf("%S - didFailLoadingWithError: %S\n", + descriptionSuitableForTestResult(identifier).c_str(), + descriptionSuitableForTestResult(error, identifier).c_str()); + } + + removeIdentifierForRequest(webView, identifier); + + return S_OK; +} |