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 "extensions/browser/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 251