<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[286171] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/286171">286171</a></dd>
<dt>Author</dt> <dd>jya@apple.com</dd>
<dt>Date</dt> <dd>2021-11-25 21:04:29 -0800 (Thu, 25 Nov 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Avoid flattening a SharedBuffer when reading reading it through SharedBufferChunkReader.
https://bugs.webkit.org/show_bug.cgi?id=233481
rdar://problem/85733358

Source/WebCore:

Reviewed by Cameron McCormack

SharedBufferChunkReader required the SharedBuffer to be flattened which
would mutate the underlying SharedBuffer.
The peek method was also incorrect if the data read overlapped multiple
segments (it would return too many characters) and some members were used
without being initialised.

Additionally, add a similar read method in SharedBuffer that will be used
in bug 233030.

Covered in existing tests, API tests added.

* Headers.cmake:
* WebCore.xcodeproj/project.pbxproj:
* platform/SharedBuffer.cpp:
(WebCore::SharedBuffer::getSomeData const):
(WebCore::SharedBuffer::getSegmentForPosition const):
(WebCore::SharedBuffer::read const):
* platform/SharedBuffer.h:
* platform/SharedBufferChunkReader.cpp:
(WebCore::SharedBufferChunkReader::SharedBufferChunkReader):
(WebCore::SharedBufferChunkReader::nextChunk):
(WebCore::SharedBufferChunkReader::peek):
* platform/SharedBufferChunkReader.h:

Tools:

Reviewed by Cameron McCormack.

Add API tests.
API tests original data come from the original bug that added
SharedBufferChunkReader (bug 59946) and then expanded.

* TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp:
(TestWebKitAPI::TEST_F):
(TestWebKitAPI::readAllChunks):
(TestWebKitAPI::checkChunks):
(TestWebKitAPI::checkDataInRange):
* TestWebKitAPI/Tests/WebCore/SharedBufferTest.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreHeaderscmake">trunk/Source/WebCore/Headers.cmake</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCoreplatformSharedBuffercpp">trunk/Source/WebCore/platform/SharedBuffer.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformSharedBufferh">trunk/Source/WebCore/platform/SharedBuffer.h</a></li>
<li><a href="#trunkSourceWebCoreplatformSharedBufferChunkReadercpp">trunk/Source/WebCore/platform/SharedBufferChunkReader.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformSharedBufferChunkReaderh">trunk/Source/WebCore/platform/SharedBufferChunkReader.h</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebCoreSharedBuffercpp">trunk/Tools/TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebCoreSharedBufferTesth">trunk/Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (286170 => 286171)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-11-26 04:15:29 UTC (rev 286170)
+++ trunk/Source/WebCore/ChangeLog      2021-11-26 05:04:29 UTC (rev 286171)
</span><span class="lines">@@ -1,3 +1,35 @@
</span><ins>+2021-11-25  Jean-Yves Avenard  <jya@apple.com>
+
+        Avoid flattening a SharedBuffer when reading reading it through SharedBufferChunkReader.
+        https://bugs.webkit.org/show_bug.cgi?id=233481
+        rdar://problem/85733358
+
+        Reviewed by Cameron McCormack
+
+        SharedBufferChunkReader required the SharedBuffer to be flattened which
+        would mutate the underlying SharedBuffer.
+        The peek method was also incorrect if the data read overlapped multiple
+        segments (it would return too many characters) and some members were used
+        without being initialised.
+
+        Additionally, add a similar read method in SharedBuffer that will be used
+        in bug 233030.
+
+        Covered in existing tests, API tests added.
+
+        * Headers.cmake:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/SharedBuffer.cpp:
+        (WebCore::SharedBuffer::getSomeData const):
+        (WebCore::SharedBuffer::getSegmentForPosition const):
+        (WebCore::SharedBuffer::read const):
+        * platform/SharedBuffer.h:
+        * platform/SharedBufferChunkReader.cpp:
+        (WebCore::SharedBufferChunkReader::SharedBufferChunkReader):
+        (WebCore::SharedBufferChunkReader::nextChunk):
+        (WebCore::SharedBufferChunkReader::peek):
+        * platform/SharedBufferChunkReader.h:
+
</ins><span class="cx"> 2021-11-25  Antti Koivisto  <antti@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [:has() pseudo-class] Invalidation support for adding and removing nodes
</span></span></pre></div>
<a id="trunkSourceWebCoreHeaderscmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Headers.cmake (286170 => 286171)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Headers.cmake       2021-11-26 04:15:29 UTC (rev 286170)
+++ trunk/Source/WebCore/Headers.cmake  2021-11-26 05:04:29 UTC (rev 286171)
</span><span class="lines">@@ -1171,6 +1171,7 @@
</span><span class="cx">     platform/SerializedPlatformDataCue.h
</span><span class="cx">     platform/SerializedPlatformDataCueValue.h
</span><span class="cx">     platform/SharedBuffer.h
</span><ins>+    platform/SharedBufferChunkReader.h
</ins><span class="cx">     platform/SharedStringHash.h
</span><span class="cx">     platform/SleepDisabler.h
</span><span class="cx">     platform/SleepDisablerClient.h
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (286170 => 286171)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj   2021-11-26 04:15:29 UTC (rev 286170)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj      2021-11-26 05:04:29 UTC (rev 286171)
</span><span class="lines">@@ -488,6 +488,7 @@
</span><span class="cx">          1A494EDF0A123F4C00FDAFC1 /* JSDocumentFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A494EDD0A123F4C00FDAFC1 /* JSDocumentFragment.h */; };
</span><span class="cx">          1A4A2DF00A1B852A00C807F8 /* JSHTMLAnchorElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4A2DEC0A1B852A00C807F8 /* JSHTMLAnchorElement.h */; };
</span><span class="cx">          1A4A954E0B4EDCCB002D8C3C /* SharedBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4A954C0B4EDCCB002D8C3C /* SharedBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+               51FA2EDF27506FDE0011C15D /* SharedBufferChunkReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 51FA2ED6274F78370011C15D /* SharedBufferChunkReader.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">           1A4DA4221CDD3A8300F4473C /* LinkIconCollector.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4DA4201CDD3A8300F4473C /* LinkIconCollector.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          1A569D120D7E2B82007C3983 /* objc_class.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A569CE30D7E2B82007C3983 /* objc_class.h */; };
</span><span class="cx">          1A569D130D7E2B82007C3983 /* objc_class.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A569CE40D7E2B82007C3983 /* objc_class.mm */; };
</span><span class="lines">@@ -9606,6 +9607,8 @@
</span><span class="cx">          51F798EC1BE880D3008AE491 /* IDBIndexInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBIndexInfo.h; sourceTree = "<group>"; };
</span><span class="cx">          51F886BE1F32920700C193EF /* JSNavigatorServiceWorker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSNavigatorServiceWorker.cpp; sourceTree = "<group>"; };
</span><span class="cx">          51F886BF1F32920700C193EF /* JSNavigatorServiceWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSNavigatorServiceWorker.h; sourceTree = "<group>"; };
</span><ins>+               51FA2ED6274F78370011C15D /* SharedBufferChunkReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SharedBufferChunkReader.h; sourceTree = "<group>"; };
+               51FA2ED7274F78370011C15D /* SharedBufferChunkReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SharedBufferChunkReader.cpp; sourceTree = "<group>"; };
</ins><span class="cx">           51FB5502113E3E9100821176 /* JSCloseEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCloseEvent.h; sourceTree = "<group>"; };
</span><span class="cx">          51FB5503113E3E9100821176 /* JSCloseEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCloseEvent.cpp; sourceTree = "<group>"; };
</span><span class="cx">          51FB67D91AE6B5E400D06C5A /* ContentExtensionStyleSheet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContentExtensionStyleSheet.cpp; sourceTree = "<group>"; };
</span><span class="lines">@@ -29213,6 +29216,8 @@
</span><span class="cx">                          076D1C1D23F6D9D800D95B06 /* SerializedPlatformDataCueValue.h */,
</span><span class="cx">                          1A4A954B0B4EDCCB002D8C3C /* SharedBuffer.cpp */,
</span><span class="cx">                          1A4A954C0B4EDCCB002D8C3C /* SharedBuffer.h */,
</span><ins>+                               51FA2ED7274F78370011C15D /* SharedBufferChunkReader.cpp */,
+                               51FA2ED6274F78370011C15D /* SharedBufferChunkReader.h */,
</ins><span class="cx">                           834DFACE1F7DAE5700C2725B /* SharedStringHash.cpp */,
</span><span class="cx">                          834DFACC1F7DAE5600C2725B /* SharedStringHash.h */,
</span><span class="cx">                          93309EA0099EB78C0056E581 /* SharedTimer.h */,
</span><span class="lines">@@ -36222,6 +36227,7 @@
</span><span class="cx">                          FD1AF1501656F15100C6D4F7 /* ShapeValue.h in Headers */,
</span><span class="cx">                          1D9F0FC12122029B005D8FD4 /* ShareData.h in Headers */,
</span><span class="cx">                          1A4A954E0B4EDCCB002D8C3C /* SharedBuffer.h in Headers */,
</span><ins>+                               51FA2EDF27506FDE0011C15D /* SharedBufferChunkReader.h in Headers */,
</ins><span class="cx">                           510A91DC24CF46FE00BFD89C /* SharedGamepadValue.h in Headers */,
</span><span class="cx">                          CD36C16B260A65CC00C8C529 /* SharedRoutingArbitrator.h in Headers */,
</span><span class="cx">                          834DFAD01F7DAE5D00C2725B /* SharedStringHash.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformSharedBuffercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/SharedBuffer.cpp (286170 => 286171)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/SharedBuffer.cpp   2021-11-26 04:15:29 UTC (rev 286170)
+++ trunk/Source/WebCore/platform/SharedBuffer.cpp      2021-11-26 05:04:29 UTC (rev 286171)
</span><span class="lines">@@ -156,6 +156,12 @@
</span><span class="cx"> 
</span><span class="cx"> SharedBufferDataView SharedBuffer::getSomeData(size_t position) const
</span><span class="cx"> {
</span><ins>+    const DataSegmentVectorEntry* element = getSegmentForPosition(position);
+    return { element->segment.copyRef(), position - element->beginPosition };
+}
+
+const SharedBuffer::DataSegmentVectorEntry* SharedBuffer::getSegmentForPosition(size_t position) const
+{
</ins><span class="cx">     RELEASE_ASSERT(position < m_size);
</span><span class="cx">     auto comparator = [](const size_t& position, const DataSegmentVectorEntry& entry) {
</span><span class="cx">         return position < entry.beginPosition;
</span><span class="lines">@@ -162,7 +168,7 @@
</span><span class="cx">     };
</span><span class="cx">     const DataSegmentVectorEntry* element = std::upper_bound(m_segments.begin(), m_segments.end(), position, comparator);
</span><span class="cx">     element--; // std::upper_bound gives a pointer to the element that is greater than position. We want the element just before that.
</span><del>-    return { element->segment.copyRef(), position - element->beginPosition };
</del><ins>+    return element;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> String SharedBuffer::toHexString() const
</span><span class="lines">@@ -277,6 +283,33 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Vector<uint8_t> SharedBuffer::read(size_t offset, size_t length) const
+{
+    Vector<uint8_t> data;
+    if (offset >= size())
+        return data;
+    auto remaining = std::min(length, size() - offset);
+    if (!remaining)
+        return data;
+
+    data.reserveInitialCapacity(remaining);
+    auto* currentSegment = getSegmentForPosition(offset);
+    size_t offsetInSegment = offset - currentSegment->beginPosition;
+    size_t availableInSegment = std::min(currentSegment->segment->size() - offsetInSegment, remaining);
+    data.append(currentSegment->segment->data() + offsetInSegment, availableInSegment);
+
+    remaining -= availableInSegment;
+
+    auto* afterLastSegment = end();
+
+    while (remaining && ++currentSegment != afterLastSegment) {
+        size_t lengthInSegment = std::min(currentSegment->segment->size(), remaining);
+        data.append(currentSegment->segment->data(), lengthInSegment);
+        remaining -= lengthInSegment;
+    }
+    return data;
+}
+
</ins><span class="cx"> void SharedBuffer::copyTo(void* destination, size_t length) const
</span><span class="cx"> {
</span><span class="cx">     return copyTo(destination, 0, length);
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformSharedBufferh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/SharedBuffer.h (286170 => 286171)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/SharedBuffer.h     2021-11-26 04:15:29 UTC (rev 286170)
+++ trunk/Source/WebCore/platform/SharedBuffer.h        2021-11-26 05:04:29 UTC (rev 286171)
</span><span class="lines">@@ -102,6 +102,7 @@
</span><span class="cx">     const uint8_t* data() const;
</span><span class="cx">     const char* dataAsCharPtr() const { return reinterpret_cast<const char*>(data()); }
</span><span class="cx">     Vector<uint8_t> copyData() const;
</span><ins>+    Vector<uint8_t> read(size_t offset, size_t length) const;
</ins><span class="cx"> 
</span><span class="cx">     // Similar to copyData() but avoids copying and will take the data instead when it is safe (The SharedBuffer is not shared).
</span><span class="cx">     Vector<uint8_t> extractData();
</span><span class="lines">@@ -244,7 +245,9 @@
</span><span class="cx"> 
</span><span class="cx">     // Combines all the segments into a Vector and returns that vector after clearing the SharedBuffer.
</span><span class="cx">     Vector<uint8_t> takeData();
</span><del>-    
</del><ins>+
+    const DataSegmentVectorEntry* getSegmentForPosition(size_t positition) const;
+
</ins><span class="cx">     static RefPtr<SharedBuffer> createFromReadingFile(const String& filePath);
</span><span class="cx"> 
</span><span class="cx">     size_t m_size { 0 };
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformSharedBufferChunkReadercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/SharedBufferChunkReader.cpp (286170 => 286171)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/SharedBufferChunkReader.cpp        2021-11-26 04:15:29 UTC (rev 286170)
+++ trunk/Source/WebCore/platform/SharedBufferChunkReader.cpp   2021-11-26 05:04:29 UTC (rev 286171)
</span><span class="lines">@@ -1,5 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2011 Google Inc. All rights reserved.
</span><ins>+ * Copyright (C) 2021 Apple Inc.  All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions are
</span><span class="lines">@@ -31,23 +32,22 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "SharedBufferChunkReader.h"
</span><span class="cx"> 
</span><ins>+namespace WebCore {
+
</ins><span class="cx"> #if ENABLE(MHTML)
</span><span class="cx"> 
</span><del>-// FIXME: This class is overkill. Remove this class and just iterate the segments of a SharedBuffer
-// using the cool new SharedBuffer::begin() and SharedBuffer::end() instead of using this class.
-
-#include "SharedBuffer.h"
-
-namespace WebCore {
-
</del><span class="cx"> SharedBufferChunkReader::SharedBufferChunkReader(SharedBuffer* buffer, const Vector<char>& separator)
</span><del>-    : m_buffer(buffer)
</del><ins>+    : m_iteratorCurrent(buffer->begin())
+    , m_iteratorEnd(buffer->end())
+    , m_segment(m_iteratorCurrent != m_iteratorEnd ? m_iteratorCurrent->segment->data() : nullptr)
</ins><span class="cx">     , m_separator(separator)
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SharedBufferChunkReader::SharedBufferChunkReader(SharedBuffer* buffer, const char* separator)
</span><del>-    : m_buffer(buffer)
</del><ins>+    : m_iteratorCurrent(buffer->begin())
+    , m_iteratorEnd(buffer->end())
+    , m_segment(m_iteratorCurrent != m_iteratorEnd ? m_iteratorCurrent->segment->data() : nullptr)
</ins><span class="cx"> {
</span><span class="cx">     setSeparator(separator);
</span><span class="cx"> }
</span><span class="lines">@@ -65,12 +65,13 @@
</span><span class="cx"> 
</span><span class="cx"> bool SharedBufferChunkReader::nextChunk(Vector<uint8_t>& chunk, bool includeSeparator)
</span><span class="cx"> {
</span><del>-    if (m_reachedEndOfFile)
</del><ins>+    if (m_iteratorCurrent == m_iteratorEnd)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     chunk.clear();
</span><span class="cx">     while (true) {
</span><del>-        while (m_segmentIndex < m_segmentLength) {
</del><ins>+        while (m_segmentIndex < m_iteratorCurrent->segment->size()) {
+            // FIXME: The existing code to check for separators doesn't work correctly with arbitrary separator strings.
</ins><span class="cx">             auto currentCharacter = m_segment[m_segmentIndex++];
</span><span class="cx">             if (currentCharacter != m_separator[m_separatorIndex]) {
</span><span class="cx">                 if (m_separatorIndex > 0) {
</span><span class="lines">@@ -92,18 +93,15 @@
</span><span class="cx"> 
</span><span class="cx">         // Read the next segment.
</span><span class="cx">         m_segmentIndex = 0;
</span><del>-        m_bufferPosition += m_segmentLength;
-        // Let's pretend all the data is in one block.
-        // FIXME: This class should be removed in favor of just iterating the segments of the SharedBuffer.
-        m_segment = m_buffer->data() + m_bufferPosition;
-        m_segmentLength = m_buffer->size() - m_bufferPosition;
-        if (!m_segmentLength) {
-            m_reachedEndOfFile = true;
</del><ins>+        if (++m_iteratorCurrent == m_iteratorEnd) {
+            m_segment = nullptr;
</ins><span class="cx">             if (m_separatorIndex > 0)
</span><span class="cx">                 chunk.append(reinterpret_cast<const uint8_t*>(m_separator.data()), m_separatorIndex);
</span><span class="cx">             return !chunk.isEmpty();
</span><span class="cx">         }
</span><ins>+        m_segment = m_iteratorCurrent->segment->data();
</ins><span class="cx">     }
</span><ins>+
</ins><span class="cx">     ASSERT_NOT_REACHED();
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="lines">@@ -120,31 +118,28 @@
</span><span class="cx"> size_t SharedBufferChunkReader::peek(Vector<uint8_t>& data, size_t requestedSize)
</span><span class="cx"> {
</span><span class="cx">     data.clear();
</span><del>-    if (requestedSize <= m_segmentLength - m_segmentIndex) {
-        data.append(m_segment + m_segmentIndex, requestedSize);
-        return requestedSize;
-    }
</del><ins>+    if (m_iteratorCurrent == m_iteratorEnd)
+        return 0;
</ins><span class="cx"> 
</span><del>-    size_t readBytesCount = m_segmentLength - m_segmentIndex;
-    data.append(m_segment + m_segmentIndex, readBytesCount);
</del><ins>+    size_t availableInSegment = std::min(m_iteratorCurrent->segment->size() - m_segmentIndex, requestedSize);
+    data.append(m_segment + m_segmentIndex, availableInSegment);
</ins><span class="cx"> 
</span><del>-    size_t bufferPosition = m_bufferPosition + m_segmentLength;
-    const uint8_t* segment = nullptr;
</del><ins>+    size_t readBytesCount = availableInSegment;
+    requestedSize -= readBytesCount;
</ins><span class="cx"> 
</span><del>-    // Let's pretend all the data is in one block.
-    // FIXME: This class should be removed in favor of just iterating the segments of the SharedBuffer.
-    if (bufferPosition != m_buffer->size()) {
-        segment = m_buffer->data() + bufferPosition;
-        size_t segmentLength = m_buffer->size() - bufferPosition;
-        if (segmentLength > requestedSize)
-            segmentLength = requestedSize;
-        data.append(segment, segmentLength);
-        readBytesCount += segmentLength;
-        bufferPosition += segmentLength;
</del><ins>+    auto currentSegment = m_iteratorCurrent;
+
+    while (requestedSize && ++currentSegment != m_iteratorEnd) {
+        const uint8_t* segment = currentSegment->segment->data();
+        size_t lengthInSegment = std::min(currentSegment->segment->size(), requestedSize);
+        data.append(segment, lengthInSegment);
+        readBytesCount += lengthInSegment;
+        requestedSize -= lengthInSegment;
</ins><span class="cx">     }
</span><span class="cx">     return readBytesCount;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#endif
+
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-#endif
</del></span></pre></div>
<a id="trunkSourceWebCoreplatformSharedBufferChunkReaderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/SharedBufferChunkReader.h (286170 => 286171)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/SharedBufferChunkReader.h  2021-11-26 04:15:29 UTC (rev 286170)
+++ trunk/Source/WebCore/platform/SharedBufferChunkReader.h     2021-11-26 05:04:29 UTC (rev 286171)
</span><span class="lines">@@ -1,5 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2011 Google Inc. All rights reserved.
</span><ins>+ * Copyright (C) 2021 Apple Inc.  All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions are
</span><span class="lines">@@ -32,14 +33,13 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MHTML)
</span><span class="cx"> 
</span><ins>+#include "SharedBuffer.h"
</ins><span class="cx"> #include <wtf/Vector.h>
</span><span class="cx"> #include <wtf/text/WTFString.h>
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-class SharedBuffer;
-
-class SharedBufferChunkReader {
</del><ins>+class WEBCORE_EXPORT SharedBufferChunkReader {
</ins><span class="cx"> public:
</span><span class="cx">     SharedBufferChunkReader(SharedBuffer*, const Vector<char>& separator);
</span><span class="cx">     SharedBufferChunkReader(SharedBuffer*, const char* separator);
</span><span class="lines">@@ -58,12 +58,10 @@
</span><span class="cx">     size_t peek(Vector<uint8_t>&, size_t);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    SharedBuffer* m_buffer;
-    size_t m_bufferPosition { 0 };
</del><ins>+    SharedBuffer::DataSegmentVector::const_iterator m_iteratorCurrent;
+    const SharedBuffer::DataSegmentVector::const_iterator m_iteratorEnd;
</ins><span class="cx">     const uint8_t* m_segment { nullptr };
</span><del>-    size_t m_segmentLength { 0 };
</del><span class="cx">     size_t m_segmentIndex { 0 };
</span><del>-    bool m_reachedEndOfFile;
</del><span class="cx">     Vector<char> m_separator { false };
</span><span class="cx">     size_t m_separatorIndex { 0 };
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (286170 => 286171)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2021-11-26 04:15:29 UTC (rev 286170)
+++ trunk/Tools/ChangeLog       2021-11-26 05:04:29 UTC (rev 286171)
</span><span class="lines">@@ -1,3 +1,22 @@
</span><ins>+2021-11-25  Jean-Yves Avenard  <jya@apple.com>
+
+        Avoid flattening a SharedBuffer when reading reading it through SharedBufferChunkReader.
+        https://bugs.webkit.org/show_bug.cgi?id=233481
+        rdar://problem/85733358
+
+        Reviewed by Cameron McCormack.
+
+        Add API tests.
+        API tests original data come from the original bug that added
+        SharedBufferChunkReader (bug 59946) and then expanded.
+
+        * TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp:
+        (TestWebKitAPI::TEST_F):
+        (TestWebKitAPI::readAllChunks):
+        (TestWebKitAPI::checkChunks):
+        (TestWebKitAPI::checkDataInRange):
+        * TestWebKitAPI/Tests/WebCore/SharedBufferTest.h:
+
</ins><span class="cx"> 2021-11-25  Lauro Moura  <lmoura@igalia.com>
</span><span class="cx"> 
</span><span class="cx">         [GTK] Gardening API test authentication-success flaky timeout
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebCoreSharedBuffercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp (286170 => 286171)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp 2021-11-26 04:15:29 UTC (rev 286170)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp    2021-11-26 05:04:29 UTC (rev 286171)
</span><span class="lines">@@ -31,6 +31,9 @@
</span><span class="cx"> #include "Test.h"
</span><span class="cx"> #include <JavaScriptCore/ArrayBuffer.h>
</span><span class="cx"> #include <WebCore/SharedBuffer.h>
</span><ins>+#if ENABLE(MHTML)
+#include <WebCore/SharedBufferChunkReader.h>
+#endif
</ins><span class="cx"> #include <wtf/MainThread.h>
</span><span class="cx"> #include <wtf/StringExtras.h>
</span><span class="cx"> 
</span><span class="lines">@@ -229,4 +232,309 @@
</span><span class="cx">     EXPECT_EQ(buffer->toHexString(), "");
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+TEST_F(SharedBufferTest, read)
+{
+    const char* const simpleText = "This is a simple test.";
+
+    auto check = [](SharedBuffer& sharedBuffer) {
+        Vector<uint8_t> data = sharedBuffer.read(4, 3);
+        EXPECT_EQ(data.size(), 3u);
+        EXPECT_EQ(String(data.data(), 3), " is");
+
+        data = sharedBuffer.read(4, 1000);
+        EXPECT_EQ(data.size(), 18u);
+
+        EXPECT_EQ(String(data.data(), 18), " is a simple test.");
+    };
+    auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
+    check(sharedBuffer);
+
+    sharedBuffer = SharedBuffer::create();
+    for (size_t i = 0; i < strlen(simpleText); i++)
+        sharedBuffer->append(&simpleText[i], 1);
+    check(sharedBuffer);
+
+    sharedBuffer = SharedBuffer::create();
+    for (size_t i = 0; i < strlen(simpleText); i += 2)
+        sharedBuffer->append(&simpleText[i], 2);
+    EXPECT_EQ(sharedBuffer->size(), strlen(simpleText));
+    check(sharedBuffer);
</ins><span class="cx"> }
</span><ins>+
+#if ENABLE(MHTML)
+// SharedBufferChunkReader unit-tests -------------------------------------
+template< typename T, size_t N >
+constexpr size_t arraysize( const T (&)[N] ) { return N; }
+
+static void readAllChunks(std::vector<String>* chunks, SharedBuffer& buffer, const String& separator = "\r\n", bool includeSeparator = false)
+{
+    SharedBufferChunkReader chunkReader(&buffer, separator.utf8().data());
+    String chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback(includeSeparator);
+    while (!chunk.isNull()) {
+        chunks->push_back(chunk);
+        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback(includeSeparator);
+    }
+}
+
+static bool checkChunks(const std::vector<String>& chunks, const char* const expectedChunks[], size_t expectedSize)
+{
+    if (chunks.size() != expectedSize) {
+        EXPECT_EQ(chunks.size(), expectedSize);
+        return false;
+    }
+
+    for (size_t i = 0; i < chunks.size(); ++i) {
+        if (chunks[i] != expectedChunks[i])
+            return false;
+    }
+    return true;
+}
+
+static void checkDataInRange(const Vector<uint8_t>& data, size_t start, size_t length)
+{
+    ASSERT_EQ(data.size(), length);
+    for (size_t i = 0; i < length; ++i)
+        ASSERT_EQ(data[i], static_cast<uint8_t>(start + i));
+}
+
+TEST_F(SharedBufferChunkReaderTest, includeSeparator)
+{
+    auto check = [](SharedBuffer& sharedBuffer) {
+        SharedBufferChunkReader chunkReader(&sharedBuffer, "\x10\x11\x12");
+        Vector<uint8_t> out;
+        EXPECT_TRUE(chunkReader.nextChunk(out));
+        checkDataInRange(out, 0, 16);
+
+        EXPECT_TRUE(chunkReader.nextChunk(out));
+        checkDataInRange(out, 19, 237);
+
+        EXPECT_FALSE(chunkReader.nextChunk(out));
+    };
+    uint8_t data[256];
+    for (size_t i = 0; i < 256; ++i)
+        data[i] = i;
+
+    auto sharedBuffer = SharedBuffer::create(data, 256);
+    check(sharedBuffer);
+    sharedBuffer = SharedBuffer::create();
+    for (size_t i = 0; i < 256; ++i) {
+        char c = i;
+        sharedBuffer->append(&c, 1);
+    }
+    check(sharedBuffer);
+}
+
+TEST_F(SharedBufferChunkReaderTest, peekData)
+{
+    const char* const simpleText = "This is a simple test.";
+
+    auto check = [](SharedBuffer& sharedBuffer) {
+        SharedBufferChunkReader chunkReader(&sharedBuffer, "is");
+
+        String chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
+        EXPECT_EQ(chunk, "Th");
+
+        Vector<uint8_t> data;
+        size_t read = chunkReader.peek(data, 3);
+        EXPECT_EQ(read, 3u);
+
+        EXPECT_EQ(String(data.data(), 3), " is");
+
+        read = chunkReader.peek(data, 1000);
+        EXPECT_EQ(read, 18u);
+
+        EXPECT_EQ(String(data.data(), 18), " is a simple test.");
+
+        // Ensure the cursor has not changed.
+        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
+        EXPECT_EQ(chunk, " ");
+
+        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
+        EXPECT_EQ(chunk, " a simple test.");
+
+        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
+        EXPECT_TRUE(chunk.isNull());
+    };
+    auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
+    check(sharedBuffer);
+
+    sharedBuffer = SharedBuffer::create();
+    for (size_t i = 0; i < strlen(simpleText); i++)
+        sharedBuffer->append(&simpleText[i], 1);
+    check(sharedBuffer);
+
+    sharedBuffer = SharedBuffer::create();
+    for (size_t i = 0; i < strlen(simpleText); i += 2)
+        sharedBuffer->append(&simpleText[i], 2);
+    EXPECT_EQ(sharedBuffer->size(), strlen(simpleText));
+    check(sharedBuffer);
+}
+
+TEST_F(SharedBufferChunkReaderTest, readAllChunksInMultiSegment)
+{
+    const char* const simpleText = "This is the most ridiculous history there is.";
+    auto check = [](SharedBuffer& sharedBuffer) {
+        std::vector<String> chunks;
+        const char* const expectedChunks1WithoutSeparator[] = { "Th", "s ", "s the most r", "d", "culous h", "story there ", "s." };
+        readAllChunks(&chunks, sharedBuffer, "i");
+        EXPECT_TRUE(checkChunks(chunks, expectedChunks1WithoutSeparator, arraysize(expectedChunks1WithoutSeparator)));
+
+        chunks.clear();
+        const char* const expectedChunks1WithSeparator[] = { "Thi", "s i", "s the most ri", "di", "culous hi", "story there i", "s." };
+        readAllChunks(&chunks, sharedBuffer, "i", true);
+        EXPECT_TRUE(checkChunks(chunks, expectedChunks1WithSeparator, arraysize(expectedChunks1WithSeparator)));
+
+        chunks.clear();
+        const char* const expectedChunks2WithoutSeparator[] = { "Th", " ", " the most ridiculous h", "tory there ", "." };
+        readAllChunks(&chunks, sharedBuffer, "is");
+        EXPECT_TRUE(checkChunks(chunks, expectedChunks2WithoutSeparator, arraysize(expectedChunks2WithoutSeparator)));
+
+        chunks.clear();
+        const char* const expectedChunks2WithSeparator[] = { "This", " is", " the most ridiculous his", "tory there is", "." };
+        readAllChunks(&chunks, sharedBuffer, "is", true);
+        EXPECT_TRUE(checkChunks(chunks, expectedChunks2WithSeparator, arraysize(expectedChunks2WithSeparator)));
+
+        chunks.clear();
+        const char* const expectedChunks3WithoutSeparator[] = { "This is the most ridiculous h", "ory there is." };
+        readAllChunks(&chunks, sharedBuffer, "ist");
+        EXPECT_TRUE(checkChunks(chunks, expectedChunks3WithoutSeparator, arraysize(expectedChunks3WithoutSeparator)));
+
+        chunks.clear();
+        const char* const expectedChunks3WithSeparator[] = { "This is the most ridiculous hist", "ory there is." };
+        readAllChunks(&chunks, sharedBuffer, "ist", true);
+        EXPECT_TRUE(checkChunks(chunks, expectedChunks3WithSeparator, arraysize(expectedChunks3WithSeparator)));
+    };
+    auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
+    check(sharedBuffer);
+    sharedBuffer = SharedBuffer::create();
+    for (size_t i = 0; i < strlen(simpleText); i++)
+        sharedBuffer->append(&simpleText[i], 1);
+    EXPECT_EQ(sharedBuffer->size(), strlen(simpleText));
+    check(sharedBuffer);
+
+    sharedBuffer = SharedBuffer::create();
+    for (size_t i = 0; i < strlen(simpleText); i += 5)
+        sharedBuffer->append(&simpleText[i], 5);
+    EXPECT_EQ(sharedBuffer->size(), strlen(simpleText));
+    check(sharedBuffer);
+}
+
+TEST_F(SharedBufferChunkReaderTest, changingIterator)
+{
+    {
+        const char* const simpleText = "This is the most ridiculous history there is.";
+        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
+        SharedBufferChunkReader chunkReader(sharedBuffer.ptr(), "is");
+        String chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
+        EXPECT_EQ(chunk, "Th");
+
+        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
+        EXPECT_EQ(chunk, " ");
+
+        chunkReader.setSeparator("he");
+        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
+        EXPECT_EQ(chunk, " t");
+
+        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
+        EXPECT_EQ(chunk, " most ridiculous history t");
+
+        // Set a non existing separator.
+        chunkReader.setSeparator("tchinta");
+        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
+        EXPECT_EQ(chunk, "re is.");
+
+        // We should be at the end of the string, so any subsequent call to nextChunk should return null.
+        chunkReader.setSeparator(".");
+        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback(true);
+        EXPECT_TRUE(chunk.isNull());
+    }
+
+    {
+        const char* const simpleText = "dog";
+        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
+        const char* const expectedChunksWithoutSeparator[] = { "" };
+        std::vector<String> chunks;
+        readAllChunks(&chunks, sharedBuffer, "dog");
+        EXPECT_TRUE(checkChunks(chunks, expectedChunksWithoutSeparator, arraysize(expectedChunksWithoutSeparator)));
+
+        chunks.clear();
+        const char* const expectedChunksWithSeparator[] = { "dog" };
+        readAllChunks(&chunks, sharedBuffer, "dog", true);
+        EXPECT_TRUE(checkChunks(chunks, expectedChunksWithSeparator, arraysize(expectedChunksWithSeparator)));
+    }
+
+    // Ends with repeated separators.
+    {
+        const char* const simpleText = "Beaucoup de chats catcatcatcatcat";
+        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
+        const char* const expectedChunksWithoutSeparator[] = { "Beaucoup de chats ", "", "", "", "" };
+        std::vector<String> chunks;
+        readAllChunks(&chunks, sharedBuffer, "cat");
+        EXPECT_TRUE(checkChunks(chunks, expectedChunksWithoutSeparator, arraysize(expectedChunksWithoutSeparator)));
+
+        chunks.clear();
+        const char* const expectedChunksWithSeparator[] = { "Beaucoup de chats cat", "cat", "cat", "cat", "cat" };
+        readAllChunks(&chunks, sharedBuffer, "cat", true);
+        EXPECT_TRUE(checkChunks(chunks, expectedChunksWithSeparator, arraysize(expectedChunksWithSeparator)));
+    }
+    {
+        const char* const simpleText = "This is a simple test.\r\nNothing special.\r\n";
+        const char* const expectedChunks[] = { "This is a simple test.", "Nothing special." };
+        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
+        std::vector<String> chunks;
+        readAllChunks(&chunks, sharedBuffer);
+        EXPECT_TRUE(checkChunks(chunks, expectedChunks, arraysize(expectedChunks)));
+    }
+
+    {
+        const char* const simpleText = "This is a simple test.\r\nNothing special.";
+        const char* const expectedChunks[] = { "This is a simple test.", "Nothing special." };
+        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
+
+        std::vector<String> chunks;
+        readAllChunks(&chunks, sharedBuffer);
+        EXPECT_TRUE(checkChunks(chunks, expectedChunks, arraysize(expectedChunks)));
+    }
+
+    {
+        const char* const simpleText = "Simple line with no EOL.";
+        const char* const expectedChunks[] = { "Simple line with no EOL." };
+        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
+
+        std::vector<String> chunks;
+        readAllChunks(&chunks, sharedBuffer);
+        EXPECT_TRUE(checkChunks(chunks, expectedChunks, arraysize(expectedChunks)));
+    }
+
+    {
+        const char* const simpleText = "Line that has a EOL\r\nand then ends with a CR\r";
+        const char* const expectedChunks[] = { "Line that has a EOL", "and then ends with a CR\r" };
+        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
+
+        std::vector<String> chunks;
+        readAllChunks(&chunks, sharedBuffer);
+        EXPECT_TRUE(checkChunks(chunks, expectedChunks, arraysize(expectedChunks)));
+    }
+
+    {
+        const char* const simpleText = "Repeated CRs should not cause probems\r\r\r\nShouln't they?";
+        const char* const expectedChunks[] = { "Repeated CRs should not cause probems\r\r", "Shouln't they?" };
+        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
+
+        std::vector<String> chunks;
+        readAllChunks(&chunks, sharedBuffer);
+        EXPECT_TRUE(checkChunks(chunks, expectedChunks, arraysize(expectedChunks)));
+    }
+    {
+        const char* const simpleText = "EOL\r\n betwe\r\nen segments";
+        const char* const expectedChunks[] = { "EOL", " betwe", "en segments" };
+        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
+
+        std::vector<String> chunks;
+        readAllChunks(&chunks, sharedBuffer);
+        EXPECT_TRUE(checkChunks(chunks, expectedChunks, arraysize(expectedChunks)));
+    }
+}
+#endif
+
+}
</ins></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebCoreSharedBufferTesth"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.h (286170 => 286171)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.h       2021-11-26 04:15:29 UTC (rev 286170)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.h  2021-11-26 05:04:29 UTC (rev 286171)
</span><span class="lines">@@ -43,4 +43,9 @@
</span><span class="cx">     String m_tempEmptyFilePath;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+#if ENABLE(MHTML)
+class SharedBufferChunkReaderTest : public testing::Test {
+};
+#endif
+
</ins><span class="cx"> } // namespace TestWebKitAPI
</span></span></pre>
</div>
</div>

</body>
</html>