Chromium Code Reviews| 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 "chrome/browser/extensions/api/web_request/post_data_parser.h" | |
| 6 | |
| 7 #include "net/url_request/url_request.h" | |
| 8 #include "net/base/escape.h" | |
| 9 | |
| 10 namespace { | |
| 11 const char kContentDisposition[] = "Content-Disposition:"; | |
| 12 } | |
| 13 | |
| 14 namespace extensions { | |
| 15 | |
| 16 // Implementation of PostDataParser and PostDataParser::Result . | |
| 17 | |
| 18 PostDataParser::Result::Result() {} | |
| 19 | |
| 20 void PostDataParser::Result::Reset() { | |
| 21 key_.erase(); | |
| 22 val_.erase(); | |
| 23 } | |
| 24 | |
| 25 void PostDataParser::Result::SetKey(const char* s, size_t n) { | |
| 26 key_.replace(0, std::string::npos, s, n); | |
| 27 } | |
| 28 | |
| 29 void PostDataParser::Result::SetVal(const char* s, size_t n) { | |
| 30 val_.replace(0, std::string::npos, s, n); | |
| 31 } | |
| 32 | |
| 33 // static | |
| 34 scoped_ptr<PostDataParser> PostDataParser::CreatePostDataParser( | |
| 35 net::URLRequest* request) { | |
| 36 std::string value; | |
| 37 const bool found = request->extra_request_headers().GetHeader( | |
| 38 "Content-Type", &value); | |
| 39 std::string content_type = value.substr(0, value.find(';')); | |
| 40 if (!found || content_type == "application/x-www-form-urlencoded") { | |
| 41 return scoped_ptr<PostDataParser>(new PostDataParserUrlEncoded()); | |
| 42 } else if (content_type == "multipart/form-data") { | |
| 43 const char kBoundaryString[] = "boundary="; | |
| 44 size_t offset = value.find(kBoundaryString); | |
| 45 if (offset == std::string::npos) { | |
| 46 // Malformed header. | |
| 47 return scoped_ptr<PostDataParser>(); | |
| 48 } | |
| 49 offset += strlen(kBoundaryString); | |
| 50 std::string boundary = value.substr(offset, value.find(';', offset)); | |
| 51 return scoped_ptr<PostDataParser>(new PostDataParserMultipart(boundary)); | |
| 52 } else if (content_type == "text/plain") { | |
| 53 // Unable to parse, may be ambiguous. | |
| 54 return scoped_ptr<PostDataParser>(); | |
| 55 } else { | |
| 56 // Another error. | |
| 57 return scoped_ptr<PostDataParser>(); | |
| 58 } | |
| 59 } | |
| 60 | |
| 61 // Implementation of PostDataParserUrlEncoded. | |
| 62 | |
| 63 PostDataParserUrlEncoded::PostDataParserUrlEncoded() : source_(NULL) {} | |
| 64 | |
| 65 PostDataParserUrlEncoded::~PostDataParserUrlEncoded() {} | |
| 66 | |
| 67 bool PostDataParserUrlEncoded::AllDataReadOK() { | |
| 68 return source_ != NULL && offset_ == source_->end(); | |
| 69 } | |
| 70 | |
| 71 bool PostDataParserUrlEncoded::GetNextPair(Result* result) { | |
| 72 result->Reset(); | |
| 73 if (source_ == NULL) | |
| 74 return false; | |
| 75 if (offset_ == source_->end()) | |
| 76 return false; | |
| 77 std::vector<char>::const_iterator seek = offset_; | |
| 78 // (*) Now we have |seek| >= |offset_| until the end of this function: | |
| 79 while (seek != source_->end() && *seek != '=') | |
| 80 ++seek; | |
| 81 if (seek == source_->end()) { | |
| 82 // This means the data is malformed. | |
| 83 offset_ = seek; | |
| 84 return false; | |
| 85 } | |
| 86 std::string encoded_key(&(*offset_), seek - offset_); // Safe, see (*). | |
| 87 const net::UnescapeRule::Type unescape_rules = | |
| 88 net::UnescapeRule::URL_SPECIAL_CHARS | net::UnescapeRule::CONTROL_CHARS | | |
| 89 net::UnescapeRule::SPACES | net::UnescapeRule::REPLACE_PLUS_WITH_SPACE; | |
| 90 result->get_key() = net::UnescapeURLComponent(encoded_key, unescape_rules); | |
|
battre
2012/07/13 15:20:04
I think this would be more natural as
result->set_
vabr (Chromium)
2012/07/16 15:40:51
Done.
| |
| 91 offset_ = ++seek; | |
| 92 while (seek != source_->end() && *seek != '&') | |
| 93 ++seek; | |
| 94 std::string encoded_val(&(*offset_), seek - offset_); // Safe, see (*). | |
| 95 result->get_val() = net::UnescapeURLComponent(encoded_val, unescape_rules); | |
|
battre
2012/07/13 15:20:04
same as above.
vabr (Chromium)
2012/07/16 15:40:51
Done.
| |
| 96 offset_ = (seek == source_->end()) ? seek : seek + 1; | |
| 97 return true; | |
| 98 } | |
| 99 | |
| 100 bool PostDataParserUrlEncoded::SetSource(const std::vector<char>* source) { | |
| 101 if (source_ != NULL) | |
| 102 return false; | |
| 103 source_ = source; | |
| 104 offset_ = source_->begin(); | |
| 105 return true; | |
| 106 } | |
| 107 | |
| 108 // Implementation of PostDataParserMultipart. | |
| 109 | |
| 110 PostDataParserMultipart::PostDataParserMultipart( | |
| 111 const std::string& boundary_separator) | |
| 112 : source_(NULL), | |
| 113 length_(0), // Dummy value. | |
| 114 line_start_(0), // Dummy value. | |
| 115 line_end_(0), // Dummy value. | |
| 116 next_line_(0), // Dummy value. | |
| 117 boundary_("--" + boundary_separator), | |
| 118 final_boundary_(boundary_+"--"), | |
|
battre
2012/07/13 15:20:04
nit: spaces around +
vabr (Chromium)
2012/07/16 15:40:51
Done.
| |
| 119 state_(kInit), | |
| 120 line_type_(kEmpty) // Dummy value. | |
| 121 {} | |
| 122 | |
| 123 PostDataParserMultipart::~PostDataParserMultipart() {} | |
| 124 | |
| 125 bool PostDataParserMultipart::AllDataReadOK() { | |
| 126 return source_ != NULL && next_line_ >= length_ && state_ == kFinal; | |
| 127 } | |
| 128 | |
| 129 bool PostDataParserMultipart::GetNextPair(Result* result) { | |
|
battre
2012/07/13 15:20:04
Can you add more explanation what this function do
vabr (Chromium)
2012/07/16 15:40:51
Done.
| |
| 130 result->Reset(); | |
| 131 if (state_ == kError) | |
| 132 return false; | |
| 133 while (state_ != kSkip) { | |
|
battre
2012/07/13 15:20:04
Can you explain this logic, maybe in a comment. Wh
vabr (Chromium)
2012/07/16 15:40:51
I changed kSkip and other state names to describe
| |
| 134 if (!DoStep()) | |
| 135 return false; | |
| 136 } | |
| 137 bool val_extracted = false; | |
| 138 bool name_parsed = ParseHead(result, &val_extracted); | |
| 139 while (state_ != kBody) { | |
| 140 if (!DoStep()) | |
| 141 return false; | |
| 142 } | |
| 143 size_t val_start; | |
| 144 size_t val_end = 0; // Dummy value, replaced below, see (*). | |
| 145 // There may not be more to read from |source_| if the current result comes | |
| 146 // from a "file" input element. But then |result| is complete already. | |
| 147 if (!DoStep()) | |
| 148 return val_extracted; | |
| 149 val_start = line_start_; | |
| 150 // (*) Now state_ == kBody, so val_end gets updated below. | |
| 151 while (state_ != kFirst && state_ != kFinal) { | |
| 152 val_end = line_end_; | |
| 153 if (!DoStep()) break; | |
| 154 } | |
| 155 if (name_parsed && !val_extracted) { | |
| 156 result->SetVal(source_ + val_start, val_end - val_start); | |
| 157 } | |
| 158 return name_parsed; | |
| 159 } | |
| 160 | |
| 161 bool PostDataParserMultipart::SetSource(const std::vector<char>* source) { | |
| 162 if (state_ == kError) | |
| 163 return false; | |
| 164 if (source_ != NULL && next_line_ < length_) | |
| 165 return false; | |
| 166 source_ = &(source->front()); | |
| 167 length_ = source->size(); | |
| 168 next_line_ = 0; | |
| 169 return true; | |
| 170 } | |
| 171 | |
| 172 bool PostDataParserMultipart::DoStep() { | |
| 173 if (!GetNextLine()) | |
| 174 return false; | |
| 175 switch (state_) { | |
| 176 case kInit: | |
| 177 if (line_type_ == kBoundary) | |
| 178 state_ = kFirst; | |
| 179 else | |
| 180 state_ = kError; | |
| 181 break; | |
| 182 case kFirst: | |
| 183 if (line_type_ == kDisposition) | |
| 184 state_ = kSkip; | |
| 185 else | |
| 186 state_ = kHead; | |
| 187 break; | |
| 188 case kHead: | |
| 189 if (line_type_ == kDisposition) | |
| 190 state_ = kSkip; | |
| 191 break; | |
| 192 case kSkip: | |
| 193 if (line_type_ == kEmpty) | |
| 194 state_ = kBody; | |
| 195 break; | |
| 196 case kBody: | |
| 197 if (line_type_ == kBoundary) | |
| 198 state_ = kFirst; | |
| 199 else if (line_type_ == kEndBoundary) | |
| 200 state_ = kFinal; | |
| 201 break; | |
| 202 case kFinal: | |
| 203 if (line_type_ != kEmpty) | |
| 204 state_ = kError; | |
| 205 case kError: | |
| 206 break; | |
| 207 } | |
| 208 return true; | |
| 209 } | |
| 210 | |
| 211 // Contract: only to be called from GetNextLine(). | |
|
battre
2012/07/13 15:20:04
optional: What do you think of changing this to
Li
vabr (Chromium)
2012/07/16 15:40:51
Done.
| |
| 212 void PostDataParserMultipart::GetLineType() { | |
|
battre
2012/07/13 15:20:04
I think if you don't return anything I would renam
vabr (Chromium)
2012/07/16 15:40:51
Changed to returning Lines.
| |
| 213 const size_t line_length = line_end_ - line_start_; | |
| 214 const base::StringPiece line(source_ + line_start_, line_length); | |
| 215 if (line == boundary_) | |
| 216 line_type_ = kBoundary; | |
| 217 else if (line == final_boundary_) | |
| 218 line_type_ = kEndBoundary; | |
| 219 else if (line.starts_with(kContentDisposition)) | |
| 220 line_type_ = kDisposition; | |
| 221 else if (line_start_ == line_end_) | |
| 222 line_type_ = kEmpty; | |
| 223 else | |
| 224 line_type_ = kOther; | |
| 225 } | |
| 226 | |
| 227 // Contract: only to be called from DoStep(). | |
| 228 bool PostDataParserMultipart::GetNextLine() { | |
|
battre
2012/07/13 15:20:04
opt: SeekNextLine?
vabr (Chromium)
2012/07/16 15:40:51
Done.
| |
| 229 if (source_ == NULL || state_ == kError) | |
| 230 return false; | |
| 231 if (next_line_ >= length_) | |
| 232 return false; | |
| 233 line_start_ = next_line_; | |
| 234 size_t seek = line_start_; | |
| 235 while (seek < length_ && *(source_ + seek) != '\r') | |
| 236 ++seek; | |
| 237 line_end_ = seek; | |
|
battre
2012/07/13 15:20:04
so line_end_ points to after the end of the line,
vabr (Chromium)
2012/07/16 15:40:51
Done.
| |
| 238 GetLineType(); | |
| 239 if (seek < length_ && *(source_ + seek + 1) != '\n') | |
|
battre
2012/07/13 15:20:04
source_ + seek + 1 could point beyond the end of t
vabr (Chromium)
2012/07/16 15:40:51
Corrected.
| |
| 240 return false; | |
| 241 next_line_ = seek + 2; | |
| 242 return true; | |
| 243 } | |
| 244 | |
| 245 // Contract: line_type_ == kDisposition. | |
| 246 bool PostDataParserMultipart::ParseHead(Result* result, bool* val_extracted) { | |
| 247 DCHECK_EQ(kDisposition, line_type_); | |
| 248 base::StringPiece line(source_ + line_start_, line_end_ - line_start_); | |
| 249 const char kNameEquals[] = " name=\""; | |
| 250 const char kFilenameEquals[] = " filename=\""; | |
| 251 size_t key_offset = line.find(kNameEquals); | |
| 252 if (key_offset == base::StringPiece::npos) | |
| 253 return false; | |
| 254 key_offset += strlen(kNameEquals); | |
| 255 result->SetKey(source_ + line_start_ + key_offset, | |
| 256 line.find('"', key_offset) - key_offset); | |
| 257 size_t val_offset = line.find(kFilenameEquals); | |
| 258 if (val_offset == std::string::npos) { | |
| 259 *val_extracted = false; | |
| 260 } else { | |
| 261 *val_extracted = true; | |
| 262 val_offset += strlen(kFilenameEquals); | |
| 263 result->SetVal(source_ + line_start_ + val_offset, | |
| 264 line.find('"', val_offset) - val_offset); | |
| 265 } | |
| 266 return true; | |
| 267 } | |
| 268 | |
| 269 } // namespace extensions | |
| OLD | NEW |