| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "base/basictypes.h" | |
| 6 #include "base/logging.h" | |
| 7 #include "base/strings/string_piece.h" | |
| 8 #include "chrome/browser/extensions/api/web_request/form_data_parser.h" | |
| 9 #include "testing/gtest/include/gtest/gtest.h" | |
| 10 | |
| 11 namespace extensions { | |
| 12 | |
| 13 namespace { | |
| 14 | |
| 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(); | |
| 23 } | |
| 24 | |
| 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()); | |
| 44 } | |
| 45 } | |
| 46 return parser->AllDataReadOK(); | |
| 47 } | |
| 48 | |
| 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()); | |
| 65 } | |
| 66 } | |
| 67 return !parser->AllDataReadOK(); | |
| 68 } | |
| 69 | |
| 70 } // namespace | |
| 71 | |
| 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" | |
| 155 }; | |
| 156 const std::vector<std::string> kExpected(kPairs, kPairs + arraysize(kPairs)); | |
| 157 | |
| 158 std::vector<const base::StringPiece*> input; | |
| 159 std::vector<std::string> output; | |
| 160 | |
| 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); | |
| 165 | |
| 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); | |
| 172 | |
| 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); | |
| 178 | |
| 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)); | |
| 184 } | |
| 185 | |
| 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; | |
| 224 | |
| 225 std::vector<const base::StringPiece*> input; | |
| 226 | |
| 227 // First test: malformed multipart POST data. | |
| 228 input.push_back(&kMultipartBytes); | |
| 229 EXPECT_TRUE(CheckParserFails(kMultipart, input)); | |
| 230 | |
| 231 // Second test: empty multipart POST data. | |
| 232 input.clear(); | |
| 233 input.push_back(&kMultipartBytesEmpty); | |
| 234 EXPECT_TRUE(CheckParserFails(kMultipart, input)); | |
| 235 | |
| 236 // Third test: malformed URL-encoded POST data. | |
| 237 input.clear(); | |
| 238 input.push_back(&kUrlEncodedBytes); | |
| 239 EXPECT_TRUE(CheckParserFails(kUrlEncoded, input)); | |
| 240 | |
| 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()); | |
| 248 } | |
| 249 | |
| 250 } // namespace extensions | |
| OLD | NEW |