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