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

Side by Side Diff: third_party/WebKit/Source/modules/fetch/FetchDataLoader.cpp

Issue 2292763002: [Fetch API] Implement Request.formData and Response.formData. (Closed)
Patch Set: Created 3 years, 11 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
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 "core/fileapi/File.h"
8 #include "core/html/FormData.h"
7 #include "core/html/parser/TextResourceDecoder.h" 9 #include "core/html/parser/TextResourceDecoder.h"
8 #include "modules/fetch/BytesConsumer.h" 10 #include "modules/fetch/BytesConsumer.h"
11 #include "modules/fetch/MultipartParser.h"
12 #include "platform/HTTPNames.h"
13 #include "platform/network/ParsedContentType.h"
9 #include "wtf/PtrUtil.h" 14 #include "wtf/PtrUtil.h"
10 #include "wtf/text/StringBuilder.h" 15 #include "wtf/text/StringBuilder.h"
11 #include "wtf/text/WTFString.h" 16 #include "wtf/text/WTFString.h"
12 #include "wtf/typed_arrays/ArrayBufferBuilder.h" 17 #include "wtf/typed_arrays/ArrayBufferBuilder.h"
13 #include <memory> 18 #include <memory>
14 19
15 namespace blink { 20 namespace blink {
16 21
17 namespace { 22 namespace {
18 23
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 BytesConsumer::Client::trace(visitor); 166 BytesConsumer::Client::trace(visitor);
162 } 167 }
163 168
164 private: 169 private:
165 Member<BytesConsumer> m_consumer; 170 Member<BytesConsumer> m_consumer;
166 Member<FetchDataLoader::Client> m_client; 171 Member<FetchDataLoader::Client> m_client;
167 172
168 std::unique_ptr<ArrayBufferBuilder> m_rawData; 173 std::unique_ptr<ArrayBufferBuilder> m_rawData;
169 }; 174 };
170 175
176 class FetchDataLoaderAsFormData final : public FetchDataLoader,
177 public BytesConsumer::Client,
178 public MultipartParser::Client {
179 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsFormData);
180
181 public:
182 explicit FetchDataLoaderAsFormData(const String& multipartBoundary)
183 : m_multipartBoundary(multipartBoundary) {}
184
185 void start(BytesConsumer* consumer,
186 FetchDataLoader::Client* client) override {
187 DCHECK(!m_client);
188 DCHECK(!m_consumer);
189 DCHECK(!m_formData);
190 DCHECK(!m_multipartParser);
191
192 const CString multipartBoundaryCString = m_multipartBoundary.utf8();
yhirano 2017/01/11 08:54:03 Is this variable needed? Isn't it enough to run |m
e_hakkinen 2017/05/02 23:38:56 |Utf8()| is not a getter but a conversion function
193 Vector<char> multipartBoundaryVector;
194 multipartBoundaryVector.append(multipartBoundaryCString.data(),
195 multipartBoundaryCString.length());
196
197 m_client = client;
198 m_formData = FormData::create();
199 m_multipartParser =
200 new MultipartParser(std::move(multipartBoundaryVector), this);
201 m_consumer = consumer;
202 m_consumer->setClient(this);
203 onStateChange();
204 }
205
206 void onStateChange() override {
207 while (true) {
208 const char* buffer;
209 size_t available;
210 auto result = m_consumer->beginRead(&buffer, &available);
211 if (result == BytesConsumer::Result::ShouldWait)
212 return;
213 if (result == BytesConsumer::Result::Ok) {
214 const bool bufferAppended =
215 m_multipartParser->appendData(buffer, available);
216 const bool multipartReceiveFailed = m_multipartParser->isCancelled();
217 result = m_consumer->endRead(available);
218 if (!bufferAppended || multipartReceiveFailed)
219 result = BytesConsumer::Result::Error;
220 }
221 switch (result) {
222 case BytesConsumer::Result::Ok:
223 break;
224 case BytesConsumer::Result::ShouldWait:
225 NOTREACHED();
226 return;
227 case BytesConsumer::Result::Done:
228 if (m_multipartParser->finish()) {
229 DCHECK(!m_multipartParser->isCancelled());
230 m_client->didFetchDataLoadedFormData(m_formData);
231 return;
232 }
233 // Fall throught.
yhirano 2017/01/11 08:54:03 Can you write m_client->didFetchDataLoadFailed() h
e_hakkinen 2017/05/02 23:38:56 Done.
234 case BytesConsumer::Result::Error:
235 m_client->didFetchDataLoadFailed();
236 return;
237 }
238 }
239 }
240
241 void cancel() override {
242 m_consumer->cancel();
243 m_multipartParser->cancel();
244 }
245
246 DEFINE_INLINE_TRACE() {
247 visitor->trace(m_consumer);
248 visitor->trace(m_client);
249 visitor->trace(m_formData);
250 visitor->trace(m_multipartParser);
251 FetchDataLoader::trace(visitor);
252 BytesConsumer::Client::trace(visitor);
253 MultipartParser::Client::trace(visitor);
254 }
255
256 private:
257 void partHeaderFieldsInMultipartReceived(
258 const HTTPHeaderMap& headerFields) override {
259 if (!m_currentEntry.initialize(headerFields))
260 m_multipartParser->cancel();
yhirano 2017/01/11 08:54:03 Shouldn't be this cancel() (i.e., this->cancel())?
e_hakkinen 2017/05/02 23:38:56 No, it should not. This member function is called
261 }
262
263 void partDataInMultipartReceived(const char* bytes, size_t size) override {
264 if (!m_currentEntry.appendBytes(bytes, size))
265 m_multipartParser->cancel();
266 }
267
268 void partDataInMultipartFullyReceived() override {
269 if (!m_currentEntry.finish(m_formData))
270 m_multipartParser->cancel();
271 }
272
273 class Entry {
274 public:
275 bool initialize(const HTTPHeaderMap& headerFields) {
276 const ParsedContentType disposition(
277 headerFields.get(HTTPNames::Content_Disposition));
278 const String dispositionType = disposition.mimeType();
279 m_filename = disposition.parameterValueForName("filename");
280 m_name = disposition.parameterValueForName("name");
281 m_blobData.reset();
282 m_stringBuilder.reset();
283 if (dispositionType != "form-data" || m_name.isNull())
284 return false;
285 if (!m_filename.isNull()) {
286 m_blobData = BlobData::create();
287 const AtomicString& contentType =
288 headerFields.get(HTTPNames::Content_Type);
289 m_blobData->setContentType(contentType.isNull() ? "text/plain"
290 : contentType);
291 } else {
292 if (!m_decoder)
293 m_decoder = TextResourceDecoder::createAlwaysUseUTF8ForText();
294 m_stringBuilder.reset(new StringBuilder);
295 }
296 return true;
297 }
298
299 bool appendBytes(const char* bytes, size_t size) {
300 if (m_blobData)
301 m_blobData->appendBytes(bytes, size);
302 if (m_stringBuilder) {
303 m_stringBuilder->append(m_decoder->decode(bytes, size));
304 if (m_decoder->sawError())
305 return false;
306 }
307 return true;
308 }
309
310 bool finish(FormData* formData) {
311 if (m_blobData) {
312 DCHECK(!m_stringBuilder);
313 const auto size = m_blobData->length();
314 File* file =
315 File::create(m_filename, invalidFileTime(),
316 BlobDataHandle::create(std::move(m_blobData), size));
317 formData->append(m_name, file, m_filename);
318 }
319 if (m_stringBuilder) {
320 DCHECK(!m_blobData);
321 m_stringBuilder->append(m_decoder->flush());
322 if (m_decoder->sawError())
323 return false;
324 formData->append(m_name, m_stringBuilder->toString());
325 }
326 return true;
327 }
328
329 private:
330 std::unique_ptr<BlobData> m_blobData;
331 std::unique_ptr<TextResourceDecoder> m_decoder;
332 String m_filename;
333 String m_name;
334 std::unique_ptr<StringBuilder> m_stringBuilder;
335 };
336
337 Member<BytesConsumer> m_consumer;
338 Member<FetchDataLoader::Client> m_client;
339 Member<FormData> m_formData;
340 Member<MultipartParser> m_multipartParser;
341
342 Entry m_currentEntry;
343 String m_multipartBoundary;
344 };
345
171 class FetchDataLoaderAsString final : public FetchDataLoader, 346 class FetchDataLoaderAsString final : public FetchDataLoader,
172 public BytesConsumer::Client { 347 public BytesConsumer::Client {
173 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString); 348 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString);
174 349
175 public: 350 public:
176 void start(BytesConsumer* consumer, 351 void start(BytesConsumer* consumer,
177 FetchDataLoader::Client* client) override { 352 FetchDataLoader::Client* client) override {
178 DCHECK(!m_client); 353 DCHECK(!m_client);
179 DCHECK(!m_decoder); 354 DCHECK(!m_decoder);
180 DCHECK(!m_consumer); 355 DCHECK(!m_consumer);
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 484
310 FetchDataLoader* FetchDataLoader::createLoaderAsBlobHandle( 485 FetchDataLoader* FetchDataLoader::createLoaderAsBlobHandle(
311 const String& mimeType) { 486 const String& mimeType) {
312 return new FetchDataLoaderAsBlobHandle(mimeType); 487 return new FetchDataLoaderAsBlobHandle(mimeType);
313 } 488 }
314 489
315 FetchDataLoader* FetchDataLoader::createLoaderAsArrayBuffer() { 490 FetchDataLoader* FetchDataLoader::createLoaderAsArrayBuffer() {
316 return new FetchDataLoaderAsArrayBuffer(); 491 return new FetchDataLoaderAsArrayBuffer();
317 } 492 }
318 493
494 FetchDataLoader* FetchDataLoader::createLoaderAsFormData(
495 const String& multipartBoundary) {
496 return new FetchDataLoaderAsFormData(multipartBoundary);
497 }
498
319 FetchDataLoader* FetchDataLoader::createLoaderAsString() { 499 FetchDataLoader* FetchDataLoader::createLoaderAsString() {
320 return new FetchDataLoaderAsString(); 500 return new FetchDataLoaderAsString();
321 } 501 }
322 502
323 FetchDataLoader* FetchDataLoader::createLoaderAsStream(Stream* outStream) { 503 FetchDataLoader* FetchDataLoader::createLoaderAsStream(Stream* outStream) {
324 return new FetchDataLoaderAsStream(outStream); 504 return new FetchDataLoaderAsStream(outStream);
325 } 505 }
326 506
327 } // namespace blink 507 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698