Home | History | Annotate | Download | only in chrome_frame
      1 // Copyright (c) 2012 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 "chrome_frame/urlmon_upload_data_stream.h"
      6 
      7 #include "net/base/io_buffer.h"
      8 #include "net/base/net_errors.h"
      9 #include "net/base/upload_bytes_element_reader.h"
     10 #include "net/base/upload_file_element_reader.h"
     11 
     12 namespace {
     13 
     14 // Creates UploadDataStream from UploadData.
     15 net::UploadDataStream* CreateUploadDataStream(net::UploadData* upload_data) {
     16   net::UploadDataStream* upload_data_stream = NULL;
     17   const ScopedVector<net::UploadElement>& elements = upload_data->elements();
     18 
     19   if (upload_data->is_chunked()) {
     20     // Use AppendChunk when data is chunked.
     21     upload_data_stream = new net::UploadDataStream(
     22         net::UploadDataStream::CHUNKED, upload_data->identifier());
     23 
     24     for (size_t i = 0; i < elements.size(); ++i) {
     25       const net::UploadElement& element = *elements[i];
     26       const bool is_last_chunk =
     27           i == elements.size() - 1 && upload_data->last_chunk_appended();
     28       DCHECK_EQ(net::UploadElement::TYPE_BYTES, element.type());
     29       upload_data_stream->AppendChunk(element.bytes(), element.bytes_length(),
     30                                       is_last_chunk);
     31     }
     32   } else {
     33     // Not chunked.
     34     ScopedVector<net::UploadElementReader> element_readers;
     35     for (size_t i = 0; i < elements.size(); ++i) {
     36       const net::UploadElement& element = *elements[i];
     37       net::UploadElementReader* reader = NULL;
     38       switch (element.type()) {
     39         case net::UploadElement::TYPE_BYTES:
     40           reader = new net::UploadBytesElementReader(element.bytes(),
     41                                                      element.bytes_length());
     42           break;
     43         case net::UploadElement::TYPE_FILE:
     44           reader = new net::UploadFileElementReaderSync(
     45               element.file_path(),
     46               element.file_range_offset(),
     47               element.file_range_length(),
     48               element.expected_file_modification_time());
     49           break;
     50       }
     51       DCHECK(reader);
     52       element_readers.push_back(reader);
     53     }
     54     upload_data_stream = new net::UploadDataStream(&element_readers,
     55                                                    upload_data->identifier());
     56   }
     57   return upload_data_stream;
     58 }
     59 
     60 }  // namespace
     61 
     62 void UrlmonUploadDataStream::Initialize(net::UploadData* upload_data) {
     63   upload_data_ = upload_data;
     64   request_body_stream_.reset(CreateUploadDataStream(upload_data));
     65   const int result = request_body_stream_->Init(net::CompletionCallback());
     66   DCHECK_EQ(net::OK, result);
     67 }
     68 
     69 STDMETHODIMP UrlmonUploadDataStream::Read(void* pv, ULONG cb, ULONG* read) {
     70   if (pv == NULL) {
     71     NOTREACHED();
     72     return E_POINTER;
     73   }
     74 
     75   // Have we already read past the end of the stream?
     76   if (request_body_stream_->IsEOF()) {
     77     if (read) {
     78       *read = 0;
     79     }
     80     return S_FALSE;
     81   }
     82 
     83   // The data in request_body_stream_ can be smaller than 'cb' so it's not
     84   // guaranteed that we'll be able to read total_bytes_to_copy bytes.
     85   uint64 total_bytes_to_copy = cb;
     86 
     87   uint64 bytes_copied = 0;
     88 
     89   char* write_pointer = reinterpret_cast<char*>(pv);
     90   while (bytes_copied < total_bytes_to_copy) {
     91     size_t bytes_to_copy_now = total_bytes_to_copy - bytes_copied;
     92 
     93     scoped_refptr<net::IOBufferWithSize> buf(
     94         new net::IOBufferWithSize(bytes_to_copy_now));
     95     int bytes_read = request_body_stream_->Read(buf, buf->size(),
     96                                                 net::CompletionCallback());
     97     DCHECK_NE(net::ERR_IO_PENDING, bytes_read);
     98     if (bytes_read == 0)  // Reached the end of the stream.
     99       break;
    100 
    101     memcpy(write_pointer, buf->data(), bytes_read);
    102 
    103     // Advance our copy tally
    104     bytes_copied += bytes_read;
    105 
    106     // Advance our write pointer
    107     write_pointer += bytes_read;
    108   }
    109 
    110   DCHECK_LE(bytes_copied, total_bytes_to_copy);
    111 
    112   if (read) {
    113     *read = static_cast<ULONG>(bytes_copied);
    114   }
    115 
    116   return S_OK;
    117 }
    118 
    119 STDMETHODIMP UrlmonUploadDataStream::Seek(LARGE_INTEGER move, DWORD origin,
    120                                           ULARGE_INTEGER* new_pos) {
    121   // UploadDataStream is really not very seek-able, so for now allow
    122   // STREAM_SEEK_SETs to work with a 0 offset, but fail on everything else.
    123   if (origin == STREAM_SEEK_SET && move.QuadPart == 0) {
    124     if (request_body_stream_->position() != 0) {
    125       request_body_stream_.reset(CreateUploadDataStream(upload_data_));
    126       const int result = request_body_stream_->Init(net::CompletionCallback());
    127       DCHECK_EQ(net::OK, result);
    128     }
    129     if (new_pos) {
    130       new_pos->QuadPart = 0;
    131     }
    132     return S_OK;
    133   }
    134 
    135   DCHECK(false) << __FUNCTION__;
    136   return STG_E_INVALIDFUNCTION;
    137 }
    138 
    139 STDMETHODIMP UrlmonUploadDataStream::Stat(STATSTG *stat_stg,
    140                                           DWORD grf_stat_flag) {
    141   if (stat_stg == NULL)
    142     return E_POINTER;
    143 
    144   memset(stat_stg, 0, sizeof(STATSTG));
    145   if (0 == (grf_stat_flag & STATFLAG_NONAME)) {
    146     const wchar_t kStreamBuffer[] = L"PostStream";
    147     stat_stg->pwcsName =
    148         static_cast<wchar_t*>(::CoTaskMemAlloc(sizeof(kStreamBuffer)));
    149     lstrcpy(stat_stg->pwcsName, kStreamBuffer);
    150   }
    151   stat_stg->type = STGTY_STREAM;
    152   stat_stg->cbSize.QuadPart = request_body_stream_->size();
    153   return S_OK;
    154 }
    155