Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / extensions / browser / api / web_request / form_data_parser_unittest.cc
blobc848bfa466ca6a94b4769b780f692fffa9a6d91b
1 // Copyright (c) 2012 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.
5 #include "base/basictypes.h"
6 #include "base/logging.h"
7 #include "base/strings/string_piece.h"
8 #include "extensions/browser/api/web_request/form_data_parser.h"
9 #include "testing/gtest/include/gtest/gtest.h"
11 namespace extensions {
13 namespace {
15 // Attempts to create a parser corresponding to the |content_type_header|.
16 // On success, returns the parser.
17 scoped_ptr<FormDataParser> InitParser(const std::string& content_type_header) {
18 scoped_ptr<FormDataParser> parser(
19 FormDataParser::CreateFromContentTypeHeader(&content_type_header));
20 if (parser.get() == NULL)
21 return scoped_ptr<FormDataParser>();
22 return parser.Pass();
25 // Attempts to run the parser corresponding to the |content_type_header|
26 // on the source represented by the concatenation of blocks from |bytes|.
27 // On success, returns true and the parsed |output|, else false.
28 // Parsed |output| has names on even positions (0, 2, ...), values on odd ones.
29 bool RunParser(const std::string& content_type_header,
30 const std::vector<const base::StringPiece*>& bytes,
31 std::vector<std::string>* output) {
32 DCHECK(output);
33 output->clear();
34 scoped_ptr<FormDataParser> parser(InitParser(content_type_header));
35 if (!parser.get())
36 return false;
37 FormDataParser::Result result;
38 for (size_t block = 0; block < bytes.size(); ++block) {
39 if (!parser->SetSource(*(bytes[block])))
40 return false;
41 while (parser->GetNextNameValue(&result)) {
42 output->push_back(result.name());
43 output->push_back(result.value());
46 return parser->AllDataReadOK();
49 // Attempts to run the parser corresponding to the |content_type_header|
50 // on the source represented by the concatenation of blocks from |bytes|.
51 // Checks that the parser fails parsing.
52 bool CheckParserFails(const std::string& content_type_header,
53 const std::vector<const base::StringPiece*>& bytes) {
54 std::vector<std::string> output;
55 scoped_ptr<FormDataParser> parser(InitParser(content_type_header));
56 if (!parser.get())
57 return false;
58 FormDataParser::Result result;
59 for (size_t block = 0; block < bytes.size(); ++block) {
60 if (!parser->SetSource(*(bytes[block])))
61 break;
62 while (parser->GetNextNameValue(&result)) {
63 output.push_back(result.name());
64 output.push_back(result.value());
67 return !parser->AllDataReadOK();
70 } // namespace
72 TEST(WebRequestFormDataParserTest, Parsing) {
73 // We verify that POST data parsers cope with various formats of POST data.
74 // Construct the test data.
75 const std::string kBoundary = "THIS_IS_A_BOUNDARY";
76 const std::string kBlockStr1 =
77 std::string("--") + kBoundary +
78 "\r\n"
79 "Content-Disposition: form-data; name=\"text\"\r\n"
80 "\r\n"
81 "test\rtext\nwith non-CRLF line breaks\r\n"
82 "--" +
83 kBoundary +
84 "\r\n"
85 "Content-Disposition: form-data; name=\"file\"; filename=\"test\"\r\n"
86 "Content-Type: application/octet-stream\r\n"
87 "\r\n";
88 const std::string kBlockStr2 =
89 std::string("\r\n--") + kBoundary +
90 "\r\n"
91 "Content-Disposition: form-data; name=\"password\"\r\n"
92 "\r\n"
93 "test password\r\n"
94 "--" +
95 kBoundary +
96 "\r\n"
97 "Content-Disposition: form-data; name=\"radio\"\r\n"
98 "\r\n"
99 "Yes\r\n"
100 "--" +
101 kBoundary +
102 "\r\n"
103 "Content-Disposition: form-data; name=\"check\"\r\n"
104 "\r\n"
105 "option A\r\n"
106 "--" +
107 kBoundary +
108 "\r\n"
109 "Content-Disposition: form-data; name=\"check\"\r\n"
110 "\r\n"
111 "option B\r\n"
112 "--" +
113 kBoundary +
114 "\r\n"
115 "Content-Disposition: form-data; name=\"txtarea\"\r\n"
116 "\r\n"
117 "Some text.\r\n"
118 "Other.\r\n"
119 "\r\n"
120 "--" +
121 kBoundary +
122 "\r\n"
123 "Content-Disposition: form-data; name=\"select\"\r\n"
124 "\r\n"
125 "one\r\n"
126 "--" +
127 kBoundary + "--";
128 // POST data input.
129 const std::string kBigBlock = kBlockStr1 + kBlockStr2;
130 const std::string kUrlEncodedBlock =
131 "text=test%0Dtext%0Awith+non-CRLF+line+breaks"
132 "&file=test&password=test+password&radio=Yes&check=option+A"
133 "&check=option+B&txtarea=Some+text.%0D%0AOther.%0D%0A&select=one";
134 const base::StringPiece kMultipartBytes(kBigBlock);
135 const base::StringPiece kMultipartBytesSplit1(kBlockStr1);
136 const base::StringPiece kMultipartBytesSplit2(kBlockStr2);
137 const base::StringPiece kUrlEncodedBytes(kUrlEncodedBlock);
138 const std::string kPlainBlock = "abc";
139 const base::StringPiece kTextPlainBytes(kPlainBlock);
140 // Headers.
141 const std::string kUrlEncoded = "application/x-www-form-urlencoded";
142 const std::string kTextPlain = "text/plain";
143 const std::string kMultipart =
144 std::string("multipart/form-data; boundary=") + kBoundary;
145 // Expected output.
146 const char* kPairs[] = {
147 "text", "test\rtext\nwith non-CRLF line breaks",
148 "file", "test",
149 "password", "test password",
150 "radio", "Yes",
151 "check", "option A",
152 "check", "option B",
153 "txtarea", "Some text.\r\nOther.\r\n",
154 "select", "one"
156 const std::vector<std::string> kExpected(kPairs, kPairs + arraysize(kPairs));
158 std::vector<const base::StringPiece*> input;
159 std::vector<std::string> output;
161 // First test: multipart POST data in one lump.
162 input.push_back(&kMultipartBytes);
163 EXPECT_TRUE(RunParser(kMultipart, input, &output));
164 EXPECT_EQ(kExpected, output);
166 // Second test: multipart POST data in several lumps.
167 input.clear();
168 input.push_back(&kMultipartBytesSplit1);
169 input.push_back(&kMultipartBytesSplit2);
170 EXPECT_TRUE(RunParser(kMultipart, input, &output));
171 EXPECT_EQ(kExpected, output);
173 // Third test: URL-encoded POST data.
174 input.clear();
175 input.push_back(&kUrlEncodedBytes);
176 EXPECT_TRUE(RunParser(kUrlEncoded, input, &output));
177 EXPECT_EQ(kExpected, output);
179 // Fourth test: text/plain POST data in one lump.
180 input.clear();
181 input.push_back(&kTextPlainBytes);
182 // This should fail, text/plain is ambiguous and thus unparseable.
183 EXPECT_FALSE(RunParser(kTextPlain, input, &output));
186 TEST(WebRequestFormDataParserTest, MalformedPayload) {
187 // We verify that POST data parsers reject malformed data.
188 // Construct the test data.
189 const std::string kBoundary = "THIS_IS_A_BOUNDARY";
190 const std::string kBlockStr =
191 std::string("--") + kBoundary +
192 "\r\n"
193 "Content-Disposition: form-data; name=\"text\"\r\n"
194 "\r\n"
195 "test\rtext\nwith non-CRLF line breaks\r\n"
196 "-" +
197 kBoundary +
198 "\r\n" /* Missing '-'. */
199 "Content-Disposition: form-data; name=\"file\"; filename=\"test\"\r\n"
200 "Content-Type: application/octet-stream\r\n"
201 /* Two CRLF missing. */
202 "--" +
203 kBoundary +
204 "\r\n"
205 "Content-Disposition: form-data; name=\"select\"\r\n"
206 "\r\n"
207 "one\r\n"
208 "--" +
209 kBoundary + "-" /* Missing '-' at the end. */;
210 // POST data input.
211 // The following block is corrupted -- contains a "==" substring.
212 const std::string kUrlEncodedBlock =
213 "text=test%0Dtext%0Awith+non-CRLF+line+breaks"
214 "&file==test&password=test+password&radio=Yes&check=option+A"
215 "&check=option+B&txtarea=Some+text.%0D%0AOther.%0D%0A&select=one";
216 const base::StringPiece kMultipartBytes(kBlockStr);
217 const base::StringPiece kMultipartBytesEmpty("");
218 const base::StringPiece kUrlEncodedBytes(kUrlEncodedBlock);
219 const base::StringPiece kUrlEncodedBytesEmpty("");
220 // Headers.
221 const std::string kUrlEncoded = "application/x-www-form-urlencoded";
222 const std::string kMultipart =
223 std::string("multipart/form-data; boundary=") + kBoundary;
225 std::vector<const base::StringPiece*> input;
227 // First test: malformed multipart POST data.
228 input.push_back(&kMultipartBytes);
229 EXPECT_TRUE(CheckParserFails(kMultipart, input));
231 // Second test: empty multipart POST data.
232 input.clear();
233 input.push_back(&kMultipartBytesEmpty);
234 EXPECT_TRUE(CheckParserFails(kMultipart, input));
236 // Third test: malformed URL-encoded POST data.
237 input.clear();
238 input.push_back(&kUrlEncodedBytes);
239 EXPECT_TRUE(CheckParserFails(kUrlEncoded, input));
241 // Fourth test: empty URL-encoded POST data. Note that an empty string is a
242 // valid url-encoded value, so this should parse correctly.
243 std::vector<std::string> output;
244 input.clear();
245 input.push_back(&kUrlEncodedBytesEmpty);
246 EXPECT_TRUE(RunParser(kUrlEncoded, input, &output));
247 EXPECT_EQ(0u, output.size());
250 } // namespace extensions