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 |