1 // Copyright 2012 The Chromium Authors
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 "net/base/elements_upload_data_stream.h"
6
7 #include <utility>
8
9 #include "base/check_op.h"
10 #include "base/functional/bind.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/net_errors.h"
13 #include "net/base/upload_bytes_element_reader.h"
14 #include "net/base/upload_element_reader.h"
15
16 namespace net {
17
ElementsUploadDataStream(std::vector<std::unique_ptr<UploadElementReader>> element_readers,int64_t identifier)18 ElementsUploadDataStream::ElementsUploadDataStream(
19 std::vector<std::unique_ptr<UploadElementReader>> element_readers,
20 int64_t identifier)
21 : UploadDataStream(false, identifier),
22 element_readers_(std::move(element_readers)) {}
23
24 ElementsUploadDataStream::~ElementsUploadDataStream() = default;
25
CreateWithReader(std::unique_ptr<UploadElementReader> reader)26 std::unique_ptr<UploadDataStream> ElementsUploadDataStream::CreateWithReader(
27 std::unique_ptr<UploadElementReader> reader) {
28 std::vector<std::unique_ptr<UploadElementReader>> readers;
29 readers.push_back(std::move(reader));
30 return std::make_unique<ElementsUploadDataStream>(std::move(readers),
31 /*identifier=*/0);
32 }
33
InitInternal(const NetLogWithSource & net_log)34 int ElementsUploadDataStream::InitInternal(const NetLogWithSource& net_log) {
35 return InitElements(0);
36 }
37
ReadInternal(IOBuffer * buf,int buf_len)38 int ElementsUploadDataStream::ReadInternal(
39 IOBuffer* buf,
40 int buf_len) {
41 DCHECK_GT(buf_len, 0);
42 return ReadElements(base::MakeRefCounted<DrainableIOBuffer>(buf, buf_len));
43 }
44
IsInMemory() const45 bool ElementsUploadDataStream::IsInMemory() const {
46 for (const std::unique_ptr<UploadElementReader>& it : element_readers_) {
47 if (!it->IsInMemory())
48 return false;
49 }
50 return true;
51 }
52
53 const std::vector<std::unique_ptr<UploadElementReader>>*
GetElementReaders() const54 ElementsUploadDataStream::GetElementReaders() const {
55 return &element_readers_;
56 }
57
ResetInternal()58 void ElementsUploadDataStream::ResetInternal() {
59 weak_ptr_factory_.InvalidateWeakPtrs();
60 read_error_ = OK;
61 element_index_ = 0;
62 }
63
InitElements(size_t start_index)64 int ElementsUploadDataStream::InitElements(size_t start_index) {
65 // Call Init() for all elements.
66 for (size_t i = start_index; i < element_readers_.size(); ++i) {
67 UploadElementReader* reader = element_readers_[i].get();
68 // When new_result is ERR_IO_PENDING, InitInternal() will be called
69 // with start_index == i + 1 when reader->Init() finishes.
70 int result = reader->Init(
71 base::BindOnce(&ElementsUploadDataStream::OnInitElementCompleted,
72 weak_ptr_factory_.GetWeakPtr(), i));
73 DCHECK(result != ERR_IO_PENDING || !reader->IsInMemory());
74 DCHECK_LE(result, OK);
75 if (result != OK)
76 return result;
77 }
78
79 uint64_t total_size = 0;
80 for (const std::unique_ptr<UploadElementReader>& it : element_readers_) {
81 total_size += it->GetContentLength();
82 }
83 SetSize(total_size);
84 return OK;
85 }
86
OnInitElementCompleted(size_t index,int result)87 void ElementsUploadDataStream::OnInitElementCompleted(size_t index,
88 int result) {
89 DCHECK_NE(ERR_IO_PENDING, result);
90
91 // Check the last result.
92 if (result == OK)
93 result = InitElements(index + 1);
94
95 if (result != ERR_IO_PENDING)
96 OnInitCompleted(result);
97 }
98
ReadElements(const scoped_refptr<DrainableIOBuffer> & buf)99 int ElementsUploadDataStream::ReadElements(
100 const scoped_refptr<DrainableIOBuffer>& buf) {
101 while (read_error_ == OK && element_index_ < element_readers_.size()) {
102 UploadElementReader* reader = element_readers_[element_index_].get();
103
104 if (reader->BytesRemaining() == 0) {
105 ++element_index_;
106 continue;
107 }
108
109 if (buf->BytesRemaining() == 0)
110 break;
111
112 int result = reader->Read(
113 buf.get(), buf->BytesRemaining(),
114 base::BindOnce(&ElementsUploadDataStream::OnReadElementCompleted,
115 weak_ptr_factory_.GetWeakPtr(), buf));
116 if (result == ERR_IO_PENDING)
117 return ERR_IO_PENDING;
118 ProcessReadResult(buf, result);
119 }
120
121 if (buf->BytesConsumed() > 0)
122 return buf->BytesConsumed();
123
124 return read_error_;
125 }
126
OnReadElementCompleted(const scoped_refptr<DrainableIOBuffer> & buf,int result)127 void ElementsUploadDataStream::OnReadElementCompleted(
128 const scoped_refptr<DrainableIOBuffer>& buf,
129 int result) {
130 ProcessReadResult(buf, result);
131
132 result = ReadElements(buf);
133 if (result != ERR_IO_PENDING) {
134 if (result < ERR_IO_PENDING) {
135 LOG(ERROR) << "OnReadElementCompleted failed with Error: " << result;
136 }
137 OnReadCompleted(result);
138 }
139 }
140
ProcessReadResult(const scoped_refptr<DrainableIOBuffer> & buf,int result)141 void ElementsUploadDataStream::ProcessReadResult(
142 const scoped_refptr<DrainableIOBuffer>& buf,
143 int result) {
144 DCHECK_NE(ERR_IO_PENDING, result);
145 DCHECK(!read_error_);
146
147 if (result >= 0) {
148 buf->DidConsume(result);
149 } else {
150 read_error_ = result;
151 }
152 }
153
154 } // namespace net
155