Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "modules/fetch/MultipartParser.h" | |
| 6 | |
| 7 #include "platform/HTTPNames.h" | |
| 8 #include "testing/gtest/include/gtest/gtest.h" | |
| 9 | |
| 10 #include <algorithm> | |
|
yhirano
2016/09/26 10:59:34
#include <string.h>
e_hakkinen
2016/09/28 15:15:05
Done.
| |
| 11 | |
| 12 namespace blink { | |
| 13 | |
| 14 namespace { | |
| 15 | |
| 16 class MockClient final : public GarbageCollectedFinalized<MockClient>, public Mu ltipartParser::Client { | |
| 17 USING_GARBAGE_COLLECTED_MIXIN(MockClient); | |
| 18 public: | |
| 19 struct Part { | |
| 20 Part() = default; | |
| 21 explicit Part(const ResourceResponse& response) : response(response), da taFullyReceived(false) {} | |
| 22 ResourceResponse response; | |
| 23 Vector<char> data; | |
| 24 bool dataFullyReceived; | |
| 25 }; | |
| 26 void partHeaderFieldsInMultipartReceived(const ResourceResponse& response) o verride | |
| 27 { | |
| 28 m_parts.append(response); | |
| 29 } | |
| 30 void partDataInMultipartReceived(const char* bytes, size_t size) override | |
| 31 { | |
| 32 m_parts.last().data.append(bytes, size); | |
| 33 } | |
| 34 void partDataInMultipartFullyReceived() override | |
| 35 { | |
| 36 m_parts.last().dataFullyReceived = true; | |
| 37 } | |
| 38 size_t numberOfParts() const | |
| 39 { | |
| 40 return m_parts.size(); | |
| 41 } | |
| 42 const Part& part(size_t partIndex) const | |
| 43 { | |
| 44 EXPECT_LT(partIndex, numberOfParts()); | |
| 45 return partIndex < numberOfParts() ? m_parts[partIndex] : m_emptyPart; | |
| 46 } | |
| 47 private: | |
| 48 Part m_emptyPart; | |
| 49 Vector<Part> m_parts; | |
| 50 }; | |
| 51 | |
| 52 constexpr char kBytes[] = | |
| 53 "preamble" | |
| 54 "\r\n--boundary\r\n\r\n" | |
| 55 "\r\n--boundary\r\ncontent-type: application/xhtml+xml\r\n\r\n1" | |
| 56 "\r\n--boundary\t\r\ncontent-type: text/html\r\n\r\n2\r\n--\r\n--bound--\r\n --\r\n2\r\n" | |
| 57 "\r\n--boundary \r\ncontent-type: text/plain\r\n\r\n333" | |
| 58 "\r\n--boundary--\t \r\n" | |
| 59 "epilogue"; | |
| 60 | |
| 61 TEST(MultipartParserTest, AppendDataInChunks) | |
| 62 { | |
| 63 const size_t sizes[] = {1u, 2u, strlen(kBytes)}; | |
| 64 | |
| 65 Vector<char> boundary; | |
| 66 boundary.append("boundary", 8u); | |
| 67 for (size_t size : sizes) { | |
| 68 MockClient* client = new MockClient; | |
| 69 MultipartParser* parser = new MultipartParser(boundary, client); | |
| 70 | |
| 71 for (size_t i = 0u, length = strlen(kBytes); i < length; i += size) | |
| 72 EXPECT_TRUE(parser->appendData(kBytes + i, std::min(size, length - i ))); | |
| 73 EXPECT_TRUE(parser->finish()) << " size=" << size; | |
| 74 EXPECT_EQ(4u, client->numberOfParts()) << " size=" << size; | |
| 75 EXPECT_TRUE(client->part(0).response.httpHeaderField(HTTPNames::Content_ Type).isNull()); | |
| 76 EXPECT_EQ(0u, client->part(0).data.size()); | |
| 77 EXPECT_TRUE(client->part(0).dataFullyReceived); | |
| 78 EXPECT_EQ(String("application/xhtml+xml"), client->part(1).response.http HeaderField(HTTPNames::Content_Type)); | |
| 79 EXPECT_EQ(String("1"), client->part(1).data); | |
| 80 EXPECT_TRUE(client->part(1).dataFullyReceived); | |
| 81 EXPECT_EQ(String("text/html"), client->part(2).response.httpHeaderField( HTTPNames::Content_Type)); | |
| 82 EXPECT_EQ(String("2\r\n--\r\n--bound--\r\n--\r\n2\r\n"), client->part(2) .data); | |
| 83 EXPECT_TRUE(client->part(2).dataFullyReceived); | |
| 84 EXPECT_EQ(String("text/plain"), client->part(3).response.httpHeaderField (HTTPNames::Content_Type)); | |
| 85 EXPECT_EQ(String("333"), client->part(3).data); | |
| 86 EXPECT_TRUE(client->part(3).dataFullyReceived); | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 TEST(MultipartParserTest, Epilogue) | |
| 91 { | |
| 92 constexpr size_t ends[] = { | |
| 93 0u, // Non-empty epilogue in the end. | |
| 94 8u, // Empty epilogue in the end. | |
| 95 9u, // Partial CRLF after close delimiter in the end. | |
| 96 10u, // No CRLF after close delimiter in the end. | |
| 97 12u, // No transport padding nor CRLF after close delimiter in the end. | |
| 98 13u, // Partial close delimiter in the end. | |
| 99 14u, // No close delimiter but a delimiter in the end. | |
| 100 15u // Partial delimiter in the end. | |
| 101 }; | |
| 102 | |
| 103 Vector<char> boundary; | |
| 104 boundary.append("boundary", 8u); | |
| 105 for (size_t end : ends) { | |
| 106 MockClient* client = new MockClient; | |
| 107 MultipartParser* parser = new MultipartParser(boundary, client); | |
| 108 | |
| 109 EXPECT_TRUE(parser->appendData(kBytes, strlen(kBytes) - end)); | |
| 110 EXPECT_EQ(end <= 12u, parser->finish()) << " end=" << end; | |
| 111 EXPECT_EQ(4u, client->numberOfParts()) << " end=" << end; | |
| 112 EXPECT_TRUE(client->part(0).response.httpHeaderField(HTTPNames::Content_ Type).isNull()); | |
| 113 EXPECT_EQ(0u, client->part(0).data.size()); | |
| 114 EXPECT_TRUE(client->part(0).dataFullyReceived); | |
| 115 EXPECT_EQ(String("application/xhtml+xml"), client->part(1).response.http HeaderField(HTTPNames::Content_Type)); | |
| 116 EXPECT_EQ(String("1"), client->part(1).data); | |
| 117 EXPECT_TRUE(client->part(1).dataFullyReceived); | |
| 118 EXPECT_EQ(String("text/html"), client->part(2).response.httpHeaderField( HTTPNames::Content_Type)); | |
| 119 EXPECT_EQ(String("2\r\n--\r\n--bound--\r\n--\r\n2\r\n"), client->part(2) .data); | |
| 120 EXPECT_TRUE(client->part(2).dataFullyReceived); | |
| 121 EXPECT_EQ(String("text/plain"), client->part(3).response.httpHeaderField (HTTPNames::Content_Type)); | |
| 122 switch (end) { | |
| 123 case 15u: | |
| 124 EXPECT_EQ(String("333\r\n--boundar"), client->part(3).data); | |
| 125 EXPECT_FALSE(client->part(3).dataFullyReceived); | |
| 126 break; | |
| 127 default: | |
| 128 EXPECT_EQ(String("333"), client->part(3).data); | |
| 129 EXPECT_TRUE(client->part(3).dataFullyReceived); | |
|
yhirano
2016/09/26 10:59:34
+break for consistency
e_hakkinen
2016/09/28 15:15:05
Done.
| |
| 130 } | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 TEST(MultipartParserTest, NoEndBoundary) | |
| 135 { | |
| 136 constexpr char bytes[] = "--boundary\r\ncontent-type: application/xhtml+xml\ r\n\r\n1"; | |
| 137 | |
| 138 Vector<char> boundary; | |
| 139 boundary.append("boundary", 8u); | |
| 140 MockClient* client = new MockClient; | |
| 141 MultipartParser* parser = new MultipartParser(boundary, client); | |
| 142 | |
| 143 EXPECT_TRUE(parser->appendData(bytes, strlen(bytes))); | |
| 144 EXPECT_FALSE(parser->finish()); // No close delimiter. | |
| 145 EXPECT_EQ(1u, client->numberOfParts()); | |
| 146 EXPECT_EQ(String("1"), client->part(0).data); | |
| 147 EXPECT_FALSE(client->part(0).dataFullyReceived); | |
| 148 } | |
| 149 | |
| 150 TEST(MultipartParserTest, NoStartBoundary) | |
| 151 { | |
| 152 constexpr char bytes[] = "content-type: application/xhtml+xml\r\n\r\n1\r\n-- boundary--\r\n"; | |
| 153 | |
| 154 Vector<char> boundary; | |
| 155 boundary.append("boundary", 8u); | |
| 156 MockClient* client = new MockClient; | |
| 157 MultipartParser* parser = new MultipartParser(boundary, client); | |
| 158 | |
| 159 EXPECT_FALSE(parser->appendData(bytes, strlen(bytes))); // Close delimiter b efore delimiter. | |
| 160 EXPECT_FALSE(parser->finish()); // No parts. | |
| 161 EXPECT_EQ(0u, client->numberOfParts()); | |
| 162 } | |
| 163 | |
| 164 TEST(MultipartParserTest, NoStartNorEndBoundary) | |
| 165 { | |
| 166 constexpr char bytes[] = "content-type: application/xhtml+xml\r\n\r\n1"; | |
| 167 | |
| 168 Vector<char> boundary; | |
| 169 boundary.append("boundary", 8u); | |
| 170 MockClient* client = new MockClient; | |
| 171 MultipartParser* parser = new MultipartParser(boundary, client); | |
| 172 | |
| 173 EXPECT_TRUE(parser->appendData(bytes, strlen(bytes))); // Valid preamble. | |
| 174 EXPECT_FALSE(parser->finish()); // No parts. | |
| 175 EXPECT_EQ(0u, client->numberOfParts()); | |
| 176 } | |
| 177 | |
| 178 constexpr size_t kStarts[] = { | |
| 179 0u, // Non-empty preamble in the beginning. | |
| 180 8u, // Empty preamble in the beginning. | |
| 181 9u, // Truncated delimiter in the beginning. | |
| 182 10u, // No preamble in the beginning. | |
| 183 11u // Truncated dash boundary in the beginning. | |
| 184 }; | |
| 185 | |
| 186 TEST(MultipartParserTest, Preamble) | |
| 187 { | |
| 188 Vector<char> boundary; | |
| 189 boundary.append("boundary", 8u); | |
| 190 for (size_t start : kStarts) { | |
| 191 MockClient* client = new MockClient; | |
| 192 MultipartParser* parser = new MultipartParser(boundary, client); | |
| 193 | |
| 194 EXPECT_TRUE(parser->appendData(kBytes + start, strlen(kBytes + start))); | |
| 195 EXPECT_TRUE(parser->finish()); | |
| 196 switch (start) { | |
| 197 case 9u: | |
| 198 case 11u: | |
| 199 EXPECT_EQ(3u, client->numberOfParts()) << " start=" << start; | |
| 200 EXPECT_EQ(String("application/xhtml+xml"), client->part(0).response. httpHeaderField(HTTPNames::Content_Type)); | |
| 201 EXPECT_EQ(String("1"), client->part(0).data); | |
| 202 EXPECT_TRUE(client->part(0).dataFullyReceived); | |
| 203 EXPECT_EQ(String("text/html"), client->part(1).response.httpHeaderFi eld(HTTPNames::Content_Type)); | |
| 204 EXPECT_EQ(String("2\r\n--\r\n--bound--\r\n--\r\n2\r\n"), client->par t(1).data); | |
| 205 EXPECT_TRUE(client->part(1).dataFullyReceived); | |
| 206 EXPECT_EQ(String("text/plain"), client->part(2).response.httpHeaderF ield(HTTPNames::Content_Type)); | |
| 207 EXPECT_EQ(String("333"), client->part(2).data); | |
| 208 EXPECT_TRUE(client->part(2).dataFullyReceived); | |
| 209 break; | |
| 210 default: | |
| 211 EXPECT_EQ(4u, client->numberOfParts()) << " start=" << start; | |
| 212 EXPECT_TRUE(client->part(0).response.httpHeaderField(HTTPNames::Cont ent_Type).isNull()); | |
| 213 EXPECT_EQ(0u, client->part(0).data.size()); | |
| 214 EXPECT_TRUE(client->part(0).dataFullyReceived); | |
| 215 EXPECT_EQ(String("application/xhtml+xml"), client->part(1).response. httpHeaderField(HTTPNames::Content_Type)); | |
| 216 EXPECT_EQ(String("1"), client->part(1).data); | |
| 217 EXPECT_TRUE(client->part(1).dataFullyReceived); | |
| 218 EXPECT_EQ(String("text/html"), client->part(2).response.httpHeaderFi eld(HTTPNames::Content_Type)); | |
| 219 EXPECT_EQ(String("2\r\n--\r\n--bound--\r\n--\r\n2\r\n"), client->par t(2).data); | |
| 220 EXPECT_TRUE(client->part(2).dataFullyReceived); | |
| 221 EXPECT_EQ(String("text/plain"), client->part(3).response.httpHeaderF ield(HTTPNames::Content_Type)); | |
| 222 EXPECT_EQ(String("333"), client->part(3).data); | |
| 223 EXPECT_TRUE(client->part(3).dataFullyReceived); | |
|
yhirano
2016/09/26 10:59:34
+break for consistency
e_hakkinen
2016/09/28 15:15:05
Done.
| |
| 224 } | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 TEST(MultipartParserTest, PreambleWithMalformedBoundary) | |
| 229 { | |
| 230 Vector<char> boundary; | |
| 231 boundary.append("--boundary", 10u); | |
| 232 for (size_t start : kStarts) { | |
| 233 MockClient* client = new MockClient; | |
| 234 MultipartParser* parser = new MultipartParser(boundary, client); | |
| 235 | |
| 236 EXPECT_TRUE(parser->appendData(kBytes + start, strlen(kBytes + start))); // Valid preamble. | |
| 237 EXPECT_FALSE(parser->finish()); // No parts. | |
| 238 EXPECT_EQ(0u, client->numberOfParts()); | |
| 239 } | |
| 240 } | |
|
yhirano
2016/09/26 10:59:34
Can you add a test for non-empty charset?
yhirano
2016/09/26 10:59:34
Can you add tests for non-empty content-transfer-e
e_hakkinen
2016/09/28 15:15:05
Done, although this tests only MultipartParser and
e_hakkinen
2016/09/28 15:15:05
Done.
| |
| 241 | |
| 242 } // namespace | |
| 243 | |
| 244 } // namespace blink | |
| OLD | NEW |