HTTPHeaderMap wastes 226KB of HashTable capacity on cnn.com
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 19 Jun 2018 17:10:33 +0000 (17:10 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 19 Jun 2018 17:10:33 +0000 (17:10 +0000)
https://bugs.webkit.org/show_bug.cgi?id=186735
<rdar://problem/41189164>

Reviewed by Geoffrey Garen.

Source/WebCore:

Resource requests and responses normally do not have a large amount of HTTP headers
(local testing shows 6 common headers on average and 0.3 uncommon ones).
As a result, move the internal representation of HTTPHeaderMap from HashMaps to
Vectors. Given the number of headers, the impact on performance should be negligible.
However, the new implementation uses a lot less memory. In a follow-up, we can save
even more memory by calling HTTPHeaderMap::shrinkToFit() when possible.

* loader/CrossOriginAccessControl.cpp:
(WebCore::createAccessControlPreflightRequest):
* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::responseReceived):
* loader/cache/CachedRawResource.cpp:
(WebCore::CachedRawResource::canReuse const):
* platform/network/HTTPHeaderMap.cpp:
(WebCore::HTTPHeaderMap::isolatedCopy const):
(WebCore::HTTPHeaderMap::get const):
(WebCore::HTTPHeaderMap::set):
(WebCore::HTTPHeaderMap::add):
(WebCore::HTTPHeaderMap::append):
(WebCore::HTTPHeaderMap::addIfNotPresent):
(WebCore::HTTPHeaderMap::contains const):
(WebCore::HTTPHeaderMap::remove):
* platform/network/HTTPHeaderMap.h:
(WebCore::HTTPHeaderMap::CommonHeader::isolatedCopy const):
(WebCore::HTTPHeaderMap::CommonHeader::operator== const):
(WebCore::HTTPHeaderMap::UncommonHeader::isolatedCopy const):
(WebCore::HTTPHeaderMap::UncommonHeader::operator== const):
(WebCore::HTTPHeaderMap::HTTPHeaderMapConstIterator::HTTPHeaderMapConstIterator):
(WebCore::HTTPHeaderMap::HTTPHeaderMapConstIterator::updateKeyValue):
(WebCore::HTTPHeaderMap::shrinkToFit):
(WebCore::HTTPHeaderMap::commonHeaders const):
(WebCore::HTTPHeaderMap::uncommonHeaders const):
(WebCore::HTTPHeaderMap::commonHeaders):
(WebCore::HTTPHeaderMap::uncommonHeaders):
(WebCore::HTTPHeaderMap::CommonHeader::encode const):
(WebCore::HTTPHeaderMap::CommonHeader::decode):
(WebCore::HTTPHeaderMap::UncommonHeader::encode const):
(WebCore::HTTPHeaderMap::UncommonHeader::decode):
(WebCore::HTTPHeaderMap::encode const):
(WebCore::HTTPHeaderMap::decode):
* platform/network/ResourceResponseBase.cpp:
(WebCore::ResourceResponseBase::filter):
(WebCore::ResourceResponseBase::sanitizeHTTPHeaderFields):

Source/WebKit:

* NetworkProcess/cache/NetworkCacheCoders.cpp:
(WTF::Persistence::Coder<WebCore::HTTPHeaderMap>::decode):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@232964 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WTF/wtf/CrossThreadCopier.h
Source/WebCore/ChangeLog
Source/WebCore/loader/CrossOriginAccessControl.cpp
Source/WebCore/loader/DocumentLoader.cpp
Source/WebCore/loader/cache/CachedRawResource.cpp
Source/WebCore/platform/network/HTTPHeaderMap.cpp
Source/WebCore/platform/network/HTTPHeaderMap.h
Source/WebCore/platform/network/ResourceResponseBase.cpp
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/cache/NetworkCacheCoders.cpp
Source/WebKit/Platform/IPC/ArgumentCoders.h

index 86ca68e..f4e4fd9 100644 (file)
@@ -108,8 +108,8 @@ struct CrossThreadCopier : public CrossThreadCopierBase<CrossThreadCopierBaseHel
 };
 
 // Default specialization for Vectors of CrossThreadCopyable classes.
-template<typename T> struct CrossThreadCopierBase<false, false, Vector<T>> {
-    typedef Vector<T> Type;
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> struct CrossThreadCopierBase<false, false, Vector<T, inlineCapacity, OverflowHandler, minCapacity>> {
+    using Type = Vector<T, inlineCapacity, OverflowHandler, minCapacity>;
     static Type copy(const Type& source)
     {
         Type destination;
index 2f58c80..f4c4e19 100644 (file)
@@ -1,3 +1,55 @@
+2018-06-19  Chris Dumez  <cdumez@apple.com>
+
+        HTTPHeaderMap wastes 226KB of HashTable capacity on cnn.com
+        https://bugs.webkit.org/show_bug.cgi?id=186735
+        <rdar://problem/41189164>
+
+        Reviewed by Geoffrey Garen.
+
+        Resource requests and responses normally do not have a large amount of HTTP headers
+        (local testing shows 6 common headers on average and 0.3 uncommon ones).
+        As a result, move the internal representation of HTTPHeaderMap from HashMaps to
+        Vectors. Given the number of headers, the impact on performance should be negligible.
+        However, the new implementation uses a lot less memory. In a follow-up, we can save
+        even more memory by calling HTTPHeaderMap::shrinkToFit() when possible.
+
+        * loader/CrossOriginAccessControl.cpp:
+        (WebCore::createAccessControlPreflightRequest):
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::responseReceived):
+        * loader/cache/CachedRawResource.cpp:
+        (WebCore::CachedRawResource::canReuse const):
+        * platform/network/HTTPHeaderMap.cpp:
+        (WebCore::HTTPHeaderMap::isolatedCopy const):
+        (WebCore::HTTPHeaderMap::get const):
+        (WebCore::HTTPHeaderMap::set):
+        (WebCore::HTTPHeaderMap::add):
+        (WebCore::HTTPHeaderMap::append):
+        (WebCore::HTTPHeaderMap::addIfNotPresent):
+        (WebCore::HTTPHeaderMap::contains const):
+        (WebCore::HTTPHeaderMap::remove):
+        * platform/network/HTTPHeaderMap.h:
+        (WebCore::HTTPHeaderMap::CommonHeader::isolatedCopy const):
+        (WebCore::HTTPHeaderMap::CommonHeader::operator== const):
+        (WebCore::HTTPHeaderMap::UncommonHeader::isolatedCopy const):
+        (WebCore::HTTPHeaderMap::UncommonHeader::operator== const):
+        (WebCore::HTTPHeaderMap::HTTPHeaderMapConstIterator::HTTPHeaderMapConstIterator):
+        (WebCore::HTTPHeaderMap::HTTPHeaderMapConstIterator::updateKeyValue):
+        (WebCore::HTTPHeaderMap::shrinkToFit):
+        (WebCore::HTTPHeaderMap::commonHeaders const):
+        (WebCore::HTTPHeaderMap::uncommonHeaders const):
+        (WebCore::HTTPHeaderMap::commonHeaders):
+        (WebCore::HTTPHeaderMap::uncommonHeaders):
+        (WebCore::HTTPHeaderMap::CommonHeader::encode const):
+        (WebCore::HTTPHeaderMap::CommonHeader::decode):
+        (WebCore::HTTPHeaderMap::UncommonHeader::encode const):
+        (WebCore::HTTPHeaderMap::UncommonHeader::decode):
+        (WebCore::HTTPHeaderMap::encode const):
+        (WebCore::HTTPHeaderMap::decode):
+        * platform/network/ResourceResponseBase.cpp:
+        (WebCore::ResourceResponseBase::filter):
+        (WebCore::ResourceResponseBase::sanitizeHTTPHeaderFields):
+
 2018-06-19  Youenn Fablet  <youenn@apple.com>
 
         Network Preflights do not show in WebInspector after moving CORS checks to NetworkProcess
index 1e026b6..2658095 100644 (file)
@@ -92,12 +92,10 @@ ResourceRequest createAccessControlPreflightRequest(const ResourceRequest& reque
 
     if (!requestHeaderFields.isEmpty()) {
         Vector<String> unsafeHeaders;
-        for (const auto& headerField : requestHeaderFields.commonHeaders()) {
-            if (!isCrossOriginSafeRequestHeader(headerField.key, headerField.value))
-                unsafeHeaders.append(httpHeaderNameString(headerField.key).toStringWithoutCopying().convertToASCIILowercase());
+        for (auto& headerField : requestHeaderFields) {
+            if (!headerField.keyAsHTTPHeaderName || !isCrossOriginSafeRequestHeader(*headerField.keyAsHTTPHeaderName, headerField.value))
+                unsafeHeaders.append(headerField.key.convertToASCIILowercase());
         }
-        for (const auto& headerField : requestHeaderFields.uncommonHeaders())
-            unsafeHeaders.append(headerField.key.convertToASCIILowercase());
 
         std::sort(unsafeHeaders.begin(), unsafeHeaders.end(), WTF::codePointCompareLessThan);
 
index 47a369e..30775bc 100644 (file)
@@ -777,12 +777,10 @@ void DocumentLoader::responseReceived(const ResourceResponse& response, Completi
             return;
         }
 
-        const auto& commonHeaders = response.httpHeaderFields().commonHeaders();
-        auto it = commonHeaders.find(HTTPHeaderName::XFrameOptions);
-        if (it != commonHeaders.end()) {
-            String content = it->value;
-            if (frameLoader()->shouldInterruptLoadForXFrameOptions(content, url, identifier)) {
-                String message = "Refused to display '" + url.stringCenterEllipsizedToLength() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'.";
+        String frameOptions = response.httpHeaderFields().get(HTTPHeaderName::XFrameOptions);
+        if (!frameOptions.isNull()) {
+            if (frameLoader()->shouldInterruptLoadForXFrameOptions(frameOptions, url, identifier)) {
+                String message = "Refused to display '" + url.stringCenterEllipsizedToLength() + "' in a frame because it set 'X-Frame-Options' to '" + frameOptions + "'.";
                 m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message, identifier);
                 stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied(identifier, response);
                 return;
index 62fc063..7965366 100644 (file)
@@ -313,9 +313,9 @@ bool CachedRawResource::canReuse(const ResourceRequest& newRequest) const
     for (const auto& header : newHeaders) {
         if (header.keyAsHTTPHeaderName) {
             if (!shouldIgnoreHeaderForCacheReuse(header.keyAsHTTPHeaderName.value())
-                && header.value != oldHeaders.commonHeaders().get(header.keyAsHTTPHeaderName.value()))
+                && header.value != oldHeaders.get(header.keyAsHTTPHeaderName.value()))
                 return false;
-        } else if (header.value != oldHeaders.uncommonHeaders().get(header.key))
+        } else if (header.value != oldHeaders.get(header.key))
             return false;
     }
 
@@ -324,9 +324,9 @@ bool CachedRawResource::canReuse(const ResourceRequest& newRequest) const
     for (const auto& header : oldHeaders) {
         if (header.keyAsHTTPHeaderName) {
             if (!shouldIgnoreHeaderForCacheReuse(header.keyAsHTTPHeaderName.value())
-                && !newHeaders.commonHeaders().contains(header.keyAsHTTPHeaderName.value()))
+                && !newHeaders.contains(header.keyAsHTTPHeaderName.value()))
                 return false;
-        } else if (!newHeaders.uncommonHeaders().contains(header.key))
+        } else if (!newHeaders.contains(header.key))
             return false;
     }
 
index 6bf1cf5..3b01843 100644 (file)
@@ -32,6 +32,7 @@
 #include "HTTPHeaderMap.h"
 
 #include <utility>
+#include <wtf/CrossThreadCopier.h>
 #include <wtf/text/StringView.h>
 
 namespace WebCore {
@@ -43,22 +44,21 @@ 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());
-
+    map.m_commonHeaders = crossThreadCopy(m_commonHeaders);
+    map.m_uncommonHeaders = crossThreadCopy(m_uncommonHeaders);
     return map;
 }
 
 String HTTPHeaderMap::get(const String& name) const
 {
     HTTPHeaderName headerName;
-    if (!findHTTPHeaderName(name, headerName))
-        return m_uncommonHeaders.get(name);
-    return m_commonHeaders.get(headerName);
+    if (findHTTPHeaderName(name, headerName))
+        return get(headerName);
+
+    auto index = m_uncommonHeaders.findMatching([&](auto& header) {
+        return equalIgnoringASCIICase(header.key, name);
+    });
+    return index != notFound ? m_uncommonHeaders[index].value : String();
 }
 
 #if USE(CF)
@@ -69,10 +69,16 @@ void HTTPHeaderMap::set(CFStringRef name, const String& value)
     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);
+        if (findHTTPHeaderName(StringView(reinterpret_cast<const LChar*>(nameCharacters), length), headerName)) {
+            auto index = m_commonHeaders.findMatching([&](auto& header) {
+                return header.key == headerName;
+            });
+            if (index == notFound)
+                m_commonHeaders.append(CommonHeader { headerName, value });
+            else
+                m_commonHeaders[index].value = value;
+        } else
+            set(String(nameCharacters, length), value);
         return;
     }
 
@@ -84,28 +90,54 @@ void HTTPHeaderMap::set(CFStringRef name, const String& value)
 void HTTPHeaderMap::set(const String& name, const String& value)
 {
     HTTPHeaderName headerName;
-    if (!findHTTPHeaderName(name, headerName)) {
-        m_uncommonHeaders.set(name, value);
+    if (findHTTPHeaderName(name, headerName)) {
+        set(headerName, value);
         return;
     }
-    m_commonHeaders.set(headerName, value);
+
+    auto index = m_uncommonHeaders.findMatching([&](auto& header) {
+        return equalIgnoringASCIICase(header.key, name);
+    });
+    if (index == notFound)
+        m_uncommonHeaders.append(UncommonHeader { name, value });
+    else
+        m_uncommonHeaders[index].value = value;
 }
 
 void HTTPHeaderMap::add(const String& name, const String& value)
 {
     HTTPHeaderName headerName;
-    if (!findHTTPHeaderName(name, headerName)) {
-        auto result = m_uncommonHeaders.add(name, value);
-        if (!result.isNewEntry)
-            result.iterator->value = result.iterator->value + ", " + value;
+    if (findHTTPHeaderName(name, headerName)) {
+        add(headerName, value);
         return;
     }
-    add(headerName, value);
+    auto index = m_uncommonHeaders.findMatching([&](auto& header) {
+        return equalIgnoringASCIICase(header.key, name);
+    });
+    if (index == notFound)
+        m_uncommonHeaders.append(UncommonHeader { name, value });
+    else
+        m_uncommonHeaders[index].value = makeString(m_uncommonHeaders[index].value, ", ", value);
+}
+
+void HTTPHeaderMap::append(const String& name, const String& value)
+{
+    ASSERT(!contains(name));
+
+    HTTPHeaderName headerName;
+    if (findHTTPHeaderName(name, headerName))
+        m_commonHeaders.append(CommonHeader { headerName, value });
+    else
+        m_uncommonHeaders.append(UncommonHeader { name, value });
 }
 
 bool HTTPHeaderMap::addIfNotPresent(HTTPHeaderName headerName, const String& value)
 {
-    return m_commonHeaders.add(headerName, value).isNewEntry;
+    if (contains(headerName))
+        return false;
+
+    m_commonHeaders.append(CommonHeader { headerName, value });
+    return true;
 }
 
 bool HTTPHeaderMap::contains(const String& name) const
@@ -113,7 +145,10 @@ bool HTTPHeaderMap::contains(const String& name) const
     HTTPHeaderName headerName;
     if (findHTTPHeaderName(name, headerName))
         return contains(headerName);
-    return m_uncommonHeaders.contains(name);
+
+    return m_uncommonHeaders.findMatching([&](auto& header) {
+        return equalIgnoringASCIICase(header.key, name);
+    }) != notFound;
 }
 
 bool HTTPHeaderMap::remove(const String& name)
@@ -121,34 +156,54 @@ bool HTTPHeaderMap::remove(const String& name)
     HTTPHeaderName headerName;
     if (findHTTPHeaderName(name, headerName))
         return remove(headerName);
-    return m_uncommonHeaders.remove(name);
+
+    return m_uncommonHeaders.removeFirstMatching([&](auto& header) {
+        return equalIgnoringASCIICase(header.key, name);
+    });
 }
 
 String HTTPHeaderMap::get(HTTPHeaderName name) const
 {
-    return m_commonHeaders.get(name);
+    auto index = m_commonHeaders.findMatching([&](auto& header) {
+        return header.key == name;
+    });
+    return index != notFound ? m_commonHeaders[index].value : String();
 }
 
 void HTTPHeaderMap::set(HTTPHeaderName name, const String& value)
 {
-    m_commonHeaders.set(name, value);
+    auto index = m_commonHeaders.findMatching([&](auto& header) {
+        return header.key == name;
+    });
+    if (index == notFound)
+        m_commonHeaders.append(CommonHeader { name, value });
+    else
+        m_commonHeaders[index].value = value;
 }
 
 bool HTTPHeaderMap::contains(HTTPHeaderName name) const
 {
-    return m_commonHeaders.contains(name);
+    return m_commonHeaders.findMatching([&](auto& header) {
+        return header.key == name;
+    }) != notFound;
 }
 
 bool HTTPHeaderMap::remove(HTTPHeaderName name)
 {
-    return m_commonHeaders.remove(name);
+    return m_commonHeaders.removeFirstMatching([&](auto& header) {
+        return header.key == name;
+    });
 }
 
 void HTTPHeaderMap::add(HTTPHeaderName name, const String& value)
 {
-    auto result = m_commonHeaders.add(name, value);
-    if (!result.isNewEntry)
-        result.iterator->value = result.iterator->value + ", " + value;
+    auto index = m_commonHeaders.findMatching([&](auto& header) {
+        return header.key == name;
+    });
+    if (index != notFound)
+        m_commonHeaders[index].value = makeString(m_commonHeaders[index].value, ", ", value);
+    else
+        m_commonHeaders.append(CommonHeader { name, value });
 }
 
 } // namespace WebCore
index c9b4030..0bcb03f 100644 (file)
@@ -38,12 +38,34 @@ namespace WebCore {
 
 class HTTPHeaderMap {
 public:
-    typedef HashMap<HTTPHeaderName, String, WTF::IntHash<HTTPHeaderName>, WTF::StrongEnumHashTraits<HTTPHeaderName>> CommonHeadersHashMap;
-    typedef HashMap<String, String, ASCIICaseInsensitiveHash> UncommonHeadersHashMap;
+    struct CommonHeader {
+        HTTPHeaderName key;
+        String value;
+
+        CommonHeader isolatedCopy() const { return { key , value.isolatedCopy() }; }
+        template <class Encoder> void encode(Encoder&) const;
+        template <class Decoder> static std::optional<CommonHeader> decode(Decoder&);
+
+        bool operator==(const CommonHeader& other) const { return key == other.key && value == other.value; }
+    };
+
+    struct UncommonHeader {
+        String key;
+        String value;
+
+        UncommonHeader isolatedCopy() const { return { key.isolatedCopy() , value.isolatedCopy() }; }
+        template <class Encoder> void encode(Encoder&) const;
+        template <class Decoder> static std::optional<UncommonHeader> decode(Decoder&);
+
+        bool operator==(const UncommonHeader& other) const { return key == other.key && value == other.value; }
+    };
+
+    typedef Vector<CommonHeader, 0, CrashOnOverflow, 6> CommonHeadersVector;
+    typedef Vector<UncommonHeader, 0, CrashOnOverflow, 0> UncommonHeadersVector;
 
     class HTTPHeaderMapConstIterator {
     public:
-        HTTPHeaderMapConstIterator(const HTTPHeaderMap& table, CommonHeadersHashMap::const_iterator commonHeadersIt, UncommonHeadersHashMap::const_iterator uncommonHeadersIt)
+        HTTPHeaderMapConstIterator(const HTTPHeaderMap& table, CommonHeadersVector::const_iterator commonHeadersIt, UncommonHeadersVector::const_iterator uncommonHeadersIt)
             : m_table(table)
             , m_commonHeadersIt(commonHeadersIt)
             , m_uncommonHeadersIt(uncommonHeadersIt)
@@ -85,7 +107,7 @@ public:
         }
 
     private:
-        bool updateKeyValue(CommonHeadersHashMap::const_iterator it)
+        bool updateKeyValue(CommonHeadersVector::const_iterator it)
         {
             if (it == m_table.commonHeaders().end())
                 return false;
@@ -94,7 +116,7 @@ public:
             m_keyValue.value = it->value;
             return true;
         }
-        bool updateKeyValue(UncommonHeadersHashMap::const_iterator it)
+        bool updateKeyValue(UncommonHeadersVector::const_iterator it)
         {
             if (it == m_table.uncommonHeaders().end())
                 return false;
@@ -105,8 +127,8 @@ public:
         }
 
         const HTTPHeaderMap& m_table;
-        CommonHeadersHashMap::const_iterator m_commonHeadersIt;
-        UncommonHeadersHashMap::const_iterator m_uncommonHeadersIt;
+        CommonHeadersVector::const_iterator m_commonHeadersIt;
+        UncommonHeadersVector::const_iterator m_uncommonHeadersIt;
         KeyValue m_keyValue;
     };
     typedef HTTPHeaderMapConstIterator const_iterator;
@@ -125,9 +147,16 @@ public:
         m_uncommonHeaders.clear();
     }
 
+    void shrinkToFit()
+    {
+        m_commonHeaders.shrinkToFit();
+        m_uncommonHeaders.shrinkToFit();
+    }
+
     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 void append(const String& name, const String& value);
     WEBCORE_EXPORT bool contains(const String&) const;
     bool remove(const String&);
 
@@ -151,10 +180,10 @@ public:
     template<size_t length> bool contains(const char (&)[length]) = delete;
     template<size_t length> bool remove(const char (&)[length]) = delete;
 
-    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 CommonHeadersVector& commonHeaders() const { return m_commonHeaders; }
+    const UncommonHeadersVector& uncommonHeaders() const { return m_uncommonHeaders; }
+    CommonHeadersVector& commonHeaders() { return m_commonHeaders; }
+    UncommonHeadersVector& 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()); }
@@ -173,37 +202,62 @@ public:
     template <class Decoder> static bool decode(Decoder&, HTTPHeaderMap&);
 
 private:
-    CommonHeadersHashMap m_commonHeaders;
-    UncommonHeadersHashMap m_uncommonHeaders;
+    CommonHeadersVector m_commonHeaders;
+    UncommonHeadersVector m_uncommonHeaders;
 };
 
 template <class Encoder>
-void HTTPHeaderMap::encode(Encoder& encoder) const
+void HTTPHeaderMap::CommonHeader::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.encodeEnum(key);
+    encoder << value;
+}
 
+template <class Decoder>
+auto HTTPHeaderMap::CommonHeader::decode(Decoder& decoder) -> std::optional<CommonHeader>
+{
+    HTTPHeaderName name;
+    if (!decoder.decodeEnum(name))
+        return std::nullopt;
+    String value;
+    if (!decoder.decode(value))
+        return std::nullopt;
+
+    return CommonHeader { name, WTFMove(value) };
+}
+
+template <class Encoder>
+void HTTPHeaderMap::UncommonHeader::encode(Encoder& encoder) const
+{
+    encoder << key;
+    encoder << value;
+}
+
+template <class Decoder>
+auto HTTPHeaderMap::UncommonHeader::decode(Decoder& decoder) -> std::optional<UncommonHeader>
+{
+    String name;
+    if (!decoder.decode(name))
+        return std::nullopt;
+    String value;
+    if (!decoder.decode(value))
+        return std::nullopt;
+
+    return UncommonHeader { WTFMove(name), WTFMove(value) };
+}
+
+template <class Encoder>
+void HTTPHeaderMap::encode(Encoder& encoder) const
+{
+    encoder << m_commonHeaders;
     encoder << m_uncommonHeaders;
 }
 
 template <class Decoder>
 bool HTTPHeaderMap::decode(Decoder& decoder, HTTPHeaderMap& headerMap)
 {
-    uint64_t commonHeadersSize;
-    if (!decoder.decode(commonHeadersSize))
+    if (!decoder.decode(headerMap.m_commonHeaders))
         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;
index 50d97c7..fb91421 100644 (file)
@@ -136,10 +136,10 @@ ResourceResponse ResourceResponseBase::filter(const ResourceResponse& response)
 
     HTTPHeaderSet accessControlExposeHeaderSet;
     parseAccessControlExposeHeadersAllowList(response.httpHeaderField(HTTPHeaderName::AccessControlExposeHeaders), accessControlExposeHeaderSet);
-    filteredResponse.m_httpHeaderFields.uncommonHeaders().removeIf([&](auto& entry) {
+    filteredResponse.m_httpHeaderFields.uncommonHeaders().removeAllMatching([&](auto& entry) {
         return !isCrossOriginSafeHeader(entry.key, accessControlExposeHeaderSet);
     });
-    filteredResponse.m_httpHeaderFields.commonHeaders().removeIf([&](auto& entry) {
+    filteredResponse.m_httpHeaderFields.commonHeaders().removeAllMatching([&](auto& entry) {
         return !isCrossOriginSafeHeader(entry.key, accessControlExposeHeaderSet);
     });
 
@@ -430,8 +430,8 @@ void ResourceResponseBase::sanitizeHTTPHeaderFields(SanitizationType type)
 {
     lazyInit(AllFields);
 
-    m_httpHeaderFields.commonHeaders().remove(HTTPHeaderName::SetCookie);
-    m_httpHeaderFields.commonHeaders().remove(HTTPHeaderName::SetCookie2);
+    m_httpHeaderFields.remove(HTTPHeaderName::SetCookie);
+    m_httpHeaderFields.remove(HTTPHeaderName::SetCookie2);
 
     switch (type) {
     case SanitizationType::RemoveCookies:
index bc669e6..0d869a8 100644 (file)
@@ -1,3 +1,14 @@
+2018-06-19  Chris Dumez  <cdumez@apple.com>
+
+        HTTPHeaderMap wastes 226KB of HashTable capacity on cnn.com
+        https://bugs.webkit.org/show_bug.cgi?id=186735
+        <rdar://problem/41189164>
+
+        Reviewed by Geoffrey Garen.
+
+        * NetworkProcess/cache/NetworkCacheCoders.cpp:
+        (WTF::Persistence::Coder<WebCore::HTTPHeaderMap>::decode):
+
 2018-06-19  Youenn Fablet  <youenn@apple.com>
 
         Network Preflights do not show in WebInspector after moving CORS checks to NetworkProcess
index 789b4b4..f35deb4 100644 (file)
@@ -52,7 +52,7 @@ bool Coder<WebCore::HTTPHeaderMap>::decode(Decoder& decoder, WebCore::HTTPHeader
         String value;
         if (!decoder.decode(value))
             return false;
-        headers.add(name, value);
+        headers.append(name, value);
     }
     return true;
 }
index f772102..49d951a 100644 (file)
@@ -234,19 +234,19 @@ template<typename KeyType, typename ValueType> struct ArgumentCoder<WTF::KeyValu
     }
 };
 
-template<bool fixedSizeElements, typename T, size_t inlineCapacity> struct VectorArgumentCoder;
+template<bool fixedSizeElements, typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> struct VectorArgumentCoder;
 
-template<typename T, size_t inlineCapacity> struct VectorArgumentCoder<false, T, inlineCapacity> {
-    static void encode(Encoder& encoder, const Vector<T, inlineCapacity>& vector)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> struct VectorArgumentCoder<false, T, inlineCapacity, OverflowHandler, minCapacity> {
+    static void encode(Encoder& encoder, const Vector<T, inlineCapacity, OverflowHandler, minCapacity>& vector)
     {
         encoder << static_cast<uint64_t>(vector.size());
         for (size_t i = 0; i < vector.size(); ++i)
             encoder << vector[i];
     }
 
-    static bool decode(Decoder& decoder, Vector<T, inlineCapacity>& vector)
+    static bool decode(Decoder& decoder, Vector<T, inlineCapacity, OverflowHandler, minCapacity>& vector)
     {
-        std::optional<Vector<T, inlineCapacity>> optional;
+        std::optional<Vector<T, inlineCapacity, OverflowHandler, minCapacity>> optional;
         decoder >> optional;
         if (!optional)
             return false;
@@ -254,13 +254,13 @@ template<typename T, size_t inlineCapacity> struct VectorArgumentCoder<false, T,
         return true;
     }
 
-    static std::optional<Vector<T, inlineCapacity>> decode(Decoder& decoder)
+    static std::optional<Vector<T, inlineCapacity, OverflowHandler, minCapacity>> decode(Decoder& decoder)
     {
         uint64_t size;
         if (!decoder.decode(size))
             return std::nullopt;
 
-        Vector<T, inlineCapacity> vector;
+        Vector<T, inlineCapacity, OverflowHandler, minCapacity> vector;
         for (size_t i = 0; i < size; ++i) {
             std::optional<T> element;
             decoder >> element;
@@ -273,14 +273,14 @@ template<typename T, size_t inlineCapacity> struct VectorArgumentCoder<false, T,
     }
 };
 
-template<typename T, size_t inlineCapacity> struct VectorArgumentCoder<true, T, inlineCapacity> {
-    static void encode(Encoder& encoder, const Vector<T, inlineCapacity>& vector)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> struct VectorArgumentCoder<true, T, inlineCapacity, OverflowHandler, minCapacity> {
+    static void encode(Encoder& encoder, const Vector<T, inlineCapacity, OverflowHandler, minCapacity>& vector)
     {
         encoder << static_cast<uint64_t>(vector.size());
         encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(vector.data()), vector.size() * sizeof(T), alignof(T));
     }
     
-    static bool decode(Decoder& decoder, Vector<T, inlineCapacity>& vector)
+    static bool decode(Decoder& decoder, Vector<T, inlineCapacity, OverflowHandler, minCapacity>& vector)
     {
         uint64_t size;
         if (!decoder.decode(size))
@@ -294,7 +294,7 @@ template<typename T, size_t inlineCapacity> struct VectorArgumentCoder<true, T,
             return false;
         }
 
-        Vector<T, inlineCapacity> temp;
+        Vector<T, inlineCapacity, OverflowHandler, minCapacity> temp;
         temp.grow(size);
 
         decoder.decodeFixedLengthData(reinterpret_cast<uint8_t*>(temp.data()), size * sizeof(T), alignof(T));
@@ -303,7 +303,7 @@ template<typename T, size_t inlineCapacity> struct VectorArgumentCoder<true, T,
         return true;
     }
     
-    static std::optional<Vector<T, inlineCapacity>> decode(Decoder& decoder)
+    static std::optional<Vector<T, inlineCapacity, OverflowHandler, minCapacity>> decode(Decoder& decoder)
     {
         uint64_t size;
         if (!decoder.decode(size))
@@ -317,7 +317,7 @@ template<typename T, size_t inlineCapacity> struct VectorArgumentCoder<true, T,
             return std::nullopt;
         }
         
-        Vector<T, inlineCapacity> vector;
+        Vector<T, inlineCapacity, OverflowHandler, minCapacity> vector;
         vector.grow(size);
         
         decoder.decodeFixedLengthData(reinterpret_cast<uint8_t*>(vector.data()), size * sizeof(T), alignof(T));
@@ -326,7 +326,7 @@ template<typename T, size_t inlineCapacity> struct VectorArgumentCoder<true, T,
     }
 };
 
-template<typename T, size_t inlineCapacity> struct ArgumentCoder<Vector<T, inlineCapacity>> : VectorArgumentCoder<std::is_arithmetic<T>::value, T, inlineCapacity> { };
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> struct ArgumentCoder<Vector<T, inlineCapacity, OverflowHandler, minCapacity>> : VectorArgumentCoder<std::is_arithmetic<T>::value, T, inlineCapacity, OverflowHandler, minCapacity> { };
 
 template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg> struct ArgumentCoder<HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>> {
     typedef HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> HashMapType;