[GTK] Add authentication support to DRT and fix exposed issues in the libsoup backend
authormrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Dec 2012 19:20:08 +0000 (19:20 +0000)
committermrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Dec 2012 19:20:08 +0000 (19:20 +0000)
https://bugs.webkit.org/show_bug.cgi?id=104285

Reviewed by Gustavo Noronha Silva.

Source/WebCore:

Fix issues in the libsoup networking backend that were causing test
failures.

No new tests. This patch unskips authentication tests.

* platform/network/soup/ResourceHandleSoup.cpp:
(WebCore::isAuthenticationFailureStatusCode): Added this helper to catch authentication status codes
and use it everywhere.
(WebCore::applyAuthenticationToRequest): Use an early return instead of an if-statement
and instead of always using manually specified credentials, apply those found in the session
storage as well. Instead of applying the credentials to firstRequest always, accept the request
as a parameter, so this method can be properly used with redirects.
(WebCore::restartedCallback): Instead of creating the KURL directly from soup_uri_to_string
use soupURIToKURL, which preserves the password from the SoupURI. soup_uri_to_string doesn't
include the password. When calling applyAuthenticationToRequest update the new request. Before
applyAuthenticationToRequest always updated the firstRequest. Do not call willSendRequest for
instances when this method is called for authentication handling. willSendRequest should only
be called for server-side redirects.
(WebCore::createSoupRequestAndMessageForHandle): Use soup_requester_request_uri instead of
soup_requester_request. Request::soupURI properly creates a SoupURI with non-null empty strings
when either the username and password are empty.  A null username or password does not trigger
the URI-embedded credential override in SoupAuthenticationManager within libsoup. This is important
because sometimes either the username or password might empty for a request, but the other
part of the credential should still override the per-session credential storage.
(WebCore::ResourceHandle::start): We don't need to clear the username and password from the
internal data structure any longer. These need to be cleared in the CFNetwork backend because
it prevents the same failed per-request credentials from being used over and over again. In our
case we don't use these members during didReceiveAuthenticationChallenge, so this isn't an issue.
(WebCore::ResourceHandle::didReceiveAuthenticationChallenge): Don't look at the per-request
m_user/m_pass pair here any longer. We use these when initially creating a request, so we don't
want to re-use them if they fail.
* platform/network/soup/ResourceRequest.h:
(ResourceRequest): Rename urlStringForSoup to soupURI.
* platform/network/soup/ResourceRequestSoup.cpp:
(WebCore::ResourceRequest::soupURI): Instead of returning a string for the soup-bound URL
return a SoupURI that properly embeds empty usernames and passwords.

Source/WebKit/gtk:

Add support to DumpRenderTree for running authentication tests. Since the DRT
expects an authentication callback, we add one to DRTSupport to avoid #ifdefs
in platform-independent code for GTK+.

* WebCoreSupport/DumpRenderTreeSupportGtk.cpp:
(DumpRenderTreeSupportGtk::setAuthenticationCallback): Added.
* WebCoreSupport/DumpRenderTreeSupportGtk.h:
(DumpRenderTreeSupportGtk): Add a method to set the authentication callback.
* WebCoreSupport/FrameLoaderClientGtk.cpp:
(WebKit::FrameLoaderClient::dispatchDidReceiveAuthenticationChallenge): When
in DRT mode we need to call the authentication callback instead of popping
up the dialog or ignoring the request.

Tools:

Add support to DumpRenderTree for running authentication tests. Since the DRT
expects an authentication callback, we add one to DRTSupport to avoid #ifdefs
in platform-independent code for GTK+.

* DumpRenderTree/gtk/DumpRenderTree.cpp:
(resetDefaultsToConsistentValues): Reset the authentication password and username.
(authenticationCallback): Added.
(createWebView): Attach the authentiation callback during startup.
* DumpRenderTree/gtk/TestRunnerGtk.cpp:
(soupURIToKURL): soup_uri_to_string does not preserve passwords embedded
in the URL so we add a somewhat messy method of re-adding them when they exist.
It would be nice to use soupURIToKURL here, but it seems we cannot use KURL without
pulling in lots of WebCore code so we use string search and replace.
(TestRunner::queueLoad): Use the new helper.

LayoutTests:

Unskip authentication tests now that authentication support is in
the harness and issues in the libsoup backend are fixed. Also remove
two expected results for tests that now have the same output as
other platforms.

* platform/gtk/TestExpectations:
* platform/gtk/http/tests/misc/401-alternative-content-expected.txt: Removed.
* platform/gtk/http/tests/xmlhttprequest/failed-auth-expected.txt: Removed.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@137487 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/gtk/TestExpectations
LayoutTests/platform/gtk/http/tests/misc/401-alternative-content-expected.txt [deleted file]
LayoutTests/platform/gtk/http/tests/xmlhttprequest/failed-auth-expected.txt [deleted file]
Source/WebCore/ChangeLog
Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp
Source/WebCore/platform/network/soup/ResourceRequest.h
Source/WebCore/platform/network/soup/ResourceRequestSoup.cpp
Source/WebKit/gtk/ChangeLog
Source/WebKit/gtk/WebCoreSupport/DumpRenderTreeSupportGtk.cpp
Source/WebKit/gtk/WebCoreSupport/DumpRenderTreeSupportGtk.h
Source/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp
Tools/ChangeLog
Tools/DumpRenderTree/gtk/DumpRenderTree.cpp
Tools/DumpRenderTree/gtk/TestRunnerGtk.cpp

index 8b8768b..a216761 100644 (file)
@@ -1,3 +1,19 @@
+2012-12-12  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Add authentication support to DRT and fix exposed issues in the libsoup backend
+        https://bugs.webkit.org/show_bug.cgi?id=104285
+
+        Reviewed by Gustavo Noronha Silva.
+
+        Unskip authentication tests now that authentication support is in
+        the harness and issues in the libsoup backend are fixed. Also remove
+        two expected results for tests that now have the same output as
+        other platforms.
+
+        * platform/gtk/TestExpectations:
+        * platform/gtk/http/tests/misc/401-alternative-content-expected.txt: Removed.
+        * platform/gtk/http/tests/xmlhttprequest/failed-auth-expected.txt: Removed.
+
 2012-12-12  Chris Fleizach  <cfleizach@apple.com>
 
         AX: aria-busy should be exposed everywhere, not just on live regions
index 4d66746..2c9c60a 100644 (file)
@@ -890,18 +890,6 @@ webkit.org/b/30620 fast/xsl/sort-locale.xml [ Failure ]
 
 webkit.org/b/53986 svg/text/caret-in-svg-text.xhtml [ Failure ]
 
-# No authentication challenge handling
-webkit.org/b/51104 http/tests/loading/authentication-after-redirect-stores-wrong-credentials/authentication-after-redirect-stores-wrong-credentials.html [ Skip ]
-webkit.org/b/51104 http/tests/loading/basic-auth-resend-wrong-credentials.html [ Failure ]
-webkit.org/b/51104 http/tests/loading/basic-credentials-sent-automatically.html [ Failure ]
-webkit.org/b/51104 http/tests/misc/authentication-redirect-1/authentication-sent-to-redirect-cross-origin.html [ Failure ]
-webkit.org/b/51104 http/tests/misc/authentication-redirect-2/authentication-sent-to-redirect-same-origin.html [ Failure ]
-webkit.org/b/51104 http/tests/misc/authentication-redirect-3/authentication-sent-to-redirect-same-origin-with-location-credentials.html [ Failure ]
-webkit.org/b/51104 http/tests/security/401-logout/401-logout.php [ Skip ]
-webkit.org/b/51104 http/tests/xmlhttprequest/basic-auth-nouser.html [ Failure ]
-webkit.org/b/51104 http/tests/xmlhttprequest/basic-auth-nopassword.html [ Failure ]
-webkit.org/b/51104 http/tests/xmlhttprequest/remember-bad-password.html [ Failure ]
-
 # This port doesn't have a global history delegate yet
 Bug(GTK) http/tests/globalhistory [ Failure ]
 
diff --git a/LayoutTests/platform/gtk/http/tests/misc/401-alternative-content-expected.txt b/LayoutTests/platform/gtk/http/tests/misc/401-alternative-content-expected.txt
deleted file mode 100644 (file)
index 7ef22e9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-PASS
diff --git a/LayoutTests/platform/gtk/http/tests/xmlhttprequest/failed-auth-expected.txt b/LayoutTests/platform/gtk/http/tests/xmlhttprequest/failed-auth-expected.txt
deleted file mode 100644 (file)
index cc27c84..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-Test for bug 13075: XMLHttpRequest with failed authentication should set status to 401.
-
-Sync, no credentials: OK
-Sync, incorrect credentials: OK
-Async, no credentials: OK
-Async, incorrect credentials: OK
index dbd5670..906ddd0 100644 (file)
@@ -1,3 +1,47 @@
+2012-12-12  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Add authentication support to DRT and fix exposed issues in the libsoup backend
+        https://bugs.webkit.org/show_bug.cgi?id=104285
+
+        Reviewed by Gustavo Noronha Silva.
+
+        Fix issues in the libsoup networking backend that were causing test
+        failures.
+
+        No new tests. This patch unskips authentication tests.
+
+        * platform/network/soup/ResourceHandleSoup.cpp:
+        (WebCore::isAuthenticationFailureStatusCode): Added this helper to catch authentication status codes
+        and use it everywhere.
+        (WebCore::applyAuthenticationToRequest): Use an early return instead of an if-statement
+        and instead of always using manually specified credentials, apply those found in the session
+        storage as well. Instead of applying the credentials to firstRequest always, accept the request
+        as a parameter, so this method can be properly used with redirects.
+        (WebCore::restartedCallback): Instead of creating the KURL directly from soup_uri_to_string
+        use soupURIToKURL, which preserves the password from the SoupURI. soup_uri_to_string doesn't
+        include the password. When calling applyAuthenticationToRequest update the new request. Before
+        applyAuthenticationToRequest always updated the firstRequest. Do not call willSendRequest for
+        instances when this method is called for authentication handling. willSendRequest should only
+        be called for server-side redirects.
+        (WebCore::createSoupRequestAndMessageForHandle): Use soup_requester_request_uri instead of
+        soup_requester_request. Request::soupURI properly creates a SoupURI with non-null empty strings
+        when either the username and password are empty.  A null username or password does not trigger
+        the URI-embedded credential override in SoupAuthenticationManager within libsoup. This is important
+        because sometimes either the username or password might empty for a request, but the other
+        part of the credential should still override the per-session credential storage.
+        (WebCore::ResourceHandle::start): We don't need to clear the username and password from the
+        internal data structure any longer. These need to be cleared in the CFNetwork backend because
+        it prevents the same failed per-request credentials from being used over and over again. In our
+        case we don't use these members during didReceiveAuthenticationChallenge, so this isn't an issue.
+        (WebCore::ResourceHandle::didReceiveAuthenticationChallenge): Don't look at the per-request
+        m_user/m_pass pair here any longer. We use these when initially creating a request, so we don't
+        want to re-use them if they fail.
+        * platform/network/soup/ResourceRequest.h:
+        (ResourceRequest): Rename urlStringForSoup to soupURI.
+        * platform/network/soup/ResourceRequestSoup.cpp:
+        (WebCore::ResourceRequest::soupURI): Instead of returning a string for the soup-bound URL
+        return a SoupURI that properly embeds empty usernames and passwords.
+
 2012-12-12  Alexey Proskuryakov  <ap@apple.com>
 
         Make LOG() work in WebProcess and NetworkProcess
index 9f607a7..a40393d 100644 (file)
@@ -47,6 +47,7 @@
 #include "ResourceHandleInternal.h"
 #include "ResourceResponse.h"
 #include "SharedBuffer.h"
+#include "SoupURIUtils.h"
 #include "TextEncoding.h"
 #include <errno.h>
 #include <fcntl.h>
@@ -296,6 +297,11 @@ SoupSession* ResourceHandleInternal::soupSession()
     return session;
 }
 
+static bool isAuthenticationFailureStatusCode(int httpStatusCode)
+{
+    return httpStatusCode == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED || httpStatusCode == SOUP_STATUS_UNAUTHORIZED;
+}
+
 static void gotHeadersCallback(SoupMessage* message, gpointer data)
 {
     ResourceHandle* handle = static_cast<ResourceHandle*>(data);
@@ -315,7 +321,7 @@ static void gotHeadersCallback(SoupMessage* message, gpointer data)
     // since we are waiting until we know that this authentication succeeded before actually storing.
     // This is because we want to avoid hitting the disk twice (once to add and once to remove) for
     // incorrect credentials or polluting the keychain with invalid credentials.
-    if (message->status_code != 401 && message->status_code < 500 && !d->m_credentialDataToSaveInPersistentStore.credential.isEmpty()) {
+    if (!isAuthenticationFailureStatusCode(message->status_code) && message->status_code < 500 && !d->m_credentialDataToSaveInPersistentStore.credential.isEmpty()) {
         credentialBackingStore().storeCredentialsForChallenge(
             d->m_credentialDataToSaveInPersistentStore.challenge,
             d->m_credentialDataToSaveInPersistentStore.credential);
@@ -330,14 +336,11 @@ static void gotHeadersCallback(SoupMessage* message, gpointer data)
     d->m_response = response;
 }
 
-static void applyAuthenticationToRequest(ResourceHandle* handle, bool redirect)
+static void applyAuthenticationToRequest(ResourceHandle* handle, ResourceRequest& request, bool redirect)
 {
     // m_user/m_pass are credentials given manually, for instance, by the arguments passed to XMLHttpRequest.open().
     ResourceHandleInternal* d = handle->getInternal();
-    String user = d->m_user;
-    String password = d->m_pass;
 
-    ResourceRequest& request = d->m_firstRequest;
     if (handle->shouldUseCredentialStorage()) {
         if (d->m_user.isEmpty() && d->m_pass.isEmpty())
             d->m_initialCredential = CredentialStorage::get(request.url());
@@ -350,20 +353,23 @@ static void applyAuthenticationToRequest(ResourceHandle* handle, bool redirect)
         }
     }
 
+    String user = d->m_user;
+    String password = d->m_pass;
     if (!d->m_initialCredential.isEmpty()) {
         user = d->m_initialCredential.user();
         password = d->m_initialCredential.password();
     }
 
+    if (user.isEmpty() && password.isEmpty())
+        return;
+
     // We always put the credentials into the URL. In the CFNetwork-port HTTP family credentials are applied in
     // the didReceiveAuthenticationChallenge callback, but libsoup requires us to use this method to override
     // any previously remembered credentials. It has its own per-session credential storage.
-    if (!user.isEmpty() || !password.isEmpty()) {
-        KURL urlWithCredentials(request.url());
-        urlWithCredentials.setUser(d->m_user);
-        urlWithCredentials.setPass(d->m_pass);
-        request.setURL(urlWithCredentials);
-    }
+    KURL urlWithCredentials(request.url());
+    urlWithCredentials.setUser(user);
+    urlWithCredentials.setPass(password);
+    request.setURL(urlWithCredentials);
 }
 
 // Called each time the message is going to be sent again except the first time.
@@ -377,12 +383,20 @@ static void restartedCallback(SoupMessage* message, gpointer data)
     if (d->m_cancelled)
         return;
 
-    GOwnPtr<char> uri(soup_uri_to_string(soup_message_get_uri(message), false));
-    String location = String::fromUTF8(uri.get());
-    KURL newURL = KURL(handle->firstRequest().url(), location);
+    ResourceResponse& redirectResponse = d->m_response;
+#if ENABLE(WEB_TIMING)
+    redirectResponse.setResourceLoadTiming(ResourceLoadTiming::create());
+    redirectResponse.resourceLoadTiming()->requestTime = monotonicallyIncreasingTime();
+#endif
+
+    // WebCore only expects us to call willSendRequest when we are redirecting. soup
+    // fires this signal also when it's handling authentication challenges, so in that
+    // case we should not willSendRequest.
+    if (isAuthenticationFailureStatusCode(redirectResponse.httpStatusCode()))
+        return;
 
     ResourceRequest request = handle->firstRequest();
-    request.setURL(newURL);
+    request.setURL(KURL(handle->firstRequest().url(), soupURIToKURL(soup_message_get_uri(message))));
     request.setHTTPMethod(message->method);
 
     // Should not set Referer after a redirect from a secure resource to non-secure one.
@@ -396,7 +410,6 @@ static void restartedCallback(SoupMessage* message, gpointer data)
     d->m_pass = url.pass();
     request.removeCredentials();
 
-    ResourceResponse& redirectResponse = d->m_response;
     if (!protocolHostAndPortAreEqual(request.url(), redirectResponse.url())) {
         // If the network layer carries over authentication headers from the original request
         // in a cross-origin redirect, we want to clear those headers here. 
@@ -406,10 +419,10 @@ static void restartedCallback(SoupMessage* message, gpointer data)
         // TODO: We are losing any username and password specified in the redirect URL, as this is the 
         // same behavior as the CFNet port. We should investigate if this is really what we want.
     } else
-        applyAuthenticationToRequest(handle, true);
+        applyAuthenticationToRequest(handle, request, true);
 
     // Per-request authentication is handled via the URI-embedded username/password.
-    GOwnPtr<SoupURI> newSoupURI(soup_uri_new(request.urlStringForSoup().utf8().data()));
+    GOwnPtr<SoupURI> newSoupURI(request.soupURI());
     soup_message_set_uri(message, newSoupURI.get());
 
     if (d->client())
@@ -418,11 +431,6 @@ static void restartedCallback(SoupMessage* message, gpointer data)
     if (d->m_cancelled)
         return;
 
-#if ENABLE(WEB_TIMING)
-    redirectResponse.setResourceLoadTiming(ResourceLoadTiming::create());
-    redirectResponse.resourceLoadTiming()->requestTime = monotonicallyIncreasingTime();
-#endif
-
     // Update the first party in case the base URL changed with the redirect
     String firstPartyString = request.firstPartyForCookies().string();
     if (!firstPartyString.isEmpty()) {
@@ -883,7 +891,8 @@ static bool createSoupRequestAndMessageForHandle(ResourceHandle* handle, bool is
     GOwnPtr<GError> error;
     ResourceRequest& request = handle->firstRequest();
 
-    d->m_soupRequest = adoptGRef(soup_requester_request(requester, request.urlStringForSoup().utf8().data(), &error.outPtr()));
+    GOwnPtr<SoupURI> soupURI(request.soupURI());
+    d->m_soupRequest = adoptGRef(soup_requester_request_uri(requester, soupURI.get(), &error.outPtr()));
     if (error) {
         d->m_soupRequest.clear();
         return false;
@@ -921,10 +930,7 @@ bool ResourceHandle::start(NetworkingContext* context)
         return true;
     }
 
-    applyAuthenticationToRequest(this, false);
-    // The CFNet backend clears these, so we do as well.
-    d->m_user = String();
-    d->m_pass = String();
+    applyAuthenticationToRequest(this, firstRequest(), false);
 
     if (!createSoupRequestAndMessageForHandle(this, isHTTPFamilyRequest)) {
         this->scheduleFailure(InvalidURLFailure); // Error must not be reported immediately
@@ -1022,17 +1028,8 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall
 {
     ASSERT(d->m_currentWebChallenge.isNull());
 
-    bool useCredentialStorage = shouldUseCredentialStorage();
-    if (!d->m_user.isNull() && !d->m_pass.isNull()) {
-        Credential credential = Credential(d->m_user, d->m_pass, CredentialPersistenceForSession);
-        if (useCredentialStorage)
-            CredentialStorage::set(credential, challenge.protectionSpace(), challenge.failureResponse().url());
-        soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data());
-
-        return;
-    }
-
     // FIXME: Per the specification, the user shouldn't be asked for credentials if there were incorrect ones provided explicitly.
+    bool useCredentialStorage = shouldUseCredentialStorage();
     if (useCredentialStorage) {
         if (!d->m_initialCredential.isEmpty() || challenge.previousFailureCount()) {
             // The stored credential wasn't accepted, stop using it. There is a race condition
@@ -1047,7 +1044,7 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall
                 ASSERT(credential.persistence() == CredentialPersistenceNone);
 
                 // Store the credential back, possibly adding it as a default for this directory.
-                if (challenge.failureResponse().httpStatusCode() == 401)
+                if (isAuthenticationFailureStatusCode(challenge.failureResponse().httpStatusCode()))
                     CredentialStorage::set(credential, challenge.protectionSpace(), challenge.failureResponse().url());
 
                 soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data());
index 8ce00fb..d8fe011 100644 (file)
@@ -74,7 +74,7 @@ namespace WebCore {
         SoupMessageFlags soupMessageFlags() const { return m_soupFlags; }
         void setSoupMessageFlags(SoupMessageFlags soupFlags) { m_soupFlags = soupFlags; }
 
-        String urlStringForSoup() const;
+        SoupURI* soupURI() const;
 
     private:
         friend class ResourceRequestBase;
index 443402c..0dd4f4c 100644 (file)
@@ -119,7 +119,7 @@ unsigned initializeMaximumHTTPConnectionCountPerHost()
     return 10000;
 }
 
-String ResourceRequest::urlStringForSoup() const
+SoupURI* ResourceRequest::soupURI() const
 {
     // WebKit does not support fragment identifiers in data URLs, but soup does.
     // Before passing the URL to soup, we should make sure to urlencode any '#'
@@ -128,12 +128,22 @@ String ResourceRequest::urlStringForSoup() const
     if (m_url.protocolIsData()) {
         String urlString = m_url.string();
         urlString.replace("#", "%23");
-        return urlString;
+        return soup_uri_new(urlString.utf8().data());
     }
 
     KURL url = m_url;
     url.removeFragmentIdentifier();
-    return url.string();
+    SoupURI* uri = soup_uri_new(url.string().utf8().data());
+
+    // Versions of libsoup prior to 2.42 have a soup_uri_new that will convert empty passwords that are not
+    // prefixed by a colon into null. Some parts of soup like the SoupAuthenticationManager will only be active
+    // when both the username and password are non-null. When we have credentials, empty usernames and passwords
+    // should be empty strings instead of null.
+    if (!url.user().isEmpty() || !url.pass().isEmpty()) {
+        soup_uri_set_user(uri, url.user().utf8().data());
+        soup_uri_set_password(uri, url.pass().utf8().data());
+    }
+    return uri;
 }
 
 }
index ff3fd7a..890dbbc 100644 (file)
@@ -1,3 +1,23 @@
+2012-12-12  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Add authentication support to DRT and fix exposed issues in the libsoup backend
+        https://bugs.webkit.org/show_bug.cgi?id=104285
+
+        Reviewed by Gustavo Noronha Silva.
+
+        Add support to DumpRenderTree for running authentication tests. Since the DRT
+        expects an authentication callback, we add one to DRTSupport to avoid #ifdefs
+        in platform-independent code for GTK+.
+
+        * WebCoreSupport/DumpRenderTreeSupportGtk.cpp:
+        (DumpRenderTreeSupportGtk::setAuthenticationCallback): Added.
+        * WebCoreSupport/DumpRenderTreeSupportGtk.h:
+        (DumpRenderTreeSupportGtk): Add a method to set the authentication callback.
+        * WebCoreSupport/FrameLoaderClientGtk.cpp:
+        (WebKit::FrameLoaderClient::dispatchDidReceiveAuthenticationChallenge): When
+        in DRT mode we need to call the authentication callback instead of popping
+        up the dialog or ignoring the request.
+
 2012-12-12  Alexey Proskuryakov  <ap@apple.com>
 
         Make LOG() work in WebProcess and NetworkProcess
index 2810710..19aa947 100644 (file)
@@ -85,6 +85,7 @@ bool DumpRenderTreeSupportGtk::s_drtRun = false;
 bool DumpRenderTreeSupportGtk::s_linksIncludedInTabChain = true;
 bool DumpRenderTreeSupportGtk::s_selectTrailingWhitespaceEnabled = false;
 DumpRenderTreeSupportGtk::FrameLoadEventCallback DumpRenderTreeSupportGtk::s_frameLoadEventCallback = 0;
+DumpRenderTreeSupportGtk::AuthenticationCallback DumpRenderTreeSupportGtk::s_authenticationCallback = 0;
 
 DumpRenderTreeSupportGtk::DumpRenderTreeSupportGtk()
 {
@@ -841,3 +842,8 @@ void DumpRenderTreeSupportGtk::setFrameLoadEventCallback(FrameLoadEventCallback
 {
     s_frameLoadEventCallback = frameLoadEventCallback;
 }
+
+void DumpRenderTreeSupportGtk::setAuthenticationCallback(AuthenticationCallback authenticationCallback)
+{
+    s_authenticationCallback = authenticationCallback;
+}
index 5a74d16..3b24f65 100644 (file)
@@ -146,6 +146,10 @@ public:
     static void setFrameLoadEventCallback(FrameLoadEventCallback);
     static FrameLoadEventCallback s_frameLoadEventCallback;
 
+    typedef bool (*AuthenticationCallback) (CString& username, CString& password);
+    static void setAuthenticationCallback(AuthenticationCallback);
+    static AuthenticationCallback s_authenticationCallback;
+
 private:
     static bool s_drtRun;
     static bool s_linksIncludedInTabChain;
index 2e11587..77408c2 100644 (file)
@@ -193,7 +193,14 @@ bool FrameLoaderClient::shouldUseCredentialStorage(WebCore::DocumentLoader*, uns
 void FrameLoaderClient::dispatchDidReceiveAuthenticationChallenge(WebCore::DocumentLoader*, unsigned long  identifier, const AuthenticationChallenge& challenge)
 {
     if (DumpRenderTreeSupportGtk::dumpRenderTreeModeEnabled()) {
-        challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
+        CString username;
+        CString password;
+        if (!DumpRenderTreeSupportGtk::s_authenticationCallback || !DumpRenderTreeSupportGtk::s_authenticationCallback(username, password)) {
+            challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
+            return;
+        }
+
+        challenge.authenticationClient()->receivedCredential(challenge, Credential(String::fromUTF8(username.data()), String::fromUTF8(password.data()), CredentialPersistenceForSession));
         return;
     }
 
index 78f96f0..31c56b7 100644 (file)
@@ -1,3 +1,25 @@
+2012-12-12  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Add authentication support to DRT and fix exposed issues in the libsoup backend
+        https://bugs.webkit.org/show_bug.cgi?id=104285
+
+        Reviewed by Gustavo Noronha Silva.
+
+        Add support to DumpRenderTree for running authentication tests. Since the DRT
+        expects an authentication callback, we add one to DRTSupport to avoid #ifdefs
+        in platform-independent code for GTK+.
+
+        * DumpRenderTree/gtk/DumpRenderTree.cpp:
+        (resetDefaultsToConsistentValues): Reset the authentication password and username.
+        (authenticationCallback): Added.
+        (createWebView): Attach the authentiation callback during startup.
+        * DumpRenderTree/gtk/TestRunnerGtk.cpp:
+        (soupURIToKURL): soup_uri_to_string does not preserve passwords embedded
+        in the URL so we add a somewhat messy method of re-adding them when they exist.
+        It would be nice to use soupURIToKURL here, but it seems we cannot use KURL without
+        pulling in lots of WebCore code so we use string search and replace.
+        (TestRunner::queueLoad): Use the new helper.
+
 2012-12-12  Dirk Pranke  <dpranke@chromium.org>
 
         garden-o-matic should prefer efl/ over efl-wk1/ and efl-wk2/ when rebaselining
index 4d66ca3..8e53829 100644 (file)
@@ -520,6 +520,12 @@ static void resetDefaultsToConsistentValues()
     DumpRenderTreeSupportGtk::setExperimentalContentSecurityPolicyFeaturesEnabled(true);
     DumpRenderTreeSupportGtk::setShadowDOMEnabled(true);
     DumpRenderTreeSupportGtk::setStyleScopedEnabled(true);
+
+    if (gTestRunner) {
+        gTestRunner->setAuthenticationPassword("");
+        gTestRunner->setAuthenticationUsername("");
+        gTestRunner->setHandlesAuthenticationChallenges(false);
+    }
 }
 
 static bool useLongRunningServerMode(int argc, char *argv[])
@@ -1362,6 +1368,19 @@ static void frameLoadEventCallback(WebKitWebFrame* frame, DumpRenderTreeSupportG
     }
 }
 
+static bool authenticationCallback(CString& username, CString& password)
+{
+    if (!gTestRunner->handlesAuthenticationChallenges()) {
+        printf("<unknown> - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet\n");
+        return false;
+    }
+
+    username = gTestRunner->authenticationUsername().c_str();
+    password = gTestRunner->authenticationPassword().c_str();
+    printf("<unknown> - didReceiveAuthenticationChallenge - Responding with %s:%s\n", username.data(), password.data());
+    return true;
+}
+
 static WebKitWebView* createWebView()
 {
     // It is important to declare DRT is running early so when creating
@@ -1369,6 +1388,7 @@ static WebKitWebView* createWebView()
     DumpRenderTreeSupportGtk::setDumpRenderTreeModeEnabled(true);
 
     DumpRenderTreeSupportGtk::setFrameLoadEventCallback(frameLoadEventCallback);
+    DumpRenderTreeSupportGtk::setAuthenticationCallback(authenticationCallback);
 
     WebKitWebView* view = WEBKIT_WEB_VIEW(self_scrolling_webkit_web_view_new());
 
index c04ba36..452b07d 100644 (file)
@@ -48,6 +48,7 @@
 #include <libsoup/soup.h>
 #include <webkit/webkit.h>
 #include <wtf/gobject/GOwnPtr.h>
+#include <wtf/text/WTFString.h>
 
 extern "C" {
 void webkit_web_inspector_execute_script(WebKitWebInspector* inspector, long callId, const gchar* script);
@@ -157,26 +158,43 @@ JSStringRef TestRunner::pathToLocalResource(JSContextRef context, JSStringRef ur
     return JSStringCreateWithUTF8CString(testURI.get());
 }
 
+static CString soupURIToStringPreservingPassword(SoupURI* soupURI)
+{
+    if (!soupURI->password) {
+        GOwnPtr<char> uriString(soup_uri_to_string(soupURI, FALSE));
+        return uriString.get();
+    }
+
+    // soup_uri_to_string does not insert the password into the string, so we need to create the
+    // URI string and then reinsert any credentials that were present in the SoupURI. All tests that
+    // use URL-embedded credentials use HTTP, so it's safe here.
+    GOwnPtr<char> password(soupURI->password);
+    GOwnPtr<char> user(soupURI->user);
+    soupURI->password = 0;
+    soupURI->user = 0;
+
+    GOwnPtr<char> uriString(soup_uri_to_string(soupURI, FALSE));
+    String absoluteURIWithoutCredentialString = String::fromUTF8(uriString.get());
+    String protocolAndCredential = String::format("http://%s:%s@", user ? user.get() : "", password.get());
+    return absoluteURIWithoutCredentialString.replace("http://", protocolAndCredential).utf8();
+}
+
 void TestRunner::queueLoad(JSStringRef url, JSStringRef target)
 {
-    gchar* relativeURL = JSStringCopyUTF8CString(url);
+    GOwnPtr<gchar> relativeURL(JSStringCopyUTF8CString(url));
     SoupURI* baseURI = soup_uri_new(webkit_web_frame_get_uri(mainFrame));
-
-    SoupURI* absoluteURI = soup_uri_new_with_base(baseURI, relativeURL);
+    SoupURI* absoluteURI = soup_uri_new_with_base(baseURI, relativeURL.get());
     soup_uri_free(baseURI);
-    g_free(relativeURL);
-
-    gchar* absoluteCString;
-    if (absoluteURI) {
-        absoluteCString = soup_uri_to_string(absoluteURI, FALSE);
-        soup_uri_free(absoluteURI);
-    } else
-        absoluteCString = JSStringCopyUTF8CString(url);
 
-    JSRetainPtr<JSStringRef> absoluteURL(Adopt, JSStringCreateWithUTF8CString(absoluteCString));
-    g_free(absoluteCString);
+    if (!absoluteURI) {
+        WorkQueue::shared()->queue(new LoadItem(url, target));
+        return;
+    }
 
+    CString absoluteURIString = soupURIToStringPreservingPassword(absoluteURI);
+    JSRetainPtr<JSStringRef> absoluteURL(Adopt, JSStringCreateWithUTF8CString(absoluteURIString.data()));
     WorkQueue::shared()->queue(new LoadItem(absoluteURL.get(), target));
+    soup_uri_free(absoluteURI);
 }
 
 void TestRunner::setAcceptsEditing(bool acceptsEditing)