| Index: third_party/WebKit/Source/modules/fetch/MultipartParserTest.cpp
|
| diff --git a/third_party/WebKit/Source/modules/fetch/MultipartParserTest.cpp b/third_party/WebKit/Source/modules/fetch/MultipartParserTest.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3aa0446b32820e51d2eb8325738f6a7a8dcbdcd8
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/modules/fetch/MultipartParserTest.cpp
|
| @@ -0,0 +1,233 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "modules/fetch/MultipartParser.h"
|
| +
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +#include <algorithm>
|
| +
|
| +namespace blink {
|
| +
|
| +namespace {
|
| +
|
| +class MockClient final : public GarbageCollectedFinalized<MockClient>, public MultipartParser::Client {
|
| + USING_GARBAGE_COLLECTED_MIXIN(MockClient);
|
| +public:
|
| + struct Part {
|
| + Part() = default;
|
| + explicit Part(const ResourceResponse& response) : response(response), dataFullyReceived(false) {}
|
| + ResourceResponse response;
|
| + Vector<char> data;
|
| + bool dataFullyReceived;
|
| + };
|
| + void partHeaderFieldsInMultipartReceived(const ResourceResponse& response) override
|
| + {
|
| + m_parts.append(response);
|
| + }
|
| + void partDataInMultipartReceived(const char* bytes, size_t size) override
|
| + {
|
| + m_parts.last().data.append(bytes, size);
|
| + }
|
| + void partDataInMultipartFullyReceived() override
|
| + {
|
| + m_parts.last().dataFullyReceived = true;
|
| + }
|
| + size_t numberOfParts() const
|
| + {
|
| + return m_parts.size();
|
| + }
|
| + const Part& part(size_t partIndex) const
|
| + {
|
| + EXPECT_LT(partIndex, numberOfParts());
|
| + return partIndex < numberOfParts() ? m_parts[partIndex] : m_emptyPart;
|
| + }
|
| +private:
|
| + Part m_emptyPart;
|
| + Vector<Part> m_parts;
|
| +};
|
| +
|
| +const char* kBytes =
|
| + "preamble"
|
| + "\r\n--boundary\r\ncontent-type: application/xhtml+xml\r\n\r\n1"
|
| + "\r\n--boundary\t\r\ncontent-type: text/html\r\n\r\n2\r\n--\r\n--bound--\r\n--\r\n2"
|
| + "\r\n--boundary \r\ncontent-type: text/plain\r\n\r\n333"
|
| + "\r\n--boundary--\t \r\n"
|
| + "epilogue";
|
| +
|
| +TEST(MultipartParserTest, AppendDataInChunks)
|
| +{
|
| + const size_t sizes[] = {1u, 2u, strlen(kBytes)};
|
| +
|
| + Vector<char> boundary;
|
| + boundary.append("boundary", 8u);
|
| + for (size_t size : sizes) {
|
| + MockClient* client = new MockClient;
|
| + MultipartParser* parser = new MultipartParser(boundary, client);
|
| +
|
| + for (size_t i = 0u; kBytes[i]; i += size)
|
| + EXPECT_TRUE(parser->appendData(kBytes + i, std::min(size, strlen(kBytes + i))));
|
| + EXPECT_TRUE(parser->finish()) << " size=" << size;
|
| + EXPECT_EQ(3u, client->numberOfParts()) << " size=" << size;
|
| + EXPECT_EQ(String("1"), client->part(0).data);
|
| + EXPECT_TRUE(client->part(0).dataFullyReceived);
|
| + EXPECT_EQ(String("2\r\n--\r\n--bound--\r\n--\r\n2"), client->part(1).data);
|
| + EXPECT_TRUE(client->part(1).dataFullyReceived);
|
| + EXPECT_EQ(String("333"), client->part(2).data);
|
| + EXPECT_TRUE(client->part(2).dataFullyReceived);
|
| + }
|
| +}
|
| +
|
| +TEST(MultipartParserTest, Epilogue)
|
| +{
|
| + const size_t ends[] = {
|
| + 0u, // Non-empty epilogue in the end.
|
| + 8u, // Empty epilogue in the end.
|
| + 9u, // Partial CRLF after close delimiter in the end.
|
| + 10u, // No CRLF after close delimiter in the end.
|
| + 12u, // No transport padding nor CRLF after close delimiter in the end.
|
| + 13u, // Partial close delimiter in the end.
|
| + 14u, // No close delimiter but a delimiter in the end.
|
| + 15u // Partial delimiter in the end.
|
| + };
|
| +
|
| + Vector<char> boundary;
|
| + boundary.append("boundary", 8u);
|
| + for (size_t end : ends) {
|
| + MockClient* client = new MockClient;
|
| + MultipartParser* parser = new MultipartParser(boundary, client);
|
| +
|
| + EXPECT_TRUE(parser->appendData(kBytes, strlen(kBytes) - end));
|
| + EXPECT_EQ(end <= 12u, parser->finish()) << " end=" << end;
|
| + EXPECT_EQ(3u, client->numberOfParts()) << " end=" << end;
|
| + EXPECT_EQ(String("1"), client->part(0).data);
|
| + EXPECT_TRUE(client->part(0).dataFullyReceived);
|
| + EXPECT_EQ(String("2\r\n--\r\n--bound--\r\n--\r\n2"), client->part(1).data);
|
| + EXPECT_TRUE(client->part(1).dataFullyReceived);
|
| + switch (end) {
|
| + case 14u:
|
| + EXPECT_EQ(String("333"), client->part(2).data);
|
| + EXPECT_TRUE(client->part(2).dataFullyReceived);
|
| + break;
|
| + case 15u:
|
| + EXPECT_EQ(String("333\r\n--boundar"), client->part(2).data);
|
| + EXPECT_FALSE(client->part(2).dataFullyReceived);
|
| + break;
|
| + default:
|
| + EXPECT_EQ(String("333"), client->part(2).data);
|
| + EXPECT_TRUE(client->part(2).dataFullyReceived);
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST(MultipartParserTest, NoEndBoundary)
|
| +{
|
| + const char* bytes = "--boundary\r\ncontent-type: application/xhtml+xml\r\n\r\n1";
|
| +
|
| + Vector<char> boundary;
|
| + boundary.append("boundary", 8u);
|
| + MockClient* client = new MockClient;
|
| + MultipartParser* parser = new MultipartParser(boundary, client);
|
| +
|
| + EXPECT_TRUE(parser->appendData(bytes, strlen(bytes)));
|
| + EXPECT_FALSE(parser->finish()); // No close delimiter.
|
| + EXPECT_EQ(1u, client->numberOfParts());
|
| + EXPECT_EQ(String("1"), client->part(0).data);
|
| + EXPECT_FALSE(client->part(0).dataFullyReceived);
|
| +}
|
| +
|
| +TEST(MultipartParserTest, NoStartBoundary)
|
| +{
|
| + const char* bytes = "content-type: application/xhtml+xml\r\n\r\n1\r\n--boundary--\r\n";
|
| +
|
| + Vector<char> boundary;
|
| + boundary.append("boundary", 8u);
|
| + MockClient* client = new MockClient;
|
| + MultipartParser* parser = new MultipartParser(boundary, client);
|
| +
|
| + EXPECT_FALSE(parser->appendData(bytes, strlen(bytes))); // Close delimiter before delimiter.
|
| + EXPECT_FALSE(parser->finish()); // No parts.
|
| + EXPECT_EQ(0u, client->numberOfParts());
|
| +}
|
| +
|
| +TEST(MultipartParserTest, NoStartNorEndBoundary)
|
| +{
|
| + const char* bytes = "content-type: application/xhtml+xml\r\n\r\n1";
|
| +
|
| + Vector<char> boundary;
|
| + boundary.append("boundary", 8u);
|
| + MockClient* client = new MockClient;
|
| + MultipartParser* parser = new MultipartParser(boundary, client);
|
| +
|
| + EXPECT_TRUE(parser->appendData(bytes, strlen(bytes))); // Valid preamble.
|
| + EXPECT_FALSE(parser->finish()); // No parts.
|
| + EXPECT_EQ(0u, client->numberOfParts());
|
| +}
|
| +
|
| +const size_t kStarts[] = {
|
| + 0u, // Non-empty preamble in the beginning.
|
| + 8u, // Empty preamble in the beginning.
|
| + 9u, // Truncated delimiter in the beginning.
|
| + 10u, // No preamble in the beginning.
|
| + 11u // Truncated dash delimiter in the beginning.
|
| +};
|
| +
|
| +void runPreambleTests(const char* boundaryString)
|
| +{
|
| + Vector<char> boundary;
|
| + boundary.append(boundaryString, strlen(boundaryString));
|
| + for (size_t start : kStarts) {
|
| + MockClient* client = new MockClient;
|
| + MultipartParser* parser = new MultipartParser(boundary, client);
|
| +
|
| + EXPECT_TRUE(parser->appendData(kBytes + start, strlen(kBytes + start)));
|
| + EXPECT_TRUE(parser->finish());
|
| + switch (start) {
|
| + case 9u:
|
| + case 11u:
|
| + EXPECT_EQ(2u, client->numberOfParts()) << " start=" << start;
|
| + EXPECT_EQ(String("2\r\n--\r\n--bound--\r\n--\r\n2"), client->part(0).data);
|
| + EXPECT_TRUE(client->part(0).dataFullyReceived);
|
| + EXPECT_EQ(String("333"), client->part(1).data);
|
| + EXPECT_TRUE(client->part(1).dataFullyReceived);
|
| + break;
|
| + default:
|
| + EXPECT_EQ(3u, client->numberOfParts()) << " start=" << start;
|
| + EXPECT_EQ(String("1"), client->part(0).data);
|
| + EXPECT_TRUE(client->part(0).dataFullyReceived);
|
| + EXPECT_EQ(String("2\r\n--\r\n--bound--\r\n--\r\n2"), client->part(1).data);
|
| + EXPECT_TRUE(client->part(1).dataFullyReceived);
|
| + EXPECT_EQ(String("333"), client->part(2).data);
|
| + EXPECT_TRUE(client->part(2).dataFullyReceived);
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST(MultipartParserTest, Preamble)
|
| +{
|
| + runPreambleTests("boundary");
|
| +}
|
| +
|
| +TEST(MultipartParserTest, PreambleWithMalformedBoundary)
|
| +{
|
| + runPreambleTests("--boundary");
|
| +}
|
| +
|
| +TEST(MultipartParserTest, PreambleWithVeryMalformedBoundary)
|
| +{
|
| + Vector<char> boundary;
|
| + boundary.append("----boundary", 12u);
|
| + for (size_t start : kStarts) {
|
| + MockClient* client = new MockClient;
|
| + MultipartParser* parser = new MultipartParser(boundary, client);
|
| +
|
| + EXPECT_TRUE(parser->appendData(kBytes + start, strlen(kBytes + start))); // Valid preamble.
|
| + EXPECT_FALSE(parser->finish()); // No parts.
|
| + EXPECT_EQ(0u, client->numberOfParts());
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +} // namespace blink
|
|
|