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 |