summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/network
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/network')
-rw-r--r--WebCore/platform/network/ResourceRequestBase.cpp10
-rw-r--r--WebCore/platform/network/ResourceRequestBase.h2
-rw-r--r--WebCore/platform/network/SocketStreamErrorBase.cpp17
-rw-r--r--WebCore/platform/network/SocketStreamErrorBase.h14
-rw-r--r--WebCore/platform/network/cf/DNSCFNet.cpp44
-rw-r--r--WebCore/platform/network/cf/ResourceHandleCFNet.cpp2
-rw-r--r--WebCore/platform/network/cf/ResourceResponseCFNet.cpp5
-rw-r--r--WebCore/platform/network/cf/SocketStreamError.h5
-rw-r--r--WebCore/platform/network/cf/SocketStreamHandle.h4
-rw-r--r--WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp34
-rw-r--r--WebCore/platform/network/mac/AuthenticationChallenge.h1
-rw-r--r--WebCore/platform/network/mac/AuthenticationMac.mm14
-rw-r--r--WebCore/platform/network/mac/ResourceHandleMac.mm2
-rw-r--r--WebCore/platform/network/mac/ResourceResponseMac.mm6
-rw-r--r--WebCore/platform/network/qt/AuthenticationChallenge.h5
-rw-r--r--WebCore/platform/network/qt/QNetworkReplyHandler.cpp176
-rw-r--r--WebCore/platform/network/qt/QNetworkReplyHandler.h16
-rw-r--r--WebCore/platform/network/qt/QtNAMThreadSafeProxy.cpp190
-rw-r--r--WebCore/platform/network/qt/QtNAMThreadSafeProxy.h186
-rw-r--r--WebCore/platform/network/qt/ResourceHandleQt.cpp20
-rw-r--r--WebCore/platform/network/soup/ResourceHandleSoup.cpp44
-rw-r--r--WebCore/platform/network/soup/cache/soup-http-input-stream.c1
-rw-r--r--WebCore/platform/network/soup/cache/soup-request-http.c85
-rw-r--r--WebCore/platform/network/soup/cache/webkit/soup-cache.c52
24 files changed, 757 insertions, 178 deletions
diff --git a/WebCore/platform/network/ResourceRequestBase.cpp b/WebCore/platform/network/ResourceRequestBase.cpp
index 5312007..ae8316a 100644
--- a/WebCore/platform/network/ResourceRequestBase.cpp
+++ b/WebCore/platform/network/ResourceRequestBase.cpp
@@ -234,6 +234,16 @@ void ResourceRequestBase::setHTTPHeaderField(const char* name, const String& val
setHTTPHeaderField(AtomicString(name), value);
}
+void ResourceRequestBase::clearHTTPAuthorization()
+{
+ updateResourceRequest();
+
+ m_httpHeaderFields.remove("Authorization");
+
+ if (url().protocolInHTTPFamily())
+ m_platformRequestUpdated = false;
+}
+
void ResourceRequestBase::clearHTTPReferrer()
{
updateResourceRequest();
diff --git a/WebCore/platform/network/ResourceRequestBase.h b/WebCore/platform/network/ResourceRequestBase.h
index 33a184e..5cb7ee3 100644
--- a/WebCore/platform/network/ResourceRequestBase.h
+++ b/WebCore/platform/network/ResourceRequestBase.h
@@ -100,6 +100,8 @@ namespace WebCore {
void addHTTPHeaderField(const AtomicString& name, const String& value);
void addHTTPHeaderFields(const HTTPHeaderMap& headerFields);
+ void clearHTTPAuthorization();
+
String httpContentType() const { return httpHeaderField("Content-Type"); }
void setHTTPContentType(const String& httpContentType) { setHTTPHeaderField("Content-Type", httpContentType); }
diff --git a/WebCore/platform/network/SocketStreamErrorBase.cpp b/WebCore/platform/network/SocketStreamErrorBase.cpp
index 72fb44c..bbb5d55 100644
--- a/WebCore/platform/network/SocketStreamErrorBase.cpp
+++ b/WebCore/platform/network/SocketStreamErrorBase.cpp
@@ -42,7 +42,22 @@ SocketStreamError SocketStreamErrorBase::copy() const
bool SocketStreamErrorBase::compare(const SocketStreamError& a, const SocketStreamError& b)
{
- return a.errorCode() == b.errorCode();
+ if (a.isNull() && b.isNull())
+ return true;
+
+ if (a.isNull() || b.isNull())
+ return false;
+
+ if (a.errorCode() != b.errorCode())
+ return false;
+
+ if (a.failingURL() != b.failingURL())
+ return false;
+
+ if (a.localizedDescription() != b.localizedDescription())
+ return false;
+
+ return true;
}
} // namespace WebCore
diff --git a/WebCore/platform/network/SocketStreamErrorBase.h b/WebCore/platform/network/SocketStreamErrorBase.h
index b7ca35b..e6cc567 100644
--- a/WebCore/platform/network/SocketStreamErrorBase.h
+++ b/WebCore/platform/network/SocketStreamErrorBase.h
@@ -32,6 +32,8 @@
#ifndef SocketStreamErrorBase_h
#define SocketStreamErrorBase_h
+#include "PlatformString.h"
+
namespace WebCore {
class SocketStreamError;
@@ -44,6 +46,8 @@ namespace WebCore {
bool isNull() const { return m_isNull; }
int errorCode() const { return m_errorCode; }
+ const String& failingURL() const { return m_failingURL; }
+ const String& localizedDescription() const { return m_localizedDescription; }
static bool compare(const SocketStreamError&, const SocketStreamError&);
@@ -60,7 +64,17 @@ namespace WebCore {
{
}
+ SocketStreamErrorBase(int errorCode, const String& failingURL, const String& localizedDescription)
+ : m_errorCode(errorCode)
+ , m_failingURL(failingURL)
+ , m_localizedDescription(localizedDescription)
+ , m_isNull(false)
+ {
+ }
+
int m_errorCode;
+ String m_failingURL;
+ String m_localizedDescription;
bool m_isNull;
};
diff --git a/WebCore/platform/network/cf/DNSCFNet.cpp b/WebCore/platform/network/cf/DNSCFNet.cpp
index fbceb7d..166abbf 100644
--- a/WebCore/platform/network/cf/DNSCFNet.cpp
+++ b/WebCore/platform/network/cf/DNSCFNet.cpp
@@ -27,6 +27,7 @@
#include "config.h"
#include "DNS.h"
+#include "KURL.h"
#include "Timer.h"
#include <wtf/HashSet.h>
#include <wtf/RetainPtr.h>
@@ -37,6 +38,10 @@
#include "LoaderRunLoopCF.h"
#endif
+#if defined(BUILDING_ON_LEOPARD)
+#include <SystemConfiguration/SystemConfiguration.h>
+#endif
+
#ifdef BUILDING_ON_TIGER
// This function is available on Tiger, but not declared in the CFRunLoop.h header on Tiger.
extern "C" CFRunLoopRef CFRunLoopGetMain();
@@ -62,6 +67,37 @@ const int maxRequestsToQueue = 64;
// If there were queued names that couldn't be sent simultaneously, check the state of resolvers after this delay.
const double retryResolvingInSeconds = 0.1;
+static bool proxyIsEnabledInSystemPreferences()
+{
+ // Don't do DNS prefetch if proxies are involved. For many proxy types, the user agent is never exposed
+ // to the IP address during normal operation. Querying an internal DNS server may not help performance,
+ // as it doesn't necessarily look up the actual external IP. Also, if DNS returns a fake internal address,
+ // local caches may keep it even after re-connecting to another network.
+
+#if !defined(BUILDING_ON_LEOPARD)
+ RetainPtr<CFDictionaryRef> proxySettings(AdoptCF, CFNetworkCopySystemProxySettings());
+#else
+ RetainPtr<CFDictionaryRef> proxySettings(AdoptCF, SCDynamicStoreCopyProxies(0));
+#endif
+ if (!proxySettings)
+ return false;
+
+ static CFURLRef httpCFURL = KURL(ParsedURLString, "http://example.com/").createCFURL();
+ static CFURLRef httpsCFURL = KURL(ParsedURLString, "https://example.com/").createCFURL();
+
+ RetainPtr<CFArrayRef> httpProxyArray(AdoptCF, CFNetworkCopyProxiesForURL(httpCFURL, proxySettings.get()));
+ RetainPtr<CFArrayRef> httpsProxyArray(AdoptCF, CFNetworkCopyProxiesForURL(httpsCFURL, proxySettings.get()));
+
+ CFIndex httpProxyCount = CFArrayGetCount(httpProxyArray.get());
+ CFIndex httpsProxyCount = CFArrayGetCount(httpsProxyArray.get());
+ if (httpProxyCount == 1 && CFEqual(CFDictionaryGetValue(static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(httpProxyArray.get(), 0)), kCFProxyTypeKey), kCFProxyTypeNone))
+ httpProxyCount = 0;
+ if (httpsProxyCount == 1 && CFEqual(CFDictionaryGetValue(static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(httpsProxyArray.get(), 0)), kCFProxyTypeKey), kCFProxyTypeNone))
+ httpsProxyCount = 0;
+
+ return httpProxyCount || httpsProxyCount;
+}
+
class DNSResolveQueue : public TimerBase {
public:
static DNSResolveQueue& shared();
@@ -92,6 +128,9 @@ void DNSResolveQueue::add(const String& name)
{
// If there are no names queued, and few enough are in flight, resolve immediately (the mouse may be over a link).
if (!m_names.size()) {
+ if (proxyIsEnabledInSystemPreferences())
+ return;
+
if (atomicIncrement(&m_requestsInFlight) <= namesToResolveImmediately) {
resolve(name);
return;
@@ -115,6 +154,11 @@ void DNSResolveQueue::decrementRequestCount()
void DNSResolveQueue::fired()
{
+ if (proxyIsEnabledInSystemPreferences()) {
+ m_names.clear();
+ return;
+ }
+
int requestsAllowed = maxSimultaneousRequests - m_requestsInFlight;
for (; !m_names.isEmpty() && requestsAllowed > 0; --requestsAllowed) {
diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
index e48bd2d..f0773d2 100644
--- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
+++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
@@ -481,6 +481,8 @@ void ResourceHandle::willSendRequest(ResourceRequest& request, const ResourceRes
d->m_pass = url.pass();
d->m_lastHTTPMethod = request.httpMethod();
request.removeCredentials();
+ if (!protocolHostAndPortAreEqual(request.url(), redirectResponse.url()))
+ request.clearHTTPAuthorization();
client()->willSendRequest(this, request, redirectResponse);
}
diff --git a/WebCore/platform/network/cf/ResourceResponseCFNet.cpp b/WebCore/platform/network/cf/ResourceResponseCFNet.cpp
index 469e5ad..9a83add 100644
--- a/WebCore/platform/network/cf/ResourceResponseCFNet.cpp
+++ b/WebCore/platform/network/cf/ResourceResponseCFNet.cpp
@@ -79,6 +79,11 @@ void ResourceResponse::platformLazyInit()
m_expectedContentLength = CFURLResponseGetExpectedContentLength(m_cfResponse.get());
m_textEncodingName = CFURLResponseGetTextEncodingName(m_cfResponse.get());
+ // Workaround for <rdar://problem/8757088>, can be removed once that is fixed.
+ unsigned textEncodingNameLength = m_textEncodingName.length();
+ if (textEncodingNameLength >= 2 && m_textEncodingName[0U] == '"' && m_textEncodingName[textEncodingNameLength - 1] == '"')
+ m_textEncodingName = m_textEncodingName.substring(1, textEncodingNameLength - 2);
+
m_lastModifiedDate = toTimeT(CFURLResponseGetLastModifiedDate(m_cfResponse.get()));
RetainPtr<CFStringRef> suggestedFilename(AdoptCF, CFURLResponseCopySuggestedFilename(m_cfResponse.get()));
diff --git a/WebCore/platform/network/cf/SocketStreamError.h b/WebCore/platform/network/cf/SocketStreamError.h
index 6a0b441..5a0ca07 100644
--- a/WebCore/platform/network/cf/SocketStreamError.h
+++ b/WebCore/platform/network/cf/SocketStreamError.h
@@ -42,7 +42,10 @@ public:
: SocketStreamErrorBase(errorCode)
{
}
-
+ SocketStreamError(int errorCode, const String& failingURL, const String& localizedDescription)
+ : SocketStreamErrorBase(errorCode, failingURL, localizedDescription)
+ {
+ }
};
} // namespace WebCore
diff --git a/WebCore/platform/network/cf/SocketStreamHandle.h b/WebCore/platform/network/cf/SocketStreamHandle.h
index 41d543a..df1d4a3 100644
--- a/WebCore/platform/network/cf/SocketStreamHandle.h
+++ b/WebCore/platform/network/cf/SocketStreamHandle.h
@@ -84,6 +84,10 @@ private:
void readStreamCallback(CFStreamEventType);
void writeStreamCallback(CFStreamEventType);
+#ifndef BUILDING_ON_TIGER
+ void reportErrorToClient(CFErrorRef);
+#endif
+
// No authentication for streams per se, but proxy may ask for credentials.
virtual void receivedCredential(const AuthenticationChallenge&, const Credential&);
virtual void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&);
diff --git a/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp b/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp
index 24b5835..821b1ca 100644
--- a/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp
+++ b/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp
@@ -39,6 +39,7 @@
#include "SocketStreamError.h"
#include "SocketStreamHandleClient.h"
#include <wtf/MainThread.h>
+#include <wtf/text/StringConcatenate.h>
#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
#include <SystemConfiguration/SystemConfiguration.h>
@@ -530,8 +531,13 @@ void SocketStreamHandle::readStreamCallback(CFStreamEventType type)
ASSERT_NOT_REACHED();
break;
case kCFStreamEventErrorOccurred: {
+#ifndef BUILDING_ON_TIGER
+ RetainPtr<CFErrorRef> error(AdoptCF, CFReadStreamCopyError(m_readStream.get()));
+ reportErrorToClient(error.get());
+#else
CFStreamError error = CFReadStreamGetError(m_readStream.get());
m_client->didFail(this, SocketStreamError(error.error)); // FIXME: Provide a sensible error.
+#endif
break;
}
case kCFStreamEventEndEncountered:
@@ -574,8 +580,13 @@ void SocketStreamHandle::writeStreamCallback(CFStreamEventType type)
break;
}
case kCFStreamEventErrorOccurred: {
+#ifndef BUILDING_ON_TIGER
+ RetainPtr<CFErrorRef> error(AdoptCF, CFWriteStreamCopyError(m_writeStream.get()));
+ reportErrorToClient(error.get());
+#else
CFStreamError error = CFWriteStreamGetError(m_writeStream.get());
m_client->didFail(this, SocketStreamError(error.error)); // FIXME: Provide a sensible error.
+#endif
break;
}
case kCFStreamEventEndEncountered:
@@ -584,6 +595,29 @@ void SocketStreamHandle::writeStreamCallback(CFStreamEventType type)
}
}
+#ifndef BUILDING_ON_TIGER
+void SocketStreamHandle::reportErrorToClient(CFErrorRef error)
+{
+ CFIndex errorCode = CFErrorGetCode(error);
+ String description;
+
+#if PLATFORM(MAC)
+ if (CFEqual(CFErrorGetDomain(error), kCFErrorDomainOSStatus)) {
+ const char* descriptionOSStatus = GetMacOSStatusCommentString(static_cast<OSStatus>(errorCode));
+ if (descriptionOSStatus && descriptionOSStatus[0] != '\0')
+ description = makeString("OSStatus Error ", String::number(errorCode), ": ", descriptionOSStatus);
+ }
+#endif
+
+ if (description.isNull()) {
+ RetainPtr<CFStringRef> descriptionCF(AdoptCF, CFErrorCopyDescription(error));
+ description = String(descriptionCF.get());
+ }
+
+ m_client->didFail(this, SocketStreamError(static_cast<int>(errorCode), m_url.string(), description));
+}
+#endif // BUILDING_ON_TIGER
+
SocketStreamHandle::~SocketStreamHandle()
{
LOG(Network, "SocketStreamHandle %p dtor", this);
diff --git a/WebCore/platform/network/mac/AuthenticationChallenge.h b/WebCore/platform/network/mac/AuthenticationChallenge.h
index d74a92c..8f60933 100644
--- a/WebCore/platform/network/mac/AuthenticationChallenge.h
+++ b/WebCore/platform/network/mac/AuthenticationChallenge.h
@@ -49,6 +49,7 @@ public:
NSURLAuthenticationChallenge *nsURLAuthenticationChallenge() const { return m_nsChallenge.get(); }
void setAuthenticationClient(AuthenticationClient*); // Changes sender to one that invokes client methods.
+ AuthenticationClient* authenticationClient() const;
private:
friend class AuthenticationChallengeBase;
diff --git a/WebCore/platform/network/mac/AuthenticationMac.mm b/WebCore/platform/network/mac/AuthenticationMac.mm
index 1c05917..cdf643f 100644
--- a/WebCore/platform/network/mac/AuthenticationMac.mm
+++ b/WebCore/platform/network/mac/AuthenticationMac.mm
@@ -41,6 +41,7 @@ using namespace WebCore;
AuthenticationClient* m_client;
}
- (id)initWithAuthenticationClient:(AuthenticationClient*)client;
+- (AuthenticationClient*)client;
- (void)detachClient;
@end
@@ -55,6 +56,11 @@ using namespace WebCore;
return self;
}
+- (AuthenticationClient*)client
+{
+ return m_client;
+}
+
- (void)detachClient
{
m_client = 0;
@@ -123,6 +129,14 @@ void AuthenticationChallenge::setAuthenticationClient(AuthenticationClient* clie
}
}
+AuthenticationClient* AuthenticationChallenge::authenticationClient() const
+{
+ if ([m_sender.get() isMemberOfClass:[WebCoreAuthenticationClientAsChallengeSender class]])
+ return [static_cast<WebCoreAuthenticationClientAsChallengeSender*>(m_sender.get()) client];
+
+ return 0;
+}
+
bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b)
{
if (a.sender() != b.sender())
diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm
index daec366..caa33d7 100644
--- a/WebCore/platform/network/mac/ResourceHandleMac.mm
+++ b/WebCore/platform/network/mac/ResourceHandleMac.mm
@@ -552,6 +552,8 @@ void ResourceHandle::willSendRequest(ResourceRequest& request, const ResourceRes
d->m_pass = url.pass();
d->m_lastHTTPMethod = request.httpMethod();
request.removeCredentials();
+ if (!protocolHostAndPortAreEqual(request.url(), redirectResponse.url()))
+ request.clearHTTPAuthorization();
client()->willSendRequest(this, request, redirectResponse);
}
diff --git a/WebCore/platform/network/mac/ResourceResponseMac.mm b/WebCore/platform/network/mac/ResourceResponseMac.mm
index e1f1790..4376b64 100644
--- a/WebCore/platform/network/mac/ResourceResponseMac.mm
+++ b/WebCore/platform/network/mac/ResourceResponseMac.mm
@@ -74,6 +74,12 @@ void ResourceResponse::platformLazyInit()
m_mimeType = [m_nsResponse.get() MIMEType];
m_expectedContentLength = [m_nsResponse.get() expectedContentLength];
m_textEncodingName = [m_nsResponse.get() textEncodingName];
+
+ // Workaround for <rdar://problem/8757088>, can be removed once that is fixed.
+ unsigned textEncodingNameLength = m_textEncodingName.length();
+ if (textEncodingNameLength >= 2 && m_textEncodingName[0U] == '"' && m_textEncodingName[textEncodingNameLength - 1] == '"')
+ m_textEncodingName = m_textEncodingName.substring(1, textEncodingNameLength - 2);
+
m_suggestedFilename = [m_nsResponse.get() suggestedFilename];
if ([m_nsResponse.get() isKindOfClass:[NSHTTPURLResponse class]]) {
diff --git a/WebCore/platform/network/qt/AuthenticationChallenge.h b/WebCore/platform/network/qt/AuthenticationChallenge.h
index 753ac6f..ebbc0cd 100644
--- a/WebCore/platform/network/qt/AuthenticationChallenge.h
+++ b/WebCore/platform/network/qt/AuthenticationChallenge.h
@@ -29,6 +29,8 @@
namespace WebCore {
+class AuthenticationClient;
+
class AuthenticationChallenge : public AuthenticationChallengeBase {
public:
AuthenticationChallenge()
@@ -39,6 +41,9 @@ public:
: AuthenticationChallengeBase(protectionSpace, proposedCredential, previousFailureCount, response, error)
{
}
+
+ AuthenticationClient* authenticationClient() const { return 0; } // FIXME: Implement!
+
};
}
diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
index 01e624e..2ff7d9c 100644
--- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
+++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
@@ -23,6 +23,7 @@
#include "HTTPParsers.h"
#include "MIMETypeRegistry.h"
+#include "QtNAMThreadSafeProxy.h"
#include "ResourceHandle.h"
#include "ResourceHandleClient.h"
#include "ResourceHandleInternal.h"
@@ -46,7 +47,7 @@
// 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
+#define SIGNAL_CONN Qt::AutoConnection
#else
#define SIGNAL_CONN Qt::QueuedConnection
#endif
@@ -56,8 +57,9 @@ static const int gMaxRecursionLimit = 10;
namespace WebCore {
// Take a deep copy of the FormDataElement
-FormDataIODevice::FormDataIODevice(FormData* data)
- : m_formElements(data ? data->elements() : Vector<FormDataElement>())
+FormDataIODevice::FormDataIODevice(FormData* data, QObject* parent)
+ : QIODevice(parent)
+ , m_formElements(data ? data->elements() : Vector<FormDataElement>())
, m_currentFile(0)
, m_currentDelta(0)
, m_fileSize(0)
@@ -184,7 +186,7 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load
, m_resourceHandle(handle)
, m_redirected(false)
, m_responseSent(false)
- , m_responseDataSent(false)
+ , m_responseContainsData(false)
, m_loadMode(loadMode)
, m_shouldStart(true)
, m_shouldFinish(false)
@@ -192,6 +194,9 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load
, m_shouldForwardData(false)
, m_redirectionTries(gMaxRecursionLimit)
{
+ // Make this a direct function call once we require 4.6.1+.
+ connect(this, SIGNAL(processQueuedItems()), this, SLOT(sendQueuedItems()), SIGNAL_CONN);
+
const ResourceRequest &r = m_resourceHandle->firstRequest();
if (r.httpMethod() == "GET")
@@ -222,6 +227,12 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load
start();
}
+QNetworkReplyHandler::~QNetworkReplyHandler()
+{
+ if (m_reply)
+ m_reply->deleteLater();
+}
+
void QNetworkReplyHandler::setLoadMode(LoadMode mode)
{
// https://bugs.webkit.org/show_bug.cgi?id=26556
@@ -231,9 +242,13 @@ void QNetworkReplyHandler::setLoadMode(LoadMode mode)
case LoadNormal:
m_loadMode = LoadResuming;
emit processQueuedItems();
+ // Restart forwarding only after processQueuedItems to make sure
+ // our buffered data was handled before any incoming data.
+ m_reply->setForwardingDefered(false);
break;
case LoadDeferred:
m_loadMode = LoadDeferred;
+ m_reply->setForwardingDefered(true);
break;
case LoadResuming:
Q_ASSERT(0); // should never happen
@@ -245,31 +260,30 @@ void QNetworkReplyHandler::abort()
{
m_resourceHandle = 0;
if (m_reply) {
- QNetworkReply* reply = release();
+ QtNetworkReplyThreadSafeProxy* reply = release();
reply->abort();
reply->deleteLater();
}
deleteLater();
}
-QNetworkReply* QNetworkReplyHandler::release()
+QtNetworkReplyThreadSafeProxy* QNetworkReplyHandler::release()
{
- QNetworkReply* reply = m_reply;
+ QtNetworkReplyThreadSafeProxy* 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;
}
return reply;
}
-static bool ignoreHttpError(QNetworkReply* reply, bool receivedData)
+static bool ignoreHttpError(QtNetworkReplyThreadSafeProxy* reply, bool receivedData)
{
- int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ int httpStatusCode = reply->httpStatusCode();
if (httpStatusCode == 401 || httpStatusCode == 407)
return true;
@@ -300,29 +314,33 @@ void QNetworkReplyHandler::finish()
return;
}
- QNetworkReply* oldReply = m_reply;
+ 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->httpStatusCode();
- if (m_redirected) {
- resetState();
- start();
- } else if (!m_reply->error() || ignoreHttpError(m_reply, m_responseDataSent)) {
- client->didFinishLoading(m_resourceHandle, 0);
+ if (httpStatusCode) {
+ ResourceError error("HTTP", httpStatusCode, url.toString(), QString::fromAscii(m_reply->httpReasonPhrase()));
+ 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 {
- 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;
}
+ resetState();
+ start();
}
-
- oldReply->deleteLater();
- if (oldReply == m_reply)
- m_reply = 0;
}
void QNetworkReplyHandler::sendResponseIfNeeded()
@@ -331,7 +349,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded()
if (m_shouldSendResponse)
return;
- if (m_reply->error() && !ignoreHttpError(m_reply, m_responseDataSent))
+ if (m_reply->error() && !ignoreHttpError(m_reply, m_responseContainsData))
return;
if (m_responseSent || !m_resourceHandle)
@@ -342,7 +360,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded()
if (!client)
return;
- WTF::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
+ WTF::String contentType = m_reply->contentTypeHeader();
WTF::String encoding = extractCharsetFromMediaType(contentType);
WTF::String mimeType = extractMIMETypeFromMediaType(contentType);
@@ -353,7 +371,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded()
KURL url(m_reply->url());
ResourceResponse response(url, mimeType.lower(),
- m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(),
+ m_reply->contentLengthHeader(),
encoding, String());
if (url.isLocalFile()) {
@@ -362,10 +380,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_reply->httpStatusCode();
if (url.protocolInHTTPFamily()) {
- String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->rawHeader("Content-Disposition")));
+ String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->contentDispositionHeader()));
if (!suggestedFilename.isEmpty())
response.setSuggestedFilename(suggestedFilename);
@@ -373,21 +391,15 @@ void QNetworkReplyHandler::sendResponseIfNeeded()
response.setSuggestedFilename(url.lastPathComponent());
response.setHTTPStatusCode(statusCode);
- response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData());
+ response.setHTTPStatusText(m_reply->httpReasonPhrase().constData());
// Add remaining headers.
-#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
- foreach (const QNetworkReply::RawHeaderPair& pair, m_reply->rawHeaderPairs()) {
+ foreach (const QtNetworkReplyThreadSafeProxy::RawHeaderPair& pair, m_reply->rawHeaderPairs()) {
response.setHTTPHeaderField(QString::fromAscii(pair.first), QString::fromAscii(pair.second));
}
-#else
- foreach (const QByteArray& headerName, m_reply->rawHeaderList()) {
- response.setHTTPHeaderField(QString::fromAscii(headerName), QString::fromAscii(m_reply->rawHeader(headerName)));
- }
-#endif
}
- QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
+ QUrl redirection = m_reply->redirectionTarget();
if (redirection.isValid()) {
QUrl newUrl = m_reply->url().resolved(redirection);
@@ -432,11 +444,16 @@ void QNetworkReplyHandler::sendResponseIfNeeded()
client->didReceiveResponse(m_resourceHandle, response);
}
-void QNetworkReplyHandler::forwardData()
+void QNetworkReplyHandler::forwardData(const QByteArray &data)
{
m_shouldForwardData = (m_loadMode != LoadNormal);
- if (m_shouldForwardData)
+ if (m_shouldForwardData) {
+ m_bufferedData += data;
return;
+ }
+
+ if (!data.isEmpty())
+ m_responseContainsData = true;
sendResponseIfNeeded();
@@ -447,16 +464,12 @@ void QNetworkReplyHandler::forwardData()
if (!m_resourceHandle)
return;
- QByteArray data = m_reply->read(m_reply->bytesAvailable());
-
ResourceHandleClient* client = m_resourceHandle->client();
if (!client)
return;
- if (!data.isEmpty()) {
- m_responseDataSent = true;
+ if (!data.isEmpty())
client->didReceiveData(m_resourceHandle, data.constData(), data.length(), data.length() /*FixMe*/);
- }
}
void QNetworkReplyHandler::uploadProgress(qint64 bytesSent, qint64 bytesTotal)
@@ -493,41 +506,53 @@ void QNetworkReplyHandler::start()
&& (!url.toLocalFile().isEmpty() || url.scheme() == QLatin1String("data")))
m_method = QNetworkAccessManager::GetOperation;
+ m_reply = new QtNetworkReplyThreadSafeProxy(manager);
+ 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(dataReceived(const QByteArray&)), this, SLOT(forwardData(const QByteArray&)), SIGNAL_CONN);
+
+ if (m_resourceHandle->firstRequest().reportUploadProgress())
+ connect(m_reply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64)), SIGNAL_CONN);
+
switch (m_method) {
case QNetworkAccessManager::GetOperation:
- m_reply = manager->get(m_request);
+ m_reply->get(m_request);
break;
case QNetworkAccessManager::PostOperation: {
- FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody());
+ FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody(), this);
// 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);
+ m_reply->post(m_request, postDevice);
break;
}
case QNetworkAccessManager::HeadOperation:
- m_reply = manager->head(m_request);
+ m_reply->head(m_request);
break;
case QNetworkAccessManager::PutOperation: {
- FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody());
+ FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody(), this);
// 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);
+ m_reply->put(m_request, putDevice);
break;
}
case QNetworkAccessManager::DeleteOperation: {
- m_reply = manager->deleteResource(m_request);
+ m_reply->deleteResource(m_request);
break;
}
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
case QNetworkAccessManager::CustomOperation:
- m_reply = manager->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data());
+ m_reply->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data());
break;
#endif
case QNetworkAccessManager::UnknownOperation: {
+ m_reply->deleteLater();
m_reply = 0;
ResourceHandleClient* client = m_resourceHandle->client();
if (client) {
@@ -539,36 +564,13 @@ void QNetworkReplyHandler::start()
return;
}
}
-
- m_reply->setParent(this);
-
- 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);
- }
-
- // Make this a direct function call once we require 4.6.1+.
- connect(this, SIGNAL(processQueuedItems()),
- this, SLOT(sendQueuedItems()), SIGNAL_CONN);
}
void QNetworkReplyHandler::resetState()
{
m_redirected = false;
m_responseSent = false;
- m_responseDataSent = false;
+ m_responseContainsData = false;
m_shouldStart = true;
m_shouldFinish = false;
m_shouldSendResponse = false;
@@ -587,8 +589,10 @@ void QNetworkReplyHandler::sendQueuedItems()
if (m_shouldSendResponse)
sendResponseIfNeeded();
- if (m_shouldForwardData)
- forwardData();
+ if (m_shouldForwardData) {
+ forwardData(m_bufferedData);
+ m_bufferedData.clear();
+ }
if (m_shouldFinish)
finish();
diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.h b/WebCore/platform/network/qt/QNetworkReplyHandler.h
index 884a1a4..11638b3 100644
--- a/WebCore/platform/network/qt/QNetworkReplyHandler.h
+++ b/WebCore/platform/network/qt/QNetworkReplyHandler.h
@@ -23,6 +23,7 @@
#include <QNetworkRequest>
#include <QNetworkAccessManager>
+#include <QNetworkReply>
#include "FormData.h"
@@ -34,6 +35,7 @@ QT_END_NAMESPACE
namespace WebCore {
class ResourceHandle;
+class QtNetworkReplyThreadSafeProxy;
class QNetworkReplyHandler : public QObject
{
@@ -46,13 +48,12 @@ public:
};
QNetworkReplyHandler(ResourceHandle *handle, LoadMode);
+ ~QNetworkReplyHandler();
void setLoadMode(LoadMode);
- QNetworkReply* reply() const { return m_reply; }
-
void abort();
- QNetworkReply* release();
+ QtNetworkReplyThreadSafeProxy* release();
signals:
void processQueuedItems();
@@ -60,7 +61,7 @@ signals:
private slots:
void finish();
void sendResponseIfNeeded();
- void forwardData();
+ void forwardData(const QByteArray &data);
void sendQueuedItems();
void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
@@ -69,11 +70,11 @@ private:
void resetState();
String httpMethod() const;
- QNetworkReply* m_reply;
+ QtNetworkReplyThreadSafeProxy* m_reply;
ResourceHandle* m_resourceHandle;
bool m_redirected;
bool m_responseSent;
- bool m_responseDataSent;
+ bool m_responseContainsData;
LoadMode m_loadMode;
QNetworkAccessManager::Operation m_method;
QNetworkRequest m_request;
@@ -84,6 +85,7 @@ private:
bool m_shouldSendResponse;
bool m_shouldForwardData;
int m_redirectionTries;
+ QByteArray m_bufferedData;
};
// Self destructing QIODevice for FormData
@@ -94,7 +96,7 @@ private:
class FormDataIODevice : public QIODevice {
Q_OBJECT
public:
- FormDataIODevice(FormData*);
+ FormDataIODevice(FormData*, QObject* parent = 0);
~FormDataIODevice();
bool isSequential() const;
diff --git a/WebCore/platform/network/qt/QtNAMThreadSafeProxy.cpp b/WebCore/platform/network/qt/QtNAMThreadSafeProxy.cpp
new file mode 100644
index 0000000..0caeb05
--- /dev/null
+++ b/WebCore/platform/network/qt/QtNAMThreadSafeProxy.cpp
@@ -0,0 +1,190 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include "config.h"
+#include "QtNAMThreadSafeProxy.h"
+
+#include "Assertions.h"
+#include <QAbstractNetworkCache>
+#include <QNetworkAccessManager>
+#include <QNetworkCookieJar>
+#include <QStringList>
+
+// Use unused variables to be able to call qRegisterMetaType statically.
+static int dummyStaticVar1 = qRegisterMetaType<QFutureInterface<bool> >("QFutureInterface<bool>");
+static int dummyStaticVar2 = qRegisterMetaType<QFutureInterface<QList<QNetworkCookie> > >("QFutureInterface<QList<QNetworkCookie> >");
+
+namespace WebCore {
+
+QtNAMThreadSafeProxy::QtNAMThreadSafeProxy(QNetworkAccessManager *manager)
+ : m_manager(manager)
+{
+ moveToThread(manager->thread());
+
+ connect(this, SIGNAL(localSetCookiesRequested(const QUrl&, const QString&)), SLOT(localSetCookies(const QUrl&, const QString&)));
+ connect(this, SIGNAL(localCookiesForUrlRequested(QFutureInterface<QList<QNetworkCookie> >, const QUrl&)), SLOT(localCookiesForUrl(QFutureInterface<QList<QNetworkCookie> >, const QUrl&)));
+ connect(this, SIGNAL(localWillLoadFromCacheRequested(QFutureInterface<bool>, const QUrl&)), SLOT(localWillLoadFromCache(QFutureInterface<bool>, const QUrl&)));
+}
+
+void QtNAMThreadSafeProxy::localSetCookies(const QUrl& url, const QString& cookies)
+{
+ QList<QNetworkCookie> cookieList = QNetworkCookie::parseCookies(cookies.toAscii());
+ QList<QNetworkCookie>::Iterator it = cookieList.begin();
+ while (it != cookieList.end()) {
+ if (it->isHttpOnly())
+ it = cookieList.erase(it);
+ else
+ ++it;
+ }
+ m_manager->cookieJar()->setCookiesFromUrl(cookieList, url);
+}
+
+void QtNAMThreadSafeProxy::localCookiesForUrl(QFutureInterface<QList<QNetworkCookie> > fi, const QUrl& url)
+{
+ fi.reportResult(m_manager->cookieJar()->cookiesForUrl(url));
+ fi.reportFinished();
+}
+
+void QtNAMThreadSafeProxy::localWillLoadFromCache(QFutureInterface<bool> fi, const QUrl& url)
+{
+ bool retVal = false;
+ if (m_manager->cache())
+ retVal = m_manager->cache()->metaData(url).isValid();
+
+ fi.reportFinished(&retVal);
+}
+
+QtNetworkReplyThreadSafeProxy::QtNetworkReplyThreadSafeProxy(QNetworkAccessManager *manager)
+ : m_manager(manager)
+ , m_reply(0)
+ , m_forwardingDefered(false)
+ , m_contentLengthHeader(0)
+ , m_error(QNetworkReply::NoError)
+ , m_httpStatusCode(0)
+{
+ moveToThread(manager->thread());
+
+ // This might be unnecessarily heavy to do for each request while we could have the same wrapper for the manager instead
+ connect(this, SIGNAL(localGetRequested(const QNetworkRequest&)), SLOT(localGet(const QNetworkRequest&)));
+ connect(this, SIGNAL(localPostRequested(const QNetworkRequest&, QIODevice*)), SLOT(localPost(const QNetworkRequest&, QIODevice*)));
+ connect(this, SIGNAL(localHeadRequested(const QNetworkRequest&)), SLOT(localHead(const QNetworkRequest&)));
+ connect(this, SIGNAL(localPutRequested(const QNetworkRequest&, QIODevice*)), SLOT(localPut(const QNetworkRequest&, QIODevice*)));
+ connect(this, SIGNAL(localDeleteResourceRequested(const QNetworkRequest&)), SLOT(localDeleteResource(const QNetworkRequest&)));
+ connect(this, SIGNAL(localCustomRequestRequested(const QNetworkRequest&, const QByteArray&)), SLOT(localCustomRequest(const QNetworkRequest&, const QByteArray&)));
+ connect(this, SIGNAL(localAbortRequested()), SLOT(localAbort()));
+ connect(this, SIGNAL(localSetForwardingDeferedRequested(bool)), SLOT(localSetForwardingDefered(bool)));
+}
+
+QtNetworkReplyThreadSafeProxy::~QtNetworkReplyThreadSafeProxy()
+{
+ delete m_reply;
+}
+
+void QtNetworkReplyThreadSafeProxy::localGet(const QNetworkRequest& request)
+{
+ localSetReply(m_manager->get(request));
+}
+
+void QtNetworkReplyThreadSafeProxy::localPost(const QNetworkRequest& request, QIODevice* data)
+{
+ localSetReply(m_manager->post(request, data));
+}
+
+void QtNetworkReplyThreadSafeProxy::localHead(const QNetworkRequest& request)
+{
+ localSetReply(m_manager->head(request));
+}
+
+void QtNetworkReplyThreadSafeProxy::localPut(const QNetworkRequest& request, QIODevice* data)
+{
+ localSetReply(m_manager->put(request, data));
+}
+
+void QtNetworkReplyThreadSafeProxy::localDeleteResource(const QNetworkRequest& request)
+{
+ localSetReply(m_manager->deleteResource(request));
+}
+
+void QtNetworkReplyThreadSafeProxy::localCustomRequest(const QNetworkRequest& request, const QByteArray& verb)
+{
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ localSetReply(m_manager->sendCustomRequest(request, verb));
+#endif
+}
+
+void QtNetworkReplyThreadSafeProxy::localAbort()
+{
+ if (m_reply)
+ m_reply->abort();
+}
+
+void QtNetworkReplyThreadSafeProxy::localForwardData()
+{
+ if (m_reply->bytesAvailable()) {
+ QByteArray data = m_reply->read(m_reply->bytesAvailable());
+ emit dataReceived(data);
+ }
+}
+
+void QtNetworkReplyThreadSafeProxy::localSetForwardingDefered(bool forwardingDefered)
+{
+ if (m_forwardingDefered && !forwardingDefered)
+ localForwardData();
+ m_forwardingDefered = forwardingDefered;
+}
+
+void QtNetworkReplyThreadSafeProxy::localMirrorMembers()
+{
+ ASSERT(m_reply);
+ QMutexLocker lock(&m_mirroredMembersMutex);
+
+ m_contentDispositionHeader = m_reply->rawHeader("Content-Disposition");
+ m_contentLengthHeader = m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong();
+ m_contentTypeHeader = m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
+ m_error = m_reply->error();
+ m_errorString = m_reply->errorString();
+ m_httpReasonPhrase = m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray();
+ m_httpStatusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ m_url = m_reply->url();
+ m_redirectionTarget = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ m_rawHeaderPairs = m_reply->rawHeaderPairs();
+#else
+ m_rawHeaderPairs.clear();
+ foreach (const QByteArray& headerName, m_reply->rawHeaderList())
+ m_rawHeaderPairs.append(RawHeaderPair(headerName, m_reply->rawHeader(headerName)));
+#endif
+}
+
+void QtNetworkReplyThreadSafeProxy::localSetReply(QNetworkReply *reply)
+{
+ ASSERT(!m_reply);
+ m_reply = reply;
+ m_reply->setParent(0);
+ connect(m_reply, SIGNAL(readyRead()), this, SLOT(localForwardData()));
+ // Make sure localMirrorMembers() is called before the outward signal
+ connect(m_reply, SIGNAL(finished()), this, SLOT(localMirrorMembers()), Qt::DirectConnection);
+ connect(m_reply, SIGNAL(finished()), this, SIGNAL(finished()));
+ // Make sure localMirrorMembers() is called before the outward signal
+ connect(m_reply, SIGNAL(metaDataChanged()), this, SLOT(localMirrorMembers()), Qt::DirectConnection);
+ connect(m_reply, SIGNAL(metaDataChanged()), this, SIGNAL(metaDataChanged()));
+ connect(m_reply, SIGNAL(uploadProgress(qint64, qint64)), this, SIGNAL(uploadProgress(qint64, qint64)));
+}
+
+
+}
diff --git a/WebCore/platform/network/qt/QtNAMThreadSafeProxy.h b/WebCore/platform/network/qt/QtNAMThreadSafeProxy.h
new file mode 100644
index 0000000..3e0c189
--- /dev/null
+++ b/WebCore/platform/network/qt/QtNAMThreadSafeProxy.h
@@ -0,0 +1,186 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef QtNAMThreadSafeProxy_h
+#define QtNAMThreadSafeProxy_h
+
+#include <QFuture>
+#include <QMutex>
+#include <QNetworkCookie>
+#include <QNetworkReply>
+#include <QObject>
+
+class QNetworkAccessManager;
+class QNetworkRequest;
+class QUrl;
+
+namespace WebCore {
+
+class QtNAMThreadSafeProxy : public QObject {
+ Q_OBJECT
+public:
+ QtNAMThreadSafeProxy(QNetworkAccessManager *manager);
+
+ void setCookies(const QUrl& url, const QString& cookies)
+ {
+ emit localSetCookiesRequested(url, cookies);
+ }
+
+ QFuture<QList<QNetworkCookie> > cookiesForUrl(const QUrl& url)
+ {
+ QFutureInterface<QList<QNetworkCookie> > fi;
+ fi.reportStarted();
+ emit localCookiesForUrlRequested(fi, url);
+ return fi.future();
+ }
+
+ QFuture<bool> willLoadFromCache(const QUrl& url)
+ {
+ QFutureInterface<bool> fi;
+ fi.reportStarted();
+ emit localWillLoadFromCacheRequested(fi, url);
+ return fi.future();
+ }
+
+signals:
+ void localSetCookiesRequested(const QUrl& url, const QString& cookies);
+ void localCookiesForUrlRequested(QFutureInterface<QList<QNetworkCookie> > fi, const QUrl& url);
+ void localWillLoadFromCacheRequested(QFutureInterface<bool> fi, const QUrl& url);
+
+private slots:
+ void localSetCookies(const QUrl& url, const QString& cookies);
+ void localCookiesForUrl(QFutureInterface<QList<QNetworkCookie> > fi, const QUrl& url);
+ void localWillLoadFromCache(QFutureInterface<bool> fi, const QUrl& url);
+
+private:
+ QNetworkAccessManager* m_manager;
+};
+
+
+class QtNetworkReplyThreadSafeProxy : public QObject {
+ Q_OBJECT
+public:
+ typedef QPair<QByteArray, QByteArray> RawHeaderPair;
+ QtNetworkReplyThreadSafeProxy(QNetworkAccessManager *manager);
+ ~QtNetworkReplyThreadSafeProxy();
+ void abort()
+ {
+ emit localAbortRequested();
+ }
+ void setForwardingDefered(bool forwardingDefered)
+ {
+ emit localSetForwardingDeferedRequested(forwardingDefered);
+ }
+
+ QByteArray contentDispositionHeader() { QMutexLocker lock(&m_mirroredMembersMutex); return m_contentDispositionHeader; }
+ qlonglong contentLengthHeader() { QMutexLocker lock(&m_mirroredMembersMutex); return m_contentLengthHeader; }
+ QString contentTypeHeader() { QMutexLocker lock(&m_mirroredMembersMutex); return m_contentTypeHeader; }
+ QNetworkReply::NetworkError error() { QMutexLocker lock(&m_mirroredMembersMutex); return m_error; }
+ QString errorString() { QMutexLocker lock(&m_mirroredMembersMutex); return m_errorString; }
+ QByteArray httpReasonPhrase() { QMutexLocker lock(&m_mirroredMembersMutex); return m_httpReasonPhrase; }
+ int httpStatusCode() { QMutexLocker lock(&m_mirroredMembersMutex); return m_httpStatusCode; }
+ QUrl url() { QMutexLocker lock(&m_mirroredMembersMutex); return m_url; }
+ QUrl redirectionTarget() { QMutexLocker lock(&m_mirroredMembersMutex); return m_redirectionTarget; }
+ QList<RawHeaderPair> rawHeaderPairs() { QMutexLocker lock(&m_mirroredMembersMutex); return m_rawHeaderPairs; }
+
+ QNetworkReply* reply()
+ {
+ // Careful, acccessing the reply accross threads might be hazardous to your health
+ return m_reply;
+ }
+public:
+ void get(const QNetworkRequest &request)
+ {
+ emit localGetRequested(request);
+ }
+ void post(const QNetworkRequest &request, QIODevice* data)
+ {
+ emit localPostRequested(request, data);
+ }
+ void head(const QNetworkRequest &request)
+ {
+ emit localHeadRequested(request);
+ }
+ void put(const QNetworkRequest &request, QIODevice* data)
+ {
+ emit localPutRequested(request, data);
+ }
+ void deleteResource(const QNetworkRequest &request)
+ {
+ emit localDeleteResourceRequested(request);
+ }
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ void sendCustomRequest(const QNetworkRequest &request, const QByteArray& verb)
+ {
+ emit localCustomRequestRequested(request, verb);
+ }
+#endif
+
+signals:
+ void localGetRequested(const QNetworkRequest& request);
+ void localPostRequested(const QNetworkRequest& request, QIODevice* data);
+ void localHeadRequested(const QNetworkRequest& request);
+ void localPutRequested(const QNetworkRequest& request, QIODevice* data);
+ void localDeleteResourceRequested(const QNetworkRequest& request);
+ void localCustomRequestRequested(const QNetworkRequest& request, const QByteArray& verb);
+ void localAbortRequested();
+ void localSetForwardingDeferedRequested(bool forwardingDefered);
+
+ void finished();
+ void readyRead();
+ void metaDataChanged();
+ void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
+ void dataReceived(const QByteArray &data);
+
+private slots:
+ void localGet(const QNetworkRequest& request);
+ void localPost(const QNetworkRequest& request, QIODevice* data);
+ void localHead(const QNetworkRequest& request);
+ void localPut(const QNetworkRequest& request, QIODevice* data);
+ void localDeleteResource(const QNetworkRequest& request);
+ void localCustomRequest(const QNetworkRequest& request, const QByteArray& verb);
+ void localAbort();
+ void localForwardData();
+ void localSetForwardingDefered(bool forwardingDefered);
+ void localMirrorMembers();
+
+private:
+ void localSetReply(QNetworkReply *reply);
+
+ QNetworkAccessManager *m_manager;
+ QNetworkReply *m_reply;
+ bool m_forwardingDefered;
+
+ // Mirrored members
+ QMutex m_mirroredMembersMutex;
+ QByteArray m_contentDispositionHeader;
+ qlonglong m_contentLengthHeader;
+ QString m_contentTypeHeader;
+ QNetworkReply::NetworkError m_error;
+ QString m_errorString;
+ QByteArray m_httpReasonPhrase;
+ int m_httpStatusCode;
+ QUrl m_url;
+ QUrl m_redirectionTarget;
+ QList<RawHeaderPair> m_rawHeaderPairs;
+};
+
+}
+
+
+#endif // QtNAMThreadSafeProxy_h
diff --git a/WebCore/platform/network/qt/ResourceHandleQt.cpp b/WebCore/platform/network/qt/ResourceHandleQt.cpp
index a5ac4c3..f40b828 100644
--- a/WebCore/platform/network/qt/ResourceHandleQt.cpp
+++ b/WebCore/platform/network/qt/ResourceHandleQt.cpp
@@ -35,6 +35,7 @@
#include "Frame.h"
#include "FrameNetworkingContext.h"
#include "FrameLoaderClientQt.h"
+#include "QtNAMThreadSafeProxy.h"
#include "NotImplemented.h"
#include "Page.h"
#include "QNetworkReplyHandler.h"
@@ -156,20 +157,13 @@ bool ResourceHandle::willLoadFromCache(ResourceRequest& request, Frame* frame)
if (!frame)
return false;
- QNetworkAccessManager* manager = 0;
- QAbstractNetworkCache* cache = 0;
if (frame->loader()->networkingContext()) {
- manager = frame->loader()->networkingContext()->networkAccessManager();
- cache = manager->cache();
- }
-
- if (!cache)
- return false;
-
- QNetworkCacheMetaData data = cache->metaData(request.url());
- if (data.isValid()) {
- request.setCachePolicy(ReturnCacheDataDontLoad);
- return true;
+ QNetworkAccessManager* manager = frame->loader()->networkingContext()->networkAccessManager();
+ QtNAMThreadSafeProxy managerProxy(manager);
+ if (managerProxy.willLoadFromCache(request.url())) {
+ request.setCachePolicy(ReturnCacheDataDontLoad);
+ return true;
+ }
}
return false;
diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp
index c1933e3..a2440d3 100644
--- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp
+++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp
@@ -492,7 +492,7 @@ static void sendRequestCallback(GObject* source, GAsyncResult* res, gpointer use
if (isTransportError || (error->domain == G_IO_ERROR)) {
SoupURI* uri = webkit_soup_request_get_uri(d->m_soupRequest.get());
GOwnPtr<char> uriStr(soup_uri_to_string(uri, false));
- gint errorCode = isTransportError ? soupMsg->status_code : error->code;
+ gint errorCode = isTransportError ? static_cast<gint>(soupMsg->status_code) : error->code;
const gchar* errorMsg = isTransportError ? soupMsg->reason_phrase : error->message;
const gchar* quarkStr = isTransportError ? g_quark_to_string(SOUP_HTTP_ERROR) : g_quark_to_string(G_IO_ERROR);
ResourceError resourceError(quarkStr, errorCode, uriStr.get(), String::fromUTF8(errorMsg));
@@ -508,8 +508,11 @@ static void sendRequestCallback(GObject* source, GAsyncResult* res, gpointer use
fillResponseFromMessage(soupMsg, &d->m_response);
client->didReceiveResponse(handle.get(), d->m_response);
- // WebCore might have cancelled the job in the while
- if (!d->m_cancelled && soupMsg->response_body->data)
+ // WebCore might have cancelled the job in the while. We
+ // must check for response_body->length and not
+ // response_body->data as libsoup always creates the
+ // SoupBuffer for the body even if the length is 0
+ if (!d->m_cancelled && soupMsg->response_body->length)
client->didReceiveData(handle.get(), soupMsg->response_body->data, soupMsg->response_body->length, true);
}
@@ -550,6 +553,9 @@ static void sendRequestCallback(GObject* source, GAsyncResult* res, gpointer use
}
}
+ if (d->m_defersLoading)
+ soup_session_pause_message(handle->defaultSession(), d->m_soupMessage.get());
+
g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE,
G_PRIORITY_DEFAULT, d->m_cancellable.get(), readCallback, 0);
}
@@ -660,8 +666,11 @@ static bool startHttp(ResourceHandle* handle)
if (!soup_message_headers_get_one(soupMessage->request_headers, "Accept"))
soup_message_headers_append(soupMessage->request_headers, "Accept", "*/*");
- d->m_cancellable = adoptPlatformRef(g_cancellable_new());
- webkit_soup_request_send_async(d->m_soupRequest.get(), d->m_cancellable.get(), sendRequestCallback, 0);
+ // Send the request only if it's not been explicitely deferred.
+ if (!d->m_defersLoading) {
+ d->m_cancellable = adoptPlatformRef(g_cancellable_new());
+ webkit_soup_request_send_async(d->m_soupRequest.get(), d->m_cancellable.get(), sendRequestCallback, 0);
+ }
return true;
}
@@ -734,9 +743,28 @@ bool ResourceHandle::supportsBufferedData()
return false;
}
-void ResourceHandle::platformSetDefersLoading(bool)
+void ResourceHandle::platformSetDefersLoading(bool defersLoading)
{
- notImplemented();
+ // Initial implementation of this method was required for bug #44157.
+
+ if (d->m_cancelled)
+ return;
+
+ if (!defersLoading && !d->m_cancellable && d->m_soupRequest.get()) {
+ d->m_cancellable = adoptPlatformRef(g_cancellable_new());
+ webkit_soup_request_send_async(d->m_soupRequest.get(), d->m_cancellable.get(), sendRequestCallback, 0);
+ return;
+ }
+
+ // Only supported for http(s) transfers. Something similar would
+ // probably be needed for data transfers done with GIO.
+ if (!d->m_soupMessage)
+ return;
+
+ if (defersLoading)
+ soup_session_pause_message(defaultSession(), d->m_soupMessage.get());
+ else
+ soup_session_unpause_message(defaultSession(), d->m_soupMessage.get());
}
bool ResourceHandle::loadsBlocked()
@@ -758,7 +786,7 @@ void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const
// FIXME: we should use the ResourceHandle::create method here,
// but it makes us timeout in a couple of tests. See
// https://bugs.webkit.org/show_bug.cgi?id=41823
- RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(request, &syncLoader, true, false));
+ RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(request, &syncLoader, false /*defersLoading*/, false /*shouldContentSniff*/));
handle->start(context);
syncLoader.run();
diff --git a/WebCore/platform/network/soup/cache/soup-http-input-stream.c b/WebCore/platform/network/soup/cache/soup-http-input-stream.c
index dc95d6e..195c458 100644
--- a/WebCore/platform/network/soup/cache/soup-http-input-stream.c
+++ b/WebCore/platform/network/soup/cache/soup-http-input-stream.c
@@ -598,6 +598,7 @@ send_async_finished (GInputStream *stream)
g_error_free (error);
}
g_simple_async_result_complete (result);
+ g_object_unref (result);
}
static void
diff --git a/WebCore/platform/network/soup/cache/soup-request-http.c b/WebCore/platform/network/soup/cache/soup-request-http.c
index f3fe2ec..777fd72 100644
--- a/WebCore/platform/network/soup/cache/soup-request-http.c
+++ b/WebCore/platform/network/soup/cache/soup-request-http.c
@@ -188,6 +188,7 @@ typedef struct {
WebKitSoupRequestHTTP *http;
GAsyncReadyCallback callback;
gpointer user_data;
+ WebKitSoupHTTPInputStream *httpstream;
} SendAsyncHelper;
static void webkit_soup_request_http_send_async (WebKitSoupRequest *request,
@@ -199,45 +200,34 @@ static gboolean
send_async_cb (gpointer data)
{
GSimpleAsyncResult *simple;
- WebKitSoupHTTPInputStream *httpstream;
- SoupSession *session;
- WebKitSoupCache *cache;
SendAsyncHelper *helper = (SendAsyncHelper *)data;
+ const gchar *content_type;
- session = webkit_soup_request_get_session (WEBKIT_SOUP_REQUEST (helper->http));
- cache = (WebKitSoupCache *)soup_session_get_feature (session, WEBKIT_TYPE_SOUP_CACHE);
-
- httpstream = (WebKitSoupHTTPInputStream *)webkit_soup_cache_send_response (cache, SOUP_MESSAGE (helper->http->priv->msg));
-
- if (httpstream) {
- const gchar *content_type;
-
- simple = g_simple_async_result_new (G_OBJECT (helper->http),
- helper->callback, helper->user_data,
- webkit_soup_request_http_send_async);
- g_simple_async_result_set_op_res_gpointer (simple, httpstream, g_object_unref);
+ simple = g_simple_async_result_new (G_OBJECT (helper->http),
+ helper->callback, helper->user_data,
+ webkit_soup_request_http_send_async);
+ g_simple_async_result_set_op_res_gpointer (simple, helper->httpstream, g_object_unref);
- /* Update message status */
- soup_message_set_status (helper->http->priv->msg, SOUP_STATUS_OK);
+ /* Update message status */
+ soup_message_set_status (helper->http->priv->msg, SOUP_STATUS_OK);
- /* Issue signals */
- soup_message_got_headers (helper->http->priv->msg);
+ /* Issue signals */
+ soup_message_got_headers (helper->http->priv->msg);
- /* FIXME: Uncomment this when this becomes part of libsoup
- * if (!soup_message_disables_feature(helper->http->priv->msg, SOUP_TYPE_CONTENT_SNIFFER)) {
- * const gchar *content_type = soup_message_headers_get_content_type (helper->http->priv->msg->response_headers, NULL);
- * soup_message_content_sniffed (helper->http->priv->msg, content_type, NULL);
- * }
- */
- content_type = soup_message_headers_get_content_type (helper->http->priv->msg->response_headers, NULL);
- soup_message_content_sniffed (helper->http->priv->msg, content_type, NULL);
+ /* FIXME: Uncomment this when this becomes part of libsoup
+ * if (!soup_message_disables_feature(helper->http->priv->msg, SOUP_TYPE_CONTENT_SNIFFER)) {
+ * const gchar *content_type = soup_message_headers_get_content_type (helper->http->priv->msg->response_headers, NULL);
+ * soup_message_content_sniffed (helper->http->priv->msg, content_type, NULL);
+ * }
+ */
+ content_type = soup_message_headers_get_content_type (helper->http->priv->msg->response_headers, NULL);
+ soup_message_content_sniffed (helper->http->priv->msg, content_type, NULL);
- g_simple_async_result_complete (simple);
+ g_simple_async_result_complete (simple);
- soup_message_finished (helper->http->priv->msg);
+ soup_message_finished (helper->http->priv->msg);
- g_object_unref (simple);
- }
+ g_object_unref (simple);
g_object_unref (helper->http);
g_slice_free (SendAsyncHelper, helper);
@@ -265,17 +255,28 @@ webkit_soup_request_http_send_async (WebKitSoupRequest *request,
response = webkit_soup_cache_has_response (cache, http->priv->msg);
if (response == WEBKIT_SOUP_CACHE_RESPONSE_FRESH) {
- /* Do return the stream asynchronously as in
- the other cases. It's not enough to use
- g_simple_async_result_complete_in_idle as
- the signals must be also emitted
- asynchronously */
- SendAsyncHelper *helper = g_slice_new (SendAsyncHelper);
- helper->http = g_object_ref (http);
- helper->callback = callback;
- helper->user_data = user_data;
- g_timeout_add (0, send_async_cb, helper);
- return;
+ WebKitSoupHTTPInputStream *httpstream;
+
+ httpstream = (WebKitSoupHTTPInputStream *)
+ webkit_soup_cache_send_response (cache, SOUP_MESSAGE (http->priv->msg));
+
+ /* Cached resource file could have been deleted outside
+ */
+ if (httpstream) {
+ /* Do return the stream asynchronously as in
+ * the other cases. It's not enough to use
+ * g_simple_async_result_complete_in_idle as
+ * the signals must be also emitted
+ * asynchronously
+ */
+ SendAsyncHelper *helper = g_slice_new (SendAsyncHelper);
+ helper->http = g_object_ref (http);
+ helper->callback = callback;
+ helper->user_data = user_data;
+ helper->httpstream = httpstream;
+ g_timeout_add (0, send_async_cb, helper);
+ return;
+ }
} else if (response == WEBKIT_SOUP_CACHE_RESPONSE_NEEDS_VALIDATION) {
SoupMessage *conditional_msg;
ConditionalHelper *helper;
diff --git a/WebCore/platform/network/soup/cache/webkit/soup-cache.c b/WebCore/platform/network/soup/cache/webkit/soup-cache.c
index 4835750..b96428d 100644
--- a/WebCore/platform/network/soup/cache/webkit/soup-cache.c
+++ b/WebCore/platform/network/soup/cache/webkit/soup-cache.c
@@ -147,6 +147,8 @@ get_cacheability (WebKitSoupCache *cache, SoupMessage *msg)
soup_header_free_param_list (hash);
return WEBKIT_SOUP_CACHE_UNCACHEABLE;
}
+
+ soup_header_free_param_list (hash);
}
switch (msg->status_code) {
@@ -284,14 +286,12 @@ webkit_soup_cache_entry_set_freshness (WebKitSoupCacheEntry *entry, SoupMessage
{
const char *cache_control;
const char *expires, *date, *last_modified;
- GHashTable *hash;
-
- hash = NULL;
cache_control = soup_message_headers_get (entry->headers, "Cache-Control");
if (cache_control) {
const char *max_age, *s_maxage;
gint64 freshness_lifetime = 0;
+ GHashTable *hash;
WebKitSoupCachePrivate *priv = WEBKIT_SOUP_CACHE_GET_PRIVATE (cache);
hash = soup_header_parse_param_list (cache_control);
@@ -323,10 +323,9 @@ webkit_soup_cache_entry_set_freshness (WebKitSoupCacheEntry *entry, SoupMessage
soup_header_free_param_list (hash);
return;
}
- }
- if (hash != NULL)
soup_header_free_param_list (hash);
+ }
/* If the 'Expires' response header is present, use its value
* minus the value of the 'Date' response header
@@ -998,6 +997,7 @@ webkit_soup_cache_send_response (WebKitSoupCache *cache, SoupMessage *msg)
key = soup_message_get_cache_key (msg);
entry = g_hash_table_lookup (cache->priv->cache, key);
+ g_free (key);
g_return_val_if_fail (entry, NULL);
/* If we are told to send a response from cache any validation
@@ -1084,11 +1084,12 @@ webkit_soup_cache_init (WebKitSoupCache *cache)
}
static void
-remove_cache_item (gpointer key,
- gpointer value,
- WebKitSoupCache *cache)
+remove_cache_item (gpointer data,
+ gpointer user_data)
{
- WebKitSoupCacheEntry *entry = g_hash_table_lookup (cache->priv->cache, (const gchar *)key);
+ WebKitSoupCache *cache = (WebKitSoupCache *) user_data;
+ WebKitSoupCacheEntry *entry = (WebKitSoupCacheEntry *) data;
+
if (webkit_soup_cache_entry_remove (cache, entry))
webkit_soup_cache_entry_free (entry, FALSE);
}
@@ -1097,10 +1098,15 @@ static void
webkit_soup_cache_finalize (GObject *object)
{
WebKitSoupCachePrivate *priv;
+ GList *entries;
priv = WEBKIT_SOUP_CACHE (object)->priv;
- g_hash_table_foreach (priv->cache, (GHFunc)remove_cache_item, object);
+ // Cannot use g_hash_table_foreach as callbacks must not modify the hash table
+ entries = g_hash_table_get_values (priv->cache);
+ g_list_foreach (entries, remove_cache_item, object);
+ g_list_free (entries);
+
g_hash_table_destroy (priv->cache);
g_free (priv->cache_dir);
@@ -1257,7 +1263,6 @@ webkit_soup_cache_has_response (WebKitSoupCache *cache, SoupMessage *msg)
char *key;
WebKitSoupCacheEntry *entry;
const char *cache_control;
- GHashTable *hash;
gpointer value;
gboolean must_revalidate;
int max_age, max_stale, min_fresh;
@@ -1265,6 +1270,7 @@ webkit_soup_cache_has_response (WebKitSoupCache *cache, SoupMessage *msg)
key = soup_message_get_cache_key (msg);
entry = g_hash_table_lookup (cache->priv->cache, key);
+ g_free (key);
/* 1. The presented Request-URI and that of stored response
* match
@@ -1321,10 +1327,10 @@ webkit_soup_cache_has_response (WebKitSoupCache *cache, SoupMessage *msg)
cache_control = soup_message_headers_get (msg->request_headers, "Cache-Control");
if (cache_control) {
- hash = soup_header_parse_param_list (cache_control);
+ GHashTable *hash = soup_header_parse_param_list (cache_control);
if (g_hash_table_lookup_extended (hash, "no-store", NULL, NULL)) {
- g_hash_table_destroy (hash);
+ soup_header_free_param_list (hash);
return WEBKIT_SOUP_CACHE_RESPONSE_STALE;
}
@@ -1348,7 +1354,7 @@ webkit_soup_cache_has_response (WebKitSoupCache *cache, SoupMessage *msg)
if (value)
min_fresh = (int)MIN (g_ascii_strtoll (value, NULL, 10), G_MAXINT32);
- g_hash_table_destroy (hash);
+ soup_header_free_param_list (hash);
if (max_age != -1) {
guint current_age = webkit_soup_cache_entry_get_current_age (entry);
@@ -1449,11 +1455,12 @@ webkit_soup_cache_flush (WebKitSoupCache *cache)
}
static void
-clear_cache_item (gpointer key,
- gpointer value,
- WebKitSoupCache *cache)
+clear_cache_item (gpointer data,
+ gpointer user_data)
{
- WebKitSoupCacheEntry *entry = g_hash_table_lookup (cache->priv->cache, (const gchar *)key);
+ WebKitSoupCache *cache = (WebKitSoupCache *) user_data;
+ WebKitSoupCacheEntry *entry = (WebKitSoupCacheEntry *) data;
+
if (webkit_soup_cache_entry_remove (cache, entry))
webkit_soup_cache_entry_free (entry, TRUE);
}
@@ -1469,13 +1476,17 @@ void
webkit_soup_cache_clear (WebKitSoupCache *cache)
{
GHashTable *hash;
+ GList *entries;
g_return_if_fail (WEBKIT_IS_SOUP_CACHE (cache));
hash = cache->priv->cache;
g_return_if_fail (hash);
- g_hash_table_foreach (hash, (GHFunc)clear_cache_item, cache);
+ // Cannot use g_hash_table_foreach as callbacks must not modify the hash table
+ entries = g_hash_table_get_values (hash);
+ g_list_foreach (entries, clear_cache_item, cache);
+ g_list_free (entries);
}
SoupMessage *
@@ -1604,12 +1615,13 @@ webkit_soup_cache_load (WebKitSoupCache *cache)
filename = g_build_filename (priv->cache_dir, WEBKIT_SOUP_CACHE_FILE, NULL);
if (!g_file_get_contents (filename, &contents, &length, NULL)) {
g_free (filename);
+ g_free (contents);
return;
}
g_free (filename);
variant_format = g_variant_type_new (WEBKIT_SOUP_CACHE_ENTRIES_FORMAT);
- cache_variant = g_variant_new_from_data (variant_format, (const gchar *)contents, length, FALSE, NULL, NULL);
+ cache_variant = g_variant_new_from_data (variant_format, (const gchar *)contents, length, FALSE, g_free, contents);
g_variant_type_free (variant_format);
g_variant_get (cache_variant, WEBKIT_SOUP_CACHE_ENTRIES_FORMAT, &entries_iter);