diff options
author | Steve Block <steveblock@google.com> | 2009-11-05 09:23:40 +0000 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2009-11-10 22:41:12 +0000 |
commit | cac0f67c402d107cdb10971b95719e2ff9c7c76b (patch) | |
tree | d182c7f87211c6f201a5f038e332336493ebdbe7 /WebCore/platform/network | |
parent | 4b2ef0f288e7c6c4602f621b7a0e9feed304b70e (diff) | |
download | external_webkit-cac0f67c402d107cdb10971b95719e2ff9c7c76b.zip external_webkit-cac0f67c402d107cdb10971b95719e2ff9c7c76b.tar.gz external_webkit-cac0f67c402d107cdb10971b95719e2ff9c7c76b.tar.bz2 |
Merge webkit.org at r50258 : Initial merge by git.
Change-Id: I1a9e1dc4ed654b69174ad52a4f031a07240f37b0
Diffstat (limited to 'WebCore/platform/network')
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(); |