⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 286171 in webkit


Ignore:
Timestamp:
Nov 25, 2021, 9:04:29 PM (5 years ago)
Author:
Jean-Yves Avenard
Message:

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:
Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r286169 r286171  
     12021-11-25  Jean-Yves Avenard  <jya@apple.com>
     2
     3        Avoid flattening a SharedBuffer when reading reading it through SharedBufferChunkReader.
     4        https://bugs.webkit.org/show_bug.cgi?id=233481
     5        rdar://problem/85733358
     6
     7        Reviewed by Cameron McCormack
     8
     9        SharedBufferChunkReader required the SharedBuffer to be flattened which
     10        would mutate the underlying SharedBuffer.
     11        The peek method was also incorrect if the data read overlapped multiple
     12        segments (it would return too many characters) and some members were used
     13        without being initialised.
     14
     15        Additionally, add a similar read method in SharedBuffer that will be used
     16        in bug 233030.
     17
     18        Covered in existing tests, API tests added.
     19
     20        * Headers.cmake:
     21        * WebCore.xcodeproj/project.pbxproj:
     22        * platform/SharedBuffer.cpp:
     23        (WebCore::SharedBuffer::getSomeData const):
     24        (WebCore::SharedBuffer::getSegmentForPosition const):
     25        (WebCore::SharedBuffer::read const):
     26        * platform/SharedBuffer.h:
     27        * platform/SharedBufferChunkReader.cpp:
     28        (WebCore::SharedBufferChunkReader::SharedBufferChunkReader):
     29        (WebCore::SharedBufferChunkReader::nextChunk):
     30        (WebCore::SharedBufferChunkReader::peek):
     31        * platform/SharedBufferChunkReader.h:
     32
    1332021-11-25  Antti Koivisto  <antti@apple.com>
    234
  • trunk/Source/WebCore/Headers.cmake

    r286019 r286171  
    11721172    platform/SerializedPlatformDataCueValue.h
    11731173    platform/SharedBuffer.h
     1174    platform/SharedBufferChunkReader.h
    11741175    platform/SharedStringHash.h
    11751176    platform/SleepDisabler.h
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r286167 r286171  
    489489                1A4A2DF00A1B852A00C807F8 /* JSHTMLAnchorElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4A2DEC0A1B852A00C807F8 /* JSHTMLAnchorElement.h */; };
    490490                1A4A954E0B4EDCCB002D8C3C /* SharedBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4A954C0B4EDCCB002D8C3C /* SharedBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; };
     491                51FA2EDF27506FDE0011C15D /* SharedBufferChunkReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 51FA2ED6274F78370011C15D /* SharedBufferChunkReader.h */; settings = {ATTRIBUTES = (Private, ); }; };
    491492                1A4DA4221CDD3A8300F4473C /* LinkIconCollector.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4DA4201CDD3A8300F4473C /* LinkIconCollector.h */; settings = {ATTRIBUTES = (Private, ); }; };
    492493                1A569D120D7E2B82007C3983 /* objc_class.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A569CE30D7E2B82007C3983 /* objc_class.h */; };
     
    96079608                51F886BE1F32920700C193EF /* JSNavigatorServiceWorker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSNavigatorServiceWorker.cpp; sourceTree = "<group>"; };
    96089609                51F886BF1F32920700C193EF /* JSNavigatorServiceWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSNavigatorServiceWorker.h; sourceTree = "<group>"; };
     9610                51FA2ED6274F78370011C15D /* SharedBufferChunkReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SharedBufferChunkReader.h; sourceTree = "<group>"; };
     9611                51FA2ED7274F78370011C15D /* SharedBufferChunkReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SharedBufferChunkReader.cpp; sourceTree = "<group>"; };
    96099612                51FB5502113E3E9100821176 /* JSCloseEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCloseEvent.h; sourceTree = "<group>"; };
    96109613                51FB5503113E3E9100821176 /* JSCloseEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCloseEvent.cpp; sourceTree = "<group>"; };
     
    2921429217                                1A4A954B0B4EDCCB002D8C3C /* SharedBuffer.cpp */,
    2921529218                                1A4A954C0B4EDCCB002D8C3C /* SharedBuffer.h */,
     29219                                51FA2ED7274F78370011C15D /* SharedBufferChunkReader.cpp */,
     29220                                51FA2ED6274F78370011C15D /* SharedBufferChunkReader.h */,
    2921629221                                834DFACE1F7DAE5700C2725B /* SharedStringHash.cpp */,
    2921729222                                834DFACC1F7DAE5600C2725B /* SharedStringHash.h */,
     
    3622336228                                1D9F0FC12122029B005D8FD4 /* ShareData.h in Headers */,
    3622436229                                1A4A954E0B4EDCCB002D8C3C /* SharedBuffer.h in Headers */,
     36230                                51FA2EDF27506FDE0011C15D /* SharedBufferChunkReader.h in Headers */,
    3622536231                                510A91DC24CF46FE00BFD89C /* SharedGamepadValue.h in Headers */,
    3622636232                                CD36C16B260A65CC00C8C529 /* SharedRoutingArbitrator.h in Headers */,
  • trunk/Source/WebCore/platform/SharedBuffer.cpp

    r285069 r286171  
    157157SharedBufferDataView SharedBuffer::getSomeData(size_t position) const
    158158{
     159    const DataSegmentVectorEntry* element = getSegmentForPosition(position);
     160    return { element->segment.copyRef(), position - element->beginPosition };
     161}
     162
     163const SharedBuffer::DataSegmentVectorEntry* SharedBuffer::getSegmentForPosition(size_t position) const
     164{
    159165    RELEASE_ASSERT(position < m_size);
    160166    auto comparator = [](const size_t& position, const DataSegmentVectorEntry& entry) {
     
    163169    const DataSegmentVectorEntry* element = std::upper_bound(m_segments.begin(), m_segments.end(), position, comparator);
    164170    element--; // std::upper_bound gives a pointer to the element that is greater than position. We want the element just before that.
    165     return { element->segment.copyRef(), position - element->beginPosition };
     171    return element;
    166172}
    167173
     
    276282    }
    277283    return false;
     284}
     285
     286Vector<uint8_t> SharedBuffer::read(size_t offset, size_t length) const
     287{
     288    Vector<uint8_t> data;
     289    if (offset >= size())
     290        return data;
     291    auto remaining = std::min(length, size() - offset);
     292    if (!remaining)
     293        return data;
     294
     295    data.reserveInitialCapacity(remaining);
     296    auto* currentSegment = getSegmentForPosition(offset);
     297    size_t offsetInSegment = offset - currentSegment->beginPosition;
     298    size_t availableInSegment = std::min(currentSegment->segment->size() - offsetInSegment, remaining);
     299    data.append(currentSegment->segment->data() + offsetInSegment, availableInSegment);
     300
     301    remaining -= availableInSegment;
     302
     303    auto* afterLastSegment = end();
     304
     305    while (remaining && ++currentSegment != afterLastSegment) {
     306        size_t lengthInSegment = std::min(currentSegment->segment->size(), remaining);
     307        data.append(currentSegment->segment->data(), lengthInSegment);
     308        remaining -= lengthInSegment;
     309    }
     310    return data;
    278311}
    279312
  • trunk/Source/WebCore/platform/SharedBuffer.h

    r285069 r286171  
    103103    const char* dataAsCharPtr() const { return reinterpret_cast<const char*>(data()); }
    104104    Vector<uint8_t> copyData() const;
     105    Vector<uint8_t> read(size_t offset, size_t length) const;
    105106
    106107    // Similar to copyData() but avoids copying and will take the data instead when it is safe (The SharedBuffer is not shared).
     
    245246    // Combines all the segments into a Vector and returns that vector after clearing the SharedBuffer.
    246247    Vector<uint8_t> takeData();
    247    
     248
     249    const DataSegmentVectorEntry* getSegmentForPosition(size_t positition) const;
     250
    248251    static RefPtr<SharedBuffer> createFromReadingFile(const String& filePath);
    249252
  • trunk/Source/WebCore/platform/SharedBufferChunkReader.cpp

    r278516 r286171  
    11/*
    22 * Copyright (C) 2011 Google Inc. All rights reserved.
     3 * Copyright (C) 2021 Apple Inc.  All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    3233#include "SharedBufferChunkReader.h"
    3334
     35namespace WebCore {
     36
    3437#if ENABLE(MHTML)
    3538
    36 // FIXME: This class is overkill. Remove this class and just iterate the segments of a SharedBuffer
    37 // using the cool new SharedBuffer::begin() and SharedBuffer::end() instead of using this class.
    38 
    39 #include "SharedBuffer.h"
    40 
    41 namespace WebCore {
    42 
    4339SharedBufferChunkReader::SharedBufferChunkReader(SharedBuffer* buffer, const Vector<char>& separator)
    44     : m_buffer(buffer)
     40    : m_iteratorCurrent(buffer->begin())
     41    , m_iteratorEnd(buffer->end())
     42    , m_segment(m_iteratorCurrent != m_iteratorEnd ? m_iteratorCurrent->segment->data() : nullptr)
    4543    , m_separator(separator)
    4644{
     
    4846
    4947SharedBufferChunkReader::SharedBufferChunkReader(SharedBuffer* buffer, const char* separator)
    50     : m_buffer(buffer)
     48    : m_iteratorCurrent(buffer->begin())
     49    , m_iteratorEnd(buffer->end())
     50    , m_segment(m_iteratorCurrent != m_iteratorEnd ? m_iteratorCurrent->segment->data() : nullptr)
    5151{
    5252    setSeparator(separator);
     
    6666bool SharedBufferChunkReader::nextChunk(Vector<uint8_t>& chunk, bool includeSeparator)
    6767{
    68     if (m_reachedEndOfFile)
     68    if (m_iteratorCurrent == m_iteratorEnd)
    6969        return false;
    7070
    7171    chunk.clear();
    7272    while (true) {
    73         while (m_segmentIndex < m_segmentLength) {
     73        while (m_segmentIndex < m_iteratorCurrent->segment->size()) {
     74            // FIXME: The existing code to check for separators doesn't work correctly with arbitrary separator strings.
    7475            auto currentCharacter = m_segment[m_segmentIndex++];
    7576            if (currentCharacter != m_separator[m_separatorIndex]) {
     
    9394        // Read the next segment.
    9495        m_segmentIndex = 0;
    95         m_bufferPosition += m_segmentLength;
    96         // Let's pretend all the data is in one block.
    97         // FIXME: This class should be removed in favor of just iterating the segments of the SharedBuffer.
    98         m_segment = m_buffer->data() + m_bufferPosition;
    99         m_segmentLength = m_buffer->size() - m_bufferPosition;
    100         if (!m_segmentLength) {
    101             m_reachedEndOfFile = true;
     96        if (++m_iteratorCurrent == m_iteratorEnd) {
     97            m_segment = nullptr;
    10298            if (m_separatorIndex > 0)
    10399                chunk.append(reinterpret_cast<const uint8_t*>(m_separator.data()), m_separatorIndex);
    104100            return !chunk.isEmpty();
    105101        }
     102        m_segment = m_iteratorCurrent->segment->data();
    106103    }
     104
    107105    ASSERT_NOT_REACHED();
    108106    return false;
     
    121119{
    122120    data.clear();
    123     if (requestedSize <= m_segmentLength - m_segmentIndex) {
    124         data.append(m_segment + m_segmentIndex, requestedSize);
    125         return requestedSize;
    126     }
     121    if (m_iteratorCurrent == m_iteratorEnd)
     122        return 0;
    127123
    128     size_t readBytesCount = m_segmentLength - m_segmentIndex;
    129     data.append(m_segment + m_segmentIndex, readBytesCount);
     124    size_t availableInSegment = std::min(m_iteratorCurrent->segment->size() - m_segmentIndex, requestedSize);
     125    data.append(m_segment + m_segmentIndex, availableInSegment);
    130126
    131     size_t bufferPosition = m_bufferPosition + m_segmentLength;
    132     const uint8_t* segment = nullptr;
     127    size_t readBytesCount = availableInSegment;
     128    requestedSize -= readBytesCount;
    133129
    134     // Let's pretend all the data is in one block.
    135     // FIXME: This class should be removed in favor of just iterating the segments of the SharedBuffer.
    136     if (bufferPosition != m_buffer->size()) {
    137         segment = m_buffer->data() + bufferPosition;
    138         size_t segmentLength = m_buffer->size() - bufferPosition;
    139         if (segmentLength > requestedSize)
    140             segmentLength = requestedSize;
    141         data.append(segment, segmentLength);
    142         readBytesCount += segmentLength;
    143         bufferPosition += segmentLength;
     130    auto currentSegment = m_iteratorCurrent;
     131
     132    while (requestedSize && ++currentSegment != m_iteratorEnd) {
     133        const uint8_t* segment = currentSegment->segment->data();
     134        size_t lengthInSegment = std::min(currentSegment->segment->size(), requestedSize);
     135        data.append(segment, lengthInSegment);
     136        readBytesCount += lengthInSegment;
     137        requestedSize -= lengthInSegment;
    144138    }
    145139    return readBytesCount;
    146140}
    147141
     142#endif
     143
    148144}
    149145
    150 #endif
  • trunk/Source/WebCore/platform/SharedBufferChunkReader.h

    r278516 r286171  
    11/*
    22 * Copyright (C) 2011 Google Inc. All rights reserved.
     3 * Copyright (C) 2021 Apple Inc.  All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    3334#if ENABLE(MHTML)
    3435
     36#include "SharedBuffer.h"
    3537#include <wtf/Vector.h>
    3638#include <wtf/text/WTFString.h>
     
    3840namespace WebCore {
    3941
    40 class SharedBuffer;
    41 
    42 class SharedBufferChunkReader {
     42class WEBCORE_EXPORT SharedBufferChunkReader {
    4343public:
    4444    SharedBufferChunkReader(SharedBuffer*, const Vector<char>& separator);
     
    5959
    6060private:
    61     SharedBuffer* m_buffer;
    62     size_t m_bufferPosition { 0 };
     61    SharedBuffer::DataSegmentVector::const_iterator m_iteratorCurrent;
     62    const SharedBuffer::DataSegmentVector::const_iterator m_iteratorEnd;
    6363    const uint8_t* m_segment { nullptr };
    64     size_t m_segmentLength { 0 };
    6564    size_t m_segmentIndex { 0 };
    66     bool m_reachedEndOfFile;
    6765    Vector<char> m_separator { false };
    6866    size_t m_separatorIndex { 0 };
  • trunk/Tools/ChangeLog

    r286170 r286171  
     12021-11-25  Jean-Yves Avenard  <jya@apple.com>
     2
     3        Avoid flattening a SharedBuffer when reading reading it through SharedBufferChunkReader.
     4        https://bugs.webkit.org/show_bug.cgi?id=233481
     5        rdar://problem/85733358
     6
     7        Reviewed by Cameron McCormack.
     8
     9        Add API tests.
     10        API tests original data come from the original bug that added
     11        SharedBufferChunkReader (bug 59946) and then expanded.
     12
     13        * TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp:
     14        (TestWebKitAPI::TEST_F):
     15        (TestWebKitAPI::readAllChunks):
     16        (TestWebKitAPI::checkChunks):
     17        (TestWebKitAPI::checkDataInRange):
     18        * TestWebKitAPI/Tests/WebCore/SharedBufferTest.h:
     19
    1202021-11-25  Lauro Moura  <lmoura@igalia.com>
    221
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp

    r283851 r286171  
    3232#include <JavaScriptCore/ArrayBuffer.h>
    3333#include <WebCore/SharedBuffer.h>
     34#if ENABLE(MHTML)
     35#include <WebCore/SharedBufferChunkReader.h>
     36#endif
    3437#include <wtf/MainThread.h>
    3538#include <wtf/StringExtras.h>
     
    230233}
    231234
    232 }
     235TEST_F(SharedBufferTest, read)
     236{
     237    const char* const simpleText = "This is a simple test.";
     238
     239    auto check = [](SharedBuffer& sharedBuffer) {
     240        Vector<uint8_t> data = sharedBuffer.read(4, 3);
     241        EXPECT_EQ(data.size(), 3u);
     242        EXPECT_EQ(String(data.data(), 3), " is");
     243
     244        data = sharedBuffer.read(4, 1000);
     245        EXPECT_EQ(data.size(), 18u);
     246
     247        EXPECT_EQ(String(data.data(), 18), " is a simple test.");
     248    };
     249    auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
     250    check(sharedBuffer);
     251
     252    sharedBuffer = SharedBuffer::create();
     253    for (size_t i = 0; i < strlen(simpleText); i++)
     254        sharedBuffer->append(&simpleText[i], 1);
     255    check(sharedBuffer);
     256
     257    sharedBuffer = SharedBuffer::create();
     258    for (size_t i = 0; i < strlen(simpleText); i += 2)
     259        sharedBuffer->append(&simpleText[i], 2);
     260    EXPECT_EQ(sharedBuffer->size(), strlen(simpleText));
     261    check(sharedBuffer);
     262}
     263
     264#if ENABLE(MHTML)
     265// SharedBufferChunkReader unit-tests -------------------------------------
     266template< typename T, size_t N >
     267constexpr size_t arraysize( const T (&)[N] ) { return N; }
     268
     269static void readAllChunks(std::vector<String>* chunks, SharedBuffer& buffer, const String& separator = "\r\n", bool includeSeparator = false)
     270{
     271    SharedBufferChunkReader chunkReader(&buffer, separator.utf8().data());
     272    String chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback(includeSeparator);
     273    while (!chunk.isNull()) {
     274        chunks->push_back(chunk);
     275        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback(includeSeparator);
     276    }
     277}
     278
     279static bool checkChunks(const std::vector<String>& chunks, const char* const expectedChunks[], size_t expectedSize)
     280{
     281    if (chunks.size() != expectedSize) {
     282        EXPECT_EQ(chunks.size(), expectedSize);
     283        return false;
     284    }
     285
     286    for (size_t i = 0; i < chunks.size(); ++i) {
     287        if (chunks[i] != expectedChunks[i])
     288            return false;
     289    }
     290    return true;
     291}
     292
     293static void checkDataInRange(const Vector<uint8_t>& data, size_t start, size_t length)
     294{
     295    ASSERT_EQ(data.size(), length);
     296    for (size_t i = 0; i < length; ++i)
     297        ASSERT_EQ(data[i], static_cast<uint8_t>(start + i));
     298}
     299
     300TEST_F(SharedBufferChunkReaderTest, includeSeparator)
     301{
     302    auto check = [](SharedBuffer& sharedBuffer) {
     303        SharedBufferChunkReader chunkReader(&sharedBuffer, "\x10\x11\x12");
     304        Vector<uint8_t> out;
     305        EXPECT_TRUE(chunkReader.nextChunk(out));
     306        checkDataInRange(out, 0, 16);
     307
     308        EXPECT_TRUE(chunkReader.nextChunk(out));
     309        checkDataInRange(out, 19, 237);
     310
     311        EXPECT_FALSE(chunkReader.nextChunk(out));
     312    };
     313    uint8_t data[256];
     314    for (size_t i = 0; i < 256; ++i)
     315        data[i] = i;
     316
     317    auto sharedBuffer = SharedBuffer::create(data, 256);
     318    check(sharedBuffer);
     319    sharedBuffer = SharedBuffer::create();
     320    for (size_t i = 0; i < 256; ++i) {
     321        char c = i;
     322        sharedBuffer->append(&c, 1);
     323    }
     324    check(sharedBuffer);
     325}
     326
     327TEST_F(SharedBufferChunkReaderTest, peekData)
     328{
     329    const char* const simpleText = "This is a simple test.";
     330
     331    auto check = [](SharedBuffer& sharedBuffer) {
     332        SharedBufferChunkReader chunkReader(&sharedBuffer, "is");
     333
     334        String chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
     335        EXPECT_EQ(chunk, "Th");
     336
     337        Vector<uint8_t> data;
     338        size_t read = chunkReader.peek(data, 3);
     339        EXPECT_EQ(read, 3u);
     340
     341        EXPECT_EQ(String(data.data(), 3), " is");
     342
     343        read = chunkReader.peek(data, 1000);
     344        EXPECT_EQ(read, 18u);
     345
     346        EXPECT_EQ(String(data.data(), 18), " is a simple test.");
     347
     348        // Ensure the cursor has not changed.
     349        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
     350        EXPECT_EQ(chunk, " ");
     351
     352        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
     353        EXPECT_EQ(chunk, " a simple test.");
     354
     355        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
     356        EXPECT_TRUE(chunk.isNull());
     357    };
     358    auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
     359    check(sharedBuffer);
     360
     361    sharedBuffer = SharedBuffer::create();
     362    for (size_t i = 0; i < strlen(simpleText); i++)
     363        sharedBuffer->append(&simpleText[i], 1);
     364    check(sharedBuffer);
     365
     366    sharedBuffer = SharedBuffer::create();
     367    for (size_t i = 0; i < strlen(simpleText); i += 2)
     368        sharedBuffer->append(&simpleText[i], 2);
     369    EXPECT_EQ(sharedBuffer->size(), strlen(simpleText));
     370    check(sharedBuffer);
     371}
     372
     373TEST_F(SharedBufferChunkReaderTest, readAllChunksInMultiSegment)
     374{
     375    const char* const simpleText = "This is the most ridiculous history there is.";
     376    auto check = [](SharedBuffer& sharedBuffer) {
     377        std::vector<String> chunks;
     378        const char* const expectedChunks1WithoutSeparator[] = { "Th", "s ", "s the most r", "d", "culous h", "story there ", "s." };
     379        readAllChunks(&chunks, sharedBuffer, "i");
     380        EXPECT_TRUE(checkChunks(chunks, expectedChunks1WithoutSeparator, arraysize(expectedChunks1WithoutSeparator)));
     381
     382        chunks.clear();
     383        const char* const expectedChunks1WithSeparator[] = { "Thi", "s i", "s the most ri", "di", "culous hi", "story there i", "s." };
     384        readAllChunks(&chunks, sharedBuffer, "i", true);
     385        EXPECT_TRUE(checkChunks(chunks, expectedChunks1WithSeparator, arraysize(expectedChunks1WithSeparator)));
     386
     387        chunks.clear();
     388        const char* const expectedChunks2WithoutSeparator[] = { "Th", " ", " the most ridiculous h", "tory there ", "." };
     389        readAllChunks(&chunks, sharedBuffer, "is");
     390        EXPECT_TRUE(checkChunks(chunks, expectedChunks2WithoutSeparator, arraysize(expectedChunks2WithoutSeparator)));
     391
     392        chunks.clear();
     393        const char* const expectedChunks2WithSeparator[] = { "This", " is", " the most ridiculous his", "tory there is", "." };
     394        readAllChunks(&chunks, sharedBuffer, "is", true);
     395        EXPECT_TRUE(checkChunks(chunks, expectedChunks2WithSeparator, arraysize(expectedChunks2WithSeparator)));
     396
     397        chunks.clear();
     398        const char* const expectedChunks3WithoutSeparator[] = { "This is the most ridiculous h", "ory there is." };
     399        readAllChunks(&chunks, sharedBuffer, "ist");
     400        EXPECT_TRUE(checkChunks(chunks, expectedChunks3WithoutSeparator, arraysize(expectedChunks3WithoutSeparator)));
     401
     402        chunks.clear();
     403        const char* const expectedChunks3WithSeparator[] = { "This is the most ridiculous hist", "ory there is." };
     404        readAllChunks(&chunks, sharedBuffer, "ist", true);
     405        EXPECT_TRUE(checkChunks(chunks, expectedChunks3WithSeparator, arraysize(expectedChunks3WithSeparator)));
     406    };
     407    auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
     408    check(sharedBuffer);
     409    sharedBuffer = SharedBuffer::create();
     410    for (size_t i = 0; i < strlen(simpleText); i++)
     411        sharedBuffer->append(&simpleText[i], 1);
     412    EXPECT_EQ(sharedBuffer->size(), strlen(simpleText));
     413    check(sharedBuffer);
     414
     415    sharedBuffer = SharedBuffer::create();
     416    for (size_t i = 0; i < strlen(simpleText); i += 5)
     417        sharedBuffer->append(&simpleText[i], 5);
     418    EXPECT_EQ(sharedBuffer->size(), strlen(simpleText));
     419    check(sharedBuffer);
     420}
     421
     422TEST_F(SharedBufferChunkReaderTest, changingIterator)
     423{
     424    {
     425        const char* const simpleText = "This is the most ridiculous history there is.";
     426        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
     427        SharedBufferChunkReader chunkReader(sharedBuffer.ptr(), "is");
     428        String chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
     429        EXPECT_EQ(chunk, "Th");
     430
     431        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
     432        EXPECT_EQ(chunk, " ");
     433
     434        chunkReader.setSeparator("he");
     435        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
     436        EXPECT_EQ(chunk, " t");
     437
     438        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
     439        EXPECT_EQ(chunk, " most ridiculous history t");
     440
     441        // Set a non existing separator.
     442        chunkReader.setSeparator("tchinta");
     443        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback();
     444        EXPECT_EQ(chunk, "re is.");
     445
     446        // We should be at the end of the string, so any subsequent call to nextChunk should return null.
     447        chunkReader.setSeparator(".");
     448        chunk = chunkReader.nextChunkAsUTF8StringWithLatin1Fallback(true);
     449        EXPECT_TRUE(chunk.isNull());
     450    }
     451
     452    {
     453        const char* const simpleText = "dog";
     454        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
     455        const char* const expectedChunksWithoutSeparator[] = { "" };
     456        std::vector<String> chunks;
     457        readAllChunks(&chunks, sharedBuffer, "dog");
     458        EXPECT_TRUE(checkChunks(chunks, expectedChunksWithoutSeparator, arraysize(expectedChunksWithoutSeparator)));
     459
     460        chunks.clear();
     461        const char* const expectedChunksWithSeparator[] = { "dog" };
     462        readAllChunks(&chunks, sharedBuffer, "dog", true);
     463        EXPECT_TRUE(checkChunks(chunks, expectedChunksWithSeparator, arraysize(expectedChunksWithSeparator)));
     464    }
     465
     466    // Ends with repeated separators.
     467    {
     468        const char* const simpleText = "Beaucoup de chats catcatcatcatcat";
     469        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
     470        const char* const expectedChunksWithoutSeparator[] = { "Beaucoup de chats ", "", "", "", "" };
     471        std::vector<String> chunks;
     472        readAllChunks(&chunks, sharedBuffer, "cat");
     473        EXPECT_TRUE(checkChunks(chunks, expectedChunksWithoutSeparator, arraysize(expectedChunksWithoutSeparator)));
     474
     475        chunks.clear();
     476        const char* const expectedChunksWithSeparator[] = { "Beaucoup de chats cat", "cat", "cat", "cat", "cat" };
     477        readAllChunks(&chunks, sharedBuffer, "cat", true);
     478        EXPECT_TRUE(checkChunks(chunks, expectedChunksWithSeparator, arraysize(expectedChunksWithSeparator)));
     479    }
     480    {
     481        const char* const simpleText = "This is a simple test.\r\nNothing special.\r\n";
     482        const char* const expectedChunks[] = { "This is a simple test.", "Nothing special." };
     483        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
     484        std::vector<String> chunks;
     485        readAllChunks(&chunks, sharedBuffer);
     486        EXPECT_TRUE(checkChunks(chunks, expectedChunks, arraysize(expectedChunks)));
     487    }
     488
     489    {
     490        const char* const simpleText = "This is a simple test.\r\nNothing special.";
     491        const char* const expectedChunks[] = { "This is a simple test.", "Nothing special." };
     492        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
     493
     494        std::vector<String> chunks;
     495        readAllChunks(&chunks, sharedBuffer);
     496        EXPECT_TRUE(checkChunks(chunks, expectedChunks, arraysize(expectedChunks)));
     497    }
     498
     499    {
     500        const char* const simpleText = "Simple line with no EOL.";
     501        const char* const expectedChunks[] = { "Simple line with no EOL." };
     502        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
     503
     504        std::vector<String> chunks;
     505        readAllChunks(&chunks, sharedBuffer);
     506        EXPECT_TRUE(checkChunks(chunks, expectedChunks, arraysize(expectedChunks)));
     507    }
     508
     509    {
     510        const char* const simpleText = "Line that has a EOL\r\nand then ends with a CR\r";
     511        const char* const expectedChunks[] = { "Line that has a EOL", "and then ends with a CR\r" };
     512        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
     513
     514        std::vector<String> chunks;
     515        readAllChunks(&chunks, sharedBuffer);
     516        EXPECT_TRUE(checkChunks(chunks, expectedChunks, arraysize(expectedChunks)));
     517    }
     518
     519    {
     520        const char* const simpleText = "Repeated CRs should not cause probems\r\r\r\nShouln't they?";
     521        const char* const expectedChunks[] = { "Repeated CRs should not cause probems\r\r", "Shouln't they?" };
     522        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
     523
     524        std::vector<String> chunks;
     525        readAllChunks(&chunks, sharedBuffer);
     526        EXPECT_TRUE(checkChunks(chunks, expectedChunks, arraysize(expectedChunks)));
     527    }
     528    {
     529        const char* const simpleText = "EOL\r\n betwe\r\nen segments";
     530        const char* const expectedChunks[] = { "EOL", " betwe", "en segments" };
     531        auto sharedBuffer = SharedBuffer::create(simpleText, strlen(simpleText));
     532
     533        std::vector<String> chunks;
     534        readAllChunks(&chunks, sharedBuffer);
     535        EXPECT_TRUE(checkChunks(chunks, expectedChunks, arraysize(expectedChunks)));
     536    }
     537}
     538#endif
     539
     540}
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.h

    r210310 r286171  
    4444};
    4545
     46#if ENABLE(MHTML)
     47class SharedBufferChunkReaderTest : public testing::Test {
     48};
     49#endif
     50
    4651} // namespace TestWebKitAPI
Note: See TracChangeset for help on using the changeset viewer.