diff options
Diffstat (limited to 'WebCore/platform/network')
54 files changed, 1382 insertions, 360 deletions
diff --git a/WebCore/platform/network/AuthenticationClient.h b/WebCore/platform/network/AuthenticationClient.h new file mode 100644 index 0000000..1e17910 --- /dev/null +++ b/WebCore/platform/network/AuthenticationClient.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AuthenticationClient_h +#define AuthenticationClient_h + +namespace WebCore { + +class AuthenticationChallenge; +class Credential; + +class AuthenticationClient { +public: + virtual void receivedCredential(const AuthenticationChallenge&, const Credential&) = 0; + virtual void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&) = 0; + virtual void receivedCancellation(const AuthenticationChallenge&) = 0; + + void ref() { refAuthenticationClient(); } + void deref() { derefAuthenticationClient(); } + +protected: + virtual ~AuthenticationClient() { } + +private: + virtual void refAuthenticationClient() = 0; + virtual void derefAuthenticationClient() = 0; +}; + +} + +#endif diff --git a/WebCore/platform/network/Credential.cpp b/WebCore/platform/network/Credential.cpp index f905743..87cd7ff 100644 --- a/WebCore/platform/network/Credential.cpp +++ b/WebCore/platform/network/Credential.cpp @@ -33,6 +33,9 @@ Credential::Credential() : m_user("") , m_password("") , m_persistence(CredentialPersistenceNone) +#if CERTIFICATE_CREDENTIALS_SUPPORTED + , m_type(CredentialTypePassword) +#endif { } @@ -42,11 +45,31 @@ Credential::Credential(const String& user, const String& password, CredentialPer : m_user(user.length() ? user : "") , m_password(password.length() ? password : "") , m_persistence(persistence) +#if CERTIFICATE_CREDENTIALS_SUPPORTED + , m_type(CredentialTypePassword) +#endif +{ +} + +Credential::Credential(const Credential& original, CredentialPersistence persistence) + : m_user(original.user()) + , m_password(original.password()) + , m_persistence(persistence) +#if CERTIFICATE_CREDENTIALS_SUPPORTED + , m_identity(original.identity()) + , m_certificates(original.certificates()) + , m_type(original.type()) +#endif { } bool Credential::isEmpty() const { +#if CERTIFICATE_CREDENTIALS_SUPPORTED + if (m_type == CredentialTypeClientCertificate && (m_identity || m_certificates)) + return false; +#endif + return m_user.isEmpty() && m_password.isEmpty(); } @@ -69,15 +92,68 @@ CredentialPersistence Credential::persistence() const { return m_persistence; } + +#if CERTIFICATE_CREDENTIALS_SUPPORTED +Credential::Credential(SecIdentityRef identity, CFArrayRef certificates, CredentialPersistence persistence) + : m_user("") + , m_password("") + , m_persistence(persistence) + , m_identity(identity) + , m_certificates(certificates) + , m_type(CredentialTypeClientCertificate) +{ +} + +SecIdentityRef Credential::identity() const +{ + return m_identity.get(); +} + +CFArrayRef Credential::certificates() const +{ + return m_certificates.get(); +} + +const CredentialType Credential::type() const +{ + return m_type; +} +#endif bool operator==(const Credential& a, const Credential& b) { + // Check persistence first since all credential types + // have the persistence property. + if (a.persistence() != b.persistence()) + return false; + +#if CERTIFICATE_CREDENTIALS_SUPPORTED + CredentialType aType = a.type(); + if (aType != b.type()) + return false; + + // Comparing identity and certificate chain pointers is valid only + // for client certificate type credentials. + // + // FIXME: Is pointer comparison of the identity and certificates properties sufficient? + if (aType == CredentialTypeClientCertificate) { + if (a.identity() != b.identity()) + return false; + if (a.certificates() != b.certificates()) + return false; + + // We only need to check identity and certificates to compare + // client certificate based credentials. + return true; + } + + ASSERT(a.type() == CredentialTypePassword && b.type() == CredentialTypePassword); +#endif + if (a.user() != b.user()) return false; if (a.password() != b.password()) return false; - if (a.persistence() != b.persistence()) - return false; return true; } diff --git a/WebCore/platform/network/Credential.h b/WebCore/platform/network/Credential.h index 0471fbc..199817c 100644 --- a/WebCore/platform/network/Credential.h +++ b/WebCore/platform/network/Credential.h @@ -27,6 +27,13 @@ #include "PlatformString.h" +#define CERTIFICATE_CREDENTIALS_SUPPORTED ((PLATFORM(MAC) || PLATFORM(IPHONE)) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) + +#if CERTIFICATE_CREDENTIALS_SUPPORTED +#include <Security/SecBase.h> +#include <wtf/RetainPtr.h> +#endif + namespace WebCore { enum CredentialPersistence { @@ -34,12 +41,23 @@ enum CredentialPersistence { CredentialPersistenceForSession, CredentialPersistencePermanent }; - + +#if CERTIFICATE_CREDENTIALS_SUPPORTED +enum CredentialType { + CredentialTypePassword, + CredentialTypeClientCertificate +}; +#endif + class Credential { public: Credential(); Credential(const String& user, const String& password, CredentialPersistence); + Credential(const Credential& original, CredentialPersistence); +#if CERTIFICATE_CREDENTIALS_SUPPORTED + Credential(SecIdentityRef identity, CFArrayRef certificates, CredentialPersistence); +#endif bool isEmpty() const; @@ -48,10 +66,21 @@ public: bool hasPassword() const; CredentialPersistence persistence() const; +#if CERTIFICATE_CREDENTIALS_SUPPORTED + SecIdentityRef identity() const; + CFArrayRef certificates() const; + const CredentialType type() const; +#endif + private: String m_user; String m_password; CredentialPersistence m_persistence; +#if CERTIFICATE_CREDENTIALS_SUPPORTED + RetainPtr<SecIdentityRef> m_identity; + RetainPtr<CFArrayRef> m_certificates; + CredentialType m_type; +#endif }; bool operator==(const Credential& a, const Credential& b); diff --git a/WebCore/platform/network/CredentialStorage.cpp b/WebCore/platform/network/CredentialStorage.cpp index ec78372..a401751 100644 --- a/WebCore/platform/network/CredentialStorage.cpp +++ b/WebCore/platform/network/CredentialStorage.cpp @@ -85,16 +85,18 @@ static String protectionSpaceMapKeyFromURL(const KURL& url) void CredentialStorage::set(const Credential& credential, const ProtectionSpace& protectionSpace, const KURL& url) { - ASSERT(url.protocolInHTTPFamily()); - ASSERT(url.isValid()); + ASSERT(protectionSpace.isProxy() || url.protocolInHTTPFamily()); + ASSERT(protectionSpace.isProxy() || url.isValid()); protectionSpaceToCredentialMap().set(protectionSpace, credential); - originsWithCredentials().add(originStringFromURL(url)); - - ProtectionSpaceAuthenticationScheme scheme = protectionSpace.authenticationScheme(); - 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); + if (!protectionSpace.isProxy()) { + originsWithCredentials().add(originStringFromURL(url)); + + ProtectionSpaceAuthenticationScheme scheme = protectionSpace.authenticationScheme(); + 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); + } } } diff --git a/WebCore/platform/network/CredentialStorage.h b/WebCore/platform/network/CredentialStorage.h index 5086f69..21fcbad 100644 --- a/WebCore/platform/network/CredentialStorage.h +++ b/WebCore/platform/network/CredentialStorage.h @@ -34,9 +34,13 @@ class ProtectionSpace; class CredentialStorage { public: + // WebCore session credential storage. static void set(const Credential&, const ProtectionSpace&, const KURL&); static Credential get(const ProtectionSpace&); + // OS persistent storage. + static Credential getFromPersistentStorage(const ProtectionSpace&); + // 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. diff --git a/WebCore/platform/network/FormDataBuilder.cpp b/WebCore/platform/network/FormDataBuilder.cpp index 04c7527..52f62f3 100644 --- a/WebCore/platform/network/FormDataBuilder.cpp +++ b/WebCore/platform/network/FormDataBuilder.cpp @@ -127,9 +127,6 @@ static void appendQuotedString(Vector<char>& buffer, const CString& string) case '"': append(buffer, "%22"); break; - case '%': - append(buffer, "%25"); - break; default: append(buffer, c); } @@ -143,7 +140,10 @@ Vector<char> FormDataBuilder::generateUniqueBoundaryString() // The RFC 2046 spec says the alphanumeric characters plus the // following characters are legal for boundaries: '()+_,-./:=? // However the following characters, though legal, cause some sites - // to fail: (),./:= (http://bugs.webkit.org/show_bug.cgi?id=13352) + // to fail: (),./:=+ + // Note that our algorithm makes it twice as much likely for 'A' or 'B' + // to appear in the boundary string, because 0x41 and 0x42 are present in + // the below array twice. static const char alphaNumericEncodingMap[64] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, @@ -152,18 +152,7 @@ Vector<char> FormDataBuilder::generateUniqueBoundaryString() 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x41 - // FIXME <rdar://problem/5252577> gmail does not accept legal characters in the form boundary - // As stated above, some legal characters cause, sites to fail. Specifically - // the / character which was the last character in the above array. I have - // replaced the last character with another character already in the array - // (notice the first and last values are both 0x41, A). Instead of picking - // another unique legal character for boundary strings that, because it has - // never been tested, may or may not break other sites, I simply - // replaced / with A. This means A is twice as likely to occur in our boundary - // strings than any other character but I think this is fine for the time being. - // The FIXME here is about restoring the / character once the aforementioned - // radar has been resolved. + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42 }; // Start with an informative prefix. diff --git a/WebCore/platform/network/HTTPHeaderMap.cpp b/WebCore/platform/network/HTTPHeaderMap.cpp index 07c66e8..413fb7b 100644 --- a/WebCore/platform/network/HTTPHeaderMap.cpp +++ b/WebCore/platform/network/HTTPHeaderMap.cpp @@ -59,5 +59,41 @@ void HTTPHeaderMap::adopt(auto_ptr<CrossThreadHTTPHeaderMapData> data) set(header.first, header.second); } } + +// Adapter that allows the HashMap to take C strings as keys. +struct CaseFoldingCStringTranslator { + static unsigned hash(const char* cString) + { + return CaseFoldingHash::hash(cString, strlen(cString)); + } + + static bool equal(const AtomicString& key, const char* cString) + { + return equalIgnoringCase(key, cString); + } + + static void translate(AtomicString& location, const char* cString, unsigned /*hash*/) + { + location = AtomicString(cString); + } +}; + +String HTTPHeaderMap::get(const char* name) const +{ + const_iterator i = find<const char*, CaseFoldingCStringTranslator>(name); + if (i == end()) + return String(); + return i->second; +} + +bool HTTPHeaderMap::contains(const char* name) const +{ + return find<const char*, CaseFoldingCStringTranslator>(name) != end(); +} + +pair<HTTPHeaderMap::iterator, bool> HTTPHeaderMap::add(const char* name, const String& value) +{ + return HashMap<AtomicString, String, CaseFoldingHash>::add<const char*, CaseFoldingCStringTranslator>(name, value); +} } // namespace WebCore diff --git a/WebCore/platform/network/HTTPHeaderMap.h b/WebCore/platform/network/HTTPHeaderMap.h index 6da1b90..dfde974 100644 --- a/WebCore/platform/network/HTTPHeaderMap.h +++ b/WebCore/platform/network/HTTPHeaderMap.h @@ -45,6 +45,22 @@ namespace WebCore { std::auto_ptr<CrossThreadHTTPHeaderMapData> copyData() const; void adopt(std::auto_ptr<CrossThreadHTTPHeaderMapData>); + + String get(const AtomicString& name) const + { + return HashMap<AtomicString, String, CaseFoldingHash>::get(name); + } + + pair<iterator, bool> add(const AtomicString& name, const String& value) + { + return HashMap<AtomicString, String, CaseFoldingHash>::add(name, value); + } + + // Alternate accessors that are faster than converting the char* to AtomicString first. + bool contains(const char*) const; + String get(const char*) const; + pair<iterator, bool> add(const char* name, const String& value); + }; } // namespace WebCore diff --git a/WebCore/platform/network/NetworkStateNotifier.h b/WebCore/platform/network/NetworkStateNotifier.h index f918be6..a630ccd 100644 --- a/WebCore/platform/network/NetworkStateNotifier.h +++ b/WebCore/platform/network/NetworkStateNotifier.h @@ -26,6 +26,8 @@ #ifndef NetworkStateNotifier_h #define NetworkStateNotifier_h +#include <wtf/Noncopyable.h> + #if PLATFORM(MAC) #include <wtf/RetainPtr.h> @@ -46,7 +48,7 @@ typedef const struct __SCDynamicStore * SCDynamicStoreRef; namespace WebCore { -class NetworkStateNotifier { +class NetworkStateNotifier : public Noncopyable { public: NetworkStateNotifier(); void setNetworkStateChangedFunction(void (*)()); diff --git a/WebCore/platform/network/ProtectionSpace.cpp b/WebCore/platform/network/ProtectionSpace.cpp index d04bcbe..26c258f 100644 --- a/WebCore/platform/network/ProtectionSpace.cpp +++ b/WebCore/platform/network/ProtectionSpace.cpp @@ -111,7 +111,8 @@ bool operator==(const ProtectionSpace& a, const ProtectionSpace& b) return false; if (a.serverType() != b.serverType()) return false; - if (a.realm() != b.realm()) + // Ignore realm for proxies + if (!a.isProxy() && a.realm() != b.realm()) return false; if (a.authenticationScheme() != b.authenticationScheme()) return false; diff --git a/WebCore/platform/network/ProtectionSpaceHash.h b/WebCore/platform/network/ProtectionSpaceHash.h index 6f68b5b..f8c84e8 100644 --- a/WebCore/platform/network/ProtectionSpaceHash.h +++ b/WebCore/platform/network/ProtectionSpaceHash.h @@ -37,11 +37,15 @@ struct ProtectionSpaceHash { protectionSpace.host().impl() ? protectionSpace.host().impl()->hash() : 0, protectionSpace.port(), protectionSpace.serverType(), - protectionSpace.realm().impl() ? protectionSpace.realm().impl()->hash() : 0, - protectionSpace.authenticationScheme() + protectionSpace.authenticationScheme(), + protectionSpace.realm().impl() ? protectionSpace.realm().impl()->hash() : 0 }; - return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); + unsigned codeCount = sizeof(hashCodes) / sizeof(UChar); + // Ignore realm for proxies. + if (protectionSpace.isProxy()) + codeCount -= sizeof(hashCodes[0]) / sizeof(UChar); + return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), codeCount); } static bool equal(const ProtectionSpace& a, const ProtectionSpace& b) { return a == b; } diff --git a/WebCore/platform/network/ResourceHandle.cpp b/WebCore/platform/network/ResourceHandle.cpp index 5a40b21..7c20561 100644 --- a/WebCore/platform/network/ResourceHandle.cpp +++ b/WebCore/platform/network/ResourceHandle.cpp @@ -36,8 +36,6 @@ namespace WebCore { static bool shouldForceContentSniffing; -static bool portAllowed(const ResourceRequest&); - ResourceHandle::ResourceHandle(const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff, bool mightDownloadFromHandle) : d(new ResourceHandleInternal(this, request, client, defersLoading, shouldContentSniff, mightDownloadFromHandle)) @@ -57,7 +55,7 @@ PassRefPtr<ResourceHandle> ResourceHandle::create(const ResourceRequest& request return newHandle.release(); } - if (!portAllowed(request)) { + if (!portAllowed(request.url())) { newHandle->scheduleFailure(BlockedFailure); return newHandle.release(); } @@ -110,100 +108,9 @@ void ResourceHandle::clearAuthentication() { #if PLATFORM(MAC) d->m_currentMacChallenge = nil; -#elif USE(CFNETWORK) - d->m_currentCFChallenge = 0; #endif d->m_currentWebChallenge.nullify(); } - -static bool portAllowed(const ResourceRequest& request) -{ - unsigned short port = request.url().port(); - - // Since most URLs don't have a port, return early for the "no port" case. - if (!port) - return true; - - // This blocked port list matches the port blocking that Mozilla implements. - // See http://www.mozilla.org/projects/netlib/PortBanning.html for more information. - static const unsigned short blockedPortList[] = { - 1, // tcpmux - 7, // echo - 9, // discard - 11, // systat - 13, // daytime - 15, // netstat - 17, // qotd - 19, // chargen - 20, // FTP-data - 21, // FTP-control - 22, // SSH - 23, // telnet - 25, // SMTP - 37, // time - 42, // name - 43, // nicname - 53, // domain - 77, // priv-rjs - 79, // finger - 87, // ttylink - 95, // supdup - 101, // hostriame - 102, // iso-tsap - 103, // gppitnp - 104, // acr-nema - 109, // POP2 - 110, // POP3 - 111, // sunrpc - 113, // auth - 115, // SFTP - 117, // uucp-path - 119, // nntp - 123, // NTP - 135, // loc-srv / epmap - 139, // netbios - 143, // IMAP2 - 179, // BGP - 389, // LDAP - 465, // SMTP+SSL - 512, // print / exec - 513, // login - 514, // shell - 515, // printer - 526, // tempo - 530, // courier - 531, // Chat - 532, // netnews - 540, // UUCP - 556, // remotefs - 563, // NNTP+SSL - 587, // ESMTP - 601, // syslog-conn - 636, // LDAP+SSL - 993, // IMAP+SSL - 995, // POP3+SSL - 2049, // NFS - 3659, // apple-sasl / PasswordServer [Apple addition] - 4045, // lockd - 6000, // X11 - }; - const unsigned short* const blockedPortListEnd = blockedPortList - + sizeof(blockedPortList) / sizeof(blockedPortList[0]); - - // If the port is not in the blocked port list, allow it. - if (!std::binary_search(blockedPortList, blockedPortListEnd, port)) - return true; - - // Allow ports 21 and 22 for FTP URLs, as Mozilla does. - if ((port == 21 || port == 22) && request.url().protocolIs("ftp")) - return true; - - // Allow any port number in a file URL, since the port number is ignored. - if (request.url().protocolIs("file")) - return true; - - return false; -} bool ResourceHandle::shouldContentSniff() const { diff --git a/WebCore/platform/network/ResourceHandle.h b/WebCore/platform/network/ResourceHandle.h index e82e13b..e7f6092 100644 --- a/WebCore/platform/network/ResourceHandle.h +++ b/WebCore/platform/network/ResourceHandle.h @@ -27,6 +27,7 @@ #define ResourceHandle_h #include "AuthenticationChallenge.h" +#include "AuthenticationClient.h" #include "HTTPHeaderMap.h" #include "ThreadableLoader.h" #include <wtf/OwnPtr.h> @@ -84,14 +85,18 @@ class KURL; class ResourceError; class ResourceHandleClient; class ResourceHandleInternal; -struct ResourceRequest; +class ResourceRequest; class ResourceResponse; class SchedulePair; class SharedBuffer; template <typename T> class Timer; -class ResourceHandle : public RefCounted<ResourceHandle> { +class ResourceHandle : public RefCounted<ResourceHandle> +#if PLATFORM(MAC) || USE(CFNETWORK) || USE(CURL) + , public AuthenticationClient +#endif + { private: ResourceHandle(const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff, bool mightDownloadFromHandle); @@ -110,7 +115,7 @@ public: static bool didSendBodyDataDelegateExists(); #endif - ~ResourceHandle(); + virtual ~ResourceHandle(); #if PLATFORM(MAC) || USE(CFNETWORK) void willSendRequest(ResourceRequest&, const ResourceResponse& redirectResponse); @@ -118,9 +123,9 @@ public: #endif #if PLATFORM(MAC) || USE(CFNETWORK) || USE(CURL) void didReceiveAuthenticationChallenge(const AuthenticationChallenge&); - void receivedCredential(const AuthenticationChallenge&, const Credential&); - void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); - void receivedCancellation(const AuthenticationChallenge&); + virtual void receivedCredential(const AuthenticationChallenge&, const Credential&); + virtual void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); + virtual void receivedCancellation(const AuthenticationChallenge&); #endif #if PLATFORM(MAC) @@ -133,7 +138,6 @@ public: void schedule(SchedulePair*); void unschedule(SchedulePair*); #elif USE(CFNETWORK) - static CFRunLoopRef loaderRunLoop(); CFURLConnectionRef connection() const; CFURLConnectionRef releaseConnectionForDownload(); static void setHostAllowsAnyHTTPSCertificate(const String&); @@ -190,11 +194,17 @@ public: void fireFailure(Timer<ResourceHandle>*); + using RefCounted<ResourceHandle>::ref; + using RefCounted<ResourceHandle>::deref; + private: void scheduleFailure(FailureType); bool start(Frame*); + virtual void refAuthenticationClient() { ref(); } + virtual void derefAuthenticationClient() { deref(); } + friend class ResourceHandleInternal; OwnPtr<ResourceHandleInternal> d; }; diff --git a/WebCore/platform/network/ResourceHandleClient.h b/WebCore/platform/network/ResourceHandleClient.h index c99be54..b5efaed 100644 --- a/WebCore/platform/network/ResourceHandleClient.h +++ b/WebCore/platform/network/ResourceHandleClient.h @@ -50,7 +50,7 @@ namespace WebCore { class KURL; class ResourceHandle; class ResourceError; - struct ResourceRequest; + class ResourceRequest; class ResourceResponse; enum CacheStoragePolicy { diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h index fa939db..8313560 100644 --- a/WebCore/platform/network/ResourceHandleInternal.h +++ b/WebCore/platform/network/ResourceHandleInternal.h @@ -132,8 +132,6 @@ namespace WebCore { , m_startWhenScheduled(false) , m_needsSiteSpecificQuirks(false) , m_currentMacChallenge(nil) -#elif USE(CFNETWORK) - , m_currentCFChallenge(0) #endif #if PLATFORM(ANDROID) , m_loader(0) @@ -211,24 +209,24 @@ namespace WebCore { Frame* m_frame; #endif #if PLATFORM(QT) -#if QT_VERSION < 0x040400 - QWebNetworkJob* m_job; -#else QNetworkReplyHandler* m_job; -#endif QWebFrame* m_frame; #endif - // FIXME: The platform challenge is almost identical to the one stored in m_currentWebChallenge, but it has a different sender. We only need to store a sender reference here. #if PLATFORM(MAC) + // We need to keep a reference to the original challenge to be able to cancel it. + // It is almost identical to m_currentWebChallenge.nsURLAuthenticationChallenge(), but has a different sender. NSURLAuthenticationChallenge *m_currentMacChallenge; #endif +<<<<<<< HEAD:WebCore/platform/network/ResourceHandleInternal.h #if USE(CFNETWORK) CFURLAuthChallengeRef m_currentCFChallenge; #endif #if PLATFORM(ANDROID) RefPtr<ResourceLoaderAndroid> m_loader; #endif +======= +>>>>>>> webkit.org at r51976:WebCore/platform/network/ResourceHandleInternal.h AuthenticationChallenge m_currentWebChallenge; ResourceHandle::FailureType m_failureType; diff --git a/WebCore/platform/network/ResourceRequestBase.cpp b/WebCore/platform/network/ResourceRequestBase.cpp index 936f26b..41afb92 100644 --- a/WebCore/platform/network/ResourceRequestBase.cpp +++ b/WebCore/platform/network/ResourceRequestBase.cpp @@ -208,6 +208,13 @@ String ResourceRequestBase::httpHeaderField(const AtomicString& name) const return m_httpHeaderFields.get(name); } +String ResourceRequestBase::httpHeaderField(const char* name) const +{ + updateResourceRequest(); + + return m_httpHeaderFields.get(name); +} + void ResourceRequestBase::setHTTPHeaderField(const AtomicString& name, const String& value) { updateResourceRequest(); @@ -218,6 +225,11 @@ void ResourceRequestBase::setHTTPHeaderField(const AtomicString& name, const Str m_platformRequestUpdated = false; } +void ResourceRequestBase::setHTTPHeaderField(const char* name, const String& value) +{ + setHTTPHeaderField(AtomicString(name), value); +} + void ResourceRequestBase::clearHTTPReferrer() { updateResourceRequest(); diff --git a/WebCore/platform/network/ResourceRequestBase.h b/WebCore/platform/network/ResourceRequestBase.h index 84a7bd0..931a9de 100644 --- a/WebCore/platform/network/ResourceRequestBase.h +++ b/WebCore/platform/network/ResourceRequestBase.h @@ -46,12 +46,25 @@ namespace WebCore { const int unspecifiedTimeoutInterval = INT_MAX; - struct ResourceRequest; + class ResourceRequest; struct CrossThreadResourceRequestData; // Do not use this type directly. Use ResourceRequest instead. class ResourceRequestBase { public: + // The type of this ResourceRequest, based on how the resource will be used. + enum TargetType { + TargetIsMainFrame, + TargetIsSubframe, + TargetIsSubresource, // Resource is a generic subresource. (Generally a specific type should be specified) + TargetIsStyleSheet, + TargetIsScript, + TargetIsFontResource, + TargetIsImage, + TargetIsObject, + TargetIsMedia + }; + static std::auto_ptr<ResourceRequest> adopt(std::auto_ptr<CrossThreadResourceRequestData>); // Gets a copy of the data suitable for passing to another thread. @@ -79,7 +92,9 @@ namespace WebCore { const HTTPHeaderMap& httpHeaderFields() const; String httpHeaderField(const AtomicString& name) const; + String httpHeaderField(const char* name) const; void setHTTPHeaderField(const AtomicString& name, const String& value); + void setHTTPHeaderField(const char* name, const String& value); void addHTTPHeaderField(const AtomicString& name, const String& value); void addHTTPHeaderFields(const HTTPHeaderMap& headerFields); @@ -115,12 +130,17 @@ namespace WebCore { bool reportUploadProgress() const { return m_reportUploadProgress; } void setReportUploadProgress(bool reportUploadProgress) { m_reportUploadProgress = reportUploadProgress; } + // What this request is for. + TargetType targetType() const { return m_targetType; } + void setTargetType(TargetType type) { m_targetType = type; } + protected: // Used when ResourceRequest is initialized from a platform representation of the request ResourceRequestBase() : m_resourceRequestUpdated(false) , m_platformRequestUpdated(true) , m_reportUploadProgress(false) + , m_targetType(TargetIsSubresource) { } @@ -133,6 +153,7 @@ namespace WebCore { , m_resourceRequestUpdated(true) , m_platformRequestUpdated(false) , m_reportUploadProgress(false) + , m_targetType(TargetIsSubresource) { } @@ -152,6 +173,7 @@ namespace WebCore { mutable bool m_resourceRequestUpdated; mutable bool m_platformRequestUpdated; bool m_reportUploadProgress; + TargetType m_targetType; private: const ResourceRequest& asResourceRequest() const; @@ -162,7 +184,7 @@ namespace WebCore { bool operator==(const ResourceRequestBase&, const ResourceRequestBase&); inline bool operator!=(ResourceRequestBase& a, const ResourceRequestBase& b) { return !(a == b); } - struct CrossThreadResourceRequestData { + struct CrossThreadResourceRequestData : Noncopyable { KURL m_url; ResourceRequestCachePolicy m_cachePolicy; diff --git a/WebCore/platform/network/ResourceResponseBase.cpp b/WebCore/platform/network/ResourceResponseBase.cpp index fd44225..f9cd271 100644 --- a/WebCore/platform/network/ResourceResponseBase.cpp +++ b/WebCore/platform/network/ResourceResponseBase.cpp @@ -239,6 +239,13 @@ String ResourceResponseBase::httpHeaderField(const AtomicString& name) const return m_httpHeaderFields.get(name); } +String ResourceResponseBase::httpHeaderField(const char* name) const +{ + lazyInit(); + + return m_httpHeaderFields.get(name); +} + void ResourceResponseBase::setHTTPHeaderField(const AtomicString& name, const String& value) { lazyInit(); diff --git a/WebCore/platform/network/ResourceResponseBase.h b/WebCore/platform/network/ResourceResponseBase.h index 7594c09..e06c6f8 100644 --- a/WebCore/platform/network/ResourceResponseBase.h +++ b/WebCore/platform/network/ResourceResponseBase.h @@ -71,6 +71,7 @@ public: void setHTTPStatusText(const String&); String httpHeaderField(const AtomicString& name) const; + String httpHeaderField(const char* name) const; void setHTTPHeaderField(const AtomicString& name, const String& value); const HTTPHeaderMap& httpHeaderFields() const; diff --git a/WebCore/platform/network/SocketStreamHandleBase.cpp b/WebCore/platform/network/SocketStreamHandleBase.cpp index 875c248..8472713 100644 --- a/WebCore/platform/network/SocketStreamHandleBase.cpp +++ b/WebCore/platform/network/SocketStreamHandleBase.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "SocketStreamHandleBase.h" +#include "SocketStreamHandle.h" #include "SocketStreamHandleClient.h" namespace WebCore { @@ -64,7 +65,7 @@ bool SocketStreamHandleBase::send(const char* data, int length) int bytesWritten = 0; if (m_state == Open) bytesWritten = platformSend(data, length); - if (bytesWritten <= 0) + if (bytesWritten < 0) return false; if (m_buffer.size() + length - bytesWritten > bufferSize) { // FIXME: report error to indicate that buffer has no more space. @@ -77,6 +78,8 @@ bool SocketStreamHandleBase::send(const char* data, int length) void SocketStreamHandleBase::close() { + RefPtr<SocketStreamHandle> protect(static_cast<SocketStreamHandle*>(this)); // platformClose calls the client, which may make the handle get deallocated immediately. + platformClose(); m_state = Closed; } diff --git a/WebCore/platform/network/SocketStreamHandleClient.h b/WebCore/platform/network/SocketStreamHandleClient.h index 04c744e..5d97ec0 100644 --- a/WebCore/platform/network/SocketStreamHandleClient.h +++ b/WebCore/platform/network/SocketStreamHandleClient.h @@ -43,18 +43,15 @@ namespace WebCore { public: virtual ~SocketStreamHandleClient() { } - virtual void willOpenStream(SocketStreamHandle*, const KURL&) { } - virtual void willSendData(SocketStreamHandle*, const char* /*data*/, int /*length*/) { } - virtual void didOpen(SocketStreamHandle*) { } virtual void didClose(SocketStreamHandle*) { } virtual void didReceiveData(SocketStreamHandle*, const char* /*data*/, int /*length*/) { } virtual void didFail(SocketStreamHandle*, const SocketStreamError&) { } + // No authentication for streams per se, but proxy may ask for credentials. virtual void didReceiveAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&) { } virtual void didCancelAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&) { } - virtual void receivedCancellation(SocketStreamHandle*, const AuthenticationChallenge&) { } }; } // namespace WebCore diff --git a/WebCore/platform/network/cf/AuthenticationCF.cpp b/WebCore/platform/network/cf/AuthenticationCF.cpp index bb05a39..93b62a8 100644 --- a/WebCore/platform/network/cf/AuthenticationCF.cpp +++ b/WebCore/platform/network/cf/AuthenticationCF.cpp @@ -27,9 +27,9 @@ #include "AuthenticationCF.h" #include "AuthenticationChallenge.h" +#include "AuthenticationClient.h" #include "Credential.h" #include "ProtectionSpace.h" -#include "ResourceHandle.h" #include <CFNetwork/CFURLAuthChallengePriv.h> #include <CFNetwork/CFURLCredentialPriv.h> @@ -51,20 +51,20 @@ AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protecti } AuthenticationChallenge::AuthenticationChallenge(CFURLAuthChallengeRef cfChallenge, - ResourceHandle* sourceHandle) + AuthenticationClient* authenticationClient) : AuthenticationChallengeBase(core(CFURLAuthChallengeGetProtectionSpace(cfChallenge)), core(CFURLAuthChallengeGetProposedCredential(cfChallenge)), CFURLAuthChallengeGetPreviousFailureCount(cfChallenge), (CFURLResponseRef)CFURLAuthChallengeGetFailureResponse(cfChallenge), CFURLAuthChallengeGetError(cfChallenge)) - , m_sourceHandle(sourceHandle) + , m_authenticationClient(authenticationClient) , m_cfChallenge(cfChallenge) { } bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b) { - if (a.sourceHandle() != b.sourceHandle()) + if (a.authenticationClient() != b.authenticationClient()) return false; if (a.cfURLAuthChallengeRef() != b.cfURLAuthChallengeRef()) diff --git a/WebCore/platform/network/cf/AuthenticationChallenge.h b/WebCore/platform/network/cf/AuthenticationChallenge.h index 9697d7e..58fb836 100644 --- a/WebCore/platform/network/cf/AuthenticationChallenge.h +++ b/WebCore/platform/network/cf/AuthenticationChallenge.h @@ -26,29 +26,29 @@ #define AuthenticationChallenge_h #include "AuthenticationChallengeBase.h" -#include "ResourceHandle.h" +#include "AuthenticationClient.h" #include <wtf/RefPtr.h> typedef struct _CFURLAuthChallenge* CFURLAuthChallengeRef; namespace WebCore { -class ResourceHandle; - class AuthenticationChallenge : public AuthenticationChallengeBase { public: AuthenticationChallenge() {} AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse& response, const ResourceError& error); - AuthenticationChallenge(CFURLAuthChallengeRef, ResourceHandle* sourceHandle); + AuthenticationChallenge(CFURLAuthChallengeRef, AuthenticationClient*); + + AuthenticationClient* authenticationClient() const { return m_authenticationClient.get(); } + void setAuthenticationClient(AuthenticationClient* client) { m_authenticationClient = client; } - ResourceHandle* sourceHandle() const { return m_sourceHandle.get(); } CFURLAuthChallengeRef cfURLAuthChallengeRef() const { return m_cfChallenge.get(); } private: friend class AuthenticationChallengeBase; static bool platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b); - RefPtr<ResourceHandle> m_sourceHandle; + RefPtr<AuthenticationClient> m_authenticationClient; RetainPtr<CFURLAuthChallengeRef> m_cfChallenge; }; diff --git a/WebCore/platform/network/cf/CredentialStorageCFNet.cpp b/WebCore/platform/network/cf/CredentialStorageCFNet.cpp new file mode 100644 index 0000000..0a9e36f --- /dev/null +++ b/WebCore/platform/network/cf/CredentialStorageCFNet.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CredentialStorage.h" + +#include "AuthenticationCF.h" +#include "Credential.h" +#include "ProtectionSpace.h" +#include <WebKitSystemInterface/WebKitSystemInterface.h> +#include <wtf/RetainPtr.h> + +namespace WebCore { + +Credential CredentialStorage::getFromPersistentStorage(const ProtectionSpace& protectionSpace) +{ + RetainPtr<CFURLProtectionSpaceRef> protectionSpaceCF(AdoptCF, createCF(protectionSpace)); + RetainPtr<CFURLCredentialRef> credentialCF(AdoptCF, wkCopyCredentialFromCFPersistentStorage(protectionSpaceCF.get())); + return core(credentialCF.get()); +} + +} // namespace WebCore diff --git a/WebCore/platform/network/cf/DNSCFNet.cpp b/WebCore/platform/network/cf/DNSCFNet.cpp index 381dff2..6311baf 100644 --- a/WebCore/platform/network/cf/DNSCFNet.cpp +++ b/WebCore/platform/network/cf/DNSCFNet.cpp @@ -33,7 +33,7 @@ #include <wtf/StdLibExtras.h> #if PLATFORM(WIN) -#include "ResourceHandle.h" // for loaderRunLoop() +#include "LoaderRunLoopCF.h" #endif #ifdef BUILDING_ON_TIGER @@ -137,7 +137,7 @@ void DNSResolveQueue::resolve(const String& hostname) CFHostScheduleWithRunLoop(host.get(), CFRunLoopGetMain(), kCFRunLoopCommonModes); #else // On Windows, we run a separate thread with CFRunLoop, which is where clientCallback will be called. - CFHostScheduleWithRunLoop(host.get(), ResourceHandle::loaderRunLoop(), kCFRunLoopDefaultMode); + CFHostScheduleWithRunLoop(host.get(), loaderRunLoop(), kCFRunLoopDefaultMode); #endif CFHostStartInfoResolution(host.get(), kCFHostAddresses, 0); host.releaseRef(); // The host will be released from clientCallback(). diff --git a/WebCore/platform/network/cf/LoaderRunLoopCF.cpp b/WebCore/platform/network/cf/LoaderRunLoopCF.cpp new file mode 100644 index 0000000..aa68916 --- /dev/null +++ b/WebCore/platform/network/cf/LoaderRunLoopCF.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LoaderRunLoopCF.h" + +#include <wtf/Threading.h> + +namespace WebCore { + +static CFRunLoopRef loaderRunLoopObject = 0; + +static void emptyPerform(void*) +{ +} + +static void* runLoaderThread(void*) +{ + loaderRunLoopObject = CFRunLoopGetCurrent(); + + // Must add a source to the run loop to prevent CFRunLoopRun() from exiting. + CFRunLoopSourceContext ctxt = {0, (void*)1 /*must be non-NULL*/, 0, 0, 0, 0, 0, 0, 0, emptyPerform}; + CFRunLoopSourceRef bogusSource = CFRunLoopSourceCreate(0, 0, &ctxt); + CFRunLoopAddSource(loaderRunLoopObject, bogusSource, kCFRunLoopDefaultMode); + + CFRunLoopRun(); + + return 0; +} + +CFRunLoopRef loaderRunLoop() +{ + ASSERT(isMainThread()); + if (!loaderRunLoopObject) { + createThread(runLoaderThread, 0, "WebCore: CFNetwork Loader"); + while (!loaderRunLoopObject) { + // FIXME: Sleep 10? that can't be right... + Sleep(10); + } + } + return loaderRunLoopObject; +} + +} diff --git a/WebCore/platform/network/cf/LoaderRunLoopCF.h b/WebCore/platform/network/cf/LoaderRunLoopCF.h new file mode 100644 index 0000000..20e4c29 --- /dev/null +++ b/WebCore/platform/network/cf/LoaderRunLoopCF.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LoaderRunLoopCF_h +#define LoaderRunLoopCF_h + +#if !PLATFORM(WIN) +#error This code is not needed on platforms other than Windows, because main thread's CFRunLoop can be used. +#endif + +namespace WebCore { + +CFRunLoopRef loaderRunLoop(); + +} + +#endif // LoaderRunLoop_h diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp index 38a9705..8cc5022 100644 --- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp @@ -39,6 +39,7 @@ #include "FormDataStreamCFNet.h" #include "Frame.h" #include "FrameLoader.h" +#include "LoaderRunLoopCF.h" #include "Logging.h" #include "MIMETypeRegistry.h" #include "ResourceError.h" @@ -322,37 +323,6 @@ CFArrayRef arrayFromFormData(const FormData& d) return a; } -void emptyPerform(void* unused) -{ -} - -static CFRunLoopRef loaderRL = 0; -void* runLoaderThread(void *unused) -{ - loaderRL = CFRunLoopGetCurrent(); - - // Must add a source to the run loop to prevent CFRunLoopRun() from exiting - CFRunLoopSourceContext ctxt = {0, (void *)1 /*must be non-NULL*/, 0, 0, 0, 0, 0, 0, 0, emptyPerform}; - CFRunLoopSourceRef bogusSource = CFRunLoopSourceCreate(0, 0, &ctxt); - CFRunLoopAddSource(loaderRL, bogusSource,kCFRunLoopDefaultMode); - - CFRunLoopRun(); - - return 0; -} - -CFRunLoopRef ResourceHandle::loaderRunLoop() -{ - if (!loaderRL) { - createThread(runLoaderThread, 0, "WebCore: CFNetwork Loader"); - while (loaderRL == 0) { - // FIXME: sleep 10? that can't be right... - Sleep(10); - } - } - return loaderRL; -} - static CFURLRequestRef makeFinalRequest(const ResourceRequest& request, bool shouldContentSniff) { CFMutableURLRequestRef newRequest = CFURLRequestCreateMutableCopy(kCFAllocatorDefault, request.cfURLRequest()); @@ -479,11 +449,11 @@ bool ResourceHandle::shouldUseCredentialStorage() void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge) { LOG(Network, "CFNet - didReceiveAuthenticationChallenge()"); - ASSERT(!d->m_currentCFChallenge); ASSERT(d->m_currentWebChallenge.isNull()); // Since CFURLConnection networking relies on keeping a reference to the original CFURLAuthChallengeRef, // we make sure that is actually present ASSERT(challenge.cfURLAuthChallengeRef()); + ASSERT(challenge.authenticationClient() == this); // Should be already set. if (!d->m_user.isNull() && !d->m_pass.isNull()) { RetainPtr<CFStringRef> user(AdoptCF, d->m_user.createCFString()); @@ -513,8 +483,7 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall } } - d->m_currentCFChallenge = challenge.cfURLAuthChallengeRef(); - d->m_currentWebChallenge = AuthenticationChallenge(d->m_currentCFChallenge, this); + d->m_currentWebChallenge = challenge; if (client()) client()->didReceiveAuthenticationChallenge(this, d->m_currentWebChallenge); diff --git a/WebCore/platform/network/cf/ResourceRequest.h b/WebCore/platform/network/cf/ResourceRequest.h index 8ead412..e361af5 100644 --- a/WebCore/platform/network/cf/ResourceRequest.h +++ b/WebCore/platform/network/cf/ResourceRequest.h @@ -34,8 +34,8 @@ typedef const struct _CFURLRequest* CFURLRequestRef; namespace WebCore { - struct ResourceRequest : ResourceRequestBase { - + class ResourceRequest : public ResourceRequestBase { + public: ResourceRequest(const String& url) : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { @@ -64,7 +64,7 @@ namespace WebCore { CFURLRequestRef cfURLRequest() const; private: - friend struct ResourceRequestBase; + friend class ResourceRequestBase; void doUpdatePlatformRequest(); void doUpdateResourceRequest(); diff --git a/WebCore/platform/network/cf/ResourceRequestCFNet.h b/WebCore/platform/network/cf/ResourceRequestCFNet.h index d26072d..e9ebe76 100644 --- a/WebCore/platform/network/cf/ResourceRequestCFNet.h +++ b/WebCore/platform/network/cf/ResourceRequestCFNet.h @@ -30,7 +30,7 @@ typedef const struct _CFURLRequest* CFURLRequestRef; namespace WebCore { - struct ResourceRequest; + class ResourceRequest; void getResourceRequest(ResourceRequest&, CFURLRequestRef); CFURLRequestRef cfURLRequest(const ResourceRequest&); diff --git a/WebCore/platform/network/cf/SocketStreamHandle.h b/WebCore/platform/network/cf/SocketStreamHandle.h index 64139e5..63bf9a7 100644 --- a/WebCore/platform/network/cf/SocketStreamHandle.h +++ b/WebCore/platform/network/cf/SocketStreamHandle.h @@ -32,10 +32,9 @@ #ifndef SocketStreamHandle_h #define SocketStreamHandle_h +#include "AuthenticationClient.h" #include "SocketStreamHandleBase.h" - -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> +#include <wtf/RetainPtr.h> namespace WebCore { @@ -43,24 +42,69 @@ namespace WebCore { class Credential; class SocketStreamHandleClient; - class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase { + class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase, public AuthenticationClient { public: static PassRefPtr<SocketStreamHandle> create(const KURL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); } virtual ~SocketStreamHandle(); - protected: + using RefCounted<SocketStreamHandle>::ref; + using RefCounted<SocketStreamHandle>::deref; + + private: virtual int platformSend(const char* data, int length); virtual void platformClose(); - private: SocketStreamHandle(const KURL&, SocketStreamHandleClient*); + void createStreams(); + void scheduleStreams(); + void chooseProxy(); +#ifndef BUILDING_ON_TIGER + void chooseProxyFromArray(CFArrayRef); + void executePACFileURL(CFURLRef); + void removePACRunLoopSource(); + RetainPtr<CFRunLoopSourceRef> m_pacRunLoopSource; + static void pacExecutionCallback(void* client, CFArrayRef proxyList, CFErrorRef error); + static void pacExecutionCallbackMainThread(void*); + static CFStringRef copyPACExecutionDescription(void*); +#endif + + bool shouldUseSSL() const { return m_url.protocolIs("wss"); } + + void addCONNECTCredentials(CFHTTPMessageRef response); + + static CFStringRef copyCFStreamDescription(void* ); + static void readStreamCallback(CFReadStreamRef, CFStreamEventType, void*); + static void writeStreamCallback(CFWriteStreamRef, CFStreamEventType, void*); +#if PLATFORM(WIN) + static void readStreamCallbackMainThread(void*); + static void writeStreamCallbackMainThread(void*); +#endif + void readStreamCallback(CFStreamEventType); + void writeStreamCallback(CFStreamEventType); // No authentication for streams per se, but proxy may ask for credentials. - void didReceiveAuthenticationChallenge(const AuthenticationChallenge&); - void receivedCredential(const AuthenticationChallenge&, const Credential&); - void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); - void receivedCancellation(const AuthenticationChallenge&); + virtual void receivedCredential(const AuthenticationChallenge&, const Credential&); + virtual void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); + virtual void receivedCancellation(const AuthenticationChallenge&); + + virtual void refAuthenticationClient() { ref(); } + virtual void derefAuthenticationClient() { deref(); } + + enum ConnectingSubstate { New, ExecutingPACFile, WaitingForCredentials, WaitingForConnect, Connected }; + ConnectingSubstate m_connectingSubstate; + + enum ConnectionType { Unknown, Direct, SOCKSProxy, CONNECTProxy }; + ConnectionType m_connectionType; + RetainPtr<CFStringRef> m_proxyHost; + RetainPtr<CFNumberRef> m_proxyPort; + + RetainPtr<CFHTTPMessageRef> m_proxyResponseMessage; + bool m_sentStoredCredentials; + RetainPtr<CFReadStreamRef> m_readStream; + RetainPtr<CFWriteStreamRef> m_writeStream; + + RetainPtr<CFURLRef> m_httpsURL; // ws(s): replaced with https: }; } // namespace WebCore diff --git a/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp b/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp index 6aa33fc..e7e64da 100644 --- a/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp +++ b/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp @@ -1,4 +1,5 @@ /* + * Copyright (C) 2009 Apple Inc. All rights reserved. * Copyright (C) 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,58 +32,608 @@ #include "config.h" #include "SocketStreamHandle.h" -#include "KURL.h" +#include "Credential.h" +#include "CredentialStorage.h" #include "Logging.h" -#include "NotImplemented.h" +#include "ProtectionSpace.h" +#include "SocketStreamError.h" #include "SocketStreamHandleClient.h" +#include <wtf/MainThread.h> + +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) +#include <SystemConfiguration/SystemConfiguration.h> +#endif + +#if PLATFORM(WIN) +#include "LoaderRunLoopCF.h" +#include <WebKitSystemInterface/WebKitSystemInterface.h> +#else +#include "WebCoreSystemInterface.h" +#endif + +#ifdef BUILDING_ON_TIGER +#define CFN_EXPORT extern +#endif namespace WebCore { SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client) : SocketStreamHandleBase(url, client) + , m_connectingSubstate(New) + , m_connectionType(Unknown) + , m_sentStoredCredentials(false) { LOG(Network, "SocketStreamHandle %p new client %p", this, m_client); - notImplemented(); + + ASSERT(url.protocolIs("ws") || url.protocolIs("wss")); + + if (!m_url.port()) + m_url.setPort(shouldUseSSL() ? 443 : 80); + + KURL httpsURL(KURL(), "https://" + m_url.host()); + m_httpsURL.adoptCF(httpsURL.createCFURL()); + + createStreams(); + ASSERT(!m_readStream == !m_writeStream); + if (!m_readStream) // Doing asynchronous PAC file processing, streams will be created later. + return; + + scheduleStreams(); +} + +void SocketStreamHandle::scheduleStreams() +{ + ASSERT(m_readStream); + ASSERT(m_writeStream); + + CFStreamClientContext clientContext = { 0, this, 0, 0, copyCFStreamDescription }; + // FIXME: Pass specific events we're interested in instead of -1. + CFReadStreamSetClient(m_readStream.get(), static_cast<CFOptionFlags>(-1), readStreamCallback, &clientContext); + CFWriteStreamSetClient(m_writeStream.get(), static_cast<CFOptionFlags>(-1), writeStreamCallback, &clientContext); + +#if PLATFORM(WIN) + CFReadStreamScheduleWithRunLoop(m_readStream.get(), loaderRunLoop(), kCFRunLoopDefaultMode); + CFWriteStreamScheduleWithRunLoop(m_writeStream.get(), loaderRunLoop(), kCFRunLoopDefaultMode); +#else + CFReadStreamScheduleWithRunLoop(m_readStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + CFWriteStreamScheduleWithRunLoop(m_writeStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes); +#endif + + CFReadStreamOpen(m_readStream.get()); + CFWriteStreamOpen(m_writeStream.get()); + +#ifndef BUILDING_ON_TIGER + if (m_pacRunLoopSource) + removePACRunLoopSource(); +#endif + + m_connectingSubstate = WaitingForConnect; +} + +#ifndef BUILDING_ON_TIGER +CFStringRef SocketStreamHandle::copyPACExecutionDescription(void*) +{ + return CFSTR("WebSocket proxy PAC file execution"); +} + +struct MainThreadPACCallbackInfo { + MainThreadPACCallbackInfo(SocketStreamHandle* handle, CFArrayRef proxyList) : handle(handle), proxyList(proxyList) { } + SocketStreamHandle* handle; + CFArrayRef proxyList; +}; + +void SocketStreamHandle::pacExecutionCallback(void* client, CFArrayRef proxyList, CFErrorRef) +{ + SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(client); + MainThreadPACCallbackInfo info(handle, proxyList); + // If we're already on main thread (e.g. on Mac), callOnMainThreadAndWait() will be just a function call. + callOnMainThreadAndWait(pacExecutionCallbackMainThread, &info); +} + +void SocketStreamHandle::pacExecutionCallbackMainThread(void* invocation) +{ + MainThreadPACCallbackInfo* info = static_cast<MainThreadPACCallbackInfo*>(invocation); + ASSERT(info->handle->m_connectingSubstate == ExecutingPACFile); + // This time, the array won't have PAC as a first entry. + info->handle->chooseProxyFromArray(info->proxyList); + info->handle->createStreams(); + info->handle->scheduleStreams(); +} + +void SocketStreamHandle::executePACFileURL(CFURLRef pacFileURL) +{ + // CFNetwork returns an empty proxy array for WebScoket schemes, so use m_httpsURL. + CFStreamClientContext clientContext = { 0, this, 0, 0, copyPACExecutionDescription }; + m_pacRunLoopSource.adoptCF(CFNetworkExecuteProxyAutoConfigurationURL(pacFileURL, m_httpsURL.get(), pacExecutionCallback, &clientContext)); +#if PLATFORM(WIN) + CFRunLoopAddSource(loaderRunLoop(), m_pacRunLoopSource.get(), kCFRunLoopDefaultMode); +#else + CFRunLoopAddSource(CFRunLoopGetCurrent(), m_pacRunLoopSource.get(), kCFRunLoopCommonModes); +#endif + m_connectingSubstate = ExecutingPACFile; +} + +void SocketStreamHandle::removePACRunLoopSource() +{ + ASSERT(m_pacRunLoopSource); + + CFRunLoopSourceInvalidate(m_pacRunLoopSource.get()); +#if PLATFORM(WIN) + CFRunLoopRemoveSource(loaderRunLoop(), m_pacRunLoopSource.get(), kCFRunLoopDefaultMode); +#else + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_pacRunLoopSource.get(), kCFRunLoopCommonModes); +#endif + m_pacRunLoopSource = 0; +} + +void SocketStreamHandle::chooseProxy() +{ +#ifndef BUILDING_ON_LEOPARD + RetainPtr<CFDictionaryRef> proxyDictionary(AdoptCF, CFNetworkCopySystemProxySettings()); +#else + // We don't need proxy information often, so there is no need to set up a permanent dynamic store session. + RetainPtr<CFDictionaryRef> proxyDictionary(AdoptCF, SCDynamicStoreCopyProxies(0)); +#endif + + // SOCKS or HTTPS (AKA CONNECT) proxies are supported. + // WebSocket protocol relies on handshake being transferred unchanged, so we need a proxy that will not modify headers. + // Since HTTP proxies must add Via headers, they are highly unlikely to work. + // Many CONNECT proxies limit connectivity to port 443, so we prefer SOCKS, if configured. + + if (!proxyDictionary) { + m_connectionType = Direct; + return; + } + + // CFNetworkCopyProxiesForURL doesn't know about WebSocket schemes, so pretend to use http. + // Always use "https" to get HTTPS proxies in result - we'll try to use those for ws:// even though many are configured to reject connections to ports other than 443. + RetainPtr<CFArrayRef> proxyArray(AdoptCF, CFNetworkCopyProxiesForURL(m_httpsURL.get(), proxyDictionary.get())); + + chooseProxyFromArray(proxyArray.get()); +} + +void SocketStreamHandle::chooseProxyFromArray(CFArrayRef proxyArray) +{ + if (!proxyArray) + m_connectionType = Direct; + + CFIndex proxyArrayCount = CFArrayGetCount(proxyArray); + + // PAC is always the first entry, if present. + if (proxyArrayCount) { + CFDictionaryRef proxyInfo = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(proxyArray, 0)); + CFTypeRef proxyType = CFDictionaryGetValue(proxyInfo, kCFProxyTypeKey); + if (proxyType && CFGetTypeID(proxyType) == CFStringGetTypeID()) { + if (CFEqual(proxyType, kCFProxyTypeAutoConfigurationURL)) { + CFTypeRef pacFileURL = CFDictionaryGetValue(proxyInfo, kCFProxyAutoConfigurationURLKey); + if (pacFileURL && CFGetTypeID(pacFileURL) == CFURLGetTypeID()) { + executePACFileURL(static_cast<CFURLRef>(pacFileURL)); + return; + } + } + } + } + + CFDictionaryRef chosenProxy = 0; + for (CFIndex i = 0; i < proxyArrayCount; ++i) { + CFDictionaryRef proxyInfo = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(proxyArray, i)); + CFTypeRef proxyType = CFDictionaryGetValue(proxyInfo, kCFProxyTypeKey); + if (proxyType && CFGetTypeID(proxyType) == CFStringGetTypeID()) { + if (CFEqual(proxyType, kCFProxyTypeSOCKS)) { + m_connectionType = SOCKSProxy; + chosenProxy = proxyInfo; + break; + } + if (CFEqual(proxyType, kCFProxyTypeHTTPS)) { + m_connectionType = CONNECTProxy; + chosenProxy = proxyInfo; + // Keep looking for proxies, as a SOCKS one is preferable. + } + } + } + + if (chosenProxy) { + ASSERT(m_connectionType != Unknown); + ASSERT(m_connectionType != Direct); + + CFTypeRef proxyHost = CFDictionaryGetValue(chosenProxy, kCFProxyHostNameKey); + CFTypeRef proxyPort = CFDictionaryGetValue(chosenProxy, kCFProxyPortNumberKey); + + if (proxyHost && CFGetTypeID(proxyHost) == CFStringGetTypeID() && proxyPort && CFGetTypeID(proxyPort) == CFNumberGetTypeID()) { + m_proxyHost = static_cast<CFStringRef>(proxyHost); + m_proxyPort = static_cast<CFNumberRef>(proxyPort); + return; + } + } + + m_connectionType = Direct; +} + +#else // BUILDING_ON_TIGER + +void SocketStreamHandle::chooseProxy() +{ + // We don't need proxy information often, so there is no need to set up a permanent dynamic store session. + RetainPtr<CFDictionaryRef> proxyDictionary(AdoptCF, SCDynamicStoreCopyProxies(0)); + + // SOCKS or HTTPS (AKA CONNECT) proxies are supported. + // WebSocket protocol relies on handshake being transferred unchanged, so we need a proxy that will not modify headers. + // Since HTTP proxies must add Via headers, they are highly unlikely to work. + // Many CONNECT proxies limit connectivity to port 443, so we prefer SOCKS, if configured. + + if (!proxyDictionary) { + m_connectionType = Direct; + return; + } + + // FIXME: check proxy bypass list and ExcludeSimpleHostnames. + // FIXME: Support PAC files. + + CFTypeRef socksEnableCF = CFDictionaryGetValue(proxyDictionary.get(), kSCPropNetProxiesSOCKSEnable); + int socksEnable; + if (socksEnableCF && CFGetTypeID(socksEnableCF) == CFNumberGetTypeID() && CFNumberGetValue(static_cast<CFNumberRef>(socksEnableCF), kCFNumberIntType, &socksEnable) && socksEnable) { + CFTypeRef proxyHost = CFDictionaryGetValue(proxyDictionary.get(), kSCPropNetProxiesSOCKSProxy); + CFTypeRef proxyPort = CFDictionaryGetValue(proxyDictionary.get(), kSCPropNetProxiesSOCKSPort); + if (proxyHost && CFGetTypeID(proxyHost) == CFStringGetTypeID() && proxyPort && CFGetTypeID(proxyPort) == CFNumberGetTypeID()) { + m_proxyHost = static_cast<CFStringRef>(proxyHost); + m_proxyPort = static_cast<CFNumberRef>(proxyPort); + m_connectionType = SOCKSProxy; + return; + } + } + + CFTypeRef httpsEnableCF = CFDictionaryGetValue(proxyDictionary.get(), kSCPropNetProxiesHTTPSEnable); + int httpsEnable; + if (httpsEnableCF && CFGetTypeID(httpsEnableCF) == CFNumberGetTypeID() && CFNumberGetValue(static_cast<CFNumberRef>(httpsEnableCF), kCFNumberIntType, &httpsEnable) && httpsEnable) { + CFTypeRef proxyHost = CFDictionaryGetValue(proxyDictionary.get(), kSCPropNetProxiesHTTPSProxy); + CFTypeRef proxyPort = CFDictionaryGetValue(proxyDictionary.get(), kSCPropNetProxiesHTTPSPort); + + if (proxyHost && CFGetTypeID(proxyHost) == CFStringGetTypeID() && proxyPort && CFGetTypeID(proxyPort) == CFNumberGetTypeID()) { + m_proxyHost = static_cast<CFStringRef>(proxyHost); + m_proxyPort = static_cast<CFNumberRef>(proxyPort); + m_connectionType = CONNECTProxy; + return; + } + } + + m_connectionType = Direct; +} +#endif // BUILDING_ON_TIGER + +void SocketStreamHandle::createStreams() +{ + if (m_connectionType == Unknown) + chooseProxy(); + + // If it's still unknown, then we're resolving a PAC file asynchronously. + if (m_connectionType == Unknown) + return; + + RetainPtr<CFStringRef> host(AdoptCF, m_url.host().createCFString()); + + // Creating streams to final destination, not to proxy. + CFReadStreamRef readStream = 0; + CFWriteStreamRef writeStream = 0; + CFStreamCreatePairWithSocketToHost(0, host.get(), m_url.port(), &readStream, &writeStream); + + m_readStream.adoptCF(readStream); + m_writeStream.adoptCF(writeStream); + + switch (m_connectionType) { + case Unknown: + ASSERT_NOT_REACHED(); + break; + case Direct: + break; + case SOCKSProxy: { + // FIXME: SOCKS5 doesn't do challenge-response, should we try to apply credentials from Keychain right away? + // But SOCKS5 credentials don't work at the time of this writing anyway, see <rdar://6776698>. + const void* proxyKeys[] = { kCFStreamPropertySOCKSProxyHost, kCFStreamPropertySOCKSProxyPort }; + const void* proxyValues[] = { m_proxyHost.get(), m_proxyPort.get() }; + RetainPtr<CFDictionaryRef> connectDictionary(AdoptCF, CFDictionaryCreate(0, proxyKeys, proxyValues, sizeof(proxyKeys) / sizeof(*proxyKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + CFReadStreamSetProperty(m_readStream.get(), kCFStreamPropertySOCKSProxy, connectDictionary.get()); + break; + } + case CONNECTProxy: + wkSetCONNECTProxyForStream(m_readStream.get(), m_proxyHost.get(), m_proxyPort.get()); + break; + } + + if (shouldUseSSL()) { + const void* keys[] = { kCFStreamSSLPeerName, kCFStreamSSLLevel }; + const void* values[] = { host.get(), kCFStreamSocketSecurityLevelNegotiatedSSL }; + RetainPtr<CFDictionaryRef> settings(AdoptCF, CFDictionaryCreate(0, keys, values, sizeof(keys) / sizeof(*keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + CFReadStreamSetProperty(m_readStream.get(), kCFStreamPropertySSLSettings, settings.get()); + CFWriteStreamSetProperty(m_writeStream.get(), kCFStreamPropertySSLSettings, settings.get()); + } +} + +static bool getStoredCONNECTProxyCredentials(const ProtectionSpace& protectionSpace, String& login, String& password) +{ + // Try system credential storage first, matching HTTP behavior (CFNetwork only asks the client for password if it couldn't find it in Keychain). + Credential storedCredential = CredentialStorage::getFromPersistentStorage(protectionSpace); + if (storedCredential.isEmpty()) + storedCredential = CredentialStorage::get(protectionSpace); + + if (storedCredential.isEmpty()) + return false; + + login = storedCredential.user(); + password = storedCredential.password(); + + return true; +} + +static ProtectionSpaceAuthenticationScheme authenticationSchemeFromAuthenticationMethod(CFStringRef method) +{ + if (CFEqual(method, kCFHTTPAuthenticationSchemeBasic)) + return ProtectionSpaceAuthenticationSchemeHTTPBasic; + if (CFEqual(method, kCFHTTPAuthenticationSchemeDigest)) + return ProtectionSpaceAuthenticationSchemeHTTPDigest; +#ifndef BUILDING_ON_TIGER + if (CFEqual(method, kCFHTTPAuthenticationSchemeNTLM)) + return ProtectionSpaceAuthenticationSchemeNTLM; + if (CFEqual(method, kCFHTTPAuthenticationSchemeNegotiate)) + return ProtectionSpaceAuthenticationSchemeNegotiate; +#endif + ASSERT_NOT_REACHED(); + return ProtectionSpaceAuthenticationSchemeDefault; +} + +void SocketStreamHandle::addCONNECTCredentials(CFHTTPMessageRef proxyResponse) +{ + RetainPtr<CFHTTPAuthenticationRef> authentication(AdoptCF, CFHTTPAuthenticationCreateFromResponse(0, proxyResponse)); + + if (!CFHTTPAuthenticationRequiresUserNameAndPassword(authentication.get())) { + // That's all we can offer... + m_client->didFail(this, SocketStreamError()); // FIXME: Provide a sensible error. + return; + } + + int port = 0; + CFNumberGetValue(m_proxyPort.get(), kCFNumberIntType, &port); + RetainPtr<CFStringRef> methodCF(AdoptCF, CFHTTPAuthenticationCopyMethod(authentication.get())); + RetainPtr<CFStringRef> realmCF(AdoptCF, CFHTTPAuthenticationCopyRealm(authentication.get())); + ProtectionSpace protectionSpace(String(m_proxyHost.get()), port, ProtectionSpaceProxyHTTPS, String(realmCF.get()), authenticationSchemeFromAuthenticationMethod(methodCF.get())); + String login; + String password; + if (!m_sentStoredCredentials && getStoredCONNECTProxyCredentials(protectionSpace, login, password)) { + // Try to apply stored credentials, if we haven't tried those already. + RetainPtr<CFStringRef> loginCF(AdoptCF, login.createCFString()); + RetainPtr<CFStringRef> passwordCF(AdoptCF, password.createCFString()); + // Creating a temporary request to make CFNetwork apply credentials to it. Unfortunately, this cannot work with NTLM authentication. + RetainPtr<CFHTTPMessageRef> dummyRequest(AdoptCF, CFHTTPMessageCreateRequest(0, CFSTR("GET"), m_httpsURL.get(), kCFHTTPVersion1_1)); + + Boolean appliedCredentials = CFHTTPMessageApplyCredentials(dummyRequest.get(), authentication.get(), loginCF.get(), passwordCF.get(), 0); + ASSERT_UNUSED(appliedCredentials, appliedCredentials); + + RetainPtr<CFStringRef> proxyAuthorizationString(AdoptCF, CFHTTPMessageCopyHeaderFieldValue(dummyRequest.get(), CFSTR("Proxy-Authorization"))); + + if (!proxyAuthorizationString) { + // Fails e.g. for NTLM auth. + m_client->didFail(this, SocketStreamError()); // FIXME: Provide a sensible error. + return; + } + + // Setting the authorization results in a new connection attempt. + wkSetCONNECTProxyAuthorizationForStream(m_readStream.get(), proxyAuthorizationString.get()); + m_sentStoredCredentials = true; + return; + } + + // FIXME: Ask the client if credentials could not be found. + + m_client->didFail(this, SocketStreamError()); // FIXME: Provide a sensible error. +} + +CFStringRef SocketStreamHandle::copyCFStreamDescription(void* info) +{ + SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(info); + return ("WebKit socket stream, " + handle->m_url.string()).createCFString(); +} + +struct MainThreadEventCallbackInfo { + MainThreadEventCallbackInfo(CFStreamEventType type, SocketStreamHandle* handle) : type(type), handle(handle) { } + CFStreamEventType type; + SocketStreamHandle* handle; +}; + +void SocketStreamHandle::readStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void* clientCallBackInfo) +{ + SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(clientCallBackInfo); + ASSERT_UNUSED(stream, stream == handle->m_readStream.get()); +#if PLATFORM(WIN) + MainThreadEventCallbackInfo info(type, handle); + callOnMainThreadAndWait(readStreamCallbackMainThread, &info); +#else + ASSERT(isMainThread()); + handle->readStreamCallback(type); +#endif +} + +void SocketStreamHandle::writeStreamCallback(CFWriteStreamRef stream, CFStreamEventType type, void* clientCallBackInfo) +{ + SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(clientCallBackInfo); + ASSERT_UNUSED(stream, stream == handle->m_writeStream.get()); +#if PLATFORM(WIN) + MainThreadEventCallbackInfo info(type, handle); + callOnMainThreadAndWait(writeStreamCallbackMainThread, &info); +#else + ASSERT(isMainThread()); + handle->writeStreamCallback(type); +#endif +} + +#if PLATFORM(WIN) +void SocketStreamHandle::readStreamCallbackMainThread(void* invocation) +{ + MainThreadEventCallbackInfo* info = static_cast<MainThreadEventCallbackInfo*>(invocation); + info->handle->readStreamCallback(info->type); +} + +void SocketStreamHandle::writeStreamCallbackMainThread(void* invocation) +{ + MainThreadEventCallbackInfo* info = static_cast<MainThreadEventCallbackInfo*>(invocation); + info->handle->writeStreamCallback(info->type); +} +#endif // PLATFORM(WIN) + +void SocketStreamHandle::readStreamCallback(CFStreamEventType type) +{ + switch(type) { + case kCFStreamEventNone: + break; + case kCFStreamEventOpenCompleted: + break; + case kCFStreamEventHasBytesAvailable: { + if (m_connectingSubstate == WaitingForConnect) { + if (m_connectionType == CONNECTProxy) { + RetainPtr<CFHTTPMessageRef> proxyResponse(AdoptCF, wkCopyCONNECTProxyResponse(m_readStream.get(), m_httpsURL.get())); + if (proxyResponse && (407 == CFHTTPMessageGetResponseStatusCode(proxyResponse.get()))) { + addCONNECTCredentials(proxyResponse.get()); + return; + } + } + } else if (m_connectingSubstate == WaitingForCredentials) + break; + + if (m_connectingSubstate == WaitingForConnect) { + m_connectingSubstate = Connected; + m_state = Open; + + RefPtr<SocketStreamHandle> protect(this); // The client can close the handle, potentially removing the last reference. + m_client->didOpen(this); + if (m_state == Closed) + break; + // Fall through. + } else if (m_state == Closed) + break; + + ASSERT(m_state == Open); + ASSERT(m_connectingSubstate == Connected); + + CFIndex length; + UInt8 localBuffer[1024]; // Used if CFReadStreamGetBuffer couldn't return anything. + const UInt8* ptr = CFReadStreamGetBuffer(m_readStream.get(), 0, &length); + if (!ptr) { + length = CFReadStreamRead(m_readStream.get(), localBuffer, sizeof(localBuffer)); + ptr = localBuffer; + } + + m_client->didReceiveData(this, reinterpret_cast<const char*>(ptr), length); + + break; + } + case kCFStreamEventCanAcceptBytes: + ASSERT_NOT_REACHED(); + break; + case kCFStreamEventErrorOccurred: { + CFStreamError error = CFReadStreamGetError(m_readStream.get()); + m_client->didFail(this, SocketStreamError(error.error)); // FIXME: Provide a sensible error. + break; + } + case kCFStreamEventEndEncountered: + platformClose(); + break; + } +} + +void SocketStreamHandle::writeStreamCallback(CFStreamEventType type) +{ + switch(type) { + case kCFStreamEventNone: + break; + case kCFStreamEventOpenCompleted: + break; + case kCFStreamEventHasBytesAvailable: + ASSERT_NOT_REACHED(); + break; + case kCFStreamEventCanAcceptBytes: { + // Possibly, a spurious event from CONNECT handshake. + if (!CFWriteStreamCanAcceptBytes(m_writeStream.get())) + return; + + if (m_connectingSubstate == WaitingForCredentials) + break; + + if (m_connectingSubstate == WaitingForConnect) { + m_connectingSubstate = Connected; + m_state = Open; + + RefPtr<SocketStreamHandle> protect(this); // The client can close the handle, potentially removing the last reference. + m_client->didOpen(this); + break; + } + + ASSERT(m_state = Open); + ASSERT(m_connectingSubstate == Connected); + + sendPendingData(); + break; + } + case kCFStreamEventErrorOccurred: { + CFStreamError error = CFWriteStreamGetError(m_writeStream.get()); + m_client->didFail(this, SocketStreamError(error.error)); // FIXME: Provide a sensible error. + break; + } + case kCFStreamEventEndEncountered: + // FIXME: Currently, we handle closing in read callback, but these can come independently (e.g. a server can stop listening, but keep sending data). + break; + } } SocketStreamHandle::~SocketStreamHandle() { - LOG(Network, "SocketStreamHandle %p delete", this); - setClient(0); - notImplemented(); + LOG(Network, "SocketStreamHandle %p dtor", this); + +#ifndef BUILDING_ON_TIGER + ASSERT(!m_pacRunLoopSource); +#endif } -int SocketStreamHandle::platformSend(const char*, int) +int SocketStreamHandle::platformSend(const char* data, int length) { - LOG(Network, "SocketStreamHandle %p platformSend", this); - notImplemented(); - return 0; + if (!CFWriteStreamCanAcceptBytes(m_writeStream.get())) + return 0; + + return CFWriteStreamWrite(m_writeStream.get(), reinterpret_cast<const UInt8*>(data), length); } void SocketStreamHandle::platformClose() { LOG(Network, "SocketStreamHandle %p platformClose", this); - notImplemented(); -} -void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&) -{ - notImplemented(); +#ifndef BUILDING_ON_TIGER + if (m_pacRunLoopSource) + removePACRunLoopSource(); +#endif + + ASSERT(!m_readStream == !m_writeStream); + if (!m_readStream) + return; + + CFReadStreamUnscheduleFromRunLoop(m_readStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + CFWriteStreamUnscheduleFromRunLoop(m_writeStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + + CFReadStreamClose(m_readStream.get()); + CFWriteStreamClose(m_writeStream.get()); + + m_readStream = 0; + m_writeStream = 0; + + m_client->didClose(this); } void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&) { - notImplemented(); } void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&) { - notImplemented(); } void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&) { - notImplemented(); } } // namespace WebCore diff --git a/WebCore/platform/network/chromium/AuthenticationChallenge.h b/WebCore/platform/network/chromium/AuthenticationChallenge.h index cd1b430..e2d1f42 100644 --- a/WebCore/platform/network/chromium/AuthenticationChallenge.h +++ b/WebCore/platform/network/chromium/AuthenticationChallenge.h @@ -28,25 +28,23 @@ #define AuthenticationChallenge_h #include "AuthenticationChallengeBase.h" -#include "ResourceHandle.h" +#include "AuthenticationClient.h" #include <wtf/RefPtr.h> namespace WebCore { - class ResourceHandle; - class AuthenticationChallenge : public AuthenticationChallengeBase { public: AuthenticationChallenge() {} AuthenticationChallenge(const ProtectionSpace&, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse&, const ResourceError&); - ResourceHandle* sourceHandle() const { return m_sourceHandle.get(); } + AuthenticationClient* authenticationClient() const { return m_authenticationClient.get(); } private: friend class AuthenticationChallengeBase; static bool platformCompare(const AuthenticationChallenge&, const AuthenticationChallenge&); - RefPtr<ResourceHandle> m_sourceHandle; + RefPtr<AuthenticationClient> m_authenticationClient; }; } // namespace WebCore diff --git a/WebCore/platform/network/chromium/CookieJarChromium.cpp b/WebCore/platform/network/chromium/CookieJarChromium.cpp index 7862cc3..279d9b0 100644 --- a/WebCore/platform/network/chromium/CookieJarChromium.cpp +++ b/WebCore/platform/network/chromium/CookieJarChromium.cpp @@ -53,16 +53,14 @@ bool cookiesEnabled(const Document*) return true; } -bool getRawCookies(const Document*, const KURL&, Vector<Cookie>& rawCookies) +bool getRawCookies(const Document* document, const KURL& url, Vector<Cookie>& rawCookies) { - // FIXME: Not yet implemented - rawCookies.clear(); - return false; // return true when implemented + return ChromiumBridge::rawCookies(url, document->firstPartyForCookies(), &rawCookies); } -void deleteCookie(const Document*, const KURL&, const String&) +void deleteCookie(const Document*, const KURL& url, const String& cookieName) { - // FIXME: Not yet implemented + return ChromiumBridge::deleteCookie(url, cookieName); } } // namespace WebCore diff --git a/WebCore/platform/network/chromium/ResourceRequest.cpp b/WebCore/platform/network/chromium/ResourceRequest.cpp index 76d1288..5b27c1b 100644 --- a/WebCore/platform/network/chromium/ResourceRequest.cpp +++ b/WebCore/platform/network/chromium/ResourceRequest.cpp @@ -23,6 +23,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" +#include "ResourceRequest.h" + namespace WebCore { // This is used by the loader to control the number of issued parallel load requests. diff --git a/WebCore/platform/network/chromium/ResourceRequest.h b/WebCore/platform/network/chromium/ResourceRequest.h index 48ff1e7..176f923 100644 --- a/WebCore/platform/network/chromium/ResourceRequest.h +++ b/WebCore/platform/network/chromium/ResourceRequest.h @@ -35,22 +35,13 @@ namespace WebCore { class Frame; - struct ResourceRequest : public ResourceRequestBase { + class ResourceRequest : public ResourceRequestBase { public: - enum TargetType { - TargetIsMainFrame, - TargetIsSubFrame, - TargetIsSubResource, - TargetIsObject, - TargetIsMedia - }; - ResourceRequest(const String& url) : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) , m_requestorID(0) , m_requestorProcessID(0) , m_appCacheHostID(0) - , m_targetType(TargetIsSubResource) { } @@ -59,7 +50,6 @@ namespace WebCore { , m_requestorID(0) , m_requestorProcessID(0) , m_appCacheHostID(0) - , m_targetType(TargetIsSubResource) , m_securityInfo(securityInfo) { } @@ -69,7 +59,6 @@ namespace WebCore { , m_requestorID(0) , m_requestorProcessID(0) , m_appCacheHostID(0) - , m_targetType(TargetIsSubResource) { } @@ -78,7 +67,6 @@ namespace WebCore { , m_requestorID(0) , m_requestorProcessID(0) , m_appCacheHostID(0) - , m_targetType(TargetIsSubResource) { setHTTPReferrer(referrer); } @@ -88,7 +76,6 @@ namespace WebCore { , m_requestorID(0) , m_requestorProcessID(0) , m_appCacheHostID(0) - , m_targetType(TargetIsSubResource) { } @@ -96,10 +83,6 @@ namespace WebCore { int requestorID() const { return m_requestorID; } void setRequestorID(int requestorID) { m_requestorID = requestorID; } - // What this request is for. - TargetType targetType() const { return m_targetType; } - void setTargetType(TargetType type) { m_targetType = type; } - // The process id of the process from which this request originated. In // the case of out-of-process plugins, this allows to link back the // request to the plugin process (as it is processed through a render @@ -129,7 +112,6 @@ namespace WebCore { int m_requestorID; int m_requestorProcessID; int m_appCacheHostID; - TargetType m_targetType; CString m_securityInfo; }; diff --git a/WebCore/platform/network/curl/AuthenticationChallenge.h b/WebCore/platform/network/curl/AuthenticationChallenge.h index a64d575..7ace096 100644 --- a/WebCore/platform/network/curl/AuthenticationChallenge.h +++ b/WebCore/platform/network/curl/AuthenticationChallenge.h @@ -26,13 +26,11 @@ #define AuthenticationChallenge_h #include "AuthenticationChallengeBase.h" -#include "ResourceHandle.h" +#include "AuthenticationClient.h" #include <wtf/RefPtr.h> namespace WebCore { -class ResourceHandle; - class AuthenticationChallenge : public AuthenticationChallengeBase { public: AuthenticationChallenge() @@ -44,9 +42,9 @@ public: { } - ResourceHandle* sourceHandle() const { return m_sourceHandle.get(); } + AuthenticationClient* authenticationClient() const { return m_authenticationClient.get(); } - RefPtr<ResourceHandle> m_sourceHandle; + RefPtr<AuthenticationClient> m_authenticationClient; }; } diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp index d8a812f..a006a14 100644 --- a/WebCore/platform/network/curl/ResourceHandleManager.cpp +++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp @@ -49,6 +49,11 @@ #include <wtf/Threading.h> #include <wtf/Vector.h> +#if !PLATFORM(WIN_OS) +#include <sys/param.h> +#define MAX_PATH MAXPATHLEN +#endif + namespace WebCore { const int selectTimeoutMS = 5; diff --git a/WebCore/platform/network/curl/ResourceRequest.h b/WebCore/platform/network/curl/ResourceRequest.h index 3fa2795..40e1e8f 100644 --- a/WebCore/platform/network/curl/ResourceRequest.h +++ b/WebCore/platform/network/curl/ResourceRequest.h @@ -33,8 +33,8 @@ typedef const struct _CFURLRequest* CFURLRequestRef; namespace WebCore { - struct ResourceRequest : ResourceRequestBase { - + class ResourceRequest : public ResourceRequestBase { + public: ResourceRequest(const String& url) : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { diff --git a/WebCore/platform/network/mac/AuthenticationChallenge.h b/WebCore/platform/network/mac/AuthenticationChallenge.h index e8f3a2d..d74a92c 100644 --- a/WebCore/platform/network/mac/AuthenticationChallenge.h +++ b/WebCore/platform/network/mac/AuthenticationChallenge.h @@ -37,21 +37,25 @@ class NSURLAuthenticationChallenge; namespace WebCore { +class AuthenticationClient; + class AuthenticationChallenge : public AuthenticationChallengeBase { public: - AuthenticationChallenge() {} + AuthenticationChallenge() { } AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse& response, const ResourceError& error); AuthenticationChallenge(NSURLAuthenticationChallenge *); id sender() const { return m_sender.get(); } - NSURLAuthenticationChallenge *nsURLAuthenticationChallenge() const { return m_macChallenge.get(); } + NSURLAuthenticationChallenge *nsURLAuthenticationChallenge() const { return m_nsChallenge.get(); } + + void setAuthenticationClient(AuthenticationClient*); // Changes sender to one that invokes client methods. private: friend class AuthenticationChallengeBase; static bool platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b); - RetainPtr<id> m_sender; - RetainPtr<NSURLAuthenticationChallenge *> m_macChallenge; + RetainPtr<id> m_sender; // Always the same as [m_macChallenge.get() sender], cached here for performance. + RetainPtr<NSURLAuthenticationChallenge *> m_nsChallenge; }; } diff --git a/WebCore/platform/network/mac/AuthenticationMac.mm b/WebCore/platform/network/mac/AuthenticationMac.mm index 93725d5..ea06ecd 100644 --- a/WebCore/platform/network/mac/AuthenticationMac.mm +++ b/WebCore/platform/network/mac/AuthenticationMac.mm @@ -26,6 +26,7 @@ #import "AuthenticationMac.h" #import "AuthenticationChallenge.h" +#import "AuthenticationClient.h" #import "Credential.h" #import "ProtectionSpace.h" @@ -33,6 +34,51 @@ #import <Foundation/NSURLCredential.h> #import <Foundation/NSURLProtectionSpace.h> +using namespace WebCore; + +@interface WebCoreAuthenticationClientAsChallengeSender : NSObject <NSURLAuthenticationChallengeSender> +{ + AuthenticationClient* m_client; +} +- (id)initWithAuthenticationClient:(AuthenticationClient*)client; +- (void)detachClient; +@end + +@implementation WebCoreAuthenticationClientAsChallengeSender + +- (id)initWithAuthenticationClient:(AuthenticationClient*)client +{ + self = [self init]; + if (!self) + return nil; + m_client = client; + return self; +} + +- (void)detachClient +{ + m_client = 0; +} + +- (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + if (m_client) + m_client->receivedCredential(core(challenge), core(credential)); +} + +- (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + if (m_client) + m_client->receivedRequestToContinueWithoutCredential(core(challenge)); +} + +- (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + if (m_client) + m_client->receivedCancellation(core(challenge)); +} + +@end namespace WebCore { @@ -49,17 +95,28 @@ AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protecti { } -AuthenticationChallenge::AuthenticationChallenge(NSURLAuthenticationChallenge *macChallenge) - : AuthenticationChallengeBase(core([macChallenge protectionSpace]), - core([macChallenge proposedCredential]), - [macChallenge previousFailureCount], - [macChallenge failureResponse], - [macChallenge error]) - , m_sender([macChallenge sender]) - , m_macChallenge(macChallenge) +AuthenticationChallenge::AuthenticationChallenge(NSURLAuthenticationChallenge *challenge) + : AuthenticationChallengeBase(core([challenge protectionSpace]), + core([challenge proposedCredential]), + [challenge previousFailureCount], + [challenge failureResponse], + [challenge error]) + , m_sender([challenge sender]) + , m_nsChallenge(challenge) { } +void AuthenticationChallenge::setAuthenticationClient(AuthenticationClient* client) +{ + if (client) { + m_sender.adoptNS([[WebCoreAuthenticationClientAsChallengeSender alloc] initWithAuthenticationClient:client]); + m_nsChallenge.adoptNS([[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:m_nsChallenge.get() sender:m_sender.get()]); + } else { + if ([m_sender.get() isMemberOfClass:[WebCoreAuthenticationClientAsChallengeSender class]]) + [(WebCoreAuthenticationClientAsChallengeSender *)m_sender.get() detachClient]; + } +} + bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b) { if (a.sender() != b.sender()) @@ -131,6 +188,11 @@ NSURLProtectionSpace *mac(const ProtectionSpace& coreSpace) case ProtectionSpaceAuthenticationSchemeHTMLForm: method = NSURLAuthenticationMethodHTMLForm; break; +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + case ProtectionSpaceAuthenticationSchemeNTLM: + method = NSURLAuthenticationMethodNTLM; + break; +#endif default: ASSERT_NOT_REACHED(); } @@ -167,6 +229,15 @@ NSURLCredential *mac(const Credential& coreCredential) ASSERT_NOT_REACHED(); } +#if CERTIFICATE_CREDENTIALS_SUPPORTED + if (coreCredential.type() == CredentialTypeClientCertificate) { + return [[[NSURLCredential alloc] initWithIdentity:coreCredential.identity() + certificates:(NSArray *)coreCredential.certificates() + persistence:persistence] + autorelease]; + } +#endif + return [[[NSURLCredential alloc] initWithUser:coreCredential.user() password:coreCredential.password() persistence:persistence] @@ -218,6 +289,10 @@ ProtectionSpace core(NSURLProtectionSpace *macSpace) scheme = ProtectionSpaceAuthenticationSchemeHTTPDigest; else if ([method isEqualToString:NSURLAuthenticationMethodHTMLForm]) scheme = ProtectionSpaceAuthenticationSchemeHTMLForm; +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + else if ([method isEqualToString:NSURLAuthenticationMethodNTLM]) + scheme = ProtectionSpaceAuthenticationSchemeNTLM; +#endif else ASSERT_NOT_REACHED(); @@ -240,6 +315,12 @@ Credential core(NSURLCredential *macCredential) default: ASSERT_NOT_REACHED(); } + +#if CERTIFICATE_CREDENTIALS_SUPPORTED + SecIdentityRef identity = [macCredential identity]; + if (identity) + return Credential(identity, (CFArrayRef)[macCredential certificates], persistence); +#endif return Credential([macCredential user], [macCredential password], persistence); } diff --git a/WebCore/platform/network/mac/CredentialStorageMac.mm b/WebCore/platform/network/mac/CredentialStorageMac.mm new file mode 100644 index 0000000..66e94e9 --- /dev/null +++ b/WebCore/platform/network/mac/CredentialStorageMac.mm @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CredentialStorage.h" + +#include "AuthenticationMac.h" +#include "Credential.h" + +namespace WebCore { + +Credential CredentialStorage::getFromPersistentStorage(const ProtectionSpace& protectionSpace) +{ + NSURLCredential *credential = [[NSURLCredentialStorage sharedCredentialStorage] defaultCredentialForProtectionSpace:mac(protectionSpace)]; + return credential ? core(credential) : Credential(); +} + +} // namespace WebCore diff --git a/WebCore/platform/network/mac/NetworkStateNotifierMac.cpp b/WebCore/platform/network/mac/NetworkStateNotifierMac.cpp index c0918a4..2045eb3 100644 --- a/WebCore/platform/network/mac/NetworkStateNotifierMac.cpp +++ b/WebCore/platform/network/mac/NetworkStateNotifierMac.cpp @@ -28,10 +28,10 @@ #include <SystemConfiguration/SystemConfiguration.h> -#ifdef BUILDING_ON_TIGER -// This function is available on Tiger, but not declared in the CFRunLoop.h header on Tiger. -extern "C" CFRunLoopRef CFRunLoopGetMain(); -#endif +#ifdef BUILDING_ON_TIGER +// This function is available on Tiger, but not declared in the CFRunLoop.h header on Tiger. +extern "C" CFRunLoopRef CFRunLoopGetMain(); +#endif namespace WebCore { diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm index 3630b30..360425e 100644 --- a/WebCore/platform/network/mac/ResourceHandleMac.mm +++ b/WebCore/platform/network/mac/ResourceHandleMac.mm @@ -55,7 +55,7 @@ typedef int NSInteger; using namespace WebCore; -@interface WebCoreResourceHandleAsDelegate : NSObject <NSURLAuthenticationChallengeSender> +@interface WebCoreResourceHandleAsDelegate : NSObject { ResourceHandle* m_handle; } @@ -138,6 +138,7 @@ ResourceHandleInternal::~ResourceHandleInternal() ResourceHandle::~ResourceHandle() { releaseDelegate(); + d->m_currentWebChallenge.setAuthenticationClient(0); LOG(Network, "Handle %p destroyed", this); } @@ -511,10 +512,8 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall #endif d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge(); - NSURLAuthenticationChallenge *webChallenge = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:d->m_currentMacChallenge - sender:(id<NSURLAuthenticationChallengeSender>)delegate()]; - d->m_currentWebChallenge = core(webChallenge); - [webChallenge release]; + d->m_currentWebChallenge = core(d->m_currentMacChallenge); + d->m_currentWebChallenge.setAuthenticationClient(this); if (client()) client()->didReceiveAuthenticationChallenge(this, d->m_currentWebChallenge); @@ -523,8 +522,8 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall void ResourceHandle::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge) { ASSERT(d->m_currentMacChallenge); + ASSERT(d->m_currentMacChallenge == challenge.nsURLAuthenticationChallenge()); ASSERT(!d->m_currentWebChallenge.isNull()); - ASSERT(d->m_currentWebChallenge == challenge); if (client()) client()->didCancelAuthenticationChallenge(this, challenge); @@ -547,7 +546,7 @@ void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge // Manage per-session credentials internally, because once NSURLCredentialPersistenceForSession is used, there is no way // to ignore it for a particular request (short of removing it altogether). // <rdar://problem/6867598> gallery.me.com is temporarily whitelisted, so that QuickTime plug-in could see the credentials. - Credential webCredential(credential.user(), credential.password(), CredentialPersistenceNone); + Credential webCredential(credential, CredentialPersistenceNone); KURL urlToStore; if (challenge.failureResponse().httpStatusCode() == 401) urlToStore = d->m_request.url(); @@ -868,27 +867,6 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen return newResponse; } -- (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge -{ - if (!m_handle) - return; - m_handle->receivedCredential(core(challenge), core(credential)); -} - -- (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge -{ - if (!m_handle) - return; - m_handle->receivedRequestToContinueWithoutCredential(core(challenge)); -} - -- (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge -{ - if (!m_handle) - return; - m_handle->receivedCancellation(core(challenge)); -} - @end #ifndef BUILDING_ON_TIGER diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index ed5e024..f7bbb9d 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -21,8 +21,6 @@ #include "config.h" #include "QNetworkReplyHandler.h" -#if QT_VERSION >= 0x040400 - #include "HTTPParsers.h" #include "MIMETypeRegistry.h" #include "ResourceHandle.h" @@ -140,10 +138,14 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load m_method = QNetworkAccessManager::PostOperation; else if (r.httpMethod() == "PUT") m_method = QNetworkAccessManager::PutOperation; +#if QT_VERSION >= 0x040600 + else if (r.httpMethod() == "DELETE") + m_method = QNetworkAccessManager::DeleteOperation; +#endif else m_method = QNetworkAccessManager::UnknownOperation; - m_request = r.toNetworkRequest(); + m_request = r.toNetworkRequest(m_resourceHandle->getInternal()->m_frame); if (m_loadMode == LoadNormal) start(); @@ -255,7 +257,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded() if (m_shouldSendResponse) return; - if (m_reply->error()) + if (m_reply->error() && !ignoreHttpError(m_reply, m_responseDataSent)) return; if (m_responseSent || !m_resourceHandle) @@ -305,9 +307,15 @@ void QNetworkReplyHandler::sendResponseIfNeeded() response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData()); // Add remaining headers. +#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) + foreach (const QNetworkReply::RawHeaderPair& pair, m_reply->rawHeaderPairs()) { + response.setHTTPHeaderField(QString::fromAscii(pair.first), QString::fromAscii(pair.second)); + } +#else foreach (const QByteArray& headerName, m_reply->rawHeaderList()) { response.setHTTPHeaderField(QString::fromAscii(headerName), QString::fromAscii(m_reply->rawHeader(headerName))); } +#endif } QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); @@ -321,12 +329,13 @@ void QNetworkReplyHandler::sendResponseIfNeeded() newRequest.setHTTPMethod("GET"); } + // Should not set Referer after a redirect from a secure resource to non-secure one. + if (!newRequest.url().protocolIs("https") && protocolIs(newRequest.httpReferrer(), "https")) + newRequest.clearHTTPReferrer(); + client->willSendRequest(m_resourceHandle, newRequest, response); m_redirected = true; - m_request = newRequest.toNetworkRequest(); - - ResourceHandleInternal* d = m_resourceHandle->getInternal(); - emit d->m_frame->page()->networkRequestStarted(d->m_frame, &m_request); + m_request = newRequest.toNetworkRequest(m_resourceHandle->getInternal()->m_frame); return; } @@ -368,8 +377,6 @@ void QNetworkReplyHandler::start() QNetworkAccessManager* manager = d->m_frame->page()->networkAccessManager(); - emit d->m_frame->page()->networkRequestStarted(d->m_frame, &m_request); - const QUrl url = m_request.url(); const QString scheme = url.scheme(); // Post requests on files and data don't really make sense, but for @@ -398,6 +405,12 @@ void QNetworkReplyHandler::start() putDevice->setParent(m_reply); break; } +#if QT_VERSION >= 0x040600 + case QNetworkAccessManager::DeleteOperation: { + m_reply = manager->deleteResource(m_request); + break; + } +#endif case QNetworkAccessManager::UnknownOperation: { m_reply = 0; ResourceHandleClient* client = m_resourceHandle->client(); @@ -461,5 +474,3 @@ void QNetworkReplyHandler::sendQueuedItems() } #include "moc_QNetworkReplyHandler.cpp" - -#endif diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.h b/WebCore/platform/network/qt/QNetworkReplyHandler.h index fccc4a6..2171083 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.h +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.h @@ -21,8 +21,6 @@ #include <QObject> -#if QT_VERSION >= 0x040400 - #include <QNetworkRequest> #include <QNetworkAccessManager> @@ -113,6 +111,4 @@ private: } -#endif - #endif // QNETWORKREPLYHANDLER_H diff --git a/WebCore/platform/network/qt/ResourceHandleQt.cpp b/WebCore/platform/network/qt/ResourceHandleQt.cpp index f4c30c9..09cdefd 100644 --- a/WebCore/platform/network/qt/ResourceHandleQt.cpp +++ b/WebCore/platform/network/qt/ResourceHandleQt.cpp @@ -48,13 +48,9 @@ #endif #include <QCoreApplication> #include <QUrl> -#if QT_VERSION >= 0x040400 #include <QNetworkAccessManager> #include <QNetworkRequest> #include <QNetworkReply> -#else -#include "qwebnetworkinterface_p.h" -#endif namespace WebCore { @@ -131,24 +127,25 @@ bool ResourceHandle::start(Frame* frame) if (!page) return false; + if (!(d->m_user.isEmpty() || d->m_pass.isEmpty())) { + // If credentials were specified for this request, add them to the url, + // so that they will be passed to QNetworkRequest. + KURL urlWithCredentials(d->m_request.url()); + urlWithCredentials.setUser(d->m_user); + urlWithCredentials.setPass(d->m_pass); + d->m_request.setURL(urlWithCredentials); + } + getInternal()->m_frame = static_cast<FrameLoaderClientQt*>(frame->loader()->client())->webFrame(); -#if QT_VERSION < 0x040400 - return QWebNetworkManager::self()->add(this, getInternal()->m_frame->page()->d->networkInterface); -#else ResourceHandleInternal *d = getInternal(); d->m_job = new QNetworkReplyHandler(this, QNetworkReplyHandler::LoadMode(d->m_defersLoading)); return true; -#endif } void ResourceHandle::cancel() { -#if QT_VERSION < 0x040400 - QWebNetworkManager::self()->cancel(this); -#else if (d->m_job) d->m_job->abort(); -#endif } bool ResourceHandle::loadsBlocked() @@ -196,17 +193,17 @@ void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, S WebCoreSynchronousLoader syncLoader; ResourceHandle handle(request, &syncLoader, true, false, true); -#if QT_VERSION < 0x040400 - if (!QWebNetworkManager::self()->add(&handle, QWebNetworkInterface::defaultInterface(), QWebNetworkManager::SynchronousJob)) { - // FIXME Create a sane ResourceError - error = ResourceError(String(), -1, String(), String()); - return; - } -#else ResourceHandleInternal *d = handle.getInternal(); + if (!(d->m_user.isEmpty() || d->m_pass.isEmpty())) { + // If credentials were specified for this request, add them to the url, + // so that they will be passed to QNetworkRequest. + KURL urlWithCredentials(d->m_request.url()); + urlWithCredentials.setUser(d->m_user); + urlWithCredentials.setPass(d->m_pass); + d->m_request.setURL(urlWithCredentials); + } d->m_frame = static_cast<FrameLoaderClientQt*>(frame->loader()->client())->webFrame(); d->m_job = new QNetworkReplyHandler(&handle, QNetworkReplyHandler::LoadNormal); -#endif syncLoader.waitForCompletion(); error = syncLoader.resourceError(); @@ -219,10 +216,8 @@ void ResourceHandle::setDefersLoading(bool defers) { d->m_defersLoading = defers; -#if QT_VERSION >= 0x040400 if (d->m_job) d->m_job->setLoadMode(QNetworkReplyHandler::LoadMode(defers)); -#endif } } // namespace WebCore diff --git a/WebCore/platform/network/qt/ResourceRequest.h b/WebCore/platform/network/qt/ResourceRequest.h index 93dacf3..fb69326 100644 --- a/WebCore/platform/network/qt/ResourceRequest.h +++ b/WebCore/platform/network/qt/ResourceRequest.h @@ -31,12 +31,13 @@ QT_BEGIN_NAMESPACE class QNetworkRequest; +class QObject; QT_END_NAMESPACE namespace WebCore { - struct ResourceRequest : ResourceRequestBase { - + class ResourceRequest : public ResourceRequestBase { + public: ResourceRequest(const String& url) : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { @@ -58,9 +59,7 @@ namespace WebCore { { } -#if QT_VERSION >= 0x040400 - QNetworkRequest toNetworkRequest() const; -#endif + QNetworkRequest toNetworkRequest(QObject* originatingObject) const; private: friend class ResourceRequestBase; diff --git a/WebCore/platform/network/qt/ResourceRequestQt.cpp b/WebCore/platform/network/qt/ResourceRequestQt.cpp index c8f6ad5..752abfe 100644 --- a/WebCore/platform/network/qt/ResourceRequestQt.cpp +++ b/WebCore/platform/network/qt/ResourceRequestQt.cpp @@ -21,24 +21,31 @@ #include "ResourceRequest.h" #include <qglobal.h> -#if QT_VERSION >= 0x040400 #include <QNetworkRequest> #include <QUrl> namespace WebCore { -QNetworkRequest ResourceRequest::toNetworkRequest() const +QNetworkRequest ResourceRequest::toNetworkRequest(QObject* originatingFrame) const { QNetworkRequest request; request.setUrl(url()); +#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) + request.setOriginatingObject(originatingFrame); +#endif const HTTPHeaderMap &headers = httpHeaderFields(); for (HTTPHeaderMap::const_iterator it = headers.begin(), end = headers.end(); it != end; ++it) { QByteArray name = QString(it->first).toAscii(); QByteArray value = QString(it->second).toAscii(); - request.setRawHeader(name, value); + // QNetworkRequest::setRawHeader() would remove the header if the value is null + // Make sure to set an empty header instead of null header. + if (!value.isNull()) + request.setRawHeader(name, value); + else + request.setRawHeader(name, ""); } switch (cachePolicy()) { @@ -62,4 +69,3 @@ QNetworkRequest ResourceRequest::toNetworkRequest() const } -#endif diff --git a/WebCore/platform/network/soup/DNSSoup.cpp b/WebCore/platform/network/soup/DNSSoup.cpp index 1ffe1a0..ce55143 100644 --- a/WebCore/platform/network/soup/DNSSoup.cpp +++ b/WebCore/platform/network/soup/DNSSoup.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2009 Igalia S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,13 +27,19 @@ #include "config.h" #include "DNS.h" -#include "NotImplemented.h" +#include "CString.h" +#include "ResourceHandle.h" namespace WebCore { void prefetchDNS(const String& hostname) { - notImplemented(); + #ifdef HAVE_LIBSOUP_2_29_3 + String uri = "http://"+hostname; + SoupURI* soupUri = soup_uri_new(uri.utf8().data()); + soup_session_prepare_for_uri(ResourceHandle::defaultSession(), soupUri); + soup_uri_free(soupUri); + #endif } } diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp index 2177bd2..6367a3e 100644 --- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -200,6 +200,13 @@ static void restartedCallback(SoupMessage* msg, gpointer data) request.setURL(newURL); request.setHTTPMethod(msg->method); fillResponseFromMessage(msg, &response); + + // 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(); + soup_message_headers_remove(msg->request_headers, "Referer"); + } + if (d->client()) d->client()->willSendRequest(handle, request, response); } @@ -686,6 +693,13 @@ static void closeCallback(GObject* source, GAsyncResult* res, gpointer) g_input_stream_close_finish(d->m_inputStream, res, 0); cleanupGioOperation(handle.get()); + + // The load may have been cancelled, the client may have been + // destroyed already. In such cases calling didFinishLoading is a + // bad idea. + if (d->m_cancelled || !client) + return; + client->didFinishLoading(handle.get()); } @@ -866,7 +880,7 @@ static bool startGio(ResourceHandle* handle, KURL url) // using GIO internally, and providing URIs instead of file paths url.removeFragmentIdentifier(); url.setQuery(String()); - url.setPort(0); + url.removePort(); #if !PLATFORM(WIN_OS) // we avoid the escaping for local files, because diff --git a/WebCore/platform/network/soup/ResourceRequest.h b/WebCore/platform/network/soup/ResourceRequest.h index 42b7baa..8270863 100644 --- a/WebCore/platform/network/soup/ResourceRequest.h +++ b/WebCore/platform/network/soup/ResourceRequest.h @@ -33,8 +33,8 @@ namespace WebCore { - struct ResourceRequest : ResourceRequestBase { - + class ResourceRequest : public ResourceRequestBase { + public: ResourceRequest(const String& url) : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { @@ -66,7 +66,7 @@ namespace WebCore { void updateFromSoupMessage(SoupMessage* soupMessage); private: - friend struct ResourceRequestBase; + friend class ResourceRequestBase; void doUpdatePlatformRequest() {}; void doUpdateResourceRequest() {}; diff --git a/WebCore/platform/network/soup/ResourceResponse.h b/WebCore/platform/network/soup/ResourceResponse.h index 5fa31a0..ecd9f21 100644 --- a/WebCore/platform/network/soup/ResourceResponse.h +++ b/WebCore/platform/network/soup/ResourceResponse.h @@ -44,7 +44,14 @@ public: { } + ResourceResponse(SoupMessage* soupMessage) + : ResourceResponseBase() + { + updateFromSoupMessage(soupMessage); + } + SoupMessage* toSoupMessage() const; + void updateFromSoupMessage(SoupMessage* soupMessage); private: friend class ResourceResponseBase; diff --git a/WebCore/platform/network/soup/ResourceResponseSoup.cpp b/WebCore/platform/network/soup/ResourceResponseSoup.cpp index 293577f..caf0b31 100644 --- a/WebCore/platform/network/soup/ResourceResponseSoup.cpp +++ b/WebCore/platform/network/soup/ResourceResponseSoup.cpp @@ -22,6 +22,7 @@ #include "ResourceResponse.h" #include "CString.h" +#include "GOwnPtr.h" #include "PlatformString.h" using namespace std; @@ -49,4 +50,21 @@ SoupMessage* ResourceResponse::toSoupMessage() const return soupMessage; } +void ResourceResponse::updateFromSoupMessage(SoupMessage* soupMessage) +{ + SoupURI* soupURI = soup_message_get_uri(soupMessage); + GOwnPtr<gchar> uri(soup_uri_to_string(soupURI, FALSE)); + m_url = KURL(KURL(), String::fromUTF8(uri.get())); + + m_httpStatusCode = soupMessage->status_code; + + SoupMessageHeadersIter headersIter; + const char* headerName; + const char* headerValue; + + soup_message_headers_iter_init(&headersIter, soupMessage->response_headers); + while (soup_message_headers_iter_next(&headersIter, &headerName, &headerValue)) + m_httpHeaderFields.set(String::fromUTF8(headerName), String::fromUTF8(headerValue)); +} + } |