Home | History | Annotate | Download | only in loader
      1 // Copyright 2013 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 "content/browser/loader/upload_data_stream_builder.h"
      6 
      7 #include "base/logging.h"
      8 #include "net/base/upload_bytes_element_reader.h"
      9 #include "net/base/upload_data_stream.h"
     10 #include "net/base/upload_file_element_reader.h"
     11 #include "webkit/browser/blob/blob_storage_controller.h"
     12 #include "webkit/browser/fileapi/upload_file_system_file_element_reader.h"
     13 #include "webkit/common/resource_request_body.h"
     14 
     15 using webkit_blob::BlobData;
     16 using webkit_blob::BlobStorageController;
     17 using webkit_glue::ResourceRequestBody;
     18 
     19 namespace content {
     20 namespace {
     21 
     22 // A subclass of net::UploadBytesElementReader which owns ResourceRequestBody.
     23 class BytesElementReader : public net::UploadBytesElementReader {
     24  public:
     25   BytesElementReader(ResourceRequestBody* resource_request_body,
     26                      const ResourceRequestBody::Element& element)
     27       : net::UploadBytesElementReader(element.bytes(), element.length()),
     28         resource_request_body_(resource_request_body) {
     29     DCHECK_EQ(ResourceRequestBody::Element::TYPE_BYTES, element.type());
     30   }
     31 
     32   virtual ~BytesElementReader() {}
     33 
     34  private:
     35   scoped_refptr<ResourceRequestBody> resource_request_body_;
     36 
     37   DISALLOW_COPY_AND_ASSIGN(BytesElementReader);
     38 };
     39 
     40 // A subclass of net::UploadFileElementReader which owns ResourceRequestBody.
     41 // This class is necessary to ensure the BlobData and any attached shareable
     42 // files survive until upload completion.
     43 class FileElementReader : public net::UploadFileElementReader {
     44  public:
     45   FileElementReader(ResourceRequestBody* resource_request_body,
     46                     base::TaskRunner* task_runner,
     47                     const ResourceRequestBody::Element& element)
     48       : net::UploadFileElementReader(task_runner,
     49                                      element.path(),
     50                                      element.offset(),
     51                                      element.length(),
     52                                      element.expected_modification_time()),
     53         resource_request_body_(resource_request_body) {
     54     DCHECK_EQ(ResourceRequestBody::Element::TYPE_FILE, element.type());
     55   }
     56 
     57   virtual ~FileElementReader() {}
     58 
     59  private:
     60   scoped_refptr<ResourceRequestBody> resource_request_body_;
     61 
     62   DISALLOW_COPY_AND_ASSIGN(FileElementReader);
     63 };
     64 
     65 void ResolveBlobReference(
     66     ResourceRequestBody* body,
     67     webkit_blob::BlobStorageController* blob_controller,
     68     const GURL& blob_url,
     69     std::vector<const ResourceRequestBody::Element*>* resolved_elements) {
     70   DCHECK(blob_controller);
     71   BlobData* blob_data = blob_controller->GetBlobDataFromUrl(blob_url);
     72   DCHECK(blob_data);
     73   if (!blob_data)
     74     return;
     75 
     76   // If there is no element in the referred blob data, just return.
     77   if (blob_data->items().empty())
     78     return;
     79 
     80   // Ensure the blob and any attached shareable files survive until
     81   // upload completion.
     82   body->SetUserData(blob_data, new base::UserDataAdapter<BlobData>(blob_data));
     83 
     84   // Append the elements in the referred blob data.
     85   for (size_t i = 0; i < blob_data->items().size(); ++i) {
     86     const BlobData::Item& item = blob_data->items().at(i);
     87     DCHECK_NE(BlobData::Item::TYPE_BLOB, item.type());
     88     resolved_elements->push_back(&item);
     89   }
     90 }
     91 
     92 }  // namespace
     93 
     94 scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
     95     ResourceRequestBody* body,
     96     BlobStorageController* blob_controller,
     97     fileapi::FileSystemContext* file_system_context,
     98     base::TaskRunner* file_task_runner) {
     99   // Resolve all blob elements.
    100   std::vector<const ResourceRequestBody::Element*> resolved_elements;
    101   for (size_t i = 0; i < body->elements()->size(); ++i) {
    102     const ResourceRequestBody::Element& element = (*body->elements())[i];
    103     if (element.type() == ResourceRequestBody::Element::TYPE_BLOB) {
    104       ResolveBlobReference(body, blob_controller, element.url(),
    105                            &resolved_elements);
    106     } else {
    107       // No need to resolve, just append the element.
    108       resolved_elements.push_back(&element);
    109     }
    110   }
    111 
    112   ScopedVector<net::UploadElementReader> element_readers;
    113   for (size_t i = 0; i < resolved_elements.size(); ++i) {
    114     const ResourceRequestBody::Element& element = *resolved_elements[i];
    115     switch (element.type()) {
    116       case ResourceRequestBody::Element::TYPE_BYTES:
    117         element_readers.push_back(new BytesElementReader(body, element));
    118         break;
    119       case ResourceRequestBody::Element::TYPE_FILE:
    120         element_readers.push_back(
    121             new FileElementReader(body, file_task_runner, element));
    122         break;
    123       case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM:
    124         element_readers.push_back(
    125             new fileapi::UploadFileSystemFileElementReader(
    126                 file_system_context,
    127                 element.url(),
    128                 element.offset(),
    129                 element.length(),
    130                 element.expected_modification_time()));
    131         break;
    132       case ResourceRequestBody::Element::TYPE_BLOB:
    133         // Blob elements should be resolved beforehand.
    134         NOTREACHED();
    135         break;
    136       case ResourceRequestBody::Element::TYPE_UNKNOWN:
    137         NOTREACHED();
    138         break;
    139     }
    140   }
    141 
    142   return make_scoped_ptr(
    143       new net::UploadDataStream(&element_readers, body->identifier()));
    144 }
    145 
    146 }  // namespace content
    147