1 // Copyright 2015 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 "components/cronet/cronet_upload_data_stream.h"
6
7 #include "net/base/io_buffer.h"
8 #include "net/base/net_errors.h"
9
10 namespace cronet {
11
CronetUploadDataStream(Delegate * delegate,int64_t size)12 CronetUploadDataStream::CronetUploadDataStream(Delegate* delegate, int64_t size)
13 : UploadDataStream(size < 0, 0),
14 size_(size),
15 waiting_on_read_(false),
16 read_in_progress_(false),
17 waiting_on_rewind_(false),
18 rewind_in_progress_(false),
19 at_front_of_stream_(true),
20 delegate_(delegate) {}
21
~CronetUploadDataStream()22 CronetUploadDataStream::~CronetUploadDataStream() {
23 delegate_->OnUploadDataStreamDestroyed();
24 }
25
InitInternal(const net::NetLogWithSource & net_log)26 int CronetUploadDataStream::InitInternal(const net::NetLogWithSource& net_log) {
27 // ResetInternal should have been called before init, if the stream was in
28 // use.
29 DCHECK(!waiting_on_read_);
30 DCHECK(!waiting_on_rewind_);
31
32 if (!weak_factory_.HasWeakPtrs())
33 delegate_->InitializeOnNetworkThread(weak_factory_.GetWeakPtr());
34
35 // Set size of non-chunked uploads.
36 if (size_ >= 0)
37 SetSize(static_cast<uint64_t>(size_));
38
39 // If already at the front of the stream, nothing to do.
40 if (at_front_of_stream_) {
41 // Being at the front of the stream implies there's no read or rewind in
42 // progress.
43 DCHECK(!read_in_progress_);
44 DCHECK(!rewind_in_progress_);
45 return net::OK;
46 }
47
48 // Otherwise, the request is now waiting for the stream to be rewound.
49 waiting_on_rewind_ = true;
50
51 // Start rewinding the stream if no operation is in progress.
52 if (!read_in_progress_ && !rewind_in_progress_)
53 StartRewind();
54 return net::ERR_IO_PENDING;
55 }
56
ReadInternal(net::IOBuffer * buf,int buf_len)57 int CronetUploadDataStream::ReadInternal(net::IOBuffer* buf, int buf_len) {
58 // All pending operations should have completed before a read can start.
59 DCHECK(!waiting_on_read_);
60 DCHECK(!read_in_progress_);
61 DCHECK(!waiting_on_rewind_);
62 DCHECK(!rewind_in_progress_);
63
64 DCHECK(buf);
65 DCHECK_GT(buf_len, 0);
66
67 read_in_progress_ = true;
68 waiting_on_read_ = true;
69 at_front_of_stream_ = false;
70 scoped_refptr<net::IOBuffer> buffer(base::WrapRefCounted(buf));
71 delegate_->Read(std::move(buffer), buf_len);
72 return net::ERR_IO_PENDING;
73 }
74
ResetInternal()75 void CronetUploadDataStream::ResetInternal() {
76 // Consumer is not waiting on any operation. Note that the active operation,
77 // if any, will continue.
78 waiting_on_read_ = false;
79 waiting_on_rewind_ = false;
80 }
81
OnReadSuccess(int bytes_read,bool final_chunk)82 void CronetUploadDataStream::OnReadSuccess(int bytes_read, bool final_chunk) {
83 DCHECK(read_in_progress_);
84 DCHECK(!rewind_in_progress_);
85 DCHECK(bytes_read > 0 || (final_chunk && bytes_read == 0));
86 if (!is_chunked()) {
87 DCHECK(!final_chunk);
88 }
89
90 read_in_progress_ = false;
91
92 if (waiting_on_rewind_) {
93 DCHECK(!waiting_on_read_);
94 // Since a read just completed, can't be at the front of the stream.
95 StartRewind();
96 return;
97 }
98 // ResetInternal has been called, but still waiting on InitInternal.
99 if (!waiting_on_read_)
100 return;
101
102 waiting_on_read_ = false;
103 if (final_chunk)
104 SetIsFinalChunk();
105 OnReadCompleted(bytes_read);
106 }
107
OnRewindSuccess()108 void CronetUploadDataStream::OnRewindSuccess() {
109 DCHECK(!waiting_on_read_);
110 DCHECK(!read_in_progress_);
111 DCHECK(rewind_in_progress_);
112 DCHECK(!at_front_of_stream_);
113
114 rewind_in_progress_ = false;
115 at_front_of_stream_ = true;
116
117 // Possible that ResetInternal was called since the rewind was started, but
118 // InitInternal has not been.
119 if (!waiting_on_rewind_)
120 return;
121
122 waiting_on_rewind_ = false;
123 OnInitCompleted(net::OK);
124 }
125
StartRewind()126 void CronetUploadDataStream::StartRewind() {
127 DCHECK(!waiting_on_read_);
128 DCHECK(!read_in_progress_);
129 DCHECK(waiting_on_rewind_);
130 DCHECK(!rewind_in_progress_);
131 DCHECK(!at_front_of_stream_);
132
133 rewind_in_progress_ = true;
134 delegate_->Rewind();
135 }
136
137 } // namespace cronet
138