• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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