summaryrefslogtreecommitdiff
path: root/Source/WebCore/platform/network
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/network')
-rw-r--r--Source/WebCore/platform/network/AuthenticationChallengeBase.cpp4
-rw-r--r--Source/WebCore/platform/network/AuthenticationChallengeBase.h22
-rw-r--r--Source/WebCore/platform/network/AuthenticationClient.h2
-rw-r--r--Source/WebCore/platform/network/BlobData.cpp78
-rw-r--r--Source/WebCore/platform/network/BlobData.h172
-rw-r--r--Source/WebCore/platform/network/BlobDataFileReference.cpp120
-rw-r--r--Source/WebCore/platform/network/BlobDataFileReference.h72
-rw-r--r--Source/WebCore/platform/network/BlobPart.h87
-rw-r--r--Source/WebCore/platform/network/BlobRegistry.cpp14
-rw-r--r--Source/WebCore/platform/network/BlobRegistry.h35
-rw-r--r--Source/WebCore/platform/network/BlobRegistryImpl.cpp262
-rw-r--r--Source/WebCore/platform/network/BlobRegistryImpl.h35
-rw-r--r--Source/WebCore/platform/network/BlobResourceHandle.cpp310
-rw-r--r--Source/WebCore/platform/network/BlobResourceHandle.h85
-rw-r--r--Source/WebCore/platform/network/CacheValidation.cpp422
-rw-r--r--Source/WebCore/platform/network/CacheValidation.h81
-rw-r--r--Source/WebCore/platform/network/CookieStorage.h13
-rw-r--r--Source/WebCore/platform/network/Credential.cpp162
-rw-r--r--Source/WebCore/platform/network/Credential.h81
-rw-r--r--Source/WebCore/platform/network/CredentialBase.cpp97
-rw-r--r--Source/WebCore/platform/network/CredentialBase.h74
-rw-r--r--Source/WebCore/platform/network/CredentialStorage.cpp104
-rw-r--r--Source/WebCore/platform/network/CredentialStorage.h36
-rw-r--r--Source/WebCore/platform/network/DNS.h4
-rw-r--r--Source/WebCore/platform/network/DNSResolveQueue.cpp21
-rw-r--r--Source/WebCore/platform/network/DNSResolveQueue.h12
-rw-r--r--Source/WebCore/platform/network/DataURLDecoder.cpp196
-rw-r--r--Source/WebCore/platform/network/DataURLDecoder.h65
-rw-r--r--Source/WebCore/platform/network/FormData.cpp421
-rw-r--r--Source/WebCore/platform/network/FormData.h235
-rw-r--r--Source/WebCore/platform/network/FormDataBuilder.cpp33
-rw-r--r--Source/WebCore/platform/network/FormDataBuilder.h3
-rw-r--r--Source/WebCore/platform/network/HTTPHeaderMap.cpp130
-rw-r--r--Source/WebCore/platform/network/HTTPHeaderMap.h202
-rw-r--r--Source/WebCore/platform/network/HTTPHeaderNames.in112
-rw-r--r--Source/WebCore/platform/network/HTTPHeaderValues.cpp61
-rw-r--r--Source/WebCore/platform/network/HTTPHeaderValues.h39
-rw-r--r--Source/WebCore/platform/network/HTTPParsers.cpp398
-rw-r--r--Source/WebCore/platform/network/HTTPParsers.h63
-rw-r--r--Source/WebCore/platform/network/HTTPStatusCodes.h27
-rw-r--r--Source/WebCore/platform/network/MIMEHeader.cpp29
-rw-r--r--Source/WebCore/platform/network/MIMEHeader.h3
-rw-r--r--Source/WebCore/platform/network/NetworkLoadTiming.h138
-rw-r--r--Source/WebCore/platform/network/NetworkStateNotifier.cpp21
-rw-r--r--Source/WebCore/platform/network/NetworkStateNotifier.h53
-rw-r--r--Source/WebCore/platform/network/NetworkStorageSession.cpp (renamed from Source/WebCore/platform/network/ResourceLoadTiming.cpp)31
-rw-r--r--Source/WebCore/platform/network/NetworkStorageSession.h85
-rw-r--r--Source/WebCore/platform/network/NetworkStorageSessionStub.cpp76
-rw-r--r--Source/WebCore/platform/network/NetworkingContext.h21
-rw-r--r--Source/WebCore/platform/network/ParsedContentRange.cpp134
-rw-r--r--Source/WebCore/platform/network/ParsedContentRange.h (renamed from Source/WebCore/platform/network/soup/CookieJarSoup.h)36
-rw-r--r--Source/WebCore/platform/network/PingHandle.h96
-rw-r--r--Source/WebCore/platform/network/PlatformCookieJar.h27
-rw-r--r--Source/WebCore/platform/network/ProtectionSpace.h74
-rw-r--r--Source/WebCore/platform/network/ProtectionSpaceBase.cpp (renamed from Source/WebCore/platform/network/ProtectionSpace.cpp)74
-rw-r--r--Source/WebCore/platform/network/ProtectionSpaceBase.h100
-rw-r--r--Source/WebCore/platform/network/ProtectionSpaceHash.h4
-rw-r--r--Source/WebCore/platform/network/ProxyServer.cpp8
-rw-r--r--Source/WebCore/platform/network/ProxyServer.h4
-rw-r--r--Source/WebCore/platform/network/ResourceErrorBase.cpp38
-rw-r--r--Source/WebCore/platform/network/ResourceErrorBase.h71
-rw-r--r--Source/WebCore/platform/network/ResourceHandle.cpp84
-rw-r--r--Source/WebCore/platform/network/ResourceHandle.h217
-rw-r--r--Source/WebCore/platform/network/ResourceHandleClient.cpp21
-rw-r--r--Source/WebCore/platform/network/ResourceHandleClient.h63
-rw-r--r--Source/WebCore/platform/network/ResourceHandleInternal.h273
-rw-r--r--Source/WebCore/platform/network/ResourceHandleTypes.h6
-rw-r--r--Source/WebCore/platform/network/ResourceLoadPriority.h32
-rw-r--r--Source/WebCore/platform/network/ResourceLoadTiming.h123
-rw-r--r--Source/WebCore/platform/network/ResourceRequestBase.cpp316
-rw-r--r--Source/WebCore/platform/network/ResourceRequestBase.h496
-rw-r--r--Source/WebCore/platform/network/ResourceResponseBase.cpp604
-rw-r--r--Source/WebCore/platform/network/ResourceResponseBase.h332
-rw-r--r--Source/WebCore/platform/network/SocketStreamError.h (renamed from Source/WebCore/platform/network/SocketStreamErrorBase.cpp)55
-rw-r--r--Source/WebCore/platform/network/SocketStreamHandle.cpp (renamed from Source/WebCore/platform/network/SocketStreamHandleBase.cpp)57
-rw-r--r--Source/WebCore/platform/network/SocketStreamHandle.h (renamed from Source/WebCore/platform/network/BlobStorageData.h)49
-rw-r--r--Source/WebCore/platform/network/SocketStreamHandleBase.h73
-rw-r--r--Source/WebCore/platform/network/SocketStreamHandleClient.h39
-rw-r--r--Source/WebCore/platform/network/SynchronousLoaderClient.cpp10
-rw-r--r--Source/WebCore/platform/network/SynchronousLoaderClient.h35
-rwxr-xr-xSource/WebCore/platform/network/create-http-header-name-table245
-rw-r--r--Source/WebCore/platform/network/gtk/CredentialBackingStore.cpp144
-rw-r--r--Source/WebCore/platform/network/gtk/CredentialBackingStore.h53
-rw-r--r--Source/WebCore/platform/network/soup/AuthenticationChallenge.h10
-rw-r--r--Source/WebCore/platform/network/soup/AuthenticationChallengeSoup.cpp15
-rw-r--r--Source/WebCore/platform/network/soup/CertificateInfo.cpp5
-rw-r--r--Source/WebCore/platform/network/soup/CertificateInfo.h5
-rw-r--r--Source/WebCore/platform/network/soup/CookieJarSoup.cpp133
-rw-r--r--Source/WebCore/platform/network/soup/CookieStorageSoup.cpp26
-rw-r--r--Source/WebCore/platform/network/soup/CredentialStorageSoup.cpp4
-rw-r--r--Source/WebCore/platform/network/soup/DNSSoup.cpp65
-rw-r--r--Source/WebCore/platform/network/soup/GRefPtrSoup.cpp35
-rw-r--r--Source/WebCore/platform/network/soup/GRefPtrSoup.h37
-rw-r--r--Source/WebCore/platform/network/soup/GUniquePtrSoup.h2
-rw-r--r--Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp222
-rw-r--r--Source/WebCore/platform/network/soup/ProxyServerSoup.cpp4
-rw-r--r--Source/WebCore/platform/network/soup/ResourceError.h30
-rw-r--r--Source/WebCore/platform/network/soup/ResourceErrorSoup.cpp31
-rw-r--r--Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp699
-rw-r--r--Source/WebCore/platform/network/soup/ResourceRequest.h75
-rw-r--r--Source/WebCore/platform/network/soup/ResourceRequestSoup.cpp107
-rw-r--r--Source/WebCore/platform/network/soup/ResourceResponse.h45
-rw-r--r--Source/WebCore/platform/network/soup/ResourceResponseSoup.cpp53
-rw-r--r--Source/WebCore/platform/network/soup/SocketStreamError.h50
-rw-r--r--Source/WebCore/platform/network/soup/SocketStreamHandle.h84
-rw-r--r--Source/WebCore/platform/network/soup/SocketStreamHandleImpl.h (renamed from Source/WebCore/platform/network/SocketStreamErrorBase.h)79
-rw-r--r--Source/WebCore/platform/network/soup/SocketStreamHandleImplSoup.cpp274
-rw-r--r--Source/WebCore/platform/network/soup/SocketStreamHandleSoup.cpp288
-rw-r--r--Source/WebCore/platform/network/soup/SoupNetworkProxySettings.h69
-rw-r--r--Source/WebCore/platform/network/soup/SoupNetworkSession.cpp305
-rw-r--r--Source/WebCore/platform/network/soup/SoupNetworkSession.h48
-rw-r--r--Source/WebCore/platform/network/soup/SynchronousLoaderClientSoup.cpp6
-rw-r--r--Source/WebCore/platform/network/soup/WebKitSoupRequestGeneric.cpp105
-rw-r--r--Source/WebCore/platform/network/soup/WebKitSoupRequestGeneric.h65
-rw-r--r--Source/WebCore/platform/network/soup/WebKitSoupRequestGenericClient.h34
115 files changed, 7152 insertions, 4698 deletions
diff --git a/Source/WebCore/platform/network/AuthenticationChallengeBase.cpp b/Source/WebCore/platform/network/AuthenticationChallengeBase.cpp
index 77bfccd33..7c19e1f52 100644
--- a/Source/WebCore/platform/network/AuthenticationChallengeBase.cpp
+++ b/Source/WebCore/platform/network/AuthenticationChallengeBase.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
diff --git a/Source/WebCore/platform/network/AuthenticationChallengeBase.h b/Source/WebCore/platform/network/AuthenticationChallengeBase.h
index 6afb844cd..c1fed1375 100644
--- a/Source/WebCore/platform/network/AuthenticationChallengeBase.h
+++ b/Source/WebCore/platform/network/AuthenticationChallengeBase.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -36,19 +36,19 @@ class AuthenticationChallenge;
class AuthenticationChallengeBase {
public:
- AuthenticationChallengeBase();
+ WEBCORE_EXPORT AuthenticationChallengeBase();
AuthenticationChallengeBase(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse& response, const ResourceError& error);
- unsigned previousFailureCount() const;
- const Credential& proposedCredential() const;
- const ProtectionSpace& protectionSpace() const;
- const ResourceResponse& failureResponse() const;
- const ResourceError& error() const;
+ WEBCORE_EXPORT unsigned previousFailureCount() const;
+ WEBCORE_EXPORT const Credential& proposedCredential() const;
+ WEBCORE_EXPORT const ProtectionSpace& protectionSpace() const;
+ WEBCORE_EXPORT const ResourceResponse& failureResponse() const;
+ WEBCORE_EXPORT const ResourceError& error() const;
- bool isNull() const;
- void nullify();
+ WEBCORE_EXPORT bool isNull() const;
+ WEBCORE_EXPORT void nullify();
- static bool compare(const AuthenticationChallenge& a, const AuthenticationChallenge& b);
+ WEBCORE_EXPORT static bool compare(const AuthenticationChallenge& a, const AuthenticationChallenge& b);
protected:
// The AuthenticationChallenge subclass may "shadow" this method to compare platform specific fields
diff --git a/Source/WebCore/platform/network/AuthenticationClient.h b/Source/WebCore/platform/network/AuthenticationClient.h
index 1e17910e2..8dec55d47 100644
--- a/Source/WebCore/platform/network/AuthenticationClient.h
+++ b/Source/WebCore/platform/network/AuthenticationClient.h
@@ -36,6 +36,8 @@ public:
virtual void receivedCredential(const AuthenticationChallenge&, const Credential&) = 0;
virtual void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&) = 0;
virtual void receivedCancellation(const AuthenticationChallenge&) = 0;
+ virtual void receivedRequestToPerformDefaultHandling(const AuthenticationChallenge&) = 0;
+ virtual void receivedChallengeRejection(const AuthenticationChallenge&) = 0;
void ref() { refAuthenticationClient(); }
void deref() { derefAuthenticationClient(); }
diff --git a/Source/WebCore/platform/network/BlobData.cpp b/Source/WebCore/platform/network/BlobData.cpp
index 39f7126fa..38cb4d172 100644
--- a/Source/WebCore/platform/network/BlobData.cpp
+++ b/Source/WebCore/platform/network/BlobData.cpp
@@ -33,65 +33,54 @@
#include "Blob.h"
#include "BlobURL.h"
-#include "ThreadableBlobRegistry.h"
-
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefPtr.h>
-#include <wtf/Vector.h>
namespace WebCore {
-const long long BlobDataItem::toEndOfFile = -1;
-
-RawData::RawData()
-{
-}
-
-void RawData::detachFromCurrentThread()
+BlobData::BlobData(const String& contentType)
+ : m_contentType(contentType)
{
+ ASSERT(Blob::isNormalizedContentType(contentType));
}
-void BlobDataItem::detachFromCurrentThread()
-{
- data->detachFromCurrentThread();
- path = path.isolatedCopy();
- url = url.copy();
-}
+const long long BlobDataItem::toEndOfFile = -1;
-void BlobData::detachFromCurrentThread()
+long long BlobDataItem::length() const
{
- m_contentType = m_contentType.isolatedCopy();
- m_contentDisposition = m_contentDisposition.isolatedCopy();
- for (size_t i = 0; i < m_items.size(); ++i)
- m_items.at(i).detachFromCurrentThread();
+ if (m_length != toEndOfFile)
+ return m_length;
+
+ switch (m_type) {
+ case Type::Data:
+ ASSERT_NOT_REACHED();
+ return m_length;
+ case Type::File:
+ return m_file->size();
+ }
+
+ ASSERT_NOT_REACHED();
+ return m_length;
}
-void BlobData::setContentType(const String& contentType)
+void BlobData::appendData(const ThreadSafeDataBuffer& data)
{
- ASSERT(Blob::isNormalizedContentType(contentType));
- m_contentType = contentType;
+ size_t dataSize = data.data() ? data.data()->size() : 0;
+ appendData(data, 0, dataSize);
}
-void BlobData::appendData(PassRefPtr<RawData> data, long long offset, long long length)
+void BlobData::appendData(const ThreadSafeDataBuffer& data, long long offset, long long length)
{
m_items.append(BlobDataItem(data, offset, length));
}
-void BlobData::appendFile(const String& path)
+void BlobData::appendFile(Ref<BlobDataFileReference>&& file)
{
- m_items.append(BlobDataItem(path));
+ file->startTrackingModifications();
+ m_items.append(BlobDataItem(WTFMove(file)));
}
-void BlobData::appendFile(const String& path, long long offset, long long length, double expectedModificationTime)
+void BlobData::appendFile(BlobDataFileReference* file, long long offset, long long length)
{
- m_items.append(BlobDataItem(path, offset, length, expectedModificationTime));
-}
-
-void BlobData::appendBlob(const URL& url, long long offset, long long length)
-{
- m_items.append(BlobDataItem(url, offset, length));
+ m_items.append(BlobDataItem(file, offset, length));
}
void BlobData::swapItems(BlobDataItemList& items)
@@ -99,17 +88,4 @@ void BlobData::swapItems(BlobDataItemList& items)
m_items.swap(items);
}
-
-BlobDataHandle::BlobDataHandle(std::unique_ptr<BlobData> data, long long size)
-{
- UNUSED_PARAM(size);
- m_internalURL = BlobURL::createInternalURL();
- ThreadableBlobRegistry::registerBlobURL(m_internalURL, std::move(data));
-}
-
-BlobDataHandle::~BlobDataHandle()
-{
- ThreadableBlobRegistry::unregisterBlobURL(m_internalURL);
-}
-
} // namespace WebCore
diff --git a/Source/WebCore/platform/network/BlobData.h b/Source/WebCore/platform/network/BlobData.h
index 7b25c4bd5..932d5ab8b 100644
--- a/Source/WebCore/platform/network/BlobData.h
+++ b/Source/WebCore/platform/network/BlobData.h
@@ -31,175 +31,99 @@
#ifndef BlobData_h
#define BlobData_h
-#include "FileSystem.h"
+#include "BlobDataFileReference.h"
+#include "ThreadSafeDataBuffer.h"
#include "URL.h"
#include <wtf/Forward.h>
-#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
-class RawData : public ThreadSafeRefCounted<RawData> {
+class BlobDataItem {
public:
- static PassRefPtr<RawData> create()
- {
- return adoptRef(new RawData());
- }
-
- void detachFromCurrentThread();
+ WEBCORE_EXPORT static const long long toEndOfFile;
- const char* data() const { return m_data.data(); }
- size_t length() const { return m_data.size(); }
- Vector<char>* mutableData() { return &m_data; }
+ enum class Type {
+ Data,
+ File
+ };
-private:
- RawData();
+ Type type() const { return m_type; }
- Vector<char> m_data;
-};
+ // For Data type.
+ const ThreadSafeDataBuffer& data() const { return m_data; }
-struct BlobDataItem {
- static const long long toEndOfFile;
+ // For File type.
+ BlobDataFileReference* file() const { return m_file.get(); }
- // Default constructor.
- BlobDataItem()
- : type(Data)
- , offset(0)
- , length(toEndOfFile)
- , expectedModificationTime(invalidFileTime())
- {
- }
+ long long offset() const { return m_offset; }
+ WEBCORE_EXPORT long long length() const; // Computes file length if it's not known yet.
- // Constructor for String type (complete string).
- explicit BlobDataItem(PassRefPtr<RawData> data)
- : type(Data)
- , data(data)
- , offset(0)
- , length(toEndOfFile)
- , expectedModificationTime(invalidFileTime())
- {
- }
+private:
+ friend class BlobData;
- // Constructor for File type (complete file).
- explicit BlobDataItem(const String& path)
- : type(File)
- , path(path)
- , offset(0)
- , length(toEndOfFile)
- , expectedModificationTime(invalidFileTime())
+ explicit BlobDataItem(Ref<BlobDataFileReference>&& file)
+ : m_type(Type::File)
+ , m_file(WTFMove(file))
+ , m_offset(0)
+ , m_length(toEndOfFile)
{
}
- // Constructor for File type (partial file).
- BlobDataItem(const String& path, long long offset, long long length, double expectedModificationTime)
- : type(File)
- , path(path)
- , offset(offset)
- , length(length)
- , expectedModificationTime(expectedModificationTime)
+ BlobDataItem(ThreadSafeDataBuffer data, long long offset, long long length)
+ : m_type(Type::Data)
+ , m_data(data)
+ , m_offset(offset)
+ , m_length(length)
{
}
- // Constructor for Blob type.
- BlobDataItem(const URL& url, long long offset, long long length)
- : type(Blob)
- , url(url)
- , offset(offset)
- , length(length)
- , expectedModificationTime(invalidFileTime())
+ BlobDataItem(BlobDataFileReference* file, long long offset, long long length)
+ : m_type(Type::File)
+ , m_file(file)
+ , m_offset(offset)
+ , m_length(length)
{
}
- // Detaches from current thread so that it can be passed to another thread.
- void detachFromCurrentThread();
-
- enum {
- Data,
- File,
- Blob
- } type;
-
- // For Data type.
- RefPtr<RawData> data;
-
- // For File type.
- String path;
+ Type m_type;
+ ThreadSafeDataBuffer m_data;
+ RefPtr<BlobDataFileReference> m_file;
- // For Blob or URL type.
- URL url;
-
- long long offset;
- long long length;
- double expectedModificationTime;
-
-private:
- friend class BlobData;
-
- // Constructor for String type (partial string).
- BlobDataItem(PassRefPtr<RawData> data, long long offset, long long length)
- : type(Data)
- , data(data)
- , offset(offset)
- , length(length)
- , expectedModificationTime(invalidFileTime())
- {
- }
+ long long m_offset;
+ long long m_length;
};
typedef Vector<BlobDataItem> BlobDataItemList;
-class BlobData {
- WTF_MAKE_FAST_ALLOCATED;
+class BlobData : public ThreadSafeRefCounted<BlobData> {
public:
- BlobData() { }
-
- // Detaches from current thread so that it can be passed to another thread.
- void detachFromCurrentThread();
+ static Ref<BlobData> create(const String& contentType)
+ {
+ return adoptRef(*new BlobData(contentType));
+ }
const String& contentType() const { return m_contentType; }
- void setContentType(const String&);
-
- const String& contentDisposition() const { return m_contentDisposition; }
- void setContentDisposition(const String& contentDisposition) { m_contentDisposition = contentDisposition; }
const BlobDataItemList& items() const { return m_items; }
void swapItems(BlobDataItemList&);
- void appendData(PassRefPtr<RawData>, long long offset, long long length);
- void appendFile(const String& path);
- void appendFile(const String& path, long long offset, long long length, double expectedModificationTime);
- void appendBlob(const URL&, long long offset, long long length);
+ void appendData(const ThreadSafeDataBuffer&);
+ void appendFile(Ref<BlobDataFileReference>&&);
private:
friend class BlobRegistryImpl;
- friend class BlobStorageData;
+ BlobData(const String& contentType);
- // This is only exposed to BlobStorageData.
- void appendData(const RawData&, long long offset, long long length);
+ void appendData(const ThreadSafeDataBuffer&, long long offset, long long length);
+ void appendFile(BlobDataFileReference*, long long offset, long long length);
String m_contentType;
- String m_contentDisposition;
BlobDataItemList m_items;
};
-// FIXME: This class is mostly place holder until I get farther along with
-// https://bugs.webkit.org/show_bug.cgi?id=108733 and more specifically with landing
-// https://codereview.chromium.org/11192017/.
-class BlobDataHandle : public ThreadSafeRefCounted<BlobDataHandle> {
-public:
- static PassRefPtr<BlobDataHandle> create(std::unique_ptr<BlobData> data, long long size)
- {
- return adoptRef(new BlobDataHandle(std::move(data), size));
- }
-
- ~BlobDataHandle();
-
-private:
- BlobDataHandle(std::unique_ptr<BlobData>, long long size);
- URL m_internalURL;
-};
-
} // namespace WebCore
#endif // BlobData_h
diff --git a/Source/WebCore/platform/network/BlobDataFileReference.cpp b/Source/WebCore/platform/network/BlobDataFileReference.cpp
new file mode 100644
index 000000000..1f8ce0b63
--- /dev/null
+++ b/Source/WebCore/platform/network/BlobDataFileReference.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "BlobDataFileReference.h"
+
+#include "File.h"
+#include "FileMetadata.h"
+
+namespace WebCore {
+
+BlobDataFileReference::BlobDataFileReference(const String& path)
+ : m_path(path)
+#if ENABLE(FILE_REPLACEMENT)
+ , m_replacementShouldBeGenerated(false)
+#endif
+ , m_size(0)
+ , m_expectedModificationTime(invalidFileTime())
+{
+}
+
+BlobDataFileReference::~BlobDataFileReference()
+{
+#if ENABLE(FILE_REPLACEMENT)
+ if (!m_replacementPath.isNull())
+ deleteFile(m_replacementPath);
+#endif
+}
+
+const String& BlobDataFileReference::path()
+{
+#if ENABLE(FILE_REPLACEMENT)
+ if (m_replacementShouldBeGenerated)
+ generateReplacementFile();
+
+ if (!m_replacementPath.isNull())
+ return m_replacementPath;
+#endif
+
+ return m_path;
+}
+
+unsigned long long BlobDataFileReference::size()
+{
+#if ENABLE(FILE_REPLACEMENT)
+ if (m_replacementShouldBeGenerated)
+ generateReplacementFile();
+#endif
+
+ return m_size;
+}
+
+double BlobDataFileReference::expectedModificationTime()
+{
+#if ENABLE(FILE_REPLACEMENT)
+ // We do not currently track modifications for generated files, because we have a snapshot.
+ // Unfortunately, this is inconsistent with regular file handling - File objects should be invalidated when underlying files change.
+ if (m_replacementShouldBeGenerated || !m_replacementPath.isNull())
+ return invalidFileTime();
+#endif
+
+ return m_expectedModificationTime;
+}
+
+void BlobDataFileReference::startTrackingModifications()
+{
+ // This is not done automatically by the constructor, because BlobDataFileReference is
+ // also used to pass paths around before registration. Only registered blobs need to pay
+ // the cost of tracking file modifications.
+
+#if ENABLE(FILE_REPLACEMENT)
+ m_replacementShouldBeGenerated = File::shouldReplaceFile(m_path);
+#endif
+
+ // FIXME: Some platforms provide better ways to listen for file system object changes, consider using these.
+ FileMetadata metadata;
+ if (!getFileMetadata(m_path, metadata))
+ return;
+
+ m_expectedModificationTime = metadata.modificationTime;
+
+#if ENABLE(FILE_REPLACEMENT)
+ if (m_replacementShouldBeGenerated)
+ return;
+#endif
+
+ m_size = metadata.length;
+}
+
+void BlobDataFileReference::prepareForFileAccess()
+{
+}
+
+void BlobDataFileReference::revokeFileAccess()
+{
+}
+
+}
diff --git a/Source/WebCore/platform/network/BlobDataFileReference.h b/Source/WebCore/platform/network/BlobDataFileReference.h
new file mode 100644
index 000000000..6fae977ad
--- /dev/null
+++ b/Source/WebCore/platform/network/BlobDataFileReference.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BlobDataFileReference_h
+#define BlobDataFileReference_h
+
+#include "FileSystem.h"
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class WEBCORE_EXPORT BlobDataFileReference : public RefCounted<BlobDataFileReference> {
+public:
+ static Ref<BlobDataFileReference> create(const String& path)
+ {
+ return adoptRef(*new BlobDataFileReference(path));
+ }
+
+ virtual ~BlobDataFileReference();
+
+ void startTrackingModifications();
+
+ const String& path();
+ unsigned long long size();
+ double expectedModificationTime();
+
+ virtual void prepareForFileAccess();
+ virtual void revokeFileAccess();
+
+protected:
+ BlobDataFileReference(const String& path);
+
+private:
+#if ENABLE(FILE_REPLACEMENT)
+ void generateReplacementFile();
+#endif
+
+ String m_path;
+#if ENABLE(FILE_REPLACEMENT)
+ String m_replacementPath;
+ bool m_replacementShouldBeGenerated;
+#endif
+ unsigned long long m_size;
+ double m_expectedModificationTime;
+};
+
+}
+
+#endif // BlobDataFileReference_h
diff --git a/Source/WebCore/platform/network/BlobPart.h b/Source/WebCore/platform/network/BlobPart.h
new file mode 100644
index 000000000..628f939a3
--- /dev/null
+++ b/Source/WebCore/platform/network/BlobPart.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "URL.h"
+
+namespace WebCore {
+
+class BlobPart {
+public:
+ enum Type {
+ Data,
+ Blob
+ };
+
+ BlobPart()
+ : m_type(Data)
+ {
+ }
+
+ BlobPart(Vector<uint8_t>&& data)
+ : m_type(Data)
+ , m_data(WTFMove(data))
+ {
+ }
+
+ BlobPart(const URL& url)
+ : m_type(Blob)
+ , m_url(url)
+ {
+ }
+
+ Type type() const { return m_type; }
+
+ const Vector<uint8_t>& data() const
+ {
+ ASSERT(m_type == Data);
+ return m_data;
+ }
+
+ Vector<uint8_t> moveData()
+ {
+ ASSERT(m_type == Data);
+ return WTFMove(m_data);
+ }
+
+ const URL& url() const
+ {
+ ASSERT(m_type == Blob);
+ return m_url;
+ }
+
+ void detachFromCurrentThread()
+ {
+ m_url = m_url.isolatedCopy();
+ }
+
+private:
+ Type m_type;
+ Vector<uint8_t> m_data;
+ URL m_url;
+};
+
+}
diff --git a/Source/WebCore/platform/network/BlobRegistry.cpp b/Source/WebCore/platform/network/BlobRegistry.cpp
index 4a61df4c9..b1fafc689 100644
--- a/Source/WebCore/platform/network/BlobRegistry.cpp
+++ b/Source/WebCore/platform/network/BlobRegistry.cpp
@@ -26,25 +26,15 @@
#include "config.h"
#include "BlobRegistry.h"
-#if ENABLE(BLOB)
-
-#include "BlobRegistryImpl.h"
-#include "LoaderStrategy.h"
#include "PlatformStrategies.h"
#include <wtf/MainThread.h>
-#if PLATFORM(IOS)
-#include "WebCoreThread.h"
-#endif
-
namespace WebCore {
BlobRegistry& blobRegistry()
{
ASSERT(isMainThread());
-
- static BlobRegistry& instance = *platformStrategies()->loaderStrategy()->createBlobRegistry();
- return instance;
+ return *platformStrategies()->blobRegistry();
}
BlobRegistry::~BlobRegistry()
@@ -52,5 +42,3 @@ BlobRegistry::~BlobRegistry()
}
}
-
-#endif
diff --git a/Source/WebCore/platform/network/BlobRegistry.h b/Source/WebCore/platform/network/BlobRegistry.h
index 868c46c37..b1216758c 100644
--- a/Source/WebCore/platform/network/BlobRegistry.h
+++ b/Source/WebCore/platform/network/BlobRegistry.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -28,31 +29,47 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BlobRegistry_h
-#define BlobRegistry_h
+#pragma once
-#include <wtf/PassOwnPtr.h>
+#include <functional>
+#include <wtf/Forward.h>
+#include <wtf/Function.h>
+#include <wtf/Vector.h>
namespace WebCore {
-class BlobData;
-class BlobStorageData;
+class BlobDataFileReference;
+class BlobPart;
class BlobRegistry;
class URL;
-BlobRegistry& blobRegistry();
+WEBCORE_EXPORT BlobRegistry& blobRegistry();
// BlobRegistry is not thread-safe. It should only be called from main thread.
-class BlobRegistry {
+class WEBCORE_EXPORT BlobRegistry {
public:
+
+ // Registers a blob URL referring to the specified file.
+ virtual void registerFileBlobURL(const URL&, Ref<BlobDataFileReference>&&, const String& contentType) = 0;
+
// Registers a blob URL referring to the specified blob data.
- virtual void registerBlobURL(const URL&, std::unique_ptr<BlobData>) = 0;
+ virtual void registerBlobURL(const URL&, Vector<BlobPart>&&, const String& contentType) = 0;
// Registers a new blob URL referring to the blob data identified by the specified srcURL.
virtual void registerBlobURL(const URL&, const URL& srcURL) = 0;
+ // Registers a new blob URL referring to the blob data identified by the specified srcURL or, if none found, referring to the file found at the given path.
+ virtual void registerBlobURLOptionallyFileBacked(const URL&, const URL& srcURL, RefPtr<BlobDataFileReference>&&, const String& contentType) = 0;
+
+ // Negative start and end values select from the end.
+ virtual void registerBlobURLForSlice(const URL&, const URL& srcURL, long long start, long long end) = 0;
+
virtual void unregisterBlobURL(const URL&) = 0;
+ virtual unsigned long long blobSize(const URL&) = 0;
+
+ virtual void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, WTF::Function<void (const Vector<String>& filePaths)>&& completionHandler) = 0;
+
virtual bool isBlobRegistryImpl() const { return false; }
protected:
@@ -60,5 +77,3 @@ protected:
};
} // namespace WebCore
-
-#endif // BlobRegistry_h
diff --git a/Source/WebCore/platform/network/BlobRegistryImpl.cpp b/Source/WebCore/platform/network/BlobRegistryImpl.cpp
index 231af78aa..e143451fd 100644
--- a/Source/WebCore/platform/network/BlobRegistryImpl.cpp
+++ b/Source/WebCore/platform/network/BlobRegistryImpl.cpp
@@ -32,20 +32,20 @@
#include "config.h"
#include "BlobRegistryImpl.h"
-#if ENABLE(BLOB)
-
+#include "BlobData.h"
+#include "BlobPart.h"
#include "BlobResourceHandle.h"
-#include "BlobStorageData.h"
+#include "FileMetadata.h"
+#include "FileSystem.h"
#include "ResourceError.h"
#include "ResourceHandle.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
+#include "ScopeGuard.h"
#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
#include <wtf/StdLibExtras.h>
-
-#if PLATFORM(IOS)
-#include "WebCoreThread.h"
-#endif
+#include <wtf/WorkQueue.h>
namespace WebCore {
@@ -53,14 +53,14 @@ BlobRegistryImpl::~BlobRegistryImpl()
{
}
-static PassRefPtr<ResourceHandle> createResourceHandle(const ResourceRequest& request, ResourceHandleClient* client)
+static Ref<ResourceHandle> createBlobResourceHandle(const ResourceRequest& request, ResourceHandleClient* client)
{
return static_cast<BlobRegistryImpl&>(blobRegistry()).createResourceHandle(request, client);
}
-static void loadResourceSynchronously(NetworkingContext*, const ResourceRequest& request, StoredCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
+static void loadBlobResourceSynchronously(NetworkingContext*, const ResourceRequest& request, StoredCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
{
- BlobStorageData* blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(request.url());
+ BlobData* blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(request.url());
BlobResourceHandle::loadResourceSynchronously(blobData, request, error, response, data);
}
@@ -68,68 +68,64 @@ static void registerBlobResourceHandleConstructor()
{
static bool didRegister = false;
if (!didRegister) {
- ResourceHandle::registerBuiltinConstructor("blob", createResourceHandle);
- ResourceHandle::registerBuiltinSynchronousLoader("blob", loadResourceSynchronously);
+ ResourceHandle::registerBuiltinConstructor("blob", createBlobResourceHandle);
+ ResourceHandle::registerBuiltinSynchronousLoader("blob", loadBlobResourceSynchronously);
didRegister = true;
}
}
-PassRefPtr<ResourceHandle> BlobRegistryImpl::createResourceHandle(const ResourceRequest& request, ResourceHandleClient* client)
+Ref<ResourceHandle> BlobRegistryImpl::createResourceHandle(const ResourceRequest& request, ResourceHandleClient* client)
{
- RefPtr<BlobResourceHandle> handle = BlobResourceHandle::createAsync(getBlobDataFromURL(request.url()), request, client);
- if (!handle)
- return 0;
-
+ auto handle = BlobResourceHandle::createAsync(getBlobDataFromURL(request.url()), request, client);
handle->start();
- return handle.release();
+ return WTFMove(handle);
}
-void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobDataItemList& items)
-{
- for (BlobDataItemList::const_iterator iter = items.begin(); iter != items.end(); ++iter) {
- if (iter->type == BlobDataItem::Data)
- blobStorageData->m_data.appendData(iter->data, iter->offset, iter->length);
- else {
- ASSERT(iter->type == BlobDataItem::File);
- blobStorageData->m_data.appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime);
- }
- }
-}
-
-void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobDataItemList& items, long long offset, long long length)
+void BlobRegistryImpl::appendStorageItems(BlobData* blobData, const BlobDataItemList& items, long long offset, long long length)
{
ASSERT(length != BlobDataItem::toEndOfFile);
BlobDataItemList::const_iterator iter = items.begin();
if (offset) {
for (; iter != items.end(); ++iter) {
- if (offset >= iter->length)
- offset -= iter->length;
+ if (offset >= iter->length())
+ offset -= iter->length();
else
break;
}
}
for (; iter != items.end() && length > 0; ++iter) {
- long long currentLength = iter->length - offset;
+ long long currentLength = iter->length() - offset;
long long newLength = currentLength > length ? length : currentLength;
- if (iter->type == BlobDataItem::Data)
- blobStorageData->m_data.appendData(iter->data, iter->offset + offset, newLength);
+ if (iter->type() == BlobDataItem::Type::Data)
+ blobData->appendData(iter->data(), iter->offset() + offset, newLength);
else {
- ASSERT(iter->type == BlobDataItem::File);
- blobStorageData->m_data.appendFile(iter->path, iter->offset + offset, newLength, iter->expectedModificationTime);
+ ASSERT(iter->type() == BlobDataItem::Type::File);
+ blobData->appendFile(iter->file(), iter->offset() + offset, newLength);
}
length -= newLength;
offset = 0;
}
+ ASSERT(!length);
+}
+
+void BlobRegistryImpl::registerFileBlobURL(const URL& url, Ref<BlobDataFileReference>&& file, const String& contentType)
+{
+ ASSERT(isMainThread());
+ registerBlobResourceHandleConstructor();
+
+ auto blobData = BlobData::create(contentType);
+ blobData->appendFile(WTFMove(file));
+ m_blobs.set(url.string(), WTFMove(blobData));
}
-void BlobRegistryImpl::registerBlobURL(const URL& url, std::unique_ptr<BlobData> blobData)
+void BlobRegistryImpl::registerBlobURL(const URL& url, Vector<BlobPart>&& blobParts, const String& contentType)
{
ASSERT(isMainThread());
registerBlobResourceHandleConstructor();
- RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create(blobData->contentType(), blobData->contentDisposition());
+ auto blobData = BlobData::create(contentType);
// The blob data is stored in the "canonical" way. That is, it only contains a list of Data and File items.
// 1) The Data item is denoted by the raw data and the range.
@@ -137,35 +133,86 @@ void BlobRegistryImpl::registerBlobURL(const URL& url, std::unique_ptr<BlobData>
// 3) The URL item is denoted by the URL, the range and the expected modification time.
// All the Blob items in the passing blob data are resolved and expanded into a set of Data and File items.
- for (BlobDataItemList::const_iterator iter = blobData->items().begin(); iter != blobData->items().end(); ++iter) {
- switch (iter->type) {
- case BlobDataItem::Data:
- blobStorageData->m_data.appendData(iter->data, 0, iter->data->length());
- break;
- case BlobDataItem::File:
- blobStorageData->m_data.appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime);
+ for (BlobPart& part : blobParts) {
+ switch (part.type()) {
+ case BlobPart::Data: {
+ auto movedData = part.moveData();
+ auto data = ThreadSafeDataBuffer::adoptVector(movedData);
+ blobData->appendData(data);
break;
- case BlobDataItem::Blob:
- if (m_blobs.contains(iter->url.string()))
- appendStorageItems(blobStorageData.get(), m_blobs.get(iter->url.string())->items(), iter->offset, iter->length);
+ }
+ case BlobPart::Blob: {
+ if (auto blob = m_blobs.get(part.url().string())) {
+ for (const BlobDataItem& item : blob->items())
+ blobData->m_items.append(item);
+ }
break;
}
+ }
}
- m_blobs.set(url.string(), blobStorageData);
+ m_blobs.set(url.string(), WTFMove(blobData));
}
void BlobRegistryImpl::registerBlobURL(const URL& url, const URL& srcURL)
{
+ registerBlobURLOptionallyFileBacked(url, srcURL, nullptr, { });
+}
+
+void BlobRegistryImpl::registerBlobURLOptionallyFileBacked(const URL& url, const URL& srcURL, RefPtr<BlobDataFileReference>&& file, const String& contentType)
+{
ASSERT(isMainThread());
registerBlobResourceHandleConstructor();
- RefPtr<BlobStorageData> src = m_blobs.get(srcURL.string());
- ASSERT(src);
- if (!src)
+ BlobData* src = getBlobDataFromURL(srcURL);
+ if (src) {
+ m_blobs.set(url.string(), src);
return;
+ }
+
+ if (!file || file->path().isEmpty())
+ return;
+
+ auto backingFile = BlobData::create(contentType);
+ backingFile->appendFile(file.releaseNonNull());
- m_blobs.set(url.string(), src);
+ m_blobs.set(url.string(), WTFMove(backingFile));
+}
+
+void BlobRegistryImpl::registerBlobURLForSlice(const URL& url, const URL& srcURL, long long start, long long end)
+{
+ ASSERT(isMainThread());
+ BlobData* originalData = getBlobDataFromURL(srcURL);
+ if (!originalData)
+ return;
+
+ unsigned long long originalSize = blobSize(srcURL);
+
+ // Convert the negative value that is used to select from the end.
+ if (start < 0)
+ start = start + originalSize;
+ if (end < 0)
+ end = end + originalSize;
+
+ // Clamp the range if it exceeds the size limit.
+ if (start < 0)
+ start = 0;
+ if (end < 0)
+ end = 0;
+ if (static_cast<unsigned long long>(start) >= originalSize) {
+ start = 0;
+ end = 0;
+ } else if (end < start)
+ end = start;
+ else if (static_cast<unsigned long long>(end) > originalSize)
+ end = originalSize;
+
+ unsigned long long newLength = end - start;
+ auto newData = BlobData::create(originalData->contentType());
+
+ appendStorageItems(newData.ptr(), originalData->items(), start, newLength);
+
+ m_blobs.set(url.string(), WTFMove(newData));
}
void BlobRegistryImpl::unregisterBlobURL(const URL& url)
@@ -174,12 +221,111 @@ void BlobRegistryImpl::unregisterBlobURL(const URL& url)
m_blobs.remove(url.string());
}
-BlobStorageData* BlobRegistryImpl::getBlobDataFromURL(const URL& url) const
+BlobData* BlobRegistryImpl::getBlobDataFromURL(const URL& url) const
{
ASSERT(isMainThread());
return m_blobs.get(url.string());
}
-} // namespace WebCore
+unsigned long long BlobRegistryImpl::blobSize(const URL& url)
+{
+ ASSERT(isMainThread());
+ BlobData* data = getBlobDataFromURL(url);
+ if (!data)
+ return 0;
-#endif
+ unsigned long long result = 0;
+ for (const BlobDataItem& item : data->items())
+ result += item.length();
+
+ return result;
+}
+
+static WorkQueue& blobUtilityQueue()
+{
+ static NeverDestroyed<Ref<WorkQueue>> queue(WorkQueue::create("org.webkit.BlobUtility", WorkQueue::Type::Serial, WorkQueue::QOS::Background));
+ return queue.get();
+}
+
+struct BlobForFileWriting {
+ String blobURL;
+ Vector<std::pair<String, ThreadSafeDataBuffer>> filePathsOrDataBuffers;
+};
+
+void BlobRegistryImpl::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, Function<void (const Vector<String>& filePaths)>&& completionHandler)
+{
+ Vector<BlobForFileWriting> blobsForWriting;
+ for (auto& url : blobURLs) {
+ blobsForWriting.append({ });
+ blobsForWriting.last().blobURL = url.isolatedCopy();
+
+ auto* blobData = getBlobDataFromURL({ ParsedURLString, url });
+ if (!blobData) {
+ Vector<String> filePaths;
+ completionHandler(filePaths);
+ return;
+ }
+
+ for (auto& item : blobData->items()) {
+ switch (item.type()) {
+ case BlobDataItem::Type::Data:
+ blobsForWriting.last().filePathsOrDataBuffers.append({ { }, item.data() });
+ break;
+ case BlobDataItem::Type::File:
+ blobsForWriting.last().filePathsOrDataBuffers.append({ item.file()->path().isolatedCopy(), { } });
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+ }
+
+ blobUtilityQueue().dispatch([blobsForWriting = WTFMove(blobsForWriting), completionHandler = WTFMove(completionHandler)]() mutable {
+ Vector<String> filePaths;
+
+ auto performWriting = [blobsForWriting = WTFMove(blobsForWriting), &filePaths]() {
+ for (auto& blob : blobsForWriting) {
+ PlatformFileHandle file;
+ String tempFilePath = openTemporaryFile(ASCIILiteral("Blob"), file);
+
+ ScopeGuard fileCloser([file]() mutable {
+ closeFile(file);
+ });
+
+ if (tempFilePath.isEmpty() || !isHandleValid(file)) {
+ LOG_ERROR("Failed to open temporary file for writing a Blob to IndexedDB");
+ return false;
+ }
+
+ for (auto& part : blob.filePathsOrDataBuffers) {
+ if (part.second.data()) {
+ int length = part.second.data()->size();
+ if (writeToFile(file, reinterpret_cast<const char*>(part.second.data()->data()), length) != length) {
+ LOG_ERROR("Failed writing a Blob to temporary file for storage in IndexedDB");
+ return false;
+ }
+ } else {
+ ASSERT(!part.first.isEmpty());
+ if (!appendFileContentsToFileHandle(part.first, file)) {
+ LOG_ERROR("Failed copying File contents to a Blob temporary file for storage in IndexedDB (%s to %s)", part.first.utf8().data(), tempFilePath.utf8().data());
+ return false;
+ }
+ }
+ }
+
+ filePaths.append(tempFilePath.isolatedCopy());
+ }
+
+ return true;
+ };
+
+ if (!performWriting())
+ filePaths.clear();
+
+ callOnMainThread([completionHandler = WTFMove(completionHandler), filePaths = WTFMove(filePaths)]() {
+ completionHandler(filePaths);
+ });
+ });
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/network/BlobRegistryImpl.h b/Source/WebCore/platform/network/BlobRegistryImpl.h
index 5e49f2088..09312fa1d 100644
--- a/Source/WebCore/platform/network/BlobRegistryImpl.h
+++ b/Source/WebCore/platform/network/BlobRegistryImpl.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -28,11 +29,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BlobRegistryImpl_h
-#define BlobRegistryImpl_h
+#pragma once
+#include "BlobData.h"
#include "BlobRegistry.h"
-#include "BlobStorageData.h"
+#include "URLHash.h"
#include <wtf/HashMap.h>
#include <wtf/text/StringHash.h>
#include <wtf/text/WTFString.h>
@@ -45,27 +46,31 @@ class ResourceHandleClient;
class ResourceRequest;
// BlobRegistryImpl is not thread-safe. It should only be called from main thread.
-class BlobRegistryImpl : public BlobRegistry {
+class WEBCORE_EXPORT BlobRegistryImpl final : public BlobRegistry {
WTF_MAKE_FAST_ALLOCATED;
public:
virtual ~BlobRegistryImpl();
- BlobStorageData* getBlobDataFromURL(const URL&) const;
+ BlobData* getBlobDataFromURL(const URL&) const;
- PassRefPtr<ResourceHandle> createResourceHandle(const ResourceRequest&, ResourceHandleClient*);
+ Ref<ResourceHandle> createResourceHandle(const ResourceRequest&, ResourceHandleClient*);
private:
- void appendStorageItems(BlobStorageData*, const BlobDataItemList&);
- void appendStorageItems(BlobStorageData*, const BlobDataItemList&, long long offset, long long length);
+ void appendStorageItems(BlobData*, const BlobDataItemList&, long long offset, long long length);
- virtual void registerBlobURL(const URL&, std::unique_ptr<BlobData>) override;
- virtual void registerBlobURL(const URL&, const URL& srcURL) override;
- virtual void unregisterBlobURL(const URL&) override;
- virtual bool isBlobRegistryImpl() const override { return true; }
+ void registerFileBlobURL(const URL&, Ref<BlobDataFileReference>&&, const String& contentType) override;
+ void registerBlobURL(const URL&, Vector<BlobPart>&&, const String& contentType) override;
+ void registerBlobURL(const URL&, const URL& srcURL) override;
+ void registerBlobURLOptionallyFileBacked(const URL&, const URL& srcURL, RefPtr<BlobDataFileReference>&&, const String& contentType) override;
+ void registerBlobURLForSlice(const URL&, const URL& srcURL, long long start, long long end) override;
+ void unregisterBlobURL(const URL&) override;
+ bool isBlobRegistryImpl() const override { return true; }
- HashMap<String, RefPtr<BlobStorageData>> m_blobs;
+ unsigned long long blobSize(const URL&) override;
+
+ void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, Function<void (const Vector<String>& filePaths)>&& completionHandler) override;
+
+ HashMap<String, RefPtr<BlobData>> m_blobs;
};
} // namespace WebCore
-
-#endif // BlobRegistryImpl_h
diff --git a/Source/WebCore/platform/network/BlobResourceHandle.cpp b/Source/WebCore/platform/network/BlobResourceHandle.cpp
index 670d14bb3..e06fa6561 100644
--- a/Source/WebCore/platform/network/BlobResourceHandle.cpp
+++ b/Source/WebCore/platform/network/BlobResourceHandle.cpp
@@ -30,15 +30,15 @@
#include "config.h"
-#if ENABLE(BLOB)
-
#include "BlobResourceHandle.h"
#include "AsyncFileStream.h"
-#include "BlobStorageData.h"
+#include "BlobData.h"
#include "FileStream.h"
#include "FileSystem.h"
+#include "HTTPHeaderNames.h"
#include "HTTPParsers.h"
+#include "ParsedContentRange.h"
#include "URL.h"
#include "ResourceError.h"
#include "ResourceHandleClient.h"
@@ -51,29 +51,19 @@
namespace WebCore {
static const unsigned bufferSize = 512 * 1024;
-static const long long positionNotSpecified = -1;
static const int httpOK = 200;
static const int httpPartialContent = 206;
static const int httpNotAllowed = 403;
-static const int httpNotFound = 404;
static const int httpRequestedRangeNotSatisfiable = 416;
static const int httpInternalError = 500;
static const char* httpOKText = "OK";
static const char* httpPartialContentText = "Partial Content";
static const char* httpNotAllowedText = "Not Allowed";
-static const char* httpNotFoundText = "Not Found";
static const char* httpRequestedRangeNotSatisfiableText = "Requested Range Not Satisfiable";
static const char* httpInternalErrorText = "Internal Server Error";
static const char* const webKitBlobResourceDomain = "WebKitBlobResource";
-enum {
- notFoundError = 1,
- securityError = 2,
- rangeError = 3,
- notReadableError = 4,
- methodNotAllowed = 5
-};
///////////////////////////////////////////////////////////////////////////////
// BlobResourceSynchronousLoader
@@ -84,10 +74,8 @@ class BlobResourceSynchronousLoader : public ResourceHandleClient {
public:
BlobResourceSynchronousLoader(ResourceError&, ResourceResponse&, Vector<char>&);
- virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&) override;
- virtual void didReceiveData(ResourceHandle*, const char*, unsigned, int /*encodedDataLength*/) override;
- virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/) override;
- virtual void didFail(ResourceHandle*, const ResourceError&) override;
+ void didReceiveResponse(ResourceHandle*, ResourceResponse&&) override;
+ void didFail(ResourceHandle*, const ResourceError&) override;
private:
ResourceError& m_error;
@@ -102,11 +90,11 @@ BlobResourceSynchronousLoader::BlobResourceSynchronousLoader(ResourceError& erro
{
}
-void BlobResourceSynchronousLoader::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response)
+void BlobResourceSynchronousLoader::didReceiveResponse(ResourceHandle* handle, ResourceResponse&& response)
{
// We cannot handle the size that is more than maximum integer.
if (response.expectedContentLength() > INT_MAX) {
- m_error = ResourceError(webKitBlobResourceDomain, notReadableError, response.url(), "File is too large");
+ m_error = ResourceError(webKitBlobResourceDomain, static_cast<int>(BlobResourceHandle::Error::NotReadableError), response.url(), "File is too large");
return;
}
@@ -117,14 +105,6 @@ void BlobResourceSynchronousLoader::didReceiveResponse(ResourceHandle* handle, c
static_cast<BlobResourceHandle*>(handle)->readSync(m_data.data(), static_cast<int>(m_data.size()));
}
-void BlobResourceSynchronousLoader::didReceiveData(ResourceHandle*, const char*, unsigned, int)
-{
-}
-
-void BlobResourceSynchronousLoader::didFinishLoading(ResourceHandle*, double)
-{
-}
-
void BlobResourceSynchronousLoader::didFail(ResourceHandle*, const ResourceError& error)
{
m_error = error;
@@ -135,19 +115,15 @@ void BlobResourceSynchronousLoader::didFail(ResourceHandle*, const ResourceError
///////////////////////////////////////////////////////////////////////////////
// BlobResourceHandle
-PassRefPtr<BlobResourceHandle> BlobResourceHandle::createAsync(BlobStorageData* blobData, const ResourceRequest& request, ResourceHandleClient* client)
+Ref<BlobResourceHandle> BlobResourceHandle::createAsync(BlobData* blobData, const ResourceRequest& request, ResourceHandleClient* client)
{
- // FIXME: Should probably call didFail() instead of blocking the load without explanation.
- if (!equalIgnoringCase(request.httpMethod(), "GET"))
- return 0;
-
- return adoptRef(new BlobResourceHandle(blobData, request, client, true));
+ return adoptRef(*new BlobResourceHandle(blobData, request, client, true));
}
-void BlobResourceHandle::loadResourceSynchronously(BlobStorageData* blobData, const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
+void BlobResourceHandle::loadResourceSynchronously(BlobData* blobData, const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
{
- if (!equalIgnoringCase(request.httpMethod(), "GET")) {
- error = ResourceError(webKitBlobResourceDomain, methodNotAllowed, response.url(), "Request method must be GET");
+ if (!equalLettersIgnoringASCIICase(request.httpMethod(), "get")) {
+ error = ResourceError(webKitBlobResourceDomain, static_cast<int>(Error::MethodNotAllowed), response.url(), "Request method must be GET");
return;
}
@@ -156,89 +132,76 @@ void BlobResourceHandle::loadResourceSynchronously(BlobStorageData* blobData, co
handle->start();
}
-BlobResourceHandle::BlobResourceHandle(PassRefPtr<BlobStorageData> blobData, const ResourceRequest& request, ResourceHandleClient* client, bool async)
- : ResourceHandle(0, request, client, false, false)
+BlobResourceHandle::BlobResourceHandle(BlobData* blobData, const ResourceRequest& request, ResourceHandleClient* client, bool async)
+ : ResourceHandle(nullptr, request, client, false, false)
, m_blobData(blobData)
, m_async(async)
- , m_errorCode(0)
- , m_aborted(false)
- , m_rangeOffset(positionNotSpecified)
- , m_rangeEnd(positionNotSpecified)
- , m_rangeSuffixLength(positionNotSpecified)
- , m_totalRemainingSize(0)
- , m_currentItemReadSize(0)
- , m_sizeItemCount(0)
- , m_readItemCount(0)
- , m_fileOpened(false)
{
if (m_async)
- m_asyncStream = AsyncFileStream::create(this);
+ m_asyncStream = std::make_unique<AsyncFileStream>(*this);
else
- m_stream = FileStream::create();
+ m_stream = std::make_unique<FileStream>();
}
BlobResourceHandle::~BlobResourceHandle()
{
- if (m_async) {
- if (m_asyncStream)
- m_asyncStream->stop();
- } else {
- if (m_stream)
- m_stream->stop();
- }
}
void BlobResourceHandle::cancel()
{
- if (m_async) {
- if (m_asyncStream) {
- m_asyncStream->stop();
- m_asyncStream = 0;
- }
- }
+ m_asyncStream = nullptr;
+ m_fileOpened = false;
m_aborted = true;
ResourceHandle::cancel();
}
-void delayedStartBlobResourceHandle(void* context)
+void BlobResourceHandle::continueDidReceiveResponse()
{
- RefPtr<BlobResourceHandle> handle = adoptRef(static_cast<BlobResourceHandle*>(context));
- handle->doStart();
+ ASSERT(m_async);
+ ASSERT(usesAsyncCallbacks());
+
+ m_buffer.resize(bufferSize);
+ readAsync();
}
void BlobResourceHandle::start()
{
- if (m_async) {
- // Keep BlobResourceHandle alive until delayedStartBlobResourceHandle runs.
- ref();
-
- // Finish this async call quickly and return.
- callOnMainThread(delayedStartBlobResourceHandle, this);
+ if (!m_async) {
+ doStart();
return;
}
- doStart();
+ // Finish this async call quickly and return.
+ callOnMainThread([protectedThis = makeRef(*this)]() mutable {
+ protectedThis->doStart();
+ });
}
void BlobResourceHandle::doStart()
{
+ ASSERT(isMainThread());
+
// Do not continue if the request is aborted or an error occurs.
- if (m_aborted || m_errorCode)
+ if (erroredOrAborted())
return;
+ if (!equalLettersIgnoringASCIICase(firstRequest().httpMethod(), "get")) {
+ notifyFail(Error::MethodNotAllowed);
+ return;
+ }
+
// If the blob data is not found, fail now.
if (!m_blobData) {
- m_errorCode = notFoundError;
- notifyResponse();
+ notifyFail(Error::NotFoundError);
return;
}
// Parse the "Range" header we care about.
- String range = firstRequest().httpHeaderField("Range");
+ String range = firstRequest().httpHeaderField(HTTPHeaderName::Range);
if (!range.isEmpty() && !parseRange(range, m_rangeOffset, m_rangeEnd, m_rangeSuffixLength)) {
- m_errorCode = rangeError;
+ m_errorCode = Error::RangeError;
notifyResponse();
return;
}
@@ -246,8 +209,8 @@ void BlobResourceHandle::doStart()
if (m_async)
getSizeForNext();
else {
- Ref<BlobResourceHandle> protect(*this); // getSizeForNext calls the client
- for (size_t i = 0; i < m_blobData->items().size() && !m_aborted && !m_errorCode; ++i)
+ Ref<BlobResourceHandle> protectedThis(*this); // getSizeForNext calls the client
+ for (size_t i = 0; i < m_blobData->items().size() && !erroredOrAborted(); ++i)
getSizeForNext();
notifyResponse();
}
@@ -255,30 +218,35 @@ void BlobResourceHandle::doStart()
void BlobResourceHandle::getSizeForNext()
{
+ ASSERT(isMainThread());
+
// Do we finish validating and counting size for all items?
if (m_sizeItemCount >= m_blobData->items().size()) {
seek();
// Start reading if in asynchronous mode.
if (m_async) {
- Ref<BlobResourceHandle> protect(*this);
+ Ref<BlobResourceHandle> protectedThis(*this);
notifyResponse();
- m_buffer.resize(bufferSize);
- readAsync();
+ if (!usesAsyncCallbacks()) {
+ m_buffer.resize(bufferSize);
+ readAsync();
+ }
}
return;
}
const BlobDataItem& item = m_blobData->items().at(m_sizeItemCount);
- switch (item.type) {
- case BlobDataItem::Data:
- didGetSize(item.length);
+ switch (item.type()) {
+ case BlobDataItem::Type::Data:
+ didGetSize(item.length());
break;
- case BlobDataItem::File:
+ case BlobDataItem::Type::File:
+ // Files know their sizes, but asking the stream to verify that the file wasn't modified.
if (m_async)
- m_asyncStream->getSize(item.path, item.expectedModificationTime);
+ m_asyncStream->getSize(item.file()->path(), item.file()->expectedModificationTime());
else
- didGetSize(m_stream->getSize(item.path, item.expectedModificationTime));
+ didGetSize(m_stream->getSize(item.file()->path(), item.file()->expectedModificationTime()));
break;
default:
ASSERT_NOT_REACHED();
@@ -287,26 +255,27 @@ void BlobResourceHandle::getSizeForNext()
void BlobResourceHandle::didGetSize(long long size)
{
+ ASSERT(isMainThread());
+
// Do not continue if the request is aborted or an error occurs.
- if (m_aborted || m_errorCode)
+ if (erroredOrAborted())
return;
// If the size is -1, it means the file has been moved or changed. Fail now.
if (size == -1) {
- m_errorCode = notFoundError;
- notifyResponse();
+ notifyFail(Error::NotFoundError);
return;
}
// The size passed back is the size of the whole file. If the underlying item is a sliced file, we need to use the slice length.
const BlobDataItem& item = m_blobData->items().at(m_sizeItemCount);
- if (item.type == BlobDataItem::File && item.length != BlobDataItem::toEndOfFile)
- size = item.length;
+ size = item.length();
// Cache the size.
m_itemLengthList.append(size);
// Count the size.
+ m_totalSize += size;
m_totalRemainingSize += size;
m_sizeItemCount++;
@@ -316,14 +285,16 @@ void BlobResourceHandle::didGetSize(long long size)
void BlobResourceHandle::seek()
{
+ ASSERT(isMainThread());
+
// Convert from the suffix length to the range.
- if (m_rangeSuffixLength != positionNotSpecified) {
+ if (m_rangeSuffixLength != kPositionNotSpecified) {
m_rangeOffset = m_totalRemainingSize - m_rangeSuffixLength;
m_rangeEnd = m_rangeOffset + m_rangeSuffixLength - 1;
}
// Bail out if the range is not provided.
- if (m_rangeOffset == positionNotSpecified)
+ if (m_rangeOffset == kPositionNotSpecified)
return;
// Skip the initial items that are not in the range.
@@ -335,7 +306,7 @@ void BlobResourceHandle::seek()
m_currentItemReadSize = offset;
// Adjust the total remaining size in order not to go beyond the range.
- if (m_rangeEnd != positionNotSpecified) {
+ if (m_rangeEnd != kPositionNotSpecified) {
long long rangeSize = m_rangeEnd - m_rangeOffset + 1;
if (m_totalRemainingSize > rangeSize)
m_totalRemainingSize = rangeSize;
@@ -345,25 +316,27 @@ void BlobResourceHandle::seek()
int BlobResourceHandle::readSync(char* buf, int length)
{
+ ASSERT(isMainThread());
+
ASSERT(!m_async);
- Ref<BlobResourceHandle> protect(*this);
+ Ref<BlobResourceHandle> protectedThis(*this);
int offset = 0;
int remaining = length;
while (remaining) {
// Do not continue if the request is aborted or an error occurs.
- if (m_aborted || m_errorCode)
+ if (erroredOrAborted())
break;
// If there is no more remaining data to read, we are done.
if (!m_totalRemainingSize || m_readItemCount >= m_blobData->items().size())
break;
-
+
const BlobDataItem& item = m_blobData->items().at(m_readItemCount);
int bytesRead = 0;
- if (item.type == BlobDataItem::Data)
+ if (item.type() == BlobDataItem::Type::Data)
bytesRead = readDataSync(item, buf + offset, remaining);
- else if (item.type == BlobDataItem::File)
+ else if (item.type() == BlobDataItem::Type::File)
bytesRead = readFileSync(item, buf + offset, remaining);
else
ASSERT_NOT_REACHED();
@@ -375,7 +348,7 @@ int BlobResourceHandle::readSync(char* buf, int length)
}
int result;
- if (m_aborted || m_errorCode)
+ if (erroredOrAborted())
result = -1;
else
result = length - remaining;
@@ -391,17 +364,19 @@ int BlobResourceHandle::readSync(char* buf, int length)
int BlobResourceHandle::readDataSync(const BlobDataItem& item, char* buf, int length)
{
+ ASSERT(isMainThread());
+
ASSERT(!m_async);
- long long remaining = item.length - m_currentItemReadSize;
+ long long remaining = item.length() - m_currentItemReadSize;
int bytesToRead = (length > remaining) ? static_cast<int>(remaining) : length;
if (bytesToRead > m_totalRemainingSize)
bytesToRead = static_cast<int>(m_totalRemainingSize);
- memcpy(buf, item.data->data() + item.offset + m_currentItemReadSize, bytesToRead);
+ memcpy(buf, item.data().data() + item.offset() + m_currentItemReadSize, bytesToRead);
m_totalRemainingSize -= bytesToRead;
m_currentItemReadSize += bytesToRead;
- if (m_currentItemReadSize == item.length) {
+ if (m_currentItemReadSize == item.length()) {
m_readItemCount++;
m_currentItemReadSize = 0;
}
@@ -411,16 +386,18 @@ int BlobResourceHandle::readDataSync(const BlobDataItem& item, char* buf, int le
int BlobResourceHandle::readFileSync(const BlobDataItem& item, char* buf, int length)
{
+ ASSERT(isMainThread());
+
ASSERT(!m_async);
if (!m_fileOpened) {
long long bytesToRead = m_itemLengthList[m_readItemCount] - m_currentItemReadSize;
if (bytesToRead > m_totalRemainingSize)
bytesToRead = m_totalRemainingSize;
- bool success = m_stream->openForRead(item.path, item.offset + m_currentItemReadSize, bytesToRead);
+ bool success = m_stream->openForRead(item.file()->path(), item.offset() + m_currentItemReadSize, bytesToRead);
m_currentItemReadSize = 0;
if (!success) {
- m_errorCode = notReadableError;
+ m_errorCode = Error::NotReadableError;
return 0;
}
@@ -429,7 +406,7 @@ int BlobResourceHandle::readFileSync(const BlobDataItem& item, char* buf, int le
int bytesRead = m_stream->read(buf, length);
if (bytesRead < 0) {
- m_errorCode = notReadableError;
+ m_errorCode = Error::NotReadableError;
return 0;
}
if (!bytesRead) {
@@ -444,10 +421,11 @@ int BlobResourceHandle::readFileSync(const BlobDataItem& item, char* buf, int le
void BlobResourceHandle::readAsync()
{
+ ASSERT(isMainThread());
ASSERT(m_async);
// Do not continue if the request is aborted or an error occurs.
- if (m_aborted || m_errorCode)
+ if (erroredOrAborted())
return;
// If there is no more remaining data to read, we are done.
@@ -457,9 +435,9 @@ void BlobResourceHandle::readAsync()
}
const BlobDataItem& item = m_blobData->items().at(m_readItemCount);
- if (item.type == BlobDataItem::Data)
+ if (item.type() == BlobDataItem::Type::Data)
readDataAsync(item);
- else if (item.type == BlobDataItem::File)
+ else if (item.type() == BlobDataItem::Type::File)
readFileAsync(item);
else
ASSERT_NOT_REACHED();
@@ -467,18 +445,22 @@ void BlobResourceHandle::readAsync()
void BlobResourceHandle::readDataAsync(const BlobDataItem& item)
{
+ ASSERT(isMainThread());
ASSERT(m_async);
- Ref<BlobResourceHandle> protect(*this);
+ ASSERT(item.data().data());
+
+ Ref<BlobResourceHandle> protectedThis(*this);
- long long bytesToRead = item.length - m_currentItemReadSize;
+ long long bytesToRead = item.length() - m_currentItemReadSize;
if (bytesToRead > m_totalRemainingSize)
bytesToRead = m_totalRemainingSize;
- consumeData(item.data->data() + item.offset + m_currentItemReadSize, static_cast<int>(bytesToRead));
+ consumeData(reinterpret_cast<const char*>(item.data().data()->data()) + item.offset() + m_currentItemReadSize, static_cast<int>(bytesToRead));
m_currentItemReadSize = 0;
}
void BlobResourceHandle::readFileAsync(const BlobDataItem& item)
{
+ ASSERT(isMainThread());
ASSERT(m_async);
if (m_fileOpened) {
@@ -489,7 +471,7 @@ void BlobResourceHandle::readFileAsync(const BlobDataItem& item)
long long bytesToRead = m_itemLengthList[m_readItemCount] - m_currentItemReadSize;
if (bytesToRead > m_totalRemainingSize)
bytesToRead = static_cast<int>(m_totalRemainingSize);
- m_asyncStream->openForRead(item.path, item.offset + m_currentItemReadSize, bytesToRead);
+ m_asyncStream->openForRead(item.file()->path(), item.offset() + m_currentItemReadSize, bytesToRead);
m_fileOpened = true;
m_currentItemReadSize = 0;
}
@@ -499,7 +481,7 @@ void BlobResourceHandle::didOpen(bool success)
ASSERT(m_async);
if (!success) {
- failed(notReadableError);
+ failed(Error::NotReadableError);
return;
}
@@ -510,7 +492,7 @@ void BlobResourceHandle::didOpen(bool success)
void BlobResourceHandle::didRead(int bytesRead)
{
if (bytesRead < 0) {
- failed(notReadableError);
+ failed(Error::NotReadableError);
return;
}
@@ -520,7 +502,7 @@ void BlobResourceHandle::didRead(int bytesRead)
void BlobResourceHandle::consumeData(const char* data, int bytesRead)
{
ASSERT(m_async);
- Ref<BlobResourceHandle> protect(*this);
+ Ref<BlobResourceHandle> protectedThis(*this);
m_totalRemainingSize -= bytesRead;
@@ -547,10 +529,10 @@ void BlobResourceHandle::consumeData(const char* data, int bytesRead)
readAsync();
}
-void BlobResourceHandle::failed(int errorCode)
+void BlobResourceHandle::failed(Error errorCode)
{
ASSERT(m_async);
- Ref<BlobResourceHandle> protect(*this);
+ Ref<BlobResourceHandle> protectedThis(*this);
// Notify the client.
notifyFail(errorCode);
@@ -567,8 +549,8 @@ void BlobResourceHandle::notifyResponse()
if (!client())
return;
- if (m_errorCode) {
- Ref<BlobResourceHandle> protect(*this);
+ if (m_errorCode != Error::NoError) {
+ Ref<BlobResourceHandle> protectedThis(*this);
notifyResponseOnError();
notifyFinish();
} else
@@ -577,38 +559,36 @@ void BlobResourceHandle::notifyResponse()
void BlobResourceHandle::notifyResponseOnSuccess()
{
- bool isRangeRequest = m_rangeOffset != positionNotSpecified;
- ResourceResponse response(firstRequest().url(), m_blobData->contentType(), m_totalRemainingSize, String(), String());
- response.setExpectedContentLength(m_totalRemainingSize);
+ ASSERT(isMainThread());
+
+ bool isRangeRequest = m_rangeOffset != kPositionNotSpecified;
+ ResourceResponse response(firstRequest().url(), m_blobData->contentType(), m_totalRemainingSize, String());
response.setHTTPStatusCode(isRangeRequest ? httpPartialContent : httpOK);
response.setHTTPStatusText(isRangeRequest ? httpPartialContentText : httpOKText);
- if (!m_blobData->contentDisposition().isEmpty())
- response.setHTTPHeaderField("Content-Disposition", m_blobData->contentDisposition());
-
- // BlobResourceHandle cannot be used with downloading, and doesn't even wait for continueDidReceiveResponse.
- // It's currently client's responsibility to know that didReceiveResponseAsync cannot be used to convert a
- // load into a download or blobs.
- if (client()->usesAsyncCallbacks())
- client()->didReceiveResponseAsync(this, response);
- else
- client()->didReceiveResponse(this, response);
+
+ response.setHTTPHeaderField(HTTPHeaderName::ContentType, m_blobData->contentType());
+ response.setHTTPHeaderField(HTTPHeaderName::ContentLength, String::number(m_totalRemainingSize));
+
+ if (isRangeRequest)
+ response.setHTTPHeaderField(HTTPHeaderName::ContentRange, ParsedContentRange(m_rangeOffset, m_rangeEnd, m_totalSize).headerValue());
+ // FIXME: If a resource identified with a blob: URL is a File object, user agents must use that file's name attribute,
+ // as if the response had a Content-Disposition header with the filename parameter set to the File's name attribute.
+ // Notably, this will affect a name suggested in "File Save As".
+
+ didReceiveResponse(WTFMove(response));
}
void BlobResourceHandle::notifyResponseOnError()
{
- ASSERT(m_errorCode);
+ ASSERT(m_errorCode != Error::NoError);
- ResourceResponse response(firstRequest().url(), "text/plain", 0, String(), String());
+ ResourceResponse response(firstRequest().url(), "text/plain", 0, String());
switch (m_errorCode) {
- case rangeError:
+ case Error::RangeError:
response.setHTTPStatusCode(httpRequestedRangeNotSatisfiable);
response.setHTTPStatusText(httpRequestedRangeNotSatisfiableText);
break;
- case notFoundError:
- response.setHTTPStatusCode(httpNotFound);
- response.setHTTPStatusText(httpNotFoundText);
- break;
- case securityError:
+ case Error::SecurityError:
response.setHTTPStatusCode(httpNotAllowed);
response.setHTTPStatusText(httpNotAllowedText);
break;
@@ -618,12 +598,7 @@ void BlobResourceHandle::notifyResponseOnError()
break;
}
- // Note that we don't wait for continueDidReceiveResponse when using didReceiveResponseAsync.
- // This is not formally correct, but the client has to be a no-op anyway, because blobs can't be downloaded.
- if (client()->usesAsyncCallbacks())
- client()->didReceiveResponseAsync(this, response);
- else
- client()->didReceiveResponse(this, response);
+ didReceiveResponse(WTFMove(response));
}
void BlobResourceHandle::notifyReceiveData(const char* data, int bytesRead)
@@ -632,37 +607,36 @@ void BlobResourceHandle::notifyReceiveData(const char* data, int bytesRead)
client()->didReceiveBuffer(this, SharedBuffer::create(data, bytesRead), bytesRead);
}
-void BlobResourceHandle::notifyFail(int errorCode)
+void BlobResourceHandle::notifyFail(Error errorCode)
{
if (client())
- client()->didFail(this, ResourceError(webKitBlobResourceDomain, errorCode, firstRequest().url(), String()));
+ client()->didFail(this, ResourceError(webKitBlobResourceDomain, static_cast<int>(errorCode), firstRequest().url(), String()));
}
-static void doNotifyFinish(void* context)
+static void doNotifyFinish(BlobResourceHandle& handle)
{
- BlobResourceHandle* handle = static_cast<BlobResourceHandle*>(context);
- if (!handle->aborted() && handle->client())
- handle->client()->didFinishLoading(handle, 0);
+ if (handle.aborted())
+ return;
- // Balance the ref() in BlobResourceHandle::notfyFinish().
- handle->deref();
+ if (!handle.client())
+ return;
+
+ handle.client()->didFinishLoading(&handle, 0);
}
void BlobResourceHandle::notifyFinish()
{
- // Balanced in doNotifyFinish().
- ref();
-
- if (m_async) {
- // Schedule to notify the client from a standalone function because the client might dispose the handle immediately from the callback function
- // while we still have BlobResourceHandle calls in the stack.
- callOnMainThread(doNotifyFinish, this);
+ if (!m_async) {
+ doNotifyFinish(*this);
return;
}
- doNotifyFinish(this);
+ // Schedule to notify the client from a standalone function because the client might dispose the handle immediately from the callback function
+ // while we still have BlobResourceHandle calls in the stack.
+ callOnMainThread([protectedThis = makeRef(*this)]() mutable {
+ doNotifyFinish(protectedThis);
+ });
+
}
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
diff --git a/Source/WebCore/platform/network/BlobResourceHandle.h b/Source/WebCore/platform/network/BlobResourceHandle.h
index 0ec849b00..f88217e34 100644
--- a/Source/WebCore/platform/network/BlobResourceHandle.h
+++ b/Source/WebCore/platform/network/BlobResourceHandle.h
@@ -28,56 +28,60 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BlobResourceHandle_h
-#define BlobResourceHandle_h
-
-#if ENABLE(BLOB)
+#pragma once
#include "FileStreamClient.h"
#include "ResourceHandle.h"
-#include <wtf/PassRefPtr.h>
#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
class AsyncFileStream;
-class BlobStorageData;
+class BlobData;
class FileStream;
class ResourceHandleClient;
class ResourceRequest;
-struct BlobDataItem;
+class BlobDataItem;
-class BlobResourceHandle : public FileStreamClient, public ResourceHandle {
+class BlobResourceHandle final : public FileStreamClient, public ResourceHandle {
public:
- static PassRefPtr<BlobResourceHandle> createAsync(BlobStorageData*, const ResourceRequest&, ResourceHandleClient*);
-
- static void loadResourceSynchronously(BlobStorageData* blobData, const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data);
-
- // FileStreamClient methods.
- virtual void didGetSize(long long) override;
- virtual void didOpen(bool) override;
- virtual void didRead(int) override;
+ static Ref<BlobResourceHandle> createAsync(BlobData*, const ResourceRequest&, ResourceHandleClient*);
- // ResourceHandle methods.
- virtual void cancel() override;
+ static void loadResourceSynchronously(BlobData*, const ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>& data);
void start();
int readSync(char*, int);
bool aborted() const { return m_aborted; }
-private:
- friend void delayedStartBlobResourceHandle(void*);
+ enum class Error {
+ NoError = 0,
+ NotFoundError = 1,
+ SecurityError = 2,
+ RangeError = 3,
+ NotReadableError = 4,
+ MethodNotAllowed = 5
+ };
- BlobResourceHandle(PassRefPtr<BlobStorageData>, const ResourceRequest&, ResourceHandleClient*, bool async);
+private:
+ BlobResourceHandle(BlobData*, const ResourceRequest&, ResourceHandleClient*, bool async);
virtual ~BlobResourceHandle();
+ // FileStreamClient methods.
+ void didGetSize(long long) override;
+ void didOpen(bool) override;
+ void didRead(int) override;
+
+ // ResourceHandle methods.
+ void cancel() override;
+ void continueDidReceiveResponse() override;
+
void doStart();
void getSizeForNext();
void seek();
void consumeData(const char* data, int bytesRead);
- void failed(int errorCode);
+ void failed(Error);
void readAsync();
void readDataAsync(const BlobDataItem&);
@@ -90,29 +94,30 @@ private:
void notifyResponseOnSuccess();
void notifyResponseOnError();
void notifyReceiveData(const char*, int);
- void notifyFail(int errorCode);
+ void notifyFail(Error);
void notifyFinish();
- RefPtr<BlobStorageData> m_blobData;
+ bool erroredOrAborted() const { return m_aborted || m_errorCode != Error::NoError; }
+
+ enum { kPositionNotSpecified = -1 };
+
+ RefPtr<BlobData> m_blobData;
bool m_async;
- RefPtr<AsyncFileStream> m_asyncStream; // For asynchronous loading.
- RefPtr<FileStream> m_stream; // For synchronous loading.
+ std::unique_ptr<AsyncFileStream> m_asyncStream; // For asynchronous loading.
+ std::unique_ptr<FileStream> m_stream; // For synchronous loading.
Vector<char> m_buffer;
Vector<long long> m_itemLengthList;
- int m_errorCode;
- bool m_aborted;
- long long m_rangeOffset;
- long long m_rangeEnd;
- long long m_rangeSuffixLength;
- long long m_totalRemainingSize;
- long long m_currentItemReadSize;
- unsigned m_sizeItemCount;
- unsigned m_readItemCount;
- bool m_fileOpened;
+ Error m_errorCode { Error::NoError };
+ bool m_aborted { false };
+ long long m_rangeOffset { kPositionNotSpecified };
+ long long m_rangeEnd { kPositionNotSpecified };
+ long long m_rangeSuffixLength { kPositionNotSpecified };
+ long long m_totalSize { 0 };
+ long long m_totalRemainingSize { 0 };
+ long long m_currentItemReadSize { 0 };
+ unsigned m_sizeItemCount { 0 };
+ unsigned m_readItemCount { 0 };
+ bool m_fileOpened { false };
};
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
-
-#endif // BlobResourceHandle_h
diff --git a/Source/WebCore/platform/network/CacheValidation.cpp b/Source/WebCore/platform/network/CacheValidation.cpp
new file mode 100644
index 000000000..bed20e3a4
--- /dev/null
+++ b/Source/WebCore/platform/network/CacheValidation.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CacheValidation.h"
+
+#include "CookiesStrategy.h"
+#include "HTTPHeaderMap.h"
+#include "NetworkStorageSession.h"
+#include "PlatformCookieJar.h"
+#include "PlatformStrategies.h"
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/text/StringView.h>
+
+namespace WebCore {
+
+// These response headers are not copied from a revalidated response to the
+// cached response headers. For compatibility, this list is based on Chromium's
+// net/http/http_response_headers.cc.
+const char* const headersToIgnoreAfterRevalidation[] = {
+ "allow",
+ "connection",
+ "etag",
+ "keep-alive",
+ "last-modified",
+ "proxy-authenticate",
+ "proxy-connection",
+ "trailer",
+ "transfer-encoding",
+ "upgrade",
+ "www-authenticate",
+ "x-frame-options",
+ "x-xss-protection",
+};
+
+// Some header prefixes mean "Don't copy this header from a 304 response.".
+// Rather than listing all the relevant headers, we can consolidate them into
+// this list, also grabbed from Chromium's net/http/http_response_headers.cc.
+const char* const headerPrefixesToIgnoreAfterRevalidation[] = {
+ "content-",
+ "x-content-",
+ "x-webkit-"
+};
+
+static inline bool shouldUpdateHeaderAfterRevalidation(const String& header)
+{
+ for (auto& headerToIgnore : headersToIgnoreAfterRevalidation) {
+ if (equalIgnoringASCIICase(header, headerToIgnore))
+ return false;
+ }
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(headerPrefixesToIgnoreAfterRevalidation); i++) {
+ if (header.startsWith(headerPrefixesToIgnoreAfterRevalidation[i], false))
+ return false;
+ }
+ return true;
+}
+
+void updateResponseHeadersAfterRevalidation(ResourceResponse& response, const ResourceResponse& validatingResponse)
+{
+ // Freshening stored response upon validation:
+ // http://tools.ietf.org/html/rfc7234#section-4.3.4
+ for (const auto& header : validatingResponse.httpHeaderFields()) {
+ // Entity headers should not be sent by servers when generating a 304
+ // response; misconfigured servers send them anyway. We shouldn't allow
+ // such headers to update the original request. We'll base this on the
+ // list defined by RFC2616 7.1, with a few additions for extension headers
+ // we care about.
+ if (!shouldUpdateHeaderAfterRevalidation(header.key))
+ continue;
+ response.setHTTPHeaderField(header.key, header.value);
+ }
+}
+
+std::chrono::microseconds computeCurrentAge(const ResourceResponse& response, std::chrono::system_clock::time_point responseTime)
+{
+ using namespace std::chrono;
+
+ // Age calculation:
+ // http://tools.ietf.org/html/rfc7234#section-4.2.3
+ // No compensation for latency as that is not terribly important in practice.
+ auto dateValue = response.date();
+ auto apparentAge = dateValue ? std::max(0us, duration_cast<microseconds>(responseTime - *dateValue)) : 0us;
+ auto ageValue = response.age().value_or(0us);
+ auto correctedInitialAge = std::max(apparentAge, ageValue);
+ auto residentTime = duration_cast<microseconds>(system_clock::now() - responseTime);
+ return correctedInitialAge + residentTime;
+}
+
+std::chrono::microseconds computeFreshnessLifetimeForHTTPFamily(const ResourceResponse& response, std::chrono::system_clock::time_point responseTime)
+{
+ using namespace std::chrono;
+ ASSERT(response.url().protocolIsInHTTPFamily());
+
+ // Freshness Lifetime:
+ // http://tools.ietf.org/html/rfc7234#section-4.2.1
+ auto maxAge = response.cacheControlMaxAge();
+ if (maxAge)
+ return *maxAge;
+
+ auto date = response.date();
+ auto effectiveDate = date.value_or(responseTime);
+ if (auto expires = response.expires())
+ return duration_cast<microseconds>(*expires - effectiveDate);
+
+ // Implicit lifetime.
+ switch (response.httpStatusCode()) {
+ case 301: // Moved Permanently
+ case 410: // Gone
+ // These are semantically permanent and so get long implicit lifetime.
+ return 365 * 24h;
+ default:
+ // Heuristic Freshness:
+ // http://tools.ietf.org/html/rfc7234#section-4.2.2
+ if (auto lastModified = response.lastModified())
+ return duration_cast<microseconds>((effectiveDate - *lastModified) * 0.1);
+ return 0us;
+ }
+}
+
+void updateRedirectChainStatus(RedirectChainCacheStatus& redirectChainCacheStatus, const ResourceResponse& response)
+{
+ using namespace std::chrono;
+
+ if (redirectChainCacheStatus.status == RedirectChainCacheStatus::NotCachedRedirection)
+ return;
+ if (response.cacheControlContainsNoStore() || response.cacheControlContainsNoCache() || response.cacheControlContainsMustRevalidate()) {
+ redirectChainCacheStatus.status = RedirectChainCacheStatus::NotCachedRedirection;
+ return;
+ }
+
+ redirectChainCacheStatus.status = RedirectChainCacheStatus::CachedRedirection;
+ auto responseTimestamp = system_clock::now();
+ // Store the nearest end of cache validity date
+ auto endOfValidity = responseTimestamp + computeFreshnessLifetimeForHTTPFamily(response, responseTimestamp) - computeCurrentAge(response, responseTimestamp);
+ redirectChainCacheStatus.endOfValidity = std::min(redirectChainCacheStatus.endOfValidity, endOfValidity);
+}
+
+bool redirectChainAllowsReuse(RedirectChainCacheStatus redirectChainCacheStatus, ReuseExpiredRedirectionOrNot reuseExpiredRedirection)
+{
+ switch (redirectChainCacheStatus.status) {
+ case RedirectChainCacheStatus::NoRedirection:
+ return true;
+ case RedirectChainCacheStatus::NotCachedRedirection:
+ return false;
+ case RedirectChainCacheStatus::CachedRedirection:
+ return reuseExpiredRedirection || std::chrono::system_clock::now() <= redirectChainCacheStatus.endOfValidity;
+ }
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+inline bool isCacheHeaderSeparator(UChar c)
+{
+ // http://tools.ietf.org/html/rfc7230#section-3.2.6
+ switch (c) {
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '\\':
+ case '"':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '=':
+ case '{':
+ case '}':
+ case ' ':
+ case '\t':
+ return true;
+ default:
+ return false;
+ }
+}
+
+inline bool isControlCharacterOrSpace(UChar character)
+{
+ return character <= ' ' || character == 127;
+}
+
+inline StringView trimToNextSeparator(StringView string)
+{
+ return string.substring(0, string.find(isCacheHeaderSeparator));
+}
+
+static Vector<std::pair<String, String>> parseCacheHeader(const String& header)
+{
+ Vector<std::pair<String, String>> result;
+
+ String safeHeaderString = header.removeCharacters(isControlCharacterOrSpace);
+ StringView safeHeader = safeHeaderString;
+ unsigned max = safeHeader.length();
+ unsigned pos = 0;
+ while (pos < max) {
+ size_t nextCommaPosition = safeHeader.find(',', pos);
+ size_t nextEqualSignPosition = safeHeader.find('=', pos);
+ if (nextEqualSignPosition == notFound && nextCommaPosition == notFound) {
+ // Add last directive to map with empty string as value
+ result.append({ trimToNextSeparator(safeHeader.substring(pos, max - pos)).toString(), emptyString() });
+ return result;
+ }
+ if (nextCommaPosition != notFound && (nextCommaPosition < nextEqualSignPosition || nextEqualSignPosition == notFound)) {
+ // Add directive to map with empty string as value
+ result.append({ trimToNextSeparator(safeHeader.substring(pos, nextCommaPosition - pos)).toString(), emptyString() });
+ pos += nextCommaPosition - pos + 1;
+ continue;
+ }
+ // Get directive name, parse right hand side of equal sign, then add to map
+ String directive = trimToNextSeparator(safeHeader.substring(pos, nextEqualSignPosition - pos)).toString();
+ pos += nextEqualSignPosition - pos + 1;
+
+ StringView value = safeHeader.substring(pos, max - pos);
+ if (value[0] == '"') {
+ // The value is a quoted string
+ size_t nextDoubleQuotePosition = value.find('"', 1);
+ if (nextDoubleQuotePosition == notFound) {
+ // Parse error; just use the rest as the value
+ result.append({ directive, trimToNextSeparator(value.substring(1)).toString() });
+ return result;
+ }
+ // Store the value as a quoted string without quotes
+ result.append({ directive, value.substring(1, nextDoubleQuotePosition - 1).toString() });
+ pos += (safeHeader.find('"', pos) - pos) + nextDoubleQuotePosition + 1;
+ // Move past next comma, if there is one
+ size_t nextCommaPosition2 = safeHeader.find(',', pos);
+ if (nextCommaPosition2 == notFound)
+ return result; // Parse error if there is anything left with no comma
+ pos += nextCommaPosition2 - pos + 1;
+ continue;
+ }
+ // The value is a token until the next comma
+ size_t nextCommaPosition2 = value.find(',');
+ if (nextCommaPosition2 == notFound) {
+ // The rest is the value; no change to value needed
+ result.append({ directive, trimToNextSeparator(value).toString() });
+ return result;
+ }
+ // The value is delimited by the next comma
+ result.append({ directive, trimToNextSeparator(value.substring(0, nextCommaPosition2)).toString() });
+ pos += (safeHeader.find(',', pos) - pos) + 1;
+ }
+ return result;
+}
+
+CacheControlDirectives parseCacheControlDirectives(const HTTPHeaderMap& headers)
+{
+ using namespace std::chrono;
+
+ CacheControlDirectives result;
+
+ String cacheControlValue = headers.get(HTTPHeaderName::CacheControl);
+ if (!cacheControlValue.isEmpty()) {
+ auto directives = parseCacheHeader(cacheControlValue);
+
+ size_t directivesSize = directives.size();
+ for (size_t i = 0; i < directivesSize; ++i) {
+ // A no-cache directive with a value is only meaningful for proxy caches.
+ // It should be ignored by a browser level cache.
+ // http://tools.ietf.org/html/rfc7234#section-5.2.2.2
+ if (equalLettersIgnoringASCIICase(directives[i].first, "no-cache") && directives[i].second.isEmpty())
+ result.noCache = true;
+ else if (equalLettersIgnoringASCIICase(directives[i].first, "no-store"))
+ result.noStore = true;
+ else if (equalLettersIgnoringASCIICase(directives[i].first, "must-revalidate"))
+ result.mustRevalidate = true;
+ else if (equalLettersIgnoringASCIICase(directives[i].first, "max-age")) {
+ if (result.maxAge) {
+ // First max-age directive wins if there are multiple ones.
+ continue;
+ }
+ bool ok;
+ double maxAge = directives[i].second.toDouble(&ok);
+ if (ok)
+ result.maxAge = duration_cast<microseconds>(duration<double>(maxAge));
+ } else if (equalLettersIgnoringASCIICase(directives[i].first, "max-stale")) {
+ // https://tools.ietf.org/html/rfc7234#section-5.2.1.2
+ if (result.maxStale) {
+ // First max-stale directive wins if there are multiple ones.
+ continue;
+ }
+ if (directives[i].second.isEmpty()) {
+ // if no value is assigned to max-stale, then the client is willing to accept a stale response of any age.
+ result.maxStale = microseconds::max();
+ continue;
+ }
+ bool ok;
+ double maxStale = directives[i].second.toDouble(&ok);
+ if (ok)
+ result.maxStale = duration_cast<microseconds>(duration<double>(maxStale));
+ } else if (equalLettersIgnoringASCIICase(directives[i].first, "immutable"))
+ result.immutable = true;
+ }
+ }
+
+ if (!result.noCache) {
+ // Handle Pragma: no-cache
+ // This is deprecated and equivalent to Cache-control: no-cache
+ // Don't bother tokenizing the value, it is not important
+ String pragmaValue = headers.get(HTTPHeaderName::Pragma);
+
+ result.noCache = pragmaValue.contains("no-cache", false);
+ }
+
+ return result;
+}
+
+static String headerValueForVary(const ResourceRequest& request, const String& headerName, SessionID sessionID)
+{
+ // Explicit handling for cookies is needed because they are added magically by the networking layer.
+ // FIXME: The value might have changed between making the request and retrieving the cookie here.
+ // We could fetch the cookie when making the request but that seems overkill as the case is very rare and it
+ // is a blocking operation. This should be sufficient to cover reasonable cases.
+ if (headerName == httpHeaderNameString(HTTPHeaderName::Cookie)) {
+ auto* cookieStrategy = platformStrategies() ? platformStrategies()->cookiesStrategy() : nullptr;
+ if (!cookieStrategy) {
+ ASSERT(sessionID == SessionID::defaultSessionID());
+ return cookieRequestHeaderFieldValue(NetworkStorageSession::defaultStorageSession(), request.firstPartyForCookies(), request.url());
+ }
+ return cookieStrategy->cookieRequestHeaderFieldValue(sessionID, request.firstPartyForCookies(), request.url());
+ }
+ return request.httpHeaderField(headerName);
+}
+
+Vector<std::pair<String, String>> collectVaryingRequestHeaders(const WebCore::ResourceRequest& request, const WebCore::ResourceResponse& response, SessionID sessionID)
+{
+ String varyValue = response.httpHeaderField(WebCore::HTTPHeaderName::Vary);
+ if (varyValue.isEmpty())
+ return { };
+ Vector<String> varyingHeaderNames;
+ varyValue.split(',', /*allowEmptyEntries*/ false, varyingHeaderNames);
+ Vector<std::pair<String, String>> varyingRequestHeaders;
+ varyingRequestHeaders.reserveCapacity(varyingHeaderNames.size());
+ for (auto& varyHeaderName : varyingHeaderNames) {
+ String headerName = varyHeaderName.stripWhiteSpace();
+ String headerValue = headerValueForVary(request, headerName, sessionID);
+ varyingRequestHeaders.append(std::make_pair(headerName, headerValue));
+ }
+ return varyingRequestHeaders;
+}
+
+bool verifyVaryingRequestHeaders(const Vector<std::pair<String, String>>& varyingRequestHeaders, const WebCore::ResourceRequest& request, SessionID sessionID)
+{
+ for (auto& varyingRequestHeader : varyingRequestHeaders) {
+ // FIXME: Vary: * in response would ideally trigger a cache delete instead of a store.
+ if (varyingRequestHeader.first == "*")
+ return false;
+ String headerValue = headerValueForVary(request, varyingRequestHeader.first, sessionID);
+ if (headerValue != varyingRequestHeader.second)
+ return false;
+ }
+ return true;
+}
+
+// http://tools.ietf.org/html/rfc7231#page-48
+bool isStatusCodeCacheableByDefault(int statusCode)
+{
+ switch (statusCode) {
+ case 200: // OK
+ case 203: // Non-Authoritative Information
+ case 204: // No Content
+ case 206: // Partial Content
+ case 300: // Multiple Choices
+ case 301: // Moved Permanently
+ case 404: // Not Found
+ case 405: // Method Not Allowed
+ case 410: // Gone
+ case 414: // URI Too Long
+ case 501: // Not Implemented
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool isStatusCodePotentiallyCacheable(int statusCode)
+{
+ switch (statusCode) {
+ case 201: // Created
+ case 202: // Accepted
+ case 205: // Reset Content
+ case 302: // Found
+ case 303: // See Other
+ case 307: // Temporary redirect
+ case 403: // Forbidden
+ case 406: // Not Acceptable
+ case 415: // Unsupported Media Type
+ return true;
+ default:
+ return false;
+ }
+}
+
+}
diff --git a/Source/WebCore/platform/network/CacheValidation.h b/Source/WebCore/platform/network/CacheValidation.h
new file mode 100644
index 000000000..bd03c5137
--- /dev/null
+++ b/Source/WebCore/platform/network/CacheValidation.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CacheValidation_h
+#define CacheValidation_h
+
+#include "PlatformExportMacros.h"
+#include "SessionID.h"
+#include <wtf/Optional.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class HTTPHeaderMap;
+class ResourceRequest;
+class ResourceResponse;
+
+struct RedirectChainCacheStatus {
+ enum Status {
+ NoRedirection,
+ NotCachedRedirection,
+ CachedRedirection
+ };
+ RedirectChainCacheStatus()
+ : status(NoRedirection)
+ , endOfValidity(std::chrono::system_clock::time_point::max())
+ { }
+ Status status;
+ std::chrono::system_clock::time_point endOfValidity;
+};
+
+WEBCORE_EXPORT std::chrono::microseconds computeCurrentAge(const ResourceResponse&, std::chrono::system_clock::time_point responseTimestamp);
+WEBCORE_EXPORT std::chrono::microseconds computeFreshnessLifetimeForHTTPFamily(const ResourceResponse&, std::chrono::system_clock::time_point responseTimestamp);
+WEBCORE_EXPORT void updateResponseHeadersAfterRevalidation(ResourceResponse&, const ResourceResponse& validatingResponse);
+WEBCORE_EXPORT void updateRedirectChainStatus(RedirectChainCacheStatus&, const ResourceResponse&);
+
+enum ReuseExpiredRedirectionOrNot { DoNotReuseExpiredRedirection, ReuseExpiredRedirection };
+WEBCORE_EXPORT bool redirectChainAllowsReuse(RedirectChainCacheStatus, ReuseExpiredRedirectionOrNot);
+
+struct CacheControlDirectives {
+ std::optional<std::chrono::microseconds> maxAge;
+ std::optional<std::chrono::microseconds> maxStale;
+ bool noCache { false };
+ bool noStore { false };
+ bool mustRevalidate { false };
+ bool immutable { false };
+};
+WEBCORE_EXPORT CacheControlDirectives parseCacheControlDirectives(const HTTPHeaderMap&);
+
+WEBCORE_EXPORT Vector<std::pair<String, String>> collectVaryingRequestHeaders(const ResourceRequest&, const ResourceResponse&, SessionID = SessionID::defaultSessionID());
+WEBCORE_EXPORT bool verifyVaryingRequestHeaders(const Vector<std::pair<String, String>>& varyingRequestHeaders, const ResourceRequest&, SessionID = SessionID::defaultSessionID());
+
+WEBCORE_EXPORT bool isStatusCodeCacheableByDefault(int statusCode);
+WEBCORE_EXPORT bool isStatusCodePotentiallyCacheable(int statusCode);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/network/CookieStorage.h b/Source/WebCore/platform/network/CookieStorage.h
index 1c6947718..c5053cc90 100644
--- a/Source/WebCore/platform/network/CookieStorage.h
+++ b/Source/WebCore/platform/network/CookieStorage.h
@@ -23,17 +23,16 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CookieStorage_h
-#define CookieStorage_h
+#pragma once
+
+#include <functional>
namespace WebCore {
-// These are always observing the shared cookie storage, even when in private browsing mode.
+class NetworkStorageSession;
-typedef void(*CookieChangeCallbackPtr)();
-void startObservingCookieChanges(CookieChangeCallbackPtr);
-void stopObservingCookieChanges();
+WEBCORE_EXPORT void startObservingCookieChanges(const NetworkStorageSession&, std::function<void ()>&&);
+WEBCORE_EXPORT void stopObservingCookieChanges(const NetworkStorageSession&);
}
-#endif
diff --git a/Source/WebCore/platform/network/Credential.cpp b/Source/WebCore/platform/network/Credential.cpp
deleted file mode 100644
index 4b2440305..000000000
--- a/Source/WebCore/platform/network/Credential.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "config.h"
-#include "Credential.h"
-
-namespace WebCore {
-
-// Need to enforce empty, non-null strings due to the pickiness of the String == String operator
-// combined with the semantics of the String(NSString*) constructor
-Credential::Credential()
- : m_user("")
- , m_password("")
- , m_persistence(CredentialPersistenceNone)
-#if CERTIFICATE_CREDENTIALS_SUPPORTED
- , m_type(CredentialTypePassword)
-#endif
-{
-}
-
-// Need to enforce empty, non-null strings due to the pickiness of the String == String operator
-// combined with the semantics of the String(NSString*) constructor
-Credential::Credential(const String& user, const String& password, CredentialPersistence persistence)
- : m_user(user.length() ? user : "")
- , m_password(password.length() ? password : "")
- , m_persistence(persistence)
-#if CERTIFICATE_CREDENTIALS_SUPPORTED
- , m_type(CredentialTypePassword)
-#endif
-{
-}
-
-Credential::Credential(const Credential& original, CredentialPersistence persistence)
- : m_user(original.user())
- , m_password(original.password())
- , m_persistence(persistence)
-#if CERTIFICATE_CREDENTIALS_SUPPORTED
- , m_identity(original.identity())
- , m_certificates(original.certificates())
- , m_type(original.type())
-#endif
-{
-}
-
-bool Credential::isEmpty() const
-{
-#if CERTIFICATE_CREDENTIALS_SUPPORTED
- if (m_type == CredentialTypeClientCertificate && (m_identity || m_certificates))
- return false;
-#endif
-
- return m_user.isEmpty() && m_password.isEmpty();
-}
-
-const String& Credential::user() const
-{
- return m_user;
-}
-
-const String& Credential::password() const
-{
- return m_password;
-}
-
-bool Credential::hasPassword() const
-{
- return !m_password.isEmpty();
-}
-
-CredentialPersistence Credential::persistence() const
-{
- return m_persistence;
-}
-
-#if CERTIFICATE_CREDENTIALS_SUPPORTED
-Credential::Credential(SecIdentityRef identity, CFArrayRef certificates, CredentialPersistence persistence)
- : m_user("")
- , m_password("")
- , m_persistence(persistence)
- , m_identity(identity)
- , m_certificates(certificates)
- , m_type(CredentialTypeClientCertificate)
-{
-}
-
-SecIdentityRef Credential::identity() const
-{
- return m_identity.get();
-}
-
-CFArrayRef Credential::certificates() const
-{
- return m_certificates.get();
-}
-
-CredentialType Credential::type() const
-{
- return m_type;
-}
-#endif
-
-bool operator==(const Credential& a, const Credential& b)
-{
- // Check persistence first since all credential types
- // have the persistence property.
- if (a.persistence() != b.persistence())
- return false;
-
-#if CERTIFICATE_CREDENTIALS_SUPPORTED
- CredentialType aType = a.type();
- if (aType != b.type())
- return false;
-
- // Comparing identity and certificate chain pointers is valid only
- // for client certificate type credentials.
- //
- // FIXME: Is pointer comparison of the identity and certificates properties sufficient?
- if (aType == CredentialTypeClientCertificate) {
- if (a.identity() != b.identity())
- return false;
- if (a.certificates() != b.certificates())
- return false;
-
- // We only need to check identity and certificates to compare
- // client certificate based credentials.
- return true;
- }
-
- ASSERT(a.type() == CredentialTypePassword && b.type() == CredentialTypePassword);
-#endif
-
- if (a.user() != b.user())
- return false;
- if (a.password() != b.password())
- return false;
-
- return true;
-}
-
-}
-
diff --git a/Source/WebCore/platform/network/Credential.h b/Source/WebCore/platform/network/Credential.h
index 2166b9bfa..b0fb0dcd7 100644
--- a/Source/WebCore/platform/network/Credential.h
+++ b/Source/WebCore/platform/network/Credential.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -22,69 +22,40 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
#ifndef Credential_h
#define Credential_h
-#include <wtf/text/WTFString.h>
+#include <wtf/Platform.h>
-#define CERTIFICATE_CREDENTIALS_SUPPORTED (PLATFORM(IOS) || PLATFORM(MAC))
+#if PLATFORM(COCOA)
+#include "CredentialCocoa.h"
+#else
-#if CERTIFICATE_CREDENTIALS_SUPPORTED
-#include <Security/SecBase.h>
-#include <wtf/RetainPtr.h>
-#endif
+#include "CredentialBase.h"
namespace WebCore {
-enum CredentialPersistence {
- CredentialPersistenceNone,
- CredentialPersistenceForSession,
- CredentialPersistencePermanent
-};
-
-#if CERTIFICATE_CREDENTIALS_SUPPORTED
-enum CredentialType {
- CredentialTypePassword,
- CredentialTypeClientCertificate
+class Credential : public CredentialBase {
+public:
+ Credential()
+ : CredentialBase()
+ {
+ }
+
+ Credential(const String& user, const String& password, CredentialPersistence persistence)
+ : CredentialBase(user, password, persistence)
+ {
+ }
+
+ Credential(const Credential& original, CredentialPersistence persistence)
+ : CredentialBase(original, persistence)
+ {
+ }
};
-#endif
-class Credential {
+}
-public:
- Credential();
- Credential(const String& user, const String& password, CredentialPersistence);
- Credential(const Credential& original, CredentialPersistence);
-#if CERTIFICATE_CREDENTIALS_SUPPORTED
- Credential(SecIdentityRef identity, CFArrayRef certificates, CredentialPersistence);
-#endif
-
- bool isEmpty() const;
-
- const String& user() const;
- const String& password() const;
- bool hasPassword() const;
- CredentialPersistence persistence() const;
-
-#if CERTIFICATE_CREDENTIALS_SUPPORTED
- SecIdentityRef identity() const;
- CFArrayRef certificates() const;
- CredentialType type() const;
-#endif
-
-private:
- String m_user;
- String m_password;
- CredentialPersistence m_persistence;
-#if CERTIFICATE_CREDENTIALS_SUPPORTED
- RetainPtr<SecIdentityRef> m_identity;
- RetainPtr<CFArrayRef> m_certificates;
- CredentialType m_type;
#endif
-};
-bool operator==(const Credential& a, const Credential& b);
-inline bool operator!=(const Credential& a, const Credential& b) { return !(a == b); }
-
-};
-#endif
+#endif // Credential_h
diff --git a/Source/WebCore/platform/network/CredentialBase.cpp b/Source/WebCore/platform/network/CredentialBase.cpp
new file mode 100644
index 000000000..435a99cf1
--- /dev/null
+++ b/Source/WebCore/platform/network/CredentialBase.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CredentialBase.h"
+
+#include "Credential.h"
+
+namespace WebCore {
+
+// Need to enforce empty, non-null strings due to the pickiness of the String == String operator
+// combined with the semantics of the String(NSString*) constructor
+CredentialBase::CredentialBase()
+ : m_user(emptyString())
+ , m_password(emptyString())
+ , m_persistence(CredentialPersistenceNone)
+{
+}
+
+// Need to enforce empty, non-null strings due to the pickiness of the String == String operator
+// combined with the semantics of the String(NSString*) constructor
+CredentialBase::CredentialBase(const String& user, const String& password, CredentialPersistence persistence)
+ : m_user(user.length() ? user : emptyString())
+ , m_password(password.length() ? password : emptyString())
+ , m_persistence(persistence)
+{
+}
+
+CredentialBase::CredentialBase(const Credential& original, CredentialPersistence persistence)
+ : m_user(original.user())
+ , m_password(original.password())
+ , m_persistence(persistence)
+{
+}
+
+bool CredentialBase::isEmpty() const
+{
+ return m_user.isEmpty() && m_password.isEmpty();
+}
+
+const String& CredentialBase::user() const
+{
+ return m_user;
+}
+
+const String& CredentialBase::password() const
+{
+ return m_password;
+}
+
+bool CredentialBase::hasPassword() const
+{
+ return !m_password.isEmpty();
+}
+
+CredentialPersistence CredentialBase::persistence() const
+{
+ return m_persistence;
+}
+
+bool CredentialBase::compare(const Credential& a, const Credential& b)
+{
+ // Check persistence first since all credential types
+ // have the persistence property.
+ if (a.persistence() != b.persistence())
+ return false;
+ if (a.user() != b.user())
+ return false;
+ if (a.password() != b.password())
+ return false;
+
+ return Credential::platformCompare(a, b);
+}
+
+}
diff --git a/Source/WebCore/platform/network/CredentialBase.h b/Source/WebCore/platform/network/CredentialBase.h
new file mode 100644
index 000000000..8fb49716d
--- /dev/null
+++ b/Source/WebCore/platform/network/CredentialBase.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CredentialBase_h
+#define CredentialBase_h
+
+#include "PlatformExportMacros.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class Credential;
+
+enum CredentialPersistence {
+ CredentialPersistenceNone,
+ CredentialPersistenceForSession,
+ CredentialPersistencePermanent
+};
+
+class CredentialBase {
+
+public:
+ bool isEmpty() const;
+
+ WEBCORE_EXPORT const String& user() const;
+ WEBCORE_EXPORT const String& password() const;
+ WEBCORE_EXPORT bool hasPassword() const;
+ WEBCORE_EXPORT CredentialPersistence persistence() const;
+
+ bool encodingRequiresPlatformData() const { return false; }
+
+ WEBCORE_EXPORT static bool compare(const Credential&, const Credential&);
+
+protected:
+ WEBCORE_EXPORT CredentialBase();
+ WEBCORE_EXPORT CredentialBase(const String& user, const String& password, CredentialPersistence);
+ CredentialBase(const Credential& original, CredentialPersistence);
+
+ static bool platformCompare(const Credential&, const Credential&) { return true; }
+
+private:
+ String m_user;
+ String m_password;
+ CredentialPersistence m_persistence;
+};
+
+inline bool operator==(const Credential& a, const Credential& b) { return CredentialBase::compare(a, b); }
+inline bool operator!=(const Credential& a, const Credential& b) { return !(a == b); }
+
+};
+
+#endif
diff --git a/Source/WebCore/platform/network/CredentialStorage.cpp b/Source/WebCore/platform/network/CredentialStorage.cpp
index d86fd81c4..4ae98a66f 100644
--- a/Source/WebCore/platform/network/CredentialStorage.cpp
+++ b/Source/WebCore/platform/network/CredentialStorage.cpp
@@ -26,15 +26,8 @@
#include "config.h"
#include "CredentialStorage.h"
-#include "Credential.h"
+#include "NetworkStorageSession.h"
#include "URL.h"
-#include "ProtectionSpaceHash.h"
-#include <wtf/text/WTFString.h>
-#include <wtf/text/StringHash.h>
-#include <wtf/HashMap.h>
-#include <wtf/HashSet.h>
-#include <wtf/MainThread.h>
-#include <wtf/StdLibExtras.h>
#if PLATFORM(IOS)
#include "WebCoreThread.h"
@@ -42,35 +35,14 @@
namespace WebCore {
-typedef HashMap<ProtectionSpace, Credential> ProtectionSpaceToCredentialMap;
-static ProtectionSpaceToCredentialMap& protectionSpaceToCredentialMap()
+CredentialStorage& CredentialStorage::defaultCredentialStorage()
{
- ASSERT(isMainThread());
- DEFINE_STATIC_LOCAL(ProtectionSpaceToCredentialMap, map, ());
- return map;
-}
-
-static HashSet<String>& originsWithCredentials()
-{
- ASSERT(isMainThread());
- DEFINE_STATIC_LOCAL(HashSet<String>, set, ());
- return set;
-}
-
-typedef HashMap<String, ProtectionSpace> PathToDefaultProtectionSpaceMap;
-static PathToDefaultProtectionSpaceMap& pathToDefaultProtectionSpaceMap()
-{
- ASSERT(isMainThread());
- DEFINE_STATIC_LOCAL(PathToDefaultProtectionSpaceMap, map, ());
- return map;
+ return NetworkStorageSession::defaultStorageSession().credentialStorage();
}
static String originStringFromURL(const URL& url)
{
- if (url.port())
- return url.protocol() + "://" + url.host() + ':' + String::number(url.port()) + '/';
-
- return url.protocol() + "://" + url.host() + '/';
+ return makeString(url.protocol(), "://", url.hostAndPort(), '/');
}
static String protectionSpaceMapKeyFromURL(const URL& url)
@@ -91,100 +63,90 @@ static String protectionSpaceMapKeyFromURL(const URL& url)
return directoryURL;
}
-void CredentialStorage::set(const Credential& credential, const ProtectionSpace& protectionSpace, const URL& url)
+void CredentialStorage::set(const String& partitionName, const Credential& credential, const ProtectionSpace& protectionSpace, const URL& url)
{
- ASSERT(protectionSpace.isProxy() || url.protocolIsInHTTPFamily());
- ASSERT(protectionSpace.isProxy() || url.isValid());
+ ASSERT(protectionSpace.isProxy() || protectionSpace.authenticationScheme() == ProtectionSpaceAuthenticationSchemeClientCertificateRequested || url.protocolIsInHTTPFamily());
+ ASSERT(protectionSpace.isProxy() || protectionSpace.authenticationScheme() == ProtectionSpaceAuthenticationSchemeClientCertificateRequested || url.isValid());
- protectionSpaceToCredentialMap().set(protectionSpace, credential);
+ m_protectionSpaceToCredentialMap.set(std::make_pair(partitionName, protectionSpace), credential);
#if PLATFORM(IOS)
- saveToPersistentStorage(protectionSpace, credential);
+ if (protectionSpace.authenticationScheme() != ProtectionSpaceAuthenticationSchemeClientCertificateRequested)
+ saveToPersistentStorage(protectionSpace, credential);
#endif
- if (!protectionSpace.isProxy()) {
- originsWithCredentials().add(originStringFromURL(url));
+ if (!protectionSpace.isProxy() && protectionSpace.authenticationScheme() != ProtectionSpaceAuthenticationSchemeClientCertificateRequested) {
+ m_originsWithCredentials.add(originStringFromURL(url));
ProtectionSpaceAuthenticationScheme scheme = protectionSpace.authenticationScheme();
if (scheme == ProtectionSpaceAuthenticationSchemeHTTPBasic || scheme == ProtectionSpaceAuthenticationSchemeDefault) {
// The map can contain both a path and its subpath - while redundant, this makes lookups faster.
- pathToDefaultProtectionSpaceMap().set(protectionSpaceMapKeyFromURL(url), protectionSpace);
+ m_pathToDefaultProtectionSpaceMap.set(protectionSpaceMapKeyFromURL(url), protectionSpace);
}
}
}
-Credential CredentialStorage::get(const ProtectionSpace& protectionSpace)
+Credential CredentialStorage::get(const String& partitionName, const ProtectionSpace& protectionSpace)
{
- return protectionSpaceToCredentialMap().get(protectionSpace);
+ return m_protectionSpaceToCredentialMap.get(std::make_pair(partitionName, protectionSpace));
}
-void CredentialStorage::remove(const ProtectionSpace& protectionSpace)
+void CredentialStorage::remove(const String& partitionName, const ProtectionSpace& protectionSpace)
{
- protectionSpaceToCredentialMap().remove(protectionSpace);
+ m_protectionSpaceToCredentialMap.remove(std::make_pair(partitionName, protectionSpace));
}
-static PathToDefaultProtectionSpaceMap::iterator findDefaultProtectionSpaceForURL(const URL& url)
+HashMap<String, ProtectionSpace>::iterator CredentialStorage::findDefaultProtectionSpaceForURL(const URL& url)
{
ASSERT(url.protocolIsInHTTPFamily());
ASSERT(url.isValid());
- PathToDefaultProtectionSpaceMap& map = pathToDefaultProtectionSpaceMap();
-
// Don't spend time iterating the path for origins that don't have any credentials.
- if (!originsWithCredentials().contains(originStringFromURL(url)))
- return map.end();
+ if (!m_originsWithCredentials.contains(originStringFromURL(url)))
+ return m_pathToDefaultProtectionSpaceMap.end();
String directoryURL = protectionSpaceMapKeyFromURL(url);
unsigned directoryURLPathStart = url.pathStart();
while (true) {
- PathToDefaultProtectionSpaceMap::iterator iter = map.find(directoryURL);
- if (iter != map.end())
+ PathToDefaultProtectionSpaceMap::iterator iter = m_pathToDefaultProtectionSpaceMap.find(directoryURL);
+ if (iter != m_pathToDefaultProtectionSpaceMap.end())
return iter;
if (directoryURL.length() == directoryURLPathStart + 1) // path is "/" already, cannot shorten it any more
- return map.end();
+ return m_pathToDefaultProtectionSpaceMap.end();
size_t index = directoryURL.reverseFind('/', directoryURL.length() - 2);
ASSERT(index != notFound);
directoryURL = directoryURL.substring(0, (index == directoryURLPathStart) ? index + 1 : index);
ASSERT(directoryURL.length() > directoryURLPathStart);
- ASSERT(directoryURL.length() == directoryURLPathStart + 1 || directoryURL[directoryURL.length() - 1] != '/');
}
}
-bool CredentialStorage::set(const Credential& credential, const URL& url)
+bool CredentialStorage::set(const String& partitionName, const Credential& credential, const URL& url)
{
ASSERT(url.protocolIsInHTTPFamily());
ASSERT(url.isValid());
PathToDefaultProtectionSpaceMap::iterator iter = findDefaultProtectionSpaceForURL(url);
- if (iter == pathToDefaultProtectionSpaceMap().end())
+ if (iter == m_pathToDefaultProtectionSpaceMap.end())
return false;
- ASSERT(originsWithCredentials().contains(originStringFromURL(url)));
- protectionSpaceToCredentialMap().set(iter->value, credential);
+ ASSERT(m_originsWithCredentials.contains(originStringFromURL(url)));
+ m_protectionSpaceToCredentialMap.set(std::make_pair(partitionName, iter->value), credential);
return true;
}
-Credential CredentialStorage::get(const URL& url)
+Credential CredentialStorage::get(const String& partitionName, const URL& url)
{
PathToDefaultProtectionSpaceMap::iterator iter = findDefaultProtectionSpaceForURL(url);
- if (iter == pathToDefaultProtectionSpaceMap().end())
+ if (iter == m_pathToDefaultProtectionSpaceMap.end())
return Credential();
- return protectionSpaceToCredentialMap().get(iter->value);
+ return m_protectionSpaceToCredentialMap.get(std::make_pair(partitionName, iter->value));
}
-#if PLATFORM(IOS)
void CredentialStorage::clearCredentials()
{
- pathToDefaultProtectionSpaceMap().clear();
- originsWithCredentials().clear();
- protectionSpaceToCredentialMap().clear();
-}
-#endif
-
-void CredentialStorage::setPrivateMode(bool mode)
-{
- if (!mode)
- protectionSpaceToCredentialMap().clear();
+ m_protectionSpaceToCredentialMap.clear();
+ m_originsWithCredentials.clear();
+ m_pathToDefaultProtectionSpaceMap.clear();
}
} // namespace WebCore
diff --git a/Source/WebCore/platform/network/CredentialStorage.h b/Source/WebCore/platform/network/CredentialStorage.h
index 3c8c74875..8280caeae 100644
--- a/Source/WebCore/platform/network/CredentialStorage.h
+++ b/Source/WebCore/platform/network/CredentialStorage.h
@@ -26,33 +26,49 @@
#ifndef CredentialStorage_h
#define CredentialStorage_h
+#include "Credential.h"
+#include "ProtectionSpaceHash.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
namespace WebCore {
-class Credential;
class URL;
class ProtectionSpace;
class CredentialStorage {
public:
+ WEBCORE_EXPORT static CredentialStorage& defaultCredentialStorage();
+
// WebCore session credential storage.
- static void set(const Credential&, const ProtectionSpace&, const URL&);
- static Credential get(const ProtectionSpace&);
- static void remove(const ProtectionSpace&);
+ WEBCORE_EXPORT void set(const String&, const Credential&, const ProtectionSpace&, const URL&);
+ WEBCORE_EXPORT Credential get(const String&, const ProtectionSpace&);
+ WEBCORE_EXPORT void remove(const String&, const ProtectionSpace&);
// OS persistent storage.
- static Credential getFromPersistentStorage(const ProtectionSpace&);
+ WEBCORE_EXPORT Credential getFromPersistentStorage(const ProtectionSpace&);
+
+ WEBCORE_EXPORT void clearCredentials();
#if PLATFORM(IOS)
- static void saveToPersistentStorage(const ProtectionSpace&, const Credential&);
- static void clearCredentials();
+ void saveToPersistentStorage(const ProtectionSpace&, const Credential&);
#endif
// These methods work for authentication schemes that support sending credentials without waiting for a request. E.g., for HTTP Basic authentication scheme
// a client should assume that all paths at or deeper than the depth of a known protected resource share are within the same protection space.
- static bool set(const Credential&, const URL&); // Returns true if the URL corresponds to a known protection space, so credentials could be updated.
- static Credential get(const URL&);
+ WEBCORE_EXPORT bool set(const String&, const Credential&, const URL&); // Returns true if the URL corresponds to a known protection space, so credentials could be updated.
+ WEBCORE_EXPORT Credential get(const String&, const URL&);
+
+private:
+ HashMap<std::pair<String /* partitionName */, ProtectionSpace>, Credential> m_protectionSpaceToCredentialMap;
+ HashSet<String> m_originsWithCredentials;
+
+ typedef HashMap<String, ProtectionSpace> PathToDefaultProtectionSpaceMap;
+ PathToDefaultProtectionSpaceMap m_pathToDefaultProtectionSpaceMap;
- static void setPrivateMode(bool);
+ PathToDefaultProtectionSpaceMap::iterator findDefaultProtectionSpaceForURL(const URL&);
};
} // namespace WebCore
diff --git a/Source/WebCore/platform/network/DNS.h b/Source/WebCore/platform/network/DNS.h
index c6b748db8..290f40634 100644
--- a/Source/WebCore/platform/network/DNS.h
+++ b/Source/WebCore/platform/network/DNS.h
@@ -13,7 +13,7 @@
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -30,7 +30,7 @@
namespace WebCore {
-void prefetchDNS(const String& hostname);
+WEBCORE_EXPORT void prefetchDNS(const String& hostname);
}
#endif
diff --git a/Source/WebCore/platform/network/DNSResolveQueue.cpp b/Source/WebCore/platform/network/DNSResolveQueue.cpp
index cb051dcef..58773aa33 100644
--- a/Source/WebCore/platform/network/DNSResolveQueue.cpp
+++ b/Source/WebCore/platform/network/DNSResolveQueue.cpp
@@ -14,7 +14,7 @@
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -50,7 +50,7 @@ static const int gMaxRequestsToQueue = 64;
// If there were queued names that couldn't be sent simultaneously, check the state of resolvers after this delay.
static const double gRetryResolvingInSeconds = 0.1;
-DNSResolveQueue& DNSResolveQueue::shared()
+DNSResolveQueue& DNSResolveQueue::singleton()
{
static NeverDestroyed<DNSResolveQueue> queue;
@@ -58,22 +58,29 @@ DNSResolveQueue& DNSResolveQueue::shared()
}
DNSResolveQueue::DNSResolveQueue()
- : m_timer(this, &DNSResolveQueue::timerFired)
+ : m_timer(*this, &DNSResolveQueue::timerFired)
, m_requestsInFlight(0)
- , m_cachedProxyEnabledStatus(false)
+ , m_isUsingProxy(true)
, m_lastProxyEnabledStatusCheckTime(0)
{
+ // isUsingProxy will return the initial value of m_isUsingProxy at first on
+ // platforms that have an asynchronous implementation of updateIsUsingProxy,
+ // so initialize it to true so we won't prefetch before we know if we are using a proxy.
}
+// 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.
bool DNSResolveQueue::isUsingProxy()
{
double time = monotonicallyIncreasingTime();
static const double minimumProxyCheckDelay = 5;
if (time - m_lastProxyEnabledStatusCheckTime > minimumProxyCheckDelay) {
m_lastProxyEnabledStatusCheckTime = time;
- m_cachedProxyEnabledStatus = platformProxyIsEnabledInSystemPreferences();
+ updateIsUsingProxy();
}
- return m_cachedProxyEnabledStatus;
+ return m_isUsingProxy;
}
void DNSResolveQueue::add(const String& hostname)
@@ -98,7 +105,7 @@ void DNSResolveQueue::add(const String& hostname)
}
}
-void DNSResolveQueue::timerFired(Timer<DNSResolveQueue>&)
+void DNSResolveQueue::timerFired()
{
if (isUsingProxy()) {
m_names.clear();
diff --git a/Source/WebCore/platform/network/DNSResolveQueue.h b/Source/WebCore/platform/network/DNSResolveQueue.h
index de0b6f072..d2a7a77b8 100644
--- a/Source/WebCore/platform/network/DNSResolveQueue.h
+++ b/Source/WebCore/platform/network/DNSResolveQueue.h
@@ -14,7 +14,7 @@
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -39,7 +39,7 @@ class DNSResolveQueue {
friend NeverDestroyed<DNSResolveQueue>;
public:
- static DNSResolveQueue& shared();
+ static DNSResolveQueue& singleton();
void add(const String& hostname);
void decrementRequestCount()
@@ -52,16 +52,16 @@ private:
bool isUsingProxy();
- bool platformProxyIsEnabledInSystemPreferences();
+ void updateIsUsingProxy();
void platformResolve(const String&);
- void timerFired(Timer<DNSResolveQueue>&);
+ void timerFired();
- Timer<DNSResolveQueue> m_timer;
+ Timer m_timer;
HashSet<String> m_names;
std::atomic<int> m_requestsInFlight;
- bool m_cachedProxyEnabledStatus;
+ bool m_isUsingProxy;
double m_lastProxyEnabledStatusCheckTime;
};
diff --git a/Source/WebCore/platform/network/DataURLDecoder.cpp b/Source/WebCore/platform/network/DataURLDecoder.cpp
new file mode 100644
index 000000000..abfb46cec
--- /dev/null
+++ b/Source/WebCore/platform/network/DataURLDecoder.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DataURLDecoder.h"
+
+#include "DecodeEscapeSequences.h"
+#include "HTTPParsers.h"
+#include "SharedBuffer.h"
+#include "URL.h"
+#include <wtf/MainThread.h>
+#include <wtf/RunLoop.h>
+#include <wtf/WorkQueue.h>
+#include <wtf/text/Base64.h>
+
+namespace WebCore {
+namespace DataURLDecoder {
+
+static WorkQueue& decodeQueue()
+{
+ static auto& queue = WorkQueue::create("org.webkit.DataURLDecoder").leakRef();
+ return queue;
+}
+
+struct DecodeTask {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ const String urlString;
+ const StringView encodedData;
+ const bool isBase64;
+ const ScheduleContext scheduleContext;
+ const DecodeCompletionHandler completionHandler;
+
+ Result result;
+};
+
+#if HAVE(RUNLOOP_TIMER)
+
+class DecodingResultDispatcher : public ThreadSafeRefCounted<DecodingResultDispatcher> {
+public:
+ static void dispatch(std::unique_ptr<DecodeTask> decodeTask)
+ {
+ Ref<DecodingResultDispatcher> dispatcher = adoptRef(*new DecodingResultDispatcher(WTFMove(decodeTask)));
+ dispatcher->startTimer();
+ }
+
+private:
+ DecodingResultDispatcher(std::unique_ptr<DecodeTask> decodeTask)
+ : m_timer(*this, &DecodingResultDispatcher::timerFired)
+ , m_decodeTask(WTFMove(decodeTask))
+ {
+ }
+
+ void startTimer()
+ {
+ // Keep alive until the timer has fired.
+ ref();
+
+ auto scheduledPairs = m_decodeTask->scheduleContext.scheduledPairs;
+ m_timer.startOneShot(0);
+ m_timer.schedule(scheduledPairs);
+ }
+
+ void timerFired()
+ {
+ if (m_decodeTask->result.data)
+ m_decodeTask->completionHandler(WTFMove(m_decodeTask->result));
+ else
+ m_decodeTask->completionHandler({ });
+
+ // Ensure DecodeTask gets deleted in the main thread.
+ m_decodeTask = nullptr;
+
+ deref();
+ }
+
+ RunLoopTimer<DecodingResultDispatcher> m_timer;
+ std::unique_ptr<DecodeTask> m_decodeTask;
+};
+
+#endif // HAVE(RUNLOOP_TIMER)
+
+static Result parseMediaType(const String& mediaType)
+{
+ auto mimeType = extractMIMETypeFromMediaType(mediaType);
+ auto charset = extractCharsetFromMediaType(mediaType);
+
+ // https://tools.ietf.org/html/rfc2397
+ // If <mediatype> is omitted, it defaults to text/plain;charset=US-ASCII. As a shorthand,
+ // "text/plain" can be omitted but the charset parameter supplied.
+ if (mimeType.isEmpty()) {
+ mimeType = ASCIILiteral("text/plain");
+ if (charset.isEmpty())
+ charset = ASCIILiteral("US-ASCII");
+ }
+ return { mimeType, charset, !mediaType.isEmpty() ? mediaType : "text/plain;charset=US-ASCII", nullptr };
+}
+
+static std::unique_ptr<DecodeTask> createDecodeTask(const URL& url, const ScheduleContext& scheduleContext, DecodeCompletionHandler&& completionHandler)
+{
+ const char dataString[] = "data:";
+ const char base64String[] = ";base64";
+
+ auto urlString = url.string();
+ ASSERT(urlString.startsWith(dataString));
+
+ size_t headerEnd = urlString.find(',', strlen(dataString));
+ size_t encodedDataStart = headerEnd == notFound ? headerEnd : headerEnd + 1;
+
+ auto encodedData = StringView(urlString).substring(encodedDataStart);
+ auto header = StringView(urlString).substring(strlen(dataString), headerEnd - strlen(dataString));
+ bool isBase64 = header.endsWithIgnoringASCIICase(StringView(base64String));
+ auto mediaType = (isBase64 ? header.substring(0, header.length() - strlen(base64String)) : header).toString();
+
+ return std::make_unique<DecodeTask>(DecodeTask {
+ urlString.isolatedCopy(),
+ WTFMove(encodedData),
+ isBase64,
+ scheduleContext,
+ WTFMove(completionHandler),
+ parseMediaType(mediaType)
+ });
+}
+
+static void decodeBase64(DecodeTask& task)
+{
+ Vector<char> buffer;
+ // First try base64url.
+ if (!base64URLDecode(task.encodedData.toStringWithoutCopying(), buffer)) {
+ // Didn't work, try unescaping and decoding as base64.
+ auto unescapedString = decodeURLEscapeSequences(task.encodedData.toStringWithoutCopying());
+ if (!base64Decode(unescapedString, buffer, Base64IgnoreSpacesAndNewLines))
+ return;
+ }
+ buffer.shrinkToFit();
+ task.result.data = SharedBuffer::adoptVector(buffer);
+}
+
+static void decodeEscaped(DecodeTask& task)
+{
+ TextEncoding encodingFromCharset(task.result.charset);
+ auto& encoding = encodingFromCharset.isValid() ? encodingFromCharset : UTF8Encoding();
+ auto buffer = decodeURLEscapeSequencesAsData(task.encodedData, encoding);
+
+ buffer.shrinkToFit();
+ task.result.data = SharedBuffer::adoptVector(buffer);
+}
+
+void decode(const URL& url, const ScheduleContext& scheduleContext, DecodeCompletionHandler&& completionHandler)
+{
+ ASSERT(url.protocolIsData());
+
+ decodeQueue().dispatch([decodeTask = createDecodeTask(url, scheduleContext, WTFMove(completionHandler))]() mutable {
+ if (decodeTask->isBase64)
+ decodeBase64(*decodeTask);
+ else
+ decodeEscaped(*decodeTask);
+
+#if HAVE(RUNLOOP_TIMER)
+ DecodingResultDispatcher::dispatch(WTFMove(decodeTask));
+#else
+ callOnMainThread([decodeTask = WTFMove(decodeTask)] {
+ if (!decodeTask->result.data) {
+ decodeTask->completionHandler({ });
+ return;
+ }
+ decodeTask->completionHandler(WTFMove(decodeTask->result));
+ });
+#endif
+ });
+}
+
+}
+}
diff --git a/Source/WebCore/platform/network/DataURLDecoder.h b/Source/WebCore/platform/network/DataURLDecoder.h
new file mode 100644
index 000000000..e5db15426
--- /dev/null
+++ b/Source/WebCore/platform/network/DataURLDecoder.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DataURLDecoder_h
+#define DataURLDecoder_h
+
+
+#include <functional>
+#include <wtf/Optional.h>
+#include <wtf/text/WTFString.h>
+
+#if HAVE(RUNLOOP_TIMER)
+#include <wtf/RunLoopTimer.h>
+#endif
+
+namespace WebCore {
+
+class SharedBuffer;
+class URL;
+
+namespace DataURLDecoder {
+
+struct Result {
+ String mimeType;
+ String charset;
+ String contentType;
+ RefPtr<SharedBuffer> data;
+};
+
+using DecodeCompletionHandler = std::function<void (std::optional<Result>)>;
+struct ScheduleContext {
+#if HAVE(RUNLOOP_TIMER)
+ SchedulePairHashSet scheduledPairs;
+#endif
+};
+
+void decode(const URL&, const ScheduleContext&, DecodeCompletionHandler&&);
+
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/network/FormData.cpp b/Source/WebCore/platform/network/FormData.cpp
index f056b58ca..564a05379 100644
--- a/Source/WebCore/platform/network/FormData.cpp
+++ b/Source/WebCore/platform/network/FormData.cpp
@@ -20,10 +20,8 @@
*/
#include "config.h"
-
#include "FormData.h"
-#include "BlobData.h"
#include "BlobRegistryImpl.h"
#include "BlobURL.h"
#include "Chrome.h"
@@ -33,20 +31,12 @@
#include "FileSystem.h"
#include "FormDataBuilder.h"
#include "FormDataList.h"
-#include "KeyedCoding.h"
-#include "MIMETypeRegistry.h"
#include "Page.h"
#include "TextEncoding.h"
-#include <wtf/Decoder.h>
-#include <wtf/Encoder.h>
namespace WebCore {
inline FormData::FormData()
- : m_identifier(0)
- , m_hasGeneratedFiles(false)
- , m_alwaysStream(false)
- , m_containsPasswordData(false)
{
}
@@ -54,18 +44,15 @@ inline FormData::FormData(const FormData& data)
: RefCounted<FormData>()
, m_elements(data.m_elements)
, m_identifier(data.m_identifier)
- , m_hasGeneratedFiles(false)
, m_alwaysStream(false)
, m_containsPasswordData(data.m_containsPasswordData)
{
// We shouldn't be copying FormData that hasn't already removed its generated files
// but just in case, make sure the new FormData is ready to generate its own files.
- if (data.m_hasGeneratedFiles) {
- size_t n = m_elements.size();
- for (size_t i = 0; i < n; ++i) {
- FormDataElement& e = m_elements[i];
- if (e.m_type == FormDataElement::encodedFile)
- e.m_generatedFilename = String();
+ for (FormDataElement& element : m_elements) {
+ if (element.m_type == FormDataElement::Type::EncodedFile) {
+ element.m_generatedFilename = String();
+ element.m_ownsGeneratedFile = false;
}
}
}
@@ -74,84 +61,81 @@ FormData::~FormData()
{
// This cleanup should've happened when the form submission finished.
// Just in case, let's assert, and do the cleanup anyway in release builds.
- ASSERT(!m_hasGeneratedFiles);
+ ASSERT(!hasOwnedGeneratedFiles());
removeGeneratedFilesIfNeeded();
}
-PassRefPtr<FormData> FormData::create()
+Ref<FormData> FormData::create()
{
- return adoptRef(new FormData);
+ return adoptRef(*new FormData);
}
-PassRefPtr<FormData> FormData::create(const void* data, size_t size)
+Ref<FormData> FormData::create(const void* data, size_t size)
{
- RefPtr<FormData> result = create();
+ Ref<FormData> result = create();
result->appendData(data, size);
- return result.release();
+ return result;
}
-PassRefPtr<FormData> FormData::create(const CString& string)
+Ref<FormData> FormData::create(const CString& string)
{
- RefPtr<FormData> result = create();
+ Ref<FormData> result = create();
result->appendData(string.data(), string.length());
- return result.release();
+ return result;
}
-PassRefPtr<FormData> FormData::create(const Vector<char>& vector)
+Ref<FormData> FormData::create(const Vector<char>& vector)
{
- RefPtr<FormData> result = create();
+ Ref<FormData> result = create();
result->appendData(vector.data(), vector.size());
- return result.release();
+ return result;
}
-PassRefPtr<FormData> FormData::create(const FormDataList& list, const TextEncoding& encoding, EncodingType encodingType)
+Ref<FormData> FormData::create(const FormDataList& list, const TextEncoding& encoding, EncodingType encodingType)
{
- RefPtr<FormData> result = create();
+ Ref<FormData> result = create();
result->appendKeyValuePairItems(list, encoding, false, 0, encodingType);
- return result.release();
+ return result;
}
-PassRefPtr<FormData> FormData::createMultiPart(const FormDataList& list, const TextEncoding& encoding, Document* document)
+Ref<FormData> FormData::createMultiPart(const FormDataList& list, const TextEncoding& encoding, Document* document)
{
- RefPtr<FormData> result = create();
+ Ref<FormData> result = create();
result->appendKeyValuePairItems(list, encoding, true, document);
- return result.release();
+ return result;
}
-PassRefPtr<FormData> FormData::copy() const
+Ref<FormData> FormData::copy() const
{
- return adoptRef(new FormData(*this));
+ return adoptRef(*new FormData(*this));
}
-PassRefPtr<FormData> FormData::deepCopy() const
+Ref<FormData> FormData::isolatedCopy() const
{
- RefPtr<FormData> formData(create());
+ // FIXME: isolatedCopy() (historically deepCopy()) only copies certain values from `this`. Why is that?
+ auto formData = create();
formData->m_alwaysStream = m_alwaysStream;
- size_t n = m_elements.size();
- formData->m_elements.reserveInitialCapacity(n);
- for (size_t i = 0; i < n; ++i) {
- const FormDataElement& e = m_elements[i];
- switch (e.m_type) {
- case FormDataElement::data:
- formData->m_elements.uncheckedAppend(FormDataElement(e.m_data));
- break;
- case FormDataElement::encodedFile:
-#if ENABLE(BLOB)
- formData->m_elements.uncheckedAppend(FormDataElement(e.m_filename, e.m_fileStart, e.m_fileLength, e.m_expectedFileModificationTime, e.m_shouldGenerateFile));
-#else
- formData->m_elements.uncheckedAppend(FormDataElement(e.m_filename, e.m_shouldGenerateFile));
-#endif
- break;
-#if ENABLE(BLOB)
- case FormDataElement::encodedBlob:
- formData->m_elements.uncheckedAppend(FormDataElement(e.m_url));
- break;
-#endif
- }
+ formData->m_elements.reserveInitialCapacity(m_elements.size());
+ for (auto& element : m_elements)
+ formData->m_elements.uncheckedAppend(element.isolatedCopy());
+
+ return formData;
+}
+
+FormDataElement FormDataElement::isolatedCopy() const
+{
+ switch (m_type) {
+ case Type::Data:
+ return FormDataElement(m_data);
+ case Type::EncodedFile:
+ return FormDataElement(m_filename.isolatedCopy(), m_fileStart, m_fileLength, m_expectedFileModificationTime, m_shouldGenerateFile);
+ case Type::EncodedBlob:
+ return FormDataElement(m_url.isolatedCopy());
}
- return formData.release();
+
+ RELEASE_ASSERT_NOT_REACHED();
}
void FormData::appendData(const void* data, size_t size)
@@ -161,14 +145,9 @@ void FormData::appendData(const void* data, size_t size)
void FormData::appendFile(const String& filename, bool shouldGenerateFile)
{
-#if ENABLE(BLOB)
m_elements.append(FormDataElement(filename, 0, BlobDataItem::toEndOfFile, invalidFileTime(), shouldGenerateFile));
-#else
- m_elements.append(FormDataElement(filename, shouldGenerateFile));
-#endif
}
-#if ENABLE(BLOB)
void FormData::appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile)
{
m_elements.append(FormDataElement(filename, start, length, expectedModificationTime, shouldGenerateFile));
@@ -178,7 +157,6 @@ void FormData::appendBlob(const URL& blobURL)
{
m_elements.append(FormDataElement(blobURL));
}
-#endif
void FormData::appendKeyValuePairItems(const FormDataList& list, const TextEncoding& encoding, bool isMultiPartForm, Document* document, EncodingType encodingType)
{
@@ -202,16 +180,11 @@ void FormData::appendKeyValuePairItems(const FormDataList& list, const TextEncod
// If the current type is blob, then we also need to include the filename
if (value.blob()) {
String name;
- if (value.blob()->isFile()) {
- File* file = toFile(value.blob());
- // For file blob, use the filename (or relative path if it is present) as the name.
-#if ENABLE(DIRECTORY_UPLOAD)
- name = file->webkitRelativePath().isEmpty() ? file->name() : file->webkitRelativePath();
-#else
- name = file->name();
-#endif
+ if (is<File>(*value.blob())) {
+ File& file = downcast<File>(*value.blob());
+ name = file.name();
// Let the application specify a filename if it's going to generate a replacement file for the upload.
- const String& path = file->path();
+ const String& path = file.path();
if (!path.isEmpty()) {
if (Page* page = document->page()) {
String generatedFileName;
@@ -248,27 +221,19 @@ void FormData::appendKeyValuePairItems(const FormDataList& list, const TextEncod
// Append body
appendData(header.data(), header.size());
if (value.blob()) {
- if (value.blob()->isFile()) {
- File* file = toFile(value.blob());
+ if (is<File>(*value.blob())) {
+ File& file = downcast<File>(*value.blob());
// Do not add the file if the path is empty.
- if (!file->path().isEmpty())
- appendFile(file->path(), shouldGenerateFile);
+ if (!file.path().isEmpty())
+ appendFile(file.path(), shouldGenerateFile);
}
-#if ENABLE(BLOB)
else
appendBlob(value.blob()->url());
-#endif
} else
appendData(value.data().data(), value.data().length());
appendData("\r\n", 2);
- } else {
- // Omit the name "isindex" if it's the first form data element.
- // FIXME: Why is this a good rule? Is this obsolete now?
- if (encodedData.isEmpty() && key.data() == "isindex")
- FormDataBuilder::encodeStringAsFormData(encodedData, value.data());
- else
- FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data(), encodingType);
- }
+ } else
+ FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data(), encodingType);
}
if (isMultiPartForm)
@@ -279,7 +244,7 @@ void FormData::appendKeyValuePairItems(const FormDataList& list, const TextEncod
char* FormData::expandDataStore(size_t size)
{
- if (m_elements.isEmpty() || m_elements.last().m_type != FormDataElement::data)
+ if (m_elements.isEmpty() || m_elements.last().m_type != FormDataElement::Type::Data)
m_elements.append(FormDataElement());
FormDataElement& e = m_elements.last();
size_t oldSize = e.m_data.size();
@@ -294,7 +259,7 @@ void FormData::flatten(Vector<char>& data) const
size_t n = m_elements.size();
for (size_t i = 0; i < n; ++i) {
const FormDataElement& e = m_elements[i];
- if (e.m_type == FormDataElement::data)
+ if (e.m_type == FormDataElement::Type::Data)
data.append(e.m_data.data(), static_cast<size_t>(e.m_data.size()));
}
}
@@ -306,14 +271,13 @@ String FormData::flattenToString() const
return Latin1Encoding().decode(reinterpret_cast<const char*>(bytes.data()), bytes.size());
}
-#if ENABLE(BLOB)
static void appendBlobResolved(FormData* formData, const URL& url)
{
if (!blobRegistry().isBlobRegistryImpl()) {
LOG_ERROR("Tried to resolve a blob without a usable registry");
return;
}
- BlobStorageData* blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(URL(ParsedURLString, url));
+ BlobData* blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(url);
if (!blobData) {
LOG_ERROR("Could not get blob data from a registry");
return;
@@ -323,284 +287,103 @@ static void appendBlobResolved(FormData* formData, const URL& url)
const BlobDataItemList::const_iterator itend = blobData->items().end();
for (; it != itend; ++it) {
const BlobDataItem& blobItem = *it;
- if (blobItem.type == BlobDataItem::Data)
- formData->appendData(blobItem.data->data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length));
- else if (blobItem.type == BlobDataItem::File)
- formData->appendFileRange(blobItem.path, blobItem.offset, blobItem.length, blobItem.expectedModificationTime);
- else if (blobItem.type == BlobDataItem::Blob)
- appendBlobResolved(formData, blobItem.url);
+ if (blobItem.type() == BlobDataItem::Type::Data) {
+ ASSERT(blobItem.data().data());
+ formData->appendData(blobItem.data().data()->data() + static_cast<int>(blobItem.offset()), static_cast<int>(blobItem.length()));
+ } else if (blobItem.type() == BlobDataItem::Type::File)
+ formData->appendFileRange(blobItem.file()->path(), blobItem.offset(), blobItem.length(), blobItem.file()->expectedModificationTime());
else
ASSERT_NOT_REACHED();
}
}
-PassRefPtr<FormData> FormData::resolveBlobReferences()
+Ref<FormData> FormData::resolveBlobReferences()
{
// First check if any blobs needs to be resolved, or we can take the fast path.
bool hasBlob = false;
Vector<FormDataElement>::const_iterator it = elements().begin();
const Vector<FormDataElement>::const_iterator itend = elements().end();
for (; it != itend; ++it) {
- if (it->m_type == FormDataElement::encodedBlob) {
+ if (it->m_type == FormDataElement::Type::EncodedBlob) {
hasBlob = true;
break;
}
}
if (!hasBlob)
- return this;
+ return *this;
// Create a copy to append the result into.
- RefPtr<FormData> newFormData = FormData::create();
+ Ref<FormData> newFormData = FormData::create();
newFormData->setAlwaysStream(alwaysStream());
newFormData->setIdentifier(identifier());
it = elements().begin();
for (; it != itend; ++it) {
const FormDataElement& element = *it;
- if (element.m_type == FormDataElement::data)
+ if (element.m_type == FormDataElement::Type::Data)
newFormData->appendData(element.m_data.data(), element.m_data.size());
- else if (element.m_type == FormDataElement::encodedFile)
+ else if (element.m_type == FormDataElement::Type::EncodedFile)
newFormData->appendFileRange(element.m_filename, element.m_fileStart, element.m_fileLength, element.m_expectedFileModificationTime, element.m_shouldGenerateFile);
- else if (element.m_type == FormDataElement::encodedBlob)
- appendBlobResolved(newFormData.get(), element.m_url);
+ else if (element.m_type == FormDataElement::Type::EncodedBlob)
+ appendBlobResolved(newFormData.ptr(), element.m_url);
else
ASSERT_NOT_REACHED();
}
- return newFormData.release();
+ return newFormData;
}
-#endif
void FormData::generateFiles(Document* document)
{
- ASSERT(!m_hasGeneratedFiles);
-
- if (m_hasGeneratedFiles)
- return;
-
Page* page = document->page();
if (!page)
return;
- size_t n = m_elements.size();
- for (size_t i = 0; i < n; ++i) {
- FormDataElement& e = m_elements[i];
- if (e.m_type == FormDataElement::encodedFile && e.m_shouldGenerateFile) {
- e.m_generatedFilename = page->chrome().client().generateReplacementFile(e.m_filename);
- m_hasGeneratedFiles = true;
- }
- }
-}
-
-void FormData::removeGeneratedFilesIfNeeded()
-{
- if (!m_hasGeneratedFiles)
- return;
-
- size_t n = m_elements.size();
- for (size_t i = 0; i < n; ++i) {
- FormDataElement& e = m_elements[i];
- if (e.m_type == FormDataElement::encodedFile && !e.m_generatedFilename.isEmpty()) {
- ASSERT(e.m_shouldGenerateFile);
- String directory = directoryName(e.m_generatedFilename);
- deleteFile(e.m_generatedFilename);
- deleteEmptyDirectory(directory);
- e.m_generatedFilename = String();
+ for (FormDataElement& element : m_elements) {
+ if (element.m_type == FormDataElement::Type::EncodedFile && element.m_shouldGenerateFile) {
+ ASSERT(!element.m_ownsGeneratedFile);
+ ASSERT(element.m_generatedFilename.isEmpty());
+ if (!element.m_generatedFilename.isEmpty())
+ continue;
+ element.m_generatedFilename = page->chrome().client().generateReplacementFile(element.m_filename);
+ if (!element.m_generatedFilename.isEmpty())
+ element.m_ownsGeneratedFile = true;
}
}
- m_hasGeneratedFiles = false;
}
-static void encodeElement(Encoder& encoder, const FormDataElement& element)
+bool FormData::hasGeneratedFiles() const
{
- encoder.encodeUInt32(element.m_type);
-
- switch (element.m_type) {
- case FormDataElement::data:
- encoder.encodeBytes(reinterpret_cast<const uint8_t*>(element.m_data.data()), element.m_data.size());
- return;
-
- case FormDataElement::encodedFile:
- encoder.encodeString(element.m_filename);
- encoder.encodeString(element.m_generatedFilename);
- encoder.encodeBool(element.m_shouldGenerateFile);
-#if ENABLE(BLOB)
- encoder.encodeInt64(element.m_fileStart);
- encoder.encodeInt64(element.m_fileLength);
- encoder.encodeDouble(element.m_expectedFileModificationTime);
-#else
- encoder.encodeInt64(0);
- encoder.encodeInt64(0);
- encoder.encodeDouble(invalidFileTime());
-#endif
- return;
-
-#if ENABLE(BLOB)
- case FormDataElement::encodedBlob:
- encoder.encodeString(element.m_url.string());
- return;
-#endif
+ for (const FormDataElement& element : m_elements) {
+ if (element.m_type == FormDataElement::Type::EncodedFile && !element.m_generatedFilename.isEmpty())
+ return true;
}
-
- ASSERT_NOT_REACHED();
-}
-
-static void encodeElement(KeyedEncoder& encoder, const FormDataElement& element)
-{
- encoder.encodeEnum("type", element.m_type);
-
- switch (element.m_type) {
- case FormDataElement::data:
- encoder.encodeBytes("data", reinterpret_cast<const uint8_t*>(element.m_data.data()), element.m_data.size());
- return;
- case FormDataElement::encodedFile:
- encoder.encodeString("filename", element.m_filename);
- encoder.encodeString("generatedFilename", element.m_generatedFilename);
- encoder.encodeBool("shouldGenerateFile", element.m_shouldGenerateFile);
-#if ENABLE(BLOB)
- encoder.encodeInt64("fileStart", element.m_fileStart);
- encoder.encodeInt64("fileLength", element.m_fileLength);
- encoder.encodeDouble("expectedFileModificationTime", element.m_expectedFileModificationTime);
-#endif
- return;
-
-#if ENABLE(BLOB)
- case FormDataElement::encodedBlob:
- encoder.encodeString("url", element.m_url.string());
- return;
-#endif
- }
-
- ASSERT_NOT_REACHED();
+ return false;
}
-static bool decodeElement(Decoder& decoder, FormDataElement& element)
+bool FormData::hasOwnedGeneratedFiles() const
{
- uint32_t type;
- if (!decoder.decodeUInt32(type))
- return false;
-
- switch (type) {
- case FormDataElement::data: {
- element.m_type = FormDataElement::data;
- Vector<uint8_t> data;
- if (!decoder.decodeBytes(data))
- return false;
- size_t size = data.size();
- element.m_data.resize(size);
- memcpy(element.m_data.data(), data.data(), size);
- return true;
- }
-
- case FormDataElement::encodedFile:
- {
- element.m_type = static_cast<FormDataElement::Type>(type);
- String filenameOrURL;
- if (!decoder.decodeString(filenameOrURL))
- return false;
- if (type == FormDataElement::encodedFile) {
- if (!decoder.decodeString(element.m_generatedFilename))
- return false;
- if (!decoder.decodeBool(element.m_shouldGenerateFile))
- return false;
+ for (const FormDataElement& element : m_elements) {
+ if (element.m_type == FormDataElement::Type::EncodedFile && element.m_ownsGeneratedFile) {
+ ASSERT(!element.m_generatedFilename.isEmpty());
+ return true;
}
- int64_t fileStart;
- if (!decoder.decodeInt64(fileStart))
- return false;
- if (fileStart < 0)
- return false;
- int64_t fileLength;
- if (!decoder.decodeInt64(fileLength))
- return false;
- if (fileLength != BlobDataItem::toEndOfFile && fileLength < fileStart)
- return false;
- double expectedFileModificationTime;
- if (!decoder.decodeDouble(expectedFileModificationTime))
- return false;
-
- element.m_filename = filenameOrURL;
-#if ENABLE(BLOB)
- element.m_fileStart = fileStart;
- element.m_fileLength = fileLength;
- element.m_expectedFileModificationTime = expectedFileModificationTime;
-#endif
- return true;
}
-
-#if ENABLE(BLOB)
- case FormDataElement::encodedBlob:
- element.m_type = FormDataElement::encodedBlob;
- String blobURLString;
- if (!decoder.decodeString(blobURLString))
- return false;
- element.m_url = URL(URL(), blobURLString);
- return true;
-#endif
-
- }
-
return false;
}
-void FormData::encode(Encoder& encoder) const
-{
- encoder.encodeBool(m_alwaysStream);
-
- encoder.encodeBytes(reinterpret_cast<const uint8_t*>(m_boundary.data()), m_boundary.size());
-
- size_t size = m_elements.size();
- encoder.encodeUInt64(size);
- for (size_t i = 0; i < size; ++i)
- encodeElement(encoder, m_elements[i]);
-
- encoder.encodeBool(m_hasGeneratedFiles);
-
- encoder.encodeInt64(m_identifier);
-}
-
-void FormData::encode(KeyedEncoder& encoder) const
-{
- encoder.encodeBool("alwaysStream", m_alwaysStream);
- encoder.encodeBytes("boundary", reinterpret_cast<const uint8_t*>(m_boundary.data()), m_boundary.size());
-
- encoder.encodeObjects("elements", m_elements.begin(), m_elements.end(), [](KeyedEncoder& encoder, const FormDataElement& element) {
- encodeElement(encoder, element);
- });
-
- encoder.encodeBool("hasGeneratedFiles", m_hasGeneratedFiles);
- encoder.encodeInt64("identifier", m_identifier);
-}
-
-PassRefPtr<FormData> FormData::decode(Decoder& decoder)
+void FormData::removeGeneratedFilesIfNeeded()
{
- RefPtr<FormData> data = FormData::create();
-
- if (!decoder.decodeBool(data->m_alwaysStream))
- return 0;
-
- Vector<uint8_t> boundary;
- if (!decoder.decodeBytes(boundary))
- return 0;
- size_t size = boundary.size();
- data->m_boundary.resize(size);
- memcpy(data->m_boundary.data(), boundary.data(), size);
-
- uint64_t elementsSize;
- if (!decoder.decodeUInt64(elementsSize))
- return 0;
- for (size_t i = 0; i < elementsSize; ++i) {
- FormDataElement element;
- if (!decodeElement(decoder, element))
- return 0;
- data->m_elements.append(element);
+ for (FormDataElement& element : m_elements) {
+ if (element.m_type == FormDataElement::Type::EncodedFile && element.m_ownsGeneratedFile) {
+ ASSERT(!element.m_generatedFilename.isEmpty());
+ ASSERT(element.m_shouldGenerateFile);
+ String directory = directoryName(element.m_generatedFilename);
+ deleteFile(element.m_generatedFilename);
+ deleteEmptyDirectory(directory);
+ element.m_generatedFilename = String();
+ element.m_ownsGeneratedFile = false;
+ }
}
-
- if (!decoder.decodeBool(data->m_hasGeneratedFiles))
- return 0;
-
- if (!decoder.decodeInt64(data->m_identifier))
- return 0;
-
- return data.release();
}
} // namespace WebCore
diff --git a/Source/WebCore/platform/network/FormData.h b/Source/WebCore/platform/network/FormData.h
index e3761f8ba..7e44dcaf9 100644
--- a/Source/WebCore/platform/network/FormData.h
+++ b/Source/WebCore/platform/network/FormData.h
@@ -20,6 +20,7 @@
#ifndef FormData_h
#define FormData_h
+#include "BlobData.h"
#include "URL.h"
#include <wtf/Forward.h>
#include <wtf/RefCounted.h>
@@ -30,38 +31,65 @@ namespace WebCore {
class Document;
class FormDataList;
-class KeyedEncoder;
class TextEncoding;
class FormDataElement {
public:
- FormDataElement() : m_type(data) { }
- explicit FormDataElement(const Vector<char>& array) : m_type(data), m_data(array) { }
-
-#if ENABLE(BLOB)
- FormDataElement(const String& filename, long long fileStart, long long fileLength, double expectedFileModificationTime, bool shouldGenerateFile) : m_type(encodedFile), m_filename(filename), m_fileStart(fileStart), m_fileLength(fileLength), m_expectedFileModificationTime(expectedFileModificationTime), m_shouldGenerateFile(shouldGenerateFile) { }
- explicit FormDataElement(const URL& blobURL) : m_type(encodedBlob), m_url(blobURL) { }
-#else
- FormDataElement(const String& filename, bool shouldGenerateFile) : m_type(encodedFile), m_filename(filename), m_shouldGenerateFile(shouldGenerateFile) { }
-#endif
+ enum class Type {
+ Data,
+ EncodedFile,
+ EncodedBlob,
+ };
- enum Type {
- data,
- encodedFile
-#if ENABLE(BLOB)
- , encodedBlob
-#endif
- } m_type;
+ FormDataElement()
+ : m_type(Type::Data)
+ {
+ }
+
+ explicit FormDataElement(const Vector<char>& array)
+ : m_type(Type::Data)
+ , m_data(array)
+ {
+ }
+
+ FormDataElement(const String& filename, long long fileStart, long long fileLength, double expectedFileModificationTime, bool shouldGenerateFile)
+ : m_type(Type::EncodedFile)
+ , m_filename(filename)
+ , m_fileStart(fileStart)
+ , m_fileLength(fileLength)
+ , m_expectedFileModificationTime(expectedFileModificationTime)
+ , m_shouldGenerateFile(shouldGenerateFile)
+ , m_ownsGeneratedFile(false)
+ {
+ }
+
+ explicit FormDataElement(const URL& blobURL)
+ : m_type(Type::EncodedBlob)
+ , m_url(blobURL)
+ {
+ }
+
+ FormDataElement isolatedCopy() const;
+
+ template<typename Encoder>
+ void encode(Encoder&) const;
+ template<typename Decoder>
+ static bool decode(Decoder&, FormDataElement& result);
+
+ Type m_type;
Vector<char> m_data;
String m_filename;
-#if ENABLE(BLOB)
URL m_url; // For Blob or URL.
- long long m_fileStart;
- long long m_fileLength;
+ int64_t m_fileStart;
+ int64_t m_fileLength;
double m_expectedFileModificationTime;
-#endif
+ // FIXME: Generated file support in FormData is almost identical to Blob, they should be merged.
+ // We can't just switch to using Blobs for all files for two reasons:
+ // 1. Not all platforms enable BLOB support.
+ // 2. EncodedFile form data elements do not have a valid m_expectedFileModificationTime, meaning that we always upload the latest content from disk.
String m_generatedFilename;
bool m_shouldGenerateFile;
+ bool m_ownsGeneratedFile;
};
inline bool operator==(const FormDataElement& a, const FormDataElement& b)
@@ -71,16 +99,12 @@ inline bool operator==(const FormDataElement& a, const FormDataElement& b)
if (a.m_type != b.m_type)
return false;
- if (a.m_type == FormDataElement::data)
+ if (a.m_type == FormDataElement::Type::Data)
return a.m_data == b.m_data;
- if (a.m_type == FormDataElement::encodedFile)
-#if ENABLE(BLOB)
+ if (a.m_type == FormDataElement::Type::EncodedFile)
return a.m_filename == b.m_filename && a.m_fileStart == b.m_fileStart && a.m_fileLength == b.m_fileLength && a.m_expectedFileModificationTime == b.m_expectedFileModificationTime;
- if (a.m_type == FormDataElement::encodedBlob)
+ if (a.m_type == FormDataElement::Type::EncodedBlob)
return a.m_url == b.m_url;
-#else
- return a.m_filename == b.m_filename;
-#endif
return true;
}
@@ -90,6 +114,80 @@ inline bool operator!=(const FormDataElement& a, const FormDataElement& b)
return !(a == b);
}
+
+template<typename Encoder>
+void FormDataElement::encode(Encoder& encoder) const
+{
+ encoder.encodeEnum(m_type);
+
+ switch (m_type) {
+ case Type::Data:
+ encoder << m_data;
+ break;
+
+ case Type::EncodedFile:
+ encoder << m_filename;
+ encoder << m_generatedFilename;
+ encoder << m_shouldGenerateFile;
+ encoder << m_fileStart;
+ encoder << m_fileLength;
+ encoder << m_expectedFileModificationTime;
+ break;
+
+ case Type::EncodedBlob:
+ encoder << m_url.string();
+ break;
+ }
+}
+
+template<typename Decoder>
+bool FormDataElement::decode(Decoder& decoder, FormDataElement& result)
+{
+ if (!decoder.decodeEnum(result.m_type))
+ return false;
+
+ switch (result.m_type) {
+ case Type::Data:
+ if (!decoder.decode(result.m_data))
+ return false;
+
+ return true;
+
+ case Type::EncodedFile:
+ if (!decoder.decode(result.m_filename))
+ return false;
+ if (!decoder.decode(result.m_generatedFilename))
+ return false;
+ if (!decoder.decode(result.m_shouldGenerateFile))
+ return false;
+ result.m_ownsGeneratedFile = false;
+ if (!decoder.decode(result.m_fileStart))
+ return false;
+ if (!decoder.decode(result.m_fileLength))
+ return false;
+
+ if (result.m_fileLength != BlobDataItem::toEndOfFile && result.m_fileLength < result.m_fileStart)
+ return false;
+
+ if (!decoder.decode(result.m_expectedFileModificationTime))
+ return false;
+
+ return true;
+
+ case Type::EncodedBlob: {
+ String blobURLString;
+ if (!decoder.decode(blobURLString))
+ return false;
+
+ result.m_url = URL(URL(), blobURLString);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
class FormData : public RefCounted<FormData> {
public:
enum EncodingType {
@@ -98,36 +196,36 @@ public:
MultipartFormData // for multipart/form-data
};
- static PassRefPtr<FormData> create();
- static PassRefPtr<FormData> create(const void*, size_t);
- static PassRefPtr<FormData> create(const CString&);
- static PassRefPtr<FormData> create(const Vector<char>&);
- static PassRefPtr<FormData> create(const FormDataList&, const TextEncoding&, EncodingType = FormURLEncoded);
- static PassRefPtr<FormData> createMultiPart(const FormDataList&, const TextEncoding&, Document*);
- PassRefPtr<FormData> copy() const;
- PassRefPtr<FormData> deepCopy() const;
- ~FormData();
+ WEBCORE_EXPORT static Ref<FormData> create();
+ WEBCORE_EXPORT static Ref<FormData> create(const void*, size_t);
+ static Ref<FormData> create(const CString&);
+ static Ref<FormData> create(const Vector<char>&);
+ static Ref<FormData> create(const FormDataList&, const TextEncoding&, EncodingType = FormURLEncoded);
+ static Ref<FormData> createMultiPart(const FormDataList&, const TextEncoding&, Document*);
+ WEBCORE_EXPORT ~FormData();
+ // FIXME: Both these functions perform a deep copy of m_elements, but differ in handling of other data members.
+ // How much of that is intentional? We need better names that explain the difference.
+ Ref<FormData> copy() const;
+ Ref<FormData> isolatedCopy() const;
+
+ template<typename Encoder>
void encode(Encoder&) const;
- void encode(KeyedEncoder&) const;
- static PassRefPtr<FormData> decode(Decoder&);
+ template<typename Decoder>
+ static RefPtr<FormData> decode(Decoder&);
- void appendData(const void* data, size_t);
+ WEBCORE_EXPORT void appendData(const void* data, size_t);
void appendFile(const String& filePath, bool shouldGenerateFile = false);
-#if ENABLE(BLOB)
- void appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile = false);
- void appendBlob(const URL& blobURL);
-#endif
+ WEBCORE_EXPORT void appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile = false);
+ WEBCORE_EXPORT void appendBlob(const URL& blobURL);
char* expandDataStore(size_t);
void flatten(Vector<char>&) const; // omits files
String flattenToString() const; // omits files
-#if ENABLE(BLOB)
// Resolve all blob references so we only have file and data.
// If the FormData has no blob references to resolve, this is returned.
- PassRefPtr<FormData> resolveBlobReferences();
-#endif
+ Ref<FormData> resolveBlobReferences();
bool isEmpty() const { return m_elements.isEmpty(); }
const Vector<FormDataElement>& elements() const { return m_elements; }
@@ -149,9 +247,9 @@ public:
static EncodingType parseEncodingType(const String& type)
{
- if (equalIgnoringCase(type, "text/plain"))
+ if (equalLettersIgnoringASCIICase(type, "text/plain"))
return TextPlain;
- if (equalIgnoringCase(type, "multipart/form-data"))
+ if (equalLettersIgnoringASCIICase(type, "multipart/form-data"))
return MultipartFormData;
return FormURLEncoded;
}
@@ -162,13 +260,15 @@ private:
void appendKeyValuePairItems(const FormDataList&, const TextEncoding&, bool isMultiPartForm, Document*, EncodingType = FormURLEncoded);
+ bool hasGeneratedFiles() const;
+ bool hasOwnedGeneratedFiles() const;
+
Vector<FormDataElement> m_elements;
- int64_t m_identifier;
- bool m_hasGeneratedFiles;
- bool m_alwaysStream;
+ int64_t m_identifier { 0 };
+ bool m_alwaysStream { false };
Vector<char> m_boundary;
- bool m_containsPasswordData;
+ bool m_containsPasswordData { false };
};
inline bool operator==(const FormData& a, const FormData& b)
@@ -181,6 +281,35 @@ inline bool operator!=(const FormData& a, const FormData& b)
return !(a == b);
}
+template<typename Encoder>
+void FormData::encode(Encoder& encoder) const
+{
+ encoder << m_alwaysStream;
+ encoder << m_boundary;
+ encoder << m_elements;
+ encoder << m_identifier;
+}
+
+template<typename Decoder>
+RefPtr<FormData> FormData::decode(Decoder& decoder)
+{
+ RefPtr<FormData> data = FormData::create();
+
+ if (!decoder.decode(data->m_alwaysStream))
+ return nullptr;
+
+ if (!decoder.decode(data->m_boundary))
+ return nullptr;
+
+ if (!decoder.decode(data->m_elements))
+ return nullptr;
+
+ if (!decoder.decode(data->m_identifier))
+ return nullptr;
+
+ return data;
+}
+
} // namespace WebCore
#endif
diff --git a/Source/WebCore/platform/network/FormDataBuilder.cpp b/Source/WebCore/platform/network/FormDataBuilder.cpp
index a76916ebd..6888b2cce 100644
--- a/Source/WebCore/platform/network/FormDataBuilder.cpp
+++ b/Source/WebCore/platform/network/FormDataBuilder.cpp
@@ -26,14 +26,13 @@
#include "FormDataBuilder.h"
#include "Blob.h"
-#include "Document.h"
#include "TextEncoding.h"
-
#include <limits>
#include <wtf/Assertions.h>
#include <wtf/HexNumber.h>
-#include <wtf/text/CString.h>
#include <wtf/RandomNumber.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringView.h>
namespace WebCore {
@@ -61,12 +60,11 @@ static void appendQuotedString(Vector<char>& buffer, const CString& string)
size_t length = string.length();
for (size_t i = 0; i < length; ++i) {
char c = string.data()[i];
-
switch (c) {
- case 0x0a:
+ case 0xA:
append(buffer, "%0A");
break;
- case 0x0d:
+ case 0xD:
append(buffer, "%0D");
break;
case '"':
@@ -78,25 +76,6 @@ static void appendQuotedString(Vector<char>& buffer, const CString& string)
}
}
-TextEncoding FormDataBuilder::encodingFromAcceptCharset(const String& acceptCharset, Document& document)
-{
- String normalizedAcceptCharset = acceptCharset;
- normalizedAcceptCharset.replace(',', ' ');
-
- Vector<String> charsets;
- normalizedAcceptCharset.split(' ', charsets);
-
- TextEncoding encoding;
-
- Vector<String>::const_iterator end = charsets.end();
- for (Vector<String>::const_iterator it = charsets.begin(); it != end; ++it) {
- if ((encoding = TextEncoding(*it)).isValid())
- return encoding;
- }
-
- return document.inputEncoding();
-}
-
Vector<char> FormDataBuilder::generateUniqueBoundaryString()
{
Vector<char> boundary;
@@ -165,7 +144,7 @@ void FormDataBuilder::addFilenameToMultiPartHeader(Vector<char>& buffer, const T
// FIXME: This loses data irreversibly if the filename includes characters you can't encode
// in the website's character set.
append(buffer, "; filename=\"");
- appendQuotedString(buffer, encoding.encode(filename.deprecatedCharacters(), filename.length(), QuestionMarksForUnencodables));
+ appendQuotedString(buffer, encoding.encode(filename, QuestionMarksForUnencodables));
append(buffer, '"');
}
@@ -208,7 +187,7 @@ void FormDataBuilder::encodeStringAsFormData(Vector<char>& buffer, const CString
for (unsigned i = 0; i < length; ++i) {
unsigned char c = string.data()[i];
- if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || strchr(safeCharacters, c))
+ if (isASCIIAlphanumeric(c) || strchr(safeCharacters, c))
append(buffer, c);
else if (c == ' ')
append(buffer, '+');
diff --git a/Source/WebCore/platform/network/FormDataBuilder.h b/Source/WebCore/platform/network/FormDataBuilder.h
index 77b59d150..7adecaa66 100644
--- a/Source/WebCore/platform/network/FormDataBuilder.h
+++ b/Source/WebCore/platform/network/FormDataBuilder.h
@@ -26,14 +26,11 @@
namespace WebCore {
-class Document;
class TextEncoding;
class FormDataBuilder {
WTF_MAKE_NONCOPYABLE(FormDataBuilder);
public:
- static TextEncoding encodingFromAcceptCharset(const String& acceptCharset, Document&);
-
// Helper functions used by HTMLFormElement for multi-part form data
static Vector<char> generateUniqueBoundaryString();
static void beginMultiPartHeader(Vector<char>&, const CString& boundary, const CString& name);
diff --git a/Source/WebCore/platform/network/HTTPHeaderMap.cpp b/Source/WebCore/platform/network/HTTPHeaderMap.cpp
index a4593b5e2..196948010 100644
--- a/Source/WebCore/platform/network/HTTPHeaderMap.cpp
+++ b/Source/WebCore/platform/network/HTTPHeaderMap.cpp
@@ -32,6 +32,7 @@
#include "HTTPHeaderMap.h"
#include <utility>
+#include <wtf/text/StringView.h>
namespace WebCore {
@@ -39,76 +40,115 @@ HTTPHeaderMap::HTTPHeaderMap()
{
}
-HTTPHeaderMap::~HTTPHeaderMap()
+HTTPHeaderMap HTTPHeaderMap::isolatedCopy() const
{
+ HTTPHeaderMap map;
+
+ for (auto& header : m_commonHeaders)
+ map.m_commonHeaders.set(header.key, header.value.isolatedCopy());
+
+ for (auto& header : m_uncommonHeaders)
+ map.m_uncommonHeaders.set(header.key.isolatedCopy(), header.value.isolatedCopy());
+
+ return map;
}
-PassOwnPtr<CrossThreadHTTPHeaderMapData> HTTPHeaderMap::copyData() const
+String HTTPHeaderMap::get(const String& name) const
{
- OwnPtr<CrossThreadHTTPHeaderMapData> data = adoptPtr(new CrossThreadHTTPHeaderMapData());
- data->reserveInitialCapacity(size());
+ HTTPHeaderName headerName;
+ if (!findHTTPHeaderName(name, headerName))
+ return m_uncommonHeaders.get(name);
+ return m_commonHeaders.get(headerName);
+}
+
+#if USE(CF)
- HTTPHeaderMap::const_iterator end_it = end();
- for (HTTPHeaderMap::const_iterator it = begin(); it != end_it; ++it)
- data->uncheckedAppend(std::make_pair(it->key.string().isolatedCopy(), it->value.isolatedCopy()));
+void HTTPHeaderMap::set(CFStringRef name, const String& value)
+{
+ // Fast path: avoid constructing a temporary String in the common header case.
+ if (auto* nameCharacters = CFStringGetCStringPtr(name, kCFStringEncodingASCII)) {
+ unsigned length = CFStringGetLength(name);
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(StringView(reinterpret_cast<const LChar*>(nameCharacters), length), headerName))
+ m_commonHeaders.set(headerName, value);
+ else
+ m_uncommonHeaders.set(String(nameCharacters, length), value);
+ return;
+ }
- return data.release();
+ set(String(name), value);
}
-void HTTPHeaderMap::adopt(PassOwnPtr<CrossThreadHTTPHeaderMapData> data)
+#endif // USE(CF)
+
+void HTTPHeaderMap::set(const String& name, const String& value)
{
- clear();
- size_t dataSize = data->size();
- for (size_t index = 0; index < dataSize; ++index) {
- std::pair<String, String>& header = (*data)[index];
- set(header.first, header.second);
+ HTTPHeaderName headerName;
+ if (!findHTTPHeaderName(name, headerName)) {
+ m_uncommonHeaders.set(name, value);
+ return;
}
+ m_commonHeaders.set(headerName, value);
}
-String HTTPHeaderMap::get(const AtomicString& name) const
+void HTTPHeaderMap::add(const String& name, const String& value)
{
- return HashMap<AtomicString, String, CaseFoldingHash>::get(name);
+ HTTPHeaderName headerName;
+ if (!findHTTPHeaderName(name, headerName)) {
+ auto result = m_uncommonHeaders.add(name, value);
+ if (!result.isNewEntry)
+ result.iterator->value = result.iterator->value + ',' + value;
+ return;
+ }
+ add(headerName, value);
}
-HTTPHeaderMap::AddResult HTTPHeaderMap::add(const AtomicString& name, const String& value)
+bool HTTPHeaderMap::addIfNotPresent(HTTPHeaderName headerName, const String& value)
{
- return HashMap<AtomicString, String, CaseFoldingHash>::add(name, value);
+ return m_commonHeaders.add(headerName, value).isNewEntry;
}
-// Adapter that allows the HashMap to take C strings as keys.
-struct CaseFoldingCStringTranslator {
- static unsigned hash(const char* cString)
- {
- return CaseFoldingHash::hash(cString, strlen(cString));
- }
-
- static bool equal(const AtomicString& key, const char* cString)
- {
- return equalIgnoringCase(key, cString);
- }
-
- static void translate(AtomicString& location, const char* cString, unsigned /*hash*/)
- {
- location = AtomicString(cString);
- }
-};
+bool HTTPHeaderMap::contains(const String& name) const
+{
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName))
+ return contains(headerName);
+ return m_uncommonHeaders.contains(name);
+}
+
+bool HTTPHeaderMap::remove(const String& name)
+{
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName))
+ return remove(headerName);
+ return m_uncommonHeaders.remove(name);
+}
+
+String HTTPHeaderMap::get(HTTPHeaderName name) const
+{
+ return m_commonHeaders.get(name);
+}
+
+void HTTPHeaderMap::set(HTTPHeaderName name, const String& value)
+{
+ m_commonHeaders.set(name, value);
+}
-String HTTPHeaderMap::get(const char* name) const
+bool HTTPHeaderMap::contains(HTTPHeaderName name) const
{
- const_iterator i = find<CaseFoldingCStringTranslator>(name);
- if (i == end())
- return String();
- return i->value;
+ return m_commonHeaders.contains(name);
}
-
-bool HTTPHeaderMap::contains(const char* name) const
+
+bool HTTPHeaderMap::remove(HTTPHeaderName name)
{
- return find<CaseFoldingCStringTranslator>(name) != end();
+ return m_commonHeaders.remove(name);
}
-HTTPHeaderMap::AddResult HTTPHeaderMap::add(const char* name, const String& value)
+void HTTPHeaderMap::add(HTTPHeaderName name, const String& value)
{
- return HashMap<AtomicString, String, CaseFoldingHash>::add<CaseFoldingCStringTranslator>(name, value);
+ auto result = m_commonHeaders.add(name, value);
+ if (!result.isNewEntry)
+ result.iterator->value = result.iterator->value + ',' + value;
}
} // namespace WebCore
diff --git a/Source/WebCore/platform/network/HTTPHeaderMap.h b/Source/WebCore/platform/network/HTTPHeaderMap.h
index f4e678747..64559e125 100644
--- a/Source/WebCore/platform/network/HTTPHeaderMap.h
+++ b/Source/WebCore/platform/network/HTTPHeaderMap.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,43 +24,191 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTTPHeaderMap_h
-#define HTTPHeaderMap_h
+#pragma once
+#include "HTTPHeaderNames.h"
#include <utility>
#include <wtf/HashMap.h>
-#include <wtf/PassOwnPtr.h>
-#include <wtf/Vector.h>
-#include <wtf/text/AtomicString.h>
-#include <wtf/text/AtomicStringHash.h>
+#include <wtf/Optional.h>
#include <wtf/text/StringHash.h>
namespace WebCore {
- typedef Vector<std::pair<String, String>> CrossThreadHTTPHeaderMapData;
+// FIXME: Not every header fits into a map. Notably, multiple Set-Cookie header fields are needed to set multiple cookies.
- // FIXME: Not every header fits into a map. Notably, multiple Set-Cookie header fields are needed to set multiple cookies.
- class HTTPHeaderMap : public HashMap<AtomicString, String, CaseFoldingHash> {
+class HTTPHeaderMap {
+public:
+ typedef HashMap<HTTPHeaderName, String, WTF::IntHash<HTTPHeaderName>, WTF::StrongEnumHashTraits<HTTPHeaderName>> CommonHeadersHashMap;
+ typedef HashMap<String, String, ASCIICaseInsensitiveHash> UncommonHeadersHashMap;
+
+ class HTTPHeaderMapConstIterator {
public:
- HTTPHeaderMap();
- ~HTTPHeaderMap();
+ HTTPHeaderMapConstIterator(const HTTPHeaderMap& table, CommonHeadersHashMap::const_iterator commonHeadersIt, UncommonHeadersHashMap::const_iterator uncommonHeadersIt)
+ : m_table(table)
+ , m_commonHeadersIt(commonHeadersIt)
+ , m_uncommonHeadersIt(uncommonHeadersIt)
+ {
+ if (!updateKeyValue(m_commonHeadersIt))
+ updateKeyValue(m_uncommonHeadersIt);
+ }
+
+ struct KeyValue {
+ String key;
+ std::optional<HTTPHeaderName> keyAsHTTPHeaderName;
+ String value;
+ };
+
+ const KeyValue* get() const
+ {
+ ASSERT(*this != m_table.end());
+ return &m_keyValue;
+ }
+ const KeyValue& operator*() const { return *get(); }
+ const KeyValue* operator->() const { return get(); }
- // Gets a copy of the data suitable for passing to another thread.
- PassOwnPtr<CrossThreadHTTPHeaderMapData> copyData() const;
+ HTTPHeaderMapConstIterator& operator++()
+ {
+ if (m_commonHeadersIt != m_table.m_commonHeaders.end()) {
+ if (updateKeyValue(++m_commonHeadersIt))
+ return *this;
+ } else
+ ++m_uncommonHeadersIt;
- void adopt(PassOwnPtr<CrossThreadHTTPHeaderMapData>);
-
- String get(const AtomicString& name) const;
+ updateKeyValue(m_uncommonHeadersIt);
+ return *this;
+ }
- AddResult add(const AtomicString& name, const String& value);
+ bool operator!=(const HTTPHeaderMapConstIterator& other) const { return !(*this == other); }
+ bool operator==(const HTTPHeaderMapConstIterator& other) const
+ {
+ return m_commonHeadersIt == other.m_commonHeadersIt && m_uncommonHeadersIt == other.m_uncommonHeadersIt;
+ }
- // Alternate accessors that are faster than converting the char* to AtomicString first.
- bool contains(const char*) const;
- String get(const char*) const;
- AddResult add(const char* name, const String& value);
-
+ private:
+ bool updateKeyValue(CommonHeadersHashMap::const_iterator it)
+ {
+ if (it == m_table.commonHeaders().end())
+ return false;
+ m_keyValue.key = httpHeaderNameString(it->key).toStringWithoutCopying();
+ m_keyValue.keyAsHTTPHeaderName = it->key;
+ m_keyValue.value = it->value;
+ return true;
+ }
+ bool updateKeyValue(UncommonHeadersHashMap::const_iterator it)
+ {
+ if (it == m_table.uncommonHeaders().end())
+ return false;
+ m_keyValue.key = it->key;
+ m_keyValue.keyAsHTTPHeaderName = std::nullopt;
+ m_keyValue.value = it->value;
+ return true;
+ }
+
+ const HTTPHeaderMap& m_table;
+ CommonHeadersHashMap::const_iterator m_commonHeadersIt;
+ UncommonHeadersHashMap::const_iterator m_uncommonHeadersIt;
+ KeyValue m_keyValue;
};
+ typedef HTTPHeaderMapConstIterator const_iterator;
-} // namespace WebCore
+ WEBCORE_EXPORT HTTPHeaderMap();
+
+ // Gets a copy of the data suitable for passing to another thread.
+ HTTPHeaderMap isolatedCopy() const;
+
+ bool isEmpty() const { return m_commonHeaders.isEmpty() && m_uncommonHeaders.isEmpty(); }
+ int size() const { return m_commonHeaders.size() + m_uncommonHeaders.size(); }
+
+ void clear()
+ {
+ m_commonHeaders.clear();
+ m_uncommonHeaders.clear();
+ }
+
+ WEBCORE_EXPORT String get(const String& name) const;
+ WEBCORE_EXPORT void set(const String& name, const String& value);
+ WEBCORE_EXPORT void add(const String& name, const String& value);
+ WEBCORE_EXPORT bool contains(const String&) const;
+ bool remove(const String&);
+
+#if USE(CF)
+ void set(CFStringRef name, const String& value);
+#ifdef __OBJC__
+ void set(NSString *name, const String& value) { set((__bridge CFStringRef)name, value); }
+#endif
+#endif
+
+ WEBCORE_EXPORT String get(HTTPHeaderName) const;
+ void set(HTTPHeaderName, const String& value);
+ void add(HTTPHeaderName, const String& value);
+ bool addIfNotPresent(HTTPHeaderName, const String&);
+ bool contains(HTTPHeaderName) const;
+ WEBCORE_EXPORT bool remove(HTTPHeaderName);
+
+ // Instead of passing a string literal to any of these functions, just use a HTTPHeaderName instead.
+ template<size_t length> String get(const char (&)[length]) const = delete;
+ template<size_t length> void set(const char (&)[length], const String&) = delete;
+ template<size_t length> bool contains(const char (&)[length]) = delete;
+ template<size_t length> bool remove(const char (&)[length]) = delete;
-#endif // HTTPHeaderMap_h
+ const CommonHeadersHashMap& commonHeaders() const { return m_commonHeaders; }
+ const UncommonHeadersHashMap& uncommonHeaders() const { return m_uncommonHeaders; }
+ CommonHeadersHashMap& commonHeaders() { return m_commonHeaders; }
+ UncommonHeadersHashMap& uncommonHeaders() { return m_uncommonHeaders; }
+
+ const_iterator begin() const { return const_iterator(*this, m_commonHeaders.begin(), m_uncommonHeaders.begin()); }
+ const_iterator end() const { return const_iterator(*this, m_commonHeaders.end(), m_uncommonHeaders.end()); }
+
+ friend bool operator==(const HTTPHeaderMap& a, const HTTPHeaderMap& b)
+ {
+ return a.m_commonHeaders == b.m_commonHeaders && a.m_uncommonHeaders == b.m_uncommonHeaders;
+ }
+
+ friend bool operator!=(const HTTPHeaderMap& a, const HTTPHeaderMap& b)
+ {
+ return !(a == b);
+ }
+
+ template <class Encoder> void encode(Encoder&) const;
+ template <class Decoder> static bool decode(Decoder&, HTTPHeaderMap&);
+
+private:
+ CommonHeadersHashMap m_commonHeaders;
+ UncommonHeadersHashMap m_uncommonHeaders;
+};
+
+template <class Encoder>
+void HTTPHeaderMap::encode(Encoder& encoder) const
+{
+ encoder << static_cast<uint64_t>(m_commonHeaders.size());
+ for (const auto& keyValuePair : m_commonHeaders) {
+ encoder.encodeEnum(keyValuePair.key);
+ encoder << keyValuePair.value;
+ }
+
+ encoder << m_uncommonHeaders;
+}
+
+template <class Decoder>
+bool HTTPHeaderMap::decode(Decoder& decoder, HTTPHeaderMap& headerMap)
+{
+ uint64_t commonHeadersSize;
+ if (!decoder.decode(commonHeadersSize))
+ return false;
+ for (size_t i = 0; i < commonHeadersSize; ++i) {
+ HTTPHeaderName name;
+ if (!decoder.decodeEnum(name))
+ return false;
+ String value;
+ if (!decoder.decode(value))
+ return false;
+ headerMap.m_commonHeaders.add(name, value);
+ }
+
+ if (!decoder.decode(headerMap.m_uncommonHeaders))
+ return false;
+
+ return true;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/network/HTTPHeaderNames.in b/Source/WebCore/platform/network/HTTPHeaderNames.in
new file mode 100644
index 000000000..0699c9bcb
--- /dev/null
+++ b/Source/WebCore/platform/network/HTTPHeaderNames.in
@@ -0,0 +1,112 @@
+//
+// Copyright (C) 2014 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+Accept
+Accept-Charset
+Accept-Language
+Accept-Encoding
+Accept-Ranges
+Access-Control-Allow-Credentials
+Access-Control-Allow-Headers
+Access-Control-Allow-Methods
+Access-Control-Allow-Origin
+Access-Control-Expose-Headers
+Access-Control-Max-Age
+Access-Control-Request-Headers
+Access-Control-Request-Method
+Age
+Alternate-Protocol
+Authorization
+Cache-Control
+Connection
+Content-Disposition
+Content-Encoding
+Content-Language
+Content-Length
+Content-Security-Policy
+Content-Security-Policy-Report-Only
+Content-Type
+Content-Transfer-Encoding
+Content-Range
+Cookie
+Cookie2
+Date
+DNT
+Default-Style
+ETag
+Expect
+Expires
+Host
+If-Match
+If-Modified-Since
+If-None-Match
+If-Range
+If-Unmodified-Since
+Keep-Alive
+Last-Event-ID
+Last-Modified
+Location
+Link
+Origin
+Ping-From
+Ping-To
+Purpose
+Pragma
+Range
+Referer
+Refresh
+Sec-WebSocket-Accept
+Sec-WebSocket-Extensions
+Sec-WebSocket-Key
+Sec-WebSocket-Protocol
+Sec-WebSocket-Version
+Server
+Set-Cookie
+Set-Cookie2
+TE
+Timing-Allow-Origin
+Trailer
+Transfer-Encoding
+Upgrade
+Upgrade-Insecure-Requests
+User-Agent
+Vary
+Via
+X-Check-Cacheable
+X-Content-Type-Options
+X-DNS-Prefetch-Control
+X-Frame-Options
+X-Powered-By
+X-WebKit-CSP
+X-WebKit-CSP-Report-Only
+X-XSS-Protection
+
+// These headers are specific to GStreamer.
+Icy-Genre
+Icy-MetaInt
+Icy-Metadata
+Icy-Name
+Icy-Title
+Icy-URL
diff --git a/Source/WebCore/platform/network/HTTPHeaderValues.cpp b/Source/WebCore/platform/network/HTTPHeaderValues.cpp
new file mode 100644
index 000000000..72df220a0
--- /dev/null
+++ b/Source/WebCore/platform/network/HTTPHeaderValues.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "HTTPHeaderValues.h"
+
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+namespace HTTPHeaderValues {
+
+const String& textPlainContentType()
+{
+ static NeverDestroyed<const String> contentType(ASCIILiteral("text/plain;charset=UTF-8"));
+ return contentType;
+}
+
+const String& formURLEncodedContentType()
+{
+ static NeverDestroyed<const String> contentType(ASCIILiteral("application/x-www-form-urlencoded;charset=UTF-8"));
+ return contentType;
+}
+
+const String& noCache()
+{
+ static NeverDestroyed<const String> value(ASCIILiteral("no-cache"));
+ return value;
+}
+
+const String& maxAge0()
+{
+ static NeverDestroyed<const String> value(ASCIILiteral("max-age=0"));
+ return value;
+}
+
+}
+
+}
diff --git a/Source/WebCore/platform/network/HTTPHeaderValues.h b/Source/WebCore/platform/network/HTTPHeaderValues.h
new file mode 100644
index 000000000..9d85f961b
--- /dev/null
+++ b/Source/WebCore/platform/network/HTTPHeaderValues.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+namespace HTTPHeaderValues {
+
+const String& textPlainContentType();
+const String& formURLEncodedContentType();
+const String& noCache();
+const String& maxAge0();
+}
+
+}
diff --git a/Source/WebCore/platform/network/HTTPParsers.cpp b/Source/WebCore/platform/network/HTTPParsers.cpp
index 54b85d7f1..158e2d9b5 100644
--- a/Source/WebCore/platform/network/HTTPParsers.cpp
+++ b/Source/WebCore/platform/network/HTTPParsers.cpp
@@ -14,7 +14,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -33,8 +33,10 @@
#include "config.h"
#include "HTTPParsers.h"
-#include "ContentSecurityPolicy.h"
+#include "HTTPHeaderNames.h"
+#include "Language.h"
#include <wtf/DateMath.h>
+#include <wtf/NeverDestroyed.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringBuilder.h>
#include <wtf/text/WTFString.h>
@@ -46,17 +48,12 @@ namespace WebCore {
// true if there is more to parse, after incrementing pos past whitespace.
// Note: Might return pos == str.length()
-static inline bool skipWhiteSpace(const String& str, unsigned& pos, bool fromHttpEquivMeta)
+static inline bool skipWhiteSpace(const String& str, unsigned& pos)
{
unsigned len = str.length();
- if (fromHttpEquivMeta) {
- while (pos < len && str[pos] <= ' ')
- ++pos;
- } else {
- while (pos < len && (str[pos] == '\t' || str[pos] == ' '))
- ++pos;
- }
+ while (pos < len && (str[pos] == '\t' || str[pos] == ' '))
+ ++pos;
return pos < len;
}
@@ -85,7 +82,7 @@ static inline bool skipToken(const String& str, unsigned& pos, const char* token
// True if the expected equals sign is seen and there is more to follow.
static inline bool skipEquals(const String& str, unsigned &pos)
{
- return skipWhiteSpace(str, pos, false) && str[pos++] == '=' && skipWhiteSpace(str, pos, false);
+ return skipWhiteSpace(str, pos) && str[pos++] == '=' && skipWhiteSpace(str, pos);
}
// True if a value present, incrementing pos to next space or semicolon, if any.
@@ -102,21 +99,82 @@ static inline bool skipValue(const String& str, unsigned& pos)
return pos != start;
}
-bool isValidHTTPHeaderValue(const String& name)
+// See RFC 7230, Section 3.1.2.
+bool isValidReasonPhrase(const String& value)
+{
+ for (unsigned i = 0; i < value.length(); ++i) {
+ UChar c = value[i];
+ if (c == 0x7F || c > 0xFF || (c < 0x20 && c != '\t'))
+ return false;
+ }
+ return true;
+}
+
+// See RFC 7230, Section 3.2.3.
+bool isValidHTTPHeaderValue(const String& value)
{
- // FIXME: This should really match name against
- // field-value in section 4.2 of RFC 2616.
+ UChar c = value[0];
+ if (c == ' ' || c == '\t')
+ return false;
+ c = value[value.length() - 1];
+ if (c == ' ' || c == '\t')
+ return false;
+ for (unsigned i = 0; i < value.length(); ++i) {
+ c = value[i];
+ if (c == 0x7F || c > 0xFF || (c < 0x20 && c != '\t'))
+ return false;
+ }
+ return true;
+}
+
+// See RFC 7230, Section 3.2.6.
+static bool isDelimiterCharacter(const UChar c)
+{
+ // DQUOTE and "(),/:;<=>?@[\]{}"
+ return (c == '"' || c == '(' || c == ')' || c == ',' || c == '/' || c == ':' || c == ';'
+ || c == '<' || c == '=' || c == '>' || c == '?' || c == '@' || c == '[' || c == '\\'
+ || c == ']' || c == '{' || c == '}');
+}
+
+// See RFC 7231, Section 5.3.2.
+bool isValidAcceptHeaderValue(const String& value)
+{
+ for (unsigned i = 0; i < value.length(); ++i) {
+ UChar c = value[i];
+ // First check for alphanumeric for performance reasons then whitelist four delimiter characters.
+ if (isASCIIAlphanumeric(c) || c == ',' || c == '/' || c == ';' || c == '=')
+ continue;
+ if (isDelimiterCharacter(c))
+ return false;
+ }
+
+ return true;
+}
- return !name.contains('\r') && !name.contains('\n');
+// See RFC 7231, Section 5.3.5 and 3.1.3.2.
+bool isValidLanguageHeaderValue(const String& value)
+{
+ for (unsigned i = 0; i < value.length(); ++i) {
+ UChar c = value[i];
+ if (isASCIIAlphanumeric(c) || c == ' ' || c == '*' || c == ',' || c == '-' || c == '.' || c == ';' || c == '=')
+ continue;
+ return false;
+ }
+
+ // FIXME: Validate further by splitting into language tags and optional quality
+ // values (q=) and then check each language tag.
+ // Language tags https://tools.ietf.org/html/rfc7231#section-3.1.3.1
+ // Language tag syntax https://tools.ietf.org/html/bcp47#section-2.1
+ return true;
}
-// See RFC 2616, Section 2.2.
-bool isValidHTTPToken(const String& characters)
+// See RFC 7230, Section 3.2.6.
+bool isValidHTTPToken(const String& value)
{
- if (characters.isEmpty())
+ if (value.isEmpty())
return false;
- for (unsigned i = 0; i < characters.length(); ++i) {
- UChar c = characters[i];
+ auto valueStringView = StringView(value);
+ for (UChar c : valueStringView.codeUnits()) {
if (c <= 0x20 || c >= 0x7F
|| c == '(' || c == ')' || c == '<' || c == '>' || c == '@'
|| c == ',' || c == ';' || c == ':' || c == '\\' || c == '"'
@@ -136,42 +194,12 @@ static String trimInputSample(const char* p, size_t length)
return s;
}
-ContentDispositionType contentDispositionType(const String& contentDisposition)
-{
- if (contentDisposition.isEmpty())
- return ContentDispositionNone;
-
- Vector<String> parameters;
- contentDisposition.split(';', parameters);
-
- String dispositionType = parameters[0];
- dispositionType.stripWhiteSpace();
-
- if (equalIgnoringCase(dispositionType, "inline"))
- return ContentDispositionInline;
-
- // Some broken sites just send bogus headers like
- //
- // Content-Disposition: ; filename="file"
- // Content-Disposition: filename="file"
- // Content-Disposition: name="file"
- //
- // without a disposition token... screen those out.
- if (!isValidHTTPToken(dispositionType))
- return ContentDispositionNone;
-
- // We have a content-disposition of "attachment" or unknown.
- // RFC 2183, section 2.8 says that an unknown disposition
- // value should be treated as "attachment"
- return ContentDispositionAttachment;
-}
-
-bool parseHTTPRefresh(const String& refresh, bool fromHttpEquivMeta, double& delay, String& url)
+bool parseHTTPRefresh(const String& refresh, double& delay, String& url)
{
unsigned len = refresh.length();
unsigned pos = 0;
- if (!skipWhiteSpace(refresh, pos, fromHttpEquivMeta))
+ if (!skipWhiteSpace(refresh, pos))
return false;
while (pos != len && refresh[pos] != ',' && refresh[pos] != ';')
@@ -189,14 +217,14 @@ bool parseHTTPRefresh(const String& refresh, bool fromHttpEquivMeta, double& del
return false;
++pos;
- skipWhiteSpace(refresh, pos, fromHttpEquivMeta);
+ skipWhiteSpace(refresh, pos);
unsigned urlStartPos = pos;
if (refresh.find("url", urlStartPos, false) == urlStartPos) {
urlStartPos += 3;
- skipWhiteSpace(refresh, urlStartPos, fromHttpEquivMeta);
+ skipWhiteSpace(refresh, urlStartPos);
if (refresh[urlStartPos] == '=') {
++urlStartPos;
- skipWhiteSpace(refresh, urlStartPos, fromHttpEquivMeta);
+ skipWhiteSpace(refresh, urlStartPos);
} else
urlStartPos = pos; // e.g. "Refresh: 0; url.html"
}
@@ -214,7 +242,7 @@ bool parseHTTPRefresh(const String& refresh, bool fromHttpEquivMeta, double& del
// https://bugs.webkit.org/show_bug.cgi?id=27868
// Sometimes there is no closing quote for the end of the URL even though there was an opening quote.
- // If we looped over the entire alleged URL string back to the opening quote, just go ahead and use everything
+ // If we looped over the entire alleged URL string back to the opening quote, just use everything
// after the opening quote instead.
if (urlEndPos == urlStartPos)
urlEndPos = len;
@@ -225,9 +253,14 @@ bool parseHTTPRefresh(const String& refresh, bool fromHttpEquivMeta, double& del
}
}
-double parseDate(const String& value)
+std::optional<std::chrono::system_clock::time_point> parseHTTPDate(const String& value)
{
- return parseDateFromNullTerminatedCharacters(value.utf8().data());
+ double dateInMillisecondsSinceEpoch = parseDateFromNullTerminatedCharacters(value.utf8().data());
+ if (!std::isfinite(dateInMillisecondsSinceEpoch))
+ return { };
+ // This assumes system_clock epoch equals Unix epoch which is true for all implementations but unspecified.
+ // FIXME: The parsing function should be switched to std::chrono too.
+ return std::chrono::system_clock::time_point(std::chrono::milliseconds(static_cast<long long>(dateInMillisecondsSinceEpoch)));
}
// FIXME: This function doesn't comply with RFC 6266.
@@ -349,46 +382,46 @@ void findCharsetInMediaType(const String& mediaType, unsigned int& charsetPos, u
}
}
-ContentSecurityPolicy::ReflectedXSSDisposition parseXSSProtectionHeader(const String& header, String& failureReason, unsigned& failurePosition, String& reportURL)
+XSSProtectionDisposition parseXSSProtectionHeader(const String& header, String& failureReason, unsigned& failurePosition, String& reportURL)
{
- DEFINE_STATIC_LOCAL(String, failureReasonInvalidToggle, (ASCIILiteral("expected 0 or 1")));
- DEFINE_STATIC_LOCAL(String, failureReasonInvalidSeparator, (ASCIILiteral("expected semicolon")));
- DEFINE_STATIC_LOCAL(String, failureReasonInvalidEquals, (ASCIILiteral("expected equals sign")));
- DEFINE_STATIC_LOCAL(String, failureReasonInvalidMode, (ASCIILiteral("invalid mode directive")));
- DEFINE_STATIC_LOCAL(String, failureReasonInvalidReport, (ASCIILiteral("invalid report directive")));
- DEFINE_STATIC_LOCAL(String, failureReasonDuplicateMode, (ASCIILiteral("duplicate mode directive")));
- DEFINE_STATIC_LOCAL(String, failureReasonDuplicateReport, (ASCIILiteral("duplicate report directive")));
- DEFINE_STATIC_LOCAL(String, failureReasonInvalidDirective, (ASCIILiteral("unrecognized directive")));
+ static NeverDestroyed<String> failureReasonInvalidToggle(ASCIILiteral("expected 0 or 1"));
+ static NeverDestroyed<String> failureReasonInvalidSeparator(ASCIILiteral("expected semicolon"));
+ static NeverDestroyed<String> failureReasonInvalidEquals(ASCIILiteral("expected equals sign"));
+ static NeverDestroyed<String> failureReasonInvalidMode(ASCIILiteral("invalid mode directive"));
+ static NeverDestroyed<String> failureReasonInvalidReport(ASCIILiteral("invalid report directive"));
+ static NeverDestroyed<String> failureReasonDuplicateMode(ASCIILiteral("duplicate mode directive"));
+ static NeverDestroyed<String> failureReasonDuplicateReport(ASCIILiteral("duplicate report directive"));
+ static NeverDestroyed<String> failureReasonInvalidDirective(ASCIILiteral("unrecognized directive"));
unsigned pos = 0;
- if (!skipWhiteSpace(header, pos, false))
- return ContentSecurityPolicy::ReflectedXSSUnset;
+ if (!skipWhiteSpace(header, pos))
+ return XSSProtectionDisposition::Enabled;
if (header[pos] == '0')
- return ContentSecurityPolicy::AllowReflectedXSS;
+ return XSSProtectionDisposition::Disabled;
if (header[pos++] != '1') {
failureReason = failureReasonInvalidToggle;
- return ContentSecurityPolicy::ReflectedXSSInvalid;
+ return XSSProtectionDisposition::Invalid;
}
- ContentSecurityPolicy::ReflectedXSSDisposition result = ContentSecurityPolicy::FilterReflectedXSS;
+ XSSProtectionDisposition result = XSSProtectionDisposition::Enabled;
bool modeDirectiveSeen = false;
bool reportDirectiveSeen = false;
while (1) {
// At end of previous directive: consume whitespace, semicolon, and whitespace.
- if (!skipWhiteSpace(header, pos, false))
+ if (!skipWhiteSpace(header, pos))
return result;
if (header[pos++] != ';') {
failureReason = failureReasonInvalidSeparator;
failurePosition = pos;
- return ContentSecurityPolicy::ReflectedXSSInvalid;
+ return XSSProtectionDisposition::Invalid;
}
- if (!skipWhiteSpace(header, pos, false))
+ if (!skipWhiteSpace(header, pos))
return result;
// At start of next directive.
@@ -396,44 +429,44 @@ ContentSecurityPolicy::ReflectedXSSDisposition parseXSSProtectionHeader(const St
if (modeDirectiveSeen) {
failureReason = failureReasonDuplicateMode;
failurePosition = pos;
- return ContentSecurityPolicy::ReflectedXSSInvalid;
+ return XSSProtectionDisposition::Invalid;
}
modeDirectiveSeen = true;
if (!skipEquals(header, pos)) {
failureReason = failureReasonInvalidEquals;
failurePosition = pos;
- return ContentSecurityPolicy::ReflectedXSSInvalid;
+ return XSSProtectionDisposition::Invalid;
}
if (!skipToken(header, pos, "block")) {
failureReason = failureReasonInvalidMode;
failurePosition = pos;
- return ContentSecurityPolicy::ReflectedXSSInvalid;
+ return XSSProtectionDisposition::Invalid;
}
- result = ContentSecurityPolicy::BlockReflectedXSS;
+ result = XSSProtectionDisposition::BlockEnabled;
} else if (skipToken(header, pos, "report")) {
if (reportDirectiveSeen) {
failureReason = failureReasonDuplicateReport;
failurePosition = pos;
- return ContentSecurityPolicy::ReflectedXSSInvalid;
+ return XSSProtectionDisposition::Invalid;
}
reportDirectiveSeen = true;
if (!skipEquals(header, pos)) {
failureReason = failureReasonInvalidEquals;
failurePosition = pos;
- return ContentSecurityPolicy::ReflectedXSSInvalid;
+ return XSSProtectionDisposition::Invalid;
}
size_t startPos = pos;
if (!skipValue(header, pos)) {
failureReason = failureReasonInvalidReport;
failurePosition = pos;
- return ContentSecurityPolicy::ReflectedXSSInvalid;
+ return XSSProtectionDisposition::Invalid;
}
reportURL = header.substring(startPos, pos - startPos);
failurePosition = startPos; // If later semantic check deems unacceptable.
} else {
failureReason = failureReasonInvalidDirective;
failurePosition = pos;
- return ContentSecurityPolicy::ReflectedXSSInvalid;
+ return XSSProtectionDisposition::Invalid;
}
}
}
@@ -441,18 +474,19 @@ ContentSecurityPolicy::ReflectedXSSDisposition parseXSSProtectionHeader(const St
#if ENABLE(NOSNIFF)
ContentTypeOptionsDisposition parseContentTypeOptionsHeader(const String& header)
{
- if (header.stripWhiteSpace().lower() == "nosniff")
+ if (equalLettersIgnoringASCIICase(header.stripWhiteSpace(), "nosniff"))
return ContentTypeOptionsNosniff;
return ContentTypeOptionsNone;
}
#endif
-String extractReasonPhraseFromHTTPStatusLine(const String& statusLine)
+AtomicString extractReasonPhraseFromHTTPStatusLine(const String& statusLine)
{
- size_t spacePos = statusLine.find(' ');
+ StringView view = statusLine;
+ size_t spacePos = view.find(' ');
// Remove status code from the status line.
- spacePos = statusLine.find(' ', spacePos + 1);
- return statusLine.substring(spacePos + 1);
+ spacePos = view.find(' ', spacePos + 1);
+ return view.substring(spacePos + 1).toAtomicString();
}
XFrameOptionsDisposition parseXFrameOptionsHeader(const String& header)
@@ -468,11 +502,11 @@ XFrameOptionsDisposition parseXFrameOptionsHeader(const String& header)
for (size_t i = 0; i < headers.size(); i++) {
String currentHeader = headers[i].stripWhiteSpace();
XFrameOptionsDisposition currentValue = XFrameOptionsNone;
- if (equalIgnoringCase(currentHeader, "deny"))
+ if (equalLettersIgnoringASCIICase(currentHeader, "deny"))
currentValue = XFrameOptionsDeny;
- else if (equalIgnoringCase(currentHeader, "sameorigin"))
+ else if (equalLettersIgnoringASCIICase(currentHeader, "sameorigin"))
currentValue = XFrameOptionsSameOrigin;
- else if (equalIgnoringCase(currentHeader, "allowall"))
+ else if (equalLettersIgnoringASCIICase(currentHeader, "allowall"))
currentValue = XFrameOptionsAllowAll;
else
currentValue = XFrameOptionsInvalid;
@@ -568,20 +602,20 @@ size_t parseHTTPRequestLine(const char* data, size_t length, String& failureReas
// Haven't finished header line.
if (consumedLength == length) {
- failureReason = "Incomplete Request Line";
+ failureReason = ASCIILiteral("Incomplete Request Line");
return 0;
}
// RequestLine does not contain 3 parts.
if (!space1 || !space2) {
- failureReason = "Request Line does not appear to contain: <Method> <Url> <HTTPVersion>.";
+ failureReason = ASCIILiteral("Request Line does not appear to contain: <Method> <Url> <HTTPVersion>.");
return 0;
}
// The line must end with "\r\n".
const char* end = p + 1;
if (*(end - 2) != '\r') {
- failureReason = "Request line does not end with CRLF";
+ failureReason = ASCIILiteral("Request line does not end with CRLF");
return 0;
}
@@ -605,14 +639,48 @@ size_t parseHTTPRequestLine(const char* data, size_t length, String& failureReas
return end - data;
}
-size_t parseHTTPHeader(const char* start, size_t length, String& failureReason, AtomicString& nameStr, String& valueStr, bool strict)
+static inline bool isValidHeaderNameCharacter(const char* character)
+{
+ // https://tools.ietf.org/html/rfc7230#section-3.2
+ // A header name should only contain one or more of
+ // alphanumeric or ! # $ % & ' * + - . ^ _ ` | ~
+ if (isASCIIAlphanumeric(*character))
+ return true;
+ switch (*character) {
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '*':
+ case '+':
+ case '-':
+ case '.':
+ case '^':
+ case '_':
+ case '`':
+ case '|':
+ case '~':
+ return true;
+ default:
+ return false;
+ }
+}
+
+size_t parseHTTPHeader(const char* start, size_t length, String& failureReason, StringView& nameStr, String& valueStr, bool strict)
{
const char* p = start;
const char* end = start + length;
Vector<char> name;
Vector<char> value;
- nameStr = AtomicString();
+
+ bool foundFirstNameChar = false;
+ const char* namePtr = nullptr;
+ size_t nameSize = 0;
+
+ nameStr = StringView();
valueStr = String();
for (; p < end; p++) {
@@ -621,18 +689,29 @@ size_t parseHTTPHeader(const char* start, size_t length, String& failureReason,
if (name.isEmpty()) {
if (p + 1 < end && *(p + 1) == '\n')
return (p + 2) - start;
- failureReason = "CR doesn't follow LF at " + trimInputSample(p, end - p);
+ failureReason = makeString("CR doesn't follow LF in header name at ", trimInputSample(p, end - p));
return 0;
}
- failureReason = "Unexpected CR in name at " + trimInputSample(name.data(), name.size());
+ failureReason = makeString("Unexpected CR in header name at ", trimInputSample(name.data(), name.size()));
return 0;
case '\n':
- failureReason = "Unexpected LF in name at " + trimInputSample(name.data(), name.size());
+ failureReason = makeString("Unexpected LF in header name at ", trimInputSample(name.data(), name.size()));
return 0;
case ':':
break;
default:
+ if (!isValidHeaderNameCharacter(p)) {
+ if (name.size() < 1)
+ failureReason = "Unexpected start character in header name";
+ else
+ failureReason = makeString("Unexpected character in header name at ", trimInputSample(name.data(), name.size()));
+ return 0;
+ }
name.append(*p);
+ if (!foundFirstNameChar) {
+ namePtr = p;
+ foundFirstNameChar = true;
+ }
continue;
}
if (*p == ':') {
@@ -641,6 +720,9 @@ size_t parseHTTPHeader(const char* start, size_t length, String& failureReason,
}
}
+ nameSize = name.size();
+ nameStr = StringView(reinterpret_cast<const LChar*>(namePtr), nameSize);
+
for (; p < end && *p == 0x20; p++) { }
for (; p < end; p++) {
@@ -649,7 +731,7 @@ size_t parseHTTPHeader(const char* start, size_t length, String& failureReason,
break;
case '\n':
if (strict) {
- failureReason = "Unexpected LF in value at " + trimInputSample(value.data(), value.size());
+ failureReason = makeString("Unexpected LF in header value at ", trimInputSample(value.data(), value.size()));
return 0;
}
break;
@@ -662,17 +744,12 @@ size_t parseHTTPHeader(const char* start, size_t length, String& failureReason,
}
}
if (p >= end || (strict && *p != '\n')) {
- failureReason = "CR doesn't follow LF after value at " + trimInputSample(p, end - p);
+ failureReason = makeString("CR doesn't follow LF after header value at ", trimInputSample(p, end - p));
return 0;
}
- nameStr = AtomicString::fromUTF8(name.data(), name.size());
valueStr = String::fromUTF8(value.data(), value.size());
- if (nameStr.isNull()) {
- failureReason = "Invalid UTF-8 sequence in header name";
- return 0;
- }
if (valueStr.isNull()) {
- failureReason = "Invalid UTF-8 sequence in header value";
+ failureReason = ASCIILiteral("Invalid UTF-8 sequence in header value");
return 0;
}
return p - start;
@@ -686,4 +763,111 @@ size_t parseHTTPRequestBody(const char* data, size_t length, Vector<unsigned cha
return length;
}
+void parseAccessControlExposeHeadersAllowList(const String& headerValue, HTTPHeaderSet& headerSet)
+{
+ Vector<String> headers;
+ headerValue.split(',', false, headers);
+ for (auto& header : headers) {
+ String strippedHeader = header.stripWhiteSpace();
+ if (!strippedHeader.isEmpty())
+ headerSet.add(strippedHeader);
+ }
+}
+
+// Implementation of https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name
+bool isForbiddenHeaderName(const String& name)
+{
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName)) {
+ switch (headerName) {
+ case HTTPHeaderName::AcceptCharset:
+ case HTTPHeaderName::AcceptEncoding:
+ case HTTPHeaderName::AccessControlRequestHeaders:
+ case HTTPHeaderName::AccessControlRequestMethod:
+ case HTTPHeaderName::Connection:
+ case HTTPHeaderName::ContentLength:
+ case HTTPHeaderName::Cookie:
+ case HTTPHeaderName::Cookie2:
+ case HTTPHeaderName::Date:
+ case HTTPHeaderName::DNT:
+ case HTTPHeaderName::Expect:
+ case HTTPHeaderName::Host:
+ case HTTPHeaderName::KeepAlive:
+ case HTTPHeaderName::Origin:
+ case HTTPHeaderName::Referer:
+ case HTTPHeaderName::TE:
+ case HTTPHeaderName::Trailer:
+ case HTTPHeaderName::TransferEncoding:
+ case HTTPHeaderName::Upgrade:
+ case HTTPHeaderName::Via:
+ return true;
+ default:
+ break;
+ }
+ }
+ return startsWithLettersIgnoringASCIICase(name, "sec-") || startsWithLettersIgnoringASCIICase(name, "proxy-");
+}
+
+bool isForbiddenResponseHeaderName(const String& name)
+{
+ return equalLettersIgnoringASCIICase(name, "set-cookie") || equalLettersIgnoringASCIICase(name, "set-cookie2");
+}
+
+bool isSimpleHeader(const String& name, const String& value)
+{
+ HTTPHeaderName headerName;
+ if (!findHTTPHeaderName(name, headerName))
+ return false;
+ return isCrossOriginSafeRequestHeader(headerName, value);
+}
+
+bool isCrossOriginSafeHeader(HTTPHeaderName name, const HTTPHeaderSet& accessControlExposeHeaderSet)
+{
+ switch (name) {
+ case HTTPHeaderName::CacheControl:
+ case HTTPHeaderName::ContentLanguage:
+ case HTTPHeaderName::ContentType:
+ case HTTPHeaderName::Expires:
+ case HTTPHeaderName::LastModified:
+ case HTTPHeaderName::Pragma:
+ case HTTPHeaderName::Accept:
+ return true;
+ case HTTPHeaderName::SetCookie:
+ case HTTPHeaderName::SetCookie2:
+ return false;
+ default:
+ break;
+ }
+ return accessControlExposeHeaderSet.contains(httpHeaderNameString(name).toStringWithoutCopying());
+}
+
+bool isCrossOriginSafeHeader(const String& name, const HTTPHeaderSet& accessControlExposeHeaderSet)
+{
+#ifndef ASSERT_DISABLED
+ HTTPHeaderName headerName;
+ ASSERT(!findHTTPHeaderName(name, headerName));
+#endif
+ return accessControlExposeHeaderSet.contains(name);
+}
+
+// Implements https://fetch.spec.whatwg.org/#cors-safelisted-request-header
+bool isCrossOriginSafeRequestHeader(HTTPHeaderName name, const String& value)
+{
+ switch (name) {
+ case HTTPHeaderName::Accept:
+ return isValidAcceptHeaderValue(value);
+ case HTTPHeaderName::AcceptLanguage:
+ case HTTPHeaderName::ContentLanguage:
+ return isValidLanguageHeaderValue(value);
+ case HTTPHeaderName::ContentType: {
+ // Preflight is required for MIME types that can not be sent via form submission.
+ String mimeType = extractMIMETypeFromMediaType(value);
+ return equalLettersIgnoringASCIICase(mimeType, "application/x-www-form-urlencoded") || equalLettersIgnoringASCIICase(mimeType, "multipart/form-data") || equalLettersIgnoringASCIICase(mimeType, "text/plain");
+ }
+ default:
+ // FIXME: Should we also make safe other headers (DPR, Downlink, Save-Data...)? That would require validating their values.
+ return false;
+ }
+}
+
}
diff --git a/Source/WebCore/platform/network/HTTPParsers.h b/Source/WebCore/platform/network/HTTPParsers.h
index 2c570f3c4..0c04240ae 100644
--- a/Source/WebCore/platform/network/HTTPParsers.h
+++ b/Source/WebCore/platform/network/HTTPParsers.h
@@ -12,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -31,20 +31,24 @@
#ifndef HTTPParsers_h
#define HTTPParsers_h
-#include "ContentSecurityPolicy.h"
#include <wtf/Forward.h>
+#include <wtf/HashSet.h>
+#include <wtf/Optional.h>
#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
namespace WebCore {
-class HTTPHeaderMap;
-class ResourceResponseBase;
+typedef HashSet<String, ASCIICaseInsensitiveHash> HTTPHeaderSet;
-enum ContentDispositionType {
- ContentDispositionNone,
- ContentDispositionInline,
- ContentDispositionAttachment,
- ContentDispositionOther
+enum class HTTPHeaderName;
+
+enum class XSSProtectionDisposition {
+ Invalid,
+ Disabled,
+ Enabled,
+ BlockEnabled,
};
#if ENABLE(NOSNIFF)
@@ -63,21 +67,23 @@ enum XFrameOptionsDisposition {
XFrameOptionsConflict
};
-ContentDispositionType contentDispositionType(const String&);
+bool isValidReasonPhrase(const String&);
bool isValidHTTPHeaderValue(const String&);
+bool isValidAcceptHeaderValue(const String&);
+bool isValidLanguageHeaderValue(const String&);
bool isValidHTTPToken(const String&);
-bool parseHTTPRefresh(const String& refresh, bool fromHttpEquivMeta, double& delay, String& url);
-double parseDate(const String&);
-String filenameFromHTTPContentDisposition(const String&);
+bool parseHTTPRefresh(const String& refresh, double& delay, String& url);
+std::optional<std::chrono::system_clock::time_point> parseHTTPDate(const String&);
+String filenameFromHTTPContentDisposition(const String&);
String extractMIMETypeFromMediaType(const String&);
-String extractCharsetFromMediaType(const String&);
+String extractCharsetFromMediaType(const String&);
void findCharsetInMediaType(const String& mediaType, unsigned int& charsetPos, unsigned int& charsetLen, unsigned int start = 0);
-ContentSecurityPolicy::ReflectedXSSDisposition parseXSSProtectionHeader(const String& header, String& failureReason, unsigned& failurePosition, String& reportURL);
-String extractReasonPhraseFromHTTPStatusLine(const String&);
+XSSProtectionDisposition parseXSSProtectionHeader(const String& header, String& failureReason, unsigned& failurePosition, String& reportURL);
+AtomicString extractReasonPhraseFromHTTPStatusLine(const String&);
XFrameOptionsDisposition parseXFrameOptionsHeader(const String&);
// -1 could be set to one of the return parameters to indicate the value is not specified.
-bool parseRange(const String&, long long& rangeOffset, long long& rangeEnd, long long& rangeSuffixLength);
+WEBCORE_EXPORT bool parseRange(const String&, long long& rangeOffset, long long& rangeEnd, long long& rangeSuffixLength);
#if ENABLE(NOSNIFF)
ContentTypeOptionsDisposition parseContentTypeOptionsHeader(const String& header);
@@ -86,9 +92,30 @@ ContentTypeOptionsDisposition parseContentTypeOptionsHeader(const String& header
// Parsing Complete HTTP Messages.
enum HTTPVersion { Unknown, HTTP_1_0, HTTP_1_1 };
size_t parseHTTPRequestLine(const char* data, size_t length, String& failureReason, String& method, String& url, HTTPVersion&);
-size_t parseHTTPHeader(const char* data, size_t length, String& failureReason, AtomicString& nameStr, String& valueStr, bool strict = true);
+size_t parseHTTPHeader(const char* data, size_t length, String& failureReason, StringView& nameStr, String& valueStr, bool strict = true);
size_t parseHTTPRequestBody(const char* data, size_t length, Vector<unsigned char>& body);
+void parseAccessControlExposeHeadersAllowList(const String& headerValue, HTTPHeaderSet&);
+
+// HTTP Header routine as per https://fetch.spec.whatwg.org/#terminology-headers
+bool isForbiddenHeaderName(const String&);
+bool isForbiddenResponseHeaderName(const String&);
+bool isSimpleHeader(const String& name, const String& value);
+bool isCrossOriginSafeHeader(HTTPHeaderName, const HTTPHeaderSet&);
+bool isCrossOriginSafeHeader(const String&, const HTTPHeaderSet&);
+bool isCrossOriginSafeRequestHeader(HTTPHeaderName, const String&);
+
+inline bool isHTTPSpace(UChar character)
+{
+ return character <= ' ' && (character == ' ' || character == '\n' || character == '\t' || character == '\r');
+}
+
+// Strip leading and trailing whitespace as defined in https://fetch.spec.whatwg.org/#concept-header-value-normalize.
+inline String stripLeadingAndTrailingHTTPSpaces(const String& string)
+{
+ return string.stripWhiteSpace(isHTTPSpace);
+}
+
}
#endif
diff --git a/Source/WebCore/platform/network/HTTPStatusCodes.h b/Source/WebCore/platform/network/HTTPStatusCodes.h
new file mode 100644
index 000000000..c1ac8dc55
--- /dev/null
+++ b/Source/WebCore/platform/network/HTTPStatusCodes.h
@@ -0,0 +1,27 @@
+/*
+ Copyright (C) 2011 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.
+*/
+
+namespace WebCore {
+
+enum HTTPStatusCodes {
+ HTTPNoContent = 204,
+ HTTPResetContent = 205
+};
+
+}
diff --git a/Source/WebCore/platform/network/MIMEHeader.cpp b/Source/WebCore/platform/network/MIMEHeader.cpp
index 048abf807..267b597b1 100644
--- a/Source/WebCore/platform/network/MIMEHeader.cpp
+++ b/Source/WebCore/platform/network/MIMEHeader.cpp
@@ -43,13 +43,13 @@ namespace WebCore {
typedef HashMap<String, String> KeyValueMap;
-static KeyValueMap retrieveKeyValuePairs(WebCore::SharedBufferChunkReader* buffer)
+static KeyValueMap retrieveKeyValuePairs(WebCore::SharedBufferChunkReader& buffer)
{
KeyValueMap keyValuePairs;
String line;
String key;
StringBuilder value;
- while (!(line = buffer->nextChunkAsUTF8StringWithLatin1Fallback()).isNull()) {
+ while (!(line = buffer.nextChunkAsUTF8StringWithLatin1Fallback()).isNull()) {
if (line.isEmpty())
break; // Empty line means end of key/value section.
if (line[0] == '\t') {
@@ -70,7 +70,7 @@ static KeyValueMap retrieveKeyValuePairs(WebCore::SharedBufferChunkReader* buffe
// This is not a key value pair, ignore.
continue;
}
- key = line.substring(0, semiColonIndex).lower().stripWhiteSpace();
+ key = line.substring(0, semiColonIndex).convertToASCIILowercase().stripWhiteSpace();
value.append(line.substring(semiColonIndex + 1));
}
// Store the last property if there is one.
@@ -79,9 +79,9 @@ static KeyValueMap retrieveKeyValuePairs(WebCore::SharedBufferChunkReader* buffe
return keyValuePairs;
}
-PassRefPtr<MIMEHeader> MIMEHeader::parseHeader(SharedBufferChunkReader* buffer)
+RefPtr<MIMEHeader> MIMEHeader::parseHeader(SharedBufferChunkReader& buffer)
{
- RefPtr<MIMEHeader> mimeHeader = adoptRef(new MIMEHeader);
+ auto mimeHeader = adoptRef(*new MIMEHeader);
KeyValueMap keyValuePairs = retrieveKeyValuePairs(buffer);
KeyValueMap::iterator mimeParametersIterator = keyValuePairs.find("content-type");
if (mimeParametersIterator != keyValuePairs.end()) {
@@ -94,11 +94,10 @@ PassRefPtr<MIMEHeader> MIMEHeader::parseHeader(SharedBufferChunkReader* buffer)
mimeHeader->m_endOfPartBoundary = parsedContentType.parameterValueForName("boundary");
if (mimeHeader->m_endOfPartBoundary.isNull()) {
LOG_ERROR("No boundary found in multipart MIME header.");
- return 0;
+ return nullptr;
}
- mimeHeader->m_endOfPartBoundary.insert("--", 0);
- mimeHeader->m_endOfDocumentBoundary = mimeHeader->m_endOfPartBoundary;
- mimeHeader->m_endOfDocumentBoundary.append("--");
+ mimeHeader->m_endOfPartBoundary = "--" + mimeHeader->m_endOfPartBoundary;
+ mimeHeader->m_endOfDocumentBoundary = mimeHeader->m_endOfPartBoundary + "--";
}
}
@@ -110,19 +109,19 @@ PassRefPtr<MIMEHeader> MIMEHeader::parseHeader(SharedBufferChunkReader* buffer)
if (mimeParametersIterator != keyValuePairs.end())
mimeHeader->m_contentLocation = mimeParametersIterator->value;
- return mimeHeader.release();
+ return WTFMove(mimeHeader);
}
MIMEHeader::Encoding MIMEHeader::parseContentTransferEncoding(const String& text)
{
- String encoding = text.stripWhiteSpace().lower();
- if (encoding == "base64")
+ String encoding = text.stripWhiteSpace();
+ if (equalLettersIgnoringASCIICase(encoding, "base64"))
return Base64;
- if (encoding == "quoted-printable")
+ if (equalLettersIgnoringASCIICase(encoding, "quoted-printable"))
return QuotedPrintable;
- if (encoding == "7bit")
+ if (equalLettersIgnoringASCIICase(encoding, "7bit"))
return SevenBit;
- if (encoding == "binary")
+ if (equalLettersIgnoringASCIICase(encoding, "binary"))
return Binary;
LOG_ERROR("Unknown encoding '%s' found in MIME header.", text.ascii().data());
return Unknown;
diff --git a/Source/WebCore/platform/network/MIMEHeader.h b/Source/WebCore/platform/network/MIMEHeader.h
index d22d55122..4df3e28fb 100644
--- a/Source/WebCore/platform/network/MIMEHeader.h
+++ b/Source/WebCore/platform/network/MIMEHeader.h
@@ -31,7 +31,6 @@
#ifndef MIMEHeader_h
#define MIMEHeader_h
-#include <wtf/HashMap.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
#include <wtf/text/WTFString.h>
@@ -51,7 +50,7 @@ public:
Unknown
};
- static PassRefPtr<MIMEHeader> parseHeader(SharedBufferChunkReader* crLFLineReader);
+ static RefPtr<MIMEHeader> parseHeader(SharedBufferChunkReader& crLFLineReader);
bool isMultipart() const { return m_contentType.startsWith("multipart/"); }
diff --git a/Source/WebCore/platform/network/NetworkLoadTiming.h b/Source/WebCore/platform/network/NetworkLoadTiming.h
new file mode 100644
index 000000000..4432124bc
--- /dev/null
+++ b/Source/WebCore/platform/network/NetworkLoadTiming.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2014 Apple, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if PLATFORM(COCOA)
+OBJC_CLASS NSDictionary;
+#endif
+
+namespace WebCore {
+
+class NetworkLoadTiming {
+public:
+ NetworkLoadTiming()
+ : domainLookupStart(-1)
+ , domainLookupEnd(-1)
+ , connectStart(-1)
+ , connectEnd(-1)
+ , requestStart(0)
+ , responseStart(0)
+ , secureConnectionStart(-1)
+ {
+ }
+
+ NetworkLoadTiming(const NetworkLoadTiming& other)
+ : domainLookupStart(other.domainLookupStart)
+ , domainLookupEnd(other.domainLookupEnd)
+ , connectStart(other.connectStart)
+ , connectEnd(other.connectEnd)
+ , requestStart(other.requestStart)
+ , responseStart(other.responseStart)
+ , secureConnectionStart(other.secureConnectionStart)
+ {
+ }
+
+ NetworkLoadTiming& operator=(const NetworkLoadTiming& other)
+ {
+ domainLookupStart = other.domainLookupStart;
+ domainLookupEnd = other.domainLookupEnd;
+ connectStart = other.connectStart;
+ connectEnd = other.connectEnd;
+ requestStart = other.requestStart;
+ responseStart = other.responseStart;
+ secureConnectionStart = other.secureConnectionStart;
+ return *this;
+ }
+
+ NetworkLoadTiming isolatedCopy() const
+ {
+ // There are currently no members that need isolated copies, so we can use the copy constructor.
+ return *this;
+ }
+
+ bool operator==(const NetworkLoadTiming& other) const
+ {
+ return domainLookupStart == other.domainLookupStart
+ && domainLookupEnd == other.domainLookupEnd
+ && connectStart == other.connectStart
+ && connectEnd == other.connectEnd
+ && requestStart == other.requestStart
+ && responseStart == other.responseStart
+ && secureConnectionStart == other.secureConnectionStart;
+ }
+
+ bool operator!=(const NetworkLoadTiming& other) const
+ {
+ return !(*this == other);
+ }
+
+ template<class Encoder> void encode(Encoder&) const;
+ template<class Decoder> static bool decode(Decoder&, NetworkLoadTiming&);
+
+ // These are millisecond deltas from the start time.
+ double domainLookupStart;
+ double domainLookupEnd;
+ double connectStart;
+ double connectEnd;
+ double requestStart;
+ double responseStart;
+ double secureConnectionStart;
+};
+
+#if PLATFORM(COCOA)
+WEBCORE_EXPORT void copyTimingData(NSDictionary *timingData, NetworkLoadTiming&);
+#endif
+
+#if PLATFORM(COCOA) && !HAVE(TIMINGDATAOPTIONS)
+WEBCORE_EXPORT void setCollectsTimingData();
+#endif
+
+template<class Encoder>
+void NetworkLoadTiming::encode(Encoder& encoder) const
+{
+ encoder << domainLookupStart;
+ encoder << domainLookupEnd;
+ encoder << connectStart;
+ encoder << connectEnd;
+ encoder << requestStart;
+ encoder << responseStart;
+ encoder << secureConnectionStart;
+}
+
+template<class Decoder>
+bool NetworkLoadTiming::decode(Decoder& decoder, NetworkLoadTiming& timing)
+{
+ return decoder.decode(timing.domainLookupStart)
+ && decoder.decode(timing.domainLookupEnd)
+ && decoder.decode(timing.connectStart)
+ && decoder.decode(timing.connectEnd)
+ && decoder.decode(timing.requestStart)
+ && decoder.decode(timing.responseStart)
+ && decoder.decode(timing.secureConnectionStart);
+}
+
+}
diff --git a/Source/WebCore/platform/network/NetworkStateNotifier.cpp b/Source/WebCore/platform/network/NetworkStateNotifier.cpp
index 31fab8f07..5574a3583 100644
--- a/Source/WebCore/platform/network/NetworkStateNotifier.cpp
+++ b/Source/WebCore/platform/network/NetworkStateNotifier.cpp
@@ -26,32 +26,41 @@
#include "config.h"
#include "NetworkStateNotifier.h"
+#if PLATFORM(IOS)
+#include "Settings.h"
+#endif
+
#include <mutex>
#include <wtf/Assertions.h>
-#include <wtf/StdLibExtras.h>
+#include <wtf/NeverDestroyed.h>
namespace WebCore {
NetworkStateNotifier& networkStateNotifier()
{
static std::once_flag onceFlag;
- static NetworkStateNotifier* networkStateNotifier;
+ static LazyNeverDestroyed<NetworkStateNotifier> networkStateNotifier;
std::call_once(onceFlag, []{
- networkStateNotifier = std::make_unique<NetworkStateNotifier>().release();
+ networkStateNotifier.construct();
});
- return *networkStateNotifier;
+ return networkStateNotifier;
}
void NetworkStateNotifier::addNetworkStateChangeListener(std::function<void (bool)> listener)
{
ASSERT(listener);
+#if PLATFORM(IOS)
+ if (Settings::shouldOptOutOfNetworkStateObservation())
+ return;
+ registerObserverIfNecessary();
+#endif
- m_listeners.append(std::move(listener));
+ m_listeners.append(WTFMove(listener));
}
-void NetworkStateNotifier::notifyNetworkStateChange()
+void NetworkStateNotifier::notifyNetworkStateChange() const
{
for (const auto& listener : m_listeners)
listener(m_isOnLine);
diff --git a/Source/WebCore/platform/network/NetworkStateNotifier.h b/Source/WebCore/platform/network/NetworkStateNotifier.h
index 17639969b..5282ec066 100644
--- a/Source/WebCore/platform/network/NetworkStateNotifier.h
+++ b/Source/WebCore/platform/network/NetworkStateNotifier.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,7 +31,7 @@
#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>
-#if PLATFORM(MAC) && !PLATFORM(IOS)
+#if PLATFORM(MAC)
#include <wtf/RetainPtr.h>
#include "Timer.h"
@@ -43,10 +43,10 @@ typedef const struct __SCDynamicStore * SCDynamicStoreRef;
#include <windows.h>
-#elif PLATFORM(EFL)
+#elif PLATFORM(IOS)
-typedef struct _Ecore_Fd_Handler Ecore_Fd_Handler;
-typedef unsigned char Eina_Bool;
+#include <wtf/RetainPtr.h>
+OBJC_CLASS WebNetworkStateObserver;
#endif
@@ -56,51 +56,49 @@ class NetworkStateNotifier {
WTF_MAKE_NONCOPYABLE(NetworkStateNotifier); WTF_MAKE_FAST_ALLOCATED;
public:
NetworkStateNotifier();
-#if PLATFORM(EFL)
+#if PLATFORM(IOS)
~NetworkStateNotifier();
#endif
void addNetworkStateChangeListener(std::function<void (bool isOnLine)>);
- bool onLine() const { return m_isOnLine; }
-
-#if PLATFORM(IOS)
- void setIsOnLine(bool);
-#endif
+ bool onLine() const;
private:
+#if !PLATFORM(IOS)
bool m_isOnLine;
+#endif
Vector<std::function<void (bool)>> m_listeners;
- void notifyNetworkStateChange();
+ void notifyNetworkStateChange() const;
void updateState();
-#if PLATFORM(MAC) && !PLATFORM(IOS)
- void networkStateChangeTimerFired(Timer<NetworkStateNotifier>&);
+#if PLATFORM(MAC)
+ void networkStateChangeTimerFired();
static void dynamicStoreCallback(SCDynamicStoreRef, CFArrayRef changedKeys, void *info);
RetainPtr<SCDynamicStoreRef> m_store;
- Timer<NetworkStateNotifier> m_networkStateChangeTimer;
+ Timer m_networkStateChangeTimer;
#elif PLATFORM(WIN)
static void CALLBACK addrChangeCallback(void*, BOOLEAN timedOut);
- static void callAddressChanged(void*);
void addressChanged();
void registerForAddressChange();
HANDLE m_waitHandle;
OVERLAPPED m_overlapped;
-#elif PLATFORM(EFL)
- void networkInterfaceChanged();
- static Eina_Bool readSocketCallback(void* userData, Ecore_Fd_Handler*);
+#elif PLATFORM(IOS)
+ void registerObserverIfNecessary() const;
+ friend void setOnLine(const NetworkStateNotifier*, bool);
- int m_netlinkSocket;
- Ecore_Fd_Handler* m_fdHandler;
+ mutable bool m_isOnLine;
+ mutable bool m_isOnLineInitialized;
+ mutable RetainPtr<WebNetworkStateObserver> m_observer;
#endif
};
-#if !PLATFORM(MAC) && !PLATFORM(WIN) && !PLATFORM(EFL)
+#if !PLATFORM(COCOA) && !PLATFORM(WIN)
inline NetworkStateNotifier::NetworkStateNotifier()
: m_isOnLine(true)
@@ -111,8 +109,15 @@ inline void NetworkStateNotifier::updateState() { }
#endif
-NetworkStateNotifier& networkStateNotifier();
+#if !PLATFORM(IOS)
+inline bool NetworkStateNotifier::onLine() const
+{
+ return m_isOnLine;
+}
+#endif
-};
+WEBCORE_EXPORT NetworkStateNotifier& networkStateNotifier();
+
+} // namespace WebCore
#endif // NetworkStateNotifier_h
diff --git a/Source/WebCore/platform/network/ResourceLoadTiming.cpp b/Source/WebCore/platform/network/NetworkStorageSession.cpp
index e33439581..985b4cdd0 100644
--- a/Source/WebCore/platform/network/ResourceLoadTiming.cpp
+++ b/Source/WebCore/platform/network/NetworkStorageSession.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,13 +24,36 @@
*/
#include "config.h"
-#include "ResourceLoadTiming.h"
+#include "NetworkStorageSession.h"
+
+#include "SessionID.h"
+#include <wtf/NeverDestroyed.h>
namespace WebCore {
-double ResourceLoadTiming::convertResourceLoadTimeToMonotonicTime(int deltaMilliseconds) const
+HashMap<SessionID, std::unique_ptr<NetworkStorageSession>>& NetworkStorageSession::globalSessionMap()
+{
+ static NeverDestroyed<HashMap<SessionID, std::unique_ptr<NetworkStorageSession>>> map;
+ return map;
+}
+
+NetworkStorageSession* NetworkStorageSession::storageSession(SessionID sessionID)
+{
+ if (sessionID == SessionID::defaultSessionID())
+ return &defaultStorageSession();
+ return globalSessionMap().get(sessionID);
+}
+
+void NetworkStorageSession::destroySession(SessionID sessionID)
+{
+ globalSessionMap().remove(sessionID);
+}
+
+void NetworkStorageSession::forEach(std::function<void(const WebCore::NetworkStorageSession&)> functor)
{
- return requestTime + deltaMilliseconds / 1000.0;
+ functor(defaultStorageSession());
+ for (auto& storageSession : globalSessionMap().values())
+ functor(*storageSession);
}
}
diff --git a/Source/WebCore/platform/network/NetworkStorageSession.h b/Source/WebCore/platform/network/NetworkStorageSession.h
index bb6fb7fd6..aedb08a7f 100644
--- a/Source/WebCore/platform/network/NetworkStorageSession.h
+++ b/Source/WebCore/platform/network/NetworkStorageSession.h
@@ -23,71 +23,92 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef NetworkStorageSession_h
-#define NetworkStorageSession_h
+#pragma once
-#include <wtf/RetainPtr.h>
+#include "CredentialStorage.h"
+#include "SessionID.h"
#include <wtf/text/WTFString.h>
-#if PLATFORM(MAC) || USE(CFNETWORK)
-typedef const struct __CFURLStorageSession* CFURLStorageSessionRef;
-typedef struct OpaqueCFHTTPCookieStorage* CFHTTPCookieStorageRef;
+#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
+#include "CFNetworkSPI.h"
+#include <wtf/RetainPtr.h>
+#endif
+
+#if USE(SOUP)
+#include <wtf/Function.h>
+#include <wtf/glib/GRefPtr.h>
+typedef struct _SoupCookieJar SoupCookieJar;
#endif
namespace WebCore {
class NetworkingContext;
+class ResourceRequest;
class SoupNetworkSession;
class NetworkStorageSession {
WTF_MAKE_NONCOPYABLE(NetworkStorageSession); WTF_MAKE_FAST_ALLOCATED;
public:
- static NetworkStorageSession& defaultStorageSession();
- static std::unique_ptr<NetworkStorageSession> createPrivateBrowsingSession(const String& identifierBase = String());
+ WEBCORE_EXPORT static NetworkStorageSession& defaultStorageSession();
+ WEBCORE_EXPORT static NetworkStorageSession* storageSession(SessionID);
+ WEBCORE_EXPORT static void ensurePrivateBrowsingSession(SessionID, const String& identifierBase = String());
+ WEBCORE_EXPORT static void destroySession(SessionID);
+ WEBCORE_EXPORT static void forEach(std::function<void(const WebCore::NetworkStorageSession&)>);
- static void switchToNewTestingSession();
+ WEBCORE_EXPORT static void switchToNewTestingSession();
-#if PLATFORM(MAC) || USE(CFNETWORK) || USE(SOUP)
- bool isPrivateBrowsingSession() const { return m_isPrivate; }
-#endif
+ SessionID sessionID() const { return m_sessionID; }
+ CredentialStorage& credentialStorage() { return m_credentialStorage; }
+
+#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
+ NetworkStorageSession(SessionID, RetainPtr<CFURLStorageSessionRef>);
-#if PLATFORM(MAC) || USE(CFNETWORK)
- NetworkStorageSession(RetainPtr<CFURLStorageSessionRef>);
// May be null, in which case a Foundation default should be used.
CFURLStorageSessionRef platformSession() { return m_platformSession.get(); }
- RetainPtr<CFHTTPCookieStorageRef> cookieStorage() const;
+ WEBCORE_EXPORT RetainPtr<CFHTTPCookieStorageRef> cookieStorage() const;
+ WEBCORE_EXPORT static void setCookieStoragePartitioningEnabled(bool);
#elif USE(SOUP)
- NetworkStorageSession(std::unique_ptr<SoupNetworkSession>);
+ NetworkStorageSession(SessionID, std::unique_ptr<SoupNetworkSession>&&);
~NetworkStorageSession();
- SoupNetworkSession& soupNetworkSession() const;
- void setSoupNetworkSession(std::unique_ptr<SoupNetworkSession>);
+
+ SoupNetworkSession* soupNetworkSession() const { return m_session.get(); };
+ SoupNetworkSession& getOrCreateSoupNetworkSession() const;
+ SoupCookieJar* cookieStorage() const;
+ void setCookieStorage(SoupCookieJar*);
+ void setCookieObserverHandler(Function<void ()>&&);
+ void getCredentialFromPersistentStorage(const ProtectionSpace&, Function<void (Credential&&)> completionHandler);
+ void saveCredentialToPersistentStorage(const ProtectionSpace&, const Credential&);
#else
- NetworkStorageSession(NetworkingContext*);
+ NetworkStorageSession(SessionID, NetworkingContext*);
~NetworkStorageSession();
+
NetworkingContext* context() const;
#endif
private:
-#if PLATFORM(MAC) || USE(CFNETWORK)
- NetworkStorageSession();
+ static HashMap<SessionID, std::unique_ptr<NetworkStorageSession>>& globalSessionMap();
+ SessionID m_sessionID;
+
+#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
RetainPtr<CFURLStorageSessionRef> m_platformSession;
#elif USE(SOUP)
- std::unique_ptr<SoupNetworkSession> m_session;
+ static void cookiesDidChange(NetworkStorageSession*);
+
+ mutable std::unique_ptr<SoupNetworkSession> m_session;
+ GRefPtr<SoupCookieJar> m_cookieStorage;
+ Function<void ()> m_cookieObserverHandler;
+#if USE(LIBSECRET)
+ Function<void (Credential&&)> m_persisentStorageCompletionHandler;
+ GRefPtr<GCancellable> m_persisentStorageCancellable;
+#endif
#else
RefPtr<NetworkingContext> m_context;
#endif
-#if PLATFORM(MAC) || USE(CFNETWORK) || USE(SOUP)
- bool m_isPrivate;
-#endif
+ CredentialStorage m_credentialStorage;
};
-#if PLATFORM(WIN) && USE(CFNETWORK)
-// Needed for WebKit1 API only.
-void overrideCookieStorage(CFHTTPCookieStorageRef);
-CFHTTPCookieStorageRef overridenCookieStorage();
-#endif
+WEBCORE_EXPORT String cookieStoragePartition(const ResourceRequest&);
+String cookieStoragePartition(const URL& firstPartyForCookies, const URL& resource);
}
-
-#endif // NetworkStorageSession_h
diff --git a/Source/WebCore/platform/network/NetworkStorageSessionStub.cpp b/Source/WebCore/platform/network/NetworkStorageSessionStub.cpp
new file mode 100644
index 000000000..fd98432e6
--- /dev/null
+++ b/Source/WebCore/platform/network/NetworkStorageSessionStub.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if !USE(SOUP)
+
+#include "NetworkStorageSession.h"
+
+#include "NetworkingContext.h"
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+NetworkStorageSession::NetworkStorageSession(SessionID sessionID, NetworkingContext* context)
+ : m_sessionID(sessionID)
+ , m_context(context)
+{
+}
+
+NetworkStorageSession::~NetworkStorageSession()
+{
+}
+
+NetworkingContext* NetworkStorageSession::context() const
+{
+ return m_context.get();
+}
+
+void NetworkStorageSession::ensurePrivateBrowsingSession(SessionID sessionID, const String&)
+{
+ ASSERT_NOT_REACHED();
+}
+
+static std::unique_ptr<NetworkStorageSession>& defaultSession()
+{
+ static NeverDestroyed<std::unique_ptr<NetworkStorageSession>> session;
+ return session;
+}
+
+NetworkStorageSession& NetworkStorageSession::defaultStorageSession()
+{
+ if (!defaultSession())
+ defaultSession() = std::make_unique<NetworkStorageSession>(SessionID::defaultSessionID(), nullptr);
+ return *defaultSession();
+}
+
+void NetworkStorageSession::switchToNewTestingSession()
+{
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/network/NetworkingContext.h b/Source/WebCore/platform/network/NetworkingContext.h
index 3080a7e9d..95e2d5e7c 100644
--- a/Source/WebCore/platform/network/NetworkingContext.h
+++ b/Source/WebCore/platform/network/NetworkingContext.h
@@ -17,18 +17,17 @@
Boston, MA 02110-1301, USA.
*/
-#ifndef NetworkingContext_h
-#define NetworkingContext_h
+#pragma once
-#include "NetworkStorageSession.h"
#include <wtf/RefCounted.h>
#include <wtf/RetainPtr.h>
+#include <wtf/text/WTFString.h>
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
#include <wtf/SchedulePair.h>
#endif
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
OBJC_CLASS NSOperationQueue;
#endif
@@ -38,6 +37,7 @@ typedef struct _SoupSession SoupSession;
namespace WebCore {
+class NetworkStorageSession;
class ResourceError;
class ResourceRequest;
@@ -49,21 +49,18 @@ public:
virtual bool shouldClearReferrerOnHTTPSToHTTPRedirect() const = 0;
-#if PLATFORM(MAC)
- virtual bool needsSiteSpecificQuirks() const = 0;
+#if PLATFORM(COCOA)
virtual bool localFileContentSniffingEnabled() const = 0; // FIXME: Reconcile with ResourceHandle::forceContentSniffing().
virtual SchedulePairHashSet* scheduledRunLoopPairs() const { return 0; }
virtual RetainPtr<CFDataRef> sourceApplicationAuditData() const = 0;
virtual ResourceError blockedError(const ResourceRequest&) const = 0;
#endif
-#if PLATFORM(MAC) || USE(CFNETWORK) || USE(SOUP)
+ virtual String sourceApplicationIdentifier() const { return emptyString(); }
+
virtual NetworkStorageSession& storageSession() const = 0;
-#endif
#if PLATFORM(WIN)
- virtual String userAgent() const = 0;
- virtual String referrer() const = 0;
virtual ResourceError blockedError(const ResourceRequest&) const = 0;
#endif
@@ -72,5 +69,3 @@ protected:
};
}
-
-#endif // NetworkingContext_h
diff --git a/Source/WebCore/platform/network/ParsedContentRange.cpp b/Source/WebCore/platform/network/ParsedContentRange.cpp
new file mode 100644
index 000000000..00b90c485
--- /dev/null
+++ b/Source/WebCore/platform/network/ParsedContentRange.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ParsedContentRange.h"
+
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+static bool areContentRangeValuesValid(int64_t firstBytePosition, int64_t lastBytePosition, int64_t instanceLength)
+{
+ // From <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html>
+ // 14.16 Content-Range
+ // A byte-content-range-spec with a byte-range-resp-spec whose last- byte-pos value is less than its first-byte-pos value,
+ // or whose instance-length value is less than or equal to its last-byte-pos value, is invalid.
+ if (firstBytePosition < 0)
+ return false;
+
+ if (lastBytePosition < firstBytePosition)
+ return false;
+
+ if (instanceLength == ParsedContentRange::UnknownLength)
+ return true;
+
+ return lastBytePosition < instanceLength;
+}
+
+static bool parseContentRange(const String& headerValue, int64_t& firstBytePosition, int64_t& lastBytePosition, int64_t& instanceLength)
+{
+ // From <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html>
+ // 14.16 Content-Range
+ //
+ // Content-Range = "Content-Range" ":" content-range-spec
+ // content-range-spec = byte-content-range-spec
+ // byte-content-range-spec = bytes-unit SP
+ // byte-range-resp-spec "/"
+ // ( instance-length | "*" )
+ // byte-range-resp-spec = (first-byte-pos "-" last-byte-pos)
+ // | "*"
+ // instance-length = 1*DIGIT
+
+ static const char* prefix = "bytes ";
+ static const size_t prefixLength = 6;
+
+ if (!headerValue.startsWith(prefix))
+ return false;
+
+ size_t byteSeparatorTokenLoc = headerValue.find('-', prefixLength);
+ if (byteSeparatorTokenLoc == notFound)
+ return false;
+
+ size_t instanceLengthSeparatorToken = headerValue.find('/', byteSeparatorTokenLoc + 1);
+ if (instanceLengthSeparatorToken == notFound)
+ return false;
+
+ bool isOk = true;
+ String firstByteString = headerValue.substring(prefixLength, byteSeparatorTokenLoc - prefixLength);
+ if (!firstByteString.isAllSpecialCharacters<isASCIIDigit>())
+ return false;
+
+ firstBytePosition = firstByteString.toInt64Strict(&isOk);
+ if (!isOk)
+ return false;
+
+ String lastByteString = headerValue.substring(byteSeparatorTokenLoc + 1, instanceLengthSeparatorToken - (byteSeparatorTokenLoc + 1));
+ if (!lastByteString.isAllSpecialCharacters<isASCIIDigit>())
+ return false;
+
+ lastBytePosition = lastByteString.toInt64Strict(&isOk);
+ if (!isOk)
+ return false;
+
+ String instanceString = headerValue.substring(instanceLengthSeparatorToken + 1);
+ if (instanceString == "*")
+ instanceLength = ParsedContentRange::UnknownLength;
+ else {
+ if (!instanceString.isAllSpecialCharacters<isASCIIDigit>())
+ return false;
+
+ instanceLength = instanceString.toInt64Strict(&isOk);
+ if (!isOk)
+ return false;
+ }
+
+ return areContentRangeValuesValid(firstBytePosition, lastBytePosition, instanceLength);
+}
+
+ParsedContentRange::ParsedContentRange(const String& headerValue)
+{
+ m_isValid = parseContentRange(headerValue, m_firstBytePosition, m_lastBytePosition, m_instanceLength);
+}
+
+ParsedContentRange::ParsedContentRange(int64_t firstBytePosition, int64_t lastBytePosition, int64_t instanceLength)
+ : m_firstBytePosition(firstBytePosition)
+ , m_lastBytePosition(lastBytePosition)
+ , m_instanceLength(instanceLength)
+{
+ m_isValid = areContentRangeValuesValid(m_firstBytePosition, m_lastBytePosition, m_instanceLength);
+}
+
+String ParsedContentRange::headerValue() const
+{
+ if (!m_isValid)
+ return String();
+ if (m_instanceLength == UnknownLength)
+ return String::format("bytes %" PRId64 "-%" PRId64 "/*", m_firstBytePosition, m_lastBytePosition);
+ return String::format("bytes %" PRId64 "-%" PRId64 "/%" PRId64, m_firstBytePosition, m_lastBytePosition, m_instanceLength);
+}
+
+}
diff --git a/Source/WebCore/platform/network/soup/CookieJarSoup.h b/Source/WebCore/platform/network/ParsedContentRange.h
index b949ef8fa..281b803aa 100644
--- a/Source/WebCore/platform/network/soup/CookieJarSoup.h
+++ b/Source/WebCore/platform/network/ParsedContentRange.h
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2008 Xan Lopez <xan@gnome.org>
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -21,20 +20,39 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CookieJarSoup_h
-#define CookieJarSoup_h
+#ifndef ParsedContentRange_h
+#define ParsedContentRange_h
-#include <libsoup/soup.h>
+#include <wtf/Forward.h>
namespace WebCore {
-SoupCookieJar* soupCookieJar();
-void setSoupCookieJar(SoupCookieJar*);
+class ParsedContentRange {
+public:
+ WEBCORE_EXPORT explicit ParsedContentRange(const String&);
+ ParsedContentRange() { }
+ WEBCORE_EXPORT ParsedContentRange(int64_t firstBytePosition, int64_t lastBytePosition, int64_t instanceLength);
-SoupCookieJar* createPrivateBrowsingCookieJar();
+ bool isValid() const { return m_isValid; }
+ int64_t firstBytePosition() const { return m_firstBytePosition; }
+ int64_t lastBytePosition() const { return m_lastBytePosition; }
+ int64_t instanceLength() const { return m_instanceLength; }
+
+ WEBCORE_EXPORT String headerValue() const;
+
+ enum { UnknownLength = std::numeric_limits<int64_t>::max() };
+
+private:
+ template<typename T> static bool isPositive(T);
+
+ bool m_isValid { false };
+ int64_t m_firstBytePosition { 0 };
+ int64_t m_lastBytePosition { 0 };
+ int64_t m_instanceLength { UnknownLength };
+};
}
diff --git a/Source/WebCore/platform/network/PingHandle.h b/Source/WebCore/platform/network/PingHandle.h
new file mode 100644
index 000000000..cd9f2bf96
--- /dev/null
+++ b/Source/WebCore/platform/network/PingHandle.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ResourceHandle.h"
+#include "ResourceHandleClient.h"
+#include "Timer.h"
+
+namespace WebCore {
+
+// This class triggers asynchronous loads independent of the networking context staying alive (i.e., auditing pingbacks).
+// The object just needs to live long enough to ensure the message was actually sent.
+// As soon as any callback is received from the ResourceHandle, this class will cancel the load and delete itself.
+
+class PingHandle final : private ResourceHandleClient {
+ WTF_MAKE_NONCOPYABLE(PingHandle); WTF_MAKE_FAST_ALLOCATED;
+public:
+ enum class UsesAsyncCallbacks {
+ Yes,
+ No,
+ };
+
+ PingHandle(NetworkingContext* networkingContext, const ResourceRequest& request, bool shouldUseCredentialStorage, UsesAsyncCallbacks useAsyncCallbacks, bool shouldFollowRedirects)
+ : m_timeoutTimer(*this, &PingHandle::timeoutTimerFired)
+ , m_shouldUseCredentialStorage(shouldUseCredentialStorage)
+ , m_shouldFollowRedirects(shouldFollowRedirects)
+ , m_usesAsyncCallbacks(useAsyncCallbacks)
+ {
+ m_handle = ResourceHandle::create(networkingContext, request, this, false, false);
+
+ // If the server never responds, this object will hang around forever.
+ // Set a very generous timeout, just in case.
+ m_timeoutTimer.startOneShot(60000);
+ }
+
+private:
+ ResourceRequest willSendRequest(ResourceHandle*, ResourceRequest&& request, ResourceResponse&&) final
+ {
+ return m_shouldFollowRedirects ? request : ResourceRequest();
+ }
+ void willSendRequestAsync(ResourceHandle* handle, ResourceRequest&& request, ResourceResponse&&) final
+ {
+ if (m_shouldFollowRedirects) {
+ handle->continueWillSendRequest(WTFMove(request));
+ return;
+ }
+ delete this;
+ }
+ void didReceiveResponse(ResourceHandle*, ResourceResponse&&) final { delete this; }
+ void didReceiveBuffer(ResourceHandle*, Ref<SharedBuffer>&&, int) final { delete this; };
+ void didFinishLoading(ResourceHandle*, double) final { delete this; }
+ void didFail(ResourceHandle*, const ResourceError&) final { delete this; }
+ bool shouldUseCredentialStorage(ResourceHandle*) final { return m_shouldUseCredentialStorage; }
+ bool usesAsyncCallbacks() final { return m_usesAsyncCallbacks == UsesAsyncCallbacks::Yes; }
+ void timeoutTimerFired() { delete this; }
+
+ virtual ~PingHandle()
+ {
+ if (m_handle) {
+ ASSERT(m_handle->client() == this);
+ m_handle->clearClient();
+ m_handle->cancel();
+ }
+ }
+
+ RefPtr<ResourceHandle> m_handle;
+ Timer m_timeoutTimer;
+ bool m_shouldUseCredentialStorage;
+ bool m_shouldFollowRedirects;
+ UsesAsyncCallbacks m_usesAsyncCallbacks;
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/network/PlatformCookieJar.h b/Source/WebCore/platform/network/PlatformCookieJar.h
index 5e122c194..d7270c7ca 100644
--- a/Source/WebCore/platform/network/PlatformCookieJar.h
+++ b/Source/WebCore/platform/network/PlatformCookieJar.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006, 2008, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2006, 2008, 2012, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -26,6 +26,7 @@
#ifndef PlatformCookieJar_h
#define PlatformCookieJar_h
+#include <chrono>
#include <wtf/Forward.h>
#include <wtf/HashSet.h>
#include <wtf/Vector.h>
@@ -39,15 +40,17 @@ struct Cookie;
// FIXME: These should probably be NetworkStorageSession member functions.
-String cookiesForDOM(const NetworkStorageSession&, const URL& firstParty, const URL&);
-void setCookiesFromDOM(const NetworkStorageSession&, const URL& firstParty, const URL&, const String&);
-bool cookiesEnabled(const NetworkStorageSession&, const URL& firstParty, const URL&);
-String cookieRequestHeaderFieldValue(const NetworkStorageSession&, const URL& firstParty, const URL&);
-bool getRawCookies(const NetworkStorageSession&, const URL& firstParty, const URL&, Vector<Cookie>&);
-void deleteCookie(const NetworkStorageSession&, const URL&, const String&);
-void getHostnamesWithCookies(const NetworkStorageSession&, HashSet<String>& hostnames);
-void deleteCookiesForHostname(const NetworkStorageSession&, const String& hostname);
-void deleteAllCookies(const NetworkStorageSession&);
+WEBCORE_EXPORT String cookiesForDOM(const NetworkStorageSession&, const URL& firstParty, const URL&);
+WEBCORE_EXPORT void setCookiesFromDOM(const NetworkStorageSession&, const URL& firstParty, const URL&, const String&);
+WEBCORE_EXPORT bool cookiesEnabled(const NetworkStorageSession&, const URL& firstParty, const URL&);
+WEBCORE_EXPORT String cookieRequestHeaderFieldValue(const NetworkStorageSession&, const URL& firstParty, const URL&);
+WEBCORE_EXPORT bool getRawCookies(const NetworkStorageSession&, const URL& firstParty, const URL&, Vector<Cookie>&);
+WEBCORE_EXPORT void deleteCookie(const NetworkStorageSession&, const URL&, const String&);
+WEBCORE_EXPORT void addCookie(const NetworkStorageSession&, const URL&, const Cookie&);
+WEBCORE_EXPORT void getHostnamesWithCookies(const NetworkStorageSession&, HashSet<String>& hostnames);
+WEBCORE_EXPORT void deleteCookiesForHostnames(const NetworkStorageSession&, const Vector<String>& cookieHostNames);
+WEBCORE_EXPORT void deleteAllCookies(const NetworkStorageSession&);
+WEBCORE_EXPORT void deleteAllCookiesModifiedSince(const NetworkStorageSession&, std::chrono::system_clock::time_point);
}
diff --git a/Source/WebCore/platform/network/ProtectionSpace.h b/Source/WebCore/platform/network/ProtectionSpace.h
index 11369cdfa..769de805f 100644
--- a/Source/WebCore/platform/network/ProtectionSpace.h
+++ b/Source/WebCore/platform/network/ProtectionSpace.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,67 +23,29 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ProtectionSpace_h
-#define ProtectionSpace_h
+#pragma once
-#include <wtf/text/WTFString.h>
+#if PLATFORM(COCOA)
+#include "ProtectionSpaceCocoa.h"
+#elif USE(CFURLCONNECTION)
+#include "ProtectionSpaceCFNet.h"
+#else
-namespace WebCore {
-
-enum ProtectionSpaceServerType {
- ProtectionSpaceServerHTTP = 1,
- ProtectionSpaceServerHTTPS = 2,
- ProtectionSpaceServerFTP = 3,
- ProtectionSpaceServerFTPS = 4,
- ProtectionSpaceProxyHTTP = 5,
- ProtectionSpaceProxyHTTPS = 6,
- ProtectionSpaceProxyFTP = 7,
- ProtectionSpaceProxySOCKS = 8
-};
+#include "ProtectionSpaceBase.h"
-enum ProtectionSpaceAuthenticationScheme {
- ProtectionSpaceAuthenticationSchemeDefault = 1,
- ProtectionSpaceAuthenticationSchemeHTTPBasic = 2,
- ProtectionSpaceAuthenticationSchemeHTTPDigest = 3,
- ProtectionSpaceAuthenticationSchemeHTMLForm = 4,
- ProtectionSpaceAuthenticationSchemeNTLM = 5,
- ProtectionSpaceAuthenticationSchemeNegotiate = 6,
- ProtectionSpaceAuthenticationSchemeClientCertificateRequested = 7,
- ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested = 8,
- ProtectionSpaceAuthenticationSchemeUnknown = 100
-};
-
-class ProtectionSpace {
+namespace WebCore {
+class ProtectionSpace : public ProtectionSpaceBase {
public:
- ProtectionSpace();
- ProtectionSpace(const String& host, int port, ProtectionSpaceServerType, const String& realm, ProtectionSpaceAuthenticationScheme);
-
- // Hash table deleted values, which are only constructed and never copied or destroyed.
- ProtectionSpace(WTF::HashTableDeletedValueType) : m_isHashTableDeletedValue(true) { }
- bool isHashTableDeletedValue() const { return m_isHashTableDeletedValue; }
-
- const String& host() const;
- int port() const;
- ProtectionSpaceServerType serverType() const;
- bool isProxy() const;
- const String& realm() const;
- ProtectionSpaceAuthenticationScheme authenticationScheme() const;
-
- bool receivesCredentialSecurely() const;
+ ProtectionSpace() : ProtectionSpaceBase() { }
+ ProtectionSpace(const String& host, int port, ProtectionSpaceServerType serverType, const String& realm, ProtectionSpaceAuthenticationScheme authenticationScheme)
+ : ProtectionSpaceBase(host, port, serverType, realm, authenticationScheme)
+ {
+ }
-private:
- String m_host;
- int m_port;
- ProtectionSpaceServerType m_serverType;
- String m_realm;
- ProtectionSpaceAuthenticationScheme m_authenticationScheme;
- bool m_isHashTableDeletedValue;
+ ProtectionSpace(WTF::HashTableDeletedValueType deletedValue) : ProtectionSpaceBase(deletedValue) { }
};
-bool operator==(const ProtectionSpace& a, const ProtectionSpace& b);
-inline bool operator!=(const ProtectionSpace& a, const ProtectionSpace& b) { return !(a == b); }
-
} // namespace WebCore
-#endif // ProtectionSpace_h
+#endif
diff --git a/Source/WebCore/platform/network/ProtectionSpace.cpp b/Source/WebCore/platform/network/ProtectionSpaceBase.cpp
index e926ad1e1..dfc74e522 100644
--- a/Source/WebCore/platform/network/ProtectionSpace.cpp
+++ b/Source/WebCore/platform/network/ProtectionSpaceBase.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,23 +23,24 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
+#include "ProtectionSpaceBase.h"
+
#include "ProtectionSpace.h"
-#if USE(CFNETWORK) && !PLATFORM(MAC)
+#if USE(CFURLCONNECTION) && !PLATFORM(COCOA)
#include "AuthenticationCF.h"
#include <CFNetwork/CFURLProtectionSpacePriv.h>
-#include <wtf/RetainPtr.h>
#endif
namespace WebCore {
// Need to enforce empty, non-null strings due to the pickiness of the String == String operator
// combined with the semantics of the String(NSString*) constructor
-ProtectionSpace::ProtectionSpace()
- : m_host("")
+ProtectionSpaceBase::ProtectionSpaceBase()
+ : m_host(emptyString())
, m_port(0)
, m_serverType(ProtectionSpaceServerHTTP)
- , m_realm("")
+ , m_realm(emptyString())
, m_authenticationScheme(ProtectionSpaceAuthenticationSchemeDefault)
, m_isHashTableDeletedValue(false)
{
@@ -47,32 +48,32 @@ ProtectionSpace::ProtectionSpace()
// Need to enforce empty, non-null strings due to the pickiness of the String == String operator
// combined with the semantics of the String(NSString*) constructor
-ProtectionSpace::ProtectionSpace(const String& host, int port, ProtectionSpaceServerType serverType, const String& realm, ProtectionSpaceAuthenticationScheme authenticationScheme)
- : m_host(host.length() ? host : "")
+ProtectionSpaceBase::ProtectionSpaceBase(const String& host, int port, ProtectionSpaceServerType serverType, const String& realm, ProtectionSpaceAuthenticationScheme authenticationScheme)
+ : m_host(host.length() ? host : emptyString())
, m_port(port)
, m_serverType(serverType)
- , m_realm(realm.length() ? realm : "")
+ , m_realm(realm.length() ? realm : emptyString())
, m_authenticationScheme(authenticationScheme)
, m_isHashTableDeletedValue(false)
{
}
-const String& ProtectionSpace::host() const
-{
+const String& ProtectionSpaceBase::host() const
+{
return m_host;
}
-int ProtectionSpace::port() const
+int ProtectionSpaceBase::port() const
{
return m_port;
}
-ProtectionSpaceServerType ProtectionSpace::serverType() const
+ProtectionSpaceServerType ProtectionSpaceBase::serverType() const
{
- return m_serverType;
+ return m_serverType;
}
-bool ProtectionSpace::isProxy() const
+bool ProtectionSpaceBase::isProxy() const
{
return (m_serverType == ProtectionSpaceProxyHTTP ||
m_serverType == ProtectionSpaceProxyHTTPS ||
@@ -80,30 +81,45 @@ bool ProtectionSpace::isProxy() const
m_serverType == ProtectionSpaceProxySOCKS);
}
-const String& ProtectionSpace::realm() const
+const String& ProtectionSpaceBase::realm() const
{
return m_realm;
}
-ProtectionSpaceAuthenticationScheme ProtectionSpace::authenticationScheme() const
+ProtectionSpaceAuthenticationScheme ProtectionSpaceBase::authenticationScheme() const
{
return m_authenticationScheme;
}
-bool ProtectionSpace::receivesCredentialSecurely() const
+bool ProtectionSpaceBase::receivesCredentialSecurely() const
{
-#if USE(CFNETWORK) && !PLATFORM(MAC)
- RetainPtr<CFURLProtectionSpaceRef> cfSpace = adoptCF(createCF(*this));
- return cfSpace && CFURLProtectionSpaceReceivesCredentialSecurely(cfSpace.get());
-#else
- return (m_serverType == ProtectionSpaceServerHTTPS ||
+ return (m_serverType == ProtectionSpaceServerHTTPS ||
m_serverType == ProtectionSpaceServerFTPS ||
m_serverType == ProtectionSpaceProxyHTTPS ||
m_authenticationScheme == ProtectionSpaceAuthenticationSchemeHTTPDigest);
-#endif
}
-bool operator==(const ProtectionSpace& a, const ProtectionSpace& b)
+bool ProtectionSpaceBase::isPasswordBased() const
+{
+ switch (m_authenticationScheme) {
+ case ProtectionSpaceAuthenticationSchemeDefault:
+ case ProtectionSpaceAuthenticationSchemeHTTPBasic:
+ case ProtectionSpaceAuthenticationSchemeHTTPDigest:
+ case ProtectionSpaceAuthenticationSchemeHTMLForm:
+ case ProtectionSpaceAuthenticationSchemeNTLM:
+ case ProtectionSpaceAuthenticationSchemeNegotiate:
+ return true;
+ case ProtectionSpaceAuthenticationSchemeClientCertificateRequested:
+ case ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:
+ case ProtectionSpaceAuthenticationSchemeUnknown:
+ return false;
+ }
+
+ return true;
+}
+
+
+bool ProtectionSpaceBase::compare(const ProtectionSpace& a, const ProtectionSpace& b)
{
if (a.host() != b.host())
return false;
@@ -116,10 +132,8 @@ bool operator==(const ProtectionSpace& a, const ProtectionSpace& b)
return false;
if (a.authenticationScheme() != b.authenticationScheme())
return false;
-
- return true;
-}
+ return ProtectionSpace::platformCompare(a, b);
}
-
+}
diff --git a/Source/WebCore/platform/network/ProtectionSpaceBase.h b/Source/WebCore/platform/network/ProtectionSpaceBase.h
new file mode 100644
index 000000000..78e5200c2
--- /dev/null
+++ b/Source/WebCore/platform/network/ProtectionSpaceBase.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ProtectionSpaceBase_h
+#define ProtectionSpaceBase_h
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class ProtectionSpace;
+
+enum ProtectionSpaceServerType {
+ ProtectionSpaceServerHTTP = 1,
+ ProtectionSpaceServerHTTPS = 2,
+ ProtectionSpaceServerFTP = 3,
+ ProtectionSpaceServerFTPS = 4,
+ ProtectionSpaceProxyHTTP = 5,
+ ProtectionSpaceProxyHTTPS = 6,
+ ProtectionSpaceProxyFTP = 7,
+ ProtectionSpaceProxySOCKS = 8
+};
+
+enum ProtectionSpaceAuthenticationScheme {
+ ProtectionSpaceAuthenticationSchemeDefault = 1,
+ ProtectionSpaceAuthenticationSchemeHTTPBasic = 2,
+ ProtectionSpaceAuthenticationSchemeHTTPDigest = 3,
+ ProtectionSpaceAuthenticationSchemeHTMLForm = 4,
+ ProtectionSpaceAuthenticationSchemeNTLM = 5,
+ ProtectionSpaceAuthenticationSchemeNegotiate = 6,
+ ProtectionSpaceAuthenticationSchemeClientCertificateRequested = 7,
+ ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested = 8,
+ ProtectionSpaceAuthenticationSchemeUnknown = 100
+};
+
+class ProtectionSpaceBase {
+
+public:
+ bool isHashTableDeletedValue() const { return m_isHashTableDeletedValue; }
+
+ WEBCORE_EXPORT const String& host() const;
+ WEBCORE_EXPORT int port() const;
+ WEBCORE_EXPORT ProtectionSpaceServerType serverType() const;
+ WEBCORE_EXPORT bool isProxy() const;
+ WEBCORE_EXPORT const String& realm() const;
+ WEBCORE_EXPORT ProtectionSpaceAuthenticationScheme authenticationScheme() const;
+
+ bool receivesCredentialSecurely() const;
+ WEBCORE_EXPORT bool isPasswordBased() const;
+
+ bool encodingRequiresPlatformData() const { return false; }
+
+ WEBCORE_EXPORT static bool compare(const ProtectionSpace&, const ProtectionSpace&);
+
+protected:
+ WEBCORE_EXPORT ProtectionSpaceBase();
+ WEBCORE_EXPORT ProtectionSpaceBase(const String& host, int port, ProtectionSpaceServerType, const String& realm, ProtectionSpaceAuthenticationScheme);
+
+ // Hash table deleted values, which are only constructed and never copied or destroyed.
+ ProtectionSpaceBase(WTF::HashTableDeletedValueType) : m_isHashTableDeletedValue(true) { }
+
+ static bool platformCompare(const ProtectionSpace&, const ProtectionSpace&) { return true; }
+
+private:
+ String m_host;
+ int m_port;
+ ProtectionSpaceServerType m_serverType;
+ String m_realm;
+ ProtectionSpaceAuthenticationScheme m_authenticationScheme;
+ bool m_isHashTableDeletedValue;
+};
+
+inline bool operator==(const ProtectionSpace& a, const ProtectionSpace& b) { return ProtectionSpaceBase::compare(a, b); }
+inline bool operator!=(const ProtectionSpace& a, const ProtectionSpace& b) { return !(a == b); }
+
+} // namespace WebCore
+
+#endif // ProtectionSpaceBase_h
diff --git a/Source/WebCore/platform/network/ProtectionSpaceHash.h b/Source/WebCore/platform/network/ProtectionSpaceHash.h
index 2d56b313b..4526cd4f8 100644
--- a/Source/WebCore/platform/network/ProtectionSpaceHash.h
+++ b/Source/WebCore/platform/network/ProtectionSpaceHash.h
@@ -37,8 +37,8 @@ struct ProtectionSpaceHash {
unsigned hashCodes[5] = {
protectionSpace.host().impl() ? protectionSpace.host().impl()->hash() : 0,
static_cast<unsigned>(protectionSpace.port()),
- protectionSpace.serverType(),
- protectionSpace.authenticationScheme(),
+ static_cast<unsigned>(protectionSpace.serverType()),
+ static_cast<unsigned>(protectionSpace.authenticationScheme()),
protectionSpace.realm().impl() ? protectionSpace.realm().impl()->hash() : 0
};
diff --git a/Source/WebCore/platform/network/ProxyServer.cpp b/Source/WebCore/platform/network/ProxyServer.cpp
index 07c90cbf2..c6d67c21d 100644
--- a/Source/WebCore/platform/network/ProxyServer.cpp
+++ b/Source/WebCore/platform/network/ProxyServer.cpp
@@ -34,14 +34,14 @@ static void appendProxyServerString(StringBuilder& builder, const ProxyServer& p
{
switch (proxyServer.type()) {
case ProxyServer::Direct:
- builder.append("DIRECT");
+ builder.appendLiteral("DIRECT");
return;
case ProxyServer::HTTP:
case ProxyServer::HTTPS:
- builder.append("PROXY");
+ builder.appendLiteral("PROXY");
break;
case ProxyServer::SOCKS:
- builder.append("SOCKS");
+ builder.appendLiteral("SOCKS");
break;
}
@@ -63,7 +63,7 @@ String toString(const Vector<ProxyServer>& proxyServers)
StringBuilder stringBuilder;
for (size_t i = 0; i < proxyServers.size(); ++i) {
if (i)
- stringBuilder.append("; ");
+ stringBuilder.appendLiteral("; ");
appendProxyServerString(stringBuilder, proxyServers[i]);
}
diff --git a/Source/WebCore/platform/network/ProxyServer.h b/Source/WebCore/platform/network/ProxyServer.h
index 7c1914eba..76fdbba6a 100644
--- a/Source/WebCore/platform/network/ProxyServer.h
+++ b/Source/WebCore/platform/network/ProxyServer.h
@@ -68,11 +68,11 @@ private:
};
// Return a vector of proxy servers for the given URL.
-Vector<ProxyServer> proxyServersForURL(const URL&, const NetworkingContext*);
+WEBCORE_EXPORT Vector<ProxyServer> proxyServersForURL(const URL&, const NetworkingContext*);
// Converts the given vector of proxy servers to a PAC string, as described in
// http://web.archive.org/web/20060424005037/wp.netscape.com/eng/mozilla/2.0/relnotes/demo/proxy-live.html
-String toString(const Vector<ProxyServer>&);
+WEBCORE_EXPORT String toString(const Vector<ProxyServer>&);
} // namespace WebCore
diff --git a/Source/WebCore/platform/network/ResourceErrorBase.cpp b/Source/WebCore/platform/network/ResourceErrorBase.cpp
index 004a1992b..31ce763dd 100644
--- a/Source/WebCore/platform/network/ResourceErrorBase.cpp
+++ b/Source/WebCore/platform/network/ResourceErrorBase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -31,7 +31,12 @@ namespace WebCore {
const char* const errorDomainWebKitInternal = "WebKitInternal";
-ResourceError ResourceErrorBase::copy() const
+inline const ResourceError& ResourceErrorBase::asResourceError() const
+{
+ return *static_cast<const ResourceError*>(this);
+}
+
+ResourceError ResourceErrorBase::isolatedCopy() const
{
lazyInit();
@@ -40,10 +45,10 @@ ResourceError ResourceErrorBase::copy() const
errorCopy.m_errorCode = m_errorCode;
errorCopy.m_failingURL = m_failingURL.isolatedCopy();
errorCopy.m_localizedDescription = m_localizedDescription.isolatedCopy();
- errorCopy.m_isNull = m_isNull;
- errorCopy.m_isCancellation = m_isCancellation;
- errorCopy.m_isTimeout = m_isTimeout;
- platformCopy(errorCopy);
+ errorCopy.m_type = m_type;
+
+ errorCopy.doPlatformIsolatedCopy(asResourceError());
+
return errorCopy;
}
@@ -52,12 +57,19 @@ void ResourceErrorBase::lazyInit() const
const_cast<ResourceError*>(static_cast<const ResourceError*>(this))->platformLazyInit();
}
+void ResourceErrorBase::setType(Type type)
+{
+ // setType should only be used to specialize the error type.
+ ASSERT(m_type == Type::General || m_type == Type::Null || (m_type == Type::Cancellation && type == Type::AccessControl));
+ m_type = type;
+}
+
bool ResourceErrorBase::compare(const ResourceError& a, const ResourceError& b)
{
if (a.isNull() && b.isNull())
return true;
- if (a.isNull() || b.isNull())
+ if (a.type() != b.type())
return false;
if (a.domain() != b.domain())
@@ -72,13 +84,7 @@ bool ResourceErrorBase::compare(const ResourceError& a, const ResourceError& b)
if (a.localizedDescription() != b.localizedDescription())
return false;
- if (a.isCancellation() != b.isCancellation())
- return false;
-
- if (a.isTimeout() != b.isTimeout())
- return false;
-
- return platformCompare(a, b);
+ return ResourceError::platformCompare(a, b);
}
} // namespace WebCore
diff --git a/Source/WebCore/platform/network/ResourceErrorBase.h b/Source/WebCore/platform/network/ResourceErrorBase.h
index b4d777086..658c9caf2 100644
--- a/Source/WebCore/platform/network/ResourceErrorBase.h
+++ b/Source/WebCore/platform/network/ResourceErrorBase.h
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Canon Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,22 +11,22 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceErrorBase_h
-#define ResourceErrorBase_h
+#pragma once
+#include "URL.h"
#include <wtf/text/WTFString.h>
namespace WebCore {
@@ -36,67 +37,63 @@ extern const char* const errorDomainWebKitInternal; // Used for errors that won'
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; }
+ ResourceError isolatedCopy() const;
const String& domain() const { lazyInit(); return m_domain; }
int errorCode() const { lazyInit(); return m_errorCode; }
- const String& failingURL() const { lazyInit(); return m_failingURL; }
+ const URL& failingURL() const { lazyInit(); return m_failingURL; }
const String& localizedDescription() const { lazyInit(); return m_localizedDescription; }
- void setIsCancellation(bool isCancellation) { m_isCancellation = isCancellation; }
- bool isCancellation() const { return m_isCancellation; }
+ enum class Type {
+ Null,
+ General,
+ AccessControl,
+ Cancellation,
+ Timeout
+ };
- void setIsTimeout(bool isTimeout) { m_isTimeout = isTimeout; }
- bool isTimeout() const { return m_isTimeout; }
+ bool isNull() const { return m_type == Type::Null; }
+ bool isGeneral() const { return m_type == Type::General; }
+ bool isAccessControl() const { return m_type == Type::AccessControl; }
+ bool isCancellation() const { return m_type == Type::Cancellation; }
+ bool isTimeout() const { return m_type == Type::Timeout; }
static bool compare(const ResourceError&, const ResourceError&);
+ void setType(Type);
+ Type type() const { return m_type; }
+
protected:
- ResourceErrorBase()
- : m_errorCode(0)
- , m_isNull(true)
- , m_isCancellation(false)
- , m_isTimeout(false)
- {
- }
+ ResourceErrorBase(Type type) : m_type(type) { }
- ResourceErrorBase(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription)
+ ResourceErrorBase(const String& domain, int errorCode, const URL& failingURL, const String& localizedDescription, Type type)
: m_domain(domain)
, m_failingURL(failingURL)
, m_localizedDescription(localizedDescription)
, m_errorCode(errorCode)
- , m_isNull(false)
- , m_isCancellation(false)
- , m_isTimeout(false)
+ , m_type(type)
{
}
- void lazyInit() const;
+ WEBCORE_EXPORT void lazyInit() const;
// The ResourceError subclass may "shadow" this method to lazily initialize platform specific fields
void platformLazyInit() {}
- // The ResourceError subclass may "shadow" this method to copy platform specific fields
- void platformCopy(ResourceError&) const {}
-
// The ResourceError subclass may "shadow" this method to compare platform specific fields
static bool platformCompare(const ResourceError&, const ResourceError&) { return true; }
String m_domain;
- String m_failingURL;
+ URL m_failingURL;
String m_localizedDescription;
- int m_errorCode;
- bool m_isNull : 1;
- bool m_isCancellation : 1;
- bool m_isTimeout : 1;
+ int m_errorCode { 0 };
+ Type m_type { Type::General };
+
+private:
+ const ResourceError& asResourceError() const;
};
inline bool operator==(const ResourceError& a, const ResourceError& b) { return ResourceErrorBase::compare(a, b); }
inline bool operator!=(const ResourceError& a, const ResourceError& b) { return !(a == b); }
} // namespace WebCore
-
-#endif // ResourceErrorBase_h
diff --git a/Source/WebCore/platform/network/ResourceHandle.cpp b/Source/WebCore/platform/network/ResourceHandle.cpp
index 1a3994ec8..1fd0fd93a 100644
--- a/Source/WebCore/platform/network/ResourceHandle.cpp
+++ b/Source/WebCore/platform/network/ResourceHandle.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -34,6 +34,8 @@
#include "Timer.h"
#include <algorithm>
#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/AtomicStringHash.h>
#include <wtf/text/CString.h>
namespace WebCore {
@@ -48,7 +50,7 @@ static BuiltinResourceHandleConstructorMap& builtinResourceHandleConstructorMap(
#else
ASSERT(isMainThread());
#endif
- DEFINE_STATIC_LOCAL(BuiltinResourceHandleConstructorMap, map, ());
+ static NeverDestroyed<BuiltinResourceHandleConstructorMap> map;
return map;
}
@@ -61,7 +63,7 @@ typedef HashMap<AtomicString, ResourceHandle::BuiltinSynchronousLoader> BuiltinR
static BuiltinResourceHandleSynchronousLoaderMap& builtinResourceHandleSynchronousLoaderMap()
{
ASSERT(isMainThread());
- DEFINE_STATIC_LOCAL(BuiltinResourceHandleSynchronousLoaderMap, map, ());
+ static NeverDestroyed<BuiltinResourceHandleSynchronousLoaderMap> map;
return map;
}
@@ -71,7 +73,7 @@ void ResourceHandle::registerBuiltinSynchronousLoader(const AtomicString& protoc
}
ResourceHandle::ResourceHandle(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff)
- : d(adoptPtr(new ResourceHandleInternal(this, context, request, client, defersLoading, shouldContentSniff && shouldContentSniffURL(request.url()))))
+ : d(std::make_unique<ResourceHandleInternal>(this, context, request, client, defersLoading, shouldContentSniff && shouldContentSniffURL(request.url())))
{
if (!request.url().isValid()) {
scheduleFailure(InvalidURLFailure);
@@ -84,22 +86,20 @@ ResourceHandle::ResourceHandle(NetworkingContext* context, const ResourceRequest
}
}
-PassRefPtr<ResourceHandle> ResourceHandle::create(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff)
+RefPtr<ResourceHandle> ResourceHandle::create(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff)
{
- BuiltinResourceHandleConstructorMap::iterator protocolMapItem = builtinResourceHandleConstructorMap().find(request.url().protocol());
+ if (auto constructor = builtinResourceHandleConstructorMap().get(request.url().protocol().toStringWithoutCopying()))
+ return constructor(request, client);
- if (protocolMapItem != builtinResourceHandleConstructorMap().end())
- return protocolMapItem->value(request, client);
-
- RefPtr<ResourceHandle> newHandle(adoptRef(new ResourceHandle(context, request, client, defersLoading, shouldContentSniff)));
+ auto newHandle = adoptRef(*new ResourceHandle(context, request, client, defersLoading, shouldContentSniff));
if (newHandle->d->m_scheduledFailureType != NoFailure)
- return newHandle.release();
+ return WTFMove(newHandle);
if (newHandle->start())
- return newHandle.release();
+ return WTFMove(newHandle);
- return 0;
+ return nullptr;
}
void ResourceHandle::scheduleFailure(FailureType type)
@@ -108,7 +108,7 @@ void ResourceHandle::scheduleFailure(FailureType type)
d->m_failureTimer.startOneShot(0);
}
-void ResourceHandle::failureTimerFired(Timer<ResourceHandle>&)
+void ResourceHandle::failureTimerFired()
{
if (!client())
return;
@@ -132,10 +132,8 @@ void ResourceHandle::failureTimerFired(Timer<ResourceHandle>&)
void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
{
- BuiltinResourceHandleSynchronousLoaderMap::iterator protocolMapItem = builtinResourceHandleSynchronousLoaderMap().find(request.url().protocol());
-
- if (protocolMapItem != builtinResourceHandleSynchronousLoaderMap().end()) {
- protocolMapItem->value(context, request, storedCredentials, error, response, data);
+ if (auto constructor = builtinResourceHandleSynchronousLoaderMap().get(request.url().protocol().toStringWithoutCopying())) {
+ constructor(context, request, storedCredentials, error, response, data);
return;
}
@@ -147,24 +145,39 @@ ResourceHandleClient* ResourceHandle::client() const
return d->m_client;
}
-void ResourceHandle::setClient(ResourceHandleClient* client)
+void ResourceHandle::clearClient()
{
- d->m_client = client;
+ d->m_client = nullptr;
}
-#if !PLATFORM(MAC) && !USE(CFNETWORK) && !USE(SOUP)
-// ResourceHandle never uses async client calls on these platforms yet.
-void ResourceHandle::continueWillSendRequest(const ResourceRequest&)
+void ResourceHandle::didReceiveResponse(ResourceResponse&& response)
{
- notImplemented();
+ if (response.isHTTP09()) {
+ auto url = response.url();
+ std::optional<uint16_t> port = url.port();
+ if (port && !isDefaultPortForProtocol(port.value(), url.protocol())) {
+ cancel();
+ String message = "Cancelled load from '" + url.stringCenterEllipsizedToLength() + "' because it is using HTTP/0.9.";
+ d->m_client->didFail(this, { String(), 0, url, message });
+ return;
+ }
+ }
+ if (d->m_usesAsyncCallbacks)
+ d->m_client->didReceiveResponseAsync(this, WTFMove(response));
+ else {
+ d->m_client->didReceiveResponse(this, WTFMove(response));
+ platformContinueSynchronousDidReceiveResponse();
+ }
}
-void ResourceHandle::continueDidReceiveResponse()
+#if !PLATFORM(COCOA) && !USE(CFURLCONNECTION) && !USE(SOUP)
+// ResourceHandle never uses async client calls on these platforms yet.
+void ResourceHandle::continueWillSendRequest(ResourceRequest&&)
{
notImplemented();
}
-void ResourceHandle::continueShouldUseCredentialStorage(bool)
+void ResourceHandle::continueDidReceiveResponse()
{
notImplemented();
}
@@ -177,6 +190,13 @@ void ResourceHandle::continueCanAuthenticateAgainstProtectionSpace(bool)
#endif
#endif
+#if !USE(SOUP)
+void ResourceHandle::platformContinueSynchronousDidReceiveResponse()
+{
+ // Do nothing.
+}
+#endif
+
ResourceRequest& ResourceHandle::firstRequest()
{
return d->m_firstRequest;
@@ -199,7 +219,7 @@ bool ResourceHandle::hasAuthenticationChallenge() const
void ResourceHandle::clearAuthentication()
{
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
d->m_currentMacChallenge = nil;
#endif
d->m_currentWebChallenge.nullify();
@@ -212,7 +232,7 @@ bool ResourceHandle::shouldContentSniff() const
bool ResourceHandle::shouldContentSniffURL(const URL& url)
{
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
if (shouldForceContentSniffing)
return true;
#endif
@@ -244,9 +264,9 @@ void ResourceHandle::setDefersLoading(bool defers)
platformSetDefersLoading(defers);
}
-void ResourceHandle::didChangePriority(ResourceLoadPriority)
+bool ResourceHandle::usesAsyncCallbacks() const
{
- // Optionally implemented by platform.
+ return d->m_usesAsyncCallbacks;
}
} // namespace WebCore
diff --git a/Source/WebCore/platform/network/ResourceHandle.h b/Source/WebCore/platform/network/ResourceHandle.h
index c1da03494..e1c429ad0 100644
--- a/Source/WebCore/platform/network/ResourceHandle.h
+++ b/Source/WebCore/platform/network/ResourceHandle.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2006, 2011, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,19 +23,17 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceHandle_h
-#define ResourceHandle_h
+#pragma once
#include "AuthenticationClient.h"
#include "HTTPHeaderMap.h"
#include "ResourceHandleTypes.h"
#include "ResourceLoadPriority.h"
-#include <wtf/OwnPtr.h>
#include <wtf/RefCounted.h>
-#if USE(QUICK_LOOK)
-#include "QuickLook.h"
-#endif // USE(QUICK_LOOK)
+#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
+#include <wtf/RetainPtr.h>
+#endif
#if USE(SOUP)
typedef struct _GTlsCertificate GTlsCertificate;
@@ -47,20 +45,10 @@ typedef struct _SoupRequest SoupRequest;
typedef const struct __CFData * CFDataRef;
#endif
-#if USE(WININET)
-typedef unsigned long DWORD;
-typedef unsigned long DWORD_PTR;
-typedef void* LPVOID;
-typedef LPVOID HINTERNET;
-#endif
-
-#if PLATFORM(MAC) || USE(CFNETWORK)
-#include <wtf/RetainPtr.h>
-#endif
-
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
OBJC_CLASS NSCachedURLResponse;
OBJC_CLASS NSData;
+OBJC_CLASS NSDictionary;
OBJC_CLASS NSError;
OBJC_CLASS NSURLConnection;
#ifndef __OBJC__
@@ -68,14 +56,14 @@ typedef struct objc_object *id;
#endif
#endif
-#if USE(CFNETWORK)
+#if USE(CFURLCONNECTION)
typedef const struct _CFCachedURLResponse* CFCachedURLResponseRef;
typedef struct _CFURLConnection* CFURLConnectionRef;
typedef int CFHTTPCookieStorageAcceptPolicy;
typedef struct OpaqueCFHTTPCookieStorage* CFHTTPCookieStorageRef;
#endif
-#if PLATFORM(MAC) || USE(CFNETWORK)
+#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
typedef const struct __CFURLStorageSession* CFURLStorageSessionRef;
#endif
@@ -84,76 +72,91 @@ class SchedulePair;
}
namespace WebCore {
+
class AuthenticationChallenge;
class Credential;
class Frame;
class URL;
class NetworkingContext;
class ProtectionSpace;
+class QuickLookHandle;
class ResourceError;
class ResourceHandleClient;
class ResourceHandleInternal;
+class NetworkLoadTiming;
class ResourceRequest;
class ResourceResponse;
+class SoupNetworkSession;
class SharedBuffer;
+class Timer;
-template <typename T> class Timer;
+class ResourceHandle : public RefCounted<ResourceHandle>, public AuthenticationClient {
+public:
+ WEBCORE_EXPORT static RefPtr<ResourceHandle> create(NetworkingContext*, const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff);
+ WEBCORE_EXPORT static void loadResourceSynchronously(NetworkingContext*, const ResourceRequest&, StoredCredentials, ResourceError&, ResourceResponse&, Vector<char>& data);
-class ResourceHandle : public RefCounted<ResourceHandle>
-#if PLATFORM(MAC) || USE(CFNETWORK) || USE(CURL) || USE(SOUP)
- , public AuthenticationClient
+#if USE(SOUP)
+ static RefPtr<ResourceHandle> create(SoupNetworkSession&, const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff);
#endif
- {
-public:
- static PassRefPtr<ResourceHandle> create(NetworkingContext*, const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff);
- static void loadResourceSynchronously(NetworkingContext*, const ResourceRequest&, StoredCredentials, ResourceError&, ResourceResponse&, Vector<char>& data);
- virtual ~ResourceHandle();
+ WEBCORE_EXPORT virtual ~ResourceHandle();
-#if PLATFORM(MAC) || USE(CFNETWORK)
- void willSendRequest(ResourceRequest&, const ResourceResponse& redirectResponse);
+#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
+ ResourceRequest willSendRequest(ResourceRequest&&, ResourceResponse&&);
#endif
-#if PLATFORM(MAC) || USE(CFNETWORK) || USE(CURL) || USE(SOUP)
+
+ void didReceiveResponse(ResourceResponse&&);
+
bool shouldUseCredentialStorage();
void didReceiveAuthenticationChallenge(const AuthenticationChallenge&);
- virtual void receivedCredential(const AuthenticationChallenge&, const Credential&) override;
- virtual void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&) override;
- virtual void receivedCancellation(const AuthenticationChallenge&) override;
+ void receivedCredential(const AuthenticationChallenge&, const Credential&) override;
+ void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&) override;
+ void receivedCancellation(const AuthenticationChallenge&) override;
+ void receivedRequestToPerformDefaultHandling(const AuthenticationChallenge&) override;
+ void receivedChallengeRejection(const AuthenticationChallenge&) override;
+
+#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
+ bool tryHandlePasswordBasedAuthentication(const AuthenticationChallenge&);
#endif
-#if PLATFORM(MAC)
-#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+#if PLATFORM(COCOA) && USE(PROTECTION_SPACE_AUTH_CALLBACK)
bool canAuthenticateAgainstProtectionSpace(const ProtectionSpace&);
#endif
-#if !USE(CFNETWORK)
- void didCancelAuthenticationChallenge(const AuthenticationChallenge&);
- NSURLConnection *connection() const;
+
+#if PLATFORM(COCOA) && !USE(CFURLCONNECTION)
+ WEBCORE_EXPORT NSURLConnection *connection() const;
+ id makeDelegate(bool);
id delegate();
void releaseDelegate();
#endif
-
- void schedule(WTF::SchedulePair*);
- void unschedule(WTF::SchedulePair*);
+
+#if PLATFORM(COCOA) && ENABLE(WEB_TIMING)
+#if USE(CFURLCONNECTION)
+ static void getConnectionTimingData(CFURLConnectionRef, NetworkLoadTiming&);
+#else
+ static void getConnectionTimingData(NSURLConnection *, NetworkLoadTiming&);
+#endif
+#endif
+
+#if PLATFORM(COCOA)
+ void schedule(WTF::SchedulePair&);
+ void unschedule(WTF::SchedulePair&);
#endif
-#if USE(CFNETWORK)
+
+#if USE(CFURLCONNECTION)
CFURLStorageSessionRef storageSession() const;
CFURLConnectionRef connection() const;
- CFURLConnectionRef releaseConnectionForDownload();
+ WEBCORE_EXPORT RetainPtr<CFURLConnectionRef> releaseConnectionForDownload();
const ResourceRequest& currentRequest() const;
static void setHostAllowsAnyHTTPSCertificate(const String&);
static void setClientCertificate(const String& host, CFDataRef);
-
-#if USE(QUICK_LOOK)
- QuickLookHandle* quickLookHandle() { return m_quickLook.get(); }
- void setQuickLookHandle(PassOwnPtr<QuickLookHandle> handle) { m_quickLook = handle; }
-#endif // USE(QUICK_LOOK)
-
-#endif // USE(CFNETWORK)
+#endif
#if PLATFORM(WIN) && USE(CURL)
static void setHostAllowsAnyHTTPSCertificate(const String&);
static void setClientCertificateInfo(const String&, const String&, const String&);
#endif
+
#if PLATFORM(WIN) && USE(CURL) && USE(CF)
static void setClientCertificate(const String& host, CFDataRef);
#endif
@@ -161,90 +164,71 @@ public:
bool shouldContentSniff() const;
static bool shouldContentSniffURL(const URL&);
- static void forceContentSniffing();
-
-#if USE(WININET)
- void setSynchronousInternetHandle(HINTERNET);
- void fileLoadTimer(Timer<ResourceHandle>*);
- void onRedirect();
- bool onRequestComplete();
- static void CALLBACK internetStatusCallback(HINTERNET, DWORD_PTR, DWORD, LPVOID, DWORD);
-#endif
+ WEBCORE_EXPORT static void forceContentSniffing();
#if USE(CURL) || USE(SOUP)
ResourceHandleInternal* getInternal() { return d.get(); }
#endif
#if USE(SOUP)
+ RefPtr<ResourceHandle> releaseForDownload(ResourceHandleClient*);
void continueDidReceiveAuthenticationChallenge(const Credential& credentialFromPersistentStorage);
void sendPendingRequest();
bool cancelledOrClientless();
void ensureReadBuffer();
size_t currentStreamPosition() const;
void didStartRequest();
- static void setHostAllowsAnyHTTPSCertificate(const String&);
- static void setClientCertificate(const String& host, GTlsCertificate*);
- static void setIgnoreSSLErrors(bool);
+ double m_requestTime;
#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();
-
bool hasAuthenticationChallenge() const;
void clearAuthentication();
- virtual void cancel();
+ WEBCORE_EXPORT virtual void cancel();
// The client may be 0, in which case no callbacks will be made.
- ResourceHandleClient* client() const;
- void setClient(ResourceHandleClient*);
+ WEBCORE_EXPORT ResourceHandleClient* client() const;
+ WEBCORE_EXPORT void clearClient();
// Called in response to ResourceHandleClient::willSendRequestAsync().
- void continueWillSendRequest(const ResourceRequest&);
+ WEBCORE_EXPORT void continueWillSendRequest(ResourceRequest&&);
// Called in response to ResourceHandleClient::didReceiveResponseAsync().
- void continueDidReceiveResponse();
-
- // Called in response to ResourceHandleClient::shouldUseCredentialStorageAsync().
- void continueShouldUseCredentialStorage(bool);
+ WEBCORE_EXPORT virtual void continueDidReceiveResponse();
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
// Called in response to ResourceHandleClient::canAuthenticateAgainstProtectionSpaceAsync().
- void continueCanAuthenticateAgainstProtectionSpace(bool);
+ WEBCORE_EXPORT void continueCanAuthenticateAgainstProtectionSpace(bool);
#endif
// Called in response to ResourceHandleClient::willCacheResponseAsync().
-#if USE(CFNETWORK)
- void continueWillCacheResponse(CFCachedURLResponseRef);
-#elif PLATFORM(MAC)
- void continueWillCacheResponse(NSCachedURLResponse *);
+#if USE(CFURLCONNECTION)
+ WEBCORE_EXPORT void continueWillCacheResponse(CFCachedURLResponseRef);
+#endif
+#if PLATFORM(COCOA) && !USE(CFURLCONNECTION)
+ WEBCORE_EXPORT void continueWillCacheResponse(NSCachedURLResponse *);
#endif
- void setDefersLoading(bool);
-
- void didChangePriority(ResourceLoadPriority);
+ WEBCORE_EXPORT void setDefersLoading(bool);
- ResourceRequest& firstRequest();
+ WEBCORE_EXPORT ResourceRequest& firstRequest();
const String& lastHTTPMethod() const;
- void failureTimerFired(Timer<ResourceHandle>&);
+ void failureTimerFired();
NetworkingContext* context() const;
using RefCounted<ResourceHandle>::ref;
using RefCounted<ResourceHandle>::deref;
-#if PLATFORM(MAC) || USE(CFNETWORK)
- static CFStringRef synchronousLoadRunLoopMode();
-#endif
-#if PLATFORM(IOS) && USE(CFNETWORK)
- static CFMutableDictionaryRef createSSLPropertiesFromNSURLRequest(const ResourceRequest&);
+#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
+ WEBCORE_EXPORT static CFStringRef synchronousLoadRunLoopMode();
#endif
-#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
- void handleDataArray(CFArrayRef dataArray);
+#if PLATFORM(IOS) && USE(CFURLCONNECTION)
+ static CFMutableDictionaryRef createSSLPropertiesFromNSURLRequest(const ResourceRequest&);
#endif
- typedef PassRefPtr<ResourceHandle> (*BuiltinConstructor)(const ResourceRequest& request, ResourceHandleClient* client);
+ typedef Ref<ResourceHandle> (*BuiltinConstructor)(const ResourceRequest& request, ResourceHandleClient* client);
static void registerBuiltinConstructor(const AtomicString& protocol, BuiltinConstructor);
typedef void (*BuiltinSynchronousLoader)(NetworkingContext*, const ResourceRequest&, StoredCredentials, ResourceError&, ResourceResponse&, Vector<char>& data);
@@ -253,6 +237,8 @@ public:
protected:
ResourceHandle(NetworkingContext*, const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff);
+ bool usesAsyncCallbacks() const;
+
private:
enum FailureType {
NoFailure,
@@ -260,37 +246,44 @@ private:
InvalidURLFailure
};
+#if USE(SOUP)
+ ResourceHandle(SoupNetworkSession&, const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff);
+#endif
+
void platformSetDefersLoading(bool);
+ void platformContinueSynchronousDidReceiveResponse();
+
void scheduleFailure(FailureType);
bool start();
static void platformLoadResourceSynchronously(NetworkingContext*, const ResourceRequest&, StoredCredentials, ResourceError&, ResourceResponse&, Vector<char>& data);
- virtual void refAuthenticationClient() override { ref(); }
- virtual void derefAuthenticationClient() override { deref(); }
+ void refAuthenticationClient() override { ref(); }
+ void derefAuthenticationClient() override { deref(); }
-#if PLATFORM(MAC) || USE(CFNETWORK)
- enum class SchedulingBehavior {
- Asynchronous,
- Synchronous
- };
+#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
+ enum class SchedulingBehavior { Asynchronous, Synchronous };
+#endif
-#if USE(CFNETWORK)
+#if USE(CFURLCONNECTION)
void createCFURLConnection(bool shouldUseCredentialStorage, bool shouldContentSniff, SchedulingBehavior, CFDictionaryRef clientProperties);
-#else
+#endif
+
+#if PLATFORM(MAC) && !USE(CFURLCONNECTION)
void createNSURLConnection(id delegate, bool shouldUseCredentialStorage, bool shouldContentSniff, SchedulingBehavior);
#endif
+
+#if PLATFORM(IOS) && !USE(CFURLCONNECTION)
+ void createNSURLConnection(id delegate, bool shouldUseCredentialStorage, bool shouldContentSniff, SchedulingBehavior, NSDictionary *connectionProperties);
#endif
- friend class ResourceHandleInternal;
- OwnPtr<ResourceHandleInternal> d;
+#if USE(SOUP)
+ void timeoutFired();
+#endif
-#if USE(QUICK_LOOK)
- OwnPtr<QuickLookHandle> m_quickLook;
-#endif // USE(QUICK_LOOK)
+ friend class ResourceHandleInternal;
+ std::unique_ptr<ResourceHandleInternal> d;
};
}
-
-#endif // ResourceHandle_h
diff --git a/Source/WebCore/platform/network/ResourceHandleClient.cpp b/Source/WebCore/platform/network/ResourceHandleClient.cpp
index 8eb4eeb6a..9487d967e 100644
--- a/Source/WebCore/platform/network/ResourceHandleClient.cpp
+++ b/Source/WebCore/platform/network/ResourceHandleClient.cpp
@@ -27,6 +27,7 @@
#include "ResourceHandleClient.h"
#include "ResourceHandle.h"
+#include "ResourceRequest.h"
#include "SharedBuffer.h"
namespace WebCore {
@@ -38,20 +39,20 @@ ResourceHandleClient::ResourceHandleClient()
ResourceHandleClient::~ResourceHandleClient()
{
}
-
-void ResourceHandleClient::willSendRequestAsync(ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& /*redirectResponse*/)
+
+ResourceRequest ResourceHandleClient::willSendRequest(ResourceHandle*, ResourceRequest&& request, ResourceResponse&&)
{
- handle->continueWillSendRequest(request);
+ return WTFMove(request);
}
-void ResourceHandleClient::didReceiveResponseAsync(ResourceHandle* handle, const ResourceResponse&)
+void ResourceHandleClient::willSendRequestAsync(ResourceHandle* handle, ResourceRequest&& request, ResourceResponse&& /*redirectResponse*/)
{
- handle->continueDidReceiveResponse();
+ handle->continueWillSendRequest(WTFMove(request));
}
-void ResourceHandleClient::shouldUseCredentialStorageAsync(ResourceHandle* handle)
+void ResourceHandleClient::didReceiveResponseAsync(ResourceHandle* handle, ResourceResponse&&)
{
- handle->continueShouldUseCredentialStorage(false);
+ handle->continueDidReceiveResponse();
}
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
@@ -61,19 +62,19 @@ void ResourceHandleClient::canAuthenticateAgainstProtectionSpaceAsync(ResourceHa
}
#endif
-#if USE(CFNETWORK)
+#if USE(CFURLCONNECTION)
void ResourceHandleClient::willCacheResponseAsync(ResourceHandle* handle, CFCachedURLResponseRef response)
{
handle->continueWillCacheResponse(response);
}
-#elif PLATFORM(MAC)
+#elif PLATFORM(COCOA)
void ResourceHandleClient::willCacheResponseAsync(ResourceHandle* handle, NSCachedURLResponse *response)
{
handle->continueWillCacheResponse(response);
}
#endif
-void ResourceHandleClient::didReceiveBuffer(ResourceHandle* handle, PassRefPtr<SharedBuffer> buffer, int encodedDataLength)
+void ResourceHandleClient::didReceiveBuffer(ResourceHandle* handle, Ref<SharedBuffer>&& buffer, int encodedDataLength)
{
didReceiveData(handle, buffer->data(), buffer->size(), encodedDataLength);
}
diff --git a/Source/WebCore/platform/network/ResourceHandleClient.h b/Source/WebCore/platform/network/ResourceHandleClient.h
index aa4b79a87..5c371ed99 100644
--- a/Source/WebCore/platform/network/ResourceHandleClient.h
+++ b/Source/WebCore/platform/network/ResourceHandleClient.h
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2013 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -11,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,18 +23,21 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceHandleClient_h
-#define ResourceHandleClient_h
+#pragma once
-#include <wtf/PassRefPtr.h>
+#include "PlatformExportMacros.h"
+#include <wtf/Ref.h>
-#if USE(CFNETWORK)
+#if USE(CFURLCONNECTION)
#include <CFNetwork/CFURLCachePriv.h>
#include <CFNetwork/CFURLResponsePriv.h>
+#endif
+
+#if PLATFORM(IOS) || USE(CFURLCONNECTION)
#include <wtf/RetainPtr.h>
#endif
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
OBJC_CLASS NSCachedURLResponse;
#endif
@@ -58,17 +60,16 @@ namespace WebCore {
class ResourceHandleClient {
public:
- ResourceHandleClient();
- virtual ~ResourceHandleClient();
+ WEBCORE_EXPORT ResourceHandleClient();
+ WEBCORE_EXPORT virtual ~ResourceHandleClient();
- // Request may be modified.
- virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse& /*redirectResponse*/) { }
+ WEBCORE_EXPORT virtual ResourceRequest willSendRequest(ResourceHandle*, ResourceRequest&&, ResourceResponse&&);
virtual void didSendData(ResourceHandle*, unsigned long long /*bytesSent*/, unsigned long long /*totalBytesToBeSent*/) { }
- virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&) { }
+ virtual void didReceiveResponse(ResourceHandle*, ResourceResponse&&) { }
virtual void didReceiveData(ResourceHandle*, const char*, unsigned, int /*encodedDataLength*/) { }
- virtual void didReceiveBuffer(ResourceHandle*, PassRefPtr<SharedBuffer>, int encodedDataLength);
+ WEBCORE_EXPORT virtual void didReceiveBuffer(ResourceHandle*, Ref<SharedBuffer>&&, int encodedDataLength);
virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/) { }
virtual void didFail(ResourceHandle*, const ResourceError&) { }
@@ -77,23 +78,23 @@ namespace WebCore {
virtual bool usesAsyncCallbacks() { return false; }
+ virtual bool loadingSynchronousXHR() { return false; }
+
// Client will pass an updated request using ResourceHandle::continueWillSendRequest() when ready.
- virtual void willSendRequestAsync(ResourceHandle*, const ResourceRequest&, const ResourceResponse& redirectResponse);
+ WEBCORE_EXPORT virtual void willSendRequestAsync(ResourceHandle*, ResourceRequest&&, ResourceResponse&&);
// Client will call ResourceHandle::continueDidReceiveResponse() when ready.
- virtual void didReceiveResponseAsync(ResourceHandle*, const ResourceResponse&);
+ WEBCORE_EXPORT virtual void didReceiveResponseAsync(ResourceHandle*, ResourceResponse&&);
- // Client will pass an updated request using ResourceHandle::continueShouldUseCredentialStorage() when ready.
- virtual void shouldUseCredentialStorageAsync(ResourceHandle*);
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
// Client will pass an updated request using ResourceHandle::continueCanAuthenticateAgainstProtectionSpace() when ready.
- virtual void canAuthenticateAgainstProtectionSpaceAsync(ResourceHandle*, const ProtectionSpace&);
+ WEBCORE_EXPORT virtual void canAuthenticateAgainstProtectionSpaceAsync(ResourceHandle*, const ProtectionSpace&);
#endif
// Client will pass an updated request using ResourceHandle::continueWillCacheResponse() when ready.
-#if USE(CFNETWORK)
- virtual void willCacheResponseAsync(ResourceHandle*, CFCachedURLResponseRef);
-#elif PLATFORM(MAC)
- virtual void willCacheResponseAsync(ResourceHandle*, NSCachedURLResponse *);
+#if USE(CFURLCONNECTION)
+ WEBCORE_EXPORT virtual void willCacheResponseAsync(ResourceHandle*, CFCachedURLResponseRef);
+#elif PLATFORM(COCOA)
+ WEBCORE_EXPORT virtual void willCacheResponseAsync(ResourceHandle*, NSCachedURLResponse *);
#endif
#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
@@ -107,26 +108,24 @@ namespace WebCore {
virtual bool shouldUseCredentialStorage(ResourceHandle*) { return false; }
virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&) { }
- virtual void didCancelAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&) { }
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
virtual bool canAuthenticateAgainstProtectionSpace(ResourceHandle*, const ProtectionSpace&) { return false; }
#endif
virtual void receivedCancellation(ResourceHandle*, const AuthenticationChallenge&) { }
-#if USE(CFNETWORK)
- virtual CFCachedURLResponseRef willCacheResponse(ResourceHandle*, CFCachedURLResponseRef response) { return response; }
+#if PLATFORM(IOS) || USE(CFURLCONNECTION)
virtual RetainPtr<CFDictionaryRef> connectionProperties(ResourceHandle*) { return nullptr; }
+#endif
+
+#if USE(CFURLCONNECTION)
+ virtual CFCachedURLResponseRef willCacheResponse(ResourceHandle*, CFCachedURLResponseRef response) { return response; }
#if PLATFORM(WIN)
virtual bool shouldCacheResponse(ResourceHandle*, CFCachedURLResponseRef) { return true; }
#endif // PLATFORM(WIN)
-#elif PLATFORM(MAC)
+#elif PLATFORM(COCOA)
virtual NSCachedURLResponse *willCacheResponse(ResourceHandle*, NSCachedURLResponse *response) { return response; }
- virtual void willStopBufferingData(ResourceHandle*, const char*, unsigned) { }
#endif
-
};
}
-
-#endif
diff --git a/Source/WebCore/platform/network/ResourceHandleInternal.h b/Source/WebCore/platform/network/ResourceHandleInternal.h
index 6c1ba947f..d84de90cd 100644
--- a/Source/WebCore/platform/network/ResourceHandleInternal.h
+++ b/Source/WebCore/platform/network/ResourceHandleInternal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2004, 2006 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,21 +23,21 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceHandleInternal_h
-#define ResourceHandleInternal_h
+#pragma once
#include "NetworkingContext.h"
#include "ResourceHandle.h"
+#include "ResourceHandleClient.h"
#include "ResourceRequest.h"
#include "AuthenticationChallenge.h"
#include "Timer.h"
-#if USE(CFNETWORK)
+#if USE(CFURLCONNECTION)
#include "ResourceHandleCFURLConnectionDelegate.h"
#include <CFNetwork/CFURLConnectionPriv.h>
#endif
-#if USE(WININET) || (USE(CURL) && PLATFORM(WIN))
+#if USE(CURL) && PLATFORM(WIN)
#include <winsock2.h>
#include <windows.h>
#endif
@@ -50,17 +50,18 @@
#if USE(SOUP)
#include "GUniquePtrSoup.h"
+#include "SoupNetworkSession.h"
#include <libsoup/soup.h>
-#include <wtf/gobject/GRefPtr.h>
-class Frame;
+#include <wtf/RunLoop.h>
+#include <wtf/glib/GRefPtr.h>
#endif
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
OBJC_CLASS NSURLAuthenticationChallenge;
OBJC_CLASS NSURLConnection;
#endif
-#if PLATFORM(MAC) || USE(CFNETWORK)
+#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
typedef const struct __CFURLStorageSession* CFURLStorageSessionRef;
#endif
@@ -69,160 +70,120 @@ typedef const struct __CFURLStorageSession* CFURLStorageSessionRef;
// WebCoreResourceLoaderImp which avoids doing work in dealloc).
namespace WebCore {
- class ResourceHandleClient;
-
- class ResourceHandleInternal {
- WTF_MAKE_NONCOPYABLE(ResourceHandleInternal); WTF_MAKE_FAST_ALLOCATED;
- public:
- ResourceHandleInternal(ResourceHandle* loader, NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff)
- : m_context(context)
- , m_client(client)
- , m_firstRequest(request)
- , m_lastHTTPMethod(request.httpMethod())
- , status(0)
- , m_defersLoading(defersLoading)
- , m_shouldContentSniff(shouldContentSniff)
-#if USE(CFNETWORK)
- , m_connection(0)
- , m_currentRequest(request)
-#endif
-#if USE(WININET)
- , m_fileLoadTimer(loader, &ResourceHandle::fileLoadTimer)
- , m_internetHandle(0)
- , m_connectHandle(0)
- , m_requestHandle(0)
- , m_sentEndRequest(false)
- , m_bytesRemainingToWrite(0)
- , m_loadSynchronously(false)
- , m_hasReceivedResponse(false)
+
+class ResourceHandleInternal {
+ WTF_MAKE_NONCOPYABLE(ResourceHandleInternal); WTF_MAKE_FAST_ALLOCATED;
+public:
+ ResourceHandleInternal(ResourceHandle* loader, NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff)
+ : m_context(context)
+ , m_client(client)
+ , m_firstRequest(request)
+ , m_lastHTTPMethod(request.httpMethod())
+ , m_partition(request.cachePartition())
+ , m_defersLoading(defersLoading)
+ , m_shouldContentSniff(shouldContentSniff)
+ , m_usesAsyncCallbacks(client && client->usesAsyncCallbacks())
+#if USE(CFURLCONNECTION)
+ , m_currentRequest(request)
#endif
#if USE(CURL)
- , m_handle(0)
- , m_url(0)
- , m_customHeaders(0)
- , m_cancelled(false)
- , m_authFailureCount(0)
- , m_formDataStream(loader)
- , m_sslErrors(0)
+ , m_formDataStream(loader)
#endif
#if USE(SOUP)
- , m_cancelled(false)
- , m_bodySize(0)
- , m_bodyDataSent(0)
- , m_redirectCount(0)
- , m_previousPosition(0)
- , m_useAuthenticationManager(true)
-#endif
-#if PLATFORM(MAC)
- , m_startWhenScheduled(false)
- , m_needsSiteSpecificQuirks(false)
- , m_currentMacChallenge(nil)
-#endif
- , m_scheduledFailureType(ResourceHandle::NoFailure)
- , m_failureTimer(loader, &ResourceHandle::failureTimerFired)
- {
- const URL& url = m_firstRequest.url();
- m_user = url.user();
- m_pass = url.pass();
- m_firstRequest.removeCredentials();
- }
-
- ~ResourceHandleInternal();
-
- ResourceHandleClient* client() { return m_client; }
-
- RefPtr<NetworkingContext> m_context;
- ResourceHandleClient* m_client;
- ResourceRequest m_firstRequest;
- String m_lastHTTPMethod;
-
- // Suggested credentials for the current redirection step.
- String m_user;
- String m_pass;
-
- Credential m_initialCredential;
-
- int status;
-
- bool m_defersLoading;
- bool m_shouldContentSniff;
-#if USE(CFNETWORK)
- RetainPtr<CFURLConnectionRef> m_connection;
- ResourceRequest m_currentRequest;
- RefPtr<ResourceHandleCFURLConnectionDelegate> m_connectionDelegate;
-#endif
-#if PLATFORM(MAC) && !USE(CFNETWORK)
- RetainPtr<NSURLConnection> m_connection;
- RetainPtr<id> m_delegate;
-#endif
-#if PLATFORM(MAC)
- bool m_startWhenScheduled;
- bool m_needsSiteSpecificQuirks;
-#endif
-#if PLATFORM(MAC) || USE(CFNETWORK)
- RetainPtr<CFURLStorageSessionRef> m_storageSession;
-#endif
-#if USE(WININET)
- Timer<ResourceHandle> m_fileLoadTimer;
- HINTERNET m_internetHandle;
- HINTERNET m_connectHandle;
- HINTERNET m_requestHandle;
- bool m_sentEndRequest;
- Vector<char> m_formData;
- size_t m_bytesRemainingToWrite;
- bool m_loadSynchronously;
- bool m_hasReceivedResponse;
- String m_redirectUrl;
+ , m_timeoutSource(RunLoop::main(), loader, &ResourceHandle::timeoutFired)
+#endif
+ , m_failureTimer(*loader, &ResourceHandle::failureTimerFired)
+ {
+ const URL& url = m_firstRequest.url();
+ m_user = url.user();
+ m_pass = url.pass();
+ m_firstRequest.removeCredentials();
+ }
+
+ ~ResourceHandleInternal();
+
+ ResourceHandleClient* client() { return m_client; }
+
+ RefPtr<NetworkingContext> m_context;
+ ResourceHandleClient* m_client;
+ ResourceRequest m_firstRequest;
+ String m_lastHTTPMethod;
+ String m_partition;
+
+ // Suggested credentials for the current redirection step.
+ String m_user;
+ String m_pass;
+
+ Credential m_initialCredential;
+
+ int status { 0 };
+
+ bool m_defersLoading;
+ bool m_shouldContentSniff;
+ bool m_usesAsyncCallbacks;
+#if USE(CFURLCONNECTION)
+ RetainPtr<CFURLConnectionRef> m_connection;
+ ResourceRequest m_currentRequest;
+ RefPtr<ResourceHandleCFURLConnectionDelegate> m_connectionDelegate;
+#endif
+#if PLATFORM(COCOA) && !USE(CFURLCONNECTION)
+ RetainPtr<NSURLConnection> m_connection;
+ RetainPtr<id> m_delegate;
+#endif
+#if PLATFORM(COCOA)
+ bool m_startWhenScheduled { false };
+#endif
+#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
+ RetainPtr<CFURLStorageSessionRef> m_storageSession;
#endif
#if USE(CURL)
- CURL* m_handle;
- char* m_url;
- struct curl_slist* m_customHeaders;
- ResourceResponse m_response;
- bool m_cancelled;
- unsigned short m_authFailureCount;
+ CURL* m_handle { nullptr };
+ char* m_url { nullptr };
+ struct curl_slist* m_customHeaders { nullptr };
+ ResourceResponse m_response;
+ bool m_cancelled { false };
+ unsigned short m_authFailureCount { 0 };
- FormDataStream m_formDataStream;
- unsigned m_sslErrors;
- Vector<char> m_postBytes;
+ FormDataStream m_formDataStream;
+ unsigned m_sslErrors { 0 };
+ Vector<char> m_postBytes;
- OwnPtr<MultipartHandle> m_multipartHandle;
+ std::unique_ptr<MultipartHandle> m_multipartHandle;
+ bool m_addedCacheValidationHeaders { false };
#endif
#if USE(SOUP)
- GRefPtr<SoupMessage> m_soupMessage;
- ResourceResponse m_response;
- bool m_cancelled;
- GRefPtr<SoupRequest> m_soupRequest;
- GRefPtr<GInputStream> m_inputStream;
- GRefPtr<SoupMultipartInputStream> m_multipartInputStream;
- GRefPtr<GCancellable> m_cancellable;
- GRefPtr<GAsyncResult> m_deferredResult;
- GRefPtr<GSource> m_timeoutSource;
- GUniquePtr<SoupBuffer> m_soupBuffer;
- unsigned long m_bodySize;
- unsigned long m_bodyDataSent;
- SoupSession* soupSession();
- int m_redirectCount;
- size_t m_previousPosition;
- bool m_useAuthenticationManager;
-#endif
-#if PLATFORM(GTK)
- struct {
- Credential credential;
- AuthenticationChallenge challenge;
- } m_credentialDataToSaveInPersistentStore;
-#endif
-
-#if PLATFORM(MAC)
- // We need to keep a reference to the original challenge to be able to cancel it.
- // It is almost identical to m_currentWebChallenge.nsURLAuthenticationChallenge(), but has a different sender.
- NSURLAuthenticationChallenge *m_currentMacChallenge;
-#endif
- AuthenticationChallenge m_currentWebChallenge;
- ResourceHandle::FailureType m_scheduledFailureType;
- Timer<ResourceHandle> m_failureTimer;
- };
+ SoupNetworkSession* m_session { nullptr };
+ GRefPtr<SoupMessage> m_soupMessage;
+ ResourceResponse m_response;
+ bool m_cancelled { false };
+ GRefPtr<SoupRequest> m_soupRequest;
+ GRefPtr<GInputStream> m_inputStream;
+ GRefPtr<SoupMultipartInputStream> m_multipartInputStream;
+ GRefPtr<GCancellable> m_cancellable;
+ GRefPtr<GAsyncResult> m_deferredResult;
+ RunLoop::Timer<ResourceHandle> m_timeoutSource;
+ GUniquePtr<SoupBuffer> m_soupBuffer;
+ unsigned long m_bodySize { 0 };
+ unsigned long m_bodyDataSent { 0 };
+ SoupSession* soupSession();
+ int m_redirectCount { 0 };
+ size_t m_previousPosition { 0 };
+ bool m_useAuthenticationManager { true };
+ struct {
+ Credential credential;
+ ProtectionSpace protectionSpace;
+ } m_credentialDataToSaveInPersistentStore;
+#endif
+
+#if PLATFORM(COCOA)
+ // We need to keep a reference to the original challenge to be able to cancel it.
+ // It is almost identical to m_currentWebChallenge.nsURLAuthenticationChallenge(), but has a different sender.
+ NSURLAuthenticationChallenge *m_currentMacChallenge { nil };
+#endif
+
+ AuthenticationChallenge m_currentWebChallenge;
+ ResourceHandle::FailureType m_scheduledFailureType { ResourceHandle::NoFailure };
+ Timer m_failureTimer;
+};
} // namespace WebCore
-
-#endif // ResourceHandleInternal_h
diff --git a/Source/WebCore/platform/network/ResourceHandleTypes.h b/Source/WebCore/platform/network/ResourceHandleTypes.h
index 0c31f92e6..870e7957d 100644
--- a/Source/WebCore/platform/network/ResourceHandleTypes.h
+++ b/Source/WebCore/platform/network/ResourceHandleTypes.h
@@ -33,12 +33,6 @@ enum StoredCredentials {
DoNotAllowStoredCredentials
};
-enum ClientCredentialPolicy {
- AskClientForAllCredentials,
- DoNotAskClientForCrossOriginCredentials,
- DoNotAskClientForAnyCredentials
-};
-
} // namespace WebCore
#endif // ResourceHandleTypes_h
diff --git a/Source/WebCore/platform/network/ResourceLoadPriority.h b/Source/WebCore/platform/network/ResourceLoadPriority.h
index 5a7104f97..86d74a0c8 100644
--- a/Source/WebCore/platform/network/ResourceLoadPriority.h
+++ b/Source/WebCore/platform/network/ResourceLoadPriority.h
@@ -28,18 +28,30 @@
namespace WebCore {
-enum ResourceLoadPriority {
- // The unresolved priority is here for the convenience of the clients. It should not be passed to the ResourceLoadScheduler.
- ResourceLoadPriorityUnresolved = -1,
- ResourceLoadPriorityVeryLow = 0,
- ResourceLoadPriorityLow,
- ResourceLoadPriorityMedium,
- ResourceLoadPriorityHigh,
- ResourceLoadPriorityVeryHigh,
- ResourceLoadPriorityLowest = ResourceLoadPriorityVeryLow,
- ResourceLoadPriorityHighest = ResourceLoadPriorityVeryHigh,
+enum class ResourceLoadPriority {
+ VeryLow,
+ Low,
+ Medium,
+ High,
+ VeryHigh,
+ Lowest = VeryLow,
+ Highest = VeryHigh,
};
+static const unsigned resourceLoadPriorityCount { static_cast<unsigned>(ResourceLoadPriority::Highest) + 1 };
+
+inline ResourceLoadPriority& operator++(ResourceLoadPriority& priority)
+{
+ ASSERT(priority != ResourceLoadPriority::Highest);
+ return priority = static_cast<ResourceLoadPriority>(static_cast<int>(priority) + 1);
+}
+
+inline ResourceLoadPriority& operator--(ResourceLoadPriority& priority)
+{
+ ASSERT(priority != ResourceLoadPriority::Lowest);
+ return priority = static_cast<ResourceLoadPriority>(static_cast<int>(priority) - 1);
+}
+
}
#endif
diff --git a/Source/WebCore/platform/network/ResourceLoadTiming.h b/Source/WebCore/platform/network/ResourceLoadTiming.h
deleted file mode 100644
index 2a395ef7c..000000000
--- a/Source/WebCore/platform/network/ResourceLoadTiming.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ResourceLoadTiming_h
-#define ResourceLoadTiming_h
-
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
-
-namespace WebCore {
-
-class DocumentLoadTiming;
-
-class ResourceLoadTiming : public RefCounted<ResourceLoadTiming> {
-public:
- static PassRefPtr<ResourceLoadTiming> create()
- {
- return adoptRef(new ResourceLoadTiming);
- }
-
- PassRefPtr<ResourceLoadTiming> deepCopy()
- {
- RefPtr<ResourceLoadTiming> timing = create();
- timing->requestTime = requestTime;
- timing->proxyStart = proxyStart;
- timing->proxyEnd = proxyEnd;
- timing->dnsStart = dnsStart;
- timing->dnsEnd = dnsEnd;
- timing->connectStart = connectStart;
- timing->connectEnd = connectEnd;
- timing->sendStart = sendStart;
- timing->sendEnd = sendEnd;
- timing->receiveHeadersEnd = receiveHeadersEnd;
- timing->sslStart = sslStart;
- timing->sslEnd = sslEnd;
- return timing.release();
- }
-
- bool operator==(const ResourceLoadTiming& other) const
- {
- return requestTime == other.requestTime
- && proxyStart == other.proxyStart
- && proxyEnd == other.proxyEnd
- && dnsStart == other.dnsStart
- && dnsEnd == other.dnsEnd
- && connectStart == other.connectStart
- && connectEnd == other.connectEnd
- && sendStart == other.sendStart
- && sendEnd == other.sendEnd
- && receiveHeadersEnd == other.receiveHeadersEnd
- && sslStart == other.sslStart
- && sslEnd == other.sslEnd;
- }
-
- bool operator!=(const ResourceLoadTiming& other) const
- {
- return !(*this == other);
- }
-
- // We want to present a unified timeline to Javascript. Using walltime is problematic, because the clock may skew while resources
- // load. To prevent that skew, we record a single reference walltime when root document navigation begins. All other times are
- // recorded using monotonicallyIncreasingTime(). When a time needs to be presented to Javascript, we build a pseudo-walltime
- // using the following equation:
- // pseudo time = document wall reference + (resource request time - document monotonic reference) + deltaMilliseconds / 1000.0.
- double convertResourceLoadTimeToMonotonicTime(int deltaMilliseconds) const;
-
- double requestTime; // monotonicallyIncreasingTime() when the port started handling this request.
- int proxyStart; // The rest of these are millisecond deltas, using monotonicallyIncreasingTime(), from requestTime.
- int proxyEnd;
- int dnsStart;
- int dnsEnd;
- int connectStart;
- int connectEnd;
- int sendStart;
- int sendEnd;
- int receiveHeadersEnd;
- int sslStart;
- int sslEnd;
-
-private:
- ResourceLoadTiming()
- : requestTime(0)
- , proxyStart(-1)
- , proxyEnd(-1)
- , dnsStart(-1)
- , dnsEnd(-1)
- , connectStart(-1)
- , connectEnd(-1)
- , sendStart(0)
- , sendEnd(0)
- , receiveHeadersEnd(0)
- , sslStart(-1)
- , sslEnd(-1)
- {
- }
-};
-
-}
-
-#endif
diff --git a/Source/WebCore/platform/network/ResourceRequestBase.cpp b/Source/WebCore/platform/network/ResourceRequestBase.cpp
index a956bb8c0..6914671c2 100644
--- a/Source/WebCore/platform/network/ResourceRequestBase.cpp
+++ b/Source/WebCore/platform/network/ResourceRequestBase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2003, 2006 Apple Inc. All rights reserved.
* Copyright (C) 2009, 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -26,11 +26,14 @@
#include "config.h"
#include "ResourceRequestBase.h"
+#include "HTTPHeaderNames.h"
+#include "PublicSuffix.h"
#include "ResourceRequest.h"
+#include <wtf/PointerComparison.h>
namespace WebCore {
-#if !USE(SOUP) && (!PLATFORM(MAC) || USE(CFNETWORK))
+#if !USE(SOUP) && (!PLATFORM(MAC) || USE(CFURLCONNECTION))
double ResourceRequestBase::s_defaultTimeoutInterval = INT_MAX;
#else
// Will use NSURLRequest default timeout unless set to a non-zero value with setDefaultTimeoutInterval().
@@ -47,58 +50,44 @@ inline const ResourceRequest& ResourceRequestBase::asResourceRequest() const
return *static_cast<const ResourceRequest*>(this);
}
-PassOwnPtr<ResourceRequest> ResourceRequestBase::adopt(PassOwnPtr<CrossThreadResourceRequestData> data)
+ResourceRequest ResourceRequestBase::isolatedCopy() const
{
- OwnPtr<ResourceRequest> request = adoptPtr(new ResourceRequest());
- request->setURL(data->m_url);
- request->setCachePolicy(data->m_cachePolicy);
- request->setTimeoutInterval(data->m_timeoutInterval);
- request->setFirstPartyForCookies(data->m_firstPartyForCookies);
- request->setHTTPMethod(data->m_httpMethod);
- request->setPriority(data->m_priority);
+ ResourceRequest request;
+ request.setAsIsolatedCopy(asResourceRequest());
+ return request;
+}
+
+void ResourceRequestBase::setAsIsolatedCopy(const ResourceRequest& other)
+{
+ setURL(other.url().isolatedCopy());
+ setCachePolicy(other.cachePolicy());
+ setTimeoutInterval(other.timeoutInterval());
+ setFirstPartyForCookies(other.firstPartyForCookies().isolatedCopy());
+ setHTTPMethod(other.httpMethod().isolatedCopy());
+ setPriority(other.priority());
+ setRequester(other.requester());
+ setInitiatorIdentifier(other.initiatorIdentifier().isolatedCopy());
+ setCachePartition(other.cachePartition());
- request->updateResourceRequest();
- request->m_httpHeaderFields.adopt(data->m_httpHeaders.release());
+ updateResourceRequest();
+ m_httpHeaderFields = other.httpHeaderFields().isolatedCopy();
- size_t encodingCount = data->m_responseContentDispositionEncodingFallbackArray.size();
+ size_t encodingCount = other.m_responseContentDispositionEncodingFallbackArray.size();
if (encodingCount > 0) {
- String encoding1 = data->m_responseContentDispositionEncodingFallbackArray[0];
+ String encoding1 = other.m_responseContentDispositionEncodingFallbackArray[0].isolatedCopy();
String encoding2;
String encoding3;
if (encodingCount > 1) {
- encoding2 = data->m_responseContentDispositionEncodingFallbackArray[1];
+ encoding2 = other.m_responseContentDispositionEncodingFallbackArray[1].isolatedCopy();
if (encodingCount > 2)
- encoding3 = data->m_responseContentDispositionEncodingFallbackArray[2];
+ encoding3 = other.m_responseContentDispositionEncodingFallbackArray[2].isolatedCopy();
}
ASSERT(encodingCount <= 3);
- request->setResponseContentDispositionEncodingFallbackArray(encoding1, encoding2, encoding3);
+ setResponseContentDispositionEncodingFallbackArray(encoding1, encoding2, encoding3);
}
- request->setHTTPBody(data->m_httpBody);
- request->setAllowCookies(data->m_allowCookies);
- request->doPlatformAdopt(data);
- return request.release();
-}
-
-PassOwnPtr<CrossThreadResourceRequestData> ResourceRequestBase::copyData() const
-{
- OwnPtr<CrossThreadResourceRequestData> data = adoptPtr(new CrossThreadResourceRequestData());
- data->m_url = url().copy();
- data->m_cachePolicy = cachePolicy();
- data->m_timeoutInterval = timeoutInterval();
- data->m_firstPartyForCookies = firstPartyForCookies().copy();
- data->m_httpMethod = httpMethod().isolatedCopy();
- data->m_httpHeaders = httpHeaderFields().copyData();
- data->m_priority = priority();
-
- 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].isolatedCopy());
- }
- if (m_httpBody)
- data->m_httpBody = m_httpBody->deepCopy();
- data->m_allowCookies = m_allowCookies;
- return asResourceRequest().doPlatformCopyData(data.release());
+ if (other.m_httpBody)
+ setHTTPBody(other.m_httpBody->isolatedCopy());
+ setAllowCookies(other.m_allowCookies);
}
bool ResourceRequestBase::isEmpty() const
@@ -148,7 +137,7 @@ ResourceRequestCachePolicy ResourceRequestBase::cachePolicy() const
{
updateResourceRequest();
- return m_cachePolicy;
+ return m_cachePolicy;
}
void ResourceRequestBase::setCachePolicy(ResourceRequestCachePolicy cachePolicy)
@@ -230,94 +219,171 @@ const HTTPHeaderMap& ResourceRequestBase::httpHeaderFields() const
return m_httpHeaderFields;
}
-String ResourceRequestBase::httpHeaderField(const AtomicString& name) const
+String ResourceRequestBase::httpHeaderField(const String& name) const
{
updateResourceRequest();
return m_httpHeaderFields.get(name);
}
-String ResourceRequestBase::httpHeaderField(const char* name) const
+String ResourceRequestBase::httpHeaderField(HTTPHeaderName name) const
{
updateResourceRequest();
return m_httpHeaderFields.get(name);
}
-void ResourceRequestBase::setHTTPHeaderField(const AtomicString& name, const String& value)
+void ResourceRequestBase::setHTTPHeaderField(const String& name, const String& value)
{
- updateResourceRequest();
-
- m_httpHeaderFields.set(name, value);
+ updateResourceRequest();
+
+ m_httpHeaderFields.set(name, value);
if (url().protocolIsInHTTPFamily())
m_platformRequestUpdated = false;
}
-void ResourceRequestBase::setHTTPHeaderField(const char* name, const String& value)
+void ResourceRequestBase::setHTTPHeaderField(HTTPHeaderName name, const String& value)
{
- setHTTPHeaderField(AtomicString(name), value);
+ updateResourceRequest();
+
+ m_httpHeaderFields.set(name, value);
+
+ if (url().protocolIsInHTTPFamily())
+ m_platformRequestUpdated = false;
}
void ResourceRequestBase::clearHTTPAuthorization()
{
updateResourceRequest();
- HTTPHeaderMap::iterator iter = m_httpHeaderFields.find("Authorization");
- if (iter == m_httpHeaderFields.end())
+ if (!m_httpHeaderFields.remove(HTTPHeaderName::Authorization))
return;
- m_httpHeaderFields.remove(iter);
-
if (url().protocolIsInHTTPFamily())
m_platformRequestUpdated = false;
}
+String ResourceRequestBase::httpContentType() const
+{
+ return httpHeaderField(HTTPHeaderName::ContentType);
+}
+
+void ResourceRequestBase::setHTTPContentType(const String& httpContentType)
+{
+ setHTTPHeaderField(HTTPHeaderName::ContentType, httpContentType);
+}
+
void ResourceRequestBase::clearHTTPContentType()
{
updateResourceRequest();
- m_httpHeaderFields.remove("Content-Type");
+ m_httpHeaderFields.remove(HTTPHeaderName::ContentType);
if (url().protocolIsInHTTPFamily())
m_platformRequestUpdated = false;
}
+String ResourceRequestBase::httpReferrer() const
+{
+ return httpHeaderField(HTTPHeaderName::Referer);
+}
+
+bool ResourceRequestBase::hasHTTPReferrer() const
+{
+ return m_httpHeaderFields.contains(HTTPHeaderName::Referer);
+}
+
+void ResourceRequestBase::setHTTPReferrer(const String& httpReferrer)
+{
+ setHTTPHeaderField(HTTPHeaderName::Referer, httpReferrer);
+}
+
void ResourceRequestBase::clearHTTPReferrer()
{
updateResourceRequest();
- m_httpHeaderFields.remove("Referer");
+ m_httpHeaderFields.remove(HTTPHeaderName::Referer);
if (url().protocolIsInHTTPFamily())
m_platformRequestUpdated = false;
}
+String ResourceRequestBase::httpOrigin() const
+{
+ return httpHeaderField(HTTPHeaderName::Origin);
+}
+
+void ResourceRequestBase::setHTTPOrigin(const String& httpOrigin)
+{
+ setHTTPHeaderField(HTTPHeaderName::Origin, httpOrigin);
+}
+
+bool ResourceRequestBase::hasHTTPOrigin() const
+{
+ return m_httpHeaderFields.contains(HTTPHeaderName::Origin);
+}
+
void ResourceRequestBase::clearHTTPOrigin()
{
- updateResourceRequest();
+ updateResourceRequest();
- m_httpHeaderFields.remove("Origin");
+ m_httpHeaderFields.remove(HTTPHeaderName::Origin);
if (url().protocolIsInHTTPFamily())
m_platformRequestUpdated = false;
}
+bool ResourceRequestBase::hasHTTPHeader(HTTPHeaderName name) const
+{
+ return m_httpHeaderFields.contains(name);
+}
+
+String ResourceRequestBase::httpUserAgent() const
+{
+ return httpHeaderField(HTTPHeaderName::UserAgent);
+}
+
+void ResourceRequestBase::setHTTPUserAgent(const String& httpUserAgent)
+{
+ setHTTPHeaderField(HTTPHeaderName::UserAgent, httpUserAgent);
+}
+
void ResourceRequestBase::clearHTTPUserAgent()
{
updateResourceRequest();
- m_httpHeaderFields.remove("User-Agent");
+ m_httpHeaderFields.remove(HTTPHeaderName::UserAgent);
if (url().protocolIsInHTTPFamily())
m_platformRequestUpdated = false;
}
+String ResourceRequestBase::httpAccept() const
+{
+ return httpHeaderField(HTTPHeaderName::Accept);
+}
+
+void ResourceRequestBase::setHTTPAccept(const String& httpAccept)
+{
+ setHTTPHeaderField(HTTPHeaderName::Accept, httpAccept);
+}
+
void ResourceRequestBase::clearHTTPAccept()
{
updateResourceRequest();
- m_httpHeaderFields.remove("Accept");
+ m_httpHeaderFields.remove(HTTPHeaderName::Accept);
+
+ if (url().protocolIsInHTTPFamily())
+ m_platformRequestUpdated = false;
+}
+
+void ResourceRequestBase::clearHTTPAcceptEncoding()
+{
+ updateResourceRequest();
+
+ m_httpHeaderFields.remove(HTTPHeaderName::AcceptEncoding);
if (url().protocolIsInHTTPFamily())
m_platformRequestUpdated = false;
@@ -347,11 +413,11 @@ FormData* ResourceRequestBase::httpBody() const
return m_httpBody.get();
}
-void ResourceRequestBase::setHTTPBody(PassRefPtr<FormData> httpBody)
+void ResourceRequestBase::setHTTPBody(RefPtr<FormData>&& httpBody)
{
updateResourceRequest();
- m_httpBody = httpBody;
+ m_httpBody = WTFMove(httpBody);
m_resourceRequestBodyUpdated = true;
@@ -399,22 +465,50 @@ void ResourceRequestBase::setPriority(ResourceLoadPriority priority)
m_platformRequestUpdated = false;
}
-void ResourceRequestBase::addHTTPHeaderField(const AtomicString& name, const String& value)
+void ResourceRequestBase::addHTTPHeaderFieldIfNotPresent(HTTPHeaderName name, const String& value)
+{
+ updateResourceRequest();
+
+ if (!m_httpHeaderFields.addIfNotPresent(name, value))
+ return;
+
+ if (url().protocolIsInHTTPFamily())
+ m_platformRequestUpdated = false;
+}
+
+void ResourceRequestBase::addHTTPHeaderField(HTTPHeaderName name, const String& value)
+{
+ updateResourceRequest();
+
+ m_httpHeaderFields.add(name, value);
+
+ if (url().protocolIsInHTTPFamily())
+ m_platformRequestUpdated = false;
+}
+
+void ResourceRequestBase::addHTTPHeaderField(const String& name, const String& value)
{
updateResourceRequest();
- HTTPHeaderMap::AddResult result = m_httpHeaderFields.add(name, value);
- if (!result.isNewEntry)
- result.iterator->value = result.iterator->value + ',' + value;
+
+ m_httpHeaderFields.add(name, value);
if (url().protocolIsInHTTPFamily())
m_platformRequestUpdated = false;
}
-void ResourceRequestBase::addHTTPHeaderFields(const HTTPHeaderMap& headerFields)
+bool ResourceRequestBase::hasHTTPHeaderField(HTTPHeaderName headerName) const
+{
+ return m_httpHeaderFields.contains(headerName);
+}
+
+void ResourceRequestBase::setHTTPHeaderFields(HTTPHeaderMap headerFields)
{
- HTTPHeaderMap::const_iterator end = headerFields.end();
- for (HTTPHeaderMap::const_iterator it = headerFields.begin(); it != end; ++it)
- addHTTPHeaderField(it->key, it->value);
+ updateResourceRequest();
+
+ m_httpHeaderFields = WTFMove(headerFields);
+
+ if (url().protocolIsInHTTPFamily())
+ m_platformRequestUpdated = false;
}
bool equalIgnoringHeaderFields(const ResourceRequestBase& a, const ResourceRequestBase& b)
@@ -440,18 +534,10 @@ bool equalIgnoringHeaderFields(const ResourceRequestBase& a, const ResourceReque
if (a.priority() != b.priority())
return false;
- FormData* formDataA = a.httpBody();
- FormData* formDataB = b.httpBody();
-
- if (!formDataA)
- return !formDataB;
- if (!formDataB)
- return !formDataA;
-
- if (*formDataA != *formDataB)
+ if (a.requester() != b.requester())
return false;
-
- return true;
+
+ return arePointingToEqualData(a.httpBody(), b.httpBody());
}
bool ResourceRequestBase::compare(const ResourceRequest& a, const ResourceRequest& b)
@@ -465,22 +551,32 @@ bool ResourceRequestBase::compare(const ResourceRequest& a, const ResourceReques
return ResourceRequest::platformCompare(a, b);
}
+static const HTTPHeaderName conditionalHeaderNames[] = {
+ HTTPHeaderName::IfMatch,
+ HTTPHeaderName::IfModifiedSince,
+ HTTPHeaderName::IfNoneMatch,
+ HTTPHeaderName::IfRange,
+ HTTPHeaderName::IfUnmodifiedSince
+};
+
bool ResourceRequestBase::isConditional() const
{
- return (m_httpHeaderFields.contains("If-Match") ||
- m_httpHeaderFields.contains("If-Modified-Since") ||
- m_httpHeaderFields.contains("If-None-Match") ||
- m_httpHeaderFields.contains("If-Range") ||
- m_httpHeaderFields.contains("If-Unmodified-Since"));
+ updateResourceRequest();
+
+ for (auto headerName : conditionalHeaderNames) {
+ if (m_httpHeaderFields.contains(headerName))
+ return true;
+ }
+
+ return false;
}
void ResourceRequestBase::makeUnconditional()
{
- m_httpHeaderFields.remove("If-Match");
- m_httpHeaderFields.remove("If-Modified-Since");
- m_httpHeaderFields.remove("If-None-Match");
- m_httpHeaderFields.remove("If-Range");
- m_httpHeaderFields.remove("If-Unmodified-Since");
+ updateResourceRequest();
+
+ for (auto headerName : conditionalHeaderNames)
+ m_httpHeaderFields.remove(headerName);
}
double ResourceRequestBase::defaultTimeoutInterval()
@@ -523,7 +619,7 @@ void ResourceRequestBase::updateResourceRequest(HTTPBodyUpdatePolicy bodyPolicy)
}
}
-#if !PLATFORM(MAC) && !USE(CFNETWORK) && !USE(SOUP)
+#if !PLATFORM(COCOA) && !USE(CFURLCONNECTION) && !USE(SOUP)
unsigned initializeMaximumHTTPConnectionCountPerHost()
{
// This is used by the loader to control the number of issued parallel load requests.
@@ -544,4 +640,32 @@ bool ResourceRequestBase::defaultAllowCookies()
}
#endif
+void ResourceRequestBase::setCachePartition(const String& cachePartition)
+{
+#if ENABLE(CACHE_PARTITIONING)
+ ASSERT(!cachePartition.isNull());
+ ASSERT(cachePartition == partitionName(cachePartition));
+ m_cachePartition = cachePartition;
+#else
+ UNUSED_PARAM(cachePartition);
+#endif
+}
+
+String ResourceRequestBase::partitionName(const String& domain)
+{
+#if ENABLE(PUBLIC_SUFFIX_LIST)
+ if (domain.isNull())
+ return emptyString();
+ String highLevel = topPrivatelyControlledDomain(domain);
+ if (highLevel.isNull())
+ return emptyString();
+ return highLevel;
+#else
+#if ENABLE(CACHE_PARTITIONING)
+#error Cache partitioning requires PUBLIC_SUFFIX_LIST
+#endif
+ return emptyString();
+#endif
+}
+
}
diff --git a/Source/WebCore/platform/network/ResourceRequestBase.h b/Source/WebCore/platform/network/ResourceRequestBase.h
index ea66d6126..86415eaa5 100644
--- a/Source/WebCore/platform/network/ResourceRequestBase.h
+++ b/Source/WebCore/platform/network/ResourceRequestBase.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2003, 2006 Apple Inc. All rights reserved.
* Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
* Copyright (C) 2009, 2012 Google Inc. All rights reserved.
*
@@ -12,17 +12,17 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ResourceRequestBase_h
@@ -33,217 +33,309 @@
#include "URL.h"
#include "ResourceLoadPriority.h"
-#include <wtf/OwnPtr.h>
-
namespace WebCore {
- enum ResourceRequestCachePolicy {
- UseProtocolCachePolicy, // normal load
- ReloadIgnoringCacheData, // reload
- ReturnCacheDataElseLoad, // back/forward or encoding change - allow stale data
- ReturnCacheDataDontLoad // results of a post - allow stale data and only use cache
- };
-
- enum HTTPBodyUpdatePolicy {
- DoNotUpdateHTTPBody,
- UpdateHTTPBody
- };
-
- class ResourceRequest;
- struct CrossThreadResourceRequestData;
-
- // Do not use this type directly. Use ResourceRequest instead.
- class ResourceRequestBase {
- WTF_MAKE_FAST_ALLOCATED;
- public:
- static PassOwnPtr<ResourceRequest> adopt(PassOwnPtr<CrossThreadResourceRequestData>);
-
- // Gets a copy of the data suitable for passing to another thread.
- PassOwnPtr<CrossThreadResourceRequestData> copyData() const;
-
- bool isNull() const;
- bool isEmpty() const;
-
- const URL& url() const;
- void setURL(const URL& url);
-
- void removeCredentials();
-
- ResourceRequestCachePolicy cachePolicy() const;
- void setCachePolicy(ResourceRequestCachePolicy cachePolicy);
-
- double timeoutInterval() const; // May return 0 when using platform default.
- void setTimeoutInterval(double timeoutInterval);
-
- const URL& firstPartyForCookies() const;
- void setFirstPartyForCookies(const URL& firstPartyForCookies);
-
- const String& httpMethod() const;
- void setHTTPMethod(const String& httpMethod);
-
- const HTTPHeaderMap& httpHeaderFields() const;
- String httpHeaderField(const AtomicString& name) const;
- String httpHeaderField(const char* name) const;
- void setHTTPHeaderField(const AtomicString& name, const String& value);
- void setHTTPHeaderField(const char* name, const String& value);
- void addHTTPHeaderField(const AtomicString& name, const String& value);
- void addHTTPHeaderFields(const HTTPHeaderMap& headerFields);
-
- void clearHTTPAuthorization();
-
- String httpContentType() const { return httpHeaderField("Content-Type"); }
- void setHTTPContentType(const String& httpContentType) { setHTTPHeaderField("Content-Type", httpContentType); }
- void clearHTTPContentType();
-
- String httpReferrer() const { return httpHeaderField("Referer"); }
- void setHTTPReferrer(const String& httpReferrer) { setHTTPHeaderField("Referer", httpReferrer); }
- void clearHTTPReferrer();
-
- String httpOrigin() const { return httpHeaderField("Origin"); }
- void setHTTPOrigin(const String& httpOrigin) { setHTTPHeaderField("Origin", httpOrigin); }
- void clearHTTPOrigin();
-
- String httpUserAgent() const { return httpHeaderField("User-Agent"); }
- void setHTTPUserAgent(const String& httpUserAgent) { setHTTPHeaderField("User-Agent", httpUserAgent); }
- void clearHTTPUserAgent();
-
- String httpAccept() const { return httpHeaderField("Accept"); }
- void setHTTPAccept(const String& httpAccept) { setHTTPHeaderField("Accept", httpAccept); }
- void clearHTTPAccept();
-
- const Vector<String>& responseContentDispositionEncodingFallbackArray() const { return m_responseContentDispositionEncodingFallbackArray; }
- void setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2 = String(), const String& encoding3 = String());
-
- FormData* httpBody() const;
- void setHTTPBody(PassRefPtr<FormData> httpBody);
-
- bool allowCookies() const;
- void setAllowCookies(bool allowCookies);
-
- ResourceLoadPriority priority() const;
- void setPriority(ResourceLoadPriority);
-
- bool isConditional() const;
- void makeUnconditional();
-
- // 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; }
-
- // Whether the timing information should be collected for the request.
- bool reportLoadTiming() const { return m_reportLoadTiming; }
- void setReportLoadTiming(bool reportLoadTiming) { m_reportLoadTiming = reportLoadTiming; }
-
- // Whether actual headers being sent/received should be collected and reported for the request.
- bool reportRawHeaders() const { return m_reportRawHeaders; }
- void setReportRawHeaders(bool reportRawHeaders) { m_reportRawHeaders = reportRawHeaders; }
-
- static double defaultTimeoutInterval(); // May return 0 when using platform default.
- static void setDefaultTimeoutInterval(double);
+enum ResourceRequestCachePolicy {
+ UseProtocolCachePolicy, // normal load, equivalent to fetch "default" cache mode.
+ ReloadIgnoringCacheData, // reload, equivalent to fetch "reload"cache mode.
+ ReturnCacheDataElseLoad, // back/forward or encoding change - allow stale data, equivalent to fetch "force-cache" cache mode.
+ ReturnCacheDataDontLoad, // results of a post - allow stale data and only use cache, equivalent to fetch "only-if-cached" cache mode.
+ DoNotUseAnyCache, // Bypass the cache entirely, equivalent to fetch "no-store" cache mode.
+ RefreshAnyCacheData, // Serve cache data only if revalidated, equivalent to fetch "no-cache" mode.
+};
+
+enum HTTPBodyUpdatePolicy {
+ DoNotUpdateHTTPBody,
+ UpdateHTTPBody
+};
+
+class ResourceRequest;
+
+// Do not use this type directly. Use ResourceRequest instead.
+class ResourceRequestBase {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ ResourceRequest isolatedCopy() const;
+ WEBCORE_EXPORT void setAsIsolatedCopy(const ResourceRequest&);
+
+ WEBCORE_EXPORT bool isNull() const;
+ WEBCORE_EXPORT bool isEmpty() const;
+
+ WEBCORE_EXPORT const URL& url() const;
+ WEBCORE_EXPORT void setURL(const URL& url);
+
+ WEBCORE_EXPORT void removeCredentials();
+
+ WEBCORE_EXPORT ResourceRequestCachePolicy cachePolicy() const;
+ WEBCORE_EXPORT void setCachePolicy(ResourceRequestCachePolicy cachePolicy);
+
+ double timeoutInterval() const; // May return 0 when using platform default.
+ void setTimeoutInterval(double timeoutInterval);
+
+ WEBCORE_EXPORT const URL& firstPartyForCookies() const;
+ WEBCORE_EXPORT void setFirstPartyForCookies(const URL&);
+
+ WEBCORE_EXPORT const String& httpMethod() const;
+ WEBCORE_EXPORT void setHTTPMethod(const String& httpMethod);
+
+ WEBCORE_EXPORT const HTTPHeaderMap& httpHeaderFields() const;
+ WEBCORE_EXPORT void setHTTPHeaderFields(HTTPHeaderMap);
+
+ WEBCORE_EXPORT String httpHeaderField(const String& name) const;
+ WEBCORE_EXPORT String httpHeaderField(HTTPHeaderName) const;
+ WEBCORE_EXPORT void setHTTPHeaderField(const String& name, const String& value);
+ WEBCORE_EXPORT void setHTTPHeaderField(HTTPHeaderName, const String& value);
+ void addHTTPHeaderField(HTTPHeaderName, const String& value);
+ void addHTTPHeaderField(const String& name, const String& value);
+ void addHTTPHeaderFieldIfNotPresent(HTTPHeaderName, const String&);
+
+ bool hasHTTPHeaderField(HTTPHeaderName) const;
+
+ // Instead of passing a string literal to any of these functions, just use a HTTPHeaderName instead.
+ template<size_t length> String httpHeaderField(const char (&)[length]) const = delete;
+ template<size_t length> void setHTTPHeaderField(const char (&)[length], const String&) = delete;
+ template<size_t length> void addHTTPHeaderField(const char (&)[length], const String&) = delete;
+
+ WEBCORE_EXPORT void clearHTTPAuthorization();
+
+ WEBCORE_EXPORT String httpContentType() const;
+ WEBCORE_EXPORT void setHTTPContentType(const String&);
+ void clearHTTPContentType();
+
+ bool hasHTTPHeader(HTTPHeaderName) const;
+
+ WEBCORE_EXPORT String httpReferrer() const;
+ bool hasHTTPReferrer() const;
+ WEBCORE_EXPORT void setHTTPReferrer(const String&);
+ WEBCORE_EXPORT void clearHTTPReferrer();
+
+ String httpOrigin() const;
+ bool hasHTTPOrigin() const;
+ void setHTTPOrigin(const String&);
+ WEBCORE_EXPORT void clearHTTPOrigin();
+
+ WEBCORE_EXPORT String httpUserAgent() const;
+ WEBCORE_EXPORT void setHTTPUserAgent(const String&);
+ void clearHTTPUserAgent();
+
+ String httpAccept() const;
+ void setHTTPAccept(const String&);
+ void clearHTTPAccept();
+
+ void clearHTTPAcceptEncoding();
+
+ const Vector<String>& responseContentDispositionEncodingFallbackArray() const { return m_responseContentDispositionEncodingFallbackArray; }
+ WEBCORE_EXPORT void setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2 = String(), const String& encoding3 = String());
+
+ WEBCORE_EXPORT FormData* httpBody() const;
+ WEBCORE_EXPORT void setHTTPBody(RefPtr<FormData>&&);
+
+ bool allowCookies() const;
+ void setAllowCookies(bool allowCookies);
+
+ WEBCORE_EXPORT ResourceLoadPriority priority() const;
+ WEBCORE_EXPORT void setPriority(ResourceLoadPriority);
+
+ WEBCORE_EXPORT static String partitionName(const String& domain);
+ const String& cachePartition() const { return m_cachePartition; }
+ WEBCORE_EXPORT void setCachePartition(const String&);
+ void setDomainForCachePartition(const String& domain) { setCachePartition(partitionName(domain)); }
+
+ WEBCORE_EXPORT bool isConditional() const;
+ WEBCORE_EXPORT void makeUnconditional();
+
+ // 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; }
+
+ // Whether the timing information should be collected for the request.
+ bool reportLoadTiming() const { return m_reportLoadTiming; }
+ void setReportLoadTiming(bool reportLoadTiming) { m_reportLoadTiming = reportLoadTiming; }
+
+ // Whether actual headers being sent/received should be collected and reported for the request.
+ bool reportRawHeaders() const { return m_reportRawHeaders; }
+ void setReportRawHeaders(bool reportRawHeaders) { m_reportRawHeaders = reportRawHeaders; }
+
+ // Whether this request should be hidden from the Inspector.
+ bool hiddenFromInspector() const { return m_hiddenFromInspector; }
+ void setHiddenFromInspector(bool hiddenFromInspector) { m_hiddenFromInspector = hiddenFromInspector; }
+
+ // Whether this request should impact request counting and delay window.onload.
+ bool ignoreForRequestCount() const { return m_ignoreForRequestCount; }
+ void setIgnoreForRequestCount(bool ignoreForRequestCount) { m_ignoreForRequestCount = ignoreForRequestCount; }
+
+ enum class Requester { Unspecified, Main, XHR, Fetch, Media };
+ Requester requester() const { return m_requester; }
+ void setRequester(Requester requester) { m_requester = requester; }
+
+ // Who initiated the request so the Inspector can associate it with a context. E.g. a Web Worker.
+ String initiatorIdentifier() const { return m_initiatorIdentifier; }
+ void setInitiatorIdentifier(const String& identifier) { m_initiatorIdentifier = identifier; }
+
+#if !PLATFORM(COCOA)
+ bool encodingRequiresPlatformData() const { return true; }
+#endif
+ template<class Encoder> void encodeWithoutPlatformData(Encoder&) const;
+ template<class Decoder> bool decodeWithoutPlatformData(Decoder&);
+
+ WEBCORE_EXPORT static double defaultTimeoutInterval(); // May return 0 when using platform default.
+ WEBCORE_EXPORT static void setDefaultTimeoutInterval(double);
#if PLATFORM(IOS)
- static bool defaultAllowCookies();
- static void setDefaultAllowCookies(bool);
+ WEBCORE_EXPORT static bool defaultAllowCookies();
+ WEBCORE_EXPORT static void setDefaultAllowCookies(bool);
#endif
- static bool compare(const ResourceRequest&, const ResourceRequest&);
-
- protected:
- // Used when ResourceRequest is initialized from a platform representation of the request
- ResourceRequestBase()
- : m_resourceRequestUpdated(false)
- , m_platformRequestUpdated(true)
- , m_resourceRequestBodyUpdated(false)
- , m_platformRequestBodyUpdated(true)
- , m_reportUploadProgress(false)
- , m_reportLoadTiming(false)
- , m_reportRawHeaders(false)
- , m_priority(ResourceLoadPriorityLow)
- {
- }
-
- ResourceRequestBase(const URL& url, ResourceRequestCachePolicy policy)
- : m_url(url)
- , m_timeoutInterval(s_defaultTimeoutInterval)
- , m_httpMethod(ASCIILiteral("GET"))
- , m_cachePolicy(policy)
+ static bool compare(const ResourceRequest&, const ResourceRequest&);
+
+protected:
+ // Used when ResourceRequest is initialized from a platform representation of the request
+ ResourceRequestBase()
+ : m_platformRequestUpdated(true)
+ , m_platformRequestBodyUpdated(true)
+ {
+ }
+
+ ResourceRequestBase(const URL& url, ResourceRequestCachePolicy policy)
+ : m_url(url)
+ , m_timeoutInterval(s_defaultTimeoutInterval)
+ , m_httpMethod(ASCIILiteral("GET"))
+ , m_cachePolicy(policy)
#if !PLATFORM(IOS)
- , m_allowCookies(true)
+ , m_allowCookies(true)
#else
- , m_allowCookies(ResourceRequestBase::defaultAllowCookies())
+ , m_allowCookies(ResourceRequestBase::defaultAllowCookies())
#endif
- , m_resourceRequestUpdated(true)
- , m_platformRequestUpdated(false)
- , m_resourceRequestBodyUpdated(true)
- , m_platformRequestBodyUpdated(false)
- , m_reportUploadProgress(false)
- , m_reportLoadTiming(false)
- , m_reportRawHeaders(false)
- , m_priority(ResourceLoadPriorityLow)
- {
- }
-
- void updatePlatformRequest(HTTPBodyUpdatePolicy = DoNotUpdateHTTPBody) const;
- void updateResourceRequest(HTTPBodyUpdatePolicy = DoNotUpdateHTTPBody) const;
-
- // The ResourceRequest subclass may "shadow" this method to compare platform specific fields
- static bool platformCompare(const ResourceRequest&, const ResourceRequest&) { return true; }
-
- URL m_url;
- double m_timeoutInterval; // 0 is a magic value for platform default on platforms that have one.
- URL m_firstPartyForCookies;
- String m_httpMethod;
- HTTPHeaderMap m_httpHeaderFields;
- Vector<String> m_responseContentDispositionEncodingFallbackArray;
- RefPtr<FormData> m_httpBody;
- ResourceRequestCachePolicy m_cachePolicy : 3;
- bool m_allowCookies : 1;
- mutable bool m_resourceRequestUpdated : 1;
- mutable bool m_platformRequestUpdated : 1;
- mutable bool m_resourceRequestBodyUpdated : 1;
- mutable bool m_platformRequestBodyUpdated : 1;
- bool m_reportUploadProgress : 1;
- bool m_reportLoadTiming : 1;
- bool m_reportRawHeaders : 1;
- ResourceLoadPriority m_priority : 4;
-
- private:
- const ResourceRequest& asResourceRequest() const;
-
- static double s_defaultTimeoutInterval;
+ , m_resourceRequestUpdated(true)
+ , m_resourceRequestBodyUpdated(true)
+ {
+ }
+
+ void updatePlatformRequest(HTTPBodyUpdatePolicy = DoNotUpdateHTTPBody) const;
+ void updateResourceRequest(HTTPBodyUpdatePolicy = DoNotUpdateHTTPBody) const;
+
+ template<class Encoder> void encodeBase(Encoder&) const;
+ template<class Decoder> bool decodeBase(Decoder&);
+
+ // The ResourceRequest subclass may "shadow" this method to compare platform specific fields
+ static bool platformCompare(const ResourceRequest&, const ResourceRequest&) { return true; }
+
+ URL m_url;
+ double m_timeoutInterval; // 0 is a magic value for platform default on platforms that have one.
+ URL m_firstPartyForCookies;
+ String m_httpMethod;
+ HTTPHeaderMap m_httpHeaderFields;
+ Vector<String> m_responseContentDispositionEncodingFallbackArray;
+ RefPtr<FormData> m_httpBody;
+ ResourceRequestCachePolicy m_cachePolicy { UseProtocolCachePolicy };
+ bool m_allowCookies { false };
+ mutable bool m_resourceRequestUpdated { false };
+ mutable bool m_platformRequestUpdated { false };
+ mutable bool m_resourceRequestBodyUpdated { false };
+ mutable bool m_platformRequestBodyUpdated { false };
+ bool m_reportUploadProgress { false };
+ bool m_reportLoadTiming { false };
+ bool m_reportRawHeaders { false };
+ bool m_hiddenFromInspector { false };
+ bool m_ignoreForRequestCount { false };
+ ResourceLoadPriority m_priority { ResourceLoadPriority::Low };
+ Requester m_requester { Requester::Unspecified };
+ String m_initiatorIdentifier;
+ String m_cachePartition { emptyString() };
+
+private:
+ const ResourceRequest& asResourceRequest() const;
+
+ WEBCORE_EXPORT static double s_defaultTimeoutInterval;
#if PLATFORM(IOS)
- static bool s_defaultAllowCookies;
+ static bool s_defaultAllowCookies;
#endif
- };
-
- bool equalIgnoringHeaderFields(const ResourceRequestBase&, const ResourceRequestBase&);
-
- inline bool operator==(const ResourceRequest& a, const ResourceRequest& b) { return ResourceRequestBase::compare(a, b); }
- inline bool operator!=(ResourceRequest& a, const ResourceRequest& b) { return !(a == b); }
-
- struct CrossThreadResourceRequestDataBase {
- WTF_MAKE_NONCOPYABLE(CrossThreadResourceRequestDataBase); WTF_MAKE_FAST_ALLOCATED;
- public:
- CrossThreadResourceRequestDataBase() { }
- URL m_url;
-
- ResourceRequestCachePolicy m_cachePolicy;
- double m_timeoutInterval;
- URL m_firstPartyForCookies;
-
- String m_httpMethod;
- OwnPtr<CrossThreadHTTPHeaderMapData> m_httpHeaders;
- Vector<String> m_responseContentDispositionEncodingFallbackArray;
- RefPtr<FormData> m_httpBody;
- bool m_allowCookies;
- ResourceLoadPriority m_priority;
- };
-
- unsigned initializeMaximumHTTPConnectionCountPerHost();
+};
+
+bool equalIgnoringHeaderFields(const ResourceRequestBase&, const ResourceRequestBase&);
+
+inline bool operator==(const ResourceRequest& a, const ResourceRequest& b) { return ResourceRequestBase::compare(a, b); }
+inline bool operator!=(ResourceRequest& a, const ResourceRequest& b) { return !(a == b); }
+
+WEBCORE_EXPORT unsigned initializeMaximumHTTPConnectionCountPerHost();
#if PLATFORM(IOS)
- void initializeHTTPConnectionSettingsOnStartup();
+WEBCORE_EXPORT void initializeHTTPConnectionSettingsOnStartup();
#endif
+
+template<class Encoder>
+ALWAYS_INLINE void ResourceRequestBase::encodeBase(Encoder& encoder) const
+{
+ encoder << m_url;
+ encoder << m_timeoutInterval;
+ encoder << m_firstPartyForCookies.string();
+ encoder << m_httpMethod;
+ encoder << m_httpHeaderFields;
+ encoder << m_responseContentDispositionEncodingFallbackArray;
+ encoder.encodeEnum(m_cachePolicy);
+ encoder << m_allowCookies;
+ encoder.encodeEnum(m_priority);
+ encoder.encodeEnum(m_requester);
+}
+
+template<class Decoder>
+ALWAYS_INLINE bool ResourceRequestBase::decodeBase(Decoder& decoder)
+{
+ if (!decoder.decode(m_url))
+ return false;
+
+ if (!decoder.decode(m_timeoutInterval))
+ return false;
+
+ String firstPartyForCookies;
+ if (!decoder.decode(firstPartyForCookies))
+ return false;
+ m_firstPartyForCookies = URL(ParsedURLString, firstPartyForCookies);
+
+ if (!decoder.decode(m_httpMethod))
+ return false;
+
+ if (!decoder.decode(m_httpHeaderFields))
+ return false;
+
+ if (!decoder.decode(m_responseContentDispositionEncodingFallbackArray))
+ return false;
+
+ ResourceRequestCachePolicy cachePolicy;
+ if (!decoder.decodeEnum(cachePolicy))
+ return false;
+ m_cachePolicy = cachePolicy;
+
+ bool allowCookies;
+ if (!decoder.decode(allowCookies))
+ return false;
+ m_allowCookies = allowCookies;
+
+ ResourceLoadPriority priority;
+ if (!decoder.decodeEnum(priority))
+ return false;
+ m_priority = priority;
+
+ if (!decoder.decodeEnum(m_requester))
+ return false;
+
+ return true;
+}
+
+template<class Encoder>
+void ResourceRequestBase::encodeWithoutPlatformData(Encoder& encoder) const
+{
+ ASSERT(!m_httpBody);
+ ASSERT(!m_platformRequestUpdated);
+ encodeBase(encoder);
+}
+
+template<class Decoder>
+bool ResourceRequestBase::decodeWithoutPlatformData(Decoder& decoder)
+{
+ return decodeBase(decoder);
+}
+
} // namespace WebCore
#endif // ResourceRequestBase_h
diff --git a/Source/WebCore/platform/network/ResourceResponseBase.cpp b/Source/WebCore/platform/network/ResourceResponseBase.cpp
index 5c057ebb4..fd76f6b34 100644
--- a/Source/WebCore/platform/network/ResourceResponseBase.cpp
+++ b/Source/WebCore/platform/network/ResourceResponseBase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2008, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -27,120 +27,125 @@
#include "config.h"
#include "ResourceResponseBase.h"
+#include "CacheValidation.h"
+#include "HTTPHeaderNames.h"
#include "HTTPParsers.h"
+#include "ParsedContentRange.h"
#include "ResourceResponse.h"
#include <wtf/CurrentTime.h>
#include <wtf/MathExtras.h>
#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringView.h>
namespace WebCore {
-static void parseCacheHeader(const String& header, Vector<std::pair<String, String>>& result);
-
-inline const ResourceResponse& ResourceResponseBase::asResourceResponse() const
+ResourceResponseBase::ResourceResponseBase()
+ : m_isNull(true)
+ , m_expectedContentLength(0)
+ , m_httpStatusCode(0)
{
- return *static_cast<const ResourceResponse*>(this);
}
-ResourceResponseBase::ResourceResponseBase()
- : m_expectedContentLength(0)
- , m_httpStatusCode(0)
- , m_connectionID(0)
- , m_cacheControlMaxAge(0)
- , m_age(0)
- , m_date(0)
- , m_expires(0)
- , m_lastModified(0)
- , m_wasCached(false)
- , m_connectionReused(false)
- , m_isNull(true)
- , m_haveParsedCacheControlHeader(false)
- , m_haveParsedAgeHeader(false)
- , m_haveParsedDateHeader(false)
- , m_haveParsedExpiresHeader(false)
- , m_haveParsedLastModifiedHeader(false)
- , m_cacheControlContainsNoCache(false)
- , m_cacheControlContainsNoStore(false)
- , m_cacheControlContainsMustRevalidate(false)
-{
-}
-
-ResourceResponseBase::ResourceResponseBase(const URL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename)
- : m_url(url)
+ResourceResponseBase::ResourceResponseBase(const URL& url, const String& mimeType, long long expectedLength, const String& textEncodingName)
+ : m_isNull(false)
+ , m_url(url)
, m_mimeType(mimeType)
, m_expectedContentLength(expectedLength)
, m_textEncodingName(textEncodingName)
- , m_suggestedFilename(filename)
+ , m_certificateInfo(CertificateInfo()) // Empty but valid for synthetic responses.
, m_httpStatusCode(0)
- , m_connectionID(0)
- , m_cacheControlMaxAge(0)
- , m_age(0)
- , m_date(0)
- , m_expires(0)
- , m_lastModified(0)
- , m_wasCached(false)
- , m_connectionReused(false)
- , m_isNull(false)
- , m_haveParsedCacheControlHeader(false)
- , m_haveParsedAgeHeader(false)
- , m_haveParsedDateHeader(false)
- , m_haveParsedExpiresHeader(false)
- , m_haveParsedLastModifiedHeader(false)
- , m_cacheControlContainsNoCache(false)
- , m_cacheControlContainsNoStore(false)
- , m_cacheControlContainsMustRevalidate(false)
-{
-}
-
-PassOwnPtr<ResourceResponse> ResourceResponseBase::adopt(PassOwnPtr<CrossThreadResourceResponseData> data)
-{
- OwnPtr<ResourceResponse> response = adoptPtr(new ResourceResponse);
- response->setURL(data->m_url);
- response->setMimeType(data->m_mimeType);
- response->setExpectedContentLength(data->m_expectedContentLength);
- response->setTextEncodingName(data->m_textEncodingName);
- response->setSuggestedFilename(data->m_suggestedFilename);
-
- response->setHTTPStatusCode(data->m_httpStatusCode);
- response->setHTTPStatusText(data->m_httpStatusText);
-
- response->lazyInit(CommonAndUncommonFields);
- response->m_httpHeaderFields.adopt(data->m_httpHeaders.release());
- response->setResourceLoadTiming(data->m_resourceLoadTiming.release());
- response->doPlatformAdopt(data);
- return response.release();
-}
-
-PassOwnPtr<CrossThreadResourceResponseData> ResourceResponseBase::copyData() const
-{
- OwnPtr<CrossThreadResourceResponseData> data = adoptPtr(new CrossThreadResourceResponseData);
- data->m_url = url().copy();
- data->m_mimeType = mimeType().isolatedCopy();
- data->m_expectedContentLength = expectedContentLength();
- data->m_textEncodingName = textEncodingName().isolatedCopy();
- data->m_suggestedFilename = suggestedFilename().isolatedCopy();
- data->m_httpStatusCode = httpStatusCode();
- data->m_httpStatusText = httpStatusText().isolatedCopy();
- data->m_httpHeaders = httpHeaderFields().copyData();
- if (m_resourceLoadTiming)
- data->m_resourceLoadTiming = m_resourceLoadTiming->deepCopy();
- return asResourceResponse().doPlatformCopyData(data.release());
+{
}
+ResourceResponseBase::CrossThreadData ResourceResponseBase::crossThreadData() const
+{
+ CrossThreadData data;
+
+ data.url = url().isolatedCopy();
+ data.mimeType = mimeType().isolatedCopy();
+ data.expectedContentLength = expectedContentLength();
+ data.textEncodingName = textEncodingName().isolatedCopy();
+
+ data.httpStatusCode = httpStatusCode();
+ data.httpStatusText = httpStatusText().isolatedCopy();
+ data.httpVersion = httpVersion().isolatedCopy();
+
+ data.httpHeaderFields = httpHeaderFields().isolatedCopy();
+ data.networkLoadTiming = m_networkLoadTiming.isolatedCopy();
+ data.type = m_type;
+ data.isRedirected = m_isRedirected;
+
+ return data;
+}
+
+ResourceResponse ResourceResponseBase::fromCrossThreadData(CrossThreadData&& data)
+{
+ ResourceResponse response;
+
+ response.setURL(data.url);
+ response.setMimeType(data.mimeType);
+ response.setExpectedContentLength(data.expectedContentLength);
+ response.setTextEncodingName(data.textEncodingName);
+
+ response.setHTTPStatusCode(data.httpStatusCode);
+ response.setHTTPStatusText(data.httpStatusText);
+ response.setHTTPVersion(data.httpVersion);
+
+ response.m_httpHeaderFields = WTFMove(data.httpHeaderFields);
+ response.m_networkLoadTiming = data.networkLoadTiming;
+ response.m_type = data.type;
+ response.m_isRedirected = data.isRedirected;
+
+ return response;
+}
+
+ResourceResponse ResourceResponseBase::filterResponse(const ResourceResponse& response, ResourceResponse::Tainting tainting)
+{
+ if (tainting == ResourceResponse::Tainting::Opaque) {
+ ResourceResponse opaqueResponse;
+ opaqueResponse.setType(ResourceResponse::Type::Opaque);
+ return opaqueResponse;
+ }
+
+ ResourceResponse filteredResponse = response;
+ // Let's initialize filteredResponse to remove some header fields.
+ filteredResponse.lazyInit(AllFields);
+
+ if (tainting == ResourceResponse::Tainting::Basic) {
+ filteredResponse.setType(ResourceResponse::Type::Basic);
+ filteredResponse.m_httpHeaderFields.remove(HTTPHeaderName::SetCookie);
+ filteredResponse.m_httpHeaderFields.remove(HTTPHeaderName::SetCookie2);
+ return filteredResponse;
+ }
+
+ ASSERT(tainting == ResourceResponse::Tainting::Cors);
+ filteredResponse.setType(ResourceResponse::Type::Cors);
+
+ HTTPHeaderSet accessControlExposeHeaderSet;
+ parseAccessControlExposeHeadersAllowList(response.httpHeaderField(HTTPHeaderName::AccessControlExposeHeaders), accessControlExposeHeaderSet);
+ filteredResponse.m_httpHeaderFields.uncommonHeaders().removeIf([&](auto& entry) {
+ return !isCrossOriginSafeHeader(entry.key, accessControlExposeHeaderSet);
+ });
+ filteredResponse.m_httpHeaderFields.commonHeaders().removeIf([&](auto& entry) {
+ return !isCrossOriginSafeHeader(entry.key, accessControlExposeHeaderSet);
+ });
+
+ return filteredResponse;
+}
+
+// FIXME: Name does not make it clear this is true for HTTPS!
bool ResourceResponseBase::isHTTP() const
{
lazyInit(CommonFieldsOnly);
- String protocol = m_url.protocol();
-
- return equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https");
+ return m_url.protocolIsInHTTPFamily();
}
const URL& ResourceResponseBase::url() const
{
lazyInit(CommonFieldsOnly);
- return m_url;
+ return m_url;
}
void ResourceResponseBase::setURL(const URL& url)
@@ -207,23 +212,22 @@ void ResourceResponseBase::setTextEncodingName(const String& encodingName)
// FIXME: Should invalidate or update platform response if present.
}
-// FIXME should compute this on the fly
-const String& ResourceResponseBase::suggestedFilename() const
+void ResourceResponseBase::includeCertificateInfo() const
{
- lazyInit(AllFields);
-
- return m_suggestedFilename;
+ if (m_certificateInfo)
+ return;
+ m_certificateInfo = static_cast<const ResourceResponse*>(this)->platformCertificateInfo();
}
-void ResourceResponseBase::setSuggestedFilename(const String& suggestedName)
+String ResourceResponseBase::suggestedFilename() const
{
- lazyInit(AllFields);
- m_isNull = false;
-
- // FIXME: Suggested file name is calculated based on other headers. There should not be a setter for it.
- m_suggestedFilename = suggestedName;
+ return static_cast<const ResourceResponse*>(this)->platformSuggestedFilename();
+}
- // FIXME: Should invalidate or update platform response if present.
+bool ResourceResponseBase::isSuccessful() const
+{
+ int code = httpStatusCode();
+ return code >= 200 && code < 300;
}
int ResourceResponseBase::httpStatusCode() const
@@ -244,21 +248,44 @@ void ResourceResponseBase::setHTTPStatusCode(int statusCode)
const String& ResourceResponseBase::httpStatusText() const
{
- lazyInit(CommonAndUncommonFields);
+ lazyInit(AllFields);
return m_httpStatusText;
}
void ResourceResponseBase::setHTTPStatusText(const String& statusText)
{
- lazyInit(CommonAndUncommonFields);
+ lazyInit(AllFields);
m_httpStatusText = statusText;
// FIXME: Should invalidate or update platform response if present.
}
-String ResourceResponseBase::httpHeaderField(const AtomicString& name) const
+const String& ResourceResponseBase::httpVersion() const
+{
+ lazyInit(AllFields);
+
+ return m_httpVersion;
+}
+
+void ResourceResponseBase::setHTTPVersion(const String& versionText)
+{
+ lazyInit(AllFields);
+
+ m_httpVersion = versionText;
+
+ // FIXME: Should invalidate or update platform response if present.
+}
+
+bool ResourceResponseBase::isHTTP09() const
+{
+ lazyInit(AllFields);
+
+ return m_httpVersion.startsWith("HTTP/0.9");
+}
+
+String ResourceResponseBase::httpHeaderField(const String& name) const
{
lazyInit(CommonFieldsOnly);
@@ -267,12 +294,12 @@ String ResourceResponseBase::httpHeaderField(const AtomicString& name) const
if (!value.isEmpty())
return value;
- lazyInit(CommonAndUncommonFields);
+ lazyInit(AllFields);
return m_httpHeaderFields.get(name);
}
-String ResourceResponseBase::httpHeaderField(const char* name) const
+String ResourceResponseBase::httpHeaderField(HTTPHeaderName name) const
{
lazyInit(CommonFieldsOnly);
@@ -281,57 +308,89 @@ String ResourceResponseBase::httpHeaderField(const char* name) const
if (!value.isEmpty())
return value;
- lazyInit(CommonAndUncommonFields);
+ lazyInit(AllFields);
return m_httpHeaderFields.get(name);
}
-void ResourceResponseBase::updateHeaderParsedState(const AtomicString& name)
+void ResourceResponseBase::updateHeaderParsedState(HTTPHeaderName name)
{
- DEFINE_STATIC_LOCAL(const AtomicString, ageHeader, ("age", AtomicString::ConstructFromLiteral));
- DEFINE_STATIC_LOCAL(const AtomicString, cacheControlHeader, ("cache-control", AtomicString::ConstructFromLiteral));
- DEFINE_STATIC_LOCAL(const AtomicString, dateHeader, ("date", AtomicString::ConstructFromLiteral));
- DEFINE_STATIC_LOCAL(const AtomicString, expiresHeader, ("expires", AtomicString::ConstructFromLiteral));
- DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, ("last-modified", AtomicString::ConstructFromLiteral));
- DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma", AtomicString::ConstructFromLiteral));
-
- if (equalIgnoringCase(name, ageHeader))
+ switch (name) {
+ case HTTPHeaderName::Age:
m_haveParsedAgeHeader = false;
- else if (equalIgnoringCase(name, cacheControlHeader) || equalIgnoringCase(name, pragmaHeader))
+ break;
+
+ case HTTPHeaderName::CacheControl:
+ case HTTPHeaderName::Pragma:
m_haveParsedCacheControlHeader = false;
- else if (equalIgnoringCase(name, dateHeader))
+ break;
+
+ case HTTPHeaderName::Date:
m_haveParsedDateHeader = false;
- else if (equalIgnoringCase(name, expiresHeader))
+ break;
+
+ case HTTPHeaderName::Expires:
m_haveParsedExpiresHeader = false;
- else if (equalIgnoringCase(name, lastModifiedHeader))
+ break;
+
+ case HTTPHeaderName::LastModified:
m_haveParsedLastModifiedHeader = false;
+ break;
+
+ case HTTPHeaderName::ContentRange:
+ m_haveParsedContentRangeHeader = false;
+ break;
+
+ default:
+ break;
+ }
}
-void ResourceResponseBase::setHTTPHeaderField(const AtomicString& name, const String& value)
+void ResourceResponseBase::setHTTPHeaderField(const String& name, const String& value)
{
- lazyInit(CommonAndUncommonFields);
+ lazyInit(AllFields);
- updateHeaderParsedState(name);
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName))
+ updateHeaderParsedState(headerName);
m_httpHeaderFields.set(name, value);
// FIXME: Should invalidate or update platform response if present.
}
-void ResourceResponseBase::addHTTPHeaderField(const AtomicString& name, const String& value)
+void ResourceResponseBase::setHTTPHeaderField(HTTPHeaderName name, const String& value)
{
- lazyInit(CommonAndUncommonFields);
+ lazyInit(AllFields);
updateHeaderParsedState(name);
- HTTPHeaderMap::AddResult result = m_httpHeaderFields.add(name, value);
- if (!result.isNewEntry)
- result.iterator->value.append(", " + value);
+ m_httpHeaderFields.set(name, value);
+
+ // FIXME: Should invalidate or update platform response if present.
+}
+
+void ResourceResponseBase::addHTTPHeaderField(HTTPHeaderName name, const String& value)
+{
+ lazyInit(AllFields);
+ updateHeaderParsedState(name);
+ m_httpHeaderFields.add(name, value);
+}
+
+void ResourceResponseBase::addHTTPHeaderField(const String& name, const String& value)
+{
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName))
+ addHTTPHeaderField(headerName, value);
+ else {
+ lazyInit(AllFields);
+ m_httpHeaderFields.add(name, value);
+ }
}
const HTTPHeaderMap& ResourceResponseBase::httpHeaderFields() const
{
- lazyInit(CommonAndUncommonFields);
+ lazyInit(AllFields);
return m_httpHeaderFields;
}
@@ -342,227 +401,175 @@ void ResourceResponseBase::parseCacheControlDirectives() const
lazyInit(CommonFieldsOnly);
+ m_cacheControlDirectives = WebCore::parseCacheControlDirectives(m_httpHeaderFields);
m_haveParsedCacheControlHeader = true;
-
- m_cacheControlContainsMustRevalidate = false;
- m_cacheControlContainsNoCache = false;
- m_cacheControlMaxAge = std::numeric_limits<double>::quiet_NaN();
-
- DEFINE_STATIC_LOCAL(const AtomicString, cacheControlString, ("cache-control", AtomicString::ConstructFromLiteral));
- DEFINE_STATIC_LOCAL(const AtomicString, noCacheDirective, ("no-cache", AtomicString::ConstructFromLiteral));
- DEFINE_STATIC_LOCAL(const AtomicString, noStoreDirective, ("no-store", AtomicString::ConstructFromLiteral));
- DEFINE_STATIC_LOCAL(const AtomicString, mustRevalidateDirective, ("must-revalidate", AtomicString::ConstructFromLiteral));
- DEFINE_STATIC_LOCAL(const AtomicString, maxAgeDirective, ("max-age", AtomicString::ConstructFromLiteral));
-
- String cacheControlValue = m_httpHeaderFields.get(cacheControlString);
- if (!cacheControlValue.isEmpty()) {
- Vector<std::pair<String, String>> directives;
- parseCacheHeader(cacheControlValue, directives);
-
- size_t directivesSize = directives.size();
- for (size_t i = 0; i < directivesSize; ++i) {
- // RFC2616 14.9.1: A no-cache directive with a value is only meaningful for proxy caches.
- // It should be ignored by a browser level cache.
- if (equalIgnoringCase(directives[i].first, noCacheDirective) && directives[i].second.isEmpty())
- m_cacheControlContainsNoCache = true;
- else if (equalIgnoringCase(directives[i].first, noStoreDirective))
- m_cacheControlContainsNoStore = true;
- else if (equalIgnoringCase(directives[i].first, mustRevalidateDirective))
- m_cacheControlContainsMustRevalidate = true;
- else if (equalIgnoringCase(directives[i].first, maxAgeDirective)) {
- if (!std::isnan(m_cacheControlMaxAge)) {
- // First max-age directive wins if there are multiple ones.
- continue;
- }
- bool ok;
- double maxAge = directives[i].second.toDouble(&ok);
- if (ok)
- m_cacheControlMaxAge = maxAge;
- }
- }
- }
-
- if (!m_cacheControlContainsNoCache) {
- // Handle Pragma: no-cache
- // This is deprecated and equivalent to Cache-control: no-cache
- // Don't bother tokenizing the value, it is not important
- DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma", AtomicString::ConstructFromLiteral));
- String pragmaValue = m_httpHeaderFields.get(pragmaHeader);
-
- m_cacheControlContainsNoCache = pragmaValue.lower().contains(noCacheDirective);
- }
}
bool ResourceResponseBase::cacheControlContainsNoCache() const
{
if (!m_haveParsedCacheControlHeader)
parseCacheControlDirectives();
- return m_cacheControlContainsNoCache;
+ return m_cacheControlDirectives.noCache;
}
bool ResourceResponseBase::cacheControlContainsNoStore() const
{
if (!m_haveParsedCacheControlHeader)
parseCacheControlDirectives();
- return m_cacheControlContainsNoStore;
+ return m_cacheControlDirectives.noStore;
}
bool ResourceResponseBase::cacheControlContainsMustRevalidate() const
{
if (!m_haveParsedCacheControlHeader)
parseCacheControlDirectives();
- return m_cacheControlContainsMustRevalidate;
+ return m_cacheControlDirectives.mustRevalidate;
+}
+
+bool ResourceResponseBase::cacheControlContainsImmutable() const
+{
+ if (!m_haveParsedCacheControlHeader)
+ parseCacheControlDirectives();
+ return m_cacheControlDirectives.immutable;
}
bool ResourceResponseBase::hasCacheValidatorFields() const
{
lazyInit(CommonFieldsOnly);
- DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, ("last-modified", AtomicString::ConstructFromLiteral));
- DEFINE_STATIC_LOCAL(const AtomicString, eTagHeader, ("etag", AtomicString::ConstructFromLiteral));
- return !m_httpHeaderFields.get(lastModifiedHeader).isEmpty() || !m_httpHeaderFields.get(eTagHeader).isEmpty();
+ return !m_httpHeaderFields.get(HTTPHeaderName::LastModified).isEmpty() || !m_httpHeaderFields.get(HTTPHeaderName::ETag).isEmpty();
}
-double ResourceResponseBase::cacheControlMaxAge() const
+std::optional<std::chrono::microseconds> ResourceResponseBase::cacheControlMaxAge() const
{
if (!m_haveParsedCacheControlHeader)
parseCacheControlDirectives();
- return m_cacheControlMaxAge;
+ return m_cacheControlDirectives.maxAge;
}
-static double parseDateValueInHeader(const HTTPHeaderMap& headers, const AtomicString& headerName)
+static std::optional<std::chrono::system_clock::time_point> parseDateValueInHeader(const HTTPHeaderMap& headers, HTTPHeaderName headerName)
{
String headerValue = headers.get(headerName);
if (headerValue.isEmpty())
- return std::numeric_limits<double>::quiet_NaN();
+ return { };
// This handles all date formats required by RFC2616:
// Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
// Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
// Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
- double dateInMilliseconds = parseDate(headerValue);
- if (!std::isfinite(dateInMilliseconds))
- return std::numeric_limits<double>::quiet_NaN();
- return dateInMilliseconds / 1000;
+ return parseHTTPDate(headerValue);
}
-double ResourceResponseBase::date() const
+std::optional<std::chrono::system_clock::time_point> ResourceResponseBase::date() const
{
lazyInit(CommonFieldsOnly);
if (!m_haveParsedDateHeader) {
- DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("date", AtomicString::ConstructFromLiteral));
- m_date = parseDateValueInHeader(m_httpHeaderFields, headerName);
+ m_date = parseDateValueInHeader(m_httpHeaderFields, HTTPHeaderName::Date);
m_haveParsedDateHeader = true;
}
return m_date;
}
-double ResourceResponseBase::age() const
+std::optional<std::chrono::microseconds> ResourceResponseBase::age() const
{
+ using namespace std::chrono;
+
lazyInit(CommonFieldsOnly);
if (!m_haveParsedAgeHeader) {
- DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("age", AtomicString::ConstructFromLiteral));
- String headerValue = m_httpHeaderFields.get(headerName);
+ String headerValue = m_httpHeaderFields.get(HTTPHeaderName::Age);
bool ok;
- m_age = headerValue.toDouble(&ok);
- if (!ok)
- m_age = std::numeric_limits<double>::quiet_NaN();
+ double ageDouble = headerValue.toDouble(&ok);
+ if (ok)
+ m_age = duration_cast<microseconds>(duration<double>(ageDouble));
m_haveParsedAgeHeader = true;
}
return m_age;
}
-double ResourceResponseBase::expires() const
+std::optional<std::chrono::system_clock::time_point> ResourceResponseBase::expires() const
{
lazyInit(CommonFieldsOnly);
if (!m_haveParsedExpiresHeader) {
- DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("expires", AtomicString::ConstructFromLiteral));
- m_expires = parseDateValueInHeader(m_httpHeaderFields, headerName);
+ m_expires = parseDateValueInHeader(m_httpHeaderFields, HTTPHeaderName::Expires);
m_haveParsedExpiresHeader = true;
}
return m_expires;
}
-double ResourceResponseBase::lastModified() const
+std::optional<std::chrono::system_clock::time_point> ResourceResponseBase::lastModified() const
{
lazyInit(CommonFieldsOnly);
if (!m_haveParsedLastModifiedHeader) {
- DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("last-modified", AtomicString::ConstructFromLiteral));
- m_lastModified = parseDateValueInHeader(m_httpHeaderFields, headerName);
+ m_lastModified = parseDateValueInHeader(m_httpHeaderFields, HTTPHeaderName::LastModified);
+#if PLATFORM(COCOA)
+ // CFNetwork converts malformed dates into Epoch so we need to treat Epoch as
+ // an invalid value (rdar://problem/22352838).
+ const std::chrono::system_clock::time_point epoch;
+ if (m_lastModified && m_lastModified.value() == epoch)
+ m_lastModified = std::nullopt;
+#endif
m_haveParsedLastModifiedHeader = true;
}
return m_lastModified;
}
-bool ResourceResponseBase::isAttachment() const
+static ParsedContentRange parseContentRangeInHeader(const HTTPHeaderMap& headers)
{
- lazyInit(CommonAndUncommonFields);
+ String contentRangeValue = headers.get(HTTPHeaderName::ContentRange);
+ if (contentRangeValue.isEmpty())
+ return ParsedContentRange();
- DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("content-disposition", AtomicString::ConstructFromLiteral));
- String value = m_httpHeaderFields.get(headerName);
- size_t loc = value.find(';');
- if (loc != notFound)
- value = value.left(loc);
- value = value.stripWhiteSpace();
- DEFINE_STATIC_LOCAL(const AtomicString, attachmentString, ("attachment", AtomicString::ConstructFromLiteral));
- return equalIgnoringCase(value, attachmentString);
+ return ParsedContentRange(contentRangeValue);
}
-
-bool ResourceResponseBase::wasCached() const
-{
- lazyInit(CommonAndUncommonFields);
- return m_wasCached;
-}
-
-void ResourceResponseBase::setWasCached(bool value)
+ParsedContentRange& ResourceResponseBase::contentRange() const
{
- m_wasCached = value;
-}
+ lazyInit(CommonFieldsOnly);
-bool ResourceResponseBase::connectionReused() const
-{
- lazyInit(CommonAndUncommonFields);
+ if (!m_haveParsedContentRangeHeader) {
+ m_contentRange = parseContentRangeInHeader(m_httpHeaderFields);
+ m_haveParsedContentRangeHeader = true;
+ }
- return m_connectionReused;
+ return m_contentRange;
}
-void ResourceResponseBase::setConnectionReused(bool connectionReused)
+bool ResourceResponseBase::isAttachment() const
{
- lazyInit(CommonAndUncommonFields);
+ lazyInit(AllFields);
- m_connectionReused = connectionReused;
+ auto value = m_httpHeaderFields.get(HTTPHeaderName::ContentDisposition);
+ return equalLettersIgnoringASCIICase(value.left(value.find(';')).stripWhiteSpace(), "attachment");
}
-unsigned ResourceResponseBase::connectionID() const
+bool ResourceResponseBase::isAttachmentWithFilename() const
{
- lazyInit(CommonAndUncommonFields);
+ lazyInit(AllFields);
- return m_connectionID;
-}
+ String contentDisposition = m_httpHeaderFields.get(HTTPHeaderName::ContentDisposition);
+ if (contentDisposition.isNull())
+ return false;
-void ResourceResponseBase::setConnectionID(unsigned connectionID)
-{
- lazyInit(CommonAndUncommonFields);
+ if (!equalLettersIgnoringASCIICase(contentDisposition.left(contentDisposition.find(';')).stripWhiteSpace(), "attachment"))
+ return false;
- m_connectionID = connectionID;
+ String filename = filenameFromHTTPContentDisposition(contentDisposition);
+ return !filename.isNull();
}
-ResourceLoadTiming* ResourceResponseBase::resourceLoadTiming() const
+ResourceResponseBase::Source ResourceResponseBase::source() const
{
- lazyInit(CommonAndUncommonFields);
+ lazyInit(AllFields);
- return m_resourceLoadTiming.get();
+ return m_source;
}
-void ResourceResponseBase::setResourceLoadTiming(PassRefPtr<ResourceLoadTiming> resourceLoadTiming)
+void ResourceResponseBase::setSource(Source source)
{
- lazyInit(CommonAndUncommonFields);
-
- m_resourceLoadTiming = resourceLoadTiming;
+ m_source = source;
}
void ResourceResponseBase::lazyInit(InitLevel initLevel) const
@@ -590,106 +597,9 @@ bool ResourceResponseBase::compare(const ResourceResponse& a, const ResourceResp
return false;
if (a.httpHeaderFields() != b.httpHeaderFields())
return false;
- if (a.resourceLoadTiming() && b.resourceLoadTiming() && *a.resourceLoadTiming() == *b.resourceLoadTiming())
- return ResourceResponse::platformCompare(a, b);
- if (a.resourceLoadTiming() != b.resourceLoadTiming())
+ if (a.networkLoadTiming() != b.networkLoadTiming())
return false;
return ResourceResponse::platformCompare(a, b);
}
-static bool isCacheHeaderSeparator(UChar c)
-{
- // See RFC 2616, Section 2.2
- switch (c) {
- case '(':
- case ')':
- case '<':
- case '>':
- case '@':
- case ',':
- case ';':
- case ':':
- case '\\':
- case '"':
- case '/':
- case '[':
- case ']':
- case '?':
- case '=':
- case '{':
- case '}':
- case ' ':
- case '\t':
- return true;
- default:
- return false;
- }
-}
-
-static bool isControlCharacter(UChar c)
-{
- return c < ' ' || c == 127;
-}
-
-static inline String trimToNextSeparator(const String& str)
-{
- return str.substring(0, str.find(isCacheHeaderSeparator));
-}
-
-static void parseCacheHeader(const String& header, Vector<std::pair<String, String>>& result)
-{
- const String safeHeader = header.removeCharacters(isControlCharacter);
- unsigned max = safeHeader.length();
- for (unsigned pos = 0; pos < max; /* pos incremented in loop */) {
- size_t nextCommaPosition = safeHeader.find(',', pos);
- size_t nextEqualSignPosition = safeHeader.find('=', pos);
- if (nextEqualSignPosition != notFound && (nextEqualSignPosition < nextCommaPosition || nextCommaPosition == notFound)) {
- // Get directive name, parse right hand side of equal sign, then add to map
- String directive = trimToNextSeparator(safeHeader.substring(pos, nextEqualSignPosition - pos).stripWhiteSpace());
- pos += nextEqualSignPosition - pos + 1;
-
- String value = safeHeader.substring(pos, max - pos).stripWhiteSpace();
- if (value[0] == '"') {
- // The value is a quoted string
- size_t nextDoubleQuotePosition = value.find('"', 1);
- if (nextDoubleQuotePosition != notFound) {
- // Store the value as a quoted string without quotes
- result.append(std::pair<String, String>(directive, value.substring(1, nextDoubleQuotePosition - 1).stripWhiteSpace()));
- pos += (safeHeader.find('"', pos) - pos) + nextDoubleQuotePosition + 1;
- // Move past next comma, if there is one
- size_t nextCommaPosition2 = safeHeader.find(',', pos);
- if (nextCommaPosition2 != notFound)
- pos += nextCommaPosition2 - pos + 1;
- else
- return; // Parse error if there is anything left with no comma
- } else {
- // Parse error; just use the rest as the value
- result.append(std::pair<String, String>(directive, trimToNextSeparator(value.substring(1, value.length() - 1).stripWhiteSpace())));
- return;
- }
- } else {
- // The value is a token until the next comma
- size_t nextCommaPosition2 = value.find(',');
- if (nextCommaPosition2 != notFound) {
- // The value is delimited by the next comma
- result.append(std::pair<String, String>(directive, trimToNextSeparator(value.substring(0, nextCommaPosition2).stripWhiteSpace())));
- pos += (safeHeader.find(',', pos) - pos) + 1;
- } else {
- // The rest is the value; no change to value needed
- result.append(std::pair<String, String>(directive, trimToNextSeparator(value)));
- return;
- }
- }
- } else if (nextCommaPosition != notFound && (nextCommaPosition < nextEqualSignPosition || nextEqualSignPosition == notFound)) {
- // Add directive to map with empty string as value
- result.append(std::pair<String, String>(trimToNextSeparator(safeHeader.substring(pos, nextCommaPosition - pos).stripWhiteSpace()), ""));
- pos += nextCommaPosition - pos + 1;
- } else {
- // Add last directive to map with empty string as value
- result.append(std::pair<String, String>(trimToNextSeparator(safeHeader.substring(pos, max - pos).stripWhiteSpace()), ""));
- return;
- }
- }
-}
-
}
diff --git a/Source/WebCore/platform/network/ResourceResponseBase.h b/Source/WebCore/platform/network/ResourceResponseBase.h
index 9d838acc4..4365d68b9 100644
--- a/Source/WebCore/platform/network/ResourceResponseBase.h
+++ b/Source/WebCore/platform/network/ResourceResponseBase.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2008, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,93 +24,123 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceResponseBase_h
-#define ResourceResponseBase_h
+#pragma once
+#include "CacheValidation.h"
+#include "CertificateInfo.h"
#include "HTTPHeaderMap.h"
+#include "NetworkLoadTiming.h"
+#include "ParsedContentRange.h"
#include "URL.h"
-#include "ResourceLoadTiming.h"
-
-#include <wtf/PassOwnPtr.h>
-#include <wtf/RefPtr.h>
-
-#if OS(SOLARIS)
-#include <sys/time.h> // For time_t structure.
-#endif
+#include <wtf/SHA1.h>
namespace WebCore {
class ResourceResponse;
-struct CrossThreadResourceResponseData;
// Do not use this class directly, use the class ResponseResponse instead
class ResourceResponseBase {
WTF_MAKE_FAST_ALLOCATED;
public:
- static PassOwnPtr<ResourceResponse> adopt(PassOwnPtr<CrossThreadResourceResponseData>);
+ enum class Type;
+
+ struct CrossThreadData {
+ CrossThreadData(const CrossThreadData&) = delete;
+ CrossThreadData& operator=(const CrossThreadData&) = delete;
+ CrossThreadData() = default;
+ CrossThreadData(CrossThreadData&&) = default;
+
+ URL url;
+ String mimeType;
+ long long expectedContentLength;
+ String textEncodingName;
+ int httpStatusCode;
+ String httpStatusText;
+ String httpVersion;
+ HTTPHeaderMap httpHeaderFields;
+ NetworkLoadTiming networkLoadTiming;
+ Type type;
+ bool isRedirected;
+ };
- // Gets a copy of the data suitable for passing to another thread.
- PassOwnPtr<CrossThreadResourceResponseData> copyData() const;
+ CrossThreadData crossThreadData() const;
+ static ResourceResponse fromCrossThreadData(CrossThreadData&&);
+
+ enum class Tainting { Basic, Cors, Opaque };
+ static ResourceResponse filterResponse(const ResourceResponse&, Tainting);
bool isNull() const { return m_isNull; }
- bool isHTTP() const;
+ WEBCORE_EXPORT bool isHTTP() const;
+ bool isSuccessful() const;
- const URL& url() const;
- void setURL(const URL& url);
+ WEBCORE_EXPORT const URL& url() const;
+ WEBCORE_EXPORT void setURL(const URL&);
- const String& mimeType() const;
- void setMimeType(const String& mimeType);
+ WEBCORE_EXPORT const String& mimeType() const;
+ WEBCORE_EXPORT void setMimeType(const String& mimeType);
- long long expectedContentLength() const;
- void setExpectedContentLength(long long expectedContentLength);
+ WEBCORE_EXPORT long long expectedContentLength() const;
+ WEBCORE_EXPORT void setExpectedContentLength(long long expectedContentLength);
- const String& textEncodingName() const;
- void setTextEncodingName(const String& name);
+ WEBCORE_EXPORT const String& textEncodingName() const;
+ WEBCORE_EXPORT void setTextEncodingName(const String& name);
- // FIXME: Should compute this on the fly.
- // There should not be a setter exposed, as suggested file name is determined based on other headers in a manner that WebCore does not necessarily know about.
- const String& suggestedFilename() const;
- void setSuggestedFilename(const String&);
+ WEBCORE_EXPORT int httpStatusCode() const;
+ WEBCORE_EXPORT void setHTTPStatusCode(int);
- int httpStatusCode() const;
- void setHTTPStatusCode(int);
-
- const String& httpStatusText() const;
- void setHTTPStatusText(const String&);
-
- String httpHeaderField(const AtomicString& name) const;
- String httpHeaderField(const char* name) const;
- void setHTTPHeaderField(const AtomicString& name, const String& value);
- void addHTTPHeaderField(const AtomicString& name, const String& value);
- const HTTPHeaderMap& httpHeaderFields() const;
+ WEBCORE_EXPORT const String& httpStatusText() const;
+ WEBCORE_EXPORT void setHTTPStatusText(const String&);
- bool isMultipart() const { return mimeType() == "multipart/x-mixed-replace"; }
+ WEBCORE_EXPORT const String& httpVersion() const;
+ WEBCORE_EXPORT void setHTTPVersion(const String&);
+ WEBCORE_EXPORT bool isHTTP09() const;
- bool isAttachment() const;
-
- // These functions return parsed values of the corresponding response headers.
- // NaN means that the header was not present or had invalid value.
- bool cacheControlContainsNoCache() const;
- bool cacheControlContainsNoStore() const;
- bool cacheControlContainsMustRevalidate() const;
- bool hasCacheValidatorFields() const;
- double cacheControlMaxAge() const;
- double date() const;
- double age() const;
- double expires() const;
- double lastModified() const;
+ WEBCORE_EXPORT const HTTPHeaderMap& httpHeaderFields() const;
- unsigned connectionID() const;
- void setConnectionID(unsigned);
+ String httpHeaderField(const String& name) const;
+ WEBCORE_EXPORT String httpHeaderField(HTTPHeaderName) const;
+ WEBCORE_EXPORT void setHTTPHeaderField(const String& name, const String& value);
+ WEBCORE_EXPORT void setHTTPHeaderField(HTTPHeaderName, const String& value);
- bool connectionReused() const;
- void setConnectionReused(bool);
+ void addHTTPHeaderField(HTTPHeaderName, const String& value);
+ void addHTTPHeaderField(const String& name, const String& value);
- bool wasCached() const;
- void setWasCached(bool);
+ // Instead of passing a string literal to any of these functions, just use a HTTPHeaderName instead.
+ template<size_t length> String httpHeaderField(const char (&)[length]) const = delete;
+ template<size_t length> void setHTTPHeaderField(const char (&)[length], const String&) = delete;
+ template<size_t length> void addHTTPHeaderField(const char (&)[length], const String&) = delete;
- ResourceLoadTiming* resourceLoadTiming() const;
- void setResourceLoadTiming(PassRefPtr<ResourceLoadTiming>);
+ bool isMultipart() const { return mimeType() == "multipart/x-mixed-replace"; }
+
+ WEBCORE_EXPORT bool isAttachment() const;
+ WEBCORE_EXPORT bool isAttachmentWithFilename() const;
+ WEBCORE_EXPORT String suggestedFilename() const;
+
+ WEBCORE_EXPORT void includeCertificateInfo() const;
+ const std::optional<CertificateInfo>& certificateInfo() const { return m_certificateInfo; };
+
+ // These functions return parsed values of the corresponding response headers.
+ WEBCORE_EXPORT bool cacheControlContainsNoCache() const;
+ WEBCORE_EXPORT bool cacheControlContainsNoStore() const;
+ WEBCORE_EXPORT bool cacheControlContainsMustRevalidate() const;
+ WEBCORE_EXPORT bool cacheControlContainsImmutable() const;
+ WEBCORE_EXPORT bool hasCacheValidatorFields() const;
+ WEBCORE_EXPORT std::optional<std::chrono::microseconds> cacheControlMaxAge() const;
+ WEBCORE_EXPORT std::optional<std::chrono::system_clock::time_point> date() const;
+ WEBCORE_EXPORT std::optional<std::chrono::microseconds> age() const;
+ WEBCORE_EXPORT std::optional<std::chrono::system_clock::time_point> expires() const;
+ WEBCORE_EXPORT std::optional<std::chrono::system_clock::time_point> lastModified() const;
+ ParsedContentRange& contentRange() const;
+
+ // This is primarily for testing support. It is not necessarily accurate in all scenarios.
+ enum class Source { Unknown, Network, DiskCache, DiskCacheAfterValidation, MemoryCache, MemoryCacheAfterValidation };
+ WEBCORE_EXPORT Source source() const;
+ WEBCORE_EXPORT void setSource(Source);
+
+ const std::optional<SHA1::Digest>& cacheBodyKey() const { return m_cacheBodyKey; }
+ void setCacheBodyKey(const SHA1::Digest& key) { m_cacheBodyKey = key; }
+
+ NetworkLoadTiming& networkLoadTiming() const { return m_networkLoadTiming; }
// The ResourceResponse subclass may "shadow" this method to provide platform-specific memory usage information
unsigned memoryUsage() const
@@ -119,86 +149,154 @@ public:
return 1280;
}
+ enum class Type { Basic, Cors, Default, Error, Opaque, Opaqueredirect };
+ Type type() const { return m_type; }
+ void setType(Type type) { m_type = type; }
+ bool isRedirected() const { return m_isRedirected; }
+ void setRedirected(bool isRedirected) { m_isRedirected = isRedirected; }
+
static bool compare(const ResourceResponse&, const ResourceResponse&);
+ template<class Encoder> void encode(Encoder&) const;
+ template<class Decoder> static bool decode(Decoder&, ResourceResponseBase&);
+
protected:
enum InitLevel {
Uninitialized,
CommonFieldsOnly,
- CommonAndUncommonFields,
AllFields
};
- ResourceResponseBase();
- ResourceResponseBase(const URL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename);
+ WEBCORE_EXPORT ResourceResponseBase();
+ WEBCORE_EXPORT ResourceResponseBase(const URL&, const String& mimeType, long long expectedLength, const String& textEncodingName);
- void lazyInit(InitLevel) const;
+ WEBCORE_EXPORT void lazyInit(InitLevel) const;
- // The ResourceResponse subclass may "shadow" this method to lazily initialize platform specific fields
+ // The ResourceResponse subclass should shadow these functions to lazily initialize platform specific fields
void platformLazyInit(InitLevel) { }
+ CertificateInfo platformCertificateInfo() const { return CertificateInfo(); };
+ String platformSuggestedFileName() const { return String(); }
- // The ResourceResponse subclass may "shadow" this method to compare platform specific fields
static bool platformCompare(const ResourceResponse&, const ResourceResponse&) { return true; }
+private:
+ void parseCacheControlDirectives() const;
+ void updateHeaderParsedState(HTTPHeaderName);
+
+protected:
+ bool m_isNull;
URL m_url;
- String m_mimeType;
+ AtomicString m_mimeType;
long long m_expectedContentLength;
- String m_textEncodingName;
- String m_suggestedFilename;
- String m_httpStatusText;
+ AtomicString m_textEncodingName;
+ AtomicString m_httpStatusText;
+ AtomicString m_httpVersion;
HTTPHeaderMap m_httpHeaderFields;
- RefPtr<ResourceLoadTiming> m_resourceLoadTiming;
+ mutable NetworkLoadTiming m_networkLoadTiming;
- int m_httpStatusCode;
- unsigned m_connectionID;
-
-private:
- mutable double m_cacheControlMaxAge;
- mutable double m_age;
- mutable double m_date;
- mutable double m_expires;
- mutable double m_lastModified;
+ mutable std::optional<CertificateInfo> m_certificateInfo;
-public:
- bool m_wasCached : 1;
- bool m_connectionReused : 1;
+ int m_httpStatusCode;
- bool m_isNull : 1;
-
private:
- const ResourceResponse& asResourceResponse() const;
- void parseCacheControlDirectives() const;
- void updateHeaderParsedState(const AtomicString& name);
-
- mutable bool m_haveParsedCacheControlHeader : 1;
- mutable bool m_haveParsedAgeHeader : 1;
- mutable bool m_haveParsedDateHeader : 1;
- mutable bool m_haveParsedExpiresHeader : 1;
- mutable bool m_haveParsedLastModifiedHeader : 1;
-
- mutable bool m_cacheControlContainsNoCache : 1;
- mutable bool m_cacheControlContainsNoStore : 1;
- mutable bool m_cacheControlContainsMustRevalidate : 1;
+ mutable std::optional<std::chrono::microseconds> m_age;
+ mutable std::optional<std::chrono::system_clock::time_point> m_date;
+ mutable std::optional<std::chrono::system_clock::time_point> m_expires;
+ mutable std::optional<std::chrono::system_clock::time_point> m_lastModified;
+ mutable ParsedContentRange m_contentRange;
+ mutable CacheControlDirectives m_cacheControlDirectives;
+
+ mutable bool m_haveParsedCacheControlHeader { false };
+ mutable bool m_haveParsedAgeHeader { false };
+ mutable bool m_haveParsedDateHeader { false };
+ mutable bool m_haveParsedExpiresHeader { false };
+ mutable bool m_haveParsedLastModifiedHeader { false };
+ mutable bool m_haveParsedContentRangeHeader { false };
+
+ Source m_source { Source::Unknown };
+
+ std::optional<SHA1::Digest> m_cacheBodyKey;
+
+ Type m_type { Type::Default };
+ bool m_isRedirected { false };
};
inline bool operator==(const ResourceResponse& a, const ResourceResponse& b) { return ResourceResponseBase::compare(a, b); }
inline bool operator!=(const ResourceResponse& a, const ResourceResponse& b) { return !(a == b); }
-struct CrossThreadResourceResponseDataBase {
- WTF_MAKE_NONCOPYABLE(CrossThreadResourceResponseDataBase); WTF_MAKE_FAST_ALLOCATED;
-public:
- CrossThreadResourceResponseDataBase() { }
- URL m_url;
- String m_mimeType;
- long long m_expectedContentLength;
- String m_textEncodingName;
- String m_suggestedFilename;
- int m_httpStatusCode;
- String m_httpStatusText;
- OwnPtr<CrossThreadHTTPHeaderMapData> m_httpHeaders;
- RefPtr<ResourceLoadTiming> m_resourceLoadTiming;
-};
+template<class Encoder>
+void ResourceResponseBase::encode(Encoder& encoder) const
+{
+ encoder << m_isNull;
+ if (m_isNull)
+ return;
+ lazyInit(AllFields);
+
+ encoder << m_url;
+ encoder << m_mimeType;
+ encoder << static_cast<int64_t>(m_expectedContentLength);
+ encoder << m_textEncodingName;
+ encoder << m_httpStatusText;
+ encoder << m_httpVersion;
+ encoder << m_httpHeaderFields;
+
+ // We don't want to put the networkLoadTiming info
+ // into the disk cache, because we will never use the old info.
+ if (Encoder::isIPCEncoder)
+ encoder << m_networkLoadTiming;
+
+ encoder << m_httpStatusCode;
+ encoder << m_certificateInfo;
+ encoder.encodeEnum(m_source);
+ encoder << m_cacheBodyKey;
+ encoder.encodeEnum(m_type);
+ encoder << m_isRedirected;
+}
+
+template<class Decoder>
+bool ResourceResponseBase::decode(Decoder& decoder, ResourceResponseBase& response)
+{
+ ASSERT(response.m_isNull);
+ bool responseIsNull;
+ if (!decoder.decode(responseIsNull))
+ return false;
+ if (responseIsNull)
+ return true;
+
+ if (!decoder.decode(response.m_url))
+ return false;
+ if (!decoder.decode(response.m_mimeType))
+ return false;
+ int64_t expectedContentLength;
+ if (!decoder.decode(expectedContentLength))
+ return false;
+ response.m_expectedContentLength = expectedContentLength;
+ if (!decoder.decode(response.m_textEncodingName))
+ return false;
+ if (!decoder.decode(response.m_httpStatusText))
+ return false;
+ if (!decoder.decode(response.m_httpVersion))
+ return false;
+ if (!decoder.decode(response.m_httpHeaderFields))
+ return false;
+ // The networkLoadTiming info is only send over IPC and not stored in disk cache.
+ if (Decoder::isIPCDecoder && !decoder.decode(response.m_networkLoadTiming))
+ return false;
+ if (!decoder.decode(response.m_httpStatusCode))
+ return false;
+ if (!decoder.decode(response.m_certificateInfo))
+ return false;
+ if (!decoder.decodeEnum(response.m_source))
+ return false;
+ if (!decoder.decode(response.m_cacheBodyKey))
+ return false;
+ if (!decoder.decodeEnum(response.m_type))
+ return false;
+ if (!decoder.decode(response.m_isRedirected))
+ return false;
+ response.m_isNull = false;
+
+ return true;
+}
} // namespace WebCore
-
-#endif // ResourceResponseBase_h
diff --git a/Source/WebCore/platform/network/SocketStreamErrorBase.cpp b/Source/WebCore/platform/network/SocketStreamError.h
index bbb5d553f..76995c2a5 100644
--- a/Source/WebCore/platform/network/SocketStreamErrorBase.cpp
+++ b/Source/WebCore/platform/network/SocketStreamError.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2009, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,36 +29,42 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "config.h"
-#include "SocketStreamError.h"
+#pragma once
-namespace WebCore {
+#include <wtf/text/WTFString.h>
-SocketStreamError SocketStreamErrorBase::copy() const
-{
- SocketStreamError errorCopy;
- errorCopy.m_errorCode = m_errorCode;
- return errorCopy;
-}
+namespace WebCore {
-bool SocketStreamErrorBase::compare(const SocketStreamError& a, const SocketStreamError& b)
-{
- if (a.isNull() && b.isNull())
- return true;
+class SocketStreamError {
+public:
+ SocketStreamError()
+ {
+ }
- if (a.isNull() || b.isNull())
- return false;
+ explicit SocketStreamError(int errorCode)
+ : m_errorCode(errorCode)
+ , m_isNull(false)
+ {
+ }
- if (a.errorCode() != b.errorCode())
- return false;
+ SocketStreamError(int errorCode, const String& failingURL, const String& localizedDescription)
+ : m_errorCode(errorCode)
+ , m_failingURL(failingURL)
+ , m_localizedDescription(localizedDescription)
+ , m_isNull(false)
+ {
+ }
- if (a.failingURL() != b.failingURL())
- return false;
+ 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; }
- if (a.localizedDescription() != b.localizedDescription())
- return false;
+private:
+ int m_errorCode { 0 };
+ String m_failingURL;
+ String m_localizedDescription;
+ bool m_isNull { true };
+};
- return true;
}
-
-} // namespace WebCore
diff --git a/Source/WebCore/platform/network/SocketStreamHandleBase.cpp b/Source/WebCore/platform/network/SocketStreamHandle.cpp
index e7c1139dd..a4c6cb24e 100644
--- a/Source/WebCore/platform/network/SocketStreamHandleBase.cpp
+++ b/Source/WebCore/platform/network/SocketStreamHandle.cpp
@@ -29,28 +29,27 @@
*/
#include "config.h"
-#include "SocketStreamHandleBase.h"
-
#include "SocketStreamHandle.h"
+
#include "SocketStreamHandleClient.h"
namespace WebCore {
-const unsigned int bufferSize = 100 * 1024 * 1024;
+const unsigned bufferSize = 100 * 1024 * 1024;
-SocketStreamHandleBase::SocketStreamHandleBase(const URL& url, SocketStreamHandleClient* client)
+SocketStreamHandle::SocketStreamHandle(const URL& url, SocketStreamHandleClient& client)
: m_url(url)
, m_client(client)
, m_state(Connecting)
{
}
-SocketStreamHandleBase::SocketStreamState SocketStreamHandleBase::state() const
+SocketStreamHandle::SocketStreamState SocketStreamHandle::state() const
{
return m_state;
}
-bool SocketStreamHandleBase::send(const char* data, int length)
+bool SocketStreamHandle::send(const char* data, size_t length)
{
if (m_state == Connecting || m_state == Closing)
return false;
@@ -60,28 +59,28 @@ bool SocketStreamHandleBase::send(const char* data, int length)
return false;
}
m_buffer.append(data, length);
- if (m_client)
- m_client->didUpdateBufferedAmount(static_cast<SocketStreamHandle*>(this), bufferedAmount());
+ m_client.didUpdateBufferedAmount(static_cast<SocketStreamHandle&>(*this), bufferedAmount());
return true;
}
- int bytesWritten = 0;
- if (m_state == Open)
- bytesWritten = platformSend(data, length);
- if (bytesWritten < 0)
- return false;
+ size_t bytesWritten = 0;
+ if (m_state == Open) {
+ if (auto result = platformSend(data, length))
+ bytesWritten = result.value();
+ else
+ return false;
+ }
if (m_buffer.size() + length - bytesWritten > bufferSize) {
// FIXME: report error to indicate that buffer has no more space.
return false;
}
if (bytesWritten < length) {
m_buffer.append(data + bytesWritten, length - bytesWritten);
- if (m_client)
- m_client->didUpdateBufferedAmount(static_cast<SocketStreamHandle*>(this), bufferedAmount());
+ m_client.didUpdateBufferedAmount(static_cast<SocketStreamHandle&>(*this), bufferedAmount());
}
return true;
}
-void SocketStreamHandleBase::close()
+void SocketStreamHandle::close()
{
if (m_state == Closed)
return;
@@ -91,21 +90,15 @@ void SocketStreamHandleBase::close()
disconnect();
}
-void SocketStreamHandleBase::disconnect()
+void SocketStreamHandle::disconnect()
{
- Ref<SocketStreamHandle> protect(*static_cast<SocketStreamHandle*>(this)); // platformClose calls the client, which may make the handle get deallocated immediately.
+ auto protect = makeRef(static_cast<SocketStreamHandle&>(*this)); // platformClose calls the client, which may make the handle get deallocated immediately.
platformClose();
m_state = Closed;
}
-void SocketStreamHandleBase::setClient(SocketStreamHandleClient* client)
-{
- ASSERT(!client || (!m_client && m_state == Connecting));
- m_client = client;
-}
-
-bool SocketStreamHandleBase::sendPendingData()
+bool SocketStreamHandle::sendPendingData()
{
if (m_state != Open && m_state != Closing)
return false;
@@ -119,16 +112,18 @@ bool SocketStreamHandleBase::sendPendingData()
}
bool pending;
do {
- int bytesWritten = platformSend(m_buffer.firstBlockData(), m_buffer.firstBlockSize());
- pending = bytesWritten != static_cast<int>(m_buffer.firstBlockSize());
- if (bytesWritten <= 0)
+ auto result = platformSend(m_buffer.firstBlockData(), m_buffer.firstBlockSize());
+ if (!result)
+ return false;
+ size_t bytesWritten = result.value();
+ if (!bytesWritten)
return false;
+ pending = bytesWritten != m_buffer.firstBlockSize();
ASSERT(m_buffer.size() - bytesWritten <= bufferSize);
m_buffer.consume(bytesWritten);
} while (!pending && !m_buffer.isEmpty());
- if (m_client)
- m_client->didUpdateBufferedAmount(static_cast<SocketStreamHandle*>(this), bufferedAmount());
+ m_client.didUpdateBufferedAmount(static_cast<SocketStreamHandle&>(*this), bufferedAmount());
return true;
}
-} // namespace WebCore
+} // namespace WebCore
diff --git a/Source/WebCore/platform/network/BlobStorageData.h b/Source/WebCore/platform/network/SocketStreamHandle.h
index 6535e629a..fbad64195 100644
--- a/Source/WebCore/platform/network/BlobStorageData.h
+++ b/Source/WebCore/platform/network/SocketStreamHandle.h
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -28,38 +29,38 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BlobStorageData_h
-#define BlobStorageData_h
+#pragma once
-#include "BlobData.h"
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
+#include "URL.h"
+#include <wtf/StreamBuffer.h>
+#include <wtf/ThreadSafeRefCounted.h>
namespace WebCore {
-class BlobStorageData : public RefCounted<BlobStorageData> {
+class SocketStreamHandleClient;
+
+class SocketStreamHandle : public ThreadSafeRefCounted<SocketStreamHandle> {
public:
- static PassRefPtr<BlobStorageData> create(const String& contentType, const String& contentDisposition)
- {
- return adoptRef(new BlobStorageData(contentType, contentDisposition));
- }
+ enum SocketStreamState { Connecting, Open, Closing, Closed };
+ virtual ~SocketStreamHandle() { }
+ SocketStreamState state() const;
- const String& contentType() const { return m_data.contentType(); }
- const String& contentDisposition() const { return m_data.contentDisposition(); }
- const BlobDataItemList& items() const { return m_data.items(); }
+ bool send(const char* data, size_t length);
+ void close(); // Disconnect after all data in buffer are sent.
+ void disconnect();
+ size_t bufferedAmount() const { return m_buffer.size(); }
-private:
- friend class BlobRegistryImpl;
+protected:
+ SocketStreamHandle(const URL&, SocketStreamHandleClient&);
- BlobStorageData(const String& contentType, const String& contentDisposition)
- {
- m_data.setContentType(contentType);
- m_data.setContentDisposition(contentDisposition);
- }
+ bool sendPendingData();
+ virtual std::optional<size_t> platformSend(const char* data, size_t length) = 0;
+ virtual void platformClose() = 0;
- BlobData m_data;
+ URL m_url;
+ SocketStreamHandleClient& m_client;
+ StreamBuffer<char, 1024 * 1024> m_buffer;
+ SocketStreamState m_state;
};
} // namespace WebCore
-
-#endif // BlobStorageData_h
diff --git a/Source/WebCore/platform/network/SocketStreamHandleBase.h b/Source/WebCore/platform/network/SocketStreamHandleBase.h
deleted file mode 100644
index f79472021..000000000
--- a/Source/WebCore/platform/network/SocketStreamHandleBase.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2009, 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SocketStreamHandleBase_h
-#define SocketStreamHandleBase_h
-
-#include "URL.h"
-
-#include <wtf/StreamBuffer.h>
-
-namespace WebCore {
-
- class SocketStreamHandle;
- class SocketStreamHandleClient;
-
- class SocketStreamHandleBase {
- public:
- enum SocketStreamState { Connecting, Open, Closing, Closed };
- virtual ~SocketStreamHandleBase() { }
- SocketStreamState state() const;
-
- bool send(const char* data, int length);
- void close(); // Disconnect after all data in buffer are sent.
- void disconnect();
- size_t bufferedAmount() const { return m_buffer.size(); }
-
- SocketStreamHandleClient* client() const { return m_client; }
- void setClient(SocketStreamHandleClient*);
-
- protected:
- SocketStreamHandleBase(const URL&, SocketStreamHandleClient*);
-
- bool sendPendingData();
- virtual int platformSend(const char* data, int length) = 0;
- virtual void platformClose() = 0;
-
- URL m_url;
- SocketStreamHandleClient* m_client;
- StreamBuffer<char, 1024 * 1024> m_buffer;
- SocketStreamState m_state;
- };
-
-} // namespace WebCore
-
-#endif // SocketStreamHandleBase_h
diff --git a/Source/WebCore/platform/network/SocketStreamHandleClient.h b/Source/WebCore/platform/network/SocketStreamHandleClient.h
index 5a8c4d50e..e26b9a623 100644
--- a/Source/WebCore/platform/network/SocketStreamHandleClient.h
+++ b/Source/WebCore/platform/network/SocketStreamHandleClient.h
@@ -29,33 +29,24 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SocketStreamHandleClient_h
-#define SocketStreamHandleClient_h
+#pragma once
-namespace WebCore {
-
- class AuthenticationChallenge;
- class URL;
- class SocketStreamError;
- class SocketStreamHandle;
+#include <wtf/Optional.h>
- class SocketStreamHandleClient {
- public:
- virtual ~SocketStreamHandleClient() { }
-
- virtual void willOpenSocketStream(SocketStreamHandle*) { }
- virtual void didOpenSocketStream(SocketStreamHandle*) { }
- virtual void didCloseSocketStream(SocketStreamHandle*) { }
- virtual void didReceiveSocketStreamData(SocketStreamHandle*, const char* /*data*/, int /*length*/) { }
- virtual void didUpdateBufferedAmount(SocketStreamHandle*, size_t /*bufferedAmount*/) { }
+namespace WebCore {
- virtual void didFailSocketStream(SocketStreamHandle*, const SocketStreamError&) { }
+class SocketStreamError;
+class SocketStreamHandle;
- // No authentication for streams per se, but proxy may ask for credentials.
- virtual void didReceiveAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&) { }
- virtual void didCancelAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&) { }
- };
+class SocketStreamHandleClient {
+public:
+ virtual ~SocketStreamHandleClient() { }
-} // namespace WebCore
+ virtual void didOpenSocketStream(SocketStreamHandle&) = 0;
+ virtual void didCloseSocketStream(SocketStreamHandle&) = 0;
+ virtual void didReceiveSocketStreamData(SocketStreamHandle&, const char* data, std::optional<size_t> length) = 0;
+ virtual void didUpdateBufferedAmount(SocketStreamHandle&, size_t bufferedAmount) = 0;
+ virtual void didFailSocketStream(SocketStreamHandle&, const SocketStreamError&) = 0;
+};
-#endif // SocketStreamHandleClient_h
+} // namespace WebCore
diff --git a/Source/WebCore/platform/network/SynchronousLoaderClient.cpp b/Source/WebCore/platform/network/SynchronousLoaderClient.cpp
index 994682fb1..87c994b2f 100644
--- a/Source/WebCore/platform/network/SynchronousLoaderClient.cpp
+++ b/Source/WebCore/platform/network/SynchronousLoaderClient.cpp
@@ -36,16 +36,16 @@ SynchronousLoaderClient::~SynchronousLoaderClient()
{
}
-void SynchronousLoaderClient::willSendRequest(ResourceHandle* handle, ResourceRequest& request, const ResourceResponse& /*redirectResponse*/)
+ResourceRequest SynchronousLoaderClient::willSendRequest(ResourceHandle* handle, ResourceRequest&& request, ResourceResponse&&)
{
// FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
if (protocolHostAndPortAreEqual(handle->firstRequest().url(), request.url()))
- return;
+ return WTFMove(request);
ASSERT(m_error.isNull());
m_error = platformBadResponseError();
m_isDone = true;
- request = ResourceRequest();
+ return { };
}
bool SynchronousLoaderClient::shouldUseCredentialStorage(ResourceHandle*)
@@ -62,9 +62,9 @@ bool SynchronousLoaderClient::canAuthenticateAgainstProtectionSpace(ResourceHand
}
#endif
-void SynchronousLoaderClient::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
+void SynchronousLoaderClient::didReceiveResponse(ResourceHandle*, ResourceResponse&& response)
{
- m_response = response;
+ m_response = WTFMove(response);
}
void SynchronousLoaderClient::didReceiveData(ResourceHandle*, const char* data, unsigned length, int /*encodedDataLength*/)
diff --git a/Source/WebCore/platform/network/SynchronousLoaderClient.h b/Source/WebCore/platform/network/SynchronousLoaderClient.h
index 4619f8f35..9ca0e6a5d 100644
--- a/Source/WebCore/platform/network/SynchronousLoaderClient.h
+++ b/Source/WebCore/platform/network/SynchronousLoaderClient.h
@@ -32,13 +32,8 @@
namespace WebCore {
-class SynchronousLoaderClient : public ResourceHandleClient {
+class SynchronousLoaderClient final : public ResourceHandleClient {
public:
- static PassOwnPtr<SynchronousLoaderClient> create()
- {
- return adoptPtr(new SynchronousLoaderClient);
- }
-
virtual ~SynchronousLoaderClient();
void setAllowStoredCredentials(bool allow) { m_allowStoredCredentials = allow; }
@@ -47,31 +42,25 @@ public:
const ResourceError& error() const { return m_error; }
bool isDone() { return m_isDone; }
- static ResourceError platformBadResponseError();
+ WEBCORE_EXPORT static ResourceError platformBadResponseError();
private:
- SynchronousLoaderClient()
- : m_allowStoredCredentials(false)
- , m_isDone(false)
- {
- }
-
- virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse& /*redirectResponse*/) override;
- virtual bool shouldUseCredentialStorage(ResourceHandle*) override;
- virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&) override;
- virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&) override;
- virtual void didReceiveData(ResourceHandle*, const char*, unsigned, int /*encodedDataLength*/) override;
- virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/) override;
- virtual void didFail(ResourceHandle*, const ResourceError&) override;
+ ResourceRequest willSendRequest(ResourceHandle*, ResourceRequest&&, ResourceResponse&&) override;
+ bool shouldUseCredentialStorage(ResourceHandle*) override;
+ void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&) override;
+ void didReceiveResponse(ResourceHandle*, ResourceResponse&&) override;
+ void didReceiveData(ResourceHandle*, const char*, unsigned, int /*encodedDataLength*/) override;
+ void didFinishLoading(ResourceHandle*, double /*finishTime*/) override;
+ void didFail(ResourceHandle*, const ResourceError&) override;
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
- virtual bool canAuthenticateAgainstProtectionSpace(ResourceHandle*, const ProtectionSpace&) override;
+ bool canAuthenticateAgainstProtectionSpace(ResourceHandle*, const ProtectionSpace&) override;
#endif
- bool m_allowStoredCredentials;
+ bool m_allowStoredCredentials { false };
ResourceResponse m_response;
Vector<char> m_data;
ResourceError m_error;
- bool m_isDone;
+ bool m_isDone { false };
};
}
diff --git a/Source/WebCore/platform/network/create-http-header-name-table b/Source/WebCore/platform/network/create-http-header-name-table
new file mode 100755
index 000000000..755d22e94
--- /dev/null
+++ b/Source/WebCore/platform/network/create-http-header-name-table
@@ -0,0 +1,245 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+
+program_name = os.path.basename(__file__)
+if len(sys.argv) < 2:
+ sys.stderr.write("Usage: %s INPUT_FILE GPERF_EXECUTABLE\n" % program_name)
+ exit(1)
+
+input_path = sys.argv[1]
+input_file = open(input_path)
+
+http_header_name_to_id = { }
+http_header_names = []
+
+for line in input_file.xreadlines():
+ http_header_name = line.strip()
+ if not http_header_name or http_header_name[:2] == '//':
+ continue
+
+ http_header_name_to_id[http_header_name] = http_header_name.replace('-', '').replace('.', '')
+
+ http_header_names.append(http_header_name)
+
+input_file.close()
+
+http_header_names.sort()
+
+gperf_file = open('HTTPHeaderNames.gperf', 'w')
+gperf_file.write('''
+%{
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/// This file is generated by create-http-header-name-table, do not edit.
+
+#include "config.h"
+#include "HTTPHeaderNames.h"
+
+#include <wtf/text/StringView.h>
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#pragma clang diagnostic ignored "-Wdeprecated-register"
+#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
+#endif
+
+namespace WebCore {
+
+static const struct HeaderNameString {
+ const char* const name;
+ unsigned length;
+} headerNameStrings[] = {
+''')
+
+for http_header_name in http_header_names:
+ gperf_file.write(' { "%s", %u },\n' % (http_header_name, len(http_header_name)))
+
+gperf_file.write('};\n\n')
+
+gperf_file.write('''
+%}
+
+%language=C++
+%readonly-tables
+%global-table
+%compare-strncmp
+%ignore-case
+%struct-type
+struct HeaderNameHashEntry {
+ const char* name;
+ HTTPHeaderName headerName;
+};
+%define class-name HTTPHeaderNamesHash
+%define lookup-function-name findHeaderNameImpl
+%define hash-function-name header_name_hash_function
+%define word-array-name header_name_wordlist
+%enum
+%%
+''')
+
+for http_header_name in http_header_names:
+ gperf_file.write('%s, HTTPHeaderName::%s\n' % (http_header_name, http_header_name_to_id[http_header_name]))
+
+gperf_file.write('''%%
+bool findHTTPHeaderName(StringView stringView, HTTPHeaderName& headerName)
+{
+ unsigned length = stringView.length();
+ if (length > maxHTTPHeaderNameLength || length < minHTTPHeaderNameLength)
+ return false;
+
+ if (stringView.is8Bit()) {
+ if (auto nameAndString = HTTPHeaderNamesHash::findHeaderNameImpl(reinterpret_cast<const char*>(stringView.characters8()), length)) {
+ headerName = nameAndString->headerName;
+ return true;
+ }
+ } else {
+ LChar characters[maxHTTPHeaderNameLength];
+ for (unsigned i = 0; i < length; ++i) {
+ UChar character = stringView.characters16()[i];
+ if (!isASCII(character))
+ return false;
+
+ characters[i] = static_cast<LChar>(character);
+ }
+
+ if (auto nameAndString = HTTPHeaderNamesHash::findHeaderNameImpl(reinterpret_cast<const char*>(characters), length)) {
+ headerName = nameAndString->headerName;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+StringView httpHeaderNameString(HTTPHeaderName headerName)
+{
+ ASSERT(static_cast<unsigned>(headerName) < numHTTPHeaderNames);
+
+ const auto& name = headerNameStrings[static_cast<unsigned>(headerName)];
+
+ return StringView { reinterpret_cast<const LChar*>(name.name), static_cast<unsigned>(name.length) };
+}
+
+} // namespace WebCore
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+''')
+
+gperf_file.close()
+
+header_file = open('HTTPHeaderNames.h', 'w')
+header_file.write('''
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/// This file is generated by create-http-header-name-table, do not edit.
+
+#ifndef HTTPHeaderNames_h
+#define HTTPHeaderNames_h
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+enum class HTTPHeaderName {
+''')
+
+for http_header_name in http_header_names:
+ header_file.write(' %s,\n' % http_header_name_to_id[http_header_name])
+
+header_file.write('};\n\n')
+header_file.write('const unsigned numHTTPHeaderNames = %u;\n' % len(http_header_names));
+header_file.write('const size_t minHTTPHeaderNameLength = %u;\n' % len(min(http_header_names, key=len)));
+header_file.write('const size_t maxHTTPHeaderNameLength = %u;\n' % len(max(http_header_names, key=len)));
+header_file.write('''
+bool findHTTPHeaderName(StringView, HTTPHeaderName&);
+WEBCORE_EXPORT StringView httpHeaderNameString(HTTPHeaderName);
+
+} // namespace WebCore
+
+#endif // HTTPHeaderNames_h
+''')
+header_file.close()
+
+gperf = os.getenv('GPERF') or sys.argv[2]
+
+if os.system('%s --key-positions="*" -D -n -s 2 HTTPHeaderNames.gperf --output-file=HTTPHeaderNames.cpp' % gperf):
+ sys.stderr.write('Failed to run gperf.')
+ exit(1)
diff --git a/Source/WebCore/platform/network/gtk/CredentialBackingStore.cpp b/Source/WebCore/platform/network/gtk/CredentialBackingStore.cpp
deleted file mode 100644
index 086dbc15d..000000000
--- a/Source/WebCore/platform/network/gtk/CredentialBackingStore.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2012, 2013 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY IGALIA S.L. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "CredentialBackingStore.h"
-
-#if ENABLE(CREDENTIAL_STORAGE)
-#define SECRET_WITH_UNSTABLE 1
-#define SECRET_API_SUBJECT_TO_CHANGE 1
-#include "AuthenticationChallenge.h"
-#include "GRefPtrGtk.h"
-#include <glib/gi18n-lib.h>
-#include <libsecret/secret.h>
-#include <libsoup/soup.h>
-#include <wtf/gobject/GUniquePtr.h>
-#include <wtf/text/CString.h>
-#endif
-
-namespace WebCore {
-
-CredentialBackingStore& credentialBackingStore()
-{
- DEFINE_STATIC_LOCAL(CredentialBackingStore, backingStore, ());
- return backingStore;
-}
-
-#if ENABLE(CREDENTIAL_STORAGE)
-static GRefPtr<GHashTable> createAttributeHashTableFromChallenge(const AuthenticationChallenge& challenge, const Credential& credential = Credential())
-{
- SoupURI* uri = soup_message_get_uri(challenge.soupMessage());
- GRefPtr<GHashTable> attributes = adoptGRef(secret_attributes_build(
- SECRET_SCHEMA_COMPAT_NETWORK,
- "domain", soup_auth_get_realm(challenge.soupAuth()),
- "server", uri->host,
- "protocol", uri->scheme,
- "authtype", soup_auth_get_scheme_name(challenge.soupAuth()),
- "port", uri->port,
- NULL));
- if (credential.isEmpty())
- return attributes;
-
- g_hash_table_insert(attributes.get(), g_strdup("user"), g_strdup(credential.user().utf8().data()));
- return attributes;
-}
-
-struct CredentialForChallengeAsyncReadyCallbackData {
- CredentialBackingStore::CredentialForChallengeCallback callback;
- void* data;
-};
-
-static void credentialForChallengeAsyncReadyCallback(SecretService* service, GAsyncResult* asyncResult, CredentialForChallengeAsyncReadyCallbackData* callbackData)
-{
- CredentialBackingStore::CredentialForChallengeCallback callback = callbackData->callback;
- void* data = callbackData->data;
- delete callbackData;
-
- GUniqueOutPtr<GError> error;
- GUniquePtr<GList> elements(secret_service_search_finish(service, asyncResult, &error.outPtr()));
- if (error || !elements || !elements->data) {
- callback(Credential(), data);
- return;
- }
-
- GRefPtr<SecretItem> secretItem = adoptGRef(static_cast<SecretItem*>(elements->data));
- GRefPtr<GHashTable> attributes = adoptGRef(secret_item_get_attributes(secretItem.get()));
- String user = String::fromUTF8(static_cast<const char*>(g_hash_table_lookup(attributes.get(), "user")));
- if (user.isEmpty()) {
- callback(Credential(), data);
- return;
- }
-
- size_t length;
- GRefPtr<SecretValue> secretValue = adoptGRef(secret_item_get_secret(secretItem.get()));
- const char* passwordData = secret_value_get(secretValue.get(), &length);
- String password = String::fromUTF8(passwordData, length);
-
- callback(Credential(user, password, CredentialPersistencePermanent), data);
-}
-#endif // ENABLE(CREDENTIAL_STORAGE)
-
-void CredentialBackingStore::credentialForChallenge(const AuthenticationChallenge& challenge, CredentialForChallengeCallback callback, void* data)
-{
-#if ENABLE(CREDENTIAL_STORAGE)
- // The default flag only returns the most recent item, not all of them.
- SecretSearchFlags searchFlags = static_cast<SecretSearchFlags>(SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS);
- CredentialForChallengeAsyncReadyCallbackData* callbackData = new CredentialForChallengeAsyncReadyCallbackData;
- callbackData->callback = callback;
- callbackData->data = data;
-
- secret_service_search(
- 0, // The default SecretService.
- SECRET_SCHEMA_COMPAT_NETWORK,
- createAttributeHashTableFromChallenge(challenge).get(),
- searchFlags,
- 0, // cancellable
- reinterpret_cast<GAsyncReadyCallback>(credentialForChallengeAsyncReadyCallback),
- callbackData);
-#else
- callback(Credential(), data);
-#endif // ENABLE(CREDENTIAL_STORAGE)
-}
-
-void CredentialBackingStore::storeCredentialsForChallenge(const AuthenticationChallenge& challenge, const Credential& credential)
-{
-#if ENABLE(CREDENTIAL_STORAGE)
- CString utf8Password = credential.password().utf8();
- GRefPtr<SecretValue> newSecretValue = adoptGRef(secret_value_new(utf8Password.data(), utf8Password.length(), "text/plain"));
-
- secret_service_store(
- 0, // The default SecretService.
- SECRET_SCHEMA_COMPAT_NETWORK,
- createAttributeHashTableFromChallenge(challenge, credential).get(),
- SECRET_COLLECTION_DEFAULT,
- _("WebKitGTK+ password"),
- newSecretValue.get(),
- 0, // cancellable
- 0, // callback
- 0); // data
-#endif // ENABLE(CREDENTIAL_STORAGE)
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/platform/network/gtk/CredentialBackingStore.h b/Source/WebCore/platform/network/gtk/CredentialBackingStore.h
deleted file mode 100644
index 20da9a157..000000000
--- a/Source/WebCore/platform/network/gtk/CredentialBackingStore.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2012 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY IGALIA S.L. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef CredentialBackingStore_h
-#define CredentialBackingStore_h
-
-#include "Credential.h"
-
-namespace WebCore {
-
-class AuthenticationChallenge;
-
-class CredentialBackingStore {
-WTF_MAKE_NONCOPYABLE(CredentialBackingStore);
-public:
- friend CredentialBackingStore& credentialBackingStore();
- virtual ~CredentialBackingStore() { }
-
- typedef void (*CredentialForChallengeCallback)(const Credential&, void* data);
-
- void credentialForChallenge(const AuthenticationChallenge&, CredentialForChallengeCallback, void* data);
- void storeCredentialsForChallenge(const AuthenticationChallenge&, const Credential&);
-private:
- CredentialBackingStore() { }
-};
-
-CredentialBackingStore& credentialBackingStore();
-
-} // namespace WebCore
-
-#endif // CredentialBackingStore_h
diff --git a/Source/WebCore/platform/network/soup/AuthenticationChallenge.h b/Source/WebCore/platform/network/soup/AuthenticationChallenge.h
index 48cf591be..c6d4bd1dd 100644
--- a/Source/WebCore/platform/network/soup/AuthenticationChallenge.h
+++ b/Source/WebCore/platform/network/soup/AuthenticationChallenge.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -44,10 +44,8 @@ public:
{
}
- AuthenticationChallenge(SoupSession*, SoupMessage*, SoupAuth*, bool retrying, AuthenticationClient*);
+ AuthenticationChallenge(SoupMessage*, SoupAuth*, bool retrying, AuthenticationClient* = nullptr);
AuthenticationClient* authenticationClient() const { return m_authenticationClient.get(); }
- SoupSession* soupSession() const { return m_soupSession.get(); }
- SoupMessage* soupMessage() const { return m_soupMessage.get(); }
SoupAuth* soupAuth() const { return m_soupAuth.get(); }
void setProposedCredential(const Credential& credential) { m_proposedCredential = credential; }
@@ -55,8 +53,6 @@ private:
friend class AuthenticationChallengeBase;
static bool platformCompare(const AuthenticationChallenge&, const AuthenticationChallenge&);
- GRefPtr<SoupSession> m_soupSession;
- GRefPtr<SoupMessage> m_soupMessage;
GRefPtr<SoupAuth> m_soupAuth;
RefPtr<AuthenticationClient> m_authenticationClient;
};
diff --git a/Source/WebCore/platform/network/soup/AuthenticationChallengeSoup.cpp b/Source/WebCore/platform/network/soup/AuthenticationChallengeSoup.cpp
index 2e7d02852..97e923c8a 100644
--- a/Source/WebCore/platform/network/soup/AuthenticationChallengeSoup.cpp
+++ b/Source/WebCore/platform/network/soup/AuthenticationChallengeSoup.cpp
@@ -13,7 +13,7 @@
* THIS SOFTWARE IS PROVIDED BY IGALIA S.L. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if USE(SOUP)
+
#include "AuthenticationChallenge.h"
#include "ResourceError.h"
@@ -63,14 +66,12 @@ static ProtectionSpace protectionSpaceFromSoupAuthAndMessage(SoupAuth* soupAuth,
String::fromUTF8(soup_auth_get_realm(soupAuth)), scheme);
}
-AuthenticationChallenge::AuthenticationChallenge(SoupSession* soupSession, SoupMessage* soupMessage, SoupAuth* soupAuth, bool retrying, AuthenticationClient* client)
+AuthenticationChallenge::AuthenticationChallenge(SoupMessage* soupMessage, SoupAuth* soupAuth, bool retrying, AuthenticationClient* client)
: AuthenticationChallengeBase(protectionSpaceFromSoupAuthAndMessage(soupAuth, soupMessage),
Credential(), // proposedCredentials
retrying ? 1 : 0, // previousFailureCount
soupMessage, // failureResponse
ResourceError::authenticationError(soupMessage))
- , m_soupSession(soupSession)
- , m_soupMessage(soupMessage)
, m_soupAuth(soupAuth)
, m_authenticationClient(client)
{
@@ -78,9 +79,9 @@ AuthenticationChallenge::AuthenticationChallenge(SoupSession* soupSession, SoupM
bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b)
{
- return a.soupSession() == b.soupSession()
- && a.soupMessage() == b.soupMessage()
- && a.soupAuth() == b.soupAuth();
+ return a.soupAuth() == b.soupAuth();
}
} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/network/soup/CertificateInfo.cpp b/Source/WebCore/platform/network/soup/CertificateInfo.cpp
index d5fae4dbf..1db77a323 100644
--- a/Source/WebCore/platform/network/soup/CertificateInfo.cpp
+++ b/Source/WebCore/platform/network/soup/CertificateInfo.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if USE(SOUP)
+
#include "CertificateInfo.h"
#include <ResourceError.h>
@@ -60,3 +63,5 @@ CertificateInfo::~CertificateInfo()
}
} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/network/soup/CertificateInfo.h b/Source/WebCore/platform/network/soup/CertificateInfo.h
index 94e4ff585..206cdef68 100644
--- a/Source/WebCore/platform/network/soup/CertificateInfo.h
+++ b/Source/WebCore/platform/network/soup/CertificateInfo.h
@@ -27,8 +27,9 @@
#ifndef CertificateInfo_h
#define CertificateInfo_h
+#include "NotImplemented.h"
#include <libsoup/soup.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
namespace WebCore {
@@ -48,6 +49,8 @@ public:
GTlsCertificateFlags tlsErrors() const { return m_tlsErrors; }
void setTLSErrors(GTlsCertificateFlags tlsErrors) { m_tlsErrors = tlsErrors; }
+ bool containsNonRootSHA1SignedCertificate() const { notImplemented(); return false; }
+
private:
GRefPtr<GTlsCertificate> m_certificate;
GTlsCertificateFlags m_tlsErrors;
diff --git a/Source/WebCore/platform/network/soup/CookieJarSoup.cpp b/Source/WebCore/platform/network/soup/CookieJarSoup.cpp
index fec9dd544..31f009d17 100644
--- a/Source/WebCore/platform/network/soup/CookieJarSoup.cpp
+++ b/Source/WebCore/platform/network/soup/CookieJarSoup.cpp
@@ -19,55 +19,22 @@
*/
#include "config.h"
-#include "CookieJarSoup.h"
+
+#if USE(SOUP)
#include "Cookie.h"
#include "GUniquePtrSoup.h"
-#include "URL.h"
+#include "NetworkStorageSession.h"
#include "NetworkingContext.h"
#include "PlatformCookieJar.h"
#include "SoupNetworkSession.h"
-#include <wtf/gobject/GRefPtr.h>
+#include "URL.h"
+#include <wtf/DateMath.h>
+#include <wtf/glib/GRefPtr.h>
#include <wtf/text/CString.h>
namespace WebCore {
-static SoupCookieJar* cookieJarForSession(const NetworkStorageSession& session)
-{
- return session.soupNetworkSession().cookieJar();
-}
-
-static GRefPtr<SoupCookieJar>& defaultCookieJar()
-{
- DEFINE_STATIC_LOCAL(GRefPtr<SoupCookieJar>, cookieJar, ());
- return cookieJar;
-}
-
-SoupCookieJar* soupCookieJar()
-{
- if (GRefPtr<SoupCookieJar>& jar = defaultCookieJar())
- return jar.get();
-
- SoupCookieJar* jar = soup_cookie_jar_new();
- soup_cookie_jar_set_accept_policy(jar, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY);
- setSoupCookieJar(jar);
- return jar;
-}
-
-SoupCookieJar* createPrivateBrowsingCookieJar()
-{
- SoupCookieJar* jar = soup_cookie_jar_new();
-
- soup_cookie_jar_set_accept_policy(jar, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY);
-
- return jar;
-}
-
-void setSoupCookieJar(SoupCookieJar* jar)
-{
- defaultCookieJar() = jar;
-}
-
static inline bool httpOnlyCookieExists(const GSList* cookies, const gchar* name, const gchar* path)
{
for (const GSList* iter = cookies; iter; iter = g_slist_next(iter)) {
@@ -84,9 +51,7 @@ static inline bool httpOnlyCookieExists(const GSList* cookies, const gchar* name
void setCookiesFromDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url, const String& value)
{
- SoupCookieJar* jar = cookieJarForSession(session);
- if (!jar)
- return;
+ SoupCookieJar* jar = session.cookieStorage();
GUniquePtr<SoupURI> origin = url.createSoupURI();
GUniquePtr<SoupURI> firstPartyURI = firstParty.createSoupURI();
@@ -118,12 +83,8 @@ void setCookiesFromDOM(const NetworkStorageSession& session, const URL& firstPar
static String cookiesForSession(const NetworkStorageSession& session, const URL& url, bool forHTTPHeader)
{
- SoupCookieJar* jar = cookieJarForSession(session);
- if (!jar)
- return String();
-
GUniquePtr<SoupURI> uri = url.createSoupURI();
- GUniquePtr<char> cookies(soup_cookie_jar_get_cookies(jar, uri.get(), forHTTPHeader));
+ GUniquePtr<char> cookies(soup_cookie_jar_get_cookies(session.cookieStorage(), uri.get(), forHTTPHeader));
return String::fromUTF8(cookies.get());
}
@@ -139,18 +100,15 @@ String cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const
bool cookiesEnabled(const NetworkStorageSession& session, const URL& /*firstParty*/, const URL& /*url*/)
{
- return !!cookieJarForSession(session);
+ auto policy = soup_cookie_jar_get_accept_policy(session.cookieStorage());
+ return policy == SOUP_COOKIE_JAR_ACCEPT_ALWAYS || policy == SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY;
}
bool getRawCookies(const NetworkStorageSession& session, const URL& /*firstParty*/, const URL& url, Vector<Cookie>& rawCookies)
{
rawCookies.clear();
- SoupCookieJar* jar = cookieJarForSession(session);
- if (!jar)
- return false;
-
GUniquePtr<SoupURI> uri = url.createSoupURI();
- GUniquePtr<GSList> cookies(soup_cookie_jar_get_cookie_list(jar, uri.get(), TRUE));
+ GUniquePtr<GSList> cookies(soup_cookie_jar_get_cookie_list(session.cookieStorage(), uri.get(), TRUE));
if (!cookies)
return false;
@@ -167,9 +125,7 @@ bool getRawCookies(const NetworkStorageSession& session, const URL& /*firstParty
void deleteCookie(const NetworkStorageSession& session, const URL& url, const String& name)
{
- SoupCookieJar* jar = cookieJarForSession(session);
- if (!jar)
- return;
+ SoupCookieJar* jar = session.cookieStorage();
GUniquePtr<SoupURI> uri = url.createSoupURI();
GUniquePtr<GSList> cookies(soup_cookie_jar_get_cookie_list(jar, uri.get(), TRUE));
@@ -188,10 +144,36 @@ void deleteCookie(const NetworkStorageSession& session, const URL& url, const St
}
}
+static SoupDate* msToSoupDate(double ms)
+{
+ int year = msToYear(ms);
+ int dayOfYear = dayInYear(ms, year);
+ bool leapYear = isLeapYear(year);
+ return soup_date_new(year, monthFromDayInYear(dayOfYear, leapYear), dayInMonthFromDayInYear(dayOfYear, leapYear), msToHours(ms), msToMinutes(ms), static_cast<int>(ms / 1000) % 60);
+}
+
+static SoupCookie* toSoupCookie(const Cookie& cookie)
+{
+ SoupCookie* soupCookie = soup_cookie_new(cookie.name.utf8().data(), cookie.value.utf8().data(),
+ cookie.domain.utf8().data(), cookie.path.utf8().data(), -1);
+ soup_cookie_set_http_only(soupCookie, cookie.httpOnly);
+ soup_cookie_set_secure(soupCookie, cookie.secure);
+ if (!cookie.session) {
+ SoupDate* date = msToSoupDate(cookie.expires);
+ soup_cookie_set_expires(soupCookie, date);
+ soup_date_free(date);
+ }
+ return soupCookie;
+}
+
+void addCookie(const NetworkStorageSession& session, const URL&, const Cookie& cookie)
+{
+ soup_cookie_jar_add_cookie(session.cookieStorage(), toSoupCookie(cookie));
+}
+
void getHostnamesWithCookies(const NetworkStorageSession& session, HashSet<String>& hostnames)
{
- SoupCookieJar* cookieJar = cookieJarForSession(session);
- GUniquePtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar));
+ GUniquePtr<GSList> cookies(soup_cookie_jar_all_cookies(session.cookieStorage()));
for (GSList* item = cookies.get(); item; item = g_slist_next(item)) {
SoupCookie* cookie = static_cast<SoupCookie*>(item->data);
if (cookie->domain)
@@ -200,22 +182,26 @@ void getHostnamesWithCookies(const NetworkStorageSession& session, HashSet<Strin
}
}
-void deleteCookiesForHostname(const NetworkStorageSession& session, const String& hostname)
+void deleteCookiesForHostnames(const NetworkStorageSession& session, const Vector<String>& hostnames)
{
- CString hostNameString = hostname.utf8();
- SoupCookieJar* cookieJar = cookieJarForSession(session);
- GUniquePtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar));
- for (GSList* item = cookies.get(); item; item = g_slist_next(item)) {
- SoupCookie* cookie = static_cast<SoupCookie*>(item->data);
- if (soup_cookie_domain_matches(cookie, hostNameString.data()))
- soup_cookie_jar_delete_cookie(cookieJar, cookie);
- soup_cookie_free(cookie);
+ SoupCookieJar* cookieJar = session.cookieStorage();
+
+ for (const auto& hostname : hostnames) {
+ CString hostNameString = hostname.utf8();
+
+ GUniquePtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar));
+ for (GSList* item = cookies.get(); item; item = g_slist_next(item)) {
+ SoupCookie* cookie = static_cast<SoupCookie*>(item->data);
+ if (soup_cookie_domain_matches(cookie, hostNameString.data()))
+ soup_cookie_jar_delete_cookie(cookieJar, cookie);
+ soup_cookie_free(cookie);
+ }
}
}
void deleteAllCookies(const NetworkStorageSession& session)
{
- SoupCookieJar* cookieJar = cookieJarForSession(session);
+ SoupCookieJar* cookieJar = session.cookieStorage();
GUniquePtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar));
for (GSList* item = cookies.get(); item; item = g_slist_next(item)) {
SoupCookie* cookie = static_cast<SoupCookie*>(item->data);
@@ -224,4 +210,15 @@ void deleteAllCookies(const NetworkStorageSession& session)
}
}
+void deleteAllCookiesModifiedSince(const NetworkStorageSession& session, std::chrono::system_clock::time_point timestamp)
+{
+ // FIXME: Add support for deleting cookies modified since the given timestamp. It should probably be added to libsoup.
+ if (timestamp == std::chrono::system_clock::from_time_t(0))
+ deleteAllCookies(session);
+ else
+ g_warning("Deleting cookies modified since a given time span is not supported yet");
+}
+
}
+
+#endif
diff --git a/Source/WebCore/platform/network/soup/CookieStorageSoup.cpp b/Source/WebCore/platform/network/soup/CookieStorageSoup.cpp
index 65817a1bd..ea6a6b292 100644
--- a/Source/WebCore/platform/network/soup/CookieStorageSoup.cpp
+++ b/Source/WebCore/platform/network/soup/CookieStorageSoup.cpp
@@ -19,34 +19,20 @@
#include "config.h"
#include "CookieStorage.h"
-#include "CookieJarSoup.h"
-#include "NotImplemented.h"
-
-#include <stdio.h>
+#if USE(SOUP)
namespace WebCore {
-static CookieChangeCallbackPtr cookieChangeCallback;
-
-static void soupCookiesChanged(SoupCookieJar* jar, SoupCookie*, SoupCookie*, gpointer)
+void startObservingCookieChanges(const NetworkStorageSession&, std::function<void ()>&&)
{
- if (jar != soupCookieJar())
- return;
- cookieChangeCallback();
+ ASSERT_NOT_REACHED();
}
-void startObservingCookieChanges(CookieChangeCallbackPtr callback)
+void stopObservingCookieChanges(const NetworkStorageSession&)
{
- ASSERT(!cookieChangeCallback);
- cookieChangeCallback = callback;
-
- g_signal_connect(soupCookieJar(), "changed", G_CALLBACK(soupCookiesChanged), 0);
+ ASSERT_NOT_REACHED();
}
-void stopObservingCookieChanges()
-{
- g_signal_handlers_disconnect_by_func(soupCookieJar(), reinterpret_cast<void*>(soupCookiesChanged), 0);
- cookieChangeCallback = 0;
}
-}
+#endif
diff --git a/Source/WebCore/platform/network/soup/CredentialStorageSoup.cpp b/Source/WebCore/platform/network/soup/CredentialStorageSoup.cpp
index 54ccad056..e5ec16f95 100644
--- a/Source/WebCore/platform/network/soup/CredentialStorageSoup.cpp
+++ b/Source/WebCore/platform/network/soup/CredentialStorageSoup.cpp
@@ -26,6 +26,8 @@
#include "config.h"
#include "CredentialStorage.h"
+#if USE(SOUP)
+
#include "Credential.h"
namespace WebCore {
@@ -36,3 +38,5 @@ Credential CredentialStorage::getFromPersistentStorage(const ProtectionSpace&)
}
} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/network/soup/DNSSoup.cpp b/Source/WebCore/platform/network/soup/DNSSoup.cpp
index 6f630b5b8..ca11457dd 100644
--- a/Source/WebCore/platform/network/soup/DNSSoup.cpp
+++ b/Source/WebCore/platform/network/soup/DNSSoup.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
* Copyright (C) 2009, 2012 Igalia S.L.
*
* Redistribution and use in source and binary forms, with or without
@@ -14,7 +14,7 @@
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -28,31 +28,74 @@
#include "DNS.h"
#include "DNSResolveQueue.h"
+#if USE(SOUP)
+
+#include "NetworkStorageSession.h"
#include "SoupNetworkSession.h"
#include <libsoup/soup.h>
#include <wtf/MainThread.h>
+#include <wtf/glib/GUniquePtr.h>
#include <wtf/text/CString.h>
namespace WebCore {
-// There is no current reliable way to know if we're behind a proxy at
-// this level. We'll have to implement it in
-// SoupSession/SoupProxyURIResolver/GProxyResolver
-bool DNSResolveQueue::platformProxyIsEnabledInSystemPreferences()
+// Initially true to ensure prefetch stays disabled until we have proxy settings.
+static bool isUsingHttpProxy = true;
+static bool isUsingHttpsProxy = true;
+
+static bool didResolveProxy(char** uris)
+{
+ // We have a list of possible proxies to use for the URI. If the first item in the list is
+ // direct:// (the usual case), then the user prefers not to use a proxy. This is similar to
+ // resolving hostnames: there could be many possibilities returned in order of preference, and
+ // if we're trying to connect we should attempt each one in order, but here we are not trying
+ // to connect, merely to decide whether a proxy "should" be used.
+ return uris && *uris && strcmp(*uris, "direct://");
+}
+
+static void didResolveProxy(GProxyResolver* resolver, GAsyncResult* result, bool* isUsingProxyType, bool* isUsingProxy)
+{
+ GUniqueOutPtr<GError> error;
+ GUniquePtr<char*> uris(g_proxy_resolver_lookup_finish(resolver, result, &error.outPtr()));
+ if (error) {
+ WTFLogAlways("Error determining system proxy settings: %s", error->message);
+ return;
+ }
+
+ *isUsingProxyType = didResolveProxy(uris.get());
+ *isUsingProxy = isUsingHttpProxy || isUsingHttpsProxy;
+}
+
+static void proxyResolvedForHttpUriCallback(GObject* source, GAsyncResult* result, void* userData)
{
- return false;
+ didResolveProxy(G_PROXY_RESOLVER(source), result, &isUsingHttpProxy, static_cast<bool*>(userData));
+}
+
+static void proxyResolvedForHttpsUriCallback(GObject* source, GAsyncResult* result, void* userData)
+{
+ didResolveProxy(G_PROXY_RESOLVER(source), result, &isUsingHttpsProxy, static_cast<bool*>(userData));
+}
+
+void DNSResolveQueue::updateIsUsingProxy()
+{
+ GRefPtr<GProxyResolver> resolver;
+ g_object_get(NetworkStorageSession::defaultStorageSession().getOrCreateSoupNetworkSession().soupSession(), "proxy-resolver", &resolver.outPtr(), nullptr);
+ ASSERT(resolver);
+
+ g_proxy_resolver_lookup_async(resolver.get(), "http://example.com/", nullptr, proxyResolvedForHttpUriCallback, &m_isUsingProxy);
+ g_proxy_resolver_lookup_async(resolver.get(), "https://example.com/", nullptr, proxyResolvedForHttpsUriCallback, &m_isUsingProxy);
}
static void resolvedCallback(SoupAddress*, guint, void*)
{
- DNSResolveQueue::shared().decrementRequestCount();
+ DNSResolveQueue::singleton().decrementRequestCount();
}
void DNSResolveQueue::platformResolve(const String& hostname)
{
ASSERT(isMainThread());
- soup_session_prefetch_dns(SoupNetworkSession::defaultSession().soupSession(), hostname.utf8().data(), nullptr, resolvedCallback, nullptr);
+ soup_session_prefetch_dns(NetworkStorageSession::defaultStorageSession().getOrCreateSoupNetworkSession().soupSession(), hostname.utf8().data(), nullptr, resolvedCallback, nullptr);
}
void prefetchDNS(const String& hostname)
@@ -61,7 +104,9 @@ void prefetchDNS(const String& hostname)
if (hostname.isEmpty())
return;
- DNSResolveQueue::shared().add(hostname);
+ DNSResolveQueue::singleton().add(hostname);
}
}
+
+#endif
diff --git a/Source/WebCore/platform/network/soup/GRefPtrSoup.cpp b/Source/WebCore/platform/network/soup/GRefPtrSoup.cpp
new file mode 100644
index 000000000..009aec168
--- /dev/null
+++ b/Source/WebCore/platform/network/soup/GRefPtrSoup.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "GRefPtrSoup.h"
+
+namespace WTF {
+
+template <> SoupBuffer* refGPtr(SoupBuffer* ptr)
+{
+ return ptr ? soup_buffer_copy(ptr) : nullptr;
+}
+
+template <> void derefGPtr(SoupBuffer* ptr)
+{
+ if (ptr)
+ soup_buffer_free(ptr);
+}
+
+} // namespace WTF
diff --git a/Source/WebCore/platform/network/soup/GRefPtrSoup.h b/Source/WebCore/platform/network/soup/GRefPtrSoup.h
new file mode 100644
index 000000000..a5988e2fb
--- /dev/null
+++ b/Source/WebCore/platform/network/soup/GRefPtrSoup.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 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
+ * 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 GRefPtrSoup_h
+#define GRefPtrSoup_h
+
+#if USE(SOUP)
+
+#include <libsoup/soup.h>
+#include <wtf/glib/GRefPtr.h>
+
+namespace WTF {
+
+template <> SoupBuffer* refGPtr(SoupBuffer*);
+template <> void derefGPtr(SoupBuffer*);
+
+} // namespace WTF
+
+#endif // USE(SOUP)
+
+#endif
diff --git a/Source/WebCore/platform/network/soup/GUniquePtrSoup.h b/Source/WebCore/platform/network/soup/GUniquePtrSoup.h
index 32775fb46..86dc63741 100644
--- a/Source/WebCore/platform/network/soup/GUniquePtrSoup.h
+++ b/Source/WebCore/platform/network/soup/GUniquePtrSoup.h
@@ -21,7 +21,7 @@
#define GUniquePtrSoup_h
#include <libsoup/soup.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GUniquePtr.h>
namespace WTF {
diff --git a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp
index 67f195049..8417691e8 100644
--- a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp
+++ b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
* Copyright (C) 2013 University of Szeged. All rights reserved.
+ * Copyright (C) 2016 Igalia S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,21 +28,39 @@
#include "config.h"
#include "NetworkStorageSession.h"
+#if USE(SOUP)
+
#include "ResourceHandle.h"
#include "SoupNetworkSession.h"
+#include <libsoup/soup.h>
#include <wtf/MainThread.h>
#include <wtf/NeverDestroyed.h>
+#include <wtf/glib/GUniquePtr.h>
+
+#if USE(LIBSECRET)
+#include "GRefPtrGtk.h"
+#include <glib/gi18n-lib.h>
+#define SECRET_WITH_UNSTABLE 1
+#define SECRET_API_SUBJECT_TO_CHANGE 1
+#include <libsecret/secret.h>
+#endif
namespace WebCore {
-NetworkStorageSession::NetworkStorageSession(std::unique_ptr<SoupNetworkSession> session)
- : m_session(std::move(session))
- , m_isPrivate(false)
+NetworkStorageSession::NetworkStorageSession(SessionID sessionID, std::unique_ptr<SoupNetworkSession>&& session)
+ : m_sessionID(sessionID)
+ , m_session(WTFMove(session))
{
+ setCookieStorage(m_session ? m_session->cookieJar() : nullptr);
}
NetworkStorageSession::~NetworkStorageSession()
{
+ g_signal_handlers_disconnect_matched(m_cookieStorage.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
+
+#if USE(LIBSECRET)
+ g_cancellable_cancel(m_persisentStorageCancellable.get());
+#endif
}
static std::unique_ptr<NetworkStorageSession>& defaultSession()
@@ -54,30 +73,207 @@ static std::unique_ptr<NetworkStorageSession>& defaultSession()
NetworkStorageSession& NetworkStorageSession::defaultStorageSession()
{
if (!defaultSession())
- defaultSession() = std::make_unique<NetworkStorageSession>(nullptr);
+ defaultSession() = std::make_unique<NetworkStorageSession>(SessionID::defaultSessionID(), nullptr);
return *defaultSession();
}
-std::unique_ptr<NetworkStorageSession> NetworkStorageSession::createPrivateBrowsingSession(const String&)
+void NetworkStorageSession::ensurePrivateBrowsingSession(SessionID sessionID, const String&)
{
- auto session = std::make_unique<NetworkStorageSession>(SoupNetworkSession::createPrivateBrowsingSession());
- session->m_isPrivate = true;
- return session;
+ ASSERT(sessionID != SessionID::defaultSessionID());
+ ASSERT(!globalSessionMap().contains(sessionID));
+ globalSessionMap().add(sessionID, std::make_unique<NetworkStorageSession>(sessionID, std::make_unique<SoupNetworkSession>()));
}
void NetworkStorageSession::switchToNewTestingSession()
{
- defaultSession() = std::make_unique<NetworkStorageSession>(SoupNetworkSession::createTestingSession());
+ defaultSession() = std::make_unique<NetworkStorageSession>(SessionID::defaultSessionID(), std::make_unique<SoupNetworkSession>());
+}
+
+SoupNetworkSession& NetworkStorageSession::getOrCreateSoupNetworkSession() const
+{
+ if (!m_session)
+ m_session = std::make_unique<SoupNetworkSession>(m_cookieStorage.get());
+ return *m_session;
+}
+
+void NetworkStorageSession::cookiesDidChange(NetworkStorageSession* session)
+{
+ if (session->m_cookieObserverHandler)
+ session->m_cookieObserverHandler();
+}
+
+SoupCookieJar* NetworkStorageSession::cookieStorage() const
+{
+ RELEASE_ASSERT(!m_session || m_session->cookieJar() == m_cookieStorage.get());
+ return m_cookieStorage.get();
+}
+
+void NetworkStorageSession::setCookieStorage(SoupCookieJar* jar)
+{
+ if (m_cookieStorage)
+ g_signal_handlers_disconnect_matched(m_cookieStorage.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
+
+ // We always have a valid cookieStorage.
+ if (jar)
+ m_cookieStorage = jar;
+ else {
+ m_cookieStorage = adoptGRef(soup_cookie_jar_new());
+ soup_cookie_jar_set_accept_policy(m_cookieStorage.get(), SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY);
+ }
+ g_signal_connect_swapped(m_cookieStorage.get(), "changed", G_CALLBACK(cookiesDidChange), this);
+ if (m_session && m_session->cookieJar() != m_cookieStorage.get())
+ m_session->setCookieJar(m_cookieStorage.get());
+}
+
+void NetworkStorageSession::setCookieObserverHandler(Function<void ()>&& handler)
+{
+ m_cookieObserverHandler = WTFMove(handler);
}
-SoupNetworkSession& NetworkStorageSession::soupNetworkSession() const
+#if USE(LIBSECRET)
+static const char* schemeFromProtectionSpaceServerType(ProtectionSpaceServerType serverType)
{
- return m_session ? *m_session : SoupNetworkSession::defaultSession();
+ switch (serverType) {
+ case ProtectionSpaceServerHTTP:
+ case ProtectionSpaceProxyHTTP:
+ return SOUP_URI_SCHEME_HTTP;
+ case ProtectionSpaceServerHTTPS:
+ case ProtectionSpaceProxyHTTPS:
+ return SOUP_URI_SCHEME_HTTPS;
+ case ProtectionSpaceServerFTP:
+ case ProtectionSpaceProxyFTP:
+ return SOUP_URI_SCHEME_FTP;
+ case ProtectionSpaceServerFTPS:
+ case ProtectionSpaceProxySOCKS:
+ break;
+ }
+
+ ASSERT_NOT_REACHED();
+ return SOUP_URI_SCHEME_HTTP;
}
-void NetworkStorageSession::setSoupNetworkSession(std::unique_ptr<SoupNetworkSession> session)
+static const char* authTypeFromProtectionSpaceAuthenticationScheme(ProtectionSpaceAuthenticationScheme scheme)
{
- m_session = std::move(session);
+ switch (scheme) {
+ case ProtectionSpaceAuthenticationSchemeDefault:
+ case ProtectionSpaceAuthenticationSchemeHTTPBasic:
+ return "Basic";
+ case ProtectionSpaceAuthenticationSchemeHTTPDigest:
+ return "Digest";
+ case ProtectionSpaceAuthenticationSchemeNTLM:
+ return "NTLM";
+ case ProtectionSpaceAuthenticationSchemeNegotiate:
+ return "Negotiate";
+ case ProtectionSpaceAuthenticationSchemeHTMLForm:
+ case ProtectionSpaceAuthenticationSchemeClientCertificateRequested:
+ case ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:
+ ASSERT_NOT_REACHED();
+ break;
+ case ProtectionSpaceAuthenticationSchemeUnknown:
+ return "unknown";
+ }
+
+ ASSERT_NOT_REACHED();
+ return "unknown";
}
+#endif // USE(LIBSECRET)
+
+void NetworkStorageSession::getCredentialFromPersistentStorage(const ProtectionSpace& protectionSpace, Function<void (Credential&&)> completionHandler)
+{
+#if USE(LIBSECRET)
+ if (m_sessionID.isEphemeral()) {
+ completionHandler({ });
+ return;
+ }
+
+ const String& realm = protectionSpace.realm();
+ if (realm.isEmpty()) {
+ completionHandler({ });
+ return;
+ }
+
+ GRefPtr<GHashTable> attributes = adoptGRef(secret_attributes_build(SECRET_SCHEMA_COMPAT_NETWORK,
+ "domain", realm.utf8().data(),
+ "server", protectionSpace.host().utf8().data(),
+ "port", protectionSpace.port(),
+ "protocol", schemeFromProtectionSpaceServerType(protectionSpace.serverType()),
+ "authtype", authTypeFromProtectionSpaceAuthenticationScheme(protectionSpace.authenticationScheme()),
+ nullptr));
+ if (!attributes) {
+ completionHandler({ });
+ return;
+ }
+
+ m_persisentStorageCancellable = adoptGRef(g_cancellable_new());
+ m_persisentStorageCompletionHandler = WTFMove(completionHandler);
+ secret_service_search(nullptr, SECRET_SCHEMA_COMPAT_NETWORK, attributes.get(),
+ static_cast<SecretSearchFlags>(SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS), m_persisentStorageCancellable.get(),
+ [](GObject* source, GAsyncResult* result, gpointer userData) {
+ GUniqueOutPtr<GError> error;
+ GUniquePtr<GList> elements(secret_service_search_finish(SECRET_SERVICE(source), result, &error.outPtr()));
+ if (g_error_matches (error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ return;
+
+ NetworkStorageSession* session = static_cast<NetworkStorageSession*>(userData);
+ auto completionHandler = std::exchange(session->m_persisentStorageCompletionHandler, nullptr);
+ if (error || !elements || !elements->data) {
+ completionHandler({ });
+ return;
+ }
+
+ GRefPtr<SecretItem> secretItem = adoptGRef(static_cast<SecretItem*>(elements->data));
+ GRefPtr<GHashTable> attributes = adoptGRef(secret_item_get_attributes(secretItem.get()));
+ String user = String::fromUTF8(static_cast<const char*>(g_hash_table_lookup(attributes.get(), "user")));
+ if (user.isEmpty()) {
+ completionHandler({ });
+ return;
+ }
+ size_t length;
+ GRefPtr<SecretValue> secretValue = adoptGRef(secret_item_get_secret(secretItem.get()));
+ const char* passwordData = secret_value_get(secretValue.get(), &length);
+ completionHandler(Credential(user, String::fromUTF8(passwordData, length), CredentialPersistencePermanent));
+ }, this);
+#else
+ UNUSED_PARAM(protectionSpace);
+ completionHandler({ });
+#endif
}
+
+void NetworkStorageSession::saveCredentialToPersistentStorage(const ProtectionSpace& protectionSpace, const Credential& credential)
+{
+#if USE(LIBSECRET)
+ if (m_sessionID.isEphemeral())
+ return;
+
+ if (credential.isEmpty())
+ return;
+
+ const String& realm = protectionSpace.realm();
+ if (realm.isEmpty())
+ return;
+
+ GRefPtr<GHashTable> attributes = adoptGRef(secret_attributes_build(SECRET_SCHEMA_COMPAT_NETWORK,
+ "domain", realm.utf8().data(),
+ "server", protectionSpace.host().utf8().data(),
+ "port", protectionSpace.port(),
+ "protocol", schemeFromProtectionSpaceServerType(protectionSpace.serverType()),
+ "authtype", authTypeFromProtectionSpaceAuthenticationScheme(protectionSpace.authenticationScheme()),
+ nullptr));
+ if (!attributes)
+ return;
+
+ g_hash_table_insert(attributes.get(), g_strdup("user"), g_strdup(credential.user().utf8().data()));
+ CString utf8Password = credential.password().utf8();
+ GRefPtr<SecretValue> newSecretValue = adoptGRef(secret_value_new(utf8Password.data(), utf8Password.length(), "text/plain"));
+ secret_service_store(nullptr, SECRET_SCHEMA_COMPAT_NETWORK, attributes.get(), SECRET_COLLECTION_DEFAULT, _("WebKitGTK+ password"),
+ newSecretValue.get(), nullptr, nullptr, nullptr);
+#else
+ UNUSED_PARAM(protectionSpace);
+ UNUSED_PARAM(credential);
+#endif
+}
+
+} // namespace WebCore
+
+#endif // USE(SOUP)
diff --git a/Source/WebCore/platform/network/soup/ProxyServerSoup.cpp b/Source/WebCore/platform/network/soup/ProxyServerSoup.cpp
index c85fe6891..4be57ca66 100644
--- a/Source/WebCore/platform/network/soup/ProxyServerSoup.cpp
+++ b/Source/WebCore/platform/network/soup/ProxyServerSoup.cpp
@@ -26,6 +26,8 @@
#include "config.h"
#include "ProxyServer.h"
+#if USE(SOUP)
+
#include "URL.h"
namespace WebCore {
@@ -37,3 +39,5 @@ Vector<ProxyServer> proxyServersForURL(const URL&, const NetworkingContext*)
}
} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/network/soup/ResourceError.h b/Source/WebCore/platform/network/soup/ResourceError.h
index 1a705f15e..bf0291848 100644
--- a/Source/WebCore/platform/network/soup/ResourceError.h
+++ b/Source/WebCore/platform/network/soup/ResourceError.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -27,7 +27,10 @@
#define ResourceError_h
#include "ResourceErrorBase.h"
-#include <wtf/gobject/GRefPtr.h>
+
+#if USE(SOUP)
+
+#include <wtf/glib/GRefPtr.h>
typedef struct _GTlsCertificate GTlsCertificate;
typedef struct _SoupRequest SoupRequest;
@@ -38,14 +41,15 @@ namespace WebCore {
class ResourceError : public ResourceErrorBase
{
public:
- ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription)
- : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription)
+ ResourceError(Type type = Type::Null)
+ : ResourceErrorBase(type)
, m_tlsErrors(0)
{
}
- ResourceError()
- : m_tlsErrors(0)
+ ResourceError(const String& domain, int errorCode, const URL& failingURL, const String& localizedDescription, Type type = Type::General)
+ : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription, type)
+ , m_tlsErrors(0)
{
}
@@ -53,7 +57,7 @@ public:
static ResourceError transportError(SoupRequest*, int statusCode, const String& reasonPhrase);
static ResourceError genericGError(GError*, SoupRequest*);
static ResourceError tlsError(SoupRequest*, unsigned tlsErrors, GTlsCertificate*);
- static ResourceError timeoutError(const String& failingURL);
+ static ResourceError timeoutError(const URL& failingURL);
static ResourceError authenticationError(SoupMessage*);
unsigned tlsErrors() const { return m_tlsErrors; }
@@ -61,14 +65,18 @@ public:
GTlsCertificate* certificate() const { return m_certificate.get(); }
void setCertificate(GTlsCertificate* certificate) { m_certificate = certificate; }
-private:
- void platformCopy(ResourceError&) const;
static bool platformCompare(const ResourceError& a, const ResourceError& b);
+private:
+ friend class ResourceErrorBase;
+ void doPlatformIsolatedCopy(const ResourceError&);
+
unsigned m_tlsErrors;
GRefPtr<GTlsCertificate> m_certificate;
};
}
+#endif
+
#endif // ResourceError_h_
diff --git a/Source/WebCore/platform/network/soup/ResourceErrorSoup.cpp b/Source/WebCore/platform/network/soup/ResourceErrorSoup.cpp
index bb72c64c4..a608e7e10 100644
--- a/Source/WebCore/platform/network/soup/ResourceErrorSoup.cpp
+++ b/Source/WebCore/platform/network/soup/ResourceErrorSoup.cpp
@@ -13,7 +13,7 @@
* THIS SOFTWARE IS PROVIDED BY IGALIA S.L. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -26,21 +26,22 @@
#include "config.h"
#include "ResourceError.h"
+#if USE(SOUP)
+
#include "LocalizedStrings.h"
#include <libsoup/soup.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GUniquePtr.h>
#include <wtf/text/CString.h>
namespace WebCore {
-static String failingURI(SoupURI* soupURI)
+static URL failingURI(SoupURI* soupURI)
{
ASSERT(soupURI);
- GUniquePtr<char> uri(soup_uri_to_string(soupURI, FALSE));
- return uri.get();
+ return URL(soupURI);
}
-static String failingURI(SoupRequest* request)
+static URL failingURI(SoupRequest* request)
{
ASSERT(request);
return failingURI(soup_request_get_uri(request));
@@ -83,23 +84,21 @@ ResourceError ResourceError::tlsError(SoupRequest* request, unsigned tlsErrors,
return resourceError;
}
-ResourceError ResourceError::timeoutError(const String& failingURL)
+ResourceError ResourceError::timeoutError(const URL& failingURL)
{
- // FIXME: This should probably either be integrated into Errors(Gtk/EFL).h or the
- // networking errors from those files should be moved here.
+ // FIXME: This should probably either be integrated into ErrorsGtk.h or the
+ // networking errors from that file should be moved here.
// Use the same value as in NSURLError.h
static const int timeoutError = -1001;
static const char* const errorDomain = "WebKitNetworkError";
- ResourceError error = ResourceError(errorDomain, timeoutError, failingURL, "Request timed out");
- error.setIsTimeout(true);
- return error;
+ return ResourceError(errorDomain, timeoutError, failingURL, "Request timed out", ResourceError::Type::Timeout);
}
-void ResourceError::platformCopy(ResourceError& errorCopy) const
+void ResourceError::doPlatformIsolatedCopy(const ResourceError& other)
{
- errorCopy.m_certificate = m_certificate;
- errorCopy.m_tlsErrors = m_tlsErrors;
+ m_certificate = other.m_certificate;
+ m_tlsErrors = other.m_tlsErrors;
}
bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b)
@@ -108,3 +107,5 @@ bool ResourceError::platformCompare(const ResourceError& a, const ResourceError&
}
} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp
index dffa31eaa..43be3e6a5 100644
--- a/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp
+++ b/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp
@@ -29,15 +29,16 @@
#include "config.h"
#include "ResourceHandle.h"
-#include "CookieJarSoup.h"
+#if USE(SOUP)
+
#include "CredentialStorage.h"
#include "FileSystem.h"
#include "GUniquePtrSoup.h"
#include "HTTPParsers.h"
#include "LocalizedStrings.h"
#include "MIMETypeRegistry.h"
+#include "NetworkStorageSession.h"
#include "NetworkingContext.h"
-#include "NotImplemented.h"
#include "ResourceError.h"
#include "ResourceHandleClient.h"
#include "ResourceHandleInternal.h"
@@ -52,205 +53,26 @@
#include <libsoup/soup.h>
#include <sys/stat.h>
#include <sys/types.h>
+#if !COMPILER(MSVC)
#include <unistd.h>
+#endif
#include <wtf/CurrentTime.h>
-#include <wtf/SHA1.h>
-#include <wtf/gobject/GRefPtr.h>
-#include <wtf/text/Base64.h>
+#include <wtf/glib/GRefPtr.h>
#include <wtf/text/CString.h>
-#if ENABLE(BLOB)
-#include "BlobData.h"
-#include "BlobRegistryImpl.h"
-#include "BlobStorageData.h"
-#endif
-
-#if PLATFORM(GTK)
-#include "CredentialBackingStore.h"
-#endif
-
namespace WebCore {
-static bool loadingSynchronousRequest = false;
static const size_t gDefaultReadBufferSize = 8192;
-class WebCoreSynchronousLoader final : public ResourceHandleClient {
- WTF_MAKE_NONCOPYABLE(WebCoreSynchronousLoader);
-public:
-
- WebCoreSynchronousLoader(ResourceError& error, ResourceResponse& response, SoupSession* session, Vector<char>& data, StoredCredentials storedCredentials)
- : m_error(error)
- , m_response(response)
- , m_session(session)
- , m_data(data)
- , m_finished(false)
- , m_storedCredentials(storedCredentials)
- {
- // We don't want any timers to fire while we are doing our synchronous load
- // so we replace the thread default main context. The main loop iterations
- // will only process GSources associated with this inner context.
- loadingSynchronousRequest = true;
- GRefPtr<GMainContext> innerMainContext = adoptGRef(g_main_context_new());
- g_main_context_push_thread_default(innerMainContext.get());
- m_mainLoop = adoptGRef(g_main_loop_new(innerMainContext.get(), false));
-
-#if !SOUP_CHECK_VERSION(2, 49, 91)
- adjustMaxConnections(1);
-#endif
- }
-
- ~WebCoreSynchronousLoader()
- {
-#if !SOUP_CHECK_VERSION(2, 49, 91)
- adjustMaxConnections(-1);
-#endif
-
- GMainContext* context = g_main_context_get_thread_default();
- while (g_main_context_pending(context))
- g_main_context_iteration(context, FALSE);
-
- g_main_context_pop_thread_default(context);
- loadingSynchronousRequest = false;
- }
-
-#if !SOUP_CHECK_VERSION(2, 49, 91)
- void adjustMaxConnections(int adjustment)
- {
- int maxConnections, maxConnectionsPerHost;
- g_object_get(m_session,
- SOUP_SESSION_MAX_CONNS, &maxConnections,
- SOUP_SESSION_MAX_CONNS_PER_HOST, &maxConnectionsPerHost,
- NULL);
- maxConnections += adjustment;
- maxConnectionsPerHost += adjustment;
- g_object_set(m_session,
- SOUP_SESSION_MAX_CONNS, maxConnections,
- SOUP_SESSION_MAX_CONNS_PER_HOST, maxConnectionsPerHost,
- NULL);
-
- }
-#endif // SOUP_CHECK_VERSION(2, 49, 91)
-
- virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse& response) override
- {
- m_response = response;
- }
-
- virtual void didReceiveData(ResourceHandle*, const char* /* data */, unsigned /* length */, int) override
- {
- ASSERT_NOT_REACHED();
- }
-
- virtual void didReceiveBuffer(ResourceHandle*, PassRefPtr<SharedBuffer> buffer, int /* encodedLength */) override
- {
- // This pattern is suggested by SharedBuffer.h.
- const char* segment;
- unsigned position = 0;
- while (unsigned length = buffer->getSomeData(segment, position)) {
- m_data.append(segment, length);
- position += length;
- }
- }
-
- virtual void didFinishLoading(ResourceHandle*, double) override
- {
- if (g_main_loop_is_running(m_mainLoop.get()))
- g_main_loop_quit(m_mainLoop.get());
- m_finished = true;
- }
-
- virtual void didFail(ResourceHandle* handle, const ResourceError& error) override
- {
- m_error = error;
- didFinishLoading(handle, 0);
- }
-
- virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge& challenge) override
- {
- // We do not handle authentication for synchronous XMLHttpRequests.
- challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
- }
-
- virtual bool shouldUseCredentialStorage(ResourceHandle*) override
- {
- return m_storedCredentials == AllowStoredCredentials;
- }
-
- void run()
- {
- if (!m_finished)
- g_main_loop_run(m_mainLoop.get());
- }
-
-private:
- ResourceError& m_error;
- ResourceResponse& m_response;
- SoupSession* m_session;
- Vector<char>& m_data;
- bool m_finished;
- GRefPtr<GMainLoop> m_mainLoop;
- StoredCredentials m_storedCredentials;
-};
-
-class HostTLSCertificateSet {
-public:
- void add(GTlsCertificate* certificate)
- {
- String certificateHash = computeCertificateHash(certificate);
- if (!certificateHash.isEmpty())
- m_certificates.add(certificateHash);
- }
-
- bool contains(GTlsCertificate* certificate)
- {
- return m_certificates.contains(computeCertificateHash(certificate));
- }
-
-private:
- static String computeCertificateHash(GTlsCertificate* certificate)
- {
- GRefPtr<GByteArray> certificateData;
- g_object_get(G_OBJECT(certificate), "certificate", &certificateData.outPtr(), NULL);
- if (!certificateData)
- return String();
-
- SHA1 sha1;
- sha1.addBytes(certificateData->data, certificateData->len);
-
- SHA1::Digest digest;
- sha1.computeHash(digest);
-
- return base64Encode(reinterpret_cast<const char*>(digest.data()), SHA1::hashSize);
- }
-
- HashSet<String> m_certificates;
-};
-
-static bool createSoupRequestAndMessageForHandle(ResourceHandle*, const ResourceRequest&, bool isHTTPFamilyRequest);
+static bool createSoupRequestAndMessageForHandle(ResourceHandle*, const ResourceRequest&);
static void cleanupSoupRequestOperation(ResourceHandle*, bool isDestroying = false);
static void sendRequestCallback(GObject*, GAsyncResult*, gpointer);
static void readCallback(GObject*, GAsyncResult*, gpointer);
-static gboolean requestTimeoutCallback(void*);
#if ENABLE(WEB_TIMING)
-static int milisecondsSinceRequest(double requestTime);
+static double milisecondsSinceRequest(double requestTime);
#endif
static void continueAfterDidReceiveResponse(ResourceHandle*);
-static bool gIgnoreSSLErrors = false;
-
-static HashSet<String>& allowsAnyHTTPSCertificateHosts()
-{
- DEFINE_STATIC_LOCAL(HashSet<String>, hosts, ());
- return hosts;
-}
-
-typedef HashMap<String, HostTLSCertificateSet> CertificatesMap;
-static CertificatesMap& clientCertificates()
-{
- DEFINE_STATIC_LOCAL(CertificatesMap, certificates, ());
- return certificates;
-}
-
ResourceHandleInternal::~ResourceHandleInternal()
{
}
@@ -258,8 +80,8 @@ ResourceHandleInternal::~ResourceHandleInternal()
static SoupSession* sessionFromContext(NetworkingContext* context)
{
if (!context || !context->isValid())
- return SoupNetworkSession::defaultSession().soupSession();
- return context->storageSession().soupNetworkSession().soupSession();
+ return NetworkStorageSession::defaultStorageSession().getOrCreateSoupNetworkSession().soupSession();
+ return context->storageSession().getOrCreateSoupNetworkSession().soupSession();
}
ResourceHandle::~ResourceHandle()
@@ -269,7 +91,36 @@ ResourceHandle::~ResourceHandle()
SoupSession* ResourceHandleInternal::soupSession()
{
- return sessionFromContext(m_context.get());
+ return m_session ? m_session->soupSession() : sessionFromContext(m_context.get());
+}
+
+RefPtr<ResourceHandle> ResourceHandle::create(SoupNetworkSession& session, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff)
+{
+ auto newHandle = adoptRef(*new ResourceHandle(session, request, client, defersLoading, shouldContentSniff));
+
+ if (newHandle->d->m_scheduledFailureType != NoFailure)
+ return WTFMove(newHandle);
+
+ if (newHandle->start())
+ return WTFMove(newHandle);
+
+ return nullptr;
+}
+
+ResourceHandle::ResourceHandle(SoupNetworkSession& session, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff)
+ : d(std::make_unique<ResourceHandleInternal>(this, nullptr, request, client, defersLoading, shouldContentSniff && shouldContentSniffURL(request.url())))
+{
+ if (!request.url().isValid()) {
+ scheduleFailure(InvalidURLFailure);
+ return;
+ }
+
+ if (!portAllowed(request.url())) {
+ scheduleFailure(BlockedFailure);
+ return;
+ }
+
+ d->m_session = &session;
}
bool ResourceHandle::cancelledOrClientless()
@@ -305,39 +156,19 @@ static bool isAuthenticationFailureStatusCode(int httpStatusCode)
return httpStatusCode == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED || httpStatusCode == SOUP_STATUS_UNAUTHORIZED;
}
-static bool handleUnignoredTLSErrors(ResourceHandle* handle, SoupMessage* message)
-{
- if (gIgnoreSSLErrors)
- return false;
-
- GTlsCertificate* certificate = nullptr;
- GTlsCertificateFlags tlsErrors = static_cast<GTlsCertificateFlags>(0);
- soup_message_get_https_status(message, &certificate, &tlsErrors);
- if (!tlsErrors)
- return false;
-
- String lowercaseHostURL = handle->firstRequest().url().host().lower();
- if (allowsAnyHTTPSCertificateHosts().contains(lowercaseHostURL))
- return false;
-
- // We aren't ignoring errors globally, but the user may have already decided to accept this certificate.
- auto it = clientCertificates().find(lowercaseHostURL);
- if (it != clientCertificates().end() && it->value.contains(certificate))
- return false;
-
- ResourceHandleInternal* d = handle->getInternal();
- handle->client()->didFail(handle, ResourceError::tlsError(d->m_soupRequest.get(), tlsErrors, certificate));
- return true;
-}
-
static void tlsErrorsChangedCallback(SoupMessage* message, GParamSpec*, gpointer data)
{
- ResourceHandle* handle = static_cast<ResourceHandle*>(data);
+ RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
if (!handle || handle->cancelledOrClientless())
return;
- if (handleUnignoredTLSErrors(handle, message))
+ SoupNetworkSession::checkTLSErrors(handle->getInternal()->m_soupRequest.get(), message, [handle] (const ResourceError& error) {
+ if (error.isNull())
+ return;
+
+ handle->client()->didFail(handle.get(), error);
handle->cancel();
+ });
}
static void gotHeadersCallback(SoupMessage* message, gpointer data)
@@ -348,22 +179,17 @@ static void gotHeadersCallback(SoupMessage* message, gpointer data)
ResourceHandleInternal* d = handle->getInternal();
-#if ENABLE(WEB_TIMING)
- if (d->m_response.resourceLoadTiming())
- d->m_response.resourceLoadTiming()->receiveHeadersEnd = milisecondsSinceRequest(d->m_response.resourceLoadTiming()->requestTime);
-#endif
-
-#if PLATFORM(GTK)
- // We are a bit more conservative with the persistent credential storage than the session store,
- // since we are waiting until we know that this authentication succeeded before actually storing.
- // This is because we want to avoid hitting the disk twice (once to add and once to remove) for
- // incorrect credentials or polluting the keychain with invalid credentials.
- if (!isAuthenticationFailureStatusCode(message->status_code) && message->status_code < 500 && !d->m_credentialDataToSaveInPersistentStore.credential.isEmpty()) {
- credentialBackingStore().storeCredentialsForChallenge(
- d->m_credentialDataToSaveInPersistentStore.challenge,
- d->m_credentialDataToSaveInPersistentStore.credential);
+ if (d->m_context && d->m_context->isValid()) {
+ // We are a bit more conservative with the persistent credential storage than the session store,
+ // since we are waiting until we know that this authentication succeeded before actually storing.
+ // This is because we want to avoid hitting the disk twice (once to add and once to remove) for
+ // incorrect credentials or polluting the keychain with invalid credentials.
+ if (!isAuthenticationFailureStatusCode(message->status_code) && message->status_code < 500) {
+ d->m_context->storageSession().saveCredentialToPersistentStorage(
+ d->m_credentialDataToSaveInPersistentStore.protectionSpace,
+ d->m_credentialDataToSaveInPersistentStore.credential);
+ }
}
-#endif
// The original response will be needed later to feed to willSendRequest in
// doRedirect() in case we are redirected. For this reason, we store it here.
@@ -375,15 +201,17 @@ static void applyAuthenticationToRequest(ResourceHandle* handle, ResourceRequest
// m_user/m_pass are credentials given manually, for instance, by the arguments passed to XMLHttpRequest.open().
ResourceHandleInternal* d = handle->getInternal();
+ String partition = request.cachePartition();
+
if (handle->shouldUseCredentialStorage()) {
if (d->m_user.isEmpty() && d->m_pass.isEmpty())
- d->m_initialCredential = CredentialStorage::get(request.url());
+ d->m_initialCredential = CredentialStorage::defaultCredentialStorage().get(partition, request.url());
else if (!redirect) {
// If there is already a protection space known for the URL, update stored credentials
// before sending a request. This makes it possible to implement logout by sending an
// XMLHttpRequest with known incorrect credentials, and aborting it immediately (so that
// an authentication dialog doesn't pop up).
- CredentialStorage::set(Credential(d->m_user, d->m_pass, CredentialPersistenceNone), request.url());
+ CredentialStorage::defaultCredentialStorage().set(partition, Credential(d->m_user, d->m_pass, CredentialPersistenceNone), request.url());
}
}
@@ -419,10 +247,7 @@ static void restartedCallback(SoupMessage*, gpointer data)
if (!handle || handle->cancelledOrClientless())
return;
- ResourceHandleInternal* d = handle->getInternal();
- ResourceResponse& redirectResponse = d->m_response;
- redirectResponse.setResourceLoadTiming(ResourceLoadTiming::create());
- redirectResponse.resourceLoadTiming()->requestTime = monotonicallyIncreasingTime();
+ handle->m_requestTime = monotonicallyIncreasingTime();
}
#endif
@@ -465,18 +290,17 @@ static bool shouldRedirectAsGET(SoupMessage* message, URL& newURL, bool crossOri
return false;
}
-static void continueAfterWillSendRequest(ResourceHandle* handle, const ResourceRequest& request)
+static void continueAfterWillSendRequest(ResourceHandle* handle, ResourceRequest&& request)
{
// willSendRequest might cancel the load.
if (handle->cancelledOrClientless())
return;
- ResourceRequest newRequest(request);
ResourceHandleInternal* d = handle->getInternal();
- if (protocolHostAndPortAreEqual(newRequest.url(), d->m_response.url()))
- applyAuthenticationToRequest(handle, newRequest, true);
+ if (protocolHostAndPortAreEqual(request.url(), d->m_response.url()))
+ applyAuthenticationToRequest(handle, request, true);
- if (!createSoupRequestAndMessageForHandle(handle, newRequest, true)) {
+ if (!createSoupRequestAndMessageForHandle(handle, request)) {
d->client()->cannotShowURL(handle);
return;
}
@@ -501,14 +325,13 @@ static void doRedirect(ResourceHandle* handle)
URL newURL = URL(URL(soup_message_get_uri(message)), location);
bool crossOrigin = !protocolHostAndPortAreEqual(handle->firstRequest().url(), newURL);
newRequest.setURL(newURL);
- newRequest.setFirstPartyForCookies(newURL);
if (newRequest.httpMethod() != "GET") {
// Change newRequest method to GET if change was made during a previous redirection
// or if current redirection says so
if (message->method == SOUP_METHOD_GET || shouldRedirectAsGET(message, newURL, crossOrigin)) {
newRequest.setHTTPMethod("GET");
- newRequest.setHTTPBody(0);
+ newRequest.setHTTPBody(nullptr);
newRequest.clearHTTPContentType();
}
}
@@ -533,11 +356,12 @@ static void doRedirect(ResourceHandle* handle)
cleanupSoupRequestOperation(handle);
+ ResourceResponse responseCopy = d->m_response;
if (d->client()->usesAsyncCallbacks())
- d->client()->willSendRequestAsync(handle, newRequest, d->m_response);
+ d->client()->willSendRequestAsync(handle, WTFMove(newRequest), WTFMove(responseCopy));
else {
- d->client()->willSendRequest(handle, newRequest, d->m_response);
- continueAfterWillSendRequest(handle, newRequest);
+ auto request = d->client()->willSendRequest(handle, WTFMove(newRequest), WTFMove(responseCopy));
+ continueAfterWillSendRequest(handle, WTFMove(request));
}
}
@@ -603,10 +427,7 @@ static void cleanupSoupRequestOperation(ResourceHandle* handle, bool isDestroyin
d->m_soupMessage.clear();
}
- if (d->m_timeoutSource) {
- g_source_destroy(d->m_timeoutSource.get());
- d->m_timeoutSource.clear();
- }
+ d->m_timeoutSource.stop();
if (!isDestroying)
handle->deref();
@@ -657,12 +478,7 @@ static void nextMultipartResponsePartCallback(GObject* /*source*/, GAsyncResult*
d->m_previousPosition = 0;
- if (handle->client()->usesAsyncCallbacks())
- handle->client()->didReceiveResponseAsync(handle.get(), d->m_response);
- else {
- handle->client()->didReceiveResponse(handle.get(), d->m_response);
- continueAfterDidReceiveResponse(handle.get());
- }
+ handle->didReceiveResponse(ResourceResponse(d->m_response));
}
static void sendRequestCallback(GObject*, GAsyncResult* result, gpointer data)
@@ -712,17 +528,21 @@ static void sendRequestCallback(GObject*, GAsyncResult* result, gpointer data)
d->m_response.setExpectedContentLength(soup_request_get_content_length(d->m_soupRequest.get()));
}
+#if ENABLE(WEB_TIMING)
+ d->m_response.networkLoadTiming().responseStart = milisecondsSinceRequest(handle->m_requestTime);
+#endif
+
if (soupMessage && d->m_response.isMultipart())
d->m_multipartInputStream = adoptGRef(soup_multipart_input_stream_new(soupMessage, inputStream.get()));
else
d->m_inputStream = inputStream;
- if (d->client()->usesAsyncCallbacks())
- handle->client()->didReceiveResponseAsync(handle.get(), d->m_response);
- else {
- handle->client()->didReceiveResponse(handle.get(), d->m_response);
- continueAfterDidReceiveResponse(handle.get());
- }
+ handle->didReceiveResponse(ResourceResponse(d->m_response));
+}
+
+void ResourceHandle::platformContinueSynchronousDidReceiveResponse()
+{
+ continueAfterDidReceiveResponse(this);
}
static void continueAfterDidReceiveResponse(ResourceHandle* handle)
@@ -745,141 +565,23 @@ static void continueAfterDidReceiveResponse(ResourceHandle* handle)
G_PRIORITY_DEFAULT, d->m_cancellable.get(), readCallback, handle);
}
-static bool addFileToSoupMessageBody(SoupMessage* message, const String& fileNameString, size_t offset, size_t lengthToSend, unsigned long& totalBodySize)
-{
- GUniqueOutPtr<GError> error;
- CString fileName = fileSystemRepresentation(fileNameString);
- GMappedFile* fileMapping = g_mapped_file_new(fileName.data(), false, &error.outPtr());
- if (error)
- return false;
-
- gsize bufferLength = lengthToSend;
- if (!lengthToSend)
- bufferLength = g_mapped_file_get_length(fileMapping);
- totalBodySize += bufferLength;
-
- SoupBuffer* soupBuffer = soup_buffer_new_with_owner(g_mapped_file_get_contents(fileMapping) + offset,
- bufferLength,
- fileMapping,
- reinterpret_cast<GDestroyNotify>(g_mapped_file_unref));
- soup_message_body_append_buffer(message->request_body, soupBuffer);
- soup_buffer_free(soupBuffer);
- return true;
-}
-
-#if ENABLE(BLOB)
-static bool blobIsOutOfDate(const BlobDataItem& blobItem)
-{
- ASSERT(blobItem.type == BlobDataItem::File);
- if (!isValidFileTime(blobItem.expectedModificationTime))
- return false;
-
- time_t fileModificationTime;
- if (!getFileModificationTime(blobItem.path, fileModificationTime))
- return true;
-
- return fileModificationTime != static_cast<time_t>(blobItem.expectedModificationTime);
-}
-
-static void addEncodedBlobItemToSoupMessageBody(SoupMessage* message, const BlobDataItem& blobItem, unsigned long& totalBodySize)
-{
- if (blobItem.type == BlobDataItem::Data) {
- totalBodySize += blobItem.length;
- soup_message_body_append(message->request_body, SOUP_MEMORY_TEMPORARY,
- blobItem.data->data() + blobItem.offset, blobItem.length);
- return;
- }
-
- ASSERT(blobItem.type == BlobDataItem::File);
- if (blobIsOutOfDate(blobItem))
- return;
-
- addFileToSoupMessageBody(message,
- blobItem.path,
- blobItem.offset,
- blobItem.length == BlobDataItem::toEndOfFile ? 0 : blobItem.length,
- totalBodySize);
-}
-
-static void addEncodedBlobToSoupMessageBody(SoupMessage* message, const FormDataElement& element, unsigned long& totalBodySize)
-{
- RefPtr<BlobStorageData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(URL(ParsedURLString, element.m_url));
- if (!blobData)
- return;
-
- for (size_t i = 0; i < blobData->items().size(); ++i)
- addEncodedBlobItemToSoupMessageBody(message, blobData->items()[i], totalBodySize);
-}
-#endif // ENABLE(BLOB)
-
-static bool addFormElementsToSoupMessage(SoupMessage* message, const char*, FormData* httpBody, unsigned long& totalBodySize)
-{
- soup_message_body_set_accumulate(message->request_body, FALSE);
- size_t numElements = httpBody->elements().size();
- for (size_t i = 0; i < numElements; i++) {
- const FormDataElement& element = httpBody->elements()[i];
-
- if (element.m_type == FormDataElement::data) {
- totalBodySize += element.m_data.size();
- soup_message_body_append(message->request_body, SOUP_MEMORY_TEMPORARY,
- element.m_data.data(), element.m_data.size());
- continue;
- }
-
- if (element.m_type == FormDataElement::encodedFile) {
- if (!addFileToSoupMessageBody(message ,
- element.m_filename,
- 0 /* offset */,
- 0 /* lengthToSend */,
- totalBodySize))
- return false;
- continue;
- }
-
-#if ENABLE(BLOB)
- ASSERT(element.m_type == FormDataElement::encodedBlob);
- addEncodedBlobToSoupMessageBody(message, element, totalBodySize);
-#endif
- }
- return true;
-}
-
#if ENABLE(WEB_TIMING)
-static int milisecondsSinceRequest(double requestTime)
+static double milisecondsSinceRequest(double requestTime)
{
- return static_cast<int>((monotonicallyIncreasingTime() - requestTime) * 1000.0);
+ return (monotonicallyIncreasingTime() - requestTime) * 1000.0;
}
-static void wroteBodyCallback(SoupMessage*, gpointer data)
+void ResourceHandle::didStartRequest()
{
- RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
- if (!handle)
- return;
-
- ResourceHandleInternal* d = handle->getInternal();
- if (!d->m_response.resourceLoadTiming())
- return;
-
- d->m_response.resourceLoadTiming()->sendEnd = milisecondsSinceRequest(d->m_response.resourceLoadTiming()->requestTime);
+ getInternal()->m_response.networkLoadTiming().requestStart = milisecondsSinceRequest(m_requestTime);
}
-void ResourceHandle::didStartRequest()
+#if SOUP_CHECK_VERSION(2, 49, 91)
+static void startingCallback(SoupMessage*, ResourceHandle* handle)
{
- ResourceHandleInternal* d = getInternal();
- if (!d->m_response.resourceLoadTiming())
- return;
-
- d->m_response.resourceLoadTiming()->sendStart = milisecondsSinceRequest(d->m_response.resourceLoadTiming()->requestTime);
- if (d->m_response.resourceLoadTiming()->sslStart != -1) {
- // WebCore/inspector/front-end/RequestTimingView.js assumes
- // that SSL time is included in connection time so must
- // substract here the SSL delta that will be added later (see
- // WebInspector.RequestTimingView.createTimingTable in the
- // file above for more details).
- d->m_response.resourceLoadTiming()->sendStart -=
- d->m_response.resourceLoadTiming()->sslEnd - d->m_response.resourceLoadTiming()->sslStart;
- }
+ handle->didStartRequest();
}
+#endif // SOUP_CHECK_VERSION(2, 49, 91)
static void networkEventCallback(SoupMessage*, GSocketClientEvent event, GIOStream*, gpointer data)
{
@@ -891,43 +593,41 @@ static void networkEventCallback(SoupMessage*, GSocketClientEvent event, GIOStre
return;
ResourceHandleInternal* d = handle->getInternal();
- int deltaTime = milisecondsSinceRequest(d->m_response.resourceLoadTiming()->requestTime);
+ double deltaTime = milisecondsSinceRequest(handle->m_requestTime);
switch (event) {
case G_SOCKET_CLIENT_RESOLVING:
- d->m_response.resourceLoadTiming()->dnsStart = deltaTime;
+ d->m_response.networkLoadTiming().domainLookupStart = deltaTime;
break;
case G_SOCKET_CLIENT_RESOLVED:
- d->m_response.resourceLoadTiming()->dnsEnd = deltaTime;
+ d->m_response.networkLoadTiming().domainLookupEnd = deltaTime;
break;
case G_SOCKET_CLIENT_CONNECTING:
- d->m_response.resourceLoadTiming()->connectStart = deltaTime;
- if (d->m_response.resourceLoadTiming()->dnsStart != -1)
+ d->m_response.networkLoadTiming().connectStart = deltaTime;
+ if (d->m_response.networkLoadTiming().domainLookupStart != -1) {
// WebCore/inspector/front-end/RequestTimingView.js assumes
// that DNS time is included in connection time so must
// substract here the DNS delta that will be added later (see
// WebInspector.RequestTimingView.createTimingTable in the
// file above for more details).
- d->m_response.resourceLoadTiming()->connectStart -=
- d->m_response.resourceLoadTiming()->dnsEnd - d->m_response.resourceLoadTiming()->dnsStart;
+ d->m_response.networkLoadTiming().connectStart -=
+ d->m_response.networkLoadTiming().domainLookupEnd - d->m_response.networkLoadTiming().domainLookupStart;
+ }
break;
case G_SOCKET_CLIENT_CONNECTED:
// Web Timing considers that connection time involves dns, proxy & TLS negotiation...
// so we better pick G_SOCKET_CLIENT_COMPLETE for connectEnd
break;
case G_SOCKET_CLIENT_PROXY_NEGOTIATING:
- d->m_response.resourceLoadTiming()->proxyStart = deltaTime;
break;
case G_SOCKET_CLIENT_PROXY_NEGOTIATED:
- d->m_response.resourceLoadTiming()->proxyEnd = deltaTime;
break;
case G_SOCKET_CLIENT_TLS_HANDSHAKING:
- d->m_response.resourceLoadTiming()->sslStart = deltaTime;
+ d->m_response.networkLoadTiming().secureConnectionStart = deltaTime;
break;
case G_SOCKET_CLIENT_TLS_HANDSHAKED:
- d->m_response.resourceLoadTiming()->sslEnd = deltaTime;
break;
case G_SOCKET_CLIENT_COMPLETE:
- d->m_response.resourceLoadTiming()->connectEnd = deltaTime;
+ d->m_response.networkLoadTiming().connectEnd = deltaTime;
break;
default:
ASSERT_NOT_REACHED();
@@ -949,6 +649,7 @@ static bool createSoupMessageForHandleAndRequest(ResourceHandle* handle, const R
SoupMessage* soupMessage = d->m_soupMessage.get();
request.updateSoupMessage(soupMessage);
+ d->m_bodySize = soupMessage->request_body->length;
g_object_set_data(G_OBJECT(soupMessage), "handle", handle);
if (!handle->shouldContentSniff())
@@ -956,14 +657,6 @@ static bool createSoupMessageForHandleAndRequest(ResourceHandle* handle, const R
if (!d->m_useAuthenticationManager)
soup_message_disable_feature(soupMessage, SOUP_TYPE_AUTH_MANAGER);
- FormData* httpBody = request.httpBody();
- CString contentType = request.httpContentType().utf8().data();
- if (httpBody && !httpBody->isEmpty() && !addFormElementsToSoupMessage(soupMessage, contentType.data(), httpBody, d->m_bodySize)) {
- // We failed to prepare the body data, so just fail this load.
- d->m_soupMessage.clear();
- return false;
- }
-
// Make sure we have an Accept header for subresources; some sites
// want this to serve some of their subresources
if (!soup_message_headers_get_one(soupMessage->request_headers, "Accept"))
@@ -973,8 +666,7 @@ static bool createSoupMessageForHandleAndRequest(ResourceHandle* handle, const R
// for consistency with other backends (e.g. Chromium's) and other UA implementations like FF. It's done
// in the backend here instead of in XHR code since in XHR CORS checking prevents us from this kind of
// late header manipulation.
- if ((request.httpMethod() == "POST" || request.httpMethod() == "PUT")
- && (!request.httpBody() || request.httpBody()->isEmpty()))
+ if ((request.httpMethod() == "POST" || request.httpMethod() == "PUT") && !d->m_bodySize)
soup_message_headers_set_content_length(soupMessage->request_headers, 0);
g_signal_connect(d->m_soupMessage.get(), "notify::tls-errors", G_CALLBACK(tlsErrorsChangedCallback), handle);
@@ -982,19 +674,14 @@ static bool createSoupMessageForHandleAndRequest(ResourceHandle* handle, const R
g_signal_connect(d->m_soupMessage.get(), "wrote-body-data", G_CALLBACK(wroteBodyDataCallback), handle);
unsigned flags = SOUP_MESSAGE_NO_REDIRECT;
-#if SOUP_CHECK_VERSION(2, 49, 91)
- // Ignore the connection limits in synchronous loads to avoid freezing the networking process.
- // See https://bugs.webkit.org/show_bug.cgi?id=141508.
- if (loadingSynchronousRequest)
- flags |= SOUP_MESSAGE_IGNORE_CONNECTION_LIMITS;
-#endif
soup_message_set_flags(d->m_soupMessage.get(), static_cast<SoupMessageFlags>(soup_message_get_flags(d->m_soupMessage.get()) | flags));
#if ENABLE(WEB_TIMING)
- d->m_response.setResourceLoadTiming(ResourceLoadTiming::create());
+#if SOUP_CHECK_VERSION(2, 49, 91)
+ g_signal_connect(d->m_soupMessage.get(), "starting", G_CALLBACK(startingCallback), handle);
+#endif
g_signal_connect(d->m_soupMessage.get(), "network-event", G_CALLBACK(networkEventCallback), handle);
g_signal_connect(d->m_soupMessage.get(), "restarted", G_CALLBACK(restartedCallback), handle);
- g_signal_connect(d->m_soupMessage.get(), "wrote-body", G_CALLBACK(wroteBodyCallback), handle);
#endif
#if SOUP_CHECK_VERSION(2, 43, 1)
@@ -1004,7 +691,7 @@ static bool createSoupMessageForHandleAndRequest(ResourceHandle* handle, const R
return true;
}
-static bool createSoupRequestAndMessageForHandle(ResourceHandle* handle, const ResourceRequest& request, bool isHTTPFamilyRequest)
+static bool createSoupRequestAndMessageForHandle(ResourceHandle* handle, const ResourceRequest& request)
{
ResourceHandleInternal* d = handle->getInternal();
@@ -1020,7 +707,7 @@ static bool createSoupRequestAndMessageForHandle(ResourceHandle* handle, const R
}
// SoupMessages are only applicable to HTTP-family requests.
- if (isHTTPFamilyRequest && !createSoupMessageForHandleAndRequest(handle, request)) {
+ if (request.url().protocolIsInHTTPFamily() && !createSoupMessageForHandleAndRequest(handle, request)) {
d->m_soupRequest.clear();
return false;
}
@@ -1044,15 +731,14 @@ bool ResourceHandle::start()
// Only allow the POST and GET methods for non-HTTP requests.
const ResourceRequest& request = firstRequest();
- bool isHTTPFamilyRequest = request.url().protocolIsInHTTPFamily();
- if (!isHTTPFamilyRequest && request.httpMethod() != "GET" && request.httpMethod() != "POST") {
+ if (!request.url().protocolIsInHTTPFamily() && request.httpMethod() != "GET" && request.httpMethod() != "POST") {
this->scheduleFailure(InvalidURLFailure); // Error must not be reported immediately
return true;
}
applyAuthenticationToRequest(this, firstRequest(), false);
- if (!createSoupRequestAndMessageForHandle(this, request, isHTTPFamilyRequest)) {
+ if (!createSoupRequestAndMessageForHandle(this, request)) {
this->scheduleFailure(InvalidURLFailure); // Error must not be reported immediately
return true;
}
@@ -1064,19 +750,36 @@ bool ResourceHandle::start()
return true;
}
+RefPtr<ResourceHandle> ResourceHandle::releaseForDownload(ResourceHandleClient* downloadClient)
+{
+ // We don't adopt the ref, as it will be released by cleanupSoupRequestOperation, which should always run.
+ ResourceHandle* newHandle = new ResourceHandle(d->m_context.get(), firstRequest(), nullptr, d->m_defersLoading, d->m_shouldContentSniff);
+ newHandle->relaxAdoptionRequirement();
+ std::swap(d, newHandle->d);
+
+ g_signal_handlers_disconnect_matched(newHandle->d->m_soupMessage.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
+ g_object_set_data(G_OBJECT(newHandle->d->m_soupMessage.get()), "handle", newHandle);
+
+ newHandle->d->m_client = downloadClient;
+ continueAfterDidReceiveResponse(newHandle);
+
+ return newHandle;
+}
+
+void ResourceHandle::timeoutFired()
+{
+ client()->didFail(this, ResourceError::timeoutError(firstRequest().url()));
+ cancel();
+}
+
void ResourceHandle::sendPendingRequest()
{
#if ENABLE(WEB_TIMING)
- if (d->m_response.resourceLoadTiming())
- d->m_response.resourceLoadTiming()->requestTime = monotonicallyIncreasingTime();
+ m_requestTime = monotonicallyIncreasingTime();
#endif
- if (d->m_firstRequest.timeoutInterval() > 0) {
- // soup_add_timeout returns a GSource* whose only reference is owned by
- // the context. We need to have our own reference to it, hence not using adoptRef.
- d->m_timeoutSource = soup_add_timeout(g_main_context_get_thread_default(),
- d->m_firstRequest.timeoutInterval() * 1000, requestTimeoutCallback, this);
- }
+ if (d->m_firstRequest.timeoutInterval() > 0)
+ d->m_timeoutSource.startOneShot(d->m_firstRequest.timeoutInterval());
// Balanced by a deref() in cleanupSoupRequestOperation, which should always run.
ref();
@@ -1099,46 +802,21 @@ bool ResourceHandle::shouldUseCredentialStorage()
return (!client() || client()->shouldUseCredentialStorage(this)) && firstRequest().url().protocolIsInHTTPFamily();
}
-void ResourceHandle::setHostAllowsAnyHTTPSCertificate(const String& host)
-{
- allowsAnyHTTPSCertificateHosts().add(host.lower());
-}
-
-void ResourceHandle::setClientCertificate(const String& host, GTlsCertificate* certificate)
-{
- clientCertificates().add(host.lower(), HostTLSCertificateSet()).iterator->value.add(certificate);
-}
-
-void ResourceHandle::setIgnoreSSLErrors(bool ignoreSSLErrors)
-{
- gIgnoreSSLErrors = ignoreSSLErrors;
-}
-
-#if PLATFORM(GTK)
-void getCredentialFromPersistentStoreCallback(const Credential& credential, void* data)
-{
- static_cast<ResourceHandle*>(data)->continueDidReceiveAuthenticationChallenge(credential);
-}
-#endif
-
void ResourceHandle::continueDidReceiveAuthenticationChallenge(const Credential& credentialFromPersistentStorage)
{
ASSERT(!d->m_currentWebChallenge.isNull());
AuthenticationChallenge& challenge = d->m_currentWebChallenge;
- ASSERT(challenge.soupSession());
- ASSERT(challenge.soupMessage());
+ ASSERT(d->m_soupMessage);
if (!credentialFromPersistentStorage.isEmpty())
challenge.setProposedCredential(credentialFromPersistentStorage);
if (!client()) {
- soup_session_unpause_message(challenge.soupSession(), challenge.soupMessage());
+ soup_session_unpause_message(d->soupSession(), d->m_soupMessage.get());
clearAuthentication();
return;
}
- ASSERT(challenge.soupSession());
- ASSERT(challenge.soupMessage());
client()->didReceiveAuthenticationChallenge(this, challenge);
}
@@ -1146,6 +824,8 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall
{
ASSERT(d->m_currentWebChallenge.isNull());
+ String partition = firstRequest().cachePartition();
+
// FIXME: Per the specification, the user shouldn't be asked for credentials if there were incorrect ones provided explicitly.
bool useCredentialStorage = shouldUseCredentialStorage();
if (useCredentialStorage) {
@@ -1153,17 +833,17 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall
// The stored credential wasn't accepted, stop using it. There is a race condition
// here, since a different credential might have already been stored by another
// ResourceHandle, but the observable effect should be very minor, if any.
- CredentialStorage::remove(challenge.protectionSpace());
+ CredentialStorage::defaultCredentialStorage().remove(partition, challenge.protectionSpace());
}
if (!challenge.previousFailureCount()) {
- Credential credential = CredentialStorage::get(challenge.protectionSpace());
+ Credential credential = CredentialStorage::defaultCredentialStorage().get(partition, challenge.protectionSpace());
if (!credential.isEmpty() && credential != d->m_initialCredential) {
ASSERT(credential.persistence() == CredentialPersistenceNone);
// Store the credential back, possibly adding it as a default for this directory.
if (isAuthenticationFailureStatusCode(challenge.failureResponse().httpStatusCode()))
- CredentialStorage::set(credential, challenge.protectionSpace(), challenge.failureResponse().url());
+ CredentialStorage::defaultCredentialStorage().set(partition, credential, challenge.protectionSpace(), challenge.failureResponse().url());
soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data());
return;
@@ -1172,18 +852,18 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall
}
d->m_currentWebChallenge = challenge;
- soup_session_pause_message(challenge.soupSession(), challenge.soupMessage());
+ soup_session_pause_message(d->soupSession(), d->m_soupMessage.get());
-#if PLATFORM(GTK)
// We could also do this before we even start the request, but that would be at the expense
// of all request latency, versus a one-time latency for the small subset of requests that
// use HTTP authentication. In the end, this doesn't matter much, because persistent credentials
// will become session credentials after the first use.
- if (useCredentialStorage) {
- credentialBackingStore().credentialForChallenge(challenge, getCredentialFromPersistentStoreCallback, this);
+ if (useCredentialStorage && d->m_context && d->m_context->isValid()) {
+ d->m_context->storageSession().getCredentialFromPersistentStorage(challenge.protectionSpace(), [this, protectedThis = makeRef(*this)] (Credential&& credential) {
+ continueDidReceiveAuthenticationChallenge(WTFMove(credential));
+ });
return;
}
-#endif
continueDidReceiveAuthenticationChallenge(Credential());
}
@@ -1193,7 +873,7 @@ void ResourceHandle::receivedRequestToContinueWithoutCredential(const Authentica
ASSERT(!challenge.isNull());
if (challenge != d->m_currentWebChallenge)
return;
- soup_session_unpause_message(challenge.soupSession(), challenge.soupMessage());
+ soup_session_unpause_message(d->soupSession(), d->m_soupMessage.get());
clearAuthentication();
}
@@ -1210,26 +890,25 @@ void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge
return;
}
+ String partition = firstRequest().cachePartition();
+
if (shouldUseCredentialStorage()) {
// Eventually we will manage per-session credentials only internally or use some newly-exposed API from libsoup,
// because once we authenticate via libsoup, there is no way to ignore it for a particular request. Right now,
// we place the credentials in the store even though libsoup will never fire the authenticate signal again for
// this protection space.
if (credential.persistence() == CredentialPersistenceForSession || credential.persistence() == CredentialPersistencePermanent)
- CredentialStorage::set(credential, challenge.protectionSpace(), challenge.failureResponse().url());
+ CredentialStorage::defaultCredentialStorage().set(partition, credential, challenge.protectionSpace(), challenge.failureResponse().url());
-#if PLATFORM(GTK)
if (credential.persistence() == CredentialPersistencePermanent) {
d->m_credentialDataToSaveInPersistentStore.credential = credential;
- d->m_credentialDataToSaveInPersistentStore.challenge = challenge;
+ d->m_credentialDataToSaveInPersistentStore.protectionSpace = challenge.protectionSpace();
}
-#endif
}
- ASSERT(challenge.soupSession());
- ASSERT(challenge.soupMessage());
+ ASSERT(d->m_soupMessage);
soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data());
- soup_session_unpause_message(challenge.soupSession(), challenge.soupMessage());
+ soup_session_unpause_message(d->soupSession(), d->m_soupMessage.get());
clearAuthentication();
}
@@ -1245,9 +924,8 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen
return;
}
- ASSERT(challenge.soupSession());
- ASSERT(challenge.soupMessage());
- soup_session_unpause_message(challenge.soupSession(), challenge.soupMessage());
+ ASSERT(d->m_soupMessage);
+ soup_session_unpause_message(d->soupSession(), d->m_soupMessage.get());
if (client())
client()->receivedCancellation(this, challenge);
@@ -1255,6 +933,18 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen
clearAuthentication();
}
+void ResourceHandle::receivedRequestToPerformDefaultHandling(const AuthenticationChallenge&)
+{
+ ASSERT_NOT_REACHED();
+}
+
+void ResourceHandle::receivedChallengeRejection(const AuthenticationChallenge& challenge)
+{
+ // This is only used by layout tests, soup based ports don't implement this.
+ notImplemented();
+ receivedRequestToContinueWithoutCredential(challenge);
+}
+
static bool waitingToSendRequest(ResourceHandle* handle)
{
// We need to check for d->m_soupRequest because the request may have raised a failure
@@ -1270,10 +960,7 @@ void ResourceHandle::platformSetDefersLoading(bool defersLoading)
// Except when canceling a possible timeout timer, we only need to take action here to UN-defer loading.
if (defersLoading) {
- if (d->m_timeoutSource) {
- g_source_destroy(d->m_timeoutSource.get());
- d->m_timeoutSource.clear();
- }
+ d->m_timeoutSource.stop();
return;
}
@@ -1292,27 +979,9 @@ void ResourceHandle::platformSetDefersLoading(bool defersLoading)
}
}
-bool ResourceHandle::loadsBlocked()
+void ResourceHandle::platformLoadResourceSynchronously(NetworkingContext*, const ResourceRequest&, StoredCredentials, ResourceError&, ResourceResponse&, Vector<char>&)
{
- return false;
-}
-
-void ResourceHandle::platformLoadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
-{
- ASSERT(!loadingSynchronousRequest);
- if (loadingSynchronousRequest) // In practice this cannot happen, but if for some reason it does,
- return; // we want to avoid accidentally going into an infinite loop of requests.
-
- WebCoreSynchronousLoader syncLoader(error, response, sessionFromContext(context), data, storedCredentials);
- RefPtr<ResourceHandle> handle = create(context, request, &syncLoader, false /*defersLoading*/, false /*shouldContentSniff*/);
- if (!handle)
- return;
-
- // If the request has already failed, do not run the main loop, or else we'll block indefinitely.
- if (handle->d->m_scheduledFailureType != NoFailure)
- return;
-
- syncLoader.run();
+ ASSERT_NOT_REACHED();
}
static void readCallback(GObject*, GAsyncResult* asyncResult, gpointer data)
@@ -1378,34 +1047,18 @@ static void readCallback(GObject*, GAsyncResult* asyncResult, gpointer data)
d->m_cancellable.get(), readCallback, handle.get());
}
-void ResourceHandle::continueWillSendRequest(const ResourceRequest& request)
+void ResourceHandle::continueWillSendRequest(ResourceRequest&& request)
{
- ASSERT(client());
- ASSERT(client()->usesAsyncCallbacks());
- continueAfterWillSendRequest(this, request);
+ ASSERT(!client() || client()->usesAsyncCallbacks());
+ continueAfterWillSendRequest(this, WTFMove(request));
}
void ResourceHandle::continueDidReceiveResponse()
{
- ASSERT(client());
- ASSERT(client()->usesAsyncCallbacks());
+ ASSERT(!client() || client()->usesAsyncCallbacks());
continueAfterDidReceiveResponse(this);
}
-void ResourceHandle::continueShouldUseCredentialStorage(bool)
-{
- ASSERT(client());
- ASSERT(client()->usesAsyncCallbacks());
- // FIXME: Implement this method if needed: https://bugs.webkit.org/show_bug.cgi?id=126114.
}
-static gboolean requestTimeoutCallback(gpointer data)
-{
- RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
- handle->client()->didFail(handle.get(), ResourceError::timeoutError(handle->getInternal()->m_firstRequest.url().string()));
- handle->cancel();
-
- return FALSE;
-}
-
-}
+#endif
diff --git a/Source/WebCore/platform/network/soup/ResourceRequest.h b/Source/WebCore/platform/network/soup/ResourceRequest.h
index 45b1ce880..04d5d4841 100644
--- a/Source/WebCore/platform/network/soup/ResourceRequest.h
+++ b/Source/WebCore/platform/network/soup/ResourceRequest.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2003, 2006 Apple Inc. All rights reserved.
* Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -86,7 +86,7 @@ namespace WebCore {
updateFromSoupRequest(soupRequest);
}
- void updateFromDelegatePreservingOldHTTPBody(const ResourceRequest& delegateProvidedRequest) { *this = delegateProvidedRequest; }
+ void updateFromDelegatePreservingOldProperties(const ResourceRequest& delegateProvidedRequest) { *this = delegateProvidedRequest; }
bool acceptEncoding() const { return m_acceptEncoding; }
void setAcceptEncoding(bool acceptEncoding) { m_acceptEncoding = acceptEncoding; }
@@ -94,7 +94,6 @@ namespace WebCore {
void updateSoupMessageHeaders(SoupMessageHeaders*) const;
void updateFromSoupMessageHeaders(SoupMessageHeaders*);
void updateSoupMessage(SoupMessage*) const;
- SoupMessage* toSoupMessage() const;
void updateFromSoupMessage(SoupMessage*);
void updateSoupRequest(SoupRequest*) const;
void updateFromSoupRequest(SoupRequest*);
@@ -107,6 +106,9 @@ namespace WebCore {
GUniquePtr<SoupURI> createSoupURI() const;
+ template<class Encoder> void encodeWithPlatformData(Encoder&) const;
+ template<class Decoder> bool decodeWithPlatformData(Decoder&);
+
private:
friend class ResourceRequestBase;
@@ -115,33 +117,74 @@ namespace WebCore {
uint64_t m_initiatingPageID;
void updateSoupMessageMembers(SoupMessage*) const;
+ void updateSoupMessageBody(SoupMessage*) const;
void doUpdatePlatformRequest() { }
void doUpdateResourceRequest() { }
void doUpdatePlatformHTTPBody() { }
void doUpdateResourceHTTPBody() { }
- PassOwnPtr<CrossThreadResourceRequestData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceRequestData> data) const { return data; }
- void doPlatformAdopt(PassOwnPtr<CrossThreadResourceRequestData>) { }
+ void doPlatformSetAsIsolatedCopy(const ResourceRequest&) { }
};
- struct CrossThreadResourceRequestData : public CrossThreadResourceRequestDataBase {
- };
+template<class Encoder>
+void ResourceRequest::encodeWithPlatformData(Encoder& encoder) const
+{
+ encodeBase(encoder);
+
+ // FIXME: Do not encode HTTP message body.
+ // 1. It can be large and thus costly to send across.
+ // 2. It is misleading to provide a body with some requests, while others use body streams, which cannot be serialized at all.
+ encoder << static_cast<bool>(m_httpBody);
+ if (m_httpBody)
+ encoder << m_httpBody->flattenToString();
+
+ encoder << static_cast<uint32_t>(m_soupFlags);
+ encoder << m_initiatingPageID;
+}
+
+template<class Decoder>
+bool ResourceRequest::decodeWithPlatformData(Decoder& decoder)
+{
+ if (!decodeBase(decoder))
+ return false;
+
+ bool hasHTTPBody;
+ if (!decoder.decode(hasHTTPBody))
+ return false;
+ if (hasHTTPBody) {
+ String httpBody;
+ if (!decoder.decode(httpBody))
+ return false;
+ setHTTPBody(FormData::create(httpBody.utf8()));
+ }
+
+ uint32_t soupMessageFlags;
+ if (!decoder.decode(soupMessageFlags))
+ return false;
+ m_soupFlags = static_cast<SoupMessageFlags>(soupMessageFlags);
+
+ uint64_t initiatingPageID;
+ if (!decoder.decode(initiatingPageID))
+ return false;
+ m_initiatingPageID = initiatingPageID;
+
+ return true;
+}
+
#if SOUP_CHECK_VERSION(2, 43, 1)
inline SoupMessagePriority toSoupMessagePriority(ResourceLoadPriority priority)
{
switch (priority) {
- case ResourceLoadPriorityUnresolved:
- return SOUP_MESSAGE_PRIORITY_NORMAL;
- case ResourceLoadPriorityVeryLow:
+ case ResourceLoadPriority::VeryLow:
return SOUP_MESSAGE_PRIORITY_VERY_LOW;
- case ResourceLoadPriorityLow:
+ case ResourceLoadPriority::Low:
return SOUP_MESSAGE_PRIORITY_LOW;
- case ResourceLoadPriorityMedium:
+ case ResourceLoadPriority::Medium:
return SOUP_MESSAGE_PRIORITY_NORMAL;
- case ResourceLoadPriorityHigh:
+ case ResourceLoadPriority::High:
return SOUP_MESSAGE_PRIORITY_HIGH;
- case ResourceLoadPriorityVeryHigh:
+ case ResourceLoadPriority::VeryHigh:
return SOUP_MESSAGE_PRIORITY_VERY_HIGH;
}
diff --git a/Source/WebCore/platform/network/soup/ResourceRequestSoup.cpp b/Source/WebCore/platform/network/soup/ResourceRequestSoup.cpp
index cadb84b29..64578615c 100644
--- a/Source/WebCore/platform/network/soup/ResourceRequestSoup.cpp
+++ b/Source/WebCore/platform/network/soup/ResourceRequestSoup.cpp
@@ -18,16 +18,82 @@
*/
#include "config.h"
+
+#if USE(SOUP)
#include "ResourceRequest.h"
+#include "BlobData.h"
+#include "BlobRegistryImpl.h"
#include "GUniquePtrSoup.h"
#include "HTTPParsers.h"
#include "MIMETypeRegistry.h"
+#include "SharedBuffer.h"
+#include "WebKitSoupRequestGeneric.h"
#include <wtf/text/CString.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
+static uint64_t appendEncodedBlobItemToSoupMessageBody(SoupMessage* soupMessage, const BlobDataItem& blobItem)
+{
+ switch (blobItem.type()) {
+ case BlobDataItem::Type::Data:
+ soup_message_body_append(soupMessage->request_body, SOUP_MEMORY_TEMPORARY, blobItem.data().data()->data() + blobItem.offset(), blobItem.length());
+ return blobItem.length();
+ case BlobDataItem::Type::File: {
+ if (!isValidFileTime(blobItem.file()->expectedModificationTime()))
+ return 0;
+
+ time_t fileModificationTime;
+ if (!getFileModificationTime(blobItem.file()->path(), fileModificationTime)
+ || fileModificationTime != static_cast<time_t>(blobItem.file()->expectedModificationTime()))
+ return 0;
+
+ if (RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(blobItem.file()->path())) {
+ GUniquePtr<SoupBuffer> soupBuffer(buffer->createSoupBuffer(blobItem.offset(), blobItem.length() == BlobDataItem::toEndOfFile ? 0 : blobItem.length()));
+ soup_message_body_append_buffer(soupMessage->request_body, soupBuffer.get());
+ return soupBuffer->length;
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void ResourceRequest::updateSoupMessageBody(SoupMessage* soupMessage) const
+{
+ auto* formData = httpBody();
+ if (!formData || formData->isEmpty())
+ return;
+
+ soup_message_body_set_accumulate(soupMessage->request_body, FALSE);
+ uint64_t bodySize = 0;
+ for (const auto& element : formData->elements()) {
+ switch (element.m_type) {
+ case FormDataElement::Type::Data:
+ bodySize += element.m_data.size();
+ soup_message_body_append(soupMessage->request_body, SOUP_MEMORY_TEMPORARY, element.m_data.data(), element.m_data.size());
+ break;
+ case FormDataElement::Type::EncodedFile:
+ if (RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(element.m_filename)) {
+ GUniquePtr<SoupBuffer> soupBuffer(buffer->createSoupBuffer());
+ bodySize += buffer->size();
+ soup_message_body_append_buffer(soupMessage->request_body, soupBuffer.get());
+ }
+ break;
+ case FormDataElement::Type::EncodedBlob:
+ if (auto* blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(element.m_url)) {
+ for (const auto& item : blobData->items())
+ bodySize += appendEncodedBlobItemToSoupMessageBody(soupMessage, item);
+ }
+ break;
+ }
+ }
+
+ ASSERT(bodySize == static_cast<uint64_t>(soupMessage->request_body->length));
+}
+
void ResourceRequest::updateSoupMessageMembers(SoupMessage* soupMessage) const
{
updateSoupMessageHeaders(soupMessage->request_headers);
@@ -50,7 +116,7 @@ void ResourceRequest::updateSoupMessageHeaders(SoupMessageHeaders* soupHeaders)
if (!headers.isEmpty()) {
HTTPHeaderMap::const_iterator end = headers.end();
for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it)
- soup_message_headers_append(soupHeaders, it->key.string().utf8().data(), it->value.utf8().data());
+ soup_message_headers_append(soupHeaders, it->key.utf8().data(), it->value.utf8().data());
}
}
@@ -73,25 +139,12 @@ void ResourceRequest::updateSoupMessage(SoupMessage* soupMessage) const
soup_message_set_uri(soupMessage, uri.get());
updateSoupMessageMembers(soupMessage);
-}
-
-SoupMessage* ResourceRequest::toSoupMessage() const
-{
- SoupMessage* soupMessage = soup_message_new(httpMethod().ascii().data(), url().string().utf8().data());
- if (!soupMessage)
- return 0;
-
- updateSoupMessageMembers(soupMessage);
-
- // Body data is only handled at ResourceHandleSoup::startHttp for
- // now; this is because this may not be a good place to go
- // openning and mmapping files. We should maybe revisit this.
- return soupMessage;
+ updateSoupMessageBody(soupMessage);
}
void ResourceRequest::updateFromSoupMessage(SoupMessage* soupMessage)
{
- bool shouldPortBeResetToZero = m_url.hasPort() && !m_url.port();
+ bool shouldPortBeResetToZero = m_url.port() && !m_url.port().value();
m_url = URL(soup_message_get_uri(soupMessage));
// SoupURI cannot differeniate between an explicitly specified port 0 and
@@ -119,12 +172,14 @@ static const char* gSoupRequestInitiatingPageIDKey = "wk-soup-request-initiating
void ResourceRequest::updateSoupRequest(SoupRequest* soupRequest) const
{
- if (!m_initiatingPageID)
- return;
+ if (m_initiatingPageID) {
+ uint64_t* initiatingPageIDPtr = static_cast<uint64_t*>(fastMalloc(sizeof(uint64_t)));
+ *initiatingPageIDPtr = m_initiatingPageID;
+ g_object_set_data_full(G_OBJECT(soupRequest), g_intern_static_string(gSoupRequestInitiatingPageIDKey), initiatingPageIDPtr, fastFree);
+ }
- uint64_t* initiatingPageIDPtr = static_cast<uint64_t*>(fastMalloc(sizeof(uint64_t)));
- *initiatingPageIDPtr = m_initiatingPageID;
- g_object_set_data_full(G_OBJECT(soupRequest), g_intern_static_string(gSoupRequestInitiatingPageIDKey), initiatingPageIDPtr, fastFree);
+ if (WEBKIT_IS_SOUP_REQUEST_GENERIC(soupRequest))
+ webkitSoupRequestGenericSetRequest(WEBKIT_SOUP_REQUEST_GENERIC(soupRequest), *this);
}
void ResourceRequest::updateFromSoupRequest(SoupRequest* soupRequest)
@@ -153,13 +208,7 @@ GUniquePtr<SoupURI> ResourceRequest::createSoupURI() const
return GUniquePtr<SoupURI>(soup_uri_new(urlString.utf8().data()));
}
- GUniquePtr<SoupURI> soupURI;
- if (m_url.hasFragmentIdentifier()) {
- URL url = m_url;
- url.removeFragmentIdentifier();
- soupURI.reset(soup_uri_new(url.string().utf8().data()));
- } else
- soupURI = m_url.createSoupURI();
+ GUniquePtr<SoupURI> soupURI = m_url.createSoupURI();
// Versions of libsoup prior to 2.42 have a soup_uri_new that will convert empty passwords that are not
// prefixed by a colon into null. Some parts of soup like the SoupAuthenticationManager will only be active
@@ -176,3 +225,5 @@ GUniquePtr<SoupURI> ResourceRequest::createSoupURI() const
}
}
+
+#endif
diff --git a/Source/WebCore/platform/network/soup/ResourceResponse.h b/Source/WebCore/platform/network/soup/ResourceResponse.h
index 4891f935f..9e206bba9 100644
--- a/Source/WebCore/platform/network/soup/ResourceResponse.h
+++ b/Source/WebCore/platform/network/soup/ResourceResponse.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,13 +23,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceResponse_h
-#define ResourceResponse_h
+#pragma once
#include "ResourceResponseBase.h"
#include <libsoup/soup.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
namespace WebCore {
@@ -42,8 +41,8 @@ public:
{
}
- ResourceResponse(const URL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename)
- : ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename)
+ ResourceResponse(const URL& url, const String& mimeType, long long expectedLength, const String& textEncodingName)
+ : ResourceResponseBase(url, mimeType, expectedLength, textEncodingName)
, m_soupFlags(static_cast<SoupMessageFlags>(0))
, m_tlsErrors(static_cast<GTlsCertificateFlags>(0))
{
@@ -57,7 +56,7 @@ public:
updateFromSoupMessage(soupMessage);
}
- SoupMessage* toSoupMessage() const;
+ void updateSoupMessageHeaders(SoupMessageHeaders*) const;
void updateFromSoupMessage(SoupMessage*);
void updateFromSoupMessageHeaders(const SoupMessageHeaders*);
@@ -73,7 +72,8 @@ public:
GTlsCertificateFlags soupMessageTLSErrors() const { return m_tlsErrors; }
void setSoupMessageTLSErrors(GTlsCertificateFlags tlsErrors) { m_tlsErrors = tlsErrors; }
- bool platformResponseIsUpToDate() const { return false; }
+ template<class Encoder> void encode(Encoder&) const;
+ template<class Decoder> static bool decode(Decoder&, ResourceResponse&);
private:
friend class ResourceResponseBase;
@@ -84,14 +84,25 @@ private:
GTlsCertificateFlags m_tlsErrors;
void doUpdateResourceResponse() { }
-
- PassOwnPtr<CrossThreadResourceResponseData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceResponseData> data) const { return data; }
- void doPlatformAdopt(PassOwnPtr<CrossThreadResourceResponseData>) { }
+ String platformSuggestedFilename() const;
+ CertificateInfo platformCertificateInfo() const;
};
-struct CrossThreadResourceResponseData : public CrossThreadResourceResponseDataBase {
-};
+template<class Encoder>
+void ResourceResponse::encode(Encoder& encoder) const
+{
+ ResourceResponseBase::encode(encoder);
+ encoder.encodeEnum(m_soupFlags);
+}
+
+template<class Decoder>
+bool ResourceResponse::decode(Decoder& decoder, ResourceResponse& response)
+{
+ if (!ResourceResponseBase::decode(decoder, response))
+ return false;
+ if (!decoder.decodeEnum(response.m_soupFlags))
+ return false;
+ return true;
+}
} // namespace WebCore
-
-#endif // ResourceResponse_h
diff --git a/Source/WebCore/platform/network/soup/ResourceResponseSoup.cpp b/Source/WebCore/platform/network/soup/ResourceResponseSoup.cpp
index a7a8fa435..50cfa3e6e 100644
--- a/Source/WebCore/platform/network/soup/ResourceResponseSoup.cpp
+++ b/Source/WebCore/platform/network/soup/ResourceResponseSoup.cpp
@@ -19,45 +19,37 @@
*/
#include "config.h"
+
+#if USE(SOUP)
+
#include "ResourceResponse.h"
+#include "HTTPHeaderNames.h"
#include "HTTPParsers.h"
#include "MIMETypeRegistry.h"
#include <wtf/text/CString.h>
-#include <wtf/text/StringBuilder.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
-SoupMessage* ResourceResponse::toSoupMessage() const
+void ResourceResponse::updateSoupMessageHeaders(SoupMessageHeaders* soupHeaders) const
{
- // This GET here is just because SoupMessage wants it, we dn't really know.
- SoupMessage* soupMessage = soup_message_new("GET", url().string().utf8().data());
- if (!soupMessage)
- return 0;
-
- soupMessage->status_code = httpStatusCode();
-
- const HTTPHeaderMap& headers = httpHeaderFields();
- SoupMessageHeaders* soupHeaders = soupMessage->response_headers;
- if (!headers.isEmpty()) {
- HTTPHeaderMap::const_iterator end = headers.end();
- for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it)
- soup_message_headers_append(soupHeaders, it->key.string().utf8().data(), it->value.utf8().data());
- }
-
- soup_message_set_flags(soupMessage, m_soupFlags);
-
- g_object_set(G_OBJECT(soupMessage), "tls-certificate", m_certificate.get(), "tls-errors", m_tlsErrors, NULL);
-
- // Body data is not in the message.
- return soupMessage;
+ for (const auto& header : httpHeaderFields())
+ soup_message_headers_append(soupHeaders, header.key.utf8().data(), header.value.utf8().data());
}
void ResourceResponse::updateFromSoupMessage(SoupMessage* soupMessage)
{
m_url = URL(soup_message_get_uri(soupMessage));
+ switch (soup_message_get_http_version(soupMessage)) {
+ case SOUP_HTTP_1_0:
+ m_httpVersion = AtomicString("HTTP/1.0", AtomicString::ConstructFromLiteral);
+ break;
+ case SOUP_HTTP_1_1:
+ m_httpVersion = AtomicString("HTTP/1.1", AtomicString::ConstructFromLiteral);
+ break;
+ }
m_httpStatusCode = soupMessage->status_code;
setHTTPStatusText(soupMessage->reason_phrase);
@@ -95,6 +87,19 @@ void ResourceResponse::updateFromSoupMessageHeaders(const SoupMessageHeaders* me
setTextEncodingName(extractCharsetFromMediaType(contentType));
setExpectedContentLength(soup_message_headers_get_content_length(headers));
- setSuggestedFilename(filenameFromHTTPContentDisposition(httpHeaderField("Content-Disposition")));}
+}
+CertificateInfo ResourceResponse::platformCertificateInfo() const
+{
+ return CertificateInfo(m_certificate.get(), m_tlsErrors);
+}
+
+String ResourceResponse::platformSuggestedFilename() const
+{
+ String contentDisposition(httpHeaderField(HTTPHeaderName::ContentDisposition));
+ return filenameFromHTTPContentDisposition(String::fromUTF8WithLatin1Fallback(contentDisposition.characters8(), contentDisposition.length()));
}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/network/soup/SocketStreamError.h b/Source/WebCore/platform/network/soup/SocketStreamError.h
deleted file mode 100644
index 0676893ce..000000000
--- a/Source/WebCore/platform/network/soup/SocketStreamError.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2009, 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SocketStreamError_h
-#define SocketStreamError_h
-
-#include "SocketStreamErrorBase.h"
-
-namespace WebCore {
-
- class SocketStreamError : public SocketStreamErrorBase {
- public:
- SocketStreamError() { }
- SocketStreamError(int errorCode, const gchar* description)
- : SocketStreamErrorBase(errorCode, String(), String(description))
- {
- }
-
- };
-
-} // namespace WebCore
-
-#endif // SocketStreamError_h
diff --git a/Source/WebCore/platform/network/soup/SocketStreamHandle.h b/Source/WebCore/platform/network/soup/SocketStreamHandle.h
deleted file mode 100644
index fa0168805..000000000
--- a/Source/WebCore/platform/network/soup/SocketStreamHandle.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2009 Google Inc. All rights reserved.
- * Copyright (C) 2012 Samsung Electronics Ltd. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SocketStreamHandle_h
-#define SocketStreamHandle_h
-
-#include "SocketStreamHandleBase.h"
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/gobject/GRefPtr.h>
-
-namespace WebCore {
-
- class AuthenticationChallenge;
- class Credential;
- class SocketStreamHandleClient;
-
- class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase {
- public:
- static PassRefPtr<SocketStreamHandle> create(const URL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); }
- static PassRefPtr<SocketStreamHandle> create(GSocketConnection* socketConnection, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(socketConnection, client)); }
-
- virtual ~SocketStreamHandle();
- void connected(GSocketConnection*, GError*);
- void readBytes(signed long, GError*);
- void writeReady();
- void* id() { return m_id; }
-
- protected:
- virtual int platformSend(const char* data, int length);
- virtual void platformClose();
-
- private:
- GRefPtr<GSocketConnection> m_socketConnection;
- GRefPtr<GInputStream> m_inputStream;
- GRefPtr<GPollableOutputStream> m_outputStream;
- GRefPtr<GSource> m_writeReadySource;
- std::unique_ptr<char[]> m_readBuffer;
- void* m_id;
-
- SocketStreamHandle(const URL&, SocketStreamHandleClient*);
- SocketStreamHandle(GSocketConnection*, SocketStreamHandleClient*);
-
- // No authentication for streams per se, but proxy may ask for credentials.
- void didReceiveAuthenticationChallenge(const AuthenticationChallenge&);
- void receivedCredential(const AuthenticationChallenge&, const Credential&);
- void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&);
- void receivedCancellation(const AuthenticationChallenge&);
- void beginWaitingForSocketWritability();
- void stopWaitingForSocketWritability();
- };
-
-} // namespace WebCore
-
-#endif // SocketStreamHandle_h
diff --git a/Source/WebCore/platform/network/SocketStreamErrorBase.h b/Source/WebCore/platform/network/soup/SocketStreamHandleImpl.h
index 132063f2b..0459e907e 100644
--- a/Source/WebCore/platform/network/SocketStreamErrorBase.h
+++ b/Source/WebCore/platform/network/soup/SocketStreamHandleImpl.h
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2009 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2012 Samsung Electronics Ltd. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -29,58 +30,54 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SocketStreamErrorBase_h
-#define SocketStreamErrorBase_h
+#pragma once
-#include <wtf/text/WTFString.h>
+#include "SocketStreamHandle.h"
-namespace WebCore {
+#if USE(SOUP)
+
+#include "SessionID.h"
+#include <wtf/RefCounted.h>
+#include <wtf/glib/GRefPtr.h>
- class SocketStreamError;
+namespace WebCore {
- class SocketStreamErrorBase {
- public:
- // Makes a deep copy. Useful for when you need to use a SocketStreamError on another thread.
- SocketStreamError copy() const;
+class SocketStreamError;
+class SocketStreamHandleClient;
- bool isNull() const { return m_isNull; }
+class SocketStreamHandleImpl final : public SocketStreamHandle {
+public:
+ static Ref<SocketStreamHandleImpl> create(const URL&, SocketStreamHandleClient&, SessionID, const String&);
+ static Ref<SocketStreamHandle> create(GSocketConnection*, SocketStreamHandleClient&);
- int errorCode() const { return m_errorCode; }
- const String& failingURL() const { return m_failingURL; }
- const String& localizedDescription() const { return m_localizedDescription; }
+ virtual ~SocketStreamHandleImpl();
- static bool compare(const SocketStreamError&, const SocketStreamError&);
+private:
+ SocketStreamHandleImpl(const URL&, SocketStreamHandleClient&);
- protected:
- SocketStreamErrorBase()
- : m_errorCode(0)
- , m_isNull(true)
- {
- }
+ std::optional<size_t> platformSend(const char* data, size_t length) final;
+ void platformClose() final;
- explicit SocketStreamErrorBase(int errorCode)
- : m_errorCode(errorCode)
- , m_isNull(false)
- {
- }
+ void beginWaitingForSocketWritability();
+ void stopWaitingForSocketWritability();
- SocketStreamErrorBase(int errorCode, const String& failingURL, const String& localizedDescription)
- : m_errorCode(errorCode)
- , m_failingURL(failingURL)
- , m_localizedDescription(localizedDescription)
- , m_isNull(false)
- {
- }
+ static void connectedCallback(GSocketClient*, GAsyncResult*, SocketStreamHandleImpl*);
+ static void readReadyCallback(GInputStream*, GAsyncResult*, SocketStreamHandleImpl*);
+ static gboolean writeReadyCallback(GPollableOutputStream*, SocketStreamHandleImpl*);
- int m_errorCode;
- String m_failingURL;
- String m_localizedDescription;
- bool m_isNull;
- };
+ void connected(GRefPtr<GSocketConnection>&&);
+ void readBytes(gssize);
+ void didFail(SocketStreamError&&);
+ void writeReady();
- inline bool operator==(const SocketStreamError& a, const SocketStreamError& b) { return SocketStreamErrorBase::compare(a, b); }
- inline bool operator!=(const SocketStreamError& a, const SocketStreamError& b) { return !(a == b); }
+ GRefPtr<GSocketConnection> m_socketConnection;
+ GRefPtr<GInputStream> m_inputStream;
+ GRefPtr<GPollableOutputStream> m_outputStream;
+ GRefPtr<GSource> m_writeReadySource;
+ GRefPtr<GCancellable> m_cancellable;
+ std::unique_ptr<char[]> m_readBuffer;
+};
-} // namespace WebCore
+} // namespace WebCore
-#endif // SocketStreamErrorBase_h
+#endif
diff --git a/Source/WebCore/platform/network/soup/SocketStreamHandleImplSoup.cpp b/Source/WebCore/platform/network/soup/SocketStreamHandleImplSoup.cpp
new file mode 100644
index 000000000..20d19e3b1
--- /dev/null
+++ b/Source/WebCore/platform/network/soup/SocketStreamHandleImplSoup.cpp
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2009, 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2012 Samsung Electronics Ltd. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SocketStreamHandleImpl.h"
+
+#if USE(SOUP)
+
+#include "Logging.h"
+#include "Settings.h"
+#include "SocketStreamError.h"
+#include "SocketStreamHandleClient.h"
+#include "URL.h"
+#include <gio/gio.h>
+#include <glib.h>
+#include <wtf/Vector.h>
+#include <wtf/glib/GUniquePtr.h>
+#include <wtf/text/CString.h>
+
+#define READ_BUFFER_SIZE 1024
+
+namespace WebCore {
+
+static gboolean wssConnectionAcceptCertificateCallback(GTlsConnection*, GTlsCertificate*, GTlsCertificateFlags)
+{
+ return TRUE;
+}
+
+static void wssSocketClientEventCallback(GSocketClient*, GSocketClientEvent event, GSocketConnectable*, GIOStream* connection)
+{
+ if (event != G_SOCKET_CLIENT_TLS_HANDSHAKING)
+ return;
+
+ g_signal_connect(connection, "accept-certificate", G_CALLBACK(wssConnectionAcceptCertificateCallback), nullptr);
+}
+
+Ref<SocketStreamHandleImpl> SocketStreamHandleImpl::create(const URL& url, SocketStreamHandleClient& client, SessionID, const String&)
+{
+ Ref<SocketStreamHandleImpl> socket = adoptRef(*new SocketStreamHandleImpl(url, client));
+
+ unsigned port = url.port() ? url.port().value() : (url.protocolIs("wss") ? 443 : 80);
+ GRefPtr<GSocketClient> socketClient = adoptGRef(g_socket_client_new());
+ if (url.protocolIs("wss")) {
+ g_socket_client_set_tls(socketClient.get(), TRUE);
+ // FIXME: this is only used by tests, but using Settings from here is a layering violation.
+ if (Settings::allowsAnySSLCertificate())
+ g_signal_connect(socketClient.get(), "event", G_CALLBACK(wssSocketClientEventCallback), nullptr);
+ }
+ Ref<SocketStreamHandle> protectedSocketStreamHandle = socket.copyRef();
+ g_socket_client_connect_to_host_async(socketClient.get(), url.host().utf8().data(), port, socket->m_cancellable.get(),
+ reinterpret_cast<GAsyncReadyCallback>(connectedCallback), &protectedSocketStreamHandle.leakRef());
+ return socket;
+}
+
+Ref<SocketStreamHandle> SocketStreamHandleImpl::create(GSocketConnection* socketConnection, SocketStreamHandleClient& client)
+{
+ Ref<SocketStreamHandleImpl> socket = adoptRef(*new SocketStreamHandleImpl(URL(), client));
+
+ GRefPtr<GSocketConnection> connection = socketConnection;
+ socket->connected(WTFMove(connection));
+ return WTFMove(socket);
+}
+
+SocketStreamHandleImpl::SocketStreamHandleImpl(const URL& url, SocketStreamHandleClient& client)
+ : SocketStreamHandle(url, client)
+ , m_cancellable(adoptGRef(g_cancellable_new()))
+{
+ LOG(Network, "SocketStreamHandle %p new client %p", this, &m_client);
+}
+
+SocketStreamHandleImpl::~SocketStreamHandleImpl()
+{
+ LOG(Network, "SocketStreamHandle %p delete", this);
+}
+
+void SocketStreamHandleImpl::connected(GRefPtr<GSocketConnection>&& socketConnection)
+{
+ m_socketConnection = WTFMove(socketConnection);
+ m_outputStream = G_POLLABLE_OUTPUT_STREAM(g_io_stream_get_output_stream(G_IO_STREAM(m_socketConnection.get())));
+ m_inputStream = g_io_stream_get_input_stream(G_IO_STREAM(m_socketConnection.get()));
+ m_readBuffer = std::make_unique<char[]>(READ_BUFFER_SIZE);
+
+ RefPtr<SocketStreamHandleImpl> protectedThis(this);
+ g_input_stream_read_async(m_inputStream.get(), m_readBuffer.get(), READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, m_cancellable.get(),
+ reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), protectedThis.leakRef());
+
+ m_state = Open;
+ m_client.didOpenSocketStream(*this);
+}
+
+void SocketStreamHandleImpl::connectedCallback(GSocketClient* client, GAsyncResult* result, SocketStreamHandleImpl* handle)
+{
+ RefPtr<SocketStreamHandle> protectedThis = adoptRef(handle);
+
+ // Always finish the connection, even if this SocketStreamHandle was cancelled earlier.
+ GUniqueOutPtr<GError> error;
+ GRefPtr<GSocketConnection> socketConnection = adoptGRef(g_socket_client_connect_to_host_finish(client, result, &error.outPtr()));
+
+ // The SocketStreamHandle has been cancelled, so just close the connection, ignoring errors.
+ if (g_cancellable_is_cancelled(handle->m_cancellable.get())) {
+ if (socketConnection)
+ g_io_stream_close(G_IO_STREAM(socketConnection.get()), nullptr, nullptr);
+ return;
+ }
+
+ if (error)
+ handle->didFail(SocketStreamError(error->code, String(), error->message));
+ else
+ handle->connected(WTFMove(socketConnection));
+}
+
+void SocketStreamHandleImpl::readBytes(gssize bytesRead)
+{
+ if (!bytesRead) {
+ close();
+ return;
+ }
+
+ // The client can close the handle, potentially removing the last reference.
+ RefPtr<SocketStreamHandle> protectedThis(this);
+ std::optional<size_t> optionalLength;
+ if (bytesRead != -1)
+ optionalLength = static_cast<size_t>(bytesRead);
+ m_client.didReceiveSocketStreamData(*this, m_readBuffer.get(), optionalLength);
+ if (m_inputStream) {
+ g_input_stream_read_async(m_inputStream.get(), m_readBuffer.get(), READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, m_cancellable.get(),
+ reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), protectedThis.leakRef());
+ }
+}
+
+void SocketStreamHandleImpl::readReadyCallback(GInputStream* stream, GAsyncResult* result, SocketStreamHandleImpl* handle)
+{
+ RefPtr<SocketStreamHandle> protectedThis = adoptRef(handle);
+
+ // Always finish the read, even if this SocketStreamHandle was cancelled earlier.
+ GUniqueOutPtr<GError> error;
+ gssize bytesRead = g_input_stream_read_finish(stream, result, &error.outPtr());
+
+ if (g_cancellable_is_cancelled(handle->m_cancellable.get()))
+ return;
+
+ if (error)
+ handle->didFail(SocketStreamError(error->code, String(), error->message));
+ else
+ handle->readBytes(bytesRead);
+}
+
+void SocketStreamHandleImpl::didFail(SocketStreamError&& error)
+{
+ m_client.didFailSocketStream(*this, WTFMove(error));
+}
+
+void SocketStreamHandleImpl::writeReady()
+{
+ // We no longer have buffered data, so stop waiting for the socket to be writable.
+ if (!bufferedAmount()) {
+ stopWaitingForSocketWritability();
+ return;
+ }
+
+ sendPendingData();
+}
+
+std::optional<size_t> SocketStreamHandleImpl::platformSend(const char* data, size_t length)
+{
+ LOG(Network, "SocketStreamHandle %p platformSend", this);
+ if (!m_outputStream || !data)
+ return 0;
+
+ GUniqueOutPtr<GError> error;
+ gssize written = g_pollable_output_stream_write_nonblocking(m_outputStream.get(), data, length, m_cancellable.get(), &error.outPtr());
+ if (error) {
+ if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+ beginWaitingForSocketWritability();
+ else
+ didFail(SocketStreamError(error->code, String(), error->message));
+ return std::nullopt;
+ }
+
+ // If we did not send all the bytes we were given, we know that
+ // SocketStreamHandle will need to send more in the future.
+ if (written == -1 || static_cast<size_t>(written) < length)
+ beginWaitingForSocketWritability();
+
+ if (written == -1)
+ return std::nullopt;
+
+ return static_cast<size_t>(written);
+}
+
+void SocketStreamHandleImpl::platformClose()
+{
+ LOG(Network, "SocketStreamHandle %p platformClose", this);
+ // We cancel this handle first to disable all callbacks.
+ g_cancellable_cancel(m_cancellable.get());
+ stopWaitingForSocketWritability();
+
+ if (m_socketConnection) {
+ GUniqueOutPtr<GError> error;
+ g_io_stream_close(G_IO_STREAM(m_socketConnection.get()), nullptr, &error.outPtr());
+ if (error)
+ didFail(SocketStreamError(error->code, String(), error->message));
+ m_socketConnection = nullptr;
+ }
+
+ m_outputStream = nullptr;
+ m_inputStream = nullptr;
+ m_readBuffer = nullptr;
+
+ m_client.didCloseSocketStream(*this);
+}
+
+void SocketStreamHandleImpl::beginWaitingForSocketWritability()
+{
+ if (m_writeReadySource) // Already waiting.
+ return;
+
+ m_writeReadySource = adoptGRef(g_pollable_output_stream_create_source(m_outputStream.get(), m_cancellable.get()));
+ ref();
+ g_source_set_callback(m_writeReadySource.get(), reinterpret_cast<GSourceFunc>(writeReadyCallback), this, [](gpointer handle) {
+ static_cast<SocketStreamHandleImpl*>(handle)->deref();
+ });
+ g_source_attach(m_writeReadySource.get(), g_main_context_get_thread_default());
+}
+
+void SocketStreamHandleImpl::stopWaitingForSocketWritability()
+{
+ if (!m_writeReadySource) // Not waiting.
+ return;
+
+ g_source_destroy(m_writeReadySource.get());
+ m_writeReadySource = nullptr;
+}
+
+gboolean SocketStreamHandleImpl::writeReadyCallback(GPollableOutputStream*, SocketStreamHandleImpl* handle)
+{
+ if (g_cancellable_is_cancelled(handle->m_cancellable.get()))
+ return G_SOURCE_REMOVE;
+
+ handle->writeReady();
+ return G_SOURCE_CONTINUE;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/network/soup/SocketStreamHandleSoup.cpp b/Source/WebCore/platform/network/soup/SocketStreamHandleSoup.cpp
deleted file mode 100644
index 71c21216d..000000000
--- a/Source/WebCore/platform/network/soup/SocketStreamHandleSoup.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2009, 2011 Google Inc. All rights reserved.
- * Copyright (C) 2012 Samsung Electronics Ltd. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "SocketStreamHandle.h"
-
-#include "URL.h"
-#include "Logging.h"
-#include "NotImplemented.h"
-#include "SocketStreamError.h"
-#include "SocketStreamHandleClient.h"
-
-#include <gio/gio.h>
-#include <glib.h>
-
-#include <wtf/Vector.h>
-#include <wtf/gobject/GUniquePtr.h>
-#include <wtf/text/CString.h>
-
-#define READ_BUFFER_SIZE 1024
-
-namespace WebCore {
-
-// These functions immediately call the similarly named SocketStreamHandle methods.
-static void connectedCallback(GSocketClient*, GAsyncResult*, void*);
-static void readReadyCallback(GInputStream*, GAsyncResult*, void*);
-static gboolean writeReadyCallback(GPollableOutputStream*, void*);
-
-// Having a list of active handles means that we do not have to worry about WebCore
-// reference counting in GLib callbacks. Once the handle is off the active handles list
-// we just ignore it in the callback. We avoid a lot of extra checks and tricky
-// situations this way.
-static HashMap<void*, SocketStreamHandle*> gActiveHandles;
-COMPILE_ASSERT(HashTraits<SocketStreamHandle*>::emptyValueIsZero, emptyMapValue_is_0);
-
-static SocketStreamHandle* getHandleFromId(void* id)
-{
- return gActiveHandles.get(id);
-}
-
-static void deactivateHandle(SocketStreamHandle* handle)
-{
- gActiveHandles.remove(handle->id());
-}
-
-static void* activateHandle(SocketStreamHandle* handle)
-{
- // The first id cannot be 0, because it conflicts with the HashMap emptyValue.
- static gint currentHandleId = 1;
- void* id = GINT_TO_POINTER(currentHandleId++);
- gActiveHandles.set(id, handle);
- return id;
-}
-
-SocketStreamHandle::SocketStreamHandle(const URL& url, SocketStreamHandleClient* client)
- : SocketStreamHandleBase(url, client)
-{
- LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
- unsigned int port = url.hasPort() ? url.port() : (url.protocolIs("wss") ? 443 : 80);
-
- m_id = activateHandle(this);
- GRefPtr<GSocketClient> socketClient = adoptGRef(g_socket_client_new());
- if (url.protocolIs("wss"))
- g_socket_client_set_tls(socketClient.get(), TRUE);
- g_socket_client_connect_to_host_async(socketClient.get(), url.host().utf8().data(), port, 0,
- reinterpret_cast<GAsyncReadyCallback>(connectedCallback), m_id);
-}
-
-SocketStreamHandle::SocketStreamHandle(GSocketConnection* socketConnection, SocketStreamHandleClient* client)
- : SocketStreamHandleBase(URL(), client)
-{
- LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
- m_id = activateHandle(this);
- connected(socketConnection, 0);
-}
-
-SocketStreamHandle::~SocketStreamHandle()
-{
- LOG(Network, "SocketStreamHandle %p delete", this);
- // If for some reason we were destroyed without closing, ensure that we are deactivated.
- deactivateHandle(this);
- setClient(0);
-}
-
-void SocketStreamHandle::connected(GSocketConnection* socketConnection, GError* error)
-{
- if (error) {
- m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
- return;
- }
-
- m_socketConnection = socketConnection;
- m_outputStream = G_POLLABLE_OUTPUT_STREAM(g_io_stream_get_output_stream(G_IO_STREAM(m_socketConnection.get())));
- m_inputStream = g_io_stream_get_input_stream(G_IO_STREAM(m_socketConnection.get()));
-
- m_readBuffer = std::make_unique<char[]>(READ_BUFFER_SIZE);
- g_input_stream_read_async(m_inputStream.get(), m_readBuffer.get(), READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
- reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), m_id);
-
- m_state = Open;
- m_client->didOpenSocketStream(this);
-}
-
-void SocketStreamHandle::readBytes(signed long bytesRead, GError* error)
-{
- if (error) {
- m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
- return;
- }
-
- if (!bytesRead) {
- close();
- return;
- }
-
- // The client can close the handle, potentially removing the last reference.
- RefPtr<SocketStreamHandle> protect(this);
- m_client->didReceiveSocketStreamData(this, m_readBuffer.get(), bytesRead);
- if (m_inputStream) // The client may have closed the connection.
- g_input_stream_read_async(m_inputStream.get(), m_readBuffer.get(), READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
- reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), m_id);
-}
-
-void SocketStreamHandle::writeReady()
-{
- // We no longer have buffered data, so stop waiting for the socket to be writable.
- if (!bufferedAmount()) {
- stopWaitingForSocketWritability();
- return;
- }
-
- sendPendingData();
-}
-
-int SocketStreamHandle::platformSend(const char* data, int length)
-{
- LOG(Network, "SocketStreamHandle %p platformSend", this);
- if (!m_outputStream || !data)
- return 0;
-
- GUniqueOutPtr<GError> error;
- gssize written = g_pollable_output_stream_write_nonblocking(m_outputStream.get(), data, length, 0, &error.outPtr());
- if (error) {
- if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
- beginWaitingForSocketWritability();
- else
- m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
- return 0;
- }
-
- // If we did not send all the bytes we were given, we know that
- // SocketStreamHandleBase will need to send more in the future.
- if (written < length)
- beginWaitingForSocketWritability();
-
- return written;
-}
-
-void SocketStreamHandle::platformClose()
-{
- LOG(Network, "SocketStreamHandle %p platformClose", this);
- // We remove this handle from the active handles list first, to disable all callbacks.
- deactivateHandle(this);
- stopWaitingForSocketWritability();
-
- if (m_socketConnection) {
- GUniqueOutPtr<GError> error;
- g_io_stream_close(G_IO_STREAM(m_socketConnection.get()), 0, &error.outPtr());
- if (error)
- m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
- m_socketConnection = 0;
- }
-
- m_outputStream = 0;
- m_inputStream = 0;
- m_readBuffer = nullptr;
-
- m_client->didCloseSocketStream(this);
-}
-
-void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&)
-{
- notImplemented();
-}
-
-void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&)
-{
- notImplemented();
-}
-
-void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&)
-{
- notImplemented();
-}
-
-void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&)
-{
- notImplemented();
-}
-
-void SocketStreamHandle::beginWaitingForSocketWritability()
-{
- if (m_writeReadySource) // Already waiting.
- return;
-
- m_writeReadySource = adoptGRef(g_pollable_output_stream_create_source(m_outputStream.get(), 0));
- g_source_set_callback(m_writeReadySource.get(), reinterpret_cast<GSourceFunc>(writeReadyCallback), m_id, 0);
- g_source_attach(m_writeReadySource.get(), 0);
-}
-
-void SocketStreamHandle::stopWaitingForSocketWritability()
-{
- if (!m_writeReadySource) // Not waiting.
- return;
-
- g_source_remove(g_source_get_id(m_writeReadySource.get()));
- m_writeReadySource = 0;
-}
-
-static void connectedCallback(GSocketClient* client, GAsyncResult* result, void* id)
-{
- // Always finish the connection, even if this SocketStreamHandle was deactivated earlier.
- GUniqueOutPtr<GError> error;
- GSocketConnection* socketConnection = g_socket_client_connect_to_host_finish(client, result, &error.outPtr());
-
- // The SocketStreamHandle has been deactivated, so just close the connection, ignoring errors.
- SocketStreamHandle* handle = getHandleFromId(id);
- if (!handle) {
- if (socketConnection)
- g_io_stream_close(G_IO_STREAM(socketConnection), 0, 0);
- return;
- }
-
- handle->connected(socketConnection, error.get());
-}
-
-static void readReadyCallback(GInputStream* stream, GAsyncResult* result, void* id)
-{
- // Always finish the read, even if this SocketStreamHandle was deactivated earlier.
- GUniqueOutPtr<GError> error;
- gssize bytesRead = g_input_stream_read_finish(stream, result, &error.outPtr());
-
- SocketStreamHandle* handle = getHandleFromId(id);
- if (!handle)
- return;
-
- handle->readBytes(bytesRead, error.get());
-}
-
-static gboolean writeReadyCallback(GPollableOutputStream*, void* id)
-{
- SocketStreamHandle* handle = getHandleFromId(id);
- if (!handle)
- return FALSE;
-
- handle->writeReady();
- return TRUE;
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/platform/network/soup/SoupNetworkProxySettings.h b/Source/WebCore/platform/network/soup/SoupNetworkProxySettings.h
new file mode 100644
index 000000000..273267350
--- /dev/null
+++ b/Source/WebCore/platform/network/soup/SoupNetworkProxySettings.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/HashMap.h>
+#include <wtf/glib/GUniquePtr.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+struct SoupNetworkProxySettings {
+ enum class Mode { Default, NoProxy, Custom };
+
+ SoupNetworkProxySettings() = default;
+
+ explicit SoupNetworkProxySettings(Mode proxyMode)
+ : mode(proxyMode)
+ {
+ }
+
+ SoupNetworkProxySettings(const WebCore::SoupNetworkProxySettings& other)
+ : mode(other.mode)
+ , defaultProxyURL(other.defaultProxyURL)
+ , ignoreHosts(g_strdupv(other.ignoreHosts.get()))
+ , proxyMap(other.proxyMap)
+ {
+ }
+
+ SoupNetworkProxySettings& operator=(const WebCore::SoupNetworkProxySettings& other)
+ {
+ mode = other.mode;
+ defaultProxyURL = other.defaultProxyURL;
+ ignoreHosts.reset(g_strdupv(other.ignoreHosts.get()));
+ proxyMap = other.proxyMap;
+ return *this;
+ }
+
+ bool isEmpty() const { return mode == Mode::Custom && defaultProxyURL.isNull() && !ignoreHosts && proxyMap.isEmpty(); }
+
+ Mode mode { Mode::Default };
+ CString defaultProxyURL;
+ GUniquePtr<char*> ignoreHosts;
+ HashMap<CString, CString> proxyMap;
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/network/soup/SoupNetworkSession.cpp b/Source/WebCore/platform/network/soup/SoupNetworkSession.cpp
index 715e39f04..7c17e604e 100644
--- a/Source/WebCore/platform/network/soup/SoupNetworkSession.cpp
+++ b/Source/WebCore/platform/network/soup/SoupNetworkSession.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,23 +24,32 @@
*/
#include "config.h"
+
+#if USE(SOUP)
+
#include "SoupNetworkSession.h"
#include "AuthenticationChallenge.h"
-#include "CookieJarSoup.h"
+#include "FileSystem.h"
#include "GUniquePtrSoup.h"
#include "Logging.h"
#include "ResourceHandle.h"
+#include "SoupNetworkProxySettings.h"
+#include <glib/gstdio.h>
#include <libsoup/soup.h>
+#include <pal/crypto/CryptoDigest.h>
+#include <wtf/HashSet.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/Base64.h>
#include <wtf/text/CString.h>
-#include <wtf/text/StringBuilder.h>
-
-#if PLATFORM(EFL)
-#include "ProxyResolverSoup.h"
-#endif
namespace WebCore {
+static bool gIgnoreTLSErrors;
+static CString gInitialAcceptLanguages;
+static SoupNetworkProxySettings gProxySettings;
+static GType gCustomProtocolRequestType;
+
#if !LOG_DISABLED
inline static void soupLogPrinter(SoupLogger*, SoupLoggerLogLevel, char direction, const char* data, gpointer)
{
@@ -48,37 +57,53 @@ inline static void soupLogPrinter(SoupLogger*, SoupLoggerLogLevel, char directio
}
#endif
-SoupNetworkSession& SoupNetworkSession::defaultSession()
-{
- static SoupNetworkSession networkSession(soupCookieJar());
- return networkSession;
-}
+class HostTLSCertificateSet {
+public:
+ void add(GTlsCertificate* certificate)
+ {
+ String certificateHash = computeCertificateHash(certificate);
+ if (!certificateHash.isEmpty())
+ m_certificates.add(certificateHash);
+ }
-std::unique_ptr<SoupNetworkSession> SoupNetworkSession::createPrivateBrowsingSession()
-{
- return std::unique_ptr<SoupNetworkSession>(new SoupNetworkSession(soupCookieJar()));
-}
+ bool contains(GTlsCertificate* certificate) const
+ {
+ return m_certificates.contains(computeCertificateHash(certificate));
+ }
-std::unique_ptr<SoupNetworkSession> SoupNetworkSession::createTestingSession()
-{
- GRefPtr<SoupCookieJar> cookieJar = adoptGRef(createPrivateBrowsingCookieJar());
- return std::unique_ptr<SoupNetworkSession>(new SoupNetworkSession(cookieJar.get()));
-}
+private:
+ static String computeCertificateHash(GTlsCertificate* certificate)
+ {
+ GRefPtr<GByteArray> certificateData;
+ g_object_get(G_OBJECT(certificate), "certificate", &certificateData.outPtr(), nullptr);
+ if (!certificateData)
+ return String();
+
+ auto digest = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256);
+ digest->addBytes(certificateData->data, certificateData->len);
+
+ auto hash = digest->computeHash();
+ return base64Encode(reinterpret_cast<const char*>(hash.data()), hash.size());
+ }
-std::unique_ptr<SoupNetworkSession> SoupNetworkSession::createForSoupSession(SoupSession* soupSession)
+ HashSet<String> m_certificates;
+};
+
+static HashMap<String, HostTLSCertificateSet, ASCIICaseInsensitiveHash>& clientCertificates()
{
- return std::unique_ptr<SoupNetworkSession>(new SoupNetworkSession(soupSession));
+ static NeverDestroyed<HashMap<String, HostTLSCertificateSet, ASCIICaseInsensitiveHash>> certificates;
+ return certificates;
}
-static void authenticateCallback(SoupSession* session, SoupMessage* soupMessage, SoupAuth* soupAuth, gboolean retrying)
+static void authenticateCallback(SoupSession*, SoupMessage* soupMessage, SoupAuth* soupAuth, gboolean retrying)
{
RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(G_OBJECT(soupMessage), "handle"));
if (!handle)
return;
- handle->didReceiveAuthenticationChallenge(AuthenticationChallenge(session, soupMessage, soupAuth, retrying, handle.get()));
+ handle->didReceiveAuthenticationChallenge(AuthenticationChallenge(soupMessage, soupAuth, retrying, handle.get()));
}
-#if ENABLE(WEB_TIMING)
+#if ENABLE(WEB_TIMING) && !SOUP_CHECK_VERSION(2, 49, 91)
static void requestStartedCallback(SoupSession*, SoupMessage* soupMessage, SoupSocket*, gpointer)
{
RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(G_OBJECT(soupMessage), "handle"));
@@ -95,33 +120,50 @@ SoupNetworkSession::SoupNetworkSession(SoupCookieJar* cookieJar)
// the rule "Do What Every Other Modern Browser Is Doing". They seem
// to significantly improve page loading time compared to soup's
// default values.
- static const int maxConnections = 35;
+ static const int maxConnections = 17;
static const int maxConnectionsPerHost = 6;
+ GRefPtr<SoupCookieJar> jar = cookieJar;
+ if (!jar) {
+ jar = adoptGRef(soup_cookie_jar_new());
+ soup_cookie_jar_set_accept_policy(jar.get(), SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY);
+ }
+
g_object_set(m_soupSession.get(),
SOUP_SESSION_MAX_CONNS, maxConnections,
SOUP_SESSION_MAX_CONNS_PER_HOST, maxConnectionsPerHost,
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_DECODER,
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_SNIFFER,
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_DEFAULT,
- SOUP_SESSION_ADD_FEATURE, cookieJar,
+ SOUP_SESSION_ADD_FEATURE, jar.get(),
SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
+ SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
+ SOUP_SESSION_SSL_STRICT, FALSE,
nullptr);
+ setupCustomProtocols();
+
+ if (!gInitialAcceptLanguages.isNull())
+ setAcceptLanguages(gInitialAcceptLanguages);
+
+#if SOUP_CHECK_VERSION(2, 53, 92)
+ if (soup_auth_negotiate_supported()) {
+ g_object_set(m_soupSession.get(),
+ SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_AUTH_NEGOTIATE,
+ nullptr);
+ }
+#endif
+
+ if (gProxySettings.mode != SoupNetworkProxySettings::Mode::Default)
+ setupProxy();
setupLogger();
g_signal_connect(m_soupSession.get(), "authenticate", G_CALLBACK(authenticateCallback), nullptr);
-#if ENABLE(WEB_TIMING)
+#if ENABLE(WEB_TIMING) && !SOUP_CHECK_VERSION(2, 49, 91)
g_signal_connect(m_soupSession.get(), "request-started", G_CALLBACK(requestStartedCallback), nullptr);
#endif
}
-SoupNetworkSession::SoupNetworkSession(SoupSession* soupSession)
- : m_soupSession(soupSession)
-{
- setupLogger();
-}
-
SoupNetworkSession::~SoupNetworkSession()
{
}
@@ -150,134 +192,137 @@ SoupCookieJar* SoupNetworkSession::cookieJar() const
return SOUP_COOKIE_JAR(soup_session_get_feature(m_soupSession.get(), SOUP_TYPE_COOKIE_JAR));
}
-void SoupNetworkSession::setCache(SoupCache* cache)
+static inline bool stringIsNumeric(const char* str)
{
- ASSERT(!soup_session_get_feature(m_soupSession.get(), SOUP_TYPE_CACHE));
- soup_session_add_feature(m_soupSession.get(), SOUP_SESSION_FEATURE(cache));
+ while (*str) {
+ if (!g_ascii_isdigit(*str))
+ return false;
+ str++;
+ }
+ return true;
}
-SoupCache* SoupNetworkSession::cache() const
+// Old versions of WebKit created this cache.
+void SoupNetworkSession::clearOldSoupCache(const String& cacheDirectory)
{
- SoupSessionFeature* soupCache = soup_session_get_feature(m_soupSession.get(), SOUP_TYPE_CACHE);
- return soupCache ? SOUP_CACHE(soupCache) : nullptr;
-}
+ CString cachePath = fileSystemRepresentation(cacheDirectory);
+ GUniquePtr<char> cacheFile(g_build_filename(cachePath.data(), "soup.cache2", nullptr));
+ if (!g_file_test(cacheFile.get(), G_FILE_TEST_IS_REGULAR))
+ return;
-void SoupNetworkSession::setSSLPolicy(SSLPolicy flags)
-{
- g_object_set(m_soupSession.get(),
- SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, flags & SSLUseSystemCAFile ? TRUE : FALSE,
- SOUP_SESSION_SSL_STRICT, flags & SSLStrict ? TRUE : FALSE,
- nullptr);
-}
+ GUniquePtr<GDir> dir(g_dir_open(cachePath.data(), 0, nullptr));
+ if (!dir)
+ return;
-SoupNetworkSession::SSLPolicy SoupNetworkSession::sslPolicy() const
-{
- gboolean useSystemCAFile, strict;
- g_object_get(m_soupSession.get(),
- SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, &useSystemCAFile,
- SOUP_SESSION_SSL_STRICT, &strict,
- nullptr);
+ while (const char* name = g_dir_read_name(dir.get())) {
+ if (!g_str_has_prefix(name, "soup.cache") && !stringIsNumeric(name))
+ continue;
- SSLPolicy flags = 0;
- if (useSystemCAFile)
- flags |= SSLUseSystemCAFile;
- if (strict)
- flags |= SSLStrict;
- return flags;
+ GUniquePtr<gchar> filename(g_build_filename(cachePath.data(), name, nullptr));
+ if (g_file_test(filename.get(), G_FILE_TEST_IS_REGULAR))
+ g_unlink(filename.get());
+ }
}
-void SoupNetworkSession::setHTTPProxy(const char* httpProxy, const char* httpProxyExceptions)
+void SoupNetworkSession::setupProxy()
{
-#if PLATFORM(EFL)
- // Only for EFL because GTK port uses the default resolver, which uses GIO's proxy resolver.
- if (!httpProxy) {
- soup_session_remove_feature_by_type(m_soupSession.get(), SOUP_TYPE_PROXY_URI_RESOLVER);
- return;
+ GRefPtr<GProxyResolver> resolver;
+ switch (gProxySettings.mode) {
+ case SoupNetworkProxySettings::Mode::Default: {
+ GRefPtr<GProxyResolver> currentResolver;
+ g_object_get(m_soupSession.get(), SOUP_SESSION_PROXY_RESOLVER, &currentResolver.outPtr(), nullptr);
+ GProxyResolver* defaultResolver = g_proxy_resolver_get_default();
+ if (currentResolver.get() == defaultResolver)
+ return;
+ resolver = defaultResolver;
+ break;
+ }
+ case SoupNetworkProxySettings::Mode::NoProxy:
+ // Do nothing in this case, resolver is nullptr so that when set it will disable proxies.
+ break;
+ case SoupNetworkProxySettings::Mode::Custom:
+ resolver = adoptGRef(g_simple_proxy_resolver_new(nullptr, nullptr));
+ if (!gProxySettings.defaultProxyURL.isNull())
+ g_simple_proxy_resolver_set_default_proxy(G_SIMPLE_PROXY_RESOLVER(resolver.get()), gProxySettings.defaultProxyURL.data());
+ if (gProxySettings.ignoreHosts)
+ g_simple_proxy_resolver_set_ignore_hosts(G_SIMPLE_PROXY_RESOLVER(resolver.get()), gProxySettings.ignoreHosts.get());
+ for (const auto& iter : gProxySettings.proxyMap)
+ g_simple_proxy_resolver_set_uri_proxy(G_SIMPLE_PROXY_RESOLVER(resolver.get()), iter.key.data(), iter.value.data());
+ break;
}
- GRefPtr<SoupProxyURIResolver> resolver = adoptGRef(soupProxyResolverWkNew(httpProxy, httpProxyExceptions));
- soup_session_add_feature(m_soupSession.get(), SOUP_SESSION_FEATURE(resolver.get()));
-#else
- UNUSED_PARAM(httpProxy);
- UNUSED_PARAM(httpProxyExceptions);
-#endif
+ g_object_set(m_soupSession.get(), SOUP_SESSION_PROXY_RESOLVER, resolver.get(), nullptr);
+ soup_session_abort(m_soupSession.get());
}
-char* SoupNetworkSession::httpProxy() const
+void SoupNetworkSession::setProxySettings(const SoupNetworkProxySettings& settings)
{
-#if PLATFORM(EFL)
- SoupSessionFeature* soupResolver = soup_session_get_feature(m_soupSession.get(), SOUP_TYPE_PROXY_URI_RESOLVER);
- if (!soupResolver)
- return nullptr;
+ gProxySettings = settings;
+}
- GUniqueOutPtr<SoupURI> uri;
- g_object_get(soupResolver, SOUP_PROXY_RESOLVER_WK_PROXY_URI, &uri.outPtr(), nullptr);
+void SoupNetworkSession::setInitialAcceptLanguages(const CString& languages)
+{
+ gInitialAcceptLanguages = languages;
+}
- return uri ? soup_uri_to_string(uri.get(), FALSE) : nullptr;
-#else
- return nullptr;
-#endif
+void SoupNetworkSession::setAcceptLanguages(const CString& languages)
+{
+ g_object_set(m_soupSession.get(), "accept-language", languages.data(), nullptr);
}
-void SoupNetworkSession::setupHTTPProxyFromEnvironment()
+void SoupNetworkSession::setCustomProtocolRequestType(GType requestType)
{
-#if PLATFORM(EFL)
- const char* httpProxy = getenv("http_proxy");
- if (!httpProxy)
+ ASSERT(g_type_is_a(requestType, SOUP_TYPE_REQUEST));
+ gCustomProtocolRequestType = requestType;
+}
+
+void SoupNetworkSession::setupCustomProtocols()
+{
+ if (!g_type_is_a(gCustomProtocolRequestType, SOUP_TYPE_REQUEST))
return;
- setHTTPProxy(httpProxy, getenv("no_proxy"));
-#endif
+ auto* requestClass = static_cast<SoupRequestClass*>(g_type_class_peek(gCustomProtocolRequestType));
+ if (!requestClass || !requestClass->schemes)
+ return;
+
+ soup_session_add_feature_by_type(m_soupSession.get(), gCustomProtocolRequestType);
}
-static CString buildAcceptLanguages(const Vector<String>& languages)
+void SoupNetworkSession::setShouldIgnoreTLSErrors(bool ignoreTLSErrors)
{
- size_t languagesCount = languages.size();
-
- // Ignore "C" locale.
- size_t cLocalePosition = languages.find("c");
- if (cLocalePosition != notFound)
- languagesCount--;
-
- // Fallback to "en" if the list is empty.
- if (!languagesCount)
- return "en";
-
- // Calculate deltas for the quality values.
- int delta;
- if (languagesCount < 10)
- delta = 10;
- else if (languagesCount < 20)
- delta = 5;
- else
- delta = 1;
-
- // Set quality values for each language.
- StringBuilder builder;
- for (size_t i = 0; i < languages.size(); ++i) {
- if (i == cLocalePosition)
- continue;
+ gIgnoreTLSErrors = ignoreTLSErrors;
+}
- if (i)
- builder.appendLiteral(", ");
+void SoupNetworkSession::checkTLSErrors(SoupRequest* soupRequest, SoupMessage* message, std::function<void (const ResourceError&)>&& completionHandler)
+{
+ if (gIgnoreTLSErrors) {
+ completionHandler({ });
+ return;
+ }
- builder.append(languages[i]);
+ GTlsCertificate* certificate = nullptr;
+ GTlsCertificateFlags tlsErrors = static_cast<GTlsCertificateFlags>(0);
+ soup_message_get_https_status(message, &certificate, &tlsErrors);
+ if (!tlsErrors) {
+ completionHandler({ });
+ return;
+ }
- int quality = 100 - i * delta;
- if (quality > 0 && quality < 100) {
- char buffer[8];
- g_ascii_formatd(buffer, 8, "%.2f", quality / 100.0);
- builder.append(String::format(";q=%s", buffer));
- }
+ URL url(soup_request_get_uri(soupRequest));
+ auto it = clientCertificates().find(url.host());
+ if (it != clientCertificates().end() && it->value.contains(certificate)) {
+ completionHandler({ });
+ return;
}
- return builder.toString().utf8();
+ completionHandler(ResourceError::tlsError(soupRequest, tlsErrors, certificate));
}
-void SoupNetworkSession::setAcceptLanguages(const Vector<String>& languages)
+void SoupNetworkSession::allowSpecificHTTPSCertificateForHost(const CertificateInfo& certificateInfo, const String& host)
{
- g_object_set(m_soupSession.get(), "accept-language", buildAcceptLanguages(languages).data(), nullptr);
+ clientCertificates().add(host, HostTLSCertificateSet()).iterator->value.add(certificateInfo.certificate());
}
} // namespace WebCore
+#endif
diff --git a/Source/WebCore/platform/network/soup/SoupNetworkSession.h b/Source/WebCore/platform/network/soup/SoupNetworkSession.h
index b9801f9f9..908b6cb6d 100644
--- a/Source/WebCore/platform/network/soup/SoupNetworkSession.h
+++ b/Source/WebCore/platform/network/soup/SoupNetworkSession.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -26,54 +26,52 @@
#ifndef SoupNetworkSession_h
#define SoupNetworkSession_h
+#include <functional>
+#include <glib-object.h>
#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
#include <wtf/text/WTFString.h>
typedef struct _SoupCache SoupCache;
typedef struct _SoupCookieJar SoupCookieJar;
+typedef struct _SoupMessage SoupMessage;
+typedef struct _SoupRequest SoupRequest;
typedef struct _SoupSession SoupSession;
namespace WebCore {
+class CertificateInfo;
+class ResourceError;
+struct SoupNetworkProxySettings;
+
class SoupNetworkSession {
WTF_MAKE_NONCOPYABLE(SoupNetworkSession); WTF_MAKE_FAST_ALLOCATED;
public:
+ explicit SoupNetworkSession(SoupCookieJar* = nullptr);
~SoupNetworkSession();
- static SoupNetworkSession& defaultSession();
- static std::unique_ptr<SoupNetworkSession> createPrivateBrowsingSession();
- static std::unique_ptr<SoupNetworkSession> createTestingSession();
- static std::unique_ptr<SoupNetworkSession> createForSoupSession(SoupSession*);
-
- enum SSLPolicyFlags {
- SSLStrict = 1 << 0,
- SSLUseSystemCAFile = 1 << 1
- };
- typedef unsigned SSLPolicy;
-
SoupSession* soupSession() const { return m_soupSession.get(); }
void setCookieJar(SoupCookieJar*);
SoupCookieJar* cookieJar() const;
- void setCache(SoupCache*);
- SoupCache* cache() const;
+ static void clearOldSoupCache(const String& cacheDirectory);
- void setSSLPolicy(SSLPolicy);
- SSLPolicy sslPolicy() const;
+ static void setProxySettings(const SoupNetworkProxySettings&);
+ void setupProxy();
- void setHTTPProxy(const char* httpProxy, const char* httpProxyExceptions);
- char* httpProxy() const;
- void setupHTTPProxyFromEnvironment();
+ static void setInitialAcceptLanguages(const CString&);
+ void setAcceptLanguages(const CString&);
- void setAcceptLanguages(const Vector<String>&);
+ static void setShouldIgnoreTLSErrors(bool);
+ static void checkTLSErrors(SoupRequest*, SoupMessage*, std::function<void (const ResourceError&)>&&);
+ static void allowSpecificHTTPSCertificateForHost(const CertificateInfo&, const String& host);
-private:
- SoupNetworkSession(SoupCookieJar*);
- SoupNetworkSession(SoupSession*);
+ static void setCustomProtocolRequestType(GType);
+ void setupCustomProtocols();
+private:
void setupLogger();
GRefPtr<SoupSession> m_soupSession;
diff --git a/Source/WebCore/platform/network/soup/SynchronousLoaderClientSoup.cpp b/Source/WebCore/platform/network/soup/SynchronousLoaderClientSoup.cpp
index cfc01aed7..09e42d8e9 100644
--- a/Source/WebCore/platform/network/soup/SynchronousLoaderClientSoup.cpp
+++ b/Source/WebCore/platform/network/soup/SynchronousLoaderClientSoup.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if USE(SOUP)
+
#include "SynchronousLoaderClient.h"
#include "AuthenticationChallenge.h"
@@ -44,3 +47,6 @@ ResourceError SynchronousLoaderClient::platformBadResponseError()
}
}
+
+#endif
+
diff --git a/Source/WebCore/platform/network/soup/WebKitSoupRequestGeneric.cpp b/Source/WebCore/platform/network/soup/WebKitSoupRequestGeneric.cpp
new file mode 100644
index 000000000..ec1325842
--- /dev/null
+++ b/Source/WebCore/platform/network/soup/WebKitSoupRequestGeneric.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2012 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
+ * 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 "WebKitSoupRequestGeneric.h"
+
+#include "ResourceRequest.h"
+#include <wtf/text/CString.h>
+
+using namespace WebCore;
+
+G_DEFINE_TYPE(WebKitSoupRequestGeneric, webkit_soup_request_generic, SOUP_TYPE_REQUEST)
+
+struct _WebKitSoupRequestGenericPrivate {
+ CString mimeType;
+ goffset contentLength;
+ ResourceRequest resourceRequest;
+};
+
+static void webkitSoupRequestGenericFinalize(GObject* object)
+{
+ WEBKIT_SOUP_REQUEST_GENERIC(object)->priv->~WebKitSoupRequestGenericPrivate();
+ G_OBJECT_CLASS(webkit_soup_request_generic_parent_class)->finalize(object);
+}
+
+static void webkit_soup_request_generic_init(WebKitSoupRequestGeneric* request)
+{
+ WebKitSoupRequestGenericPrivate* priv = G_TYPE_INSTANCE_GET_PRIVATE(request, WEBKIT_TYPE_SOUP_REQUEST_GENERIC, WebKitSoupRequestGenericPrivate);
+ request->priv = priv;
+ new (priv) WebKitSoupRequestGenericPrivate();
+}
+
+static void webkitSoupRequestGenericSendAsync(SoupRequest* request, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
+{
+ WebKitSoupRequestGenericClient* client = WEBKIT_SOUP_REQUEST_GENERIC_GET_CLASS(request)->client;
+ ASSERT(client);
+ client->startRequest(adoptGRef(g_task_new(request, cancellable, callback, userData)));
+}
+
+static GInputStream* webkitSoupRequestGenericSendFinish(SoupRequest* request, GAsyncResult* result, GError** error)
+{
+ g_return_val_if_fail(g_task_is_valid(result, request), nullptr);
+ auto* inputStream = g_task_propagate_pointer(G_TASK(result), error);
+ return inputStream ? G_INPUT_STREAM(inputStream) : nullptr;
+}
+
+static goffset webkitSoupRequestGenericGetContentLength(SoupRequest* request)
+{
+ return WEBKIT_SOUP_REQUEST_GENERIC(request)->priv->contentLength;
+}
+
+static const char* webkitSoupRequestGenericGetContentType(SoupRequest* request)
+{
+ return WEBKIT_SOUP_REQUEST_GENERIC(request)->priv->mimeType.data();
+}
+
+static void webkit_soup_request_generic_class_init(WebKitSoupRequestGenericClass* requestGenericClass)
+{
+ GObjectClass* gObjectClass = G_OBJECT_CLASS(requestGenericClass);
+ gObjectClass->finalize = webkitSoupRequestGenericFinalize;
+
+ SoupRequestClass* requestClass = SOUP_REQUEST_CLASS(requestGenericClass);
+ requestClass->send_async = webkitSoupRequestGenericSendAsync;
+ requestClass->send_finish = webkitSoupRequestGenericSendFinish;
+ requestClass->get_content_length = webkitSoupRequestGenericGetContentLength;
+ requestClass->get_content_type = webkitSoupRequestGenericGetContentType;
+
+ g_type_class_add_private(requestGenericClass, sizeof(WebKitSoupRequestGenericPrivate));
+}
+
+void webkitSoupRequestGenericSetContentLength(WebKitSoupRequestGeneric* request, goffset contentLength)
+{
+ request->priv->contentLength = contentLength;
+}
+
+void webkitSoupRequestGenericSetContentType(WebKitSoupRequestGeneric* request, const char* mimeType)
+{
+ request->priv->mimeType = mimeType;
+}
+
+void webkitSoupRequestGenericSetRequest(WebKitSoupRequestGeneric* request, const ResourceRequest& resourceRequest)
+{
+ request->priv->resourceRequest = resourceRequest;
+}
+
+const ResourceRequest& webkitSoupRequestGenericGetRequest(WebKitSoupRequestGeneric* request)
+{
+ return request->priv->resourceRequest;
+}
diff --git a/Source/WebCore/platform/network/soup/WebKitSoupRequestGeneric.h b/Source/WebCore/platform/network/soup/WebKitSoupRequestGeneric.h
new file mode 100644
index 000000000..09cbd2725
--- /dev/null
+++ b/Source/WebCore/platform/network/soup/WebKitSoupRequestGeneric.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 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
+ * 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 WebKitSoupRequestGeneric_h
+#define WebKitSoupRequestGeneric_h
+
+#include "WebKitSoupRequestGenericClient.h"
+#include <glib-object.h>
+#include <libsoup/soup.h>
+
+G_BEGIN_DECLS
+
+namespace WebCore {
+class ResourceRequest;
+}
+
+#define WEBKIT_TYPE_SOUP_REQUEST_GENERIC (webkit_soup_request_generic_get_type())
+#define WEBKIT_SOUP_REQUEST_GENERIC(object) (G_TYPE_CHECK_INSTANCE_CAST((object), WEBKIT_TYPE_SOUP_REQUEST_GENERIC, WebKitSoupRequestGeneric))
+#define WEBKIT_IS_SOUP_REQUEST_GENERIC(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), WEBKIT_TYPE_SOUP_REQUEST_GENERIC))
+#define WEBKIT_SOUP_REQUEST_GENERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_SOUP_REQUEST_GENERIC, WebKitSoupRequestGenericClass))
+#define WEBKIT_IS_SOUP_REQUEST_GENERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_SOUP_REQUEST_GENERIC))
+#define WEBKIT_SOUP_REQUEST_GENERIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_SOUP_REQUEST_GENERIC, WebKitSoupRequestGenericClass))
+
+typedef struct _WebKitSoupRequestGeneric WebKitSoupRequestGeneric;
+typedef struct _WebKitSoupRequestGenericClass WebKitSoupRequestGenericClass;
+typedef struct _WebKitSoupRequestGenericPrivate WebKitSoupRequestGenericPrivate;
+
+struct _WebKitSoupRequestGeneric {
+ SoupRequest parent;
+
+ WebKitSoupRequestGenericPrivate *priv;
+};
+
+struct _WebKitSoupRequestGenericClass {
+ SoupRequestClass parent;
+
+ WebCore::WebKitSoupRequestGenericClient* client;
+};
+
+GType webkit_soup_request_generic_get_type();
+
+void webkitSoupRequestGenericSetContentLength(WebKitSoupRequestGeneric*, goffset contentLength);
+void webkitSoupRequestGenericSetContentType(WebKitSoupRequestGeneric*, const char* mimeType);
+void webkitSoupRequestGenericSetRequest(WebKitSoupRequestGeneric*, const WebCore::ResourceRequest&);
+const WebCore::ResourceRequest& webkitSoupRequestGenericGetRequest(WebKitSoupRequestGeneric*);
+
+G_END_DECLS
+
+#endif // WebKitSoupRequestGeneric_h
diff --git a/Source/WebCore/platform/network/soup/WebKitSoupRequestGenericClient.h b/Source/WebCore/platform/network/soup/WebKitSoupRequestGenericClient.h
new file mode 100644
index 000000000..db470a67f
--- /dev/null
+++ b/Source/WebCore/platform/network/soup/WebKitSoupRequestGenericClient.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 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
+ * 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.
+ */
+
+#pragma once
+
+#include <wtf/glib/GRefPtr.h>
+
+typedef struct _GTask GTask;
+
+namespace WebCore {
+
+class WebKitSoupRequestGenericClient {
+public:
+ virtual void startRequest(GRefPtr<GTask>&&) = 0;
+};
+
+} // namespace WebCore
+