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 "content/browser/fileapi/upload_file_system_file_element_reader.h"
      9 #include "content/common/resource_request_body.h"
     10 #include "net/base/upload_bytes_element_reader.h"
     11 #include "net/base/upload_data_stream.h"
     12 #include "net/base/upload_file_element_reader.h"
     13 #include "webkit/browser/blob/blob_data_handle.h"
     14 #include "webkit/browser/blob/blob_storage_context.h"
     15 
     16 using webkit_blob::BlobData;
     17 using webkit_blob::BlobDataHandle;
     18 using webkit_blob::BlobStorageContext;
     19 
     20 namespace content {
     21 namespace {
     22 
     23 // A subclass of net::UploadBytesElementReader which owns ResourceRequestBody.
     24 class BytesElementReader : public net::UploadBytesElementReader {
     25  public:
     26   BytesElementReader(ResourceRequestBody* resource_request_body,
     27                      const ResourceRequestBody::Element& element)
     28       : net::UploadBytesElementReader(element.bytes(), element.length()),
     29         resource_request_body_(resource_request_body) {
     30     DCHECK_EQ(ResourceRequestBody::Element::TYPE_BYTES, element.type());
     31   }
     32 
     33   virtual ~BytesElementReader() {}
     34 
     35  private:
     36   scoped_refptr<ResourceRequestBody> resource_request_body_;
     37 
     38   DISALLOW_COPY_AND_ASSIGN(BytesElementReader);
     39 };
     40 
     41 // A subclass of net::UploadFileElementReader which owns ResourceRequestBody.
     42 // This class is necessary to ensure the BlobData and any attached shareable
     43 // files survive until upload completion.
     44 class FileElementReader : public net::UploadFileElementReader {
     45  public:
     46   FileElementReader(ResourceRequestBody* resource_request_body,
     47                     base::TaskRunner* task_runner,
     48                     const ResourceRequestBody::Element& element)
     49       : net::UploadFileElementReader(task_runner,
     50                                      element.path(),
     51                                      element.offset(),
     52                                      element.length(),
     53                                      element.expected_modification_time()),
     54         resource_request_body_(resource_request_body) {
     55     DCHECK_EQ(ResourceRequestBody::Element::TYPE_FILE, element.type());
     56   }
     57 
     58   virtual ~FileElementReader() {}
     59 
     60  private:
     61   scoped_refptr<ResourceRequestBody> resource_request_body_;
     62 
     63   DISALLOW_COPY_AND_ASSIGN(FileElementReader);
     64 };
     65 
     66 void ResolveBlobReference(
     67     ResourceRequestBody* body,
     68     webkit_blob::BlobStorageContext* blob_context,
     69     const ResourceRequestBody::Element& element,
     70     std::vector<const ResourceRequestBody::Element*>* resolved_elements) {
     71   DCHECK(blob_context);
     72   scoped_ptr<webkit_blob::BlobDataHandle> handle =
     73       blob_context->GetBlobDataFromUUID(element.blob_uuid());
     74   DCHECK(handle);
     75   if (!handle)
     76     return;
     77 
     78   // If there is no element in the referred blob data, just return.
     79   if (handle->data()->items().empty())
     80     return;
     81 
     82   // Append the elements in the referenced blob data.
     83   for (size_t i = 0; i < handle->data()->items().size(); ++i) {
     84     const BlobData::Item& item = handle->data()->items().at(i);
     85     DCHECK_NE(BlobData::Item::TYPE_BLOB, item.type());
     86     resolved_elements->push_back(&item);
     87   }
     88 
     89   // Ensure the blob and any attached shareable files survive until
     90   // upload completion. The |body| takes ownership of |handle|.
     91   const void* key = handle.get();
     92   body->SetUserData(key, handle.release());
     93 }
     94 
     95 }  // namespace
     96 
     97 scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
     98     ResourceRequestBody* body,
     99     BlobStorageContext* blob_context,
    100     fileapi::FileSystemContext* file_system_context,
    101     base::TaskRunner* file_task_runner) {
    102   // Resolve all blob elements.
    103   std::vector<const ResourceRequestBody::Element*> resolved_elements;
    104   for (size_t i = 0; i < body->elements()->size(); ++i) {
    105     const ResourceRequestBody::Element& element = (*body->elements())[i];
    106     if (element.type() == ResourceRequestBody::Element::TYPE_BLOB)
    107       ResolveBlobReference(body, blob_context, element, &resolved_elements);
    108     else
    109       resolved_elements.push_back(&element);
    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 content::UploadFileSystemFileElementReader(
    126                 file_system_context,
    127                 element.filesystem_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.Pass(), body->identifier()));
    144 }
    145 
    146 }  // namespace content
    147