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 "core/fileapi/Blob.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 Loading... |
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, public BytesCons
umer::Client, public MultipartParser::Client { |
| 177 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsFormData); |
| 178 |
| 179 public: |
| 180 explicit FetchDataLoaderAsFormData(const String& multipartBoundary) |
| 181 : m_multipartBoundary(multipartBoundary) |
| 182 { |
| 183 } |
| 184 |
| 185 void start(BytesConsumer* consumer, FetchDataLoader::Client* client) overrid
e |
| 186 { |
| 187 DCHECK(!m_client); |
| 188 DCHECK(!m_multipartParser); |
| 189 DCHECK(!m_consumer); |
| 190 |
| 191 CString multipartBoundaryCString = m_multipartBoundary.utf8(); |
| 192 Vector<char> multipartBoundaryVector; |
| 193 multipartBoundaryVector.append(multipartBoundaryCString.data(), multipar
tBoundaryCString.length()); |
| 194 |
| 195 m_client = client; |
| 196 m_formData = FormData::create(); |
| 197 m_multipartParser = new MultipartParser(std::move(multipartBoundaryVecto
r), this); |
| 198 m_consumer = consumer; |
| 199 m_consumer->setClient(this); |
| 200 onStateChange(); |
| 201 } |
| 202 |
| 203 void onStateChange() override |
| 204 { |
| 205 while (!m_multipartParser->isCancelled()) { |
| 206 const char* buffer; |
| 207 size_t available; |
| 208 switch (m_consumer->beginRead(&buffer, &available)) { |
| 209 case BytesConsumer::Result::Ok: |
| 210 if (available > 0) { |
| 211 if (!m_multipartParser->appendData(buffer, available)) |
| 212 failed(); |
| 213 } |
| 214 m_consumer->endRead(available); |
| 215 break; |
| 216 case BytesConsumer::Result::ShouldWait: |
| 217 return; |
| 218 case BytesConsumer::Result::Done: |
| 219 if (m_multipartParser->finish()) { |
| 220 m_client->didFetchDataLoadedFormData(m_formData); |
| 221 } else { |
| 222 m_client->didFetchDataLoadFailed(); |
| 223 } |
| 224 return; |
| 225 case BytesConsumer::Result::Error: |
| 226 m_client->didFetchDataLoadFailed(); |
| 227 return; |
| 228 } |
| 229 } |
| 230 } |
| 231 |
| 232 void cancel() override |
| 233 { |
| 234 m_consumer->cancel(); |
| 235 m_multipartParser->cancel(); |
| 236 } |
| 237 |
| 238 DEFINE_INLINE_TRACE() |
| 239 { |
| 240 visitor->trace(m_consumer); |
| 241 visitor->trace(m_client); |
| 242 visitor->trace(m_formData); |
| 243 visitor->trace(m_multipartParser); |
| 244 FetchDataLoader::trace(visitor); |
| 245 BytesConsumer::Client::trace(visitor); |
| 246 MultipartParser::Client::trace(visitor); |
| 247 } |
| 248 |
| 249 private: |
| 250 void failed() |
| 251 { |
| 252 m_client->didFetchDataLoadFailed(); |
| 253 // The client does not like to be notified multiple times thus stop |
| 254 // parsing so that no more errors will be reached. |
| 255 cancel(); |
| 256 } |
| 257 |
| 258 void partHeaderFieldsInMultipartReceived(const ResourceResponse& response) o
verride |
| 259 { |
| 260 if (!m_currentEntry.initialize(response)) |
| 261 failed(); |
| 262 } |
| 263 |
| 264 void partDataInMultipartReceived(const char* bytes, size_t size) override |
| 265 { |
| 266 if (!m_currentEntry.appendBytes(bytes, size)) |
| 267 failed(); |
| 268 } |
| 269 |
| 270 void partDataInMultipartFullyReceived() override |
| 271 { |
| 272 if (!m_currentEntry.finish(m_formData)) |
| 273 failed(); |
| 274 } |
| 275 |
| 276 class Entry { |
| 277 public: |
| 278 bool initialize(const ResourceResponse& response) |
| 279 { |
| 280 ParsedContentType disposition(response.httpHeaderField(HTTPNames::Co
ntent_Disposition)); |
| 281 String dispositionType = disposition.mimeType(); |
| 282 m_filename = disposition.parameterValueForName("filename"); |
| 283 m_name = disposition.parameterValueForName("name"); |
| 284 m_blobData.reset(); |
| 285 m_stringBuilder.reset(); |
| 286 if (dispositionType != "form-data" || m_name.isNull()) |
| 287 return false; |
| 288 if (!m_filename.isNull()) { |
| 289 m_blobData = BlobData::create(); |
| 290 m_blobData->setContentType(response.httpHeaderField(HTTPNames::C
ontent_Type)); |
| 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 { |
| 301 if (m_blobData) |
| 302 m_blobData->appendBytes(bytes, size); |
| 303 if (m_stringBuilder) { |
| 304 m_stringBuilder->append(m_decoder->decode(bytes, size)); |
| 305 if (m_decoder->sawError()) |
| 306 return false; |
| 307 } |
| 308 return true; |
| 309 } |
| 310 |
| 311 bool finish(FormData* formData) |
| 312 { |
| 313 if (m_blobData) { |
| 314 DCHECK(!m_stringBuilder); |
| 315 auto size = m_blobData->length(); |
| 316 formData->append(m_name, Blob::create(BlobDataHandle::create(std
::move(m_blobData), size)), m_filename); |
| 317 } |
| 318 if (m_stringBuilder) { |
| 319 DCHECK(!m_blobData); |
| 320 m_stringBuilder->append(m_decoder->flush()); |
| 321 if (m_decoder->sawError()) |
| 322 return false; |
| 323 formData->append(m_name, m_stringBuilder->toString()); |
| 324 } |
| 325 return true; |
| 326 } |
| 327 |
| 328 private: |
| 329 std::unique_ptr<BlobData> m_blobData; |
| 330 std::unique_ptr<TextResourceDecoder> m_decoder; |
| 331 String m_filename; |
| 332 String m_name; |
| 333 std::unique_ptr<StringBuilder> m_stringBuilder; |
| 334 }; |
| 335 |
| 336 Member<BytesConsumer> m_consumer; |
| 337 Member<FetchDataLoader::Client> m_client; |
| 338 Member<FormData> m_formData; |
| 339 Member<MultipartParser> m_multipartParser; |
| 340 |
| 341 Entry m_currentEntry; |
| 342 String m_multipartBoundary; |
| 343 }; |
| 344 |
171 class FetchDataLoaderAsString final : public FetchDataLoader, public BytesConsum
er::Client { | 345 class FetchDataLoaderAsString final : public FetchDataLoader, public BytesConsum
er::Client { |
172 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString); | 346 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString); |
173 public: | 347 public: |
174 void start(BytesConsumer* consumer, FetchDataLoader::Client* client) overrid
e | 348 void start(BytesConsumer* consumer, FetchDataLoader::Client* client) overrid
e |
175 { | 349 { |
176 DCHECK(!m_client); | 350 DCHECK(!m_client); |
177 DCHECK(!m_decoder); | 351 DCHECK(!m_decoder); |
178 DCHECK(!m_consumer); | 352 DCHECK(!m_consumer); |
179 m_client = client; | 353 m_client = client; |
180 m_decoder = TextResourceDecoder::createAlwaysUseUTF8ForText(); | 354 m_decoder = TextResourceDecoder::createAlwaysUseUTF8ForText(); |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
312 FetchDataLoader* FetchDataLoader::createLoaderAsBlobHandle(const String& mimeTyp
e) | 486 FetchDataLoader* FetchDataLoader::createLoaderAsBlobHandle(const String& mimeTyp
e) |
313 { | 487 { |
314 return new FetchDataLoaderAsBlobHandle(mimeType); | 488 return new FetchDataLoaderAsBlobHandle(mimeType); |
315 } | 489 } |
316 | 490 |
317 FetchDataLoader* FetchDataLoader::createLoaderAsArrayBuffer() | 491 FetchDataLoader* FetchDataLoader::createLoaderAsArrayBuffer() |
318 { | 492 { |
319 return new FetchDataLoaderAsArrayBuffer(); | 493 return new FetchDataLoaderAsArrayBuffer(); |
320 } | 494 } |
321 | 495 |
| 496 FetchDataLoader* FetchDataLoader::createLoaderAsFormData(const String& multipart
Boundary) |
| 497 { |
| 498 return new FetchDataLoaderAsFormData(multipartBoundary); |
| 499 } |
| 500 |
322 FetchDataLoader* FetchDataLoader::createLoaderAsString() | 501 FetchDataLoader* FetchDataLoader::createLoaderAsString() |
323 { | 502 { |
324 return new FetchDataLoaderAsString(); | 503 return new FetchDataLoaderAsString(); |
325 } | 504 } |
326 | 505 |
327 FetchDataLoader* FetchDataLoader::createLoaderAsStream(Stream* outStream) | 506 FetchDataLoader* FetchDataLoader::createLoaderAsStream(Stream* outStream) |
328 { | 507 { |
329 return new FetchDataLoaderAsStream(outStream); | 508 return new FetchDataLoaderAsStream(outStream); |
330 } | 509 } |
331 | 510 |
332 } // namespace blink | 511 } // namespace blink |
OLD | NEW |