diff options
Diffstat (limited to 'dom')
-rw-r--r-- | dom/fetch/InternalHeaders.cpp | 58 | ||||
-rw-r--r-- | dom/fetch/InternalHeaders.h | 31 | ||||
-rw-r--r-- | dom/html/nsTextEditorState.cpp | 31 | ||||
-rw-r--r-- | dom/html/nsTextEditorState.h | 2 | ||||
-rw-r--r-- | dom/security/nsCSPContext.cpp | 8 | ||||
-rw-r--r-- | dom/security/test/csp/file_frame_ancestors_ro.html | 1 | ||||
-rw-r--r-- | dom/security/test/csp/file_frame_ancestors_ro.html^headers^ | 1 | ||||
-rw-r--r-- | dom/security/test/csp/mochitest.ini | 3 | ||||
-rw-r--r-- | dom/security/test/csp/test_frame_ancestors_ro.html | 69 | ||||
-rw-r--r-- | dom/tests/mochitest/fetch/test_headers_common.js | 10 |
10 files changed, 175 insertions, 39 deletions
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<Entry>&& aHeaders, HeadersGuardEnum aGuard) : mGuard(aGuard) , mList(aHeaders) + , mListDirty(true) { } InternalHeaders::InternalHeaders(const nsTArray<HeadersEntry>& 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<nsCString>& 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<Entry> mList; + nsTArray<Entry> 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/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp index d70199362..187afb66d 100644 --- a/dom/html/nsTextEditorState.cpp +++ b/dom/html/nsTextEditorState.cpp @@ -1418,19 +1418,16 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue) } } - if (shouldInitializeEditor) { - // Initialize the plaintext editor - nsCOMPtr<nsIPlaintextEditor> textEditor(do_QueryInterface(newEditor)); - if (textEditor) { + // Initialize the plaintext editor + nsCOMPtr<nsIPlaintextEditor> textEditor = do_QueryInterface(newEditor); + if (textEditor) { + if (shouldInitializeEditor) { // Set up wrapping textEditor->SetWrapColumn(GetWrapCols()); - - // Set max text field length - int32_t maxLength; - if (GetMaxLength(&maxLength)) { - textEditor->SetMaxTextLength(maxLength); - } } + + // Set max text field length + textEditor->SetMaxTextLength(GetMaxLength()); } nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement); @@ -1895,22 +1892,22 @@ be called if @placeholder is the empty string when trimmed from line breaks"); return NS_OK; } -bool -nsTextEditorState::GetMaxLength(int32_t* aMaxLength) +int32_t +nsTextEditorState::GetMaxLength() { nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement); nsGenericHTMLElement* element = nsGenericHTMLElement::FromContentOrNull(content); - NS_ENSURE_TRUE(element, false); + if (NS_WARN_IF(!element)) { + return -1; + } const nsAttrValue* attr = element->GetParsedAttr(nsGkAtoms::maxlength); if (attr && attr->Type() == nsAttrValue::eInteger) { - *aMaxLength = attr->GetIntegerValue(); - - return true; + return attr->GetIntegerValue(); } - return false; + return -1; } void diff --git a/dom/html/nsTextEditorState.h b/dom/html/nsTextEditorState.h index 11494f155..caf5e8eed 100644 --- a/dom/html/nsTextEditorState.h +++ b/dom/html/nsTextEditorState.h @@ -203,7 +203,7 @@ public: * @param aMaxLength the value of the max length attr * @returns false if attr not defined */ - bool GetMaxLength(int32_t* aMaxLength); + int32_t GetMaxLength(); void ClearValueCache() { mCachedValue.Truncate(); } diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp index 5e435d4ca..a7517f65e 100644 --- a/dom/security/nsCSPContext.cpp +++ b/dom/security/nsCSPContext.cpp @@ -219,14 +219,6 @@ nsCSPContext::permitsInternal(CSPDirective aDir, nsAutoString violatedDirective; for (uint32_t p = 0; p < mPolicies.Length(); p++) { - - // According to the W3C CSP spec, frame-ancestors checks are ignored for - // report-only policies (when "monitoring"). - if (aDir == nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE && - mPolicies[p]->getReportOnlyFlag()) { - continue; - } - if (!mPolicies[p]->permits(aDir, aContentLocation, aNonce, diff --git a/dom/security/test/csp/file_frame_ancestors_ro.html b/dom/security/test/csp/file_frame_ancestors_ro.html new file mode 100644 index 000000000..ff5ae9cf9 --- /dev/null +++ b/dom/security/test/csp/file_frame_ancestors_ro.html @@ -0,0 +1 @@ +<html><body>Child Document</body></html> diff --git a/dom/security/test/csp/file_frame_ancestors_ro.html^headers^ b/dom/security/test/csp/file_frame_ancestors_ro.html^headers^ new file mode 100644 index 000000000..d018af3a9 --- /dev/null +++ b/dom/security/test/csp/file_frame_ancestors_ro.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy-Report-Only: frame-ancestors 'none'; report-uri http://mochi.test:8888/foo.sjs diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini index ca5c2c6ea..33b112020 100644 --- a/dom/security/test/csp/mochitest.ini +++ b/dom/security/test/csp/mochitest.ini @@ -91,6 +91,8 @@ support-files = file_bug941404.html file_bug941404_xhr.html file_bug941404_xhr.html^headers^ + file_frame_ancestors_ro.html + file_frame_ancestors_ro.html^headers^ file_hash_source.html file_dual_header_testserver.sjs file_hash_source.html^headers^ @@ -240,6 +242,7 @@ skip-if = toolkit == 'android' # Times out, not sure why (bug 1008445) [test_bug910139.html] [test_bug909029.html] [test_bug1229639.html] +[test_frame_ancestors_ro.html] [test_policyuri_regression_from_multipolicy.html] [test_nonce_source.html] [test_bug941404.html] diff --git a/dom/security/test/csp/test_frame_ancestors_ro.html b/dom/security/test/csp/test_frame_ancestors_ro.html new file mode 100644 index 000000000..90f68e25e --- /dev/null +++ b/dom/security/test/csp/test_frame_ancestors_ro.html @@ -0,0 +1,69 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for frame-ancestors support in Content-Security-Policy-Report-Only</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<iframe style="width: 100%" id="cspframe"></iframe> +<script type="text/javascript"> +const docUri = "http://mochi.test:8888/tests/dom/security/test/csp/file_frame_ancestors_ro.html"; +const frame = document.getElementById("cspframe"); + +let testResults = { + reportFired: false, + frameLoaded: false +}; + +function checkResults(reportObj) { + let cspReport = reportObj["csp-report"]; + is(cspReport["document-uri"], docUri, "Incorrect document-uri"); + + // we can not test for the whole referrer since it includes platform specific information + is(cspReport["referrer"], document.location.toString(), "Incorrect referrer"); + is(cspReport["blocked-uri"], document.location.toString(), "Incorrect blocked-uri"); + is(cspReport["violated-directive"], "frame-ancestors 'none'", "Incorrect violated-directive"); + is(cspReport["original-policy"], "frame-ancestors 'none'; report-uri http://mochi.test:8888/foo.sjs", "Incorrect original-policy"); + testResults.reportFired = true; +} + +let chromeScriptUrl = SimpleTest.getTestFileURL("file_report_chromescript.js"); +let script = SpecialPowers.loadChromeScript(chromeScriptUrl); + +script.addMessageListener('opening-request-completed', function ml(msg) { + if (msg.error) { + ok(false, "Could not query report (exception: " + msg.error + ")"); + } else { + try { + let reportObj = JSON.parse(msg.report); + // test for the proper values in the report object + checkResults(reportObj); + } catch (e) { + ok(false, "Error verifying report object (exception: " + e + ")"); + } + } + + script.removeMessageListener('opening-request-completed', ml); + script.sendAsyncMessage("finish"); + checkTestResults(); +}); + +frame.addEventListener( 'load', () => { + // Make sure the frame is still loaded + testResults.frameLoaded = true; + checkTestResults() +} ); + +function checkTestResults() { + if( testResults.reportFired && testResults.frameLoaded ) { + SimpleTest.finish(); + } +} + +SimpleTest.waitForExplicitFinish(); +frame.src = docUri; + +</script> +</body> +</html> 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() { |