diff options
Diffstat (limited to 'WebCore/platform/network')
28 files changed, 618 insertions, 348 deletions
diff --git a/WebCore/platform/network/FormData.cpp b/WebCore/platform/network/FormData.cpp index 3cac168..af3b7f0 100644 --- a/WebCore/platform/network/FormData.cpp +++ b/WebCore/platform/network/FormData.cpp @@ -29,7 +29,8 @@ namespace WebCore { inline FormData::FormData() - : m_hasGeneratedFiles(false) + : m_identifier(0) + , m_hasGeneratedFiles(false) , m_alwaysStream(false) { } @@ -37,6 +38,7 @@ inline FormData::FormData() inline FormData::FormData(const FormData& data) : RefCounted<FormData>() , m_elements(data.m_elements) + , m_identifier(data.m_identifier) , m_hasGeneratedFiles(false) , m_alwaysStream(false) { @@ -98,7 +100,7 @@ PassRefPtr<FormData> FormData::deepCopy() const formData->m_alwaysStream = m_alwaysStream; size_t n = m_elements.size(); - formData->m_elements.reserveCapacity(n); + formData->m_elements.reserveInitialCapacity(n); for (size_t i = 0; i < n; ++i) { const FormDataElement& e = m_elements[i]; switch (e.m_type) { diff --git a/WebCore/platform/network/FormData.h b/WebCore/platform/network/FormData.h index 5998b1b..7278f2e 100644 --- a/WebCore/platform/network/FormData.h +++ b/WebCore/platform/network/FormData.h @@ -86,11 +86,17 @@ public: bool alwaysStream() const { return m_alwaysStream; } void setAlwaysStream(bool alwaysStream) { m_alwaysStream = alwaysStream; } + // Identifies a particular form submission instance. A value of 0 is used + // to indicate an unspecified identifier. + void setIdentifier(int64_t identifier) { m_identifier = identifier; } + int64_t identifier() const { return m_identifier; } + private: FormData(); FormData(const FormData&); - + Vector<FormDataElement> m_elements; + int64_t m_identifier; bool m_hasGeneratedFiles; bool m_alwaysStream; }; diff --git a/WebCore/platform/network/HTTPHeaderMap.cpp b/WebCore/platform/network/HTTPHeaderMap.cpp index aa9c5fa..ff470a0 100644 --- a/WebCore/platform/network/HTTPHeaderMap.cpp +++ b/WebCore/platform/network/HTTPHeaderMap.cpp @@ -41,7 +41,7 @@ namespace WebCore { auto_ptr<CrossThreadHTTPHeaderMapData> HTTPHeaderMap::copyData() const { auto_ptr<CrossThreadHTTPHeaderMapData> data(new CrossThreadHTTPHeaderMapData()); - data->reserveCapacity(size()); + data->reserveInitialCapacity(size()); HTTPHeaderMap::const_iterator end_it = end(); for (HTTPHeaderMap::const_iterator it = begin(); it != end_it; ++it) { diff --git a/WebCore/platform/network/HTTPParsers.cpp b/WebCore/platform/network/HTTPParsers.cpp index 0858fc9..f36e9fb 100644 --- a/WebCore/platform/network/HTTPParsers.cpp +++ b/WebCore/platform/network/HTTPParsers.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -131,18 +132,18 @@ String filenameFromHTTPContentDisposition(const String& value) String extractMIMETypeFromMediaType(const String& mediaType) { - String mimeType; + Vector<UChar, 64> mimeType; unsigned length = mediaType.length(); + mimeType.reserveCapacity(length); for (unsigned offset = 0; offset < length; offset++) { UChar c = mediaType[offset]; if (c == ';') break; else if (isSpaceOrNewline(c)) // FIXME: This seems wrong, " " is an invalid MIME type character according to RFC 2045. bug 8644 continue; - // FIXME: This is a very slow way to build a string, given WebCore::String's implementation. - mimeType += String(&c, 1); + mimeType.append(c); } - return mimeType; + return String(mimeType.data(), mimeType.size()); } String extractCharsetFromMediaType(const String& mediaType) diff --git a/WebCore/platform/network/ResourceErrorBase.cpp b/WebCore/platform/network/ResourceErrorBase.cpp index 1ea35b0..370650f 100644 --- a/WebCore/platform/network/ResourceErrorBase.cpp +++ b/WebCore/platform/network/ResourceErrorBase.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,6 +29,20 @@ namespace WebCore { +ResourceError ResourceErrorBase::copy() const +{ + lazyInit(); + + ResourceError errorCopy; + errorCopy.m_domain = m_domain.copy(); + errorCopy.m_errorCode = m_errorCode; + errorCopy.m_failingURL = m_failingURL.copy(); + errorCopy.m_localizedDescription = m_localizedDescription.copy(); + errorCopy.m_isNull = m_isNull; + errorCopy.m_isCancellation = m_isCancellation; + return errorCopy; +} + void ResourceErrorBase::lazyInit() const { const_cast<ResourceError*>(static_cast<const ResourceError*>(this))->platformLazyInit(); @@ -59,4 +74,4 @@ bool ResourceErrorBase::compare(const ResourceError& a, const ResourceError& b) return platformCompare(a, b); } -} +} // namespace WebCore diff --git a/WebCore/platform/network/ResourceErrorBase.h b/WebCore/platform/network/ResourceErrorBase.h index 4631324..237db9e 100644 --- a/WebCore/platform/network/ResourceErrorBase.h +++ b/WebCore/platform/network/ResourceErrorBase.h @@ -34,6 +34,9 @@ class ResourceError; class ResourceErrorBase { public: + // Makes a deep copy. Useful for when you need to use a ResourceError on another thread. + ResourceError copy() const; + bool isNull() const { return m_isNull; } const String& domain() const { lazyInit(); return m_domain; } @@ -44,7 +47,7 @@ public: void setIsCancellation(bool isCancellation) { m_isCancellation = isCancellation; } bool isCancellation() const { return m_isCancellation; } - static bool compare(const ResourceError& a, const ResourceError& b); + static bool compare(const ResourceError&, const ResourceError&); protected: ResourceErrorBase() @@ -85,4 +88,4 @@ inline bool operator!=(const ResourceError& a, const ResourceError& b) { return } // namespace WebCore -#endif // ResourceErrorBase_h_ +#endif // ResourceErrorBase_h diff --git a/WebCore/platform/network/ResourceHandle.h b/WebCore/platform/network/ResourceHandle.h index c981483..e3038ca 100644 --- a/WebCore/platform/network/ResourceHandle.h +++ b/WebCore/platform/network/ResourceHandle.h @@ -30,6 +30,10 @@ #include "HTTPHeaderMap.h" #include <wtf/OwnPtr.h> +#if USE(SOUP) +typedef struct _SoupSession SoupSession; +#endif + #if PLATFORM(CF) typedef const struct __CFData * CFDataRef; #endif @@ -79,7 +83,7 @@ class KURL; class ResourceError; class ResourceHandleClient; class ResourceHandleInternal; -class ResourceRequest; +struct ResourceRequest; class ResourceResponse; class SchedulePair; class SharedBuffer; @@ -159,6 +163,10 @@ public: ResourceHandleInternal* getInternal() { return d.get(); } #endif +#if USE(SOUP) + static SoupSession* defaultSession(); +#endif + // Used to work around the fact that you don't get any more NSURLConnection callbacks until you return from the one you're in. static bool loadsBlocked(); @@ -179,7 +187,7 @@ private: #if USE(SOUP) bool startData(String urlString); bool startHttp(String urlString); - bool startGio(String urlString); + bool startGio(KURL url); #endif void scheduleFailure(FailureType); diff --git a/WebCore/platform/network/ResourceHandleClient.h b/WebCore/platform/network/ResourceHandleClient.h index 3668d88..54c27d2 100644 --- a/WebCore/platform/network/ResourceHandleClient.h +++ b/WebCore/platform/network/ResourceHandleClient.h @@ -32,6 +32,7 @@ #if USE(CFNETWORK) #include <ConditionalMacros.h> +#include <CFNetwork/CFURLCachePriv.h> #include <CFNetwork/CFURLResponsePriv.h> #endif @@ -49,7 +50,7 @@ namespace WebCore { class KURL; class ResourceHandle; class ResourceError; - class ResourceRequest; + struct ResourceRequest; class ResourceResponse; enum CacheStoragePolicy { @@ -86,6 +87,9 @@ namespace WebCore { virtual NSCachedURLResponse* willCacheResponse(ResourceHandle*, NSCachedURLResponse* response) { return response; } virtual void willStopBufferingData(ResourceHandle*, const char*, int) { } #endif +#if USE(CFNETWORK) + virtual bool shouldCacheResponse(ResourceHandle*, CFCachedURLResponseRef response) { return true; } +#endif }; } diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h index cc90cc8..c592a1a 100644 --- a/WebCore/platform/network/ResourceHandleInternal.h +++ b/WebCore/platform/network/ResourceHandleInternal.h @@ -47,6 +47,7 @@ #if USE(SOUP) #include <libsoup/soup.h> +class Frame; #endif #if PLATFORM(QT) @@ -116,13 +117,15 @@ namespace WebCore { #if USE(SOUP) , m_msg(0) , m_cancelled(false) + , m_reportedHeaders(false) , m_gfile(0) - , m_input_stream(0) + , m_inputStream(0) , m_cancellable(0) , m_buffer(0) - , m_bufsize(0) + , m_bufferSize(0) , m_total(0) , m_idleHandler(0) + , m_frame(0) #endif #if PLATFORM(QT) , m_job(0) @@ -190,12 +193,14 @@ namespace WebCore { SoupMessage* m_msg; ResourceResponse m_response; bool m_cancelled; + bool m_reportedHeaders; GFile* m_gfile; - GInputStream* m_input_stream; + GInputStream* m_inputStream; GCancellable* m_cancellable; char* m_buffer; - gsize m_bufsize, m_total; + gsize m_bufferSize, m_total; guint m_idleHandler; + Frame* m_frame; #endif #if PLATFORM(QT) #if QT_VERSION < 0x040400 diff --git a/WebCore/platform/network/ResourceRequestBase.cpp b/WebCore/platform/network/ResourceRequestBase.cpp index 15469a0..fd27718 100644 --- a/WebCore/platform/network/ResourceRequestBase.cpp +++ b/WebCore/platform/network/ResourceRequestBase.cpp @@ -76,7 +76,7 @@ auto_ptr<CrossThreadResourceRequestData> ResourceRequestBase::copyData() const data->m_httpMethod = httpMethod().copy(); data->m_httpHeaders.adopt(httpHeaderFields().copyData()); - data->m_responseContentDispositionEncodingFallbackArray.reserveCapacity(m_responseContentDispositionEncodingFallbackArray.size()); + data->m_responseContentDispositionEncodingFallbackArray.reserveInitialCapacity(m_responseContentDispositionEncodingFallbackArray.size()); size_t encodingArraySize = m_responseContentDispositionEncodingFallbackArray.size(); for (size_t index = 0; index < encodingArraySize; ++index) { data->m_responseContentDispositionEncodingFallbackArray.append(m_responseContentDispositionEncodingFallbackArray[index].copy()); @@ -130,7 +130,8 @@ void ResourceRequestBase::setCachePolicy(ResourceRequestCachePolicy cachePolicy) m_cachePolicy = cachePolicy; - m_platformRequestUpdated = false; + if (url().protocolInHTTPFamily()) + m_platformRequestUpdated = false; } double ResourceRequestBase::timeoutInterval() const @@ -146,7 +147,8 @@ void ResourceRequestBase::setTimeoutInterval(double timeoutInterval) m_timeoutInterval = timeoutInterval; - m_platformRequestUpdated = false; + if (url().protocolInHTTPFamily()) + m_platformRequestUpdated = false; } const KURL& ResourceRequestBase::mainDocumentURL() const @@ -178,7 +180,8 @@ void ResourceRequestBase::setHTTPMethod(const String& httpMethod) m_httpMethod = httpMethod; - m_platformRequestUpdated = false; + if (url().protocolInHTTPFamily()) + m_platformRequestUpdated = false; } const HTTPHeaderMap& ResourceRequestBase::httpHeaderFields() const @@ -201,7 +204,8 @@ void ResourceRequestBase::setHTTPHeaderField(const AtomicString& name, const Str m_httpHeaderFields.set(name, value); - m_platformRequestUpdated = false; + if (url().protocolInHTTPFamily()) + m_platformRequestUpdated = false; } void ResourceRequestBase::setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2, const String& encoding3) @@ -216,7 +220,8 @@ void ResourceRequestBase::setResponseContentDispositionEncodingFallbackArray(con if (!encoding3.isNull()) m_responseContentDispositionEncodingFallbackArray.append(encoding3); - m_platformRequestUpdated = false; + if (url().protocolInHTTPFamily()) + m_platformRequestUpdated = false; } FormData* ResourceRequestBase::httpBody() const @@ -232,7 +237,8 @@ void ResourceRequestBase::setHTTPBody(PassRefPtr<FormData> httpBody) m_httpBody = httpBody; - m_platformRequestUpdated = false; + if (url().protocolInHTTPFamily()) + m_platformRequestUpdated = false; } bool ResourceRequestBase::allowHTTPCookies() const @@ -248,7 +254,8 @@ void ResourceRequestBase::setAllowHTTPCookies(bool allowHTTPCookies) m_allowHTTPCookies = allowHTTPCookies; - m_platformRequestUpdated = false; + if (url().protocolInHTTPFamily()) + m_platformRequestUpdated = false; } void ResourceRequestBase::addHTTPHeaderField(const AtomicString& name, const String& value) diff --git a/WebCore/platform/network/ResourceRequestBase.h b/WebCore/platform/network/ResourceRequestBase.h index 0f6bb47..4fd57e1 100644 --- a/WebCore/platform/network/ResourceRequestBase.h +++ b/WebCore/platform/network/ResourceRequestBase.h @@ -46,7 +46,7 @@ namespace WebCore { const int unspecifiedTimeoutInterval = INT_MAX; - class ResourceRequest; + struct ResourceRequest; struct CrossThreadResourceRequestData; // Do not use this type directly. Use ResourceRequest instead. @@ -107,12 +107,18 @@ namespace WebCore { void setAllowHTTPCookies(bool allowHTTPCookies); bool isConditional() const; - + + // Whether the associated ResourceHandleClient needs to be notified of + // upload progress made for that resource. + bool reportUploadProgress() const { return m_reportUploadProgress; } + void setReportUploadProgress(bool reportUploadProgress) { m_reportUploadProgress = reportUploadProgress; } + protected: // Used when ResourceRequest is initialized from a platform representation of the request ResourceRequestBase() : m_resourceRequestUpdated(false) , m_platformRequestUpdated(true) + , m_reportUploadProgress(false) { } @@ -124,6 +130,7 @@ namespace WebCore { , m_allowHTTPCookies(true) , m_resourceRequestUpdated(true) , m_platformRequestUpdated(false) + , m_reportUploadProgress(false) { } @@ -142,6 +149,7 @@ namespace WebCore { bool m_allowHTTPCookies; mutable bool m_resourceRequestUpdated; mutable bool m_platformRequestUpdated; + bool m_reportUploadProgress; private: const ResourceRequest& asResourceRequest() const; diff --git a/WebCore/platform/network/ResourceResponseBase.cpp b/WebCore/platform/network/ResourceResponseBase.cpp index 92ece8c..60c0097 100644 --- a/WebCore/platform/network/ResourceResponseBase.cpp +++ b/WebCore/platform/network/ResourceResponseBase.cpp @@ -39,7 +39,7 @@ static void parseCacheControlDirectiveValues(const String& directives, Vector<St auto_ptr<ResourceResponse> ResourceResponseBase::adopt(auto_ptr<CrossThreadResourceResponseData> data) { auto_ptr<ResourceResponse> response(new ResourceResponse()); - response->setUrl(data->m_url); + response->setURL(data->m_url); response->setMimeType(data->m_mimeType); response->setExpectedContentLength(data->m_expectedContentLength); response->setTextEncodingName(data->m_textEncodingName); @@ -94,7 +94,7 @@ const KURL& ResourceResponseBase::url() const return m_url; } -void ResourceResponseBase::setUrl(const KURL& url) +void ResourceResponseBase::setURL(const KURL& url) { lazyInit(); m_isNull = false; diff --git a/WebCore/platform/network/ResourceResponseBase.h b/WebCore/platform/network/ResourceResponseBase.h index c06f75b..ff34a26 100644 --- a/WebCore/platform/network/ResourceResponseBase.h +++ b/WebCore/platform/network/ResourceResponseBase.h @@ -49,7 +49,7 @@ public: bool isHTTP() const; const KURL& url() const; - void setUrl(const KURL& url); + void setURL(const KURL& url); const String& mimeType() const; void setMimeType(const String& mimeType); @@ -97,6 +97,13 @@ public: return m_cacheControlContainsMustRevalidate; } + // The ResourceResponse subclass may "shadow" this method to provide platform-specific memory usage information + unsigned memoryUsage() const + { + // average size, mostly due to URL and Header Map strings + return 1280; + } + static bool compare(const ResourceResponse& a, const ResourceResponse& b); protected: diff --git a/WebCore/platform/network/cf/FormDataStreamCFNet.cpp b/WebCore/platform/network/cf/FormDataStreamCFNet.cpp index 71fbfe7..3414d90 100644 --- a/WebCore/platform/network/cf/FormDataStreamCFNet.cpp +++ b/WebCore/platform/network/cf/FormDataStreamCFNet.cpp @@ -317,8 +317,7 @@ static void formEventCallback(CFReadStreamRef stream, CFStreamEventType type, vo void setHTTPBody(CFMutableURLRequestRef request, PassRefPtr<FormData> formData) { if (!formData) { - if (wkCanAccessCFURLRequestHTTPBodyParts()) - wkCFURLRequestSetHTTPRequestBodyParts(request, 0); + wkCFURLRequestSetHTTPRequestBodyParts(request, 0); return; } @@ -338,52 +337,20 @@ void setHTTPBody(CFMutableURLRequestRef request, PassRefPtr<FormData> formData) } } - if (wkCanAccessCFURLRequestHTTPBodyParts()) { - RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks)); - - for (size_t i = 0; i < count; ++i) { - const FormDataElement& element = formData->elements()[i]; - if (element.m_type == FormDataElement::data) { - RetainPtr<CFDataRef> data(AdoptCF, CFDataCreate(0, reinterpret_cast<const UInt8*>(element.m_data.data()), element.m_data.size())); - CFArrayAppendValue(array.get(), data.get()); - } else { - RetainPtr<CFStringRef> filename(AdoptCF, element.m_filename.createCFString()); - CFArrayAppendValue(array.get(), filename.get()); - } - } + RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks)); - wkCFURLRequestSetHTTPRequestBodyParts(request, array.get()); - return; - } - - // Precompute the content length so CFURLConnection doesn't use chunked mode. - bool haveLength = true; - long long length = 0; for (size_t i = 0; i < count; ++i) { const FormDataElement& element = formData->elements()[i]; - if (element.m_type == FormDataElement::data) - length += element.m_data.size(); - else { - long long size; - if (getFileSize(element.m_filename, size)) - length += size; - else - haveLength = false; + if (element.m_type == FormDataElement::data) { + RetainPtr<CFDataRef> data(AdoptCF, CFDataCreate(0, reinterpret_cast<const UInt8*>(element.m_data.data()), element.m_data.size())); + CFArrayAppendValue(array.get(), data.get()); + } else { + RetainPtr<CFStringRef> filename(AdoptCF, element.m_filename.createCFString()); + CFArrayAppendValue(array.get(), filename.get()); } } - if (haveLength) { - CFStringRef lengthStr = CFStringCreateWithFormat(0, 0, CFSTR("%lld"), length); - CFURLRequestSetHTTPHeaderFieldValue(request, CFSTR("Content-Length"), lengthStr); - CFRelease(lengthStr); - } - - static WCReadStreamCallBacks formDataStreamCallbacks = - { 1, formCreate, formFinalize, 0, formOpen, 0, formRead, 0, formCanRead, formClose, 0, 0, 0, formSchedule, formUnschedule }; - - CFReadStreamRef stream = CFReadStreamCreate(0, (CFReadStreamCallBacks *)&formDataStreamCallbacks, formData.releaseRef()); - CFURLRequestSetHTTPRequestBodyStream(request, stream); - CFRelease(stream); + wkCFURLRequestSetHTTPRequestBodyParts(request, array.get()); } PassRefPtr<FormData> httpBodyFromRequest(CFURLRequestRef request) @@ -391,28 +358,23 @@ PassRefPtr<FormData> httpBodyFromRequest(CFURLRequestRef request) if (RetainPtr<CFDataRef> bodyData = CFURLRequestCopyHTTPRequestBody(request)) return FormData::create(CFDataGetBytePtr(bodyData.get()), CFDataGetLength(bodyData.get())); - if (wkCanAccessCFURLRequestHTTPBodyParts()) { - if (RetainPtr<CFArrayRef> bodyParts = wkCFURLRequestCopyHTTPRequestBodyParts(request)) { - RefPtr<FormData> formData = FormData::create(); - - CFIndex count = CFArrayGetCount(bodyParts.get()); - for (CFIndex i = 0; i < count; i++) { - CFTypeRef bodyPart = CFArrayGetValueAtIndex(bodyParts.get(), i); - CFTypeID typeID = CFGetTypeID(bodyPart); - if (typeID == CFStringGetTypeID()) { - String filename = (CFStringRef)bodyPart; - formData->appendFile(filename); - } else if (typeID == CFDataGetTypeID()) { - CFDataRef data = (CFDataRef)bodyPart; - formData->appendData(CFDataGetBytePtr(data), CFDataGetLength(data)); - } else - ASSERT_NOT_REACHED(); - } - return formData.release(); + if (RetainPtr<CFArrayRef> bodyParts = wkCFURLRequestCopyHTTPRequestBodyParts(request)) { + RefPtr<FormData> formData = FormData::create(); + + CFIndex count = CFArrayGetCount(bodyParts.get()); + for (CFIndex i = 0; i < count; i++) { + CFTypeRef bodyPart = CFArrayGetValueAtIndex(bodyParts.get(), i); + CFTypeID typeID = CFGetTypeID(bodyPart); + if (typeID == CFStringGetTypeID()) { + String filename = (CFStringRef)bodyPart; + formData->appendFile(filename); + } else if (typeID == CFDataGetTypeID()) { + CFDataRef data = (CFDataRef)bodyPart; + formData->appendData(CFDataGetBytePtr(data), CFDataGetLength(data)); + } else + ASSERT_NOT_REACHED(); } - } else { - if (RetainPtr<CFReadStreamRef> bodyStream = CFURLRequestCopyHTTPRequestBodyStream(request)) - return getStreamFormDatas().get(bodyStream.get()); + return formData.release(); } // FIXME: what to do about arbitrary body streams? diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp index a4000a3..2dcbbed 100644 --- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 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 @@ -53,51 +53,6 @@ namespace WebCore { -static HMODULE findCFNetworkModule() -{ - if (HMODULE module = GetModuleHandleA("CFNetwork")) - return module; - return GetModuleHandleA("CFNetwork_debug"); -} - -static DWORD cfNetworkVersion() -{ - HMODULE cfNetworkModule = findCFNetworkModule(); - WCHAR filename[MAX_PATH]; - GetModuleFileName(cfNetworkModule, filename, MAX_PATH); - DWORD handle; - DWORD versionInfoSize = GetFileVersionInfoSize(filename, &handle); - Vector<BYTE> versionInfo(versionInfoSize); - GetFileVersionInfo(filename, handle, versionInfoSize, versionInfo.data()); - VS_FIXEDFILEINFO* fixedFileInfo; - UINT fixedFileInfoLength; - VerQueryValue(versionInfo.data(), TEXT("\\"), reinterpret_cast<LPVOID*>(&fixedFileInfo), &fixedFileInfoLength); - return fixedFileInfo->dwProductVersionMS; -} - -static CFIndex highestSupportedCFURLConnectionClientVersion() -{ - const DWORD firstCFNetworkVersionWithConnectionClientV2 = 0x000101a8; // 1.424 - const DWORD firstCFNetworkVersionWithConnectionClientV3 = 0x000101ad; // 1.429 - -#ifndef _CFURLConnectionClientV2Present - return 1; -#else - - DWORD version = cfNetworkVersion(); - if (version < firstCFNetworkVersionWithConnectionClientV2) - return 1; -#ifndef _CFURLConnectionClientV3Present - return 2; -#else - - if (version < firstCFNetworkVersionWithConnectionClientV3) - return 2; - return 3; -#endif // _CFURLConnectionClientV3Present -#endif // _CFURLConnectionClientV2Present -} - static HashSet<String>& allowsAnyHTTPSCertificateHosts() { static HashSet<String> hosts; @@ -154,7 +109,6 @@ void didReceiveData(CFURLConnectionRef conn, CFDataRef data, CFIndex originalLen handle->client()->didReceiveData(handle, (const char*)bytes, length, originalLength); } -#ifdef _CFURLConnectionClientV2Present static void didSendBodyData(CFURLConnectionRef conn, CFIndex bytesWritten, CFIndex totalBytesWritten, CFIndex totalBytesExpectedToWrite, const void *clientInfo) { ResourceHandle* handle = (ResourceHandle*)clientInfo; @@ -162,9 +116,7 @@ static void didSendBodyData(CFURLConnectionRef conn, CFIndex bytesWritten, CFInd return; handle->client()->didSendData(handle, totalBytesWritten, totalBytesExpectedToWrite); } -#endif -#ifdef _CFURLConnectionClientV3Present static Boolean shouldUseCredentialStorageCallback(CFURLConnectionRef conn, const void* clientInfo) { ResourceHandle* handle = const_cast<ResourceHandle*>(static_cast<const ResourceHandle*>(clientInfo)); @@ -176,7 +128,6 @@ static Boolean shouldUseCredentialStorageCallback(CFURLConnectionRef conn, const return handle->shouldUseCredentialStorage(); } -#endif void didFinishLoading(CFURLConnectionRef conn, const void* clientInfo) { @@ -202,6 +153,9 @@ CFCachedURLResponseRef willCacheResponse(CFURLConnectionRef conn, CFCachedURLRes { ResourceHandle* handle = (ResourceHandle*)clientInfo; + if (handle->client() && !handle->client()->shouldCacheResponse(handle, cachedResponse)) + return 0; + CacheStoragePolicy policy = static_cast<CacheStoragePolicy>(CFCachedURLResponseGetStoragePolicy(cachedResponse)); if (handle->client()) @@ -297,7 +251,7 @@ void* runLoaderThread(void *unused) CFRunLoopRef ResourceHandle::loaderRunLoop() { if (!loaderRL) { - createThread(runLoaderThread, 0, "CFNetwork::Loader"); + createThread(runLoaderThread, 0, "WebCore: CFNetwork Loader"); while (loaderRL == 0) { // FIXME: sleep 10? that can't be right... Sleep(10); @@ -348,20 +302,9 @@ bool ResourceHandle::start(Frame* frame) RetainPtr<CFURLRequestRef> request(AdoptCF, makeFinalRequest(d->m_request, d->m_shouldContentSniff)); - static CFIndex clientVersion = highestSupportedCFURLConnectionClientVersion(); - CFURLConnectionClient* client; -#if defined(_CFURLConnectionClientV3Present) - CFURLConnectionClient_V3 client_V3 = {clientVersion, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge, didSendBodyData, shouldUseCredentialStorageCallback, 0}; - client = reinterpret_cast<CFURLConnectionClient*>(&client_V3); -#elif defined(_CFURLConnectionClientV2Present) - CFURLConnectionClient_V2 client_V2 = {clientVersion, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge, didSendBodyData}; - client = reinterpret_cast<CFURLConnectionClient*>(&client_V2); -#else - CFURLConnectionClient client_V1 = {1, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge}; - client = &client_V1; -#endif - - d->m_connection.adoptCF(CFURLConnectionCreate(0, request.get(), client)); + CFURLConnectionClient_V3 client = { 3, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge, didSendBodyData, shouldUseCredentialStorageCallback, 0}; + + d->m_connection.adoptCF(CFURLConnectionCreate(0, request.get(), reinterpret_cast<CFURLConnectionClient*>(&client))); CFURLConnectionScheduleWithCurrentMessageQueue(d->m_connection.get()); CFURLConnectionScheduleDownloadWithRunLoop(d->m_connection.get(), loaderRunLoop(), kCFRunLoopDefaultMode); @@ -519,12 +462,22 @@ bool ResourceHandle::loadsBlocked() return false; } -bool ResourceHandle::willLoadFromCache(ResourceRequest&) +bool ResourceHandle::willLoadFromCache(ResourceRequest& request) { - // Not having this function means that we'll ask the user about re-posting a form - // even when we go back to a page that's still in the cache. - notImplemented(); - return false; + request.setCachePolicy(ReturnCacheDataDontLoad); + + CFURLResponseRef cfResponse = 0; + CFErrorRef cfError = 0; + RetainPtr<CFURLRequestRef> cfRequest(AdoptCF, makeFinalRequest(request, true)); + RetainPtr<CFDataRef> data(AdoptCF, CFURLConnectionSendSynchronousRequest(cfRequest.get(), &cfResponse, &cfError, request.timeoutInterval())); + bool cached = cfResponse && !cfError; + + if (cfError) + CFRelease(cfError); + if (cfResponse) + CFRelease(cfResponse); + + return cached; } } // namespace WebCore diff --git a/WebCore/platform/network/cf/ResourceRequestCFNet.h b/WebCore/platform/network/cf/ResourceRequestCFNet.h index e9ebe76..d26072d 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 { - class ResourceRequest; + struct ResourceRequest; void getResourceRequest(ResourceRequest&, CFURLRequestRef); CFURLRequestRef cfURLRequest(const ResourceRequest&); diff --git a/WebCore/platform/network/cf/ResourceResponse.h b/WebCore/platform/network/cf/ResourceResponse.h index e14c79e..04cc82c 100644 --- a/WebCore/platform/network/cf/ResourceResponse.h +++ b/WebCore/platform/network/cf/ResourceResponse.h @@ -52,6 +52,18 @@ public: { } + unsigned memoryUsage() const + { + // FIXME: Find some programmatic lighweight way to calculate ResourceResponse and associated classes. + // This is a rough estimate of resource overhead based on stats collected from the stress test. + return 3072; + /* 1280 * 2 + // average size of ResourceResponse. Doubled to account for the WebCore copy and the CF copy. + // Mostly due to the size of the hash maps, the Header Map strings and the URL. + 256 * 2 // Overhead from ResourceRequest, doubled to account for WebCore copy and CF copy. + // Mostly due to the URL and Header Map. + */ + } + CFURLResponseRef cfURLResponse() const; private: diff --git a/WebCore/platform/network/chromium/ResourceRequest.h b/WebCore/platform/network/chromium/ResourceRequest.h index 76b8b99..b14dba6 100644 --- a/WebCore/platform/network/chromium/ResourceRequest.h +++ b/WebCore/platform/network/chromium/ResourceRequest.h @@ -35,7 +35,7 @@ namespace WebCore { class Frame; - class ResourceRequest : public ResourceRequestBase { + struct ResourceRequest : public ResourceRequestBase { public: enum TargetType { TargetIsMainFrame, @@ -47,16 +47,16 @@ namespace WebCore { ResourceRequest(const String& url) : ResourceRequestBase(KURL(url), UseProtocolCachePolicy) - , m_frame(0) - , m_originPid(0) + , m_requestorID(0) + , m_requestorProcessID(0) , m_targetType(TargetIsSubResource) { } ResourceRequest(const KURL& url, const CString& securityInfo) : ResourceRequestBase(url, UseProtocolCachePolicy) - , m_frame(0) - , m_originPid(0) + , m_requestorID(0) + , m_requestorProcessID(0) , m_targetType(TargetIsSubResource) , m_securityInfo(securityInfo) { @@ -64,16 +64,16 @@ namespace WebCore { ResourceRequest(const KURL& url) : ResourceRequestBase(url, UseProtocolCachePolicy) - , m_frame(0) - , m_originPid(0) + , m_requestorID(0) + , m_requestorProcessID(0) , m_targetType(TargetIsSubResource) { } ResourceRequest(const KURL& url, const String& referrer, ResourceRequestCachePolicy policy = UseProtocolCachePolicy) : ResourceRequestBase(url, policy) - , m_frame(0) - , m_originPid(0) + , m_requestorID(0) + , m_requestorProcessID(0) , m_targetType(TargetIsSubResource) { setHTTPReferrer(referrer); @@ -81,26 +81,30 @@ namespace WebCore { ResourceRequest() : ResourceRequestBase(KURL(), UseProtocolCachePolicy) - , m_frame(0) - , m_originPid(0) + , m_requestorID(0) + , m_requestorProcessID(0) , m_targetType(TargetIsSubResource) { } - // Provides context for the resource request. - Frame* frame() const { return m_frame; } - void setFrame(Frame* frame) { m_frame = frame; } + // Allows the request to be matched up with its requestor. + int requestorID() const { return m_requestorID; } + void setRequestorID(int requestorID) { m_requestorID = requestorID; } // What this request is for. - void setTargetType(TargetType type) { m_targetType = type; } TargetType targetType() const { return m_targetType; } - - // The origin pid is 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 view process). - int originPid() const { return m_originPid; } - void setOriginPid(int originPid) { m_originPid = originPid; } + void setTargetType(TargetType type) { m_targetType = type; } + + // The document's policy base url. + KURL policyURL() const { return m_policyURL; } + void setPolicyURL(const KURL& policyURL) { m_policyURL = policyURL; } + + // 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 + // view process). + int requestorProcessID() const { return m_requestorProcessID; } + void setRequestorProcessID(int requestorProcessID) { m_requestorProcessID = requestorProcessID; } // Opaque buffer that describes the security state (including SSL // connection state) for the resource that should be reported when the @@ -117,10 +121,11 @@ namespace WebCore { void doUpdatePlatformRequest() {} void doUpdateResourceRequest() {} - Frame* m_frame; - int m_originPid; + int m_requestorID; + int m_requestorProcessID; TargetType m_targetType; CString m_securityInfo; + KURL m_policyURL; }; } // namespace WebCore diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp index 6a44233..6f009db 100644 --- a/WebCore/platform/network/curl/ResourceHandleManager.cpp +++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp @@ -126,7 +126,7 @@ static size_t writeCallback(void* ptr, size_t size, size_t nmemb, void* data) if (!d->m_response.responseFired()) { const char* hdr; err = curl_easy_getinfo(h, CURLINFO_EFFECTIVE_URL, &hdr); - d->m_response.setUrl(KURL(hdr)); + d->m_response.setURL(KURL(hdr)); if (d->client()) d->client()->didReceiveResponse(job, d->m_response); d->m_response.setResponseFired(true); @@ -180,7 +180,7 @@ static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* data) const char* hdr; err = curl_easy_getinfo(h, CURLINFO_EFFECTIVE_URL, &hdr); - d->m_response.setUrl(KURL(hdr)); + d->m_response.setURL(KURL(hdr)); long httpCode = 0; err = curl_easy_getinfo(h, CURLINFO_RESPONSE_CODE, &httpCode); diff --git a/WebCore/platform/network/mac/FormDataStreamMac.mm b/WebCore/platform/network/mac/FormDataStreamMac.mm index b618949..94fdb25 100644 --- a/WebCore/platform/network/mac/FormDataStreamMac.mm +++ b/WebCore/platform/network/mac/FormDataStreamMac.mm @@ -204,7 +204,7 @@ static void* formCreate(CFReadStreamRef stream, void* context) // Append in reverse order since we remove elements from the end. size_t size = formData->elements().size(); - newInfo->remainingElements.reserveCapacity(size); + newInfo->remainingElements.reserveInitialCapacity(size); for (size_t i = 0; i < size; ++i) newInfo->remainingElements.append(formData->elements()[size - i - 1]); diff --git a/WebCore/platform/network/mac/ResourceErrorMac.mm b/WebCore/platform/network/mac/ResourceErrorMac.mm index e59eadd..94c2124 100644 --- a/WebCore/platform/network/mac/ResourceErrorMac.mm +++ b/WebCore/platform/network/mac/ResourceErrorMac.mm @@ -26,6 +26,7 @@ #import "config.h" #import "ResourceError.h" +#import "BlockExceptions.h" #import "KURL.h" #import <Foundation/Foundation.h> @@ -46,8 +47,12 @@ void ResourceError::platformLazyInit() NSString* failingURLString = [[m_platformError.get() userInfo] valueForKey:@"NSErrorFailingURLStringKey"]; if (!failingURLString) failingURLString = [[[m_platformError.get() userInfo] valueForKey:@"NSErrorFailingURLKey"] absoluteString]; - + + // Workaround for <rdar://problem/6554067> + m_localizedDescription = failingURLString; + BEGIN_BLOCK_OBJC_EXCEPTIONS; m_localizedDescription = [m_platformError.get() _web_localizedDescription]; + END_BLOCK_OBJC_EXCEPTIONS; m_dataIsUpToDate = true; } diff --git a/WebCore/platform/network/mac/ResourceRequestMac.mm b/WebCore/platform/network/mac/ResourceRequestMac.mm index a9bbd40..92c37ee 100644 --- a/WebCore/platform/network/mac/ResourceRequestMac.mm +++ b/WebCore/platform/network/mac/ResourceRequestMac.mm @@ -119,8 +119,8 @@ void ResourceRequest::doUpdatePlatformRequest() for (HTTPHeaderMap::const_iterator it = httpHeaderFields().begin(); it != end; ++it) [nsRequest setValue:it->second forHTTPHeaderField:it->first]; - // The below check can be removed once we require a version of Foundation with -[NSMutableURLRequest setContentDispositionEncodingFallbackArray] method. - static bool supportsContentDispositionEncodingFallbackArray = [NSMutableURLRequest instancesRespondToSelector:@selector(setContentDispositionEncodingFallbackArray)]; + // The below check can be removed once we require a version of Foundation with -[NSMutableURLRequest setContentDispositionEncodingFallbackArray:] method. + static bool supportsContentDispositionEncodingFallbackArray = [NSMutableURLRequest instancesRespondToSelector:@selector(setContentDispositionEncodingFallbackArray:)]; if (supportsContentDispositionEncodingFallbackArray) { NSMutableArray *encodingFallbacks = [NSMutableArray array]; unsigned count = m_responseContentDispositionEncodingFallbackArray.size(); diff --git a/WebCore/platform/network/mac/ResourceResponse.h b/WebCore/platform/network/mac/ResourceResponse.h index b65760c..16b0cbf 100644 --- a/WebCore/platform/network/mac/ResourceResponse.h +++ b/WebCore/platform/network/mac/ResourceResponse.h @@ -57,6 +57,18 @@ public: { } + unsigned memoryUsage() const + { + // FIXME: Find some programmatic lighweight way to calculate ResourceResponse and associated classes. + // This is a rough estimate of resource overhead based on stats collected from the stress test. + return 3072; + /* 1280 * 2 + // average size of ResourceResponse. Doubled to account for the WebCore copy and the CF copy. + // Mostly due to the size of the hash maps, the Header Map strings and the URL. + 256 * 2 // Overhead from ResourceRequest, doubled to account for WebCore copy and CF copy. + // Mostly due to the URL and Header Map. + */ + } + NSURLResponse *nsURLResponse() const; private: diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index 2de2125..2c730a6 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -269,8 +269,10 @@ void QNetworkReplyHandler::sendResponseIfNeeded() const bool isLocalFileReply = (m_reply->url().scheme() == QLatin1String("file")); int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - if (!isLocalFileReply) + if (!isLocalFileReply) { response.setHTTPStatusCode(statusCode); + response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData()); + } else if (m_reply->error() == QNetworkReply::ContentNotFoundError) response.setHTTPStatusCode(404); diff --git a/WebCore/platform/network/soup/CookieJarSoup.cpp b/WebCore/platform/network/soup/CookieJarSoup.cpp index 88109e8..e3064e1 100644 --- a/WebCore/platform/network/soup/CookieJarSoup.cpp +++ b/WebCore/platform/network/soup/CookieJarSoup.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Xan Lopez <xan@gnome.org> + * Copyright (C) 2009 Igalia S.L. * Copyright (C) 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -25,15 +26,35 @@ namespace WebCore { -SoupCookieJar* getCookieJar() +static bool cookiesInitialized; +static SoupCookieJar* cookieJar; + +SoupCookieJar* defaultCookieJar() +{ + if (!cookiesInitialized) { + cookiesInitialized = true; + setDefaultCookieJar(soup_cookie_jar_new()); + } + + return cookieJar; +} + +void setDefaultCookieJar(SoupCookieJar* jar) { - static SoupCookieJar* jar = soup_cookie_jar_new(); - return jar; + cookiesInitialized = true; + + if (cookieJar) + g_object_unref(cookieJar); + + cookieJar = jar; + + if (cookieJar) + g_object_ref(cookieJar); } void setCookies(Document* /*document*/, const KURL& url, const KURL& /*policyURL*/, const String& value) { - SoupCookieJar* jar = getCookieJar(); + SoupCookieJar* jar = defaultCookieJar(); if (!jar) return; @@ -45,7 +66,7 @@ void setCookies(Document* /*document*/, const KURL& url, const KURL& /*policyURL String cookies(const Document* /*document*/, const KURL& url) { - SoupCookieJar* jar = getCookieJar(); + SoupCookieJar* jar = defaultCookieJar(); if (!jar) return String(); @@ -61,7 +82,7 @@ String cookies(const Document* /*document*/, const KURL& url) bool cookiesEnabled(const Document* /*document*/) { - return getCookieJar(); + return defaultCookieJar(); } } diff --git a/WebCore/platform/network/soup/CookieJarSoup.h b/WebCore/platform/network/soup/CookieJarSoup.h index 61179ae..ab1f95c 100644 --- a/WebCore/platform/network/soup/CookieJarSoup.h +++ b/WebCore/platform/network/soup/CookieJarSoup.h @@ -31,7 +31,8 @@ #include <libsoup/soup.h> namespace WebCore { - SoupCookieJar* getCookieJar(); + SoupCookieJar* defaultCookieJar(); + void setDefaultCookieJar(SoupCookieJar* jar); } #endif diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp index da96873..1b91e32 100644 --- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -3,6 +3,9 @@ * Copyright (C) 2008 Xan Lopez <xan@gnome.org> * Copyright (C) 2008 Collabora Ltd. * Copyright (C) 2009 Holger Hans Peter Freyther + * Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org> + * Copyright (C) 2009 Christian Dywan <christian@imendio.com> + * Copyright (C) 2009 Igalia S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,41 +24,109 @@ */ #include "config.h" -#include "CString.h" #include "ResourceHandle.h" #include "Base64.h" #include "CookieJarSoup.h" +#include "ChromeClient.h" +#include "CString.h" #include "DocLoader.h" +#include "FileSystem.h" #include "Frame.h" #include "HTTPParsers.h" +#include "Logging.h" #include "MIMETypeRegistry.h" #include "NotImplemented.h" +#include "Page.h" #include "ResourceError.h" #include "ResourceHandleClient.h" #include "ResourceHandleInternal.h" #include "ResourceResponse.h" #include "TextEncoding.h" +#include <errno.h> +#include <fcntl.h> #include <gio/gio.h> +#include <gtk/gtk.h> #include <libsoup/soup.h> -#include <libsoup/soup-message.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> #if PLATFORM(GTK) - #if GLIB_CHECK_VERSION(2,12,0) - #define USE_GLIB_BASE64 - #endif +#define USE_GLIB_BASE64 #endif namespace WebCore { -static SoupSession* session = 0; +class WebCoreSynchronousLoader : public ResourceHandleClient, Noncopyable { +public: + WebCoreSynchronousLoader(ResourceError&, ResourceResponse &, Vector<char>&); + ~WebCoreSynchronousLoader(); + + virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); + virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived); + virtual void didFinishLoading(ResourceHandle*); + virtual void didFail(ResourceHandle*, const ResourceError&); + + void run(); + +private: + ResourceError& m_error; + ResourceResponse& m_response; + Vector<char>& m_data; + bool m_finished; + GMainLoop* m_mainLoop; +}; + +WebCoreSynchronousLoader::WebCoreSynchronousLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data) + : m_error(error) + , m_response(response) + , m_data(data) + , m_finished(false) +{ + m_mainLoop = g_main_loop_new(0, false); +} + +WebCoreSynchronousLoader::~WebCoreSynchronousLoader() +{ + g_main_loop_unref(m_mainLoop); +} + +void WebCoreSynchronousLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response) +{ + m_response = response; +} + +void WebCoreSynchronousLoader::didReceiveData(ResourceHandle*, const char* data, int length, int) +{ + m_data.append(data, length); +} + +void WebCoreSynchronousLoader::didFinishLoading(ResourceHandle*) +{ + g_main_loop_quit(m_mainLoop); + m_finished = true; +} + +void WebCoreSynchronousLoader::didFail(ResourceHandle* handle, const ResourceError& error) +{ + m_error = error; + didFinishLoading(handle); +} + +void WebCoreSynchronousLoader::run() +{ + if (!m_finished) + g_main_loop_run(m_mainLoop); +} enum { ERROR_TRANSPORT, ERROR_UNKNOWN_PROTOCOL, - ERROR_BAD_NON_HTTP_METHOD + ERROR_BAD_NON_HTTP_METHOD, + ERROR_UNABLE_TO_OPEN_FILE, }; static void cleanupGioOperation(ResourceHandleInternal* handle); @@ -82,20 +153,47 @@ ResourceHandle::~ResourceHandle() static void fillResponseFromMessage(SoupMessage* msg, ResourceResponse* response) { SoupMessageHeadersIter iter; - const char* name = NULL; - const char* value = NULL; + const char* name = 0; + const char* value = 0; soup_message_headers_iter_init(&iter, msg->response_headers); while (soup_message_headers_iter_next(&iter, &name, &value)) response->setHTTPHeaderField(name, value); - String contentType = soup_message_headers_get(msg->response_headers, "Content-Type"); - char* uri = soup_uri_to_string(soup_message_get_uri(msg), FALSE); - response->setUrl(KURL(uri)); - g_free(uri); + GHashTable* contentTypeParameters = 0; + String contentType = soup_message_headers_get_content_type(msg->response_headers, &contentTypeParameters); + + // When the server sends multiple Content-Type headers, soup will + // give us their values concatenated with commas as a separator; + // we need to handle this and use only one value. We use the first + // value, and add all the parameters, afterwards, if any. + Vector<String> contentTypes; + contentType.split(',', true, contentTypes); + contentType = contentTypes[0]; + + if (contentTypeParameters) { + GHashTableIter hashTableIter; + gpointer hashKey; + gpointer hashValue; + + g_hash_table_iter_init(&hashTableIter, contentTypeParameters); + while (g_hash_table_iter_next(&hashTableIter, &hashKey, &hashValue)) { + contentType += String("; "); + contentType += String(static_cast<char*>(hashKey)); + contentType += String("="); + contentType += String(static_cast<char*>(hashValue)); + } + g_hash_table_destroy(contentTypeParameters); + } + response->setMimeType(extractMIMETypeFromMediaType(contentType)); + + char* uri = soup_uri_to_string(soup_message_get_uri(msg), false); + response->setURL(KURL(KURL(), uri)); + g_free(uri); response->setTextEncodingName(extractCharsetFromMediaType(contentType)); response->setExpectedContentLength(soup_message_headers_get_content_length(msg->response_headers)); response->setHTTPStatusCode(msg->status_code); + response->setHTTPStatusText(msg->reason_phrase); response->setSuggestedFilename(filenameFromHTTPContentDisposition(response->httpHeaderField("Content-Disposition"))); } @@ -110,11 +208,20 @@ static void restartedCallback(SoupMessage* msg, gpointer data) if (d->m_cancelled) return; - char* uri = soup_uri_to_string(soup_message_get_uri(msg), FALSE); + char* uri = soup_uri_to_string(soup_message_get_uri(msg), false); String location = String(uri); g_free(uri); KURL newURL = KURL(handle->request().url(), location); + // FIXME: This is needed because some servers use broken URIs in + // their Location header, when redirecting, such as URIs with + // white spaces instead of %20; this should be fixed in soup, in + // the future, and this work-around removed. + // See http://bugzilla.gnome.org/show_bug.cgi?id=575378. + SoupURI* soup_uri = soup_uri_new(newURL.string().utf8().data()); + soup_message_set_uri(msg, soup_uri); + soup_uri_free(soup_uri); + ResourceRequest request = handle->request(); ResourceResponse response; request.setURL(newURL); @@ -127,7 +234,32 @@ static void restartedCallback(SoupMessage* msg, gpointer data) static void gotHeadersCallback(SoupMessage* msg, gpointer data) { - if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) + // For 401, we will accumulate the resource body, and only use it + // in case authentication with the soup feature doesn't happen + if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) { + soup_message_body_set_accumulate(msg->response_body, TRUE); + return; + } + + // For all the other responses, we handle each chunk ourselves, + // and we don't need msg->response_body to contain all of the data + // we got, when we finish downloading. + soup_message_body_set_accumulate(msg->response_body, FALSE); + + // The 304 status code (SOUP_STATUS_NOT_MODIFIED) needs to be fed + // into WebCore, as opposed to other kinds of redirections, which + // are handled by soup directly, so we special-case it here and in + // gotChunk. + if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code) + || (SOUP_STATUS_IS_REDIRECTION(msg->status_code) && (msg->status_code != SOUP_STATUS_NOT_MODIFIED))) + return; + + // We still don't know anything about Content-Type, so we will try + // sniffing the contents of the file, and then report that we got + // headers; we will not do content sniffing for 304 responses, + // though, since they do not have a body. + if ((msg->status_code != SOUP_STATUS_NOT_MODIFIED) + && !soup_message_headers_get_content_type(msg->response_headers, NULL)) return; ResourceHandle* handle = static_cast<ResourceHandle*>(data); @@ -142,12 +274,14 @@ static void gotHeadersCallback(SoupMessage* msg, gpointer data) fillResponseFromMessage(msg, &d->m_response); client->didReceiveResponse(handle, d->m_response); - soup_message_set_flags(msg, SOUP_MESSAGE_OVERWRITE_CHUNKS); + d->m_reportedHeaders = true; } static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data) { - if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) + if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code) + || (SOUP_STATUS_IS_REDIRECTION(msg->status_code) && (msg->status_code != SOUP_STATUS_NOT_MODIFIED)) + || (msg->status_code == SOUP_STATUS_UNAUTHORIZED)) return; ResourceHandle* handle = static_cast<ResourceHandle*>(data); @@ -160,6 +294,17 @@ static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data) if (!client) return; + if (!d->m_reportedHeaders) { + gboolean uncertain; + char* contentType = g_content_type_guess(d->m_request.url().lastPathComponent().utf8().data(), reinterpret_cast<const guchar*>(chunk->data), chunk->length, &uncertain); + soup_message_headers_set_content_type(msg->response_headers, contentType, NULL); + g_free(contentType); + + fillResponseFromMessage(msg, &d->m_response); + client->didReceiveResponse(handle, d->m_response); + d->m_reportedHeaders = true; + } + client->didReceiveData(handle, chunk->data, chunk->length, false); } @@ -167,7 +312,7 @@ static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data) // Doesn't get called for redirects. static void finishedCallback(SoupSession *session, SoupMessage* msg, gpointer data) { - ResourceHandle* handle = static_cast<ResourceHandle*>(data); + RefPtr<ResourceHandle>handle = adoptRef(static_cast<ResourceHandle*>(data)); // TODO: maybe we should run this code even if there's no client? if (!handle) return; @@ -182,24 +327,26 @@ static void finishedCallback(SoupSession *session, SoupMessage* msg, gpointer da return; if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) { - char* uri = soup_uri_to_string(soup_message_get_uri(msg), FALSE); + char* uri = soup_uri_to_string(soup_message_get_uri(msg), false); ResourceError error("webkit-network-error", ERROR_TRANSPORT, uri, String::fromUTF8(msg->reason_phrase)); g_free(uri); - client->didFail(handle, error); + client->didFail(handle.get(), error); return; - } else if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) { + } + + if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) { fillResponseFromMessage(msg, &d->m_response); - client->didReceiveResponse(handle, d->m_response); + client->didReceiveResponse(handle.get(), d->m_response); // WebCore might have cancelled the job in the while if (d->m_cancelled) return; if (msg->response_body->data) - client->didReceiveData(handle, msg->response_body->data, msg->response_body->length, true); + client->didReceiveData(handle.get(), msg->response_body->data, msg->response_body->length, true); } - client->didFinishLoading(handle); + client->didFinishLoading(handle.get()); } // parseDataUrl() is taken from the CURL http backend. @@ -212,7 +359,7 @@ static gboolean parseDataUrl(gpointer callback_data) ASSERT(client); if (!client) - return FALSE; + return false; String url = handle->request().url().string(); ASSERT(url.startsWith("data:", false)); @@ -220,14 +367,14 @@ static gboolean parseDataUrl(gpointer callback_data) int index = url.find(','); if (index == -1) { client->cannotShowURL(handle); - return FALSE; + return false; } String mediaType = url.substring(5, index - 5); String data = url.substring(index + 1); - bool base64 = mediaType.endsWith(";base64", false); - if (base64) + bool isBase64 = mediaType.endsWith(";base64", false); + if (isBase64) mediaType = mediaType.left(mediaType.length() - 7); if (mediaType.isEmpty()) @@ -239,7 +386,7 @@ static gboolean parseDataUrl(gpointer callback_data) ResourceResponse response; response.setMimeType(mimeType); - if (base64) { + if (isBase64) { data = decodeURLEscapeSequences(data); response.setTextEncodingName(charset); client->didReceiveResponse(handle, response); @@ -269,7 +416,7 @@ static gboolean parseDataUrl(gpointer callback_data) client->didFinishLoading(handle); - return FALSE; + return false; } bool ResourceHandle::startData(String urlString) @@ -282,30 +429,44 @@ bool ResourceHandle::startData(String urlString) return true; } -bool ResourceHandle::startHttp(String urlString) +static SoupSession* createSoupSession() { - if (!session) { - session = soup_session_async_new(); + return soup_session_async_new(); +} - soup_session_add_feature(session, SOUP_SESSION_FEATURE(getCookieJar())); +static void ensureSessionIsInitialized(SoupSession* session) +{ + if (g_object_get_data(G_OBJECT(session), "webkit-init")) + return; - const char* soup_debug = g_getenv("WEBKIT_SOUP_LOGGING"); - if (soup_debug) { - int soup_debug_level = atoi(soup_debug); + SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR)); + if (!jar) + soup_session_add_feature(session, SOUP_SESSION_FEATURE(defaultCookieJar())); + else + setDefaultCookieJar(jar); - SoupLogger* logger = soup_logger_new(static_cast<SoupLoggerLogLevel>(soup_debug_level), -1); - soup_logger_attach(logger, session); - g_object_unref(logger); - } + if (!soup_session_get_feature(session, SOUP_TYPE_LOGGER) && LogNetwork.state == WTFLogChannelOn) { + SoupLogger* logger = soup_logger_new(static_cast<SoupLoggerLogLevel>(SOUP_LOGGER_LOG_BODY), -1); + soup_logger_attach(logger, session); + g_object_unref(logger); } + g_object_set_data(G_OBJECT(session), "webkit-init", reinterpret_cast<void*>(0xdeadbeef)); +} + +bool ResourceHandle::startHttp(String urlString) +{ + SoupSession* session = defaultSession(); + ensureSessionIsInitialized(session); + SoupMessage* msg; msg = soup_message_new(request().httpMethod().utf8().data(), urlString.utf8().data()); g_signal_connect(msg, "restarted", G_CALLBACK(restartedCallback), this); - g_signal_connect(msg, "got-headers", G_CALLBACK(gotHeadersCallback), this); g_signal_connect(msg, "got-chunk", G_CALLBACK(gotChunkCallback), this); + g_object_set_data(G_OBJECT(msg), "resourceHandle", reinterpret_cast<void*>(this)); + HTTPHeaderMap customHeaders = d->m_request.httpHeaderFields(); if (!customHeaders.isEmpty()) { HTTPHeaderMap::const_iterator end = customHeaders.end(); @@ -315,68 +476,130 @@ bool ResourceHandle::startHttp(String urlString) FormData* httpBody = d->m_request.httpBody(); if (httpBody && !httpBody->isEmpty()) { - // Making a copy of the request body isn't the most efficient way to - // serialize it, but by far the most simple. Dealing with individual - // FormData elements and shared buffers should be more memory - // efficient. - // - // This possibly isn't handling file uploads/attachments, for which - // shared buffers or streaming should definitely be used. - Vector<char> body; - httpBody->flatten(body); - soup_message_set_request(msg, d->m_request.httpContentType().utf8().data(), - SOUP_MEMORY_COPY, body.data(), body.size()); + size_t numElements = httpBody->elements().size(); + + // handle the most common case (i.e. no file upload) + if (numElements < 2) { + Vector<char> body; + httpBody->flatten(body); + soup_message_set_request(msg, d->m_request.httpContentType().utf8().data(), + SOUP_MEMORY_COPY, body.data(), body.size()); + } else { + /* + * we have more than one element to upload, and some may + * be (big) files, which we will want to mmap instead of + * copying into memory; TODO: support upload of non-local + * (think sftp://) files by using GIO? + */ + soup_message_body_set_accumulate(msg->request_body, FALSE); + for (size_t i = 0; i < numElements; i++) { + const FormDataElement& element = httpBody->elements()[i]; + + if (element.m_type == FormDataElement::data) + soup_message_body_append(msg->request_body, SOUP_MEMORY_TEMPORARY, element.m_data.data(), element.m_data.size()); + else { + /* + * mapping for uploaded files code inspired by technique used in + * libsoup's simple-httpd test + */ + GError* error = 0; + gchar* fileName = filenameFromString(element.m_filename); + GMappedFile* fileMapping = g_mapped_file_new(fileName, false, &error); + + g_free(fileName); + + if (error) { + ResourceError resourceError("webkit-network-error", ERROR_UNABLE_TO_OPEN_FILE, urlString, error->message); + g_error_free(error); + + d->client()->didFail(this, resourceError); + + g_object_unref(msg); + return false; + } + + SoupBuffer* soupBuffer = soup_buffer_new_with_owner(g_mapped_file_get_contents(fileMapping), + g_mapped_file_get_length(fileMapping), + fileMapping, reinterpret_cast<GDestroyNotify>(g_mapped_file_free)); + soup_message_body_append_buffer(msg->request_body, soupBuffer); + soup_buffer_free(soupBuffer); + } + } + } } d->m_msg = static_cast<SoupMessage*>(g_object_ref(msg)); + // balanced by a deref() in finishedCallback, which should always run + ref(); + soup_session_queue_message(session, d->m_msg, finishedCallback, this); return true; } +static gboolean reportUnknownProtocolError(gpointer callback_data) +{ + ResourceHandle* handle = static_cast<ResourceHandle*>(callback_data); + ResourceHandleInternal* d = handle->getInternal(); + ResourceHandleClient* client = handle->client(); + + if (d->m_cancelled || !client) { + handle->deref(); + return false; + } + + KURL url = handle->request().url(); + ResourceError error("webkit-network-error", ERROR_UNKNOWN_PROTOCOL, url.string(), url.protocol()); + client->didFail(handle, error); + + handle->deref(); + return false; +} + bool ResourceHandle::start(Frame* frame) { ASSERT(!d->m_msg); - // If we are no longer attached to a Page, this must be an attempted load from an - // onUnload handler, so let's just block it. - if (!frame->page()) + + // The frame could be null if the ResourceHandle is not associated to any + // Frame, e.g. if we are downloading a file. + // If the frame is not null but the page is null this must be an attempted + // load from an onUnload handler, so let's just block it. + if (frame && !frame->page()) return false; KURL url = request().url(); String urlString = url.string(); String protocol = url.protocol(); + // Used to set the authentication dialog toplevel; may be NULL + d->m_frame = frame; + if (equalIgnoringCase(protocol, "data")) return startData(urlString); - else if ((equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https")) && SOUP_URI_VALID_FOR_HTTP(soup_uri_new(urlString.utf8().data()))) + + if ((equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https")) && SOUP_URI_VALID_FOR_HTTP(soup_uri_new(urlString.utf8().data()))) return startHttp(urlString); - else if (equalIgnoringCase(protocol, "file") || equalIgnoringCase(protocol, "ftp") || equalIgnoringCase(protocol, "ftps")) + + if (equalIgnoringCase(protocol, "file") || equalIgnoringCase(protocol, "ftp") || equalIgnoringCase(protocol, "ftps")) // FIXME: should we be doing any other protocols here? - return startGio(urlString); - else { - // If we don't call didFail the job is not complete for webkit even false is returned. - if (d->client()) { - ResourceError error("webkit-network-error", ERROR_UNKNOWN_PROTOCOL, urlString, protocol); - d->client()->didFail(this, error); - } - return false; - } + return startGio(url); + + // Error must not be reported immediately, but through an idle function. + // Despite error, we should return true so a proper handle is created, + // to which this failure can be reported. + ref(); + d->m_idleHandler = g_idle_add(reportUnknownProtocolError, this); + return true; } void ResourceHandle::cancel() { d->m_cancelled = true; - if (d->m_msg) { - soup_session_cancel_message(session, d->m_msg, SOUP_STATUS_CANCELLED); - // For re-entrancy troubles we call didFinishLoading when the message hasn't been handled yet. - if (client()) - client()->didFinishLoading(this); - } else if (d->m_cancellable) { + if (d->m_msg) + soup_session_cancel_message(defaultSession(), d->m_msg, SOUP_STATUS_CANCELLED); + else if (d->m_cancellable) g_cancellable_cancel(d->m_cancellable); - if (client()) - client()->didFinishLoading(this); - } } PassRefPtr<SharedBuffer> ResourceHandle::bufferedData() @@ -409,9 +632,13 @@ bool ResourceHandle::willLoadFromCache(ResourceRequest&) return false; } -void ResourceHandle::loadResourceSynchronously(const ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>&, Frame*) +void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame* frame) { - notImplemented(); + WebCoreSynchronousLoader syncLoader(error, response, data); + ResourceHandle handle(request, &syncLoader, true, false, true); + + handle.start(frame); + syncLoader.run(); } // GIO-based loader @@ -420,7 +647,7 @@ static inline ResourceError networkErrorForFile(GFile* file, GError* error) { // FIXME: Map gio errors to a more detailed error code when we have it in WebKit. gchar* uri = g_file_get_uri(file); - ResourceError resourceError("webkit-network-error", ERROR_TRANSPORT, uri, String::fromUTF8(error->message)); + ResourceError resourceError("webkit-network-error", ERROR_TRANSPORT, uri, error ? String::fromUTF8(error->message) : String()); g_free(uri); return resourceError; } @@ -430,20 +657,23 @@ static void cleanupGioOperation(ResourceHandleInternal* d) if (d->m_gfile) { g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", 0); g_object_unref(d->m_gfile); - d->m_gfile = NULL; + d->m_gfile = 0; } + if (d->m_cancellable) { g_object_unref(d->m_cancellable); - d->m_cancellable = NULL; + d->m_cancellable = 0; } - if (d->m_input_stream) { - g_object_set_data(G_OBJECT(d->m_input_stream), "webkit-resource", 0); - g_object_unref(d->m_input_stream); - d->m_input_stream = NULL; + + if (d->m_inputStream) { + g_object_set_data(G_OBJECT(d->m_inputStream), "webkit-resource", 0); + g_object_unref(d->m_inputStream); + d->m_inputStream = 0; } + if (d->m_buffer) { g_free(d->m_buffer); - d->m_buffer = NULL; + d->m_buffer = 0; } } @@ -456,14 +686,15 @@ static void closeCallback(GObject* source, GAsyncResult* res, gpointer) ResourceHandleInternal* d = handle->getInternal(); ResourceHandleClient* client = handle->client(); - g_input_stream_close_finish(d->m_input_stream, res, NULL); + g_input_stream_close_finish(d->m_inputStream, res, 0); cleanupGioOperation(d); client->didFinishLoading(handle); } static void readCallback(GObject* source, GAsyncResult* res, gpointer) { - ResourceHandle* handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); + // didReceiveData may cancel the load, which may release the last reference. + RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); if (!handle) return; @@ -475,27 +706,34 @@ static void readCallback(GObject* source, GAsyncResult* res, gpointer) return; } - gssize nread; GError *error = 0; - nread = g_input_stream_read_finish(d->m_input_stream, res, &error); + gssize bytesRead = g_input_stream_read_finish(d->m_inputStream, res, &error); if (error) { ResourceError resourceError = networkErrorForFile(d->m_gfile, error); + g_error_free(error); cleanupGioOperation(d); - client->didFail(handle, resourceError); + client->didFail(handle.get(), resourceError); return; - } else if (!nread) { - g_input_stream_close_async(d->m_input_stream, G_PRIORITY_DEFAULT, - NULL, closeCallback, NULL); + } + + if (!bytesRead) { + g_input_stream_close_async(d->m_inputStream, G_PRIORITY_DEFAULT, + 0, closeCallback, 0); return; } - d->m_total += nread; - client->didReceiveData(handle, d->m_buffer, nread, d->m_total); + d->m_total += bytesRead; + client->didReceiveData(handle.get(), d->m_buffer, bytesRead, d->m_total); - g_input_stream_read_async(d->m_input_stream, d->m_buffer, d->m_bufsize, + if (d->m_cancelled) { + cleanupGioOperation(d); + return; + } + + g_input_stream_read_async(d->m_inputStream, d->m_buffer, d->m_bufferSize, G_PRIORITY_DEFAULT, d->m_cancellable, - readCallback, NULL); + readCallback, 0); } static void openCallback(GObject* source, GAsyncResult* res, gpointer) @@ -512,24 +750,24 @@ static void openCallback(GObject* source, GAsyncResult* res, gpointer) return; } - GFileInputStream* in; - GError *error = NULL; - in = g_file_read_finish(G_FILE(source), res, &error); + GError *error = 0; + GFileInputStream* in = g_file_read_finish(G_FILE(source), res, &error); if (error) { ResourceError resourceError = networkErrorForFile(d->m_gfile, error); + g_error_free(error); cleanupGioOperation(d); client->didFail(handle, resourceError); return; } - d->m_input_stream = G_INPUT_STREAM(in); - d->m_bufsize = 8192; - d->m_buffer = static_cast<char*>(g_malloc(d->m_bufsize)); + d->m_inputStream = G_INPUT_STREAM(in); + d->m_bufferSize = 8192; + d->m_buffer = static_cast<char*>(g_malloc(d->m_bufferSize)); d->m_total = 0; - g_object_set_data(G_OBJECT(d->m_input_stream), "webkit-resource", handle); - g_input_stream_read_async(d->m_input_stream, d->m_buffer, d->m_bufsize, + g_object_set_data(G_OBJECT(d->m_inputStream), "webkit-resource", handle); + g_input_stream_read_async(d->m_inputStream, d->m_buffer, d->m_bufferSize, G_PRIORITY_DEFAULT, d->m_cancellable, - readCallback, NULL); + readCallback, 0); } static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) @@ -549,10 +787,10 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) ResourceResponse response; char* uri = g_file_get_uri(d->m_gfile); - response.setUrl(KURL(uri)); + response.setURL(KURL(KURL(), uri)); g_free(uri); - GError *error = NULL; + GError *error = 0; GFileInfo* info = g_file_query_info_finish(d->m_gfile, res, &error); if (error) { @@ -564,6 +802,7 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) // for a while). ResourceError resourceError = networkErrorForFile(d->m_gfile, error); + g_error_free(error); cleanupGioOperation(d); client->didFail(handle, resourceError); return; @@ -573,7 +812,7 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) // FIXME: what if the URI points to a directory? Should we // generate a listing? How? What do other backends do here? - ResourceError resourceError = networkErrorForFile(d->m_gfile, error); + ResourceError resourceError = networkErrorForFile(d->m_gfile, 0); cleanupGioOperation(d); client->didFail(handle, resourceError); return; @@ -581,7 +820,6 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) response.setMimeType(g_file_info_get_content_type(info)); response.setExpectedContentLength(g_file_info_get_size(info)); - response.setHTTPStatusCode(SOUP_STATUS_OK); GTimeVal tv; g_file_info_get_modification_time(info, &tv); @@ -590,23 +828,31 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) client->didReceiveResponse(handle, response); g_file_read_async(d->m_gfile, G_PRIORITY_DEFAULT, d->m_cancellable, - openCallback, NULL); + openCallback, 0); } -bool ResourceHandle::startGio(String urlString) +bool ResourceHandle::startGio(KURL url) { - if (request().httpMethod() != "GET") { - ResourceError error("webkit-network-error", ERROR_BAD_NON_HTTP_METHOD, urlString, request().httpMethod()); + if (request().httpMethod() != "GET" && request().httpMethod() != "POST") { + ResourceError error("webkit-network-error", ERROR_BAD_NON_HTTP_METHOD, url.string(), request().httpMethod()); d->client()->didFail(this, error); return false; } - // Remove the fragment part of the URL since the file backend doesn't deal with it - int fragPos; - if ((fragPos = urlString.find("#")) != -1) - urlString = urlString.left(fragPos); - - d->m_gfile = g_file_new_for_uri(urlString.utf8().data()); + // GIO doesn't know how to handle refs and queries, so remove them + // TODO: use KURL.fileSystemPath after KURLGtk and FileSystemGtk are + // using GIO internally, and providing URIs instead of file paths + url.removeRef(); + url.setQuery(String()); + url.setPort(0); + + // we avoid the escaping for local files, because + // g_filename_from_uri (used internally by GFile) has problems + // decoding strings with arbitrary percent signs + if (url.isLocalFile()) + d->m_gfile = g_file_new_for_path(url.prettyURL().utf8().data() + sizeof("file://") - 1); + else + d->m_gfile = g_file_new_for_uri(url.string().utf8().data()); g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", this); d->m_cancellable = g_cancellable_new(); g_file_query_info_async(d->m_gfile, @@ -615,9 +861,16 @@ bool ResourceHandle::startGio(String urlString) G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, d->m_cancellable, - queryInfoCallback, NULL); + queryInfoCallback, 0); return true; } +SoupSession* ResourceHandle::defaultSession() +{ + static SoupSession* session = createSoupSession();; + + return session; +} + } diff --git a/WebCore/platform/network/win/CookieJarCFNetWin.cpp b/WebCore/platform/network/win/CookieJarCFNetWin.cpp index 56d7265..7e64813 100644 --- a/WebCore/platform/network/win/CookieJarCFNetWin.cpp +++ b/WebCore/platform/network/win/CookieJarCFNetWin.cpp @@ -41,28 +41,6 @@ namespace WebCore { static const CFStringRef s_setCookieKeyCF = CFSTR("Set-Cookie"); static const CFStringRef s_cookieCF = CFSTR("Cookie"); -typedef Boolean (*IsHTTPOnlyFunction)(CFHTTPCookieRef); - -static HMODULE findCFNetworkModule() -{ - if (HMODULE module = GetModuleHandleA("CFNetwork")) - return module; - return GetModuleHandleA("CFNetwork_debug"); -} - -static IsHTTPOnlyFunction findIsHTTPOnlyFunction() -{ - return reinterpret_cast<IsHTTPOnlyFunction>(GetProcAddress(findCFNetworkModule(), "CFHTTPCookieIsHTTPOnly")); -} - -static bool isHTTPOnly(CFHTTPCookieRef cookie) -{ - // Once we require a newer version of CFNetwork with the CFHTTPCookieIsHTTPOnly function, - // we can change this to be a normal function call and eliminate findIsHTTPOnlyFunction. - static IsHTTPOnlyFunction function = findIsHTTPOnlyFunction(); - return function && function(cookie); -} - static RetainPtr<CFArrayRef> filterCookies(CFArrayRef unfilteredCookies) { CFIndex count = CFArrayGetCount(unfilteredCookies); @@ -77,7 +55,7 @@ static RetainPtr<CFArrayRef> filterCookies(CFArrayRef unfilteredCookies) if (!CFStringGetLength(CFHTTPCookieGetName(cookie))) continue; - if (isHTTPOnly(cookie)) + if (CFHTTPCookieIsHTTPOnly(cookie)) continue; CFArrayAppendValue(filteredCookies.get(), cookie); |