From 9ee567082c6bdf949f6c02a7e6c2e8b7bfef6590 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Sat, 14 Apr 2018 22:18:47 +0200 Subject: moebius#140: Fix: Fetch - headers should sort and combine https://github.com/MoonchildProductions/moebius/pull/140 --- dom/fetch/InternalHeaders.cpp | 58 ++++++++++++++++++++++++ dom/fetch/InternalHeaders.h | 31 +++++++++---- dom/tests/mochitest/fetch/test_headers_common.js | 10 ++-- 3 files changed, 86 insertions(+), 13 deletions(-) (limited to 'dom') diff --git a/dom/fetch/InternalHeaders.cpp b/dom/fetch/InternalHeaders.cpp index e81863173..11585615e 100644 --- a/dom/fetch/InternalHeaders.cpp +++ b/dom/fetch/InternalHeaders.cpp @@ -21,12 +21,14 @@ InternalHeaders::InternalHeaders(const nsTArray&& aHeaders, HeadersGuardEnum aGuard) : mGuard(aGuard) , mList(aHeaders) + , mListDirty(true) { } InternalHeaders::InternalHeaders(const nsTArray& aHeadersEntryList, HeadersGuardEnum aGuard) : mGuard(aGuard) + , mListDirty(true) { for (const HeadersEntry& headersEntry : aHeadersEntryList) { mList.AppendElement(Entry(headersEntry.name(), headersEntry.value())); @@ -56,6 +58,8 @@ InternalHeaders::Append(const nsACString& aName, const nsACString& aValue, return; } + SetListDirty(); + mList.AppendElement(Entry(lowerName, aValue)); } @@ -69,6 +73,8 @@ InternalHeaders::Delete(const nsACString& aName, ErrorResult& aRv) return; } + SetListDirty(); + // remove in reverse order to minimize copying for (int32_t i = mList.Length() - 1; i >= 0; --i) { if (lowerName == mList[i].mName) { @@ -155,6 +161,8 @@ InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorRes return; } + SetListDirty(); + int32_t firstIndex = INT32_MAX; // remove in reverse order to minimize copying @@ -177,6 +185,7 @@ InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorRes void InternalHeaders::Clear() { + SetListDirty(); mList.Clear(); } @@ -419,5 +428,54 @@ InternalHeaders::GetUnsafeHeaders(nsTArray& aNames) const } } +void +InternalHeaders::MaybeSortList() +{ + class Comparator { + public: + bool Equals(const Entry& aA, const Entry& aB) const + { + return aA.mName == aB.mName; + } + + bool LessThan(const Entry& aA, const Entry& aB) const + { + return aA.mName < aB.mName; + } + }; + + if (!mListDirty) { + return; + } + + mListDirty = false; + + Comparator comparator; + + mSortedList.Clear(); + for (const Entry& entry : mList) { + bool found = false; + for (Entry& sortedEntry : mSortedList) { + if (sortedEntry.mName == entry.mName) { + sortedEntry.mValue += ", "; + sortedEntry.mValue += entry.mValue; + found = true; + break; + } + } + + if (!found) { + mSortedList.InsertElementSorted(entry, comparator); + } + } +} + +void +InternalHeaders::SetListDirty() +{ + mSortedList.Clear(); + mListDirty = true; +} + } // namespace dom } // namespace mozilla diff --git a/dom/fetch/InternalHeaders.h b/dom/fetch/InternalHeaders.h index e47066669..9a6d6dae7 100644 --- a/dom/fetch/InternalHeaders.h +++ b/dom/fetch/InternalHeaders.h @@ -45,14 +45,23 @@ private: HeadersGuardEnum mGuard; nsTArray mList; + nsTArray mSortedList; + + // This boolean is set to true at any writing operation to mList. It's set to + // false when mSortedList is regenerated. This happens when the header is + // iterated. + bool mListDirty; + public: explicit InternalHeaders(HeadersGuardEnum aGuard = HeadersGuardEnum::None) : mGuard(aGuard) + , mListDirty(false) { } explicit InternalHeaders(const InternalHeaders& aOther) : mGuard(HeadersGuardEnum::None) + , mListDirty(true) { ErrorResult result; Fill(aOther, result); @@ -79,19 +88,22 @@ public: bool Has(const nsACString& aName, ErrorResult& aRv) const; void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv); - uint32_t GetIterableLength() const + uint32_t GetIterableLength() { - return mList.Length(); + MaybeSortList(); + return mSortedList.Length(); } - const NS_ConvertASCIItoUTF16 GetKeyAtIndex(unsigned aIndex) const + const NS_ConvertASCIItoUTF16 GetKeyAtIndex(unsigned aIndex) { - MOZ_ASSERT(aIndex < mList.Length()); - return NS_ConvertASCIItoUTF16(mList[aIndex].mName); + MaybeSortList(); + MOZ_ASSERT(aIndex < mSortedList.Length()); + return NS_ConvertASCIItoUTF16(mSortedList[aIndex].mName); } - const NS_ConvertASCIItoUTF16 GetValueAtIndex(unsigned aIndex) const + const NS_ConvertASCIItoUTF16 GetValueAtIndex(unsigned aIndex) { - MOZ_ASSERT(aIndex < mList.Length()); - return NS_ConvertASCIItoUTF16(mList[aIndex].mValue); + MaybeSortList(); + MOZ_ASSERT(aIndex < mSortedList.Length()); + return NS_ConvertASCIItoUTF16(mSortedList[aIndex].mValue); } void Clear(); @@ -152,6 +164,9 @@ private: const nsACString& aValue); static bool IsRevalidationHeader(const nsACString& aName); + + void MaybeSortList(); + void SetListDirty(); }; } // namespace dom diff --git a/dom/tests/mochitest/fetch/test_headers_common.js b/dom/tests/mochitest/fetch/test_headers_common.js index fe792b25b..8b17b6b12 100644 --- a/dom/tests/mochitest/fetch/test_headers_common.js +++ b/dom/tests/mochitest/fetch/test_headers_common.js @@ -213,12 +213,12 @@ function TestHeadersIterator() { var value_iter = headers.values(); var entries_iter = headers.entries(); - arrayEquals(iterate(key_iter), ["foo", "foo", "foo2"], "Correct key iterator"); - arrayEquals(iterate(value_iter), ["bar", ehsanInflated, "baz2"], "Correct value iterator"); - arrayEquals(iterate(entries_iter), [["foo", "bar"], ["foo", ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator"); + arrayEquals(iterate(key_iter), ["foo", "foo2"], "Correct key iterator"); + arrayEquals(iterate(value_iter), ["bar, " + ehsanInflated, "baz2"], "Correct value iterator"); + arrayEquals(iterate(entries_iter), [["foo", "bar, " + ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator"); - arrayEquals(iterateForOf(headers), [["foo", "bar"], ["foo", ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator"); - arrayEquals(iterateForOf(new Headers(headers)), [["foo", "bar"], ["foo", ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator"); + arrayEquals(iterateForOf(headers), [["foo", "bar, " + ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator"); + arrayEquals(iterateForOf(new Headers(headers)), [["foo", "bar, " + ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator"); } function runTest() { -- cgit v1.2.3