OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "modules/fetch/FetchDataLoader.h" | 5 #include "modules/fetch/FetchDataLoader.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include "core/fileapi/File.h" | |
9 #include "core/html/FormData.h" | |
8 #include "core/html/parser/TextResourceDecoder.h" | 10 #include "core/html/parser/TextResourceDecoder.h" |
9 #include "modules/fetch/BytesConsumer.h" | 11 #include "modules/fetch/BytesConsumer.h" |
12 #include "modules/fetch/MultipartParser.h" | |
10 #include "mojo/public/cpp/system/simple_watcher.h" | 13 #include "mojo/public/cpp/system/simple_watcher.h" |
14 #include "platform/HTTPNames.h" | |
15 #include "platform/network/ParsedContentType.h" | |
11 #include "platform/wtf/Functional.h" | 16 #include "platform/wtf/Functional.h" |
12 #include "platform/wtf/PtrUtil.h" | 17 #include "platform/wtf/PtrUtil.h" |
13 #include "platform/wtf/text/StringBuilder.h" | 18 #include "platform/wtf/text/StringBuilder.h" |
14 #include "platform/wtf/text/WTFString.h" | 19 #include "platform/wtf/text/WTFString.h" |
15 #include "platform/wtf/typed_arrays/ArrayBufferBuilder.h" | 20 #include "platform/wtf/typed_arrays/ArrayBufferBuilder.h" |
16 | 21 |
17 namespace blink { | 22 namespace blink { |
18 | 23 |
19 namespace { | 24 namespace { |
20 | 25 |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
163 BytesConsumer::Client::Trace(visitor); | 168 BytesConsumer::Client::Trace(visitor); |
164 } | 169 } |
165 | 170 |
166 private: | 171 private: |
167 Member<BytesConsumer> consumer_; | 172 Member<BytesConsumer> consumer_; |
168 Member<FetchDataLoader::Client> client_; | 173 Member<FetchDataLoader::Client> client_; |
169 | 174 |
170 std::unique_ptr<ArrayBufferBuilder> raw_data_; | 175 std::unique_ptr<ArrayBufferBuilder> raw_data_; |
171 }; | 176 }; |
172 | 177 |
178 class FetchDataLoaderAsFormData final : public FetchDataLoader, | |
179 public BytesConsumer::Client, | |
180 public MultipartParser::Client { | |
181 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsFormData); | |
182 | |
183 public: | |
184 explicit FetchDataLoaderAsFormData(const String& multipart_boundary) | |
185 : multipart_boundary_(multipart_boundary) {} | |
186 | |
187 void Start(BytesConsumer* consumer, | |
188 FetchDataLoader::Client* client) override { | |
189 DCHECK(!client_); | |
190 DCHECK(!consumer_); | |
191 DCHECK(!form_data_); | |
192 DCHECK(!multipart_parser_); | |
193 | |
194 const CString multipart_boundary_utf8 = multipart_boundary_.Utf8(); | |
195 Vector<char> multipart_boundary_vector; | |
196 multipart_boundary_vector.Append(multipart_boundary_utf8.data(), | |
197 multipart_boundary_utf8.length()); | |
198 | |
199 client_ = client; | |
200 form_data_ = FormData::Create(); | |
201 multipart_parser_ = | |
202 new MultipartParser(std::move(multipart_boundary_vector), this); | |
203 consumer_ = consumer; | |
204 consumer_->SetClient(this); | |
205 OnStateChange(); | |
206 } | |
207 | |
208 void OnStateChange() override { | |
209 while (true) { | |
210 const char* buffer; | |
211 size_t available; | |
212 auto result = consumer_->BeginRead(&buffer, &available); | |
213 if (result == BytesConsumer::Result::kShouldWait) | |
214 return; | |
215 if (result == BytesConsumer::Result::kOk) { | |
216 const bool buffer_appended = | |
217 multipart_parser_->AppendData(buffer, available); | |
218 const bool multipart_receive_failed = multipart_parser_->IsCancelled(); | |
219 result = consumer_->EndRead(available); | |
220 if (!buffer_appended || multipart_receive_failed) | |
221 result = BytesConsumer::Result::kError; | |
222 } | |
223 switch (result) { | |
224 case BytesConsumer::Result::kOk: | |
225 break; | |
226 case BytesConsumer::Result::kShouldWait: | |
227 NOTREACHED(); | |
228 return; | |
229 case BytesConsumer::Result::kDone: | |
230 if (multipart_parser_->Finish()) { | |
231 DCHECK(!multipart_parser_->IsCancelled()); | |
232 client_->DidFetchDataLoadedFormData(form_data_); | |
233 } else { | |
234 client_->DidFetchDataLoadFailed(); | |
235 } | |
236 return; | |
237 case BytesConsumer::Result::kError: | |
238 client_->DidFetchDataLoadFailed(); | |
239 return; | |
240 } | |
241 } | |
242 } | |
243 | |
244 void Cancel() override { | |
245 consumer_->Cancel(); | |
246 multipart_parser_->Cancel(); | |
247 } | |
248 | |
249 DEFINE_INLINE_TRACE() { | |
250 visitor->Trace(consumer_); | |
251 visitor->Trace(client_); | |
252 visitor->Trace(form_data_); | |
253 visitor->Trace(multipart_parser_); | |
254 FetchDataLoader::Trace(visitor); | |
255 BytesConsumer::Client::Trace(visitor); | |
256 MultipartParser::Client::Trace(visitor); | |
257 } | |
258 | |
259 private: | |
260 void PartHeaderFieldsInMultipartReceived( | |
261 const HTTPHeaderMap& header_fields) override { | |
262 if (!current_entry_.Initialize(header_fields)) | |
263 multipart_parser_->Cancel(); | |
264 } | |
265 | |
266 void PartDataInMultipartReceived(const char* bytes, size_t size) override { | |
267 if (!current_entry_.AppendBytes(bytes, size)) | |
268 multipart_parser_->Cancel(); | |
269 } | |
270 | |
271 void PartDataInMultipartFullyReceived() override { | |
272 if (!current_entry_.Finish(form_data_)) | |
273 multipart_parser_->Cancel(); | |
274 } | |
275 | |
276 class Entry { | |
277 public: | |
278 bool Initialize(const HTTPHeaderMap& header_fields) { | |
279 const ParsedContentType disposition( | |
yhirano
2017/05/10 05:59:36
Need some comments why we use x-fake.
e_hakkinen
2017/05/11 11:01:51
Done.
I also created https://crrev.com/2880543003
| |
280 "x-fake/" + header_fields.Get(HTTPNames::Content_Disposition)); | |
281 const String disposition_type = disposition.MimeType().Substring(7u); | |
yhirano
2017/05/10 05:59:36
Need some comments for the magic number.
e_hakkinen
2017/05/11 11:01:51
Done.
| |
282 filename_ = disposition.ParameterValueForName("filename"); | |
283 name_ = disposition.ParameterValueForName("name"); | |
284 blob_data_.reset(); | |
285 string_builder_.reset(); | |
286 if (disposition_type != "form-data" || name_.IsNull()) | |
287 return false; | |
288 if (!filename_.IsNull()) { | |
289 blob_data_ = BlobData::Create(); | |
290 const AtomicString& content_type = | |
291 header_fields.Get(HTTPNames::Content_Type); | |
292 blob_data_->SetContentType(content_type.IsNull() ? "text/plain" | |
293 : content_type); | |
294 } else { | |
295 if (!string_decoder_) | |
296 string_decoder_ = TextResourceDecoder::CreateAlwaysUseUTF8ForText(); | |
297 string_builder_.reset(new StringBuilder); | |
298 } | |
299 return true; | |
300 } | |
301 | |
302 bool AppendBytes(const char* bytes, size_t size) { | |
303 if (blob_data_) | |
304 blob_data_->AppendBytes(bytes, size); | |
305 if (string_builder_) { | |
306 string_builder_->Append(string_decoder_->Decode(bytes, size)); | |
307 if (string_decoder_->SawError()) | |
308 return false; | |
309 } | |
310 return true; | |
311 } | |
312 | |
313 bool Finish(FormData* form_data) { | |
314 if (blob_data_) { | |
315 DCHECK(!string_builder_); | |
316 const auto size = blob_data_->length(); | |
317 File* file = | |
318 File::Create(filename_, InvalidFileTime(), | |
319 BlobDataHandle::Create(std::move(blob_data_), size)); | |
320 form_data->append(name_, file, filename_); | |
321 } | |
322 if (string_builder_) { | |
323 DCHECK(!blob_data_); | |
324 string_builder_->Append(string_decoder_->Flush()); | |
325 if (string_decoder_->SawError()) | |
326 return false; | |
327 form_data->append(name_, string_builder_->ToString()); | |
328 } | |
329 return true; | |
330 } | |
331 | |
332 private: | |
333 std::unique_ptr<BlobData> blob_data_; | |
334 String filename_; | |
335 String name_; | |
336 std::unique_ptr<StringBuilder> string_builder_; | |
337 std::unique_ptr<TextResourceDecoder> string_decoder_; | |
338 }; | |
339 | |
340 Member<BytesConsumer> consumer_; | |
341 Member<FetchDataLoader::Client> client_; | |
342 Member<FormData> form_data_; | |
343 Member<MultipartParser> multipart_parser_; | |
344 | |
345 Entry current_entry_; | |
346 String multipart_boundary_; | |
347 }; | |
348 | |
173 class FetchDataLoaderAsString final : public FetchDataLoader, | 349 class FetchDataLoaderAsString final : public FetchDataLoader, |
174 public BytesConsumer::Client { | 350 public BytesConsumer::Client { |
175 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString); | 351 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString); |
176 | 352 |
177 public: | 353 public: |
178 void Start(BytesConsumer* consumer, | 354 void Start(BytesConsumer* consumer, |
179 FetchDataLoader::Client* client) override { | 355 FetchDataLoader::Client* client) override { |
180 DCHECK(!client_); | 356 DCHECK(!client_); |
181 DCHECK(!decoder_); | 357 DCHECK(!decoder_); |
182 DCHECK(!consumer_); | 358 DCHECK(!consumer_); |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
334 | 510 |
335 FetchDataLoader* FetchDataLoader::CreateLoaderAsBlobHandle( | 511 FetchDataLoader* FetchDataLoader::CreateLoaderAsBlobHandle( |
336 const String& mime_type) { | 512 const String& mime_type) { |
337 return new FetchDataLoaderAsBlobHandle(mime_type); | 513 return new FetchDataLoaderAsBlobHandle(mime_type); |
338 } | 514 } |
339 | 515 |
340 FetchDataLoader* FetchDataLoader::CreateLoaderAsArrayBuffer() { | 516 FetchDataLoader* FetchDataLoader::CreateLoaderAsArrayBuffer() { |
341 return new FetchDataLoaderAsArrayBuffer(); | 517 return new FetchDataLoaderAsArrayBuffer(); |
342 } | 518 } |
343 | 519 |
520 FetchDataLoader* FetchDataLoader::CreateLoaderAsFormData( | |
521 const String& multipartBoundary) { | |
522 return new FetchDataLoaderAsFormData(multipartBoundary); | |
523 } | |
524 | |
344 FetchDataLoader* FetchDataLoader::CreateLoaderAsString() { | 525 FetchDataLoader* FetchDataLoader::CreateLoaderAsString() { |
345 return new FetchDataLoaderAsString(); | 526 return new FetchDataLoaderAsString(); |
346 } | 527 } |
347 | 528 |
348 FetchDataLoader* FetchDataLoader::CreateLoaderAsDataPipe( | 529 FetchDataLoader* FetchDataLoader::CreateLoaderAsDataPipe( |
349 mojo::ScopedDataPipeProducerHandle out_data_pipe) { | 530 mojo::ScopedDataPipeProducerHandle out_data_pipe) { |
350 return new FetchDataLoaderAsDataPipe(std::move(out_data_pipe)); | 531 return new FetchDataLoaderAsDataPipe(std::move(out_data_pipe)); |
351 } | 532 } |
352 | 533 |
353 } // namespace blink | 534 } // namespace blink |
OLD | NEW |