urlmon_upload_data_stream.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome_frame/urlmon_upload_data_stream.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/upload_bytes_element_reader.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/upload_file_element_reader.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Creates UploadDataStream from UploadData.
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)net::UploadDataStream* CreateUploadDataStream(net::UploadData* upload_data) {
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::UploadDataStream* upload_data_stream = NULL;
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const ScopedVector<net::UploadElement>& elements = upload_data->elements();
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (upload_data->is_chunked()) {
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Use AppendChunk when data is chunked.
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    upload_data_stream = new net::UploadDataStream(
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        net::UploadDataStream::CHUNKED, upload_data->identifier());
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < elements.size(); ++i) {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const net::UploadElement& element = *elements[i];
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const bool is_last_chunk =
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          i == elements.size() - 1 && upload_data->last_chunk_appended();
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK_EQ(net::UploadElement::TYPE_BYTES, element.type());
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      upload_data_stream->AppendChunk(element.bytes(), element.bytes_length(),
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      is_last_chunk);
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Not chunked.
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ScopedVector<net::UploadElementReader> element_readers;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < elements.size(); ++i) {
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const net::UploadElement& element = *elements[i];
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      net::UploadElementReader* reader = NULL;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      switch (element.type()) {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        case net::UploadElement::TYPE_BYTES:
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          reader = new net::UploadBytesElementReader(element.bytes(),
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                     element.bytes_length());
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        case net::UploadElement::TYPE_FILE:
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          reader = new net::UploadFileElementReaderSync(
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              element.file_path(),
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              element.file_range_offset(),
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              element.file_range_length(),
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              element.expected_file_modification_time());
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK(reader);
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      element_readers.push_back(reader);
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    upload_data_stream = new net::UploadDataStream(&element_readers,
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                   upload_data->identifier());
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return upload_data_stream;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UrlmonUploadDataStream::Initialize(net::UploadData* upload_data) {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  upload_data_ = upload_data;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request_body_stream_.reset(CreateUploadDataStream(upload_data));
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int result = request_body_stream_->Init(net::CompletionCallback());
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(net::OK, result);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STDMETHODIMP UrlmonUploadDataStream::Read(void* pv, ULONG cb, ULONG* read) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pv == NULL) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_POINTER;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Have we already read past the end of the stream?
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request_body_stream_->IsEOF()) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (read) {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *read = 0;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_FALSE;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The data in request_body_stream_ can be smaller than 'cb' so it's not
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // guaranteed that we'll be able to read total_bytes_to_copy bytes.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint64 total_bytes_to_copy = cb;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint64 bytes_copied = 0;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* write_pointer = reinterpret_cast<char*>(pv);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (bytes_copied < total_bytes_to_copy) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t bytes_to_copy_now = total_bytes_to_copy - bytes_copied;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<net::IOBufferWithSize> buf(
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new net::IOBufferWithSize(bytes_to_copy_now));
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int bytes_read = request_body_stream_->Read(buf, buf->size(),
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                net::CompletionCallback());
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_NE(net::ERR_IO_PENDING, bytes_read);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bytes_read == 0)  // Reached the end of the stream.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(write_pointer, buf->data(), bytes_read);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Advance our copy tally
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bytes_copied += bytes_read;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Advance our write pointer
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    write_pointer += bytes_read;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(bytes_copied, total_bytes_to_copy);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (read) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *read = static_cast<ULONG>(bytes_copied);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STDMETHODIMP UrlmonUploadDataStream::Seek(LARGE_INTEGER move, DWORD origin,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          ULARGE_INTEGER* new_pos) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // UploadDataStream is really not very seek-able, so for now allow
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // STREAM_SEEK_SETs to work with a 0 offset, but fail on everything else.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (origin == STREAM_SEEK_SET && move.QuadPart == 0) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (request_body_stream_->position() != 0) {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      request_body_stream_.reset(CreateUploadDataStream(upload_data_));
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const int result = request_body_stream_->Init(net::CompletionCallback());
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(net::OK, result);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (new_pos) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_pos->QuadPart = 0;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_OK;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(false) << __FUNCTION__;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return STG_E_INVALIDFUNCTION;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STDMETHODIMP UrlmonUploadDataStream::Stat(STATSTG *stat_stg,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          DWORD grf_stat_flag) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stat_stg == NULL)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_POINTER;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(stat_stg, 0, sizeof(STATSTG));
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 == (grf_stat_flag & STATFLAG_NONAME)) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t kStreamBuffer[] = L"PostStream";
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stat_stg->pwcsName =
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_cast<wchar_t*>(::CoTaskMemAlloc(sizeof(kStreamBuffer)));
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    lstrcpy(stat_stg->pwcsName, kStreamBuffer);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stat_stg->type = STGTY_STREAM;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stat_stg->cbSize.QuadPart = request_body_stream_->size();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
155