Title: [280085] trunk
Revision
280085
Author
[email protected]
Date
2021-07-20 10:32:55 -0700 (Tue, 20 Jul 2021)

Log Message

REGRESSION (r278702): Cannot login to appaloosa-store.com/users/sign_in
https://bugs.webkit.org/show_bug.cgi?id=228096
<rdar://80596391>

Reviewed by Alex Christensen.

Source/WebCore:

r278702 added an optimization to FetchBodyConsumer::takeAsBlob() to avoid a copy of the data.
What I didn't realized when I wrote this optimization is that FetchBodyConsumer is copy-constructible
and its copy constructor gets called when calling FetchResponse.clone(). The copy constructor only
does a shallow-copy of its internal buffer so several FetchResponse objects can end up with their
FetchBodyConsumer using the same underlying SharedBuffer object. When that SharedBuffer is shared,
calling takeData() on it is unacceptable as it will disturb the body of other Fetch responses.

To address the issue, we now only call SharedBuffer::takeData() and avoid the copy when the
SharedBuffer has a RefCount of 1, meaning that is it not actually shared. In the cases where it
is shared, we copy the data, like we used to do before r278702.

Test: http/tests/fetch/response-clone-blob.html

* Modules/fetch/FetchBodyConsumer.cpp:
(WebCore::FetchBodyConsumer::takeAsBlob):

LayoutTests:

Add layout test coverage.

* http/tests/fetch/response-clone-blob-expected.txt: Added.
* http/tests/fetch/response-clone-blob.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (280084 => 280085)


--- trunk/LayoutTests/ChangeLog	2021-07-20 17:07:58 UTC (rev 280084)
+++ trunk/LayoutTests/ChangeLog	2021-07-20 17:32:55 UTC (rev 280085)
@@ -1,3 +1,16 @@
+2021-07-20  Chris Dumez  <[email protected]>
+
+        REGRESSION (r278702): Cannot login to appaloosa-store.com/users/sign_in
+        https://bugs.webkit.org/show_bug.cgi?id=228096
+        <rdar://80596391>
+
+        Reviewed by Alex Christensen.
+
+        Add layout test coverage.
+
+        * http/tests/fetch/response-clone-blob-expected.txt: Added.
+        * http/tests/fetch/response-clone-blob.html: Added.
+
 2021-07-20  Chris Lord  <[email protected]>
 
         Canvas and OffscreenCanvas getContext should check if argument is an object before trying to convert it to a dictionary

Added: trunk/LayoutTests/http/tests/fetch/response-clone-blob-expected.txt (0 => 280085)


--- trunk/LayoutTests/http/tests/fetch/response-clone-blob-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/fetch/response-clone-blob-expected.txt	2021-07-20 17:32:55 UTC (rev 280085)
@@ -0,0 +1,10 @@
+Tests that calling blob() on a cloned Fetch Response does not disturb the original response.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS originalText == cloneText is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/fetch/response-clone-blob.html (0 => 280085)


--- trunk/LayoutTests/http/tests/fetch/response-clone-blob.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/fetch/response-clone-blob.html	2021-07-20 17:32:55 UTC (rev 280085)
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that calling blob() on a cloned Fetch Response does not disturb the original response.");
+jsTestIsAsync = true;
+
+async function runTest() {
+    let originalResponse = await fetch("/resources/testharnessreport.js");
+    let clonedResponse = originalResponse.clone();
+
+    let originalBlob = await originalResponse.blob();
+    let cloneBlob = await clonedResponse.blob();
+
+    originalText = await originalBlob.text();
+    cloneText = await cloneBlob.text();
+
+    shouldBeTrue("originalText == cloneText");
+
+    finishJSTest();
+}
+
+_onload_ = runTest;
+</script>
+</body>
+</html>

Modified: trunk/Source/WTF/wtf/Vector.h (280084 => 280085)


--- trunk/Source/WTF/wtf/Vector.h	2021-07-20 17:07:58 UTC (rev 280084)
+++ trunk/Source/WTF/wtf/Vector.h	2021-07-20 17:32:55 UTC (rev 280085)
@@ -34,6 +34,7 @@
 #include <wtf/MathExtras.h>
 #include <wtf/Noncopyable.h>
 #include <wtf/NotFound.h>
+#include <wtf/Span.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/ValueCheck.h>
 #include <wtf/VectorTraits.h>
@@ -784,6 +785,7 @@
 
     template<typename U> ALWAYS_INLINE void append(const U* u, size_t size) { append<FailureAction::Crash>(u, size); }
     template<typename U> ALWAYS_INLINE bool tryAppend(const U* u, size_t size) { return append<FailureAction::Report>(u, size); }
+    template<typename U> ALWAYS_INLINE void append(Span<const U> span) { append(span.data(), span.size()); }
     template<typename U, size_t otherCapacity, typename OtherOverflowHandler, size_t otherMinCapacity, typename OtherMalloc> void appendVector(const Vector<U, otherCapacity, OtherOverflowHandler, otherMinCapacity, OtherMalloc>&);
     template<typename U, size_t otherCapacity, typename OtherOverflowHandler, size_t otherMinCapacity, typename OtherMalloc> void appendVector(Vector<U, otherCapacity, OtherOverflowHandler, otherMinCapacity, OtherMalloc>&&);
 

Modified: trunk/Source/WebCore/ChangeLog (280084 => 280085)


--- trunk/Source/WebCore/ChangeLog	2021-07-20 17:07:58 UTC (rev 280084)
+++ trunk/Source/WebCore/ChangeLog	2021-07-20 17:32:55 UTC (rev 280085)
@@ -1,3 +1,27 @@
+2021-07-20  Chris Dumez  <[email protected]>
+
+        REGRESSION (r278702): Cannot login to appaloosa-store.com/users/sign_in
+        https://bugs.webkit.org/show_bug.cgi?id=228096
+        <rdar://80596391>
+
+        Reviewed by Alex Christensen.
+
+        r278702 added an optimization to FetchBodyConsumer::takeAsBlob() to avoid a copy of the data.
+        What I didn't realized when I wrote this optimization is that FetchBodyConsumer is copy-constructible
+        and its copy constructor gets called when calling FetchResponse.clone(). The copy constructor only
+        does a shallow-copy of its internal buffer so several FetchResponse objects can end up with their
+        FetchBodyConsumer using the same underlying SharedBuffer object. When that SharedBuffer is shared,
+        calling takeData() on it is unacceptable as it will disturb the body of other Fetch responses.
+
+        To address the issue, we now only call SharedBuffer::takeData() and avoid the copy when the
+        SharedBuffer has a RefCount of 1, meaning that is it not actually shared. In the cases where it
+        is shared, we copy the data, like we used to do before r278702.
+
+        Test: http/tests/fetch/response-clone-blob.html
+
+        * Modules/fetch/FetchBodyConsumer.cpp:
+        (WebCore::FetchBodyConsumer::takeAsBlob):
+
 2021-07-20  Chris Lord  <[email protected]>
 
         Canvas and OffscreenCanvas getContext should check if argument is an object before trying to convert it to a dictionary

Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp (280084 => 280085)


--- trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp	2021-07-20 17:07:58 UTC (rev 280084)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp	2021-07-20 17:32:55 UTC (rev 280085)
@@ -351,7 +351,15 @@
     if (!m_buffer)
         return Blob::create(context, Vector<uint8_t>(), Blob::normalizedContentType(m_contentType));
 
-    auto data = "" nullptr)->takeData();
+    Vector<uint8_t> data;
+    auto buffer = std::exchange(m_buffer, nullptr);
+    if (buffer->hasOneRef())
+        data = "" // Avoid copying the data in the case where the buffer isn't shared.
+    else {
+        buffer->forEachSegment([&data](auto& span) {
+            data.append(span);
+        });
+    }
     return blobFromData(context, WTFMove(data), m_contentType);
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to