diff options
Diffstat (limited to 'Source/WebCore/platform/network')
33 files changed, 1008 insertions, 696 deletions
diff --git a/Source/WebCore/platform/network/BlobData.h b/Source/WebCore/platform/network/BlobData.h index c1f5522..f919d64 100644 --- a/Source/WebCore/platform/network/BlobData.h +++ b/Source/WebCore/platform/network/BlobData.h @@ -34,11 +34,11 @@ #include "KURL.h" #include "PlatformString.h" #include <wtf/Forward.h> -#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadSafeRefCounted.h> namespace WebCore { -class RawData : public ThreadSafeShared<RawData> { +class RawData : public ThreadSafeRefCounted<RawData> { public: static PassRefPtr<RawData> create() { diff --git a/Source/WebCore/platform/network/FormDataBuilder.cpp b/Source/WebCore/platform/network/FormDataBuilder.cpp index e973f99..3174614 100644 --- a/Source/WebCore/platform/network/FormDataBuilder.cpp +++ b/Source/WebCore/platform/network/FormDataBuilder.cpp @@ -32,6 +32,7 @@ #include <limits> #include <wtf/Assertions.h> +#include <wtf/HexNumber.h> #include <wtf/text/CString.h> #include <wtf/RandomNumber.h> @@ -192,8 +193,6 @@ void FormDataBuilder::addKeyValuePairAsFormData(Vector<char>& buffer, const CStr void FormDataBuilder::encodeStringAsFormData(Vector<char>& buffer, const CString& string) { - static const char hexDigits[17] = "0123456789ABCDEF"; - // Same safe characters as Netscape for compatibility. static const char safeCharacters[] = "-._*"; @@ -210,8 +209,7 @@ void FormDataBuilder::encodeStringAsFormData(Vector<char>& buffer, const CString append(buffer, "%0D%0A"); else if (c != '\r') { append(buffer, '%'); - append(buffer, hexDigits[c >> 4]); - append(buffer, hexDigits[c & 0xF]); + appendByteAsHex(c, buffer); } } } diff --git a/Source/WebCore/platform/network/ProtectionSpace.h b/Source/WebCore/platform/network/ProtectionSpace.h index deb59d2..87758e1 100644 --- a/Source/WebCore/platform/network/ProtectionSpace.h +++ b/Source/WebCore/platform/network/ProtectionSpace.h @@ -49,7 +49,7 @@ enum ProtectionSpaceAuthenticationScheme { ProtectionSpaceAuthenticationSchemeNegotiate = 6, ProtectionSpaceAuthenticationSchemeClientCertificateRequested = 7, ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested = 8, - ProtectionSpaceAuthenticationSchemeUnknown = 100, + ProtectionSpaceAuthenticationSchemeUnknown = 100 }; class ProtectionSpace { diff --git a/Source/WebCore/platform/network/ProtectionSpaceHash.h b/Source/WebCore/platform/network/ProtectionSpaceHash.h index 9934321..40eb9b6 100644 --- a/Source/WebCore/platform/network/ProtectionSpaceHash.h +++ b/Source/WebCore/platform/network/ProtectionSpaceHash.h @@ -46,7 +46,7 @@ struct ProtectionSpaceHash { // Ignore realm for proxies. if (protectionSpace.isProxy()) codeCount -= sizeof(hashCodes[0]); - return WTF::StringHasher::createBlobHash(hashCodes, codeCount); + return StringHasher::hashMemory(hashCodes, codeCount); } static bool equal(const ProtectionSpace& a, const ProtectionSpace& b) { return a == b; } diff --git a/Source/WebCore/platform/network/ResourceErrorBase.cpp b/Source/WebCore/platform/network/ResourceErrorBase.cpp index 42bc0de..e1d29e0 100644 --- a/Source/WebCore/platform/network/ResourceErrorBase.cpp +++ b/Source/WebCore/platform/network/ResourceErrorBase.cpp @@ -42,6 +42,7 @@ ResourceError ResourceErrorBase::copy() const errorCopy.m_localizedDescription = m_localizedDescription.crossThreadString(); errorCopy.m_isNull = m_isNull; errorCopy.m_isCancellation = m_isCancellation; + platformCopy(errorCopy); return errorCopy; } diff --git a/Source/WebCore/platform/network/ResourceErrorBase.h b/Source/WebCore/platform/network/ResourceErrorBase.h index a6b7c69..2d7be70 100644 --- a/Source/WebCore/platform/network/ResourceErrorBase.h +++ b/Source/WebCore/platform/network/ResourceErrorBase.h @@ -74,6 +74,9 @@ protected: // The ResourceError subclass may "shadow" this method to lazily initialize platform specific fields void platformLazyInit() {} + // The ResourceError subclass may "shadow" this method to copy platform specific fields + void platformCopy(ResourceError&) const {} + // The ResourceError subclass may "shadow" this method to compare platform specific fields static bool platformCompare(const ResourceError&, const ResourceError&) { return true; } diff --git a/Source/WebCore/platform/network/ResourceHandleClient.h b/Source/WebCore/platform/network/ResourceHandleClient.h index d9350ee..e92b376 100644 --- a/Source/WebCore/platform/network/ResourceHandleClient.h +++ b/Source/WebCore/platform/network/ResourceHandleClient.h @@ -59,7 +59,7 @@ namespace WebCore { enum CacheStoragePolicy { StorageAllowed, StorageAllowedInMemoryOnly, - StorageNotAllowed, + StorageNotAllowed }; class ResourceHandleClient { @@ -78,6 +78,11 @@ namespace WebCore { virtual void wasBlocked(ResourceHandle*) { } virtual void cannotShowURL(ResourceHandle*) { } +#if HAVE(CFNETWORK_DATA_ARRAY_CALLBACK) + virtual bool supportsDataArray() { return false; } + virtual void didReceiveDataArray(ResourceHandle*, CFArrayRef) { } +#endif + virtual void willCacheResponse(ResourceHandle*, CacheStoragePolicy&) { } virtual bool shouldUseCredentialStorage(ResourceHandle*) { return false; } diff --git a/Source/WebCore/platform/network/ResourceRequestBase.h b/Source/WebCore/platform/network/ResourceRequestBase.h index ec7e32a..31a1e69 100644 --- a/Source/WebCore/platform/network/ResourceRequestBase.h +++ b/Source/WebCore/platform/network/ResourceRequestBase.h @@ -41,7 +41,7 @@ namespace WebCore { UseProtocolCachePolicy, // normal load ReloadIgnoringCacheData, // reload ReturnCacheDataElseLoad, // back/forward or encoding change - allow stale data - ReturnCacheDataDontLoad, // results of a post - allow stale data and only use cache + ReturnCacheDataDontLoad // results of a post - allow stale data and only use cache }; class ResourceRequest; diff --git a/Source/WebCore/platform/network/cf/CookieStorageCFNet.cpp b/Source/WebCore/platform/network/cf/CookieStorageCFNet.cpp index c2a5691..2eac3f6 100644 --- a/Source/WebCore/platform/network/cf/CookieStorageCFNet.cpp +++ b/Source/WebCore/platform/network/cf/CookieStorageCFNet.cpp @@ -42,7 +42,7 @@ namespace WebCore { -static RetainPtr<CFHTTPCookieStorageRef>& privateBrowsingCookieStorage() +static RetainPtr<CFHTTPCookieStorageRef>& privateCookieStorage() { DEFINE_STATIC_LOCAL(RetainPtr<CFHTTPCookieStorageRef>, cookieStorage, ()); return cookieStorage; @@ -52,16 +52,21 @@ CFHTTPCookieStorageRef currentCookieStorage() { ASSERT(isMainThread()); - if (CFHTTPCookieStorageRef privateCookieStorage = privateBrowsingCookieStorage().get()) - return privateCookieStorage; + if (CFHTTPCookieStorageRef cookieStorage = privateCookieStorage().get()) + return cookieStorage; return wkGetDefaultHTTPCookieStorage(); } +CFHTTPCookieStorageRef privateBrowsingCookieStorage() +{ + return privateCookieStorage().get(); +} + void setCurrentCookieStorage(CFHTTPCookieStorageRef cookieStorage) { ASSERT(isMainThread()); - privateBrowsingCookieStorage().adoptCF(cookieStorage); + privateCookieStorage().adoptCF(cookieStorage); } void setCookieStoragePrivateBrowsingEnabled(bool enabled) @@ -69,15 +74,21 @@ void setCookieStoragePrivateBrowsingEnabled(bool enabled) ASSERT(isMainThread()); if (!enabled) { - privateBrowsingCookieStorage() = nullptr; + privateCookieStorage() = nullptr; return; } #if USE(CFURLSTORAGESESSIONS) - privateBrowsingCookieStorage().adoptCF(wkCreatePrivateInMemoryHTTPCookieStorage(ResourceHandle::privateBrowsingStorageSession())); -#else - privateBrowsingCookieStorage().adoptCF(wkCreatePrivateInMemoryHTTPCookieStorage(0)); + if (CFURLStorageSessionRef privateStorageSession = ResourceHandle::privateBrowsingStorageSession()) + privateCookieStorage().adoptCF(wkCopyHTTPCookieStorage(privateStorageSession)); + else #endif + privateCookieStorage().adoptCF(wkCreateInMemoryHTTPCookieStorage()); +} + +CFHTTPCookieStorageRef defaultCookieStorage() +{ + return wkGetDefaultHTTPCookieStorage(); } static void notifyCookiesChangedOnMainThread(void* context) diff --git a/Source/WebCore/platform/network/cf/CookieStorageCFNet.h b/Source/WebCore/platform/network/cf/CookieStorageCFNet.h index 0167587..d33c76e 100644 --- a/Source/WebCore/platform/network/cf/CookieStorageCFNet.h +++ b/Source/WebCore/platform/network/cf/CookieStorageCFNet.h @@ -33,6 +33,8 @@ typedef struct OpaqueCFHTTPCookieStorage* CFHTTPCookieStorageRef; namespace WebCore { CFHTTPCookieStorageRef currentCookieStorage(); + CFHTTPCookieStorageRef defaultCookieStorage(); + CFHTTPCookieStorageRef privateBrowsingCookieStorage(); // Needed for WebKit1 API only. void setCurrentCookieStorage(CFHTTPCookieStorageRef cookieStorage); diff --git a/Source/WebCore/platform/network/cf/LoaderRunLoopCF.h b/Source/WebCore/platform/network/cf/LoaderRunLoopCF.h index e0d3ba4..272acf9 100644 --- a/Source/WebCore/platform/network/cf/LoaderRunLoopCF.h +++ b/Source/WebCore/platform/network/cf/LoaderRunLoopCF.h @@ -29,7 +29,7 @@ #if USE(CFNETWORK) #if !PLATFORM(WIN) -#error This code is not needed on platforms other than Windows, because main thread's CFRunLoop can be used. +#error This code is not needed on platforms other than Windows, because the CFRunLoop from the main thread can be used. #endif typedef struct __CFRunLoop* CFRunLoopRef; diff --git a/Source/WebCore/platform/network/cf/ResourceError.h b/Source/WebCore/platform/network/cf/ResourceError.h index aae9a4a..d36903f 100644 --- a/Source/WebCore/platform/network/cf/ResourceError.h +++ b/Source/WebCore/platform/network/cf/ResourceError.h @@ -32,6 +32,7 @@ #if USE(CFNETWORK) #include <CoreFoundation/CFStream.h> #else + #ifdef __OBJC__ @class NSError; #else @@ -54,38 +55,38 @@ public: { } -#if USE(CFNETWORK) - ResourceError(CFStreamError error); - - ResourceError(CFErrorRef error) - : m_dataIsUpToDate(false) - , m_platformError(error) - { - m_isNull = !error; - } + ResourceError(CFErrorRef error); + CFErrorRef cfError() const; operator CFErrorRef() const; + +#if USE(CFNETWORK) +#if PLATFORM(WIN) + ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription, CFDataRef certificate); + PCCERT_CONTEXT certificate() const; +#endif + ResourceError(CFStreamError error); + CFStreamError cfStreamError() const; operator CFStreamError() const; #else - ResourceError(NSError* error) - : m_dataIsUpToDate(false) - , m_platformError(error) - { - m_isNull = !error; - } - - operator NSError*() const; + ResourceError(NSError *); + NSError *nsError() const; + operator NSError *() const; #endif private: friend class ResourceErrorBase; void platformLazyInit(); + void platformCopy(ResourceError&) const; static bool platformCompare(const ResourceError& a, const ResourceError& b); bool m_dataIsUpToDate; #if USE(CFNETWORK) mutable RetainPtr<CFErrorRef> m_platformError; +#if PLATFORM(WIN) + RetainPtr<CFDataRef> m_certificate; +#endif #else mutable RetainPtr<NSError> m_platformError; #endif diff --git a/Source/WebCore/platform/network/cf/ResourceErrorCF.cpp b/Source/WebCore/platform/network/cf/ResourceErrorCF.cpp index 1eba97e..556ad6e 100644 --- a/Source/WebCore/platform/network/cf/ResourceErrorCF.cpp +++ b/Source/WebCore/platform/network/cf/ResourceErrorCF.cpp @@ -24,44 +24,46 @@ */ #include "config.h" -#include "KURL.h" #include "ResourceError.h" #if USE(CFNETWORK) -// FIXME: Once <rdar://problem/5050881> is fixed in open source we -// can remove this extern "C" -extern "C" { -#include <CFNetwork/CFNetworkErrors.h> -} - +#include "KURL.h" #include <CoreFoundation/CFError.h> +#include <CFNetwork/CFNetworkErrors.h> +#if PLATFORM(WIN) +#include <WebKitSystemInterface/WebKitSystemInterface.h> +#endif #include <WTF/RetainPtr.h> namespace WebCore { -const CFStringRef failingURLStringKey = CFSTR("NSErrorFailingURLStringKey"); -const CFStringRef failingURLKey = CFSTR("NSErrorFailingURLKey"); +ResourceError::ResourceError(CFErrorRef cfError) + : m_dataIsUpToDate(false) + , m_platformError(cfError) +{ + m_isNull = !cfError; +} -// FIXME: Once <rdar://problem/5050841> is fixed we can remove this constructor. -ResourceError::ResourceError(CFStreamError error) - : m_dataIsUpToDate(true) +#if PLATFORM(WIN) +ResourceError::ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription, CFDataRef certificate) + : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription) + , m_dataIsUpToDate(true) + , m_certificate(certificate) { - m_isNull = false; - m_errorCode = error.error; +} - switch(error.domain) { - case kCFStreamErrorDomainCustom: - m_domain ="NSCustomErrorDomain"; - break; - case kCFStreamErrorDomainPOSIX: - m_domain = "NSPOSIXErrorDomain"; - break; - case kCFStreamErrorDomainMacOSStatus: - m_domain = "NSOSStatusErrorDomain"; - break; - } +PCCERT_CONTEXT ResourceError::certificate() const +{ + if (!m_certificate) + return 0; + + return reinterpret_cast<PCCERT_CONTEXT>(CFDataGetBytePtr(m_certificate.get())); } +#endif // PLATFORM(WIN) + +const CFStringRef failingURLStringKey = CFSTR("NSErrorFailingURLStringKey"); +const CFStringRef failingURLKey = CFSTR("NSErrorFailingURLKey"); void ResourceError::platformLazyInit() { @@ -101,23 +103,34 @@ void ResourceError::platformLazyInit() } } m_localizedDescription = (CFStringRef) CFDictionaryGetValue(userInfo.get(), kCFErrorLocalizedDescriptionKey); + +#if PLATFORM(WIN) + m_certificate = wkGetSSLPeerCertificateData(userInfo.get()); +#endif } m_dataIsUpToDate = true; } +void ResourceError::platformCopy(ResourceError& errorCopy) const +{ +#if PLATFORM(WIN) + errorCopy.m_certificate = m_certificate; +#endif +} + bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b) { - return (CFErrorRef)a == (CFErrorRef)b; + return a.cfError() == b.cfError(); } -ResourceError::operator CFErrorRef() const +CFErrorRef ResourceError::cfError() const { if (m_isNull) { ASSERT(!m_platformError); return 0; } - + if (!m_platformError) { RetainPtr<CFMutableDictionaryRef> userInfo(AdoptCF, CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); @@ -133,6 +146,11 @@ ResourceError::operator CFErrorRef() const CFDictionarySetValue(userInfo.get(), failingURLKey, url.get()); } +#if PLATFORM(WIN) + if (m_certificate) + wkSetSSLPeerCertificateData(userInfo.get(), m_certificate.get()); +#endif + RetainPtr<CFStringRef> domainString(AdoptCF, m_domain.createCFString()); m_platformError.adoptCF(CFErrorCreate(0, domainString.get(), m_errorCode, userInfo.get())); } @@ -140,7 +158,32 @@ ResourceError::operator CFErrorRef() const return m_platformError.get(); } -ResourceError::operator CFStreamError() const +ResourceError::operator CFErrorRef() const +{ + return cfError(); +} + +// FIXME: Once <rdar://problem/5050841> is fixed we can remove this constructor. +ResourceError::ResourceError(CFStreamError error) + : m_dataIsUpToDate(true) +{ + m_isNull = false; + m_errorCode = error.error; + + switch(error.domain) { + case kCFStreamErrorDomainCustom: + m_domain ="NSCustomErrorDomain"; + break; + case kCFStreamErrorDomainPOSIX: + m_domain = "NSPOSIXErrorDomain"; + break; + case kCFStreamErrorDomainMacOSStatus: + m_domain = "NSOSStatusErrorDomain"; + break; + } +} + +CFStreamError ResourceError::cfStreamError() const { lazyInit(); @@ -159,6 +202,11 @@ ResourceError::operator CFStreamError() const return result; } +ResourceError::operator CFStreamError() const +{ + return cfStreamError(); +} + } // namespace WebCore #endif // USE(CFNETWORK) diff --git a/Source/WebCore/platform/network/cf/ResourceRequestCFNet.h b/Source/WebCore/platform/network/cf/ResourceRequestCFNet.h index 09f4cea..271dcd2 100644 --- a/Source/WebCore/platform/network/cf/ResourceRequestCFNet.h +++ b/Source/WebCore/platform/network/cf/ResourceRequestCFNet.h @@ -50,6 +50,8 @@ inline ResourceLoadPriority mapHTTPPipeliningPriorityToResourceLoadPriority(int return ResourceLoadPriorityMedium; case 2: return ResourceLoadPriorityHigh; + case 3: + return ResourceLoadPriorityUnresolved; default: ASSERT_NOT_REACHED(); return ResourceLoadPriorityLowest; @@ -67,8 +69,7 @@ inline int mapResourceLoadPriorityToHTTPPipeliningPriority(ResourceLoadPriority case ResourceLoadPriorityHigh: return 2; case ResourceLoadPriorityUnresolved: - ASSERT_NOT_REACHED(); - return 0; + return 3; } ASSERT_NOT_REACHED(); diff --git a/Source/WebCore/platform/network/cf/ResourceResponse.h b/Source/WebCore/platform/network/cf/ResourceResponse.h index 33b6ddc..0551ede 100644 --- a/Source/WebCore/platform/network/cf/ResourceResponse.h +++ b/Source/WebCore/platform/network/cf/ResourceResponse.h @@ -98,9 +98,9 @@ private: static bool platformCompare(const ResourceResponse& a, const ResourceResponse& b); #if USE(CFNETWORK) - RetainPtr<CFURLResponseRef> m_cfResponse; + mutable RetainPtr<CFURLResponseRef> m_cfResponse; #else - RetainPtr<NSURLResponse> m_nsResponse; + mutable RetainPtr<NSURLResponse> m_nsResponse; #endif bool m_isUpToDate; }; diff --git a/Source/WebCore/platform/network/cf/ResourceResponseCFNet.cpp b/Source/WebCore/platform/network/cf/ResourceResponseCFNet.cpp index 167b079..d4a0b31 100644 --- a/Source/WebCore/platform/network/cf/ResourceResponseCFNet.cpp +++ b/Source/WebCore/platform/network/cf/ResourceResponseCFNet.cpp @@ -43,7 +43,14 @@ using namespace std; namespace WebCore { CFURLResponseRef ResourceResponse::cfURLResponse() const -{ +{ + if (!m_cfResponse && !m_isNull) { + RetainPtr<CFURLRef> url(AdoptCF, m_url.createCFURL()); + RetainPtr<CFStringRef> mimeType(AdoptCF, m_mimeType.createCFString()); + RetainPtr<CFStringRef> textEncodingName(AdoptCF, m_textEncodingName.createCFString()); + m_cfResponse.adoptCF(CFURLResponseCreate(0, url.get(), mimeType.get(), m_expectedContentLength, textEncodingName.get(), kCFURLCacheStorageAllowed)); + } + return m_cfResponse.get(); } diff --git a/Source/WebCore/platform/network/cf/SocketStreamHandle.h b/Source/WebCore/platform/network/cf/SocketStreamHandle.h index 5c1c6ff..4adee70 100644 --- a/Source/WebCore/platform/network/cf/SocketStreamHandle.h +++ b/Source/WebCore/platform/network/cf/SocketStreamHandle.h @@ -44,14 +44,14 @@ class AuthenticationChallenge; class Credential; class SocketStreamHandleClient; -class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase, public AuthenticationClient { +class SocketStreamHandle : public ThreadSafeRefCounted<SocketStreamHandle>, public SocketStreamHandleBase, public AuthenticationClient { public: static PassRefPtr<SocketStreamHandle> create(const KURL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); } virtual ~SocketStreamHandle(); - using RefCounted<SocketStreamHandle>::ref; - using RefCounted<SocketStreamHandle>::deref; + using ThreadSafeRefCounted<SocketStreamHandle>::ref; + using ThreadSafeRefCounted<SocketStreamHandle>::deref; private: virtual int platformSend(const char* data, int length); diff --git a/Source/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp b/Source/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp index d5b1743..ee06c68 100644 --- a/Source/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp +++ b/Source/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp @@ -117,7 +117,7 @@ CFStringRef SocketStreamHandle::copyPACExecutionDescription(void*) struct MainThreadPACCallbackInfo { MainThreadPACCallbackInfo(SocketStreamHandle* handle, CFArrayRef proxyList) : handle(handle), proxyList(proxyList) { } - SocketStreamHandle* handle; + RefPtr<SocketStreamHandle> handle; CFArrayRef proxyList; }; @@ -436,7 +436,7 @@ CFStringRef SocketStreamHandle::copyCFStreamDescription(void* info) struct MainThreadEventCallbackInfo { MainThreadEventCallbackInfo(CFStreamEventType type, SocketStreamHandle* handle) : type(type), handle(handle) { } CFStreamEventType type; - SocketStreamHandle* handle; + RefPtr<SocketStreamHandle> handle; }; void SocketStreamHandle::readStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void* clientCallBackInfo) diff --git a/Source/WebCore/platform/network/mac/CookieStorageMac.mm b/Source/WebCore/platform/network/mac/CookieStorageMac.mm index db64aae..2696188 100644 --- a/Source/WebCore/platform/network/mac/CookieStorageMac.mm +++ b/Source/WebCore/platform/network/mac/CookieStorageMac.mm @@ -92,7 +92,7 @@ void setCookieStoragePrivateBrowsingEnabled(bool enabled) return; if (enabled && ResourceHandle::privateBrowsingStorageSession()) { - privateBrowsingCookieStorage().adoptCF(wkCreatePrivateInMemoryHTTPCookieStorage(ResourceHandle::privateBrowsingStorageSession())); + privateBrowsingCookieStorage().adoptCF(wkCopyHTTPCookieStorage(ResourceHandle::privateBrowsingStorageSession())); // FIXME: When Private Browsing is enabled, the Private Browsing Cookie Storage should be // observed for changes, not the default Cookie Storage. @@ -116,7 +116,10 @@ void startObservingCookieChanges() void stopObservingCookieChanges() { - ASSERT(cookieStorageAdapter); + // cookieStorageAdapter can be nil here, if the WebProcess crashed and was restarted between + // when startObservingCookieChanges was called, and stopObservingCookieChanges is currently being called. + if (!cookieStorageAdapter) + return; [cookieStorageAdapter stopListeningForCookieChangeNotifications]; } diff --git a/Source/WebCore/platform/network/mac/FormDataStreamMac.mm b/Source/WebCore/platform/network/mac/FormDataStreamMac.mm index eb6f601..f094842 100644 --- a/Source/WebCore/platform/network/mac/FormDataStreamMac.mm +++ b/Source/WebCore/platform/network/mac/FormDataStreamMac.mm @@ -192,8 +192,8 @@ static bool advanceCurrentStream(FormStreamFields* form) } #if ENABLE(BLOB) if (nextInput.m_fileStart > 0) { - CFNumberRef position = CFNumberCreate(0, kCFNumberLongLongType, &nextInput.m_fileStart); - CFReadStreamSetProperty(form->currentStream, kCFStreamPropertyFileCurrentOffset, position); + RetainPtr<CFNumberRef> position(AdoptCF, CFNumberCreate(0, kCFNumberLongLongType, &nextInput.m_fileStart)); + CFReadStreamSetProperty(form->currentStream, kCFStreamPropertyFileCurrentOffset, position.get()); } form->currentStreamRangeLength = nextInput.m_fileLength; #endif diff --git a/Source/WebCore/platform/network/mac/ResourceErrorMac.mm b/Source/WebCore/platform/network/mac/ResourceErrorMac.mm index 275ca41..0bada1f 100644 --- a/Source/WebCore/platform/network/mac/ResourceErrorMac.mm +++ b/Source/WebCore/platform/network/mac/ResourceErrorMac.mm @@ -28,6 +28,7 @@ #import "BlockExceptions.h" #import "KURL.h" +#import <CoreFoundation/CFError.h> #import <Foundation/Foundation.h> @interface NSError (WebExtras) @@ -36,6 +37,20 @@ namespace WebCore { +ResourceError::ResourceError(NSError *nsError) + : m_dataIsUpToDate(false) + , m_platformError(nsError) +{ + m_isNull = !nsError; +} + +ResourceError::ResourceError(CFErrorRef cfError) + : m_dataIsUpToDate(false) + , m_platformError((NSError *)cfError) +{ + m_isNull = !cfError; +} + void ResourceError::platformLazyInit() { if (m_dataIsUpToDate) @@ -59,10 +74,10 @@ void ResourceError::platformLazyInit() bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b) { - return (NSError*)a == (NSError*)b; + return a.nsError() == b.nsError(); } -ResourceError::operator NSError*() const +NSError *ResourceError::nsError() const { if (m_isNull) { ASSERT(!m_platformError); @@ -87,4 +102,19 @@ ResourceError::operator NSError*() const return m_platformError.get(); } +ResourceError::operator NSError *() const +{ + return nsError(); +} + +CFErrorRef ResourceError::cfError() const +{ + return (CFErrorRef)nsError(); +} + +ResourceError::operator CFErrorRef() const +{ + return cfError(); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/network/mac/ResourceHandleMac.mm b/Source/WebCore/platform/network/mac/ResourceHandleMac.mm index 96d561d..b2a89f0 100644 --- a/Source/WebCore/platform/network/mac/ResourceHandleMac.mm +++ b/Source/WebCore/platform/network/mac/ResourceHandleMac.mm @@ -886,7 +886,7 @@ String ResourceHandle::privateBrowsingStorageSessionIdentifierDefaultBase() // Avoid MIME type sniffing if the response comes back as 304 Not Modified. int statusCode = [r respondsToSelector:@selector(statusCode)] ? [(id)r statusCode] : 0; if (statusCode != 304) - [r adjustMIMETypeIfNecessary]; + adjustMIMETypeIfNecessary([r _CFURLResponse]); if ([m_handle->firstRequest().nsURLRequest() _propertyForKey:@"ForceHTMLMIMEType"]) [r _setMIMEType:@"text/html"]; @@ -910,9 +910,32 @@ String ResourceHandle::privateBrowsingStorageSessionIdentifierDefaultBase() m_handle->client()->didReceiveResponse(m_handle, r); } +#if HAVE(CFNETWORK_DATA_ARRAY_CALLBACK) +- (void)connection:(NSURLConnection *)connection didReceiveDataArray:(NSArray *)dataArray +{ + UNUSED_PARAM(connection); + LOG(Network, "Handle %p delegate connection:%p didReceiveDataArray:%p arraySize:%d", m_handle, connection, dataArray, [dataArray count]); + + if (!dataArray) + return; + + if (!m_handle || !m_handle->client()) + return; + + if (m_handle->client()->supportsDataArray()) + m_handle->client()->didReceiveDataArray(m_handle, reinterpret_cast<CFArrayRef>(dataArray)); + else { + for (NSData *data in dataArray) + m_handle->client()->didReceiveData(m_handle, static_cast<const char*>([data bytes]), [data length], static_cast<int>([data length])); + } + return; +} +#endif + - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived { UNUSED_PARAM(connection); + UNUSED_PARAM(lengthReceived); LOG(Network, "Handle %p delegate connection:%p didReceiveData:%p lengthReceived:%lld", m_handle, connection, data, lengthReceived); @@ -922,7 +945,10 @@ String ResourceHandle::privateBrowsingStorageSessionIdentifierDefaultBase() // However, with today's computers and networking speeds, this won't happen in practice. // Could be an issue with a giant local file. CallbackGuard guard; - m_handle->client()->didReceiveData(m_handle, (const char*)[data bytes], [data length], static_cast<int>(lengthReceived)); + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793 + // -1 means we do not provide any data about transfer size to inspector so it would use + // Content-Length headers or content size to show transfer size. + m_handle->client()->didReceiveData(m_handle, (const char*)[data bytes], [data length], -1); } - (void)connection:(NSURLConnection *)connection willStopBufferingData:(NSData *)data diff --git a/Source/WebCore/platform/network/mac/WebCoreURLResponse.h b/Source/WebCore/platform/network/mac/WebCoreURLResponse.h index 8d43a21..d766b96 100644 --- a/Source/WebCore/platform/network/mac/WebCoreURLResponse.h +++ b/Source/WebCore/platform/network/mac/WebCoreURLResponse.h @@ -26,10 +26,15 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -@interface NSURLResponse (WebCoreURLResponse) --(void)adjustMIMETypeIfNecessary; -@end +typedef struct _CFURLResponse* CFURLResponseRef; +#ifdef __OBJC__ @interface NSURLResponse (Details) +- (CFURLResponseRef)_CFURLResponse; - (void)_setMIMEType:(NSString *)type; @end +#endif + +namespace WebCore { +void adjustMIMETypeIfNecessary(CFURLResponseRef); +} diff --git a/Source/WebCore/platform/network/mac/WebCoreURLResponse.mm b/Source/WebCore/platform/network/mac/WebCoreURLResponse.mm index e287e5f..0960492 100644 --- a/Source/WebCore/platform/network/mac/WebCoreURLResponse.mm +++ b/Source/WebCore/platform/network/mac/WebCoreURLResponse.mm @@ -30,308 +30,429 @@ #import "WebCoreURLResponse.h" #import "MIMETypeRegistry.h" -#import <objc/objc-class.h> +#import "WebCoreSystemInterface.h" #import <wtf/Assertions.h> #import <wtf/RetainPtr.h> -#ifndef BUILDING_ON_TIGER +namespace WebCore { + // <rdar://problem/5321972> Plain text document from HTTP server detected as application/octet-stream // When we sniff a resource as application/octet-stream but the http response headers had "text/plain", // we have a hard decision to make about which of the two generic MIME types to go with. // When the URL's extension is a known binary type, we'll go with application/octet-stream. // Otherwise, we'll trust the server. -static NSSet *createBinaryExtensionsSet() +static CFSetRef createBinaryExtensionsSet() { - return [[NSSet alloc] initWithObjects: - @"3g2", - @"3gp", - @"ai", - @"aif", - @"aifc", - @"aiff", - @"au", - @"avi", - @"bcpio", - @"bin", - @"bmp", - @"boz", - @"bpk", - @"bz", - @"bz2", - @"chm", - @"class", - @"com", - @"cpio", - @"dcr", - @"dir", - @"dist", - @"distz", - @"dll", - @"dmg", - @"dms", - @"doc", - @"dot", - @"dump", - @"dv", - @"dvi", - @"dxr", - @"elc", - @"eot", - @"eps", - @"exe", - @"fgd", - @"gif", - @"gtar", - @"h261", - @"h263", - @"h264", - @"ico", - @"ims", - @"indd", - @"iso", - @"jp2", - @"jpe", - @"jpeg", - @"jpg", - @"jpgm", - @"jpgv", - @"jpm", - @"kar", - @"kmz", - @"lha", - @"lrm", - @"lzh", - @"m1v", - @"m2a", - @"m2v", - @"m3a", - @"m3u", - @"m4a", - @"m4p", - @"m4v", - @"mdb", - @"mid", - @"midi", - @"mj2", - @"mjp2", - @"mov", - @"movie", - @"mp2", - @"mp2a", - @"mp3", - @"mp4", - @"mp4a", - @"mp4s", - @"mp4v", - @"mpe", - @"mpeg", - @"mpg", - @"mpg4", - @"mpga", - @"mpp", - @"mpt", - @"msi", - @"ogg", - @"otf", - @"pct", - @"pdf", - @"pfa", - @"pfb", - @"pic", - @"pict", - @"pkg", - @"png", - @"pot", - @"pps", - @"ppt", - @"ps", - @"psd", - @"qt", - @"qti", - @"qtif", - @"qwd", - @"qwt", - @"qxb", - @"qxd", - @"qxl", - @"qxp", - @"qxt", - @"ra", - @"ram", - @"rm", - @"rmi", - @"rmp", - @"scpt", - @"sit", - @"sitx", - @"snd", - @"so", - @"swf", - @"tar", - @"tif", - @"tiff", - @"ttf", - @"wav", - @"wcm", - @"wdb", - @"wks", - @"wm", - @"wma", - @"wmd", - @"wmf", - @"wmv", - @"wmx", - @"wmz", - @"wpd", - @"wpl", - @"wps", - @"wvx", - @"xla", - @"xlc", - @"xlm", - @"xls", - @"xlt", - @"xlw", - @"xps", - @"zip", - nil - ]; + CFStringRef extensions[] = { + CFSTR("3g2"), + CFSTR("3gp"), + CFSTR("ai"), + CFSTR("aif"), + CFSTR("aifc"), + CFSTR("aiff"), + CFSTR("au"), + CFSTR("avi"), + CFSTR("bcpio"), + CFSTR("bin"), + CFSTR("bmp"), + CFSTR("boz"), + CFSTR("bpk"), + CFSTR("bz"), + CFSTR("bz2"), + CFSTR("chm"), + CFSTR("class"), + CFSTR("com"), + CFSTR("cpio"), + CFSTR("dcr"), + CFSTR("dir"), + CFSTR("dist"), + CFSTR("distz"), + CFSTR("dll"), + CFSTR("dmg"), + CFSTR("dms"), + CFSTR("doc"), + CFSTR("dot"), + CFSTR("dump"), + CFSTR("dv"), + CFSTR("dvi"), + CFSTR("dxr"), + CFSTR("elc"), + CFSTR("eot"), + CFSTR("eps"), + CFSTR("exe"), + CFSTR("fgd"), + CFSTR("gif"), + CFSTR("gtar"), + CFSTR("h261"), + CFSTR("h263"), + CFSTR("h264"), + CFSTR("ico"), + CFSTR("ims"), + CFSTR("indd"), + CFSTR("iso"), + CFSTR("jp2"), + CFSTR("jpe"), + CFSTR("jpeg"), + CFSTR("jpg"), + CFSTR("jpgm"), + CFSTR("jpgv"), + CFSTR("jpm"), + CFSTR("kar"), + CFSTR("kmz"), + CFSTR("lha"), + CFSTR("lrm"), + CFSTR("lzh"), + CFSTR("m1v"), + CFSTR("m2a"), + CFSTR("m2v"), + CFSTR("m3a"), + CFSTR("m3u"), + CFSTR("m4a"), + CFSTR("m4p"), + CFSTR("m4v"), + CFSTR("mdb"), + CFSTR("mid"), + CFSTR("midi"), + CFSTR("mj2"), + CFSTR("mjp2"), + CFSTR("mov"), + CFSTR("movie"), + CFSTR("mp2"), + CFSTR("mp2a"), + CFSTR("mp3"), + CFSTR("mp4"), + CFSTR("mp4a"), + CFSTR("mp4s"), + CFSTR("mp4v"), + CFSTR("mpe"), + CFSTR("mpeg"), + CFSTR("mpg"), + CFSTR("mpg4"), + CFSTR("mpga"), + CFSTR("mpp"), + CFSTR("mpt"), + CFSTR("msi"), + CFSTR("ogg"), + CFSTR("otf"), + CFSTR("pct"), + CFSTR("pdf"), + CFSTR("pfa"), + CFSTR("pfb"), + CFSTR("pic"), + CFSTR("pict"), + CFSTR("pkg"), + CFSTR("png"), + CFSTR("pot"), + CFSTR("pps"), + CFSTR("ppt"), + CFSTR("ps"), + CFSTR("psd"), + CFSTR("qt"), + CFSTR("qti"), + CFSTR("qtif"), + CFSTR("qwd"), + CFSTR("qwt"), + CFSTR("qxb"), + CFSTR("qxd"), + CFSTR("qxl"), + CFSTR("qxp"), + CFSTR("qxt"), + CFSTR("ra"), + CFSTR("ram"), + CFSTR("rm"), + CFSTR("rmi"), + CFSTR("rmp"), + CFSTR("scpt"), + CFSTR("sit"), + CFSTR("sitx"), + CFSTR("snd"), + CFSTR("so"), + CFSTR("swf"), + CFSTR("tar"), + CFSTR("tif"), + CFSTR("tiff"), + CFSTR("ttf"), + CFSTR("wav"), + CFSTR("wcm"), + CFSTR("wdb"), + CFSTR("wks"), + CFSTR("wm"), + CFSTR("wma"), + CFSTR("wmd"), + CFSTR("wmf"), + CFSTR("wmv"), + CFSTR("wmx"), + CFSTR("wmz"), + CFSTR("wpd"), + CFSTR("wpl"), + CFSTR("wps"), + CFSTR("wvx"), + CFSTR("xla"), + CFSTR("xlc"), + CFSTR("xlm"), + CFSTR("xls"), + CFSTR("xlt"), + CFSTR("xlw"), + CFSTR("xps"), + CFSTR("zip") + }; + return CFSetCreate(kCFAllocatorDefault, (const void **)&extensions, sizeof(extensions)/sizeof(CFStringRef), &kCFTypeSetCallBacks); } -#endif // <rdar://problem/7007389> CoreTypes UTI map is missing 100+ file extensions that GateKeeper knew about // When we disabled content sniffing for file URLs we caused problems with these 100+ extensions that CoreTypes // doesn't know about. // If CoreTypes is ever brought up to speed we can remove this table and associated code. -static NSDictionary *createExtensionToMIMETypeMap() +static CFDictionaryRef createExtensionToMIMETypeMap() { - return [[NSDictionary alloc] initWithObjectsAndKeys: - @"application/postscript", @"ai", - @"text/plain", @"asc", - @"application/x-bcpio", @"bcpio", - @"image/bmp", @"bmp", - @"application/x-netcdf", @"cdf", - @"application/octet-stream", @"class", - @"application/x-gzip", @"cpgz", - @"application/x-cpio", @"cpio", - @"application/mac-compactpro", @"cpt", - @"application/x-csh", @"csh", - @"text/css", @"css", - @"application/x-director", @"dcr", - @"application/x-director", @"dir", - @"application/x-diskcopy", @"dmg", - @"application/octet-stream", @"dms", - @"application/x-dvi", @"dvi", - @"application/x-director", @"dxr", - @"application/postscript", @"eps", - @"text/x-setext", @"etx", - @"application/andrew-inset", @"ez", - @"application/vnd.fdf", @"fdf", - @"application/octet-stream", @"fla", - @"application/x-filemaker", @"fp", - @"application/x-filemaker", @"fp2", - @"application/x-filemaker", @"fp3", - @"application/x-filemaker", @"fp4", - @"application/x-filemaker", @"fp5", - @"application/x-filemaker", @"fp6", - @"application/x-hdf", @"hdf", - @"x-conference/x-cooltalk", @"ice", - @"image/x-icon", @"ico", - @"text/calendar", @"ics", - @"image/ief", @"ief", - @"model/iges", @"iges", - @"model/iges", @"igs", - @"application/octet-stream", @"iso", - @"text/html", @"jhtml", - @"application/x-latex", @"latex", - @"application/octet-stream", @"lha", - @"application/octet-stream", @"lzh", - @"audio/x-mpegurl", @"m3u", - @"audio/x-m4p", @"m4p", - @"image/x-macpaint", @"mac", - @"application/x-troff-man", @"man", - @"application/x-troff-me", @"me", - @"model/mesh", @"mesh", - @"application/vnd.mif", @"mif", - @"video/x-sgi-movie", @"movie", - @"audio/mpeg", @"mp2", - @"audio/mpeg", @"mpga", - @"application/x-troff-ms", @"ms", - @"model/mesh", @"msh", - @"video/vnd.mpegurl", @"mxu", - @"application/x-netcdf", @"nc", - @"application/oda", @"oda", - @"image/x-portable-bitmap", @"pbm", - @"image/x-pcx", @"pcx", - @"chemical/x-pdb", @"pdb", - @"image/x-portable-graymap", @"pgm", - @"application/x-chess-pgn", @"pgn", - @"audio/scpls", @"pls", - @"image/x-portable-anymap", @"pnm", - @"image/x-macpaint", @"pnt", - @"image/x-macpaint", @"pntg", - @"image/x-portable-pixmap", @"ppm", - @"image/x-cmu-raster", @"ras", - @"image/x-rgb", @"rgb", - @"application/x-troff", @"roff", - @"audio/x-pn-realaudio-plugin", @"rpm", - @"text/richtext", @"rtx", - @"text/sgml", @"sgm", - @"text/sgml", @"sgml", - @"application/x-sh", @"sh", - @"application/x-shar", @"shar", - @"model/mesh", @"silo", - @"application/x-koan", @"skd", - @"application/x-koan", @"skm", - @"application/x-koan", @"skp", - @"application/x-koan", @"skt", - @"application/x-diskcopy", @"smi", - @"application/octet-stream", @"so", - @"application/x-futuresplash", @"spl", - @"application/x-wais-source", @"src", - @"application/x-sv4cpio", @"sv4cpio", - @"application/x-sv4crc", @"sv4crc", - @"application/x-shockwave-flash", @"swf", - @"application/x-troff", @"t", - @"image/x-targa", @"targa", - @"application/x-tcl", @"tcl", - @"application/x-tex", @"tex", - @"application/x-texinfo", @"texi", - @"application/x-texinfo", @"texinfo", - @"application/x-gzip", @"tgz", - @"application/x-bittorrent", @"torrent", - @"application/x-troff", @"tr", - @"text/tab-separated-values", @"tsv", - @"application/x-ustar", @"ustar", - @"application/x-cdlink", @"vcd", - @"model/vrml", @"vrml", - @"image/vnd.wap.wbmp", @"wbmp", - @"application/vnd.wap.wbxml", @"wbxml", - @"application/x-webarchive", @"webarchive", - @"application/x-ms-wmd", @"wmd", - @"text/vnd.wap.wml", @"wml", - @"application/vnd.wap.wmlc", @"wmlc", - @"text/vnd.wap.wmlscript", @"wmls", - @"application/vnd.wap.wmlscriptc", @"wmlsc", - @"model/vrml", @"wrl", - @"application/vnd.adobe.xdp+xml", @"xdp", - @"application/vnd.adobe.xfd+xml", @"xfd", - @"application/vnd.adobe.xfdf", @"xfdf", - @"image/x-xpixmap", @"xpm", - @"text/xml", @"xsl", - @"image/x-xwindowdump", @"xwd", - @"chemical/x-xyz", @"xyz", - @"application/x-compress", @"z", - nil - ]; + CFStringRef keys[] = { + CFSTR("ai"), + CFSTR("asc"), + CFSTR("bcpio"), + CFSTR("bmp"), + CFSTR("cdf"), + CFSTR("class"), + CFSTR("cpgz"), + CFSTR("cpio"), + CFSTR("cpt"), + CFSTR("csh"), + CFSTR("css"), + CFSTR("dcr"), + CFSTR("dir"), + CFSTR("dmg"), + CFSTR("dms"), + CFSTR("dvi"), + CFSTR("dxr"), + CFSTR("eps"), + CFSTR("etx"), + CFSTR("ez"), + CFSTR("fdf"), + CFSTR("fla"), + CFSTR("fp"), + CFSTR("fp2"), + CFSTR("fp3"), + CFSTR("fp4"), + CFSTR("fp5"), + CFSTR("fp6"), + CFSTR("hdf"), + CFSTR("ice"), + CFSTR("ico"), + CFSTR("ics"), + CFSTR("ief"), + CFSTR("iges"), + CFSTR("igs"), + CFSTR("iso"), + CFSTR("jhtml"), + CFSTR("latex"), + CFSTR("lha"), + CFSTR("lzh"), + CFSTR("m3u"), + CFSTR("m4p"), + CFSTR("mac"), + CFSTR("man"), + CFSTR("me"), + CFSTR("mesh"), + CFSTR("mif"), + CFSTR("movie"), + CFSTR("mp2"), + CFSTR("mpga"), + CFSTR("ms"), + CFSTR("msh"), + CFSTR("mxu"), + CFSTR("nc"), + CFSTR("oda"), + CFSTR("pbm"), + CFSTR("pcx"), + CFSTR("pdb"), + CFSTR("pgm"), + CFSTR("pgn"), + CFSTR("pls"), + CFSTR("pnm"), + CFSTR("pnt"), + CFSTR("pntg"), + CFSTR("ppm"), + CFSTR("ras"), + CFSTR("rgb"), + CFSTR("roff"), + CFSTR("rpm"), + CFSTR("rtx"), + CFSTR("sgm"), + CFSTR("sgml"), + CFSTR("sh"), + CFSTR("shar"), + CFSTR("silo"), + CFSTR("skd"), + CFSTR("skm"), + CFSTR("skp"), + CFSTR("skt"), + CFSTR("smi"), + CFSTR("so"), + CFSTR("spl"), + CFSTR("src"), + CFSTR("sv4cpio"), + CFSTR("sv4crc"), + CFSTR("swf"), + CFSTR("t"), + CFSTR("targa"), + CFSTR("tcl"), + CFSTR("tex"), + CFSTR("texi"), + CFSTR("texinfo"), + CFSTR("tgz"), + CFSTR("torrent"), + CFSTR("tr"), + CFSTR("tsv"), + CFSTR("ustar"), + CFSTR("vcd"), + CFSTR("vrml"), + CFSTR("wbmp"), + CFSTR("wbxml"), + CFSTR("webarchive"), + CFSTR("wmd"), + CFSTR("wml"), + CFSTR("wmlc"), + CFSTR("wmls"), + CFSTR("wmlsc"), + CFSTR("wrl"), + CFSTR("xdp"), + CFSTR("xfd"), + CFSTR("xfdf"), + CFSTR("xpm"), + CFSTR("xsl"), + CFSTR("xwd"), + CFSTR("xyz"), + CFSTR("z") + }; + + CFStringRef values[] = { + CFSTR("application/postscript"), + CFSTR("text/plain"), + CFSTR("application/x-bcpio"), + CFSTR("image/bmp"), + CFSTR("application/x-netcdf"), + CFSTR("application/octet-stream"), + CFSTR("application/x-gzip"), + CFSTR("application/x-cpio"), + CFSTR("application/mac-compactpro"), + CFSTR("application/x-csh"), + CFSTR("text/css"), + CFSTR("application/x-director"), + CFSTR("application/x-director"), + CFSTR("application/x-diskcopy"), + CFSTR("application/octet-stream"), + CFSTR("application/x-dvi"), + CFSTR("application/x-director"), + CFSTR("application/postscript"), + CFSTR("text/x-setext"), + CFSTR("application/andrew-inset"), + CFSTR("application/vnd.fdf"), + CFSTR("application/octet-stream"), + CFSTR("application/x-filemaker"), + CFSTR("application/x-filemaker"), + CFSTR("application/x-filemaker"), + CFSTR("application/x-filemaker"), + CFSTR("application/x-filemaker"), + CFSTR("application/x-filemaker"), + CFSTR("application/x-hdf"), + CFSTR("x-conference/x-cooltalk"), + CFSTR("image/x-icon"), + CFSTR("text/calendar"), + CFSTR("image/ief"), + CFSTR("model/iges"), + CFSTR("model/iges"), + CFSTR("application/octet-stream"), + CFSTR("text/html"), + CFSTR("application/x-latex"), + CFSTR("application/octet-stream"), + CFSTR("application/octet-stream"), + CFSTR("audio/x-mpegurl"), + CFSTR("audio/x-m4p"), + CFSTR("image/x-macpaint"), + CFSTR("application/x-troff-man"), + CFSTR("application/x-troff-me"), + CFSTR("model/mesh"), + CFSTR("application/vnd.mif"), + CFSTR("video/x-sgi-movie"), + CFSTR("audio/mpeg"), + CFSTR("audio/mpeg"), + CFSTR("application/x-troff-ms"), + CFSTR("model/mesh"), + CFSTR("video/vnd.mpegurl"), + CFSTR("application/x-netcdf"), + CFSTR("application/oda"), + CFSTR("image/x-portable-bitmap"), + CFSTR("image/x-pcx"), + CFSTR("chemical/x-pdb"), + CFSTR("image/x-portable-graymap"), + CFSTR("application/x-chess-pgn"), + CFSTR("audio/scpls"), + CFSTR("image/x-portable-anymap"), + CFSTR("image/x-macpaint"), + CFSTR("image/x-macpaint"), + CFSTR("image/x-portable-pixmap"), + CFSTR("image/x-cmu-raster"), + CFSTR("image/x-rgb"), + CFSTR("application/x-troff"), + CFSTR("audio/x-pn-realaudio-plugin"), + CFSTR("text/richtext"), + CFSTR("text/sgml"), + CFSTR("text/sgml"), + CFSTR("application/x-sh"), + CFSTR("application/x-shar"), + CFSTR("model/mesh"), + CFSTR("application/x-koan"), + CFSTR("application/x-koan"), + CFSTR("application/x-koan"), + CFSTR("application/x-koan"), + CFSTR("application/x-diskcopy"), + CFSTR("application/octet-stream"), + CFSTR("application/x-futuresplash"), + CFSTR("application/x-wais-source"), + CFSTR("application/x-sv4cpio"), + CFSTR("application/x-sv4crc"), + CFSTR("application/x-shockwave-flash"), + CFSTR("application/x-troff"), + CFSTR("image/x-targa"), + CFSTR("application/x-tcl"), + CFSTR("application/x-tex"), + CFSTR("application/x-texinfo"), + CFSTR("application/x-texinfo"), + CFSTR("application/x-gzip"), + CFSTR("application/x-bittorrent"), + CFSTR("application/x-troff"), + CFSTR("text/tab-separated-values"), + CFSTR("application/x-ustar"), + CFSTR("application/x-cdlink"), + CFSTR("model/vrml"), + CFSTR("image/vnd.wap.wbmp"), + CFSTR("application/vnd.wap.wbxml"), + CFSTR("application/x-webarchive"), + CFSTR("application/x-ms-wmd"), + CFSTR("text/vnd.wap.wml"), + CFSTR("application/vnd.wap.wmlc"), + CFSTR("text/vnd.wap.wmlscript"), + CFSTR("application/vnd.wap.wmlscriptc"), + CFSTR("model/vrml"), + CFSTR("application/vnd.adobe.xdp+xml"), + CFSTR("application/vnd.adobe.xfd+xml"), + CFSTR("application/vnd.adobe.xfdf"), + CFSTR("image/x-xpixmap"), + CFSTR("text/xml"), + CFSTR("image/x-xwindowdump"), + CFSTR("chemical/x-xyz"), + CFSTR("application/x-compress") + }; + + ASSERT(sizeof(keys) == sizeof(values)); + return CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, (const void**)&values, sizeof(keys)/sizeof(CFStringRef), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } -static RetainPtr<NSString> mimeTypeFromUTITree(CFStringRef uti) +static RetainPtr<CFStringRef> mimeTypeFromUTITree(CFStringRef uti) { // Check if this UTI has a MIME type. RetainPtr<CFStringRef> mimeType(AdoptCF, UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)); if (mimeType) - return (NSString *)mimeType.get(); + return mimeType.get(); // If not, walk the ancestory of this UTI via its "ConformsTo" tags and return the first MIME type we find. RetainPtr<CFDictionaryRef> decl(AdoptCF, UTTypeCopyDeclaration(uti)); @@ -353,7 +474,7 @@ static RetainPtr<NSString> mimeTypeFromUTITree(CFStringRef uti) if (CFGetTypeID(object) != CFStringGetTypeID()) continue; - if (RetainPtr<NSString> mimeType = mimeTypeFromUTITree((CFStringRef)object)) + if (RetainPtr<CFStringRef> mimeType = mimeTypeFromUTITree((CFStringRef)object)) return mimeType; } } @@ -361,33 +482,29 @@ static RetainPtr<NSString> mimeTypeFromUTITree(CFStringRef uti) return nil; } -@implementation NSURLResponse (WebCoreURLResponse) - --(void)adjustMIMETypeIfNecessary +void adjustMIMETypeIfNecessary(CFURLResponseRef cfResponse) { - RetainPtr<NSString> result = [self MIMEType]; - RetainPtr<NSString> originalResult = result; - -#ifdef BUILDING_ON_TIGER - // When content sniffing is disabled, Tiger's CFNetwork automatically returns application/octet-stream for certain - // extensions even when scouring the UTI maps would end up with a better result, so we'll give a chance for that to happen. - if ([[self URL] isFileURL] && [result.get() caseInsensitiveCompare:@"application/octet-stream"] == NSOrderedSame) - result = nil; -#endif + RetainPtr<CFStringRef> result = wkGetCFURLResponseMIMEType(cfResponse); + RetainPtr<CFStringRef> originalResult = result; if (!result) { - NSURL *url = [self URL]; - if ([url isFileURL]) { - if (NSString *extension = [[url path] pathExtension]) { + CFURLRef url = wkGetCFURLResponseURL(cfResponse); + NSURL *nsURL = (NSURL *)url; + if ([nsURL isFileURL]) { + RetainPtr<CFStringRef> extension(AdoptCF, CFURLCopyPathExtension(url)); + if (extension) { // <rdar://problem/7007389> CoreTypes UTI map is missing 100+ file extensions that GateKeeper knew about // When this radar is resolved, we can remove this file:// url specific code. - static NSDictionary *extensionMap = createExtensionToMIMETypeMap(); - result = [extensionMap objectForKey:[extension lowercaseString]]; + static CFDictionaryRef extensionMap = createExtensionToMIMETypeMap(); + CFMutableStringRef mutableExtension = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, extension.get()); + CFStringLowercase(mutableExtension, NULL); + extension.adoptCF(mutableExtension); + result = (CFStringRef) CFDictionaryGetValue(extensionMap, extension.get()); if (!result) { // If the Gatekeeper-based map doesn't have a MIME type, we'll try to figure out what it should be by // looking up the file extension in the UTI maps. - RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)extension, 0)); + RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension.get(), 0)); result = mimeTypeFromUTITree(uti.get()); } } @@ -395,29 +512,33 @@ static RetainPtr<NSString> mimeTypeFromUTITree(CFStringRef uti) } if (!result) { - static NSString *defaultMIMETypeString = [(NSString *)WebCore::defaultMIMEType() retain]; + static CFStringRef defaultMIMETypeString = WebCore::defaultMIMEType().createCFString(); result = defaultMIMETypeString; } -#ifndef BUILDING_ON_TIGER // <rdar://problem/5321972> Plain text document from HTTP server detected as application/octet-stream // Make the best guess when deciding between "generic binary" and "generic text" using a table of known binary MIME types. - if ([result.get() isEqualToString:@"application/octet-stream"] && [self respondsToSelector:@selector(allHeaderFields)] && [[[self performSelector:@selector(allHeaderFields)] objectForKey:@"Content-Type"] hasPrefix:@"text/plain"]) { - static NSSet *binaryExtensions = createBinaryExtensionsSet(); - if (![binaryExtensions containsObject:[[[self suggestedFilename] pathExtension] lowercaseString]]) - result = @"text/plain"; + if (CFStringCompare(result.get(), CFSTR("application/octet-stream"), 0) == kCFCompareEqualTo) { + CFHTTPMessageRef message = wkGetCFURLResponseHTTPResponse(cfResponse); + if (message) { + RetainPtr<CFStringRef> contentType(AdoptCF, CFHTTPMessageCopyHeaderFieldValue(message, CFSTR("Content-Type"))); + if (contentType && CFStringHasPrefix(contentType.get(), CFSTR("text/plain"))) { + static CFSetRef binaryExtensions = createBinaryExtensionsSet(); + RetainPtr<NSString> suggestedFilename(AdoptNS, (NSString *)wkCopyCFURLResponseSuggestedFilename(cfResponse)); + if (!CFSetContainsValue(binaryExtensions, (CFStringRef) [[suggestedFilename.get() pathExtension] lowercaseString])) + result = CFSTR("text/plain"); + } + } } -#endif - #ifdef BUILDING_ON_LEOPARD // Workaround for <rdar://problem/5539824> - if ([result.get() isEqualToString:@"text/xml"]) - result = @"application/xml"; + if (CFStringCompare(result.get(), CFSTR("text/xml"), 0) == kCFCompareEqualTo) + result = CFSTR("application/xml"); #endif if (result != originalResult) - [self _setMIMEType:result.get()]; + wkSetCFURLResponseMIMEType(cfResponse, result.get()); } -@end +} diff --git a/Source/WebCore/platform/network/qt/DnsPrefetchHelper.h b/Source/WebCore/platform/network/qt/DnsPrefetchHelper.h index 892a3fb..4fcd19c 100644 --- a/Source/WebCore/platform/network/qt/DnsPrefetchHelper.h +++ b/Source/WebCore/platform/network/qt/DnsPrefetchHelper.h @@ -32,7 +32,7 @@ namespace WebCore { class DnsPrefetchHelper : public QObject { Q_OBJECT public: - DnsPrefetchHelper() : QObject(), currentLookups(0) {}; + DnsPrefetchHelper() : QObject(), currentLookups(0) { } public slots: void lookup(QString hostname) @@ -42,26 +42,8 @@ namespace WebCore { if (currentLookups >= 10) return; // do not launch more than 10 lookups at the same time -#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 3) currentLookups++; QHostInfo::lookupHost(hostname, this, SLOT(lookedUp(QHostInfo))); -#else - // This code is only needed for Qt versions that do not have - // the small Qt DNS cache yet. - - QTime* entryTime = lookupCache.object(hostname); - if (entryTime && entryTime->elapsed() > 300*1000) { - // delete knowledge about lookup if it is already 300 seconds old - lookupCache.remove(hostname); - } else if (!entryTime) { - // not in cache yet, can look it up - QTime *tmpTime = new QTime(); - *tmpTime = QTime::currentTime(); - lookupCache.insert(hostname, tmpTime); - currentLookups++; - QHostInfo::lookupHost(hostname, this, SLOT(lookedUp(QHostInfo))); - } -#endif } void lookedUp(const QHostInfo&) @@ -74,9 +56,6 @@ namespace WebCore { } protected: -#if QT_VERSION < QT_VERSION_CHECK(4, 6, 3) - QCache<QString, QTime> lookupCache; // 100 entries -#endif int currentLookups; }; diff --git a/Source/WebCore/platform/network/qt/NetworkStateNotifierPrivate.h b/Source/WebCore/platform/network/qt/NetworkStateNotifierPrivate.h index 766dc90..4b8252c 100644 --- a/Source/WebCore/platform/network/qt/NetworkStateNotifierPrivate.h +++ b/Source/WebCore/platform/network/qt/NetworkStateNotifierPrivate.h @@ -22,15 +22,9 @@ #include <QObject> -#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) -namespace QtMobility { -class QNetworkConfigurationManager; -} -#else QT_BEGIN_NAMESPACE class QNetworkConfigurationManager; QT_END_NAMESPACE -#endif namespace WebCore { @@ -46,11 +40,7 @@ public slots: void networkAccessPermissionChanged(bool); public: -#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) - QtMobility::QNetworkConfigurationManager* m_configurationManager; -#else QNetworkConfigurationManager* m_configurationManager; -#endif bool m_online; bool m_networkAccessAllowed; NetworkStateNotifier* m_notifier; diff --git a/Source/WebCore/platform/network/qt/NetworkStateNotifierQt.cpp b/Source/WebCore/platform/network/qt/NetworkStateNotifierQt.cpp index f3e7023..ced52eb 100644 --- a/Source/WebCore/platform/network/qt/NetworkStateNotifierQt.cpp +++ b/Source/WebCore/platform/network/qt/NetworkStateNotifierQt.cpp @@ -25,10 +25,6 @@ #include "NetworkStateNotifierPrivate.h" #include "qnetworkconfigmanager.h" -#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) -using namespace QtMobility; -#endif - namespace WebCore { NetworkStateNotifierPrivate::NetworkStateNotifierPrivate(NetworkStateNotifier* notifier) diff --git a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index 61fe96c..6e63145 100644 --- a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -41,21 +41,11 @@ #include <QDebug> #include <QCoreApplication> -// What type of connection should be used for the signals of the -// QNetworkReply? This depends on if Qt has a bugfix for this or not. -// It is fixed in Qt 4.6.3. See https://bugs.webkit.org/show_bug.cgi?id=32113 -// and https://bugs.webkit.org/show_bug.cgi?id=36755 -#if QT_VERSION > QT_VERSION_CHECK(4, 6, 2) -#define SIGNAL_CONN Qt::DirectConnection -#else -#define SIGNAL_CONN Qt::QueuedConnection -#endif - // In Qt 4.8, the attribute for sending a request synchronously will be made public, // for now, use this hackish solution for setting the internal attribute. const QNetworkRequest::Attribute gSynchronousNetworkRequestAttribute = static_cast<QNetworkRequest::Attribute>(QNetworkRequest::HttpPipeliningWasUsedAttribute + 7); -static const int gMaxRecursionLimit = 10; +static const int gMaxRedirections = 10; namespace WebCore { @@ -159,6 +149,86 @@ bool FormDataIODevice::isSequential() const return true; } +QNetworkReplyWrapper::QNetworkReplyWrapper(QNetworkReply* reply, QObject* parent) + : QObject(parent) + , m_reply(reply) +{ + Q_ASSERT(m_reply); + + connect(m_reply, SIGNAL(metaDataChanged()), this, SLOT(receiveMetaData())); + connect(m_reply, SIGNAL(readyRead()), this, SLOT(receiveMetaData())); + connect(m_reply, SIGNAL(finished()), this, SLOT(receiveMetaData())); +} + +QNetworkReplyWrapper::~QNetworkReplyWrapper() +{ + if (m_reply) + m_reply->deleteLater(); +} + +QNetworkReply* QNetworkReplyWrapper::release() +{ + if (!m_reply) + return 0; + + resetConnections(); + QNetworkReply* reply = m_reply; + m_reply = 0; + reply->setParent(0); + return reply; +} + +void QNetworkReplyWrapper::resetConnections() +{ + if (m_reply) + m_reply->disconnect(this); + QCoreApplication::removePostedEvents(this, QEvent::MetaCall); +} + +void QNetworkReplyWrapper::receiveMetaData() +{ + // This slot is only used to receive the first signal from the QNetworkReply object. + resetConnections(); + + m_redirectionTargetUrl = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + if (m_redirectionTargetUrl.isValid()) { + emit metaDataChanged(); + emit finished(); + return; + } + + WTF::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString(); + m_encoding = extractCharsetFromMediaType(contentType); + m_advertisedMimeType = extractMIMETypeFromMediaType(contentType); + + bool hasData = m_reply->bytesAvailable(); + bool isFinished = m_reply->isFinished(); + + if (!isFinished) { + // If not finished, connect to the slots that will be used from this point on. + connect(m_reply, SIGNAL(readyRead()), this, SIGNAL(readyRead())); + connect(m_reply, SIGNAL(finished()), this, SLOT(didReceiveFinished())); + } + + emit metaDataChanged(); + + if (hasData) + emit readyRead(); + + if (isFinished) { + emit finished(); + return; + } + +} + +void QNetworkReplyWrapper::didReceiveFinished() +{ + // Disconnecting will make sure that nothing will happen after emitting the finished signal. + resetConnections(); + emit finished(); +} + String QNetworkReplyHandler::httpMethod() const { switch (m_method) { @@ -172,30 +242,24 @@ String QNetworkReplyHandler::httpMethod() const return "PUT"; case QNetworkAccessManager::DeleteOperation: return "DELETE"; -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) case QNetworkAccessManager::CustomOperation: return m_resourceHandle->firstRequest().httpMethod(); -#endif default: ASSERT_NOT_REACHED(); return "GET"; } } -QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode loadMode) +QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadType loadType, bool deferred) : QObject(0) - , m_reply(0) + , m_replyWrapper(0) , m_resourceHandle(handle) - , m_redirected(false) - , m_responseSent(false) - , m_responseContainsData(false) - , m_loadMode(loadMode) - , m_shouldStart(true) - , m_shouldFinish(false) - , m_shouldSendResponse(false) - , m_shouldForwardData(false) - , m_redirectionTries(gMaxRecursionLimit) + , m_loadType(loadType) + , m_deferred(deferred) + , m_redirectionTries(gMaxRedirections) { + resetState(); + const ResourceRequest &r = m_resourceHandle->firstRequest(); if (r.httpMethod() == "GET") @@ -208,13 +272,8 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load m_method = QNetworkAccessManager::PutOperation; else if (r.httpMethod() == "DELETE") m_method = QNetworkAccessManager::DeleteOperation; -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) else m_method = QNetworkAccessManager::CustomOperation; -#else - else - m_method = QNetworkAccessManager::UnknownOperation; -#endif QObject* originatingObject = 0; if (m_resourceHandle->getInternal()->m_context) @@ -222,40 +281,58 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load m_request = r.toNetworkRequest(originatingObject); - if (m_loadMode == LoadSynchronously) - m_request.setAttribute(gSynchronousNetworkRequestAttribute, true); - - if (m_loadMode == LoadNormal || m_loadMode == LoadSynchronously) + if (!m_deferred) start(); +} + +void QNetworkReplyHandler::resetState() +{ + m_redirected = false; + m_responseSent = false; + m_responseContainsData = false; + m_hasStarted = false; + m_callFinishOnResume = false; + m_callSendResponseIfNeededOnResume = false; + m_callForwardDataOnResume = false; + + if (m_replyWrapper) { + m_replyWrapper->deleteLater(); + m_replyWrapper = 0; + } +} - if (m_loadMode == LoadSynchronously) - m_loadMode = LoadNormal; +void QNetworkReplyHandler::setLoadingDeferred(bool deferred) +{ + m_deferred = deferred; + + if (!deferred) + resumeDeferredLoad(); } -void QNetworkReplyHandler::setLoadMode(LoadMode mode) +void QNetworkReplyHandler::resumeDeferredLoad() { - // https://bugs.webkit.org/show_bug.cgi?id=26556 - // We cannot call sendQueuedItems() from here, because the signal that - // caused us to get into deferred mode, might not be processed yet. - switch (mode) { - case LoadNormal: - m_loadMode = LoadResuming; - emit processQueuedItems(); - break; - case LoadDeferred: - m_loadMode = LoadDeferred; - break; - case LoadResuming: - Q_ASSERT(0); // should never happen - break; - }; + if (!m_hasStarted) { + ASSERT(!m_callSendResponseIfNeededOnResume); + ASSERT(!m_callForwardDataOnResume); + ASSERT(!m_callFinishOnResume); + start(); + return; + } + + if (m_callSendResponseIfNeededOnResume) + sendResponseIfNeeded(); + + if (m_callForwardDataOnResume) + forwardData(); + + if (m_callFinishOnResume) + finish(); } void QNetworkReplyHandler::abort() { m_resourceHandle = 0; - if (m_reply) { - QNetworkReply* reply = release(); + if (QNetworkReply* reply = release()) { reply->abort(); reply->deleteLater(); } @@ -264,20 +341,16 @@ void QNetworkReplyHandler::abort() QNetworkReply* QNetworkReplyHandler::release() { - QNetworkReply* reply = m_reply; - if (m_reply) { - disconnect(m_reply, 0, this, 0); - // We have queued connections to the QNetworkReply. Make sure any - // posted meta call events that were the result of a signal emission - // don't reach the slots in our instance. - QCoreApplication::removePostedEvents(this, QEvent::MetaCall); - m_reply->setParent(0); - m_reply = 0; - } + if (!m_replyWrapper) + return 0; + + QNetworkReply* reply = m_replyWrapper->release(); + m_replyWrapper->deleteLater(); + m_replyWrapper = 0; return reply; } -static bool ignoreHttpError(QNetworkReply* reply, bool receivedData) +static bool shouldIgnoreHttpError(QNetworkReply* reply, bool receivedData) { int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); @@ -292,66 +365,73 @@ static bool ignoreHttpError(QNetworkReply* reply, bool receivedData) void QNetworkReplyHandler::finish() { - m_shouldFinish = (m_loadMode != LoadNormal); - if (m_shouldFinish) + ASSERT(m_hasStarted); + + m_callFinishOnResume = m_deferred; + if (m_deferred) return; - if (!m_reply) + if (!m_replyWrapper || !m_replyWrapper->reply()) return; + sendResponseIfNeeded(); - if (!m_resourceHandle) + if (wasAborted()) return; + ResourceHandleClient* client = m_resourceHandle->client(); if (!client) { - m_reply->deleteLater(); - m_reply = 0; + m_replyWrapper->deleteLater(); + m_replyWrapper = 0; return; } - if (!m_redirected) { - if (!m_reply->error() || ignoreHttpError(m_reply, m_responseContainsData)) - client->didFinishLoading(m_resourceHandle, 0); - else { - QUrl url = m_reply->url(); - int httpStatusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - - if (httpStatusCode) { - ResourceError error("HTTP", httpStatusCode, url.toString(), m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()); - client->didFail(m_resourceHandle, error); - } else { - ResourceError error("QtNetwork", m_reply->error(), url.toString(), m_reply->errorString()); - client->didFail(m_resourceHandle, error); - } - } - if (m_reply) { - m_reply->deleteLater(); - m_reply = 0; - } - } else { - if (m_reply) { - m_reply->deleteLater(); - m_reply = 0; - } + if (m_redirected) { resetState(); start(); + return; + } + + if (!m_replyWrapper->reply()->error() || shouldIgnoreHttpError(m_replyWrapper->reply(), m_responseContainsData)) + client->didFinishLoading(m_resourceHandle, 0); + else { + QUrl url = m_replyWrapper->reply()->url(); + int httpStatusCode = m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (httpStatusCode) { + ResourceError error("HTTP", httpStatusCode, url.toString(), m_replyWrapper->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()); + client->didFail(m_resourceHandle, error); + } else { + ResourceError error("QtNetwork", m_replyWrapper->reply()->error(), url.toString(), m_replyWrapper->reply()->errorString()); + client->didFail(m_resourceHandle, error); + } + } + + if (m_replyWrapper) { + m_replyWrapper->deleteLater(); + m_replyWrapper = 0; } } void QNetworkReplyHandler::sendResponseIfNeeded() { - m_shouldSendResponse = (m_loadMode != LoadNormal); - if (m_shouldSendResponse) + ASSERT(m_hasStarted); + + m_callSendResponseIfNeededOnResume = m_deferred; + if (m_deferred) return; - if (!m_reply) + if (!m_replyWrapper || !m_replyWrapper->reply()) return; - if (m_reply->error() && !ignoreHttpError(m_reply, m_responseContainsData)) + if (m_replyWrapper->reply()->error() && !shouldIgnoreHttpError(m_replyWrapper->reply(), m_responseContainsData)) return; - if (m_responseSent || !m_resourceHandle) + if (wasAborted()) + return; + + if (m_responseSent) return; m_responseSent = true; @@ -359,18 +439,18 @@ void QNetworkReplyHandler::sendResponseIfNeeded() if (!client) return; - WTF::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString(); + WTF::String contentType = m_replyWrapper->reply()->header(QNetworkRequest::ContentTypeHeader).toString(); WTF::String encoding = extractCharsetFromMediaType(contentType); WTF::String mimeType = extractMIMETypeFromMediaType(contentType); if (mimeType.isEmpty()) { // let's try to guess from the extension - mimeType = MIMETypeRegistry::getMIMETypeForPath(m_reply->url().path()); + mimeType = MIMETypeRegistry::getMIMETypeForPath(m_replyWrapper->reply()->url().path()); } - KURL url(m_reply->url()); + KURL url(m_replyWrapper->reply()->url()); ResourceResponse response(url, mimeType.lower(), - m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), + m_replyWrapper->reply()->header(QNetworkRequest::ContentLengthHeader).toLongLong(), encoding, String()); if (url.isLocalFile()) { @@ -379,10 +459,10 @@ void QNetworkReplyHandler::sendResponseIfNeeded() } // The status code is equal to 0 for protocols not in the HTTP family. - int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + int statusCode = m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (url.protocolInHTTPFamily()) { - String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->rawHeader("Content-Disposition"))); + String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromLatin1(m_replyWrapper->reply()->rawHeader("Content-Disposition"))); if (!suggestedFilename.isEmpty()) response.setSuggestedFilename(suggestedFilename); @@ -390,70 +470,79 @@ void QNetworkReplyHandler::sendResponseIfNeeded() response.setSuggestedFilename(url.lastPathComponent()); response.setHTTPStatusCode(statusCode); - response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData()); + response.setHTTPStatusText(m_replyWrapper->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 + foreach (const QNetworkReply::RawHeaderPair& pair, m_replyWrapper->reply()->rawHeaderPairs()) + response.setHTTPHeaderField(QString::fromLatin1(pair.first), QString::fromLatin1(pair.second)); } - QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + QUrl redirection = m_replyWrapper->reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); if (redirection.isValid()) { - QUrl newUrl = m_reply->url().resolved(redirection); + redirect(response, redirection); + return; + } - m_redirectionTries--; - if (m_redirectionTries == 0) { // 10 or more redirections to the same url is considered infinite recursion - ResourceError error(newUrl.host(), 400 /*bad request*/, - newUrl.toString(), - QCoreApplication::translate("QWebPage", "Redirection limit reached")); - client->didFail(m_resourceHandle, error); - return; - } - m_redirected = true; + client->didReceiveResponse(m_resourceHandle, response); +} +void QNetworkReplyHandler::redirect(ResourceResponse& response, const QUrl& redirection) +{ + QUrl newUrl = m_replyWrapper->reply()->url().resolved(redirection); - // Status Code 301 (Moved Permanently), 302 (Moved Temporarily), 303 (See Other): - // - If original request is POST convert to GET and redirect automatically - // Status Code 307 (Temporary Redirect) and all other redirect status codes: - // - Use the HTTP method from the previous request - if ((statusCode >= 301 && statusCode <= 303) && m_resourceHandle->firstRequest().httpMethod() == "POST") - m_method = QNetworkAccessManager::GetOperation; + ResourceHandleClient* client = m_resourceHandle->client(); + ASSERT(client); + + int statusCode = m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - ResourceRequest newRequest = m_resourceHandle->firstRequest(); - newRequest.setHTTPMethod(httpMethod()); - newRequest.setURL(newUrl); + m_redirectionTries--; + if (!m_redirectionTries) { + ResourceError error(newUrl.host(), 400 /*bad request*/, + newUrl.toString(), + QCoreApplication::translate("QWebPage", "Redirection limit reached")); + client->didFail(m_resourceHandle, error); + return; + } + m_redirected = true; - // 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(); + // Status Code 301 (Moved Permanently), 302 (Moved Temporarily), 303 (See Other): + // - If original request is POST convert to GET and redirect automatically + // Status Code 307 (Temporary Redirect) and all other redirect status codes: + // - Use the HTTP method from the previous request + if ((statusCode >= 301 && statusCode <= 303) && m_resourceHandle->firstRequest().httpMethod() == "POST") + m_method = QNetworkAccessManager::GetOperation; - client->willSendRequest(m_resourceHandle, newRequest, response); - if (!m_resourceHandle) // network error did cancel the request - return; + ResourceRequest newRequest = m_resourceHandle->firstRequest(); + newRequest.setHTTPMethod(httpMethod()); + newRequest.setURL(newUrl); - QObject* originatingObject = 0; - if (m_resourceHandle->getInternal()->m_context) - originatingObject = m_resourceHandle->getInternal()->m_context->originatingObject(); + // 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(); - m_request = newRequest.toNetworkRequest(originatingObject); + client->willSendRequest(m_resourceHandle, newRequest, response); + if (wasAborted()) // Network error cancelled the request. return; - } - client->didReceiveResponse(m_resourceHandle, response); + QObject* originatingObject = 0; + if (m_resourceHandle->getInternal()->m_context) + originatingObject = m_resourceHandle->getInternal()->m_context->originatingObject(); + + m_request = newRequest.toNetworkRequest(originatingObject); } void QNetworkReplyHandler::forwardData() { - m_shouldForwardData = (m_loadMode != LoadNormal); - if (m_shouldForwardData) + ASSERT(m_hasStarted); + + m_callForwardDataOnResume = m_deferred; + if (m_deferred) return; - if (m_reply->bytesAvailable()) + if (!m_replyWrapper || !m_replyWrapper->reply()) + return; + + if (m_replyWrapper->reply()->bytesAvailable()) m_responseContainsData = true; sendResponseIfNeeded(); @@ -462,22 +551,25 @@ void QNetworkReplyHandler::forwardData() if (m_redirected) return; - if (!m_resourceHandle) + if (wasAborted()) return; - QByteArray data = m_reply->read(m_reply->bytesAvailable()); + QByteArray data = m_replyWrapper->reply()->read(m_replyWrapper->reply()->bytesAvailable()); ResourceHandleClient* client = m_resourceHandle->client(); if (!client) return; + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793 + // -1 means we do not provide any data about transfer size to inspector so it would use + // Content-Length headers or content size to show transfer size. if (!data.isEmpty()) - client->didReceiveData(m_resourceHandle, data.constData(), data.length(), data.length() /*FixMe*/); + client->didReceiveData(m_resourceHandle, data.constData(), data.length(), -1); } void QNetworkReplyHandler::uploadProgress(qint64 bytesSent, qint64 bytesTotal) { - if (!m_resourceHandle) + if (wasAborted()) return; ResourceHandleClient* client = m_resourceHandle->client(); @@ -487,9 +579,10 @@ void QNetworkReplyHandler::uploadProgress(qint64 bytesSent, qint64 bytesTotal) client->didSendData(m_resourceHandle, bytesSent, bytesTotal); } -void QNetworkReplyHandler::start() +QNetworkReply* QNetworkReplyHandler::sendNetworkRequest() { - m_shouldStart = false; + if (m_loadType == SynchronousLoad) + m_request.setAttribute(gSynchronousNetworkRequestAttribute, true); ResourceHandleInternal* d = m_resourceHandle->getInternal(); @@ -498,7 +591,7 @@ void QNetworkReplyHandler::start() manager = d->m_context->networkAccessManager(); if (!manager) - return; + return 0; const QUrl url = m_request.url(); const QString scheme = url.scheme(); @@ -511,108 +604,61 @@ void QNetworkReplyHandler::start() switch (m_method) { case QNetworkAccessManager::GetOperation: - m_reply = manager->get(m_request); - break; + return manager->get(m_request); case QNetworkAccessManager::PostOperation: { - FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody()); + FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody()); // We may be uploading files so prevent QNR from buffering data m_request.setHeader(QNetworkRequest::ContentLengthHeader, postDevice->getFormDataSize()); m_request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(true)); - m_reply = manager->post(m_request, postDevice); - postDevice->setParent(m_reply); - break; + QNetworkReply* result = manager->post(m_request, postDevice); + postDevice->setParent(result); + return result; } case QNetworkAccessManager::HeadOperation: - m_reply = manager->head(m_request); - break; + return manager->head(m_request); case QNetworkAccessManager::PutOperation: { - FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody()); + FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody()); // We may be uploading files so prevent QNR from buffering data m_request.setHeader(QNetworkRequest::ContentLengthHeader, putDevice->getFormDataSize()); m_request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(true)); - m_reply = manager->put(m_request, putDevice); - putDevice->setParent(m_reply); - break; + QNetworkReply* result = manager->put(m_request, putDevice); + putDevice->setParent(result); + return result; } case QNetworkAccessManager::DeleteOperation: { - m_reply = manager->deleteResource(m_request); - break; + return manager->deleteResource(m_request); } -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) case QNetworkAccessManager::CustomOperation: - m_reply = manager->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data()); - break; -#endif - case QNetworkAccessManager::UnknownOperation: { - m_reply = 0; - ResourceHandleClient* client = m_resourceHandle->client(); - if (client) { - ResourceError error(url.host(), 400 /*bad request*/, - url.toString(), - QCoreApplication::translate("QWebPage", "Bad HTTP request")); - client->didFail(m_resourceHandle, error); - } - return; - } - } - - m_reply->setParent(this); - - if (m_loadMode == LoadSynchronously && m_reply->isFinished()) { - // If supported, a synchronous request will be finished at this point, no need to hook up the signals. - return; - } - - connect(m_reply, SIGNAL(finished()), - this, SLOT(finish()), SIGNAL_CONN); - - // For http(s) we know that the headers are complete upon metaDataChanged() emission, so we - // can send the response as early as possible - if (scheme == QLatin1String("http") || scheme == QLatin1String("https")) - connect(m_reply, SIGNAL(metaDataChanged()), - this, SLOT(sendResponseIfNeeded()), SIGNAL_CONN); - - connect(m_reply, SIGNAL(readyRead()), - this, SLOT(forwardData()), SIGNAL_CONN); - - if (m_resourceHandle->firstRequest().reportUploadProgress()) { - connect(m_reply, SIGNAL(uploadProgress(qint64, qint64)), - this, SLOT(uploadProgress(qint64, qint64)), SIGNAL_CONN); + return manager->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data()); + case QNetworkAccessManager::UnknownOperation: + ASSERT_NOT_REACHED(); + return 0; } - - // Make this a direct function call once we require 4.6.1+. - connect(this, SIGNAL(processQueuedItems()), - this, SLOT(sendQueuedItems()), SIGNAL_CONN); + return 0; } -void QNetworkReplyHandler::resetState() +void QNetworkReplyHandler::start() { - m_redirected = false; - m_responseSent = false; - m_responseContainsData = false; - m_shouldStart = true; - m_shouldFinish = false; - m_shouldSendResponse = false; - m_shouldForwardData = false; -} + ASSERT(!m_hasStarted); + m_hasStarted = true; -void QNetworkReplyHandler::sendQueuedItems() -{ - if (m_loadMode != LoadResuming) + QNetworkReply* reply = sendNetworkRequest(); + if (!reply) return; - m_loadMode = LoadNormal; - if (m_shouldStart) - start(); + m_replyWrapper = new QNetworkReplyWrapper(reply, this); - if (m_shouldSendResponse) - sendResponseIfNeeded(); + if (m_loadType == SynchronousLoad && m_replyWrapper->reply()->isFinished()) { + // If supported, a synchronous request will be finished at this point, no need to hook up the signals. + return; + } - if (m_shouldForwardData) - forwardData(); + connect(m_replyWrapper, SIGNAL(finished()), this, SLOT(finish())); + connect(m_replyWrapper, SIGNAL(metaDataChanged()), this, SLOT(sendResponseIfNeeded())); + connect(m_replyWrapper, SIGNAL(readyRead()), this, SLOT(forwardData())); - if (m_shouldFinish) - finish(); + if (m_resourceHandle->firstRequest().reportUploadProgress()) + connect(m_replyWrapper->reply(), SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64))); } } diff --git a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.h b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.h index 8c9bd08..61694d6 100644 --- a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.h +++ b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.h @@ -34,56 +34,90 @@ QT_END_NAMESPACE namespace WebCore { class ResourceHandle; +class ResourceResponse; + +class QNetworkReplyWrapper : public QObject { + Q_OBJECT +public: + QNetworkReplyWrapper(QNetworkReply*, QObject* parent = 0); + ~QNetworkReplyWrapper(); + + QNetworkReply* reply() const { return m_reply; } + QNetworkReply* release(); + + QUrl redirectionTargetUrl() const { return m_redirectionTargetUrl; } + QString encoding() const { return m_encoding; } + QString advertisedMimeType() const { return m_advertisedMimeType; } + +Q_SIGNALS: + void finished(); + void metaDataChanged(); + void readyRead(); + void uploadProgress(qint64 bytesSent, qint64 bytesTotal); + +private Q_SLOTS: + void receiveMetaData(); + void didReceiveFinished(); + +private: + void resetConnections(); + + QNetworkReply* m_reply; + QUrl m_redirectionTargetUrl; + + QString m_encoding; + QString m_advertisedMimeType; +}; class QNetworkReplyHandler : public QObject { Q_OBJECT public: - enum LoadMode { - LoadNormal, - LoadDeferred, - LoadResuming, - LoadSynchronously + enum LoadType { + AsynchronousLoad, + SynchronousLoad }; - QNetworkReplyHandler(ResourceHandle *handle, LoadMode); - void setLoadMode(LoadMode); + QNetworkReplyHandler(ResourceHandle*, LoadType, bool deferred = false); + void setLoadingDeferred(bool); - QNetworkReply* reply() const { return m_reply; } + QNetworkReply* reply() const { return m_replyWrapper ? m_replyWrapper->reply() : 0; } void abort(); QNetworkReply* release(); -signals: - void processQueuedItems(); - public slots: void finish(); void sendResponseIfNeeded(); void forwardData(); - void sendQueuedItems(); void uploadProgress(qint64 bytesSent, qint64 bytesTotal); private: void start(); void resetState(); String httpMethod() const; + void resumeDeferredLoad(); + void redirect(ResourceResponse&, const QUrl&); + bool wasAborted() const { return !m_resourceHandle; } + QNetworkReply* sendNetworkRequest(); - QNetworkReply* m_reply; + QNetworkReplyWrapper* m_replyWrapper; ResourceHandle* m_resourceHandle; bool m_redirected; bool m_responseSent; bool m_responseContainsData; - LoadMode m_loadMode; + LoadType m_loadType; QNetworkAccessManager::Operation m_method; QNetworkRequest m_request; + bool m_deferred; + // defer state holding - bool m_shouldStart; - bool m_shouldFinish; - bool m_shouldSendResponse; - bool m_shouldForwardData; + bool m_hasStarted; + bool m_callFinishOnResume; + bool m_callSendResponseIfNeededOnResume; + bool m_callForwardDataOnResume; int m_redirectionTries; }; diff --git a/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp b/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp index cd17660..a6da432 100644 --- a/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp +++ b/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp @@ -42,9 +42,6 @@ #include "ResourceHandleInternal.h" #include "SharedBuffer.h" -// FIXME: WebCore including these headers from WebKit is a massive layering violation. -#include "qwebframe_p.h" - #include <QAbstractNetworkCache> #include <QCoreApplication> #include <QUrl> @@ -140,7 +137,7 @@ bool ResourceHandle::start(NetworkingContext* context) getInternal()->m_context = context; ResourceHandleInternal *d = getInternal(); - d->m_job = new QNetworkReplyHandler(this, QNetworkReplyHandler::LoadMode(d->m_defersLoading)); + d->m_job = new QNetworkReplyHandler(this, QNetworkReplyHandler::AsynchronousLoad, d->m_defersLoading); return true; } @@ -207,7 +204,7 @@ void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const d->m_firstRequest.setURL(urlWithCredentials); } d->m_context = context; - d->m_job = new QNetworkReplyHandler(handle.get(), QNetworkReplyHandler::LoadSynchronously); + d->m_job = new QNetworkReplyHandler(handle.get(), QNetworkReplyHandler::SynchronousLoad); QNetworkReply* reply = d->m_job->reply(); // When using synchronous calls, we are finished when reaching this point. @@ -225,8 +222,9 @@ void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const void ResourceHandle::platformSetDefersLoading(bool defers) { - if (d->m_job) - d->m_job->setLoadMode(QNetworkReplyHandler::LoadMode(defers)); + if (!d->m_job) + return; + d->m_job->setLoadingDeferred(defers); } } // namespace WebCore diff --git a/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp b/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp index 7e162ed..498c90a 100644 --- a/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp +++ b/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp @@ -83,13 +83,11 @@ QNetworkRequest ResourceRequest::toNetworkRequest(QObject* originatingFrame) con break; } -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) if (!allowCookies()) { request.setAttribute(QNetworkRequest::CookieLoadControlAttribute, QNetworkRequest::Manual); request.setAttribute(QNetworkRequest::CookieSaveControlAttribute, QNetworkRequest::Manual); request.setAttribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Manual); } -#endif return request; } diff --git a/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp index d410fa3..e5da0e3 100644 --- a/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -364,7 +364,10 @@ static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data) ASSERT(!d->m_response.isNull()); - client->didReceiveData(handle.get(), chunk->data, chunk->length, chunk->length); + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793 + // -1 means we do not provide any data about transfer size to inspector so it would use + // Content-Length headers or content size to show transfer size. + client->didReceiveData(handle.get(), chunk->data, chunk->length, -1); } static SoupSession* createSoupSession() diff --git a/Source/WebCore/platform/network/win/ResourceHandleWin.cpp b/Source/WebCore/platform/network/win/ResourceHandleWin.cpp index f50540c..dc5adc8 100644 --- a/Source/WebCore/platform/network/win/ResourceHandleWin.cpp +++ b/Source/WebCore/platform/network/win/ResourceHandleWin.cpp @@ -242,8 +242,11 @@ bool ResourceHandle::onRequestComplete() resourceHandleClient->didReceiveResponse(this, response); } + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793 + // -1 means we do not provide any data about transfer size to inspector so it would use + // Content-Length headers or content size to show transfer size. if (ResourceHandleClient* resourceHandleClient = client()) - resourceHandleClient->didReceiveData(this, buffer, buffers.dwBufferLength, 0); + resourceHandleClient->didReceiveData(this, buffer, buffers.dwBufferLength, -1); buffers.dwBufferLength = bufferSize; } @@ -385,8 +388,11 @@ void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>*) const int bufferSize = 8192; char buffer[bufferSize]; result = ReadFile(fileHandle, &buffer, bufferSize, &bytesRead, 0); + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793 + // -1 means we do not provide any data about transfer size to inspector so it would use + // Content-Length headers or content size to show transfer size. if (result && bytesRead) - client()->didReceiveData(this, buffer, bytesRead, 0); + client()->didReceiveData(this, buffer, bytesRead, -1); // Check for end of file. } while (result && bytesRead); |