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 "net/base/upload_data_stream.h"
6 
7 #include "base/check_op.h"
8 #include "base/values.h"
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
11 #include "net/log/net_log_event_type.h"
12 
13 namespace net {
14 
15 namespace {
16 
NetLogInitEndInfoParams(int result,int total_size,bool is_chunked)17 base::Value NetLogInitEndInfoParams(int result,
18                                     int total_size,
19                                     bool is_chunked) {
20   base::Value dict(base::Value::Type::DICTIONARY);
21 
22   dict.SetIntKey("net_error", result);
23   dict.SetIntKey("total_size", total_size);
24   dict.SetBoolKey("is_chunked", is_chunked);
25   return dict;
26 }
27 
CreateReadInfoParams(int current_position)28 base::Value CreateReadInfoParams(int current_position) {
29   base::Value dict(base::Value::Type::DICTIONARY);
30 
31   dict.SetIntKey("current_position", current_position);
32   return dict;
33 }
34 
35 }  // namespace
36 
UploadDataStream(bool is_chunked,int64_t identifier)37 UploadDataStream::UploadDataStream(bool is_chunked, int64_t identifier)
38     : total_size_(0),
39       current_position_(0),
40       identifier_(identifier),
41       is_chunked_(is_chunked),
42       initialized_successfully_(false),
43       is_eof_(false) {
44 }
45 
46 UploadDataStream::~UploadDataStream() = default;
47 
Init(CompletionOnceCallback callback,const NetLogWithSource & net_log)48 int UploadDataStream::Init(CompletionOnceCallback callback,
49                            const NetLogWithSource& net_log) {
50   Reset();
51   DCHECK(!initialized_successfully_);
52   DCHECK(callback_.is_null());
53   DCHECK(!callback.is_null() || IsInMemory());
54   net_log_ = net_log;
55   net_log_.BeginEvent(NetLogEventType::UPLOAD_DATA_STREAM_INIT);
56 
57   int result = InitInternal(net_log_);
58   if (result == ERR_IO_PENDING) {
59     DCHECK(!IsInMemory());
60     callback_ = std::move(callback);
61   } else {
62     OnInitCompleted(result);
63   }
64 
65   return result;
66 }
67 
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)68 int UploadDataStream::Read(IOBuffer* buf,
69                            int buf_len,
70                            CompletionOnceCallback callback) {
71   DCHECK(!callback.is_null() || IsInMemory());
72   DCHECK(initialized_successfully_);
73   DCHECK_GT(buf_len, 0);
74 
75   net_log_.BeginEvent(NetLogEventType::UPLOAD_DATA_STREAM_READ,
76                       [&] { return CreateReadInfoParams(current_position_); });
77 
78   int result = 0;
79   if (!is_eof_)
80     result = ReadInternal(buf, buf_len);
81 
82   if (result == ERR_IO_PENDING) {
83     DCHECK(!IsInMemory());
84     callback_ = std::move(callback);
85   } else {
86     OnReadCompleted(result);
87   }
88 
89   return result;
90 }
91 
IsEOF() const92 bool UploadDataStream::IsEOF() const {
93   DCHECK(initialized_successfully_);
94   DCHECK(is_chunked_ || is_eof_ == (current_position_ == total_size_));
95   return is_eof_;
96 }
97 
Reset()98 void UploadDataStream::Reset() {
99   // If there's a pending callback, there's a pending init or read call that is
100   // being canceled.
101   if (!callback_.is_null()) {
102     if (!initialized_successfully_) {
103       // If initialization has not yet succeeded, this call is aborting
104       // initialization.
105       net_log_.EndEventWithNetErrorCode(
106           NetLogEventType::UPLOAD_DATA_STREAM_INIT, ERR_ABORTED);
107     } else {
108       // Otherwise, a read is being aborted.
109       net_log_.EndEventWithNetErrorCode(
110           NetLogEventType::UPLOAD_DATA_STREAM_READ, ERR_ABORTED);
111     }
112   }
113 
114   current_position_ = 0;
115   initialized_successfully_ = false;
116   is_eof_ = false;
117   total_size_ = 0;
118   callback_.Reset();
119   ResetInternal();
120 }
121 
SetSize(uint64_t size)122 void UploadDataStream::SetSize(uint64_t size) {
123   DCHECK(!initialized_successfully_);
124   DCHECK(!is_chunked_);
125   total_size_ = size;
126 }
127 
SetIsFinalChunk()128 void UploadDataStream::SetIsFinalChunk() {
129   DCHECK(initialized_successfully_);
130   DCHECK(is_chunked_);
131   DCHECK(!is_eof_);
132   is_eof_ = true;
133 }
134 
IsInMemory() const135 bool UploadDataStream::IsInMemory() const {
136   return false;
137 }
138 
139 const std::vector<std::unique_ptr<UploadElementReader>>*
GetElementReaders() const140 UploadDataStream::GetElementReaders() const {
141   return nullptr;
142 }
143 
OnInitCompleted(int result)144 void UploadDataStream::OnInitCompleted(int result) {
145   DCHECK_NE(ERR_IO_PENDING, result);
146   DCHECK(!initialized_successfully_);
147   DCHECK_EQ(0u, current_position_);
148   DCHECK(!is_eof_);
149 
150   if (result == OK) {
151     initialized_successfully_ = true;
152     if (!is_chunked_ && total_size_ == 0)
153       is_eof_ = true;
154   }
155 
156   net_log_.EndEvent(NetLogEventType::UPLOAD_DATA_STREAM_INIT, [&] {
157     return NetLogInitEndInfoParams(result, total_size_, is_chunked_);
158   });
159 
160   if (!callback_.is_null())
161     std::move(callback_).Run(result);
162 }
163 
OnReadCompleted(int result)164 void UploadDataStream::OnReadCompleted(int result) {
165   DCHECK(initialized_successfully_);
166   DCHECK(result != 0 || is_eof_);
167   DCHECK_NE(ERR_IO_PENDING, result);
168 
169   if (result > 0) {
170     current_position_ += result;
171     if (!is_chunked_) {
172       DCHECK_LE(current_position_, total_size_);
173       if (current_position_ == total_size_)
174         is_eof_ = true;
175     }
176   }
177 
178   net_log_.EndEventWithNetErrorCode(NetLogEventType::UPLOAD_DATA_STREAM_READ,
179                                     result);
180 
181   if (!callback_.is_null())
182     std::move(callback_).Run(result);
183 }
184 
GetUploadProgress() const185 UploadProgress UploadDataStream::GetUploadProgress() const {
186   // While initialization / rewinding is in progress, return nothing.
187   if (!initialized_successfully_)
188     return UploadProgress();
189 
190   return UploadProgress(current_position_, total_size_);
191 }
192 
AllowHTTP1() const193 bool UploadDataStream::AllowHTTP1() const {
194   return true;
195 }
196 
197 }  // namespace net
198