Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(672)

Side by Side Diff: chrome/browser/extensions/api/web_request/post_data_parser.cc

Issue 10694055: Add read-only access to POST data for webRequest's onBeforeRequest (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Typo fixed Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698