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 "storage/browser/blob/blob_data_handle.h"
     14 #include "storage/browser/blob/blob_storage_context.h"
     15 
     16 using storage::BlobData;
     17 using storage::BlobDataHandle;
     18 using storage::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     storage::BlobStorageContext* blob_context,
     68     const ResourceRequestBody::Element& element,
     69     std::vector<const ResourceRequestBody::Element*>* resolved_elements) {
     70   DCHECK(blob_context);
     71   scoped_ptr<storage::BlobDataHandle> handle =
     72       blob_context->GetBlobDataFromUUID(element.blob_uuid());
     73   DCHECK(handle);
     74   if (!handle)
     75     return;
     76 
     77   // If there is no element in the referred blob data, just return.
     78   if (handle->data()->items().empty())
     79     return;
     80 
     81   // Append the elements in the referenced blob data.
     82   for (size_t i = 0; i < handle->data()->items().size(); ++i) {
     83     const BlobData::Item& item = handle->data()->items().at(i);
     84     DCHECK_NE(BlobData::Item::TYPE_BLOB, item.type());
     85     resolved_elements->push_back(&item);
     86   }
     87 }
     88 
     89 }  // namespace
     90 
     91 scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
     92     ResourceRequestBody* body,
     93     BlobStorageContext* blob_context,
     94     storage::FileSystemContext* file_system_context,
     95     base::TaskRunner* file_task_runner) {
     96   // Resolve all blob elements.
     97   std::vector<const ResourceRequestBody::Element*> resolved_elements;
     98   for (size_t i = 0; i < body->elements()->size(); ++i) {
     99     const ResourceRequestBody::Element& element = (*body->elements())[i];
    100     if (element.type() == ResourceRequestBody::Element::TYPE_BLOB)
    101       ResolveBlobReference(blob_context, element, &resolved_elements);
    102     else
    103       resolved_elements.push_back(&element);
    104   }
    105 
    106   ScopedVector<net::UploadElementReader> element_readers;
    107   for (size_t i = 0; i < resolved_elements.size(); ++i) {
    108     const ResourceRequestBody::Element& element = *resolved_elements[i];
    109     switch (element.type()) {
    110       case ResourceRequestBody::Element::TYPE_BYTES:
    111         element_readers.push_back(new BytesElementReader(body, element));
    112         break;
    113       case ResourceRequestBody::Element::TYPE_FILE:
    114         element_readers.push_back(
    115             new FileElementReader(body, file_task_runner, element));
    116         break;
    117       case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM:
    118         element_readers.push_back(
    119             new content::UploadFileSystemFileElementReader(
    120                 file_system_context,
    121                 element.filesystem_url(),
    122                 element.offset(),
    123                 element.length(),
    124                 element.expected_modification_time()));
    125         break;
    126       case ResourceRequestBody::Element::TYPE_BLOB:
    127         // Blob elements should be resolved beforehand.
    128         NOTREACHED();
    129         break;
    130       case ResourceRequestBody::Element::TYPE_UNKNOWN:
    131         NOTREACHED();
    132         break;
    133     }
    134   }
    135 
    136   return make_scoped_ptr(
    137       new net::UploadDataStream(element_readers.Pass(), body->identifier()));
    138 }
    139 
    140 }  // namespace content
    141