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