summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/network
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/network')
-rw-r--r--WebCore/platform/network/Credential.cpp3
-rw-r--r--WebCore/platform/network/Credential.h2
-rw-r--r--WebCore/platform/network/CredentialStorage.cpp125
-rw-r--r--WebCore/platform/network/CredentialStorage.h6
-rw-r--r--WebCore/platform/network/FormDataBuilder.cpp38
-rw-r--r--WebCore/platform/network/ResourceRequestBase.cpp24
-rw-r--r--WebCore/platform/network/ResourceRequestBase.h4
-rw-r--r--WebCore/platform/network/cf/ResourceHandleCFNet.cpp22
-rw-r--r--WebCore/platform/network/cf/ResourceRequestCFNet.cpp24
-rw-r--r--WebCore/platform/network/chromium/ResourceRequest.cpp34
-rw-r--r--WebCore/platform/network/curl/ResourceHandleCurl.cpp2
-rw-r--r--WebCore/platform/network/curl/ResourceHandleManager.cpp32
-rw-r--r--WebCore/platform/network/curl/ResourceHandleManager.h19
-rw-r--r--WebCore/platform/network/mac/AuthenticationMac.mm3
-rw-r--r--WebCore/platform/network/mac/ResourceHandleMac.mm45
-rw-r--r--WebCore/platform/network/mac/ResourceRequestMac.mm7
-rw-r--r--WebCore/platform/network/qt/QNetworkReplyHandler.cpp15
-rw-r--r--WebCore/platform/network/qt/QNetworkReplyHandler.h4
18 files changed, 307 insertions, 102 deletions
diff --git a/WebCore/platform/network/Credential.cpp b/WebCore/platform/network/Credential.cpp
index caca785..f905743 100644
--- a/WebCore/platform/network/Credential.cpp
+++ b/WebCore/platform/network/Credential.cpp
@@ -32,6 +32,7 @@ namespace WebCore {
Credential::Credential()
: m_user("")
, m_password("")
+ , m_persistence(CredentialPersistenceNone)
{
}
@@ -44,7 +45,7 @@ Credential::Credential(const String& user, const String& password, CredentialPer
{
}
-bool Credential::isEmpty()
+bool Credential::isEmpty() const
{
return m_user.isEmpty() && m_password.isEmpty();
}
diff --git a/WebCore/platform/network/Credential.h b/WebCore/platform/network/Credential.h
index ca4a45a..0471fbc 100644
--- a/WebCore/platform/network/Credential.h
+++ b/WebCore/platform/network/Credential.h
@@ -41,7 +41,7 @@ public:
Credential();
Credential(const String& user, const String& password, CredentialPersistence);
- bool isEmpty();
+ bool isEmpty() const;
const String& user() const;
const String& password() const;
diff --git a/WebCore/platform/network/CredentialStorage.cpp b/WebCore/platform/network/CredentialStorage.cpp
index 407ed5b..ec78372 100644
--- a/WebCore/platform/network/CredentialStorage.cpp
+++ b/WebCore/platform/network/CredentialStorage.cpp
@@ -43,13 +43,19 @@ static ProtectionSpaceToCredentialMap& protectionSpaceToCredentialMap()
return map;
}
-typedef HashMap<String, HashMap<String, Credential> > OriginToDefaultBasicCredentialMap;
-static OriginToDefaultBasicCredentialMap& originToDefaultBasicCredentialMap()
+static HashSet<String>& originsWithCredentials()
{
- DEFINE_STATIC_LOCAL(OriginToDefaultBasicCredentialMap, map, ());
+ DEFINE_STATIC_LOCAL(HashSet<String>, set, ());
+ return set;
+}
+
+typedef HashMap<String, ProtectionSpace> PathToDefaultProtectionSpaceMap;
+static PathToDefaultProtectionSpaceMap& pathToDefaultProtectionSpaceMap()
+{
+ DEFINE_STATIC_LOCAL(PathToDefaultProtectionSpaceMap, map, ());
return map;
}
-
+
static String originStringFromURL(const KURL& url)
{
if (url.port())
@@ -58,32 +64,37 @@ static String originStringFromURL(const KURL& url)
return url.protocol() + "://" + url.host() + "/";
}
+static String protectionSpaceMapKeyFromURL(const KURL& url)
+{
+ ASSERT(url.isValid());
+
+ // Remove the last path component that is not a directory to determine the subtree for which credentials will apply.
+ // We keep a leading slash, but remove a trailing one.
+ String directoryURL = url.string().substring(0, url.pathEnd());
+ unsigned directoryURLPathStart = url.pathStart();
+ ASSERT(directoryURL[directoryURLPathStart] == '/');
+ if (directoryURL.length() > directoryURLPathStart + 1) {
+ int index = directoryURL.reverseFind('/');
+ ASSERT(index > 0);
+ directoryURL = directoryURL.substring(0, (static_cast<unsigned>(index) != directoryURLPathStart) ? index : directoryURLPathStart + 1);
+ }
+ ASSERT(directoryURL.length() == directoryURLPathStart + 1 || directoryURL[directoryURL.length() - 1] != '/');
+
+ return directoryURL;
+}
+
void CredentialStorage::set(const Credential& credential, const ProtectionSpace& protectionSpace, const KURL& url)
{
ASSERT(url.protocolInHTTPFamily());
ASSERT(url.isValid());
protectionSpaceToCredentialMap().set(protectionSpace, credential);
-
+ originsWithCredentials().add(originStringFromURL(url));
+
ProtectionSpaceAuthenticationScheme scheme = protectionSpace.authenticationScheme();
- if (url.protocolInHTTPFamily() && (scheme == ProtectionSpaceAuthenticationSchemeHTTPBasic || scheme == ProtectionSpaceAuthenticationSchemeDefault)) {
- String origin = originStringFromURL(url);
-
- HashMap<String, Credential> pathToCredentialMap;
- pair<HashMap<String, HashMap<String, Credential> >::iterator, bool> result = originToDefaultBasicCredentialMap().add(origin, pathToCredentialMap);
-
- // Remove the last path component that is not a directory to determine the subpath for which this credential applies.
- // We keep a leading slash, but remove a trailing one.
- String path = url.path();
- ASSERT(path.length() > 0);
- ASSERT(path[0] == '/');
- if (path.length() > 1) {
- int index = path.reverseFind('/');
- path = path.substring(0, index ? index : 1);
- }
- ASSERT(path.length() == 1 || path[path.length() - 1] != '/');
-
- result.first->second.set(path, credential);
+ if (scheme == ProtectionSpaceAuthenticationSchemeHTTPBasic || scheme == ProtectionSpaceAuthenticationSchemeDefault) {
+ // The map can contain both a path and its subpath - while redundant, this makes lookups faster.
+ pathToDefaultProtectionSpaceMap().set(protectionSpaceMapKeyFromURL(url), protectionSpace);
}
}
@@ -92,33 +103,53 @@ Credential CredentialStorage::get(const ProtectionSpace& protectionSpace)
return protectionSpaceToCredentialMap().get(protectionSpace);
}
-Credential CredentialStorage::getDefaultAuthenticationCredential(const KURL& url)
+static PathToDefaultProtectionSpaceMap::iterator findDefaultProtectionSpaceForURL(const KURL& url)
{
ASSERT(url.protocolInHTTPFamily());
- String origin = originStringFromURL(url);
- const HashMap<String, Credential>& pathToCredentialMap(originToDefaultBasicCredentialMap().get(origin));
- if (pathToCredentialMap.isEmpty())
- return Credential();
-
- // Check to see if there is a stored credential for the subpath ancestry of this url.
- String path = url.path();
- Credential credential = pathToCredentialMap.get(path);
- while (credential.isEmpty() && !path.isNull()) {
- int index = path.reverseFind('/');
- if (index == 0) {
- credential = pathToCredentialMap.get("/");
- break;
- } else if (index == -1) {
- // This case should never happen, as all HTTP URL paths should start with a leading /
- ASSERT_NOT_REACHED();
- credential = pathToCredentialMap.get(path);
- break;
- } else {
- path = path.substring(0, index);
- credential = pathToCredentialMap.get(path);
- }
+ ASSERT(url.isValid());
+
+ PathToDefaultProtectionSpaceMap& map = pathToDefaultProtectionSpaceMap();
+
+ // Don't spend time iterating the path for origins that don't have any credentials.
+ if (!originsWithCredentials().contains(originStringFromURL(url)))
+ return map.end();
+
+ String directoryURL = protectionSpaceMapKeyFromURL(url);
+ unsigned directoryURLPathStart = url.pathStart();
+ while (true) {
+ PathToDefaultProtectionSpaceMap::iterator iter = map.find(directoryURL);
+ if (iter != map.end())
+ return iter;
+
+ if (directoryURL.length() == directoryURLPathStart + 1) // path is "/" already, cannot shorten it any more
+ return map.end();
+
+ int index = directoryURL.reverseFind('/', -2);
+ ASSERT(index > 0);
+ directoryURL = directoryURL.substring(0, (static_cast<unsigned>(index) == directoryURLPathStart) ? index + 1 : index);
+ ASSERT(directoryURL.length() > directoryURLPathStart);
+ ASSERT(directoryURL.length() == directoryURLPathStart + 1 || directoryURL[directoryURL.length() - 1] != '/');
}
- return credential;
+}
+
+bool CredentialStorage::set(const Credential& credential, const KURL& url)
+{
+ ASSERT(url.protocolInHTTPFamily());
+ ASSERT(url.isValid());
+ PathToDefaultProtectionSpaceMap::iterator iter = findDefaultProtectionSpaceForURL(url);
+ if (iter == pathToDefaultProtectionSpaceMap().end())
+ return false;
+ ASSERT(originsWithCredentials().contains(originStringFromURL(url)));
+ protectionSpaceToCredentialMap().set(iter->second, credential);
+ return true;
+}
+
+Credential CredentialStorage::get(const KURL& url)
+{
+ PathToDefaultProtectionSpaceMap::iterator iter = findDefaultProtectionSpaceForURL(url);
+ if (iter == pathToDefaultProtectionSpaceMap().end())
+ return Credential();
+ return protectionSpaceToCredentialMap().get(iter->second);
}
} // namespace WebCore
diff --git a/WebCore/platform/network/CredentialStorage.h b/WebCore/platform/network/CredentialStorage.h
index 737efa6..5086f69 100644
--- a/WebCore/platform/network/CredentialStorage.h
+++ b/WebCore/platform/network/CredentialStorage.h
@@ -36,7 +36,11 @@ class CredentialStorage {
public:
static void set(const Credential&, const ProtectionSpace&, const KURL&);
static Credential get(const ProtectionSpace&);
- static Credential getDefaultAuthenticationCredential(const KURL&);
+
+ // These methods work for authentication schemes that support sending credentials without waiting for a request. E.g., for HTTP Basic authentication scheme
+ // a client should assume that all paths at or deeper than the depth of a known protected resource share are within the same protection space.
+ static bool set(const Credential&, const KURL&); // Returns true if the URL corresponds to a known protection space, so credentials could be updated.
+ static Credential get(const KURL&);
};
} // namespace WebCore
diff --git a/WebCore/platform/network/FormDataBuilder.cpp b/WebCore/platform/network/FormDataBuilder.cpp
index 27bdee3..04c7527 100644
--- a/WebCore/platform/network/FormDataBuilder.cpp
+++ b/WebCore/platform/network/FormDataBuilder.cpp
@@ -108,6 +108,34 @@ static inline void append(Vector<char>& buffer, const CString& string)
buffer.append(string.data(), string.length());
}
+static void appendQuotedString(Vector<char>& buffer, const CString& string)
+{
+ // Append a string as a quoted value, escaping quotes and line breaks.
+ // FIXME: Is it correct to use percent escaping here? Other browsers do not encode these characters yet,
+ // so we should test popular servers to find out if there is an encoding form they can handle.
+ unsigned length = string.length();
+ for (unsigned i = 0; i < length; ++i) {
+ unsigned char c = string.data()[i];
+
+ switch (c) {
+ case 0x0a:
+ append(buffer, "%0A");
+ break;
+ case 0x0d:
+ append(buffer, "%0D");
+ break;
+ case '"':
+ append(buffer, "%22");
+ break;
+ case '%':
+ append(buffer, "%25");
+ break;
+ default:
+ append(buffer, c);
+ }
+ }
+}
+
Vector<char> FormDataBuilder::generateUniqueBoundaryString()
{
Vector<char> boundary;
@@ -161,8 +189,10 @@ void FormDataBuilder::beginMultiPartHeader(Vector<char>& buffer, const CString&
{
addBoundaryToMultiPartHeader(buffer, boundary);
+ // FIXME: This loses data irreversibly if the input name includes characters you can't encode
+ // in the website's character set.
append(buffer, "Content-Disposition: form-data; name=\"");
- append(buffer, name);
+ appendQuotedString(buffer, name);
append(buffer, '"');
}
@@ -179,12 +209,10 @@ void FormDataBuilder::addBoundaryToMultiPartHeader(Vector<char>& buffer, const C
void FormDataBuilder::addFilenameToMultiPartHeader(Vector<char>& buffer, const TextEncoding& encoding, const String& filename)
{
- // FIXME: This won't work if the filename includes a " mark,
- // or control characters like CR or LF. This also does strange
- // things if the filename includes characters you can't encode
+ // FIXME: This loses data irreversibly if the filename includes characters you can't encode
// in the website's character set.
append(buffer, "; filename=\"");
- append(buffer, encoding.encode(filename.characters(), filename.length(), QuestionMarksForUnencodables));
+ appendQuotedString(buffer, encoding.encode(filename.characters(), filename.length(), QuestionMarksForUnencodables));
append(buffer, '"');
}
diff --git a/WebCore/platform/network/ResourceRequestBase.cpp b/WebCore/platform/network/ResourceRequestBase.cpp
index ee11bcb..8ab72c1 100644
--- a/WebCore/platform/network/ResourceRequestBase.cpp
+++ b/WebCore/platform/network/ResourceRequestBase.cpp
@@ -218,6 +218,26 @@ void ResourceRequestBase::setHTTPHeaderField(const AtomicString& name, const Str
m_platformRequestUpdated = false;
}
+void ResourceRequestBase::clearHTTPReferrer()
+{
+ updateResourceRequest();
+
+ m_httpHeaderFields.remove("Referer");
+
+ if (url().protocolInHTTPFamily())
+ m_platformRequestUpdated = false;
+}
+
+void ResourceRequestBase::clearHTTPOrigin()
+{
+ updateResourceRequest();
+
+ m_httpHeaderFields.remove("Origin");
+
+ if (url().protocolInHTTPFamily())
+ m_platformRequestUpdated = false;
+}
+
void ResourceRequestBase::setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2, const String& encoding3)
{
updateResourceRequest();
@@ -358,7 +378,11 @@ void ResourceRequestBase::updateResourceRequest() const
m_resourceRequestUpdated = true;
}
+<<<<<<< HEAD:WebCore/platform/network/ResourceRequestBase.cpp
#if !PLATFORM(MAC) && !USE(CFNETWORK) && !USE(SOUP) && !PLATFORM(ANDROID)
+=======
+#if !PLATFORM(MAC) && !USE(CFNETWORK) && !USE(SOUP) && !PLATFORM(CHROMIUM)
+>>>>>>> webkit.org at r50258.:WebCore/platform/network/ResourceRequestBase.cpp
unsigned initializeMaximumHTTPConnectionCountPerHost()
{
// This is used by the loader to control the number of issued parallel load requests.
diff --git a/WebCore/platform/network/ResourceRequestBase.h b/WebCore/platform/network/ResourceRequestBase.h
index 348e6b3..84a7bd0 100644
--- a/WebCore/platform/network/ResourceRequestBase.h
+++ b/WebCore/platform/network/ResourceRequestBase.h
@@ -88,11 +88,11 @@ namespace WebCore {
String httpReferrer() const { return httpHeaderField("Referer"); }
void setHTTPReferrer(const String& httpReferrer) { setHTTPHeaderField("Referer", httpReferrer); }
- void clearHTTPReferrer() { m_httpHeaderFields.remove("Referer"); }
+ void clearHTTPReferrer();
String httpOrigin() const { return httpHeaderField("Origin"); }
void setHTTPOrigin(const String& httpOrigin) { setHTTPHeaderField("Origin", httpOrigin); }
- void clearHTTPOrigin() { m_httpHeaderFields.remove("Origin"); }
+ void clearHTTPOrigin();
String httpUserAgent() const { return httpHeaderField("User-Agent"); }
void setHTTPUserAgent(const String& httpUserAgent) { setHTTPHeaderField("User-Agent", httpUserAgent); }
diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
index ea5fcc6..38a9705 100644
--- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
+++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
@@ -156,7 +156,11 @@ CFURLRequestRef willSendRequest(CFURLConnectionRef conn, CFURLRequestRef cfReque
}
if (request.isNull())
request = cfRequest;
-
+
+ // Should not set Referer after a redirect from a secure resource to non-secure one.
+ if (!request.url().protocolIs("https") && protocolIs(request.httpReferrer(), "https"))
+ request.clearHTTPReferrer();
+
handle->willSendRequest(request, cfRedirectResponse);
if (request.isNull())
@@ -401,8 +405,18 @@ bool ResourceHandle::start(Frame* frame)
// <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication,
// try and reuse the credential preemptively, as allowed by RFC 2617.
- if (!client() || client()->shouldUseCredentialStorage(this) && d->m_request.url().protocolInHTTPFamily())
- d->m_initialCredential = CredentialStorage::getDefaultAuthenticationCredential(d->m_request.url());
+ if (!client() || client()->shouldUseCredentialStorage(this) && d->m_request.url().protocolInHTTPFamily()) {
+ if (d->m_user.isEmpty() && d->m_pass.isEmpty()) {
+ // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication,
+ // try and reuse the credential preemptively, as allowed by RFC 2617.
+ d->m_initialCredential = CredentialStorage::get(d->m_request.url());
+ } else {
+ // If there is already a protection space known for the URL, update stored credentials before sending a request.
+ // This makes it possible to implement logout by sending an XMLHttpRequest with known incorrect credentials, and aborting it immediately
+ // (so that an authentication dialog doesn't pop up).
+ CredentialStorage::set(Credential(d->m_user, d->m_pass, CredentialPersistenceNone), d->m_request.url());
+ }
+ }
if (!d->m_initialCredential.isEmpty()) {
String authHeader = "Basic " + encodeBasicAuthorization(d->m_initialCredential.user(), d->m_initialCredential.password());
@@ -769,7 +783,7 @@ RetainPtr<CFDataRef> WebCoreSynchronousLoader::load(const ResourceRequest& reque
// try and reuse the credential preemptively, as allowed by RFC 2617.
ResourceRequest requestWithInitialCredential(request);
if (loader.m_allowStoredCredentials && url.protocolInHTTPFamily())
- loader.m_initialCredential = CredentialStorage::getDefaultAuthenticationCredential(url);
+ loader.m_initialCredential = CredentialStorage::get(url);
if (!loader.m_initialCredential.isEmpty()) {
String authHeader = "Basic " + encodeBasicAuthorization(loader.m_initialCredential.user(), loader.m_initialCredential.password());
diff --git a/WebCore/platform/network/cf/ResourceRequestCFNet.cpp b/WebCore/platform/network/cf/ResourceRequestCFNet.cpp
index bba3d3e..cc0220e 100644
--- a/WebCore/platform/network/cf/ResourceRequestCFNet.cpp
+++ b/WebCore/platform/network/cf/ResourceRequestCFNet.cpp
@@ -39,9 +39,11 @@ typedef CFArrayRef (*CFURLRequestCopyContentDispositionEncodingFallbackArrayFunc
static HMODULE findCFNetworkModule()
{
- if (HMODULE module = GetModuleHandleA("CFNetwork"))
- return module;
+#ifndef DEBUG_ALL
+ return GetModuleHandleA("CFNetwork");
+#else
return GetModuleHandleA("CFNetwork_debug");
+#endif
}
static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction()
@@ -76,11 +78,18 @@ CFURLRequestRef ResourceRequest::cfURLRequest() const
return m_cfRequest.get();
}
-static inline void addHeadersFromHashMap(CFMutableURLRequestRef request, const HTTPHeaderMap& requestHeaders)
+static inline void setHeaderFields(CFMutableURLRequestRef request, const HTTPHeaderMap& requestHeaders)
{
- if (!requestHeaders.size())
- return;
-
+ // Remove existing headers first, as some of them may no longer be present in the map.
+ RetainPtr<CFDictionaryRef> oldHeaderFields(AdoptCF, CFURLRequestCopyAllHTTPHeaderFields(request));
+ CFIndex oldHeaderFieldCount = CFDictionaryGetCount(oldHeaderFields.get());
+ if (oldHeaderFieldCount) {
+ Vector<CFStringRef> oldHeaderFieldNames(oldHeaderFieldCount);
+ CFDictionaryGetKeysAndValues(oldHeaderFields.get(), reinterpret_cast<const void**>(&oldHeaderFieldNames[0]), 0);
+ for (CFIndex i = 0; i < oldHeaderFieldCount; ++i)
+ CFURLRequestSetHTTPHeaderFieldValue(request, oldHeaderFieldNames[i], 0);
+ }
+
HTTPHeaderMap::const_iterator end = requestHeaders.end();
for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) {
CFStringRef key = it->first.createCFString();
@@ -110,7 +119,7 @@ void ResourceRequest::doUpdatePlatformRequest()
RetainPtr<CFStringRef> requestMethod(AdoptCF, httpMethod().createCFString());
CFURLRequestSetHTTPRequestMethod(cfRequest, requestMethod.get());
- addHeadersFromHashMap(cfRequest, httpHeaderFields());
+ setHeaderFields(cfRequest, httpHeaderFields());
WebCore::setHTTPBody(cfRequest, httpBody());
CFURLRequestSetShouldHandleHTTPCookies(cfRequest, allowCookies());
@@ -148,6 +157,7 @@ void ResourceRequest::doUpdateResourceRequest()
}
m_allowCookies = CFURLRequestShouldHandleHTTPCookies(m_cfRequest.get());
+ m_httpHeaderFields.clear();
if (CFDictionaryRef headers = CFURLRequestCopyAllHTTPHeaderFields(m_cfRequest.get())) {
CFIndex headerCount = CFDictionaryGetCount(headers);
Vector<const void*, 128> keys(headerCount);
diff --git a/WebCore/platform/network/chromium/ResourceRequest.cpp b/WebCore/platform/network/chromium/ResourceRequest.cpp
new file mode 100644
index 0000000..76d1288
--- /dev/null
+++ b/WebCore/platform/network/chromium/ResourceRequest.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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.
+ *
+ * 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 COMPUTER, INC. OR
+ * 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.
+ */
+
+namespace WebCore {
+
+// This is used by the loader to control the number of issued parallel load requests.
+unsigned initializeMaximumHTTPConnectionCountPerHost()
+{
+ return 6;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/network/curl/ResourceHandleCurl.cpp b/WebCore/platform/network/curl/ResourceHandleCurl.cpp
index 5469ec9..5464e07 100644
--- a/WebCore/platform/network/curl/ResourceHandleCurl.cpp
+++ b/WebCore/platform/network/curl/ResourceHandleCurl.cpp
@@ -156,7 +156,7 @@ void ResourceHandle::setDefersLoading(bool defers)
if (d->m_defersLoading == defers)
return;
-#if LIBCURL_VERSION_NUM > 0x071200
+#if LIBCURL_VERSION_NUM > 0x071800
if (!d->m_handle)
d->m_defersLoading = defers;
else if (defers) {
diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp
index 14c6f31..d8a812f 100644
--- a/WebCore/platform/network/curl/ResourceHandleManager.cpp
+++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp
@@ -409,6 +409,25 @@ void ResourceHandleManager::downloadTimerCallback(Timer<ResourceHandleManager>*
m_downloadTimer.startOneShot(pollTimeSeconds);
}
+void ResourceHandleManager::setProxyInfo(const String& host,
+ unsigned long port,
+ ProxyType type,
+ const String& username,
+ const String& password)
+{
+ m_proxyType = type;
+
+ if (!host.length()) {
+ m_proxy = String("");
+ } else {
+ String userPass;
+ if (username.length() || password.length())
+ userPass = username + ":" + password + "@";
+
+ m_proxy = String("http://") + userPass + host + ":" + String::number(port);
+ }
+}
+
void ResourceHandleManager::removeFromCurl(ResourceHandle* job)
{
ResourceHandleInternal* d = job->getInternal();
@@ -678,7 +697,7 @@ void ResourceHandleManager::initializeHandle(ResourceHandle* job)
d->m_handle = curl_easy_init();
-#if LIBCURL_VERSION_NUM > 0x071200
+#if LIBCURL_VERSION_NUM > 0x071800
if (d->m_defersLoading) {
CURLcode error = curl_easy_pause(d->m_handle, CURLPAUSE_ALL);
// If we did not pause the handle, we would ASSERT in the
@@ -753,6 +772,17 @@ void ResourceHandleManager::initializeHandle(ResourceHandle* job)
curl_easy_setopt(d->m_handle, CURLOPT_HTTPHEADER, headers);
d->m_customHeaders = headers;
}
+ // curl CURLOPT_USERPWD expects username:password
+ if (d->m_user.length() || d->m_pass.length()) {
+ String userpass = d->m_user + ":" + d->m_pass;
+ curl_easy_setopt(d->m_handle, CURLOPT_USERPWD, userpass.utf8().data());
+ }
+
+ // Set proxy options if we have them.
+ if (m_proxy.length()) {
+ curl_easy_setopt(d->m_handle, CURLOPT_PROXY, m_proxy.utf8().data());
+ curl_easy_setopt(d->m_handle, CURLOPT_PROXYTYPE, m_proxyType);
+ }
}
void ResourceHandleManager::cancel(ResourceHandle* job)
diff --git a/WebCore/platform/network/curl/ResourceHandleManager.h b/WebCore/platform/network/curl/ResourceHandleManager.h
index 89b27d7..4d73d87 100644
--- a/WebCore/platform/network/curl/ResourceHandleManager.h
+++ b/WebCore/platform/network/curl/ResourceHandleManager.h
@@ -28,8 +28,9 @@
#ifndef ResourceHandleManager_h
#define ResourceHandleManager_h
-#include "Frame.h"
#include "CString.h"
+#include "Frame.h"
+#include "PlatformString.h"
#include "Timer.h"
#include "ResourceHandleClient.h"
@@ -45,6 +46,13 @@ namespace WebCore {
class ResourceHandleManager {
public:
+ enum ProxyType {
+ HTTP = CURLPROXY_HTTP,
+ Socks4 = CURLPROXY_SOCKS4,
+ Socks4A = CURLPROXY_SOCKS4A,
+ Socks5 = CURLPROXY_SOCKS5,
+ Socks5Hostname = CURLPROXY_SOCKS5_HOSTNAME
+ };
static ResourceHandleManager* sharedInstance();
void add(ResourceHandle*);
void cancel(ResourceHandle*);
@@ -55,6 +63,12 @@ public:
void setupPOST(ResourceHandle*, struct curl_slist**);
void setupPUT(ResourceHandle*, struct curl_slist**);
+ void setProxyInfo(const String& host = "",
+ unsigned long port = 0,
+ ProxyType type = HTTP,
+ const String& username = "",
+ const String& password = "");
+
private:
ResourceHandleManager();
~ResourceHandleManager();
@@ -74,6 +88,9 @@ private:
Vector<ResourceHandle*> m_resourceHandleList;
const CString m_certificatePath;
int m_runningJobs;
+
+ String m_proxy;
+ ProxyType m_proxyType;
};
}
diff --git a/WebCore/platform/network/mac/AuthenticationMac.mm b/WebCore/platform/network/mac/AuthenticationMac.mm
index 355931d..93725d5 100644
--- a/WebCore/platform/network/mac/AuthenticationMac.mm
+++ b/WebCore/platform/network/mac/AuthenticationMac.mm
@@ -150,6 +150,9 @@ NSURLProtectionSpace *mac(const ProtectionSpace& coreSpace)
NSURLCredential *mac(const Credential& coreCredential)
{
+ if (coreCredential.isEmpty())
+ return nil;
+
NSURLCredentialPersistence persistence = NSURLCredentialPersistenceNone;
switch (coreCredential.persistence()) {
case CredentialPersistenceNone:
diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm
index ec60079..3630b30 100644
--- a/WebCore/platform/network/mac/ResourceHandleMac.mm
+++ b/WebCore/platform/network/mac/ResourceHandleMac.mm
@@ -119,6 +119,7 @@ public:
}
};
+#ifndef BUILDING_ON_TIGER
static String encodeBasicAuthorization(const String& user, const String& password)
{
CString unencodedString = (user + ":" + password).utf8();
@@ -128,6 +129,7 @@ static String encodeBasicAuthorization(const String& user, const String& passwor
base64Encode(unencoded, encoded);
return String(encoded.data(), encoded.size());
}
+#endif
ResourceHandleInternal::~ResourceHandleInternal()
{
@@ -175,23 +177,38 @@ bool ResourceHandle::start(Frame* frame)
} else
delegate = ResourceHandle::delegate();
- if ((!d->m_user.isEmpty() || !d->m_pass.isEmpty()) && !d->m_request.url().protocolInHTTPFamily()) {
+ if ((!d->m_user.isEmpty() || !d->m_pass.isEmpty())
+#ifndef BUILDING_ON_TIGER
+ && !d->m_request.url().protocolInHTTPFamily() // On Tiger, always pass credentials in URL, so that they get stored even if the request gets cancelled right away.
+#endif
+ ) {
// Credentials for ftp can only be passed in URL, the connection:didReceiveAuthenticationChallenge: delegate call won't be made.
KURL urlWithCredentials(d->m_request.url());
urlWithCredentials.setUser(d->m_user);
urlWithCredentials.setPass(d->m_pass);
d->m_request.setURL(urlWithCredentials);
}
-
- // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication,
- // try and reuse the credential preemptively, as allowed by RFC 2617.
- if (!client() || client()->shouldUseCredentialStorage(this) && d->m_request.url().protocolInHTTPFamily())
- d->m_initialCredential = CredentialStorage::getDefaultAuthenticationCredential(d->m_request.url());
+
+#ifndef BUILDING_ON_TIGER
+ if ((!client() || client()->shouldUseCredentialStorage(this)) && d->m_request.url().protocolInHTTPFamily()) {
+ if (d->m_user.isEmpty() && d->m_pass.isEmpty()) {
+ // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication,
+ // try and reuse the credential preemptively, as allowed by RFC 2617.
+ d->m_initialCredential = CredentialStorage::get(d->m_request.url());
+ } else {
+ // If there is already a protection space known for the URL, update stored credentials before sending a request.
+ // This makes it possible to implement logout by sending an XMLHttpRequest with known incorrect credentials, and aborting it immediately
+ // (so that an authentication dialog doesn't pop up).
+ CredentialStorage::set(Credential(d->m_user, d->m_pass, CredentialPersistenceNone), d->m_request.url());
+ }
+ }
if (!d->m_initialCredential.isEmpty()) {
+ // FIXME: Support Digest authentication, and Proxy-Authorization.
String authHeader = "Basic " + encodeBasicAuthorization(d->m_initialCredential.user(), d->m_initialCredential.password());
d->m_request.addHTTPHeaderField("Authorization", authHeader);
}
+#endif
if (!ResourceHandle::didSendBodyDataDelegateExists())
associateStreamWithResourceHandle([d->m_request.nsURLRequest() HTTPBodyStream], this);
@@ -471,7 +488,7 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall
if (!d->m_user.isNull() && !d->m_pass.isNull()) {
NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:d->m_user
password:d->m_pass
- persistence:NSURLCredentialPersistenceNone];
+ persistence:NSURLCredentialPersistenceForSession];
d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge();
d->m_currentWebChallenge = challenge;
receivedCredential(challenge, core(credential));
@@ -482,6 +499,7 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall
return;
}
+#ifndef BUILDING_ON_TIGER
if (!challenge.previousFailureCount() && (!client() || client()->shouldUseCredentialStorage(this))) {
Credential credential = CredentialStorage::get(challenge.protectionSpace());
if (!credential.isEmpty() && credential != d->m_initialCredential) {
@@ -490,6 +508,7 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall
return;
}
}
+#endif
d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge();
NSURLAuthenticationChallenge *webChallenge = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:d->m_currentMacChallenge
@@ -521,11 +540,6 @@ void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge
if (credential.persistence() == CredentialPersistenceNone) {
// NSURLCredentialPersistenceNone doesn't work on Tiger, so we have to use session persistence.
Credential webCredential(credential.user(), credential.password(), CredentialPersistenceForSession);
- KURL urlToStore;
- if (challenge.failureResponse().httpStatusCode() == 401)
- urlToStore = d->m_request.url();
- CredentialStorage::set(webCredential, core([d->m_currentMacChallenge protectionSpace]), urlToStore);
-
[[d->m_currentMacChallenge sender] useCredential:mac(webCredential) forAuthenticationChallenge:d->m_currentMacChallenge];
} else
#else
@@ -620,6 +634,11 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen
CallbackGuard guard;
ResourceRequest request = newRequest;
+
+ // Should not set Referer after a redirect from a secure resource to non-secure one.
+ if (!request.url().protocolIs("https") && protocolIs(request.httpReferrer(), "https"))
+ request.clearHTTPReferrer();
+
m_handle->willSendRequest(request, redirectResponse);
if (!ResourceHandle::didSendBodyDataDelegateExists()) {
@@ -1055,7 +1074,7 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen
// try and reuse the credential preemptively, as allowed by RFC 2617.
ResourceRequest requestWithInitialCredentials = request;
if (allowStoredCredentials && url.protocolInHTTPFamily())
- delegate->m_initialCredential = CredentialStorage::getDefaultAuthenticationCredential(url);
+ delegate->m_initialCredential = CredentialStorage::get(url);
if (!delegate->m_initialCredential.isEmpty()) {
String authHeader = "Basic " + encodeBasicAuthorization(delegate->m_initialCredential.user(), delegate->m_initialCredential.password());
diff --git a/WebCore/platform/network/mac/ResourceRequestMac.mm b/WebCore/platform/network/mac/ResourceRequestMac.mm
index c4355b2..c2ad7d1 100644
--- a/WebCore/platform/network/mac/ResourceRequestMac.mm
+++ b/WebCore/platform/network/mac/ResourceRequestMac.mm
@@ -66,6 +66,7 @@ void ResourceRequest::doUpdateResourceRequest()
NSDictionary *headers = [m_nsRequest.get() allHTTPHeaderFields];
NSEnumerator *e = [headers keyEnumerator];
NSString *name;
+ m_httpHeaderFields.clear();
while ((name = [e nextObject]))
m_httpHeaderFields.set(name, [headers objectForKey:name]);
@@ -114,7 +115,11 @@ void ResourceRequest::doUpdatePlatformRequest()
if (!httpMethod().isEmpty())
[nsRequest setHTTPMethod:httpMethod()];
[nsRequest setHTTPShouldHandleCookies:allowCookies()];
-
+
+ // Cannot just use setAllHTTPHeaderFields here, because it does not remove headers.
+ NSArray *oldHeaderFieldNames = [[nsRequest allHTTPHeaderFields] allKeys];
+ for (unsigned i = [oldHeaderFieldNames count]; i != 0; --i)
+ [nsRequest setValue:nil forHTTPHeaderField:[oldHeaderFieldNames objectAtIndex:i - 1]];
HTTPHeaderMap::const_iterator end = httpHeaderFields().end();
for (HTTPHeaderMap::const_iterator it = httpHeaderFields().begin(); it != end; ++it)
[nsRequest setValue:it->second forHTTPHeaderField:it->first];
diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
index 7a3703d..ed5e024 100644
--- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
+++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
@@ -112,23 +112,11 @@ qint64 FormDataIODevice::writeData(const char*, qint64)
return -1;
}
-void FormDataIODevice::setParent(QNetworkReply* reply)
-{
- QIODevice::setParent(reply);
-
- connect(reply, SIGNAL(finished()), SLOT(slotFinished()), Qt::QueuedConnection);
-}
-
bool FormDataIODevice::isSequential() const
{
return true;
}
-void FormDataIODevice::slotFinished()
-{
- deleteLater();
-}
-
QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode loadMode)
: QObject(0)
, m_reply(0)
@@ -187,8 +175,8 @@ void QNetworkReplyHandler::abort()
QNetworkReply* reply = release();
reply->abort();
reply->deleteLater();
- deleteLater();
}
+ deleteLater();
}
QNetworkReply* QNetworkReplyHandler::release()
@@ -200,6 +188,7 @@ QNetworkReply* QNetworkReplyHandler::release()
// posted meta call events that were the result of a signal emission
// don't reach the slots in our instance.
QCoreApplication::removePostedEvents(this, QEvent::MetaCall);
+ m_reply->setParent(0);
m_reply = 0;
}
return reply;
diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.h b/WebCore/platform/network/qt/QNetworkReplyHandler.h
index 545119e..fccc4a6 100644
--- a/WebCore/platform/network/qt/QNetworkReplyHandler.h
+++ b/WebCore/platform/network/qt/QNetworkReplyHandler.h
@@ -96,16 +96,12 @@ public:
FormDataIODevice(FormData*);
~FormDataIODevice();
- void setParent(QNetworkReply*);
bool isSequential() const;
protected:
qint64 readData(char*, qint64);
qint64 writeData(const char*, qint64);
-private Q_SLOTS:
- void slotFinished();
-
private:
void moveToNextElement();