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 "net/base/elements_upload_data_stream.h"
8 #include "base/logging.h"
9 #include "net/base/completion_callback.h"
10 #include "net/base/io_buffer.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/upload_bytes_element_reader.h"
13 #include "net/base/upload_element_reader.h"
17 ElementsUploadDataStream::ElementsUploadDataStream(
18 ScopedVector
<UploadElementReader
> element_readers
,
20 : UploadDataStream(false, identifier
),
21 element_readers_(element_readers
.Pass()),
24 weak_ptr_factory_(this) {
27 ElementsUploadDataStream::~ElementsUploadDataStream() {
30 scoped_ptr
<UploadDataStream
> ElementsUploadDataStream::CreateWithReader(
31 scoped_ptr
<UploadElementReader
> reader
,
33 ScopedVector
<UploadElementReader
> readers
;
34 readers
.push_back(reader
.Pass());
35 return scoped_ptr
<UploadDataStream
>(
36 new ElementsUploadDataStream(readers
.Pass(), identifier
));
39 int ElementsUploadDataStream::InitInternal() {
40 return InitElements(0);
43 int ElementsUploadDataStream::ReadInternal(
46 DCHECK_GT(buf_len
, 0);
47 return ReadElements(new DrainableIOBuffer(buf
, buf_len
));
50 bool ElementsUploadDataStream::IsInMemory() const {
51 for (size_t i
= 0; i
< element_readers_
.size(); ++i
) {
52 if (!element_readers_
[i
]->IsInMemory())
58 const ScopedVector
<UploadElementReader
>*
59 ElementsUploadDataStream::GetElementReaders() const {
60 return &element_readers_
;
63 void ElementsUploadDataStream::ResetInternal() {
64 weak_ptr_factory_
.InvalidateWeakPtrs();
69 int ElementsUploadDataStream::InitElements(size_t start_index
) {
70 // Call Init() for all elements.
71 for (size_t i
= start_index
; i
< element_readers_
.size(); ++i
) {
72 UploadElementReader
* reader
= element_readers_
[i
];
73 // When new_result is ERR_IO_PENDING, InitInternal() will be called
74 // with start_index == i + 1 when reader->Init() finishes.
75 int result
= reader
->Init(
76 base::Bind(&ElementsUploadDataStream::OnInitElementCompleted
,
77 weak_ptr_factory_
.GetWeakPtr(),
79 DCHECK(result
!= ERR_IO_PENDING
|| !reader
->IsInMemory());
80 DCHECK_LE(result
, OK
);
85 uint64_t total_size
= 0;
86 for (size_t i
= 0; i
< element_readers_
.size(); ++i
) {
87 total_size
+= element_readers_
[i
]->GetContentLength();
93 void ElementsUploadDataStream::OnInitElementCompleted(size_t index
,
95 DCHECK_NE(ERR_IO_PENDING
, result
);
97 // Check the last result.
99 result
= InitElements(index
+ 1);
101 if (result
!= ERR_IO_PENDING
)
102 OnInitCompleted(result
);
105 int ElementsUploadDataStream::ReadElements(
106 const scoped_refptr
<DrainableIOBuffer
>& buf
) {
107 while (!read_failed_
&& element_index_
< element_readers_
.size()) {
108 UploadElementReader
* reader
= element_readers_
[element_index_
];
110 if (reader
->BytesRemaining() == 0) {
115 if (buf
->BytesRemaining() == 0)
118 int result
= reader
->Read(
120 buf
->BytesRemaining(),
121 base::Bind(&ElementsUploadDataStream::OnReadElementCompleted
,
122 weak_ptr_factory_
.GetWeakPtr(),
124 if (result
== ERR_IO_PENDING
)
125 return ERR_IO_PENDING
;
126 ProcessReadResult(buf
, result
);
130 // If an error occured during read operation, then pad with zero.
131 // Otherwise the server will hang waiting for the rest of the data.
132 int num_bytes_to_fill
=
133 static_cast<int>(std::min(static_cast<uint64_t>(buf
->BytesRemaining()),
134 size() - position() - buf
->BytesConsumed()));
135 DCHECK_GE(num_bytes_to_fill
, 0);
136 memset(buf
->data(), 0, num_bytes_to_fill
);
137 buf
->DidConsume(num_bytes_to_fill
);
140 return buf
->BytesConsumed();
143 void ElementsUploadDataStream::OnReadElementCompleted(
144 const scoped_refptr
<DrainableIOBuffer
>& buf
,
146 ProcessReadResult(buf
, result
);
148 result
= ReadElements(buf
);
149 if (result
!= ERR_IO_PENDING
)
150 OnReadCompleted(result
);
153 void ElementsUploadDataStream::ProcessReadResult(
154 const scoped_refptr
<DrainableIOBuffer
>& buf
,
156 DCHECK_NE(ERR_IO_PENDING
, result
);
157 DCHECK(!read_failed_
);
160 buf
->DidConsume(result
);