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.
5 #include "chrome_frame/urlmon_upload_data_stream.h"
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"
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();
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());
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(),
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());
43 case net::UploadElement::TYPE_FILE
:
44 reader
= new net::UploadFileElementReaderSync(
46 element
.file_range_offset(),
47 element
.file_range_length(),
48 element
.expected_file_modification_time());
52 element_readers
.push_back(reader
);
54 upload_data_stream
= new net::UploadDataStream(element_readers
.Pass(),
55 upload_data
->identifier());
57 return upload_data_stream
;
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
);
69 STDMETHODIMP
UrlmonUploadDataStream::Read(void* pv
, ULONG cb
, ULONG
* read
) {
75 // Have we already read past the end of the stream?
76 if (request_body_stream_
->IsEOF()) {
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
;
87 uint64 bytes_copied
= 0;
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
;
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.
101 memcpy(write_pointer
, buf
->data(), bytes_read
);
103 // Advance our copy tally
104 bytes_copied
+= bytes_read
;
106 // Advance our write pointer
107 write_pointer
+= bytes_read
;
110 DCHECK_LE(bytes_copied
, total_bytes_to_copy
);
113 *read
= static_cast<ULONG
>(bytes_copied
);
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
);
130 new_pos
->QuadPart
= 0;
135 DCHECK(false) << __FUNCTION__
;
136 return STG_E_INVALIDFUNCTION
;
139 STDMETHODIMP
UrlmonUploadDataStream::Stat(STATSTG
*stat_stg
,
140 DWORD grf_stat_flag
) {
141 if (stat_stg
== NULL
)
144 memset(stat_stg
, 0, sizeof(STATSTG
));
145 if (0 == (grf_stat_flag
& STATFLAG_NONAME
)) {
146 const wchar_t kStreamBuffer
[] = L
"PostStream";
148 static_cast<wchar_t*>(::CoTaskMemAlloc(sizeof(kStreamBuffer
)));
149 lstrcpy(stat_stg
->pwcsName
, kStreamBuffer
);
151 stat_stg
->type
= STGTY_STREAM
;
152 stat_stg
->cbSize
.QuadPart
= request_body_stream_
->size();