Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: net/quic/bidirectional_stream_quic_impl.cc

Issue 1744693002: Implement QUIC-based net::BidirectionalStream (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@basecl
Patch Set: Address comments and fixed tests Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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/quic/bidirectional_stream_quic_impl.h"
6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/timer/timer.h"
11 #include "net/http/bidirectional_stream_request_info.h"
12 #include "net/socket/next_proto.h"
13 #include "net/spdy/spdy_header_block.h"
14 #include "net/spdy/spdy_http_utils.h"
15
16 namespace net {
17
18 BidirectionalStreamQuicImpl::BidirectionalStreamQuicImpl(
19 const base::WeakPtr<QuicChromiumClientSession>& session)
20 : session_(session),
21 was_handshake_confirmed_(session->IsCryptoHandshakeConfirmed()),
22 stream_(nullptr),
23 request_info_(nullptr),
24 delegate_(nullptr),
25 response_status_(OK),
26 negotiated_protocol_(kProtoUnknown),
27 read_buffer_len_(0),
28 headers_bytes_received_(0),
29 headers_bytes_sent_(0),
30 closed_stream_received_bytes_(0),
31 closed_stream_sent_bytes_(0),
32 has_sent_headers_(false),
33 has_received_headers_(false),
34 weak_factory_(this) {
35 DCHECK(session_);
36 session_->AddObserver(this);
37 }
38
39 BidirectionalStreamQuicImpl::~BidirectionalStreamQuicImpl() {
40 Cancel();
41 if (session_)
42 session_->RemoveObserver(this);
43 }
44
45 void BidirectionalStreamQuicImpl::Start(
46 const BidirectionalStreamRequestInfo* request_info,
47 const BoundNetLog& net_log,
48 BidirectionalStreamJob::Delegate* delegate,
49 scoped_ptr<base::Timer> /* timer */) {
50 DCHECK(!stream_);
51
52 if (!session_) {
53 NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR
54 : ERR_QUIC_HANDSHAKE_FAILED);
55 return;
56 }
57
58 delegate_ = delegate;
59 request_info_ = request_info;
60
61 int rv = stream_request_.StartRequest(
62 session_, &stream_,
63 base::Bind(&BidirectionalStreamQuicImpl::OnStreamReady,
64 weak_factory_.GetWeakPtr()));
65 if (rv == OK) {
66 OnStreamReady(rv);
67 } else if (!was_handshake_confirmed_) {
68 NotifyError(ERR_QUIC_HANDSHAKE_FAILED);
69 }
70 }
71
72 int BidirectionalStreamQuicImpl::ReadData(IOBuffer* buf, int buf_len) {
mef 2016/03/09 17:20:37 nit: maybe rename buf -> buffer, buf_len -> buffer
xunjieli 2016/03/09 21:34:53 Done.
73 DCHECK(buf);
74 DCHECK(buf_len);
75
76 if (!stream_) {
77 // If the stream is already closed, there is no body to read.
78 return response_status_;
79 }
80 int rv = stream_->Read(buf, buf_len);
81 if (rv != ERR_IO_PENDING) {
82 if (stream_->IsDoneReading()) {
83 stream_->OnFinRead(); // If write side is close, will call OnClose.
mef 2016/03/09 17:20:37 nit: could you rephrase "If write side is close"?
xunjieli 2016/03/09 21:34:53 Done. Rephrased but didn't get rid of the braces,
84 }
85 return rv;
86 }
87 // Read will complete asynchronously and Delegate::OnReadCompleted will be
88 // called upon completion.
89 read_buffer_ = buf;
90 read_buffer_len_ = buf_len;
91 return ERR_IO_PENDING;
92 }
93
94 void BidirectionalStreamQuicImpl::SendData(IOBuffer* data,
95 int length,
96 bool end_stream) {
97 DCHECK(stream_);
mef 2016/03/09 17:20:37 what if stream is closed? I'd say that we need som
xunjieli 2016/03/09 21:34:53 BidirectionalStreamSpdyJob also does a DCHECK. We
98
99 if (length > 0 || end_stream) {
mef 2016/03/09 17:20:37 what happens if length < 0 and end_stream is set?
xunjieli 2016/03/09 21:34:53 Good catch. I think this should be a DCHECK and no
100 base::StringPiece string_data(data->data(), length);
101 int rv = stream_->WriteStreamData(
102 string_data, end_stream,
103 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
104 weak_factory_.GetWeakPtr()));
105 DCHECK(rv == OK || rv == ERR_IO_PENDING);
mef 2016/03/09 17:20:37 could WriteStreamData return an error?
xunjieli 2016/03/09 21:34:53 Currently it only returns OK or ERR_IO_PENDING. ht
106 if (rv == OK) {
107 base::ThreadTaskRunnerHandle::Get()->PostTask(
108 FROM_HERE,
109 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
110 weak_factory_.GetWeakPtr(), OK));
111 }
112 }
113 }
114
115 void BidirectionalStreamQuicImpl::Cancel() {
116 if (stream_) {
117 stream_->SetDelegate(nullptr);
118 stream_->Reset(QUIC_STREAM_CANCELLED);
119 ResetStream();
120 }
121 }
122
123 NextProto BidirectionalStreamQuicImpl::GetProtocol() const {
124 return negotiated_protocol_;
125 }
126
127 int64_t BidirectionalStreamQuicImpl::GetTotalReceivedBytes() const {
128 if (stream_)
129 return headers_bytes_received_ + stream_->stream_bytes_read();
130 return headers_bytes_received_ + closed_stream_received_bytes_;
131 }
132
133 int64_t BidirectionalStreamQuicImpl::GetTotalSentBytes() const {
134 if (stream_)
135 return headers_bytes_sent_ + stream_->stream_bytes_written();
136 return headers_bytes_sent_ + closed_stream_sent_bytes_;
137 }
138
139 void BidirectionalStreamQuicImpl::OnHeadersAvailable(
140 const SpdyHeaderBlock& headers,
141 size_t frame_len) {
142 headers_bytes_received_ += frame_len;
143 negotiated_protocol_ = kProtoQUIC1SPDY3;
144 if (!has_received_headers_) {
145 has_received_headers_ = true;
146 delegate_->OnHeadersReceived(headers);
147 } else {
148 delegate_->OnTrailersReceived(headers);
149 }
150 }
151
152 void BidirectionalStreamQuicImpl::OnDataAvailable() {
153 // Return early if ReadData has not been called.
154 if (!read_buffer_)
155 return;
156
157 CHECK(read_buffer_);
158 CHECK_NE(0, read_buffer_len_);
159 int rv = ReadData(read_buffer_.get(), read_buffer_len_);
160 if (rv == ERR_IO_PENDING) {
161 // Spurrious notification. Wait for the next one.
162 return;
163 }
164 read_buffer_ = nullptr;
165 read_buffer_len_ = 0;
166 delegate_->OnDataRead(rv);
167 }
168
169 void BidirectionalStreamQuicImpl::OnClose(QuicErrorCode error) {
170 DCHECK(stream_);
171 if (error == QUIC_NO_ERROR &&
172 stream_->stream_error() == QUIC_STREAM_NO_ERROR) {
173 ResetStream();
174 return;
175 }
176 ResetStream();
177 NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR
178 : ERR_QUIC_HANDSHAKE_FAILED);
179 }
180
181 void BidirectionalStreamQuicImpl::OnError(int error) {
182 NotifyError(error);
183 }
184
185 bool BidirectionalStreamQuicImpl::HasSendHeadersComplete() {
186 return has_sent_headers_;
187 }
188
189 void BidirectionalStreamQuicImpl::OnCryptoHandshakeConfirmed() {
190 was_handshake_confirmed_ = true;
191 }
192
193 void BidirectionalStreamQuicImpl::OnSessionClosed(int error) {
194 DCHECK_NE(OK, error);
195 session_.reset();
196 NotifyError(error);
197 }
198
199 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) {
200 DCHECK_NE(ERR_IO_PENDING, rv);
201 DCHECK(rv == OK || !stream_);
202 if (rv == OK) {
203 stream_->SetDelegate(this);
204 SendRequestHeaders();
205 } else {
206 NotifyError(rv);
207 }
208 }
209
210 void BidirectionalStreamQuicImpl::OnSendDataComplete(int rv) {
211 DCHECK(rv == OK || !stream_);
212 if (rv == OK) {
213 delegate_->OnDataSent();
214 } else {
215 NotifyError(rv);
216 }
217 }
218
219 void BidirectionalStreamQuicImpl::SendRequestHeaders() {
220 DCHECK(!has_sent_headers_);
221 DCHECK(stream_);
222
223 SpdyHeaderBlock headers;
224 HttpRequestInfo http_request_info;
225 http_request_info.url = request_info_->url;
226 http_request_info.method = request_info_->method;
227 http_request_info.extra_headers = request_info_->extra_headers;
228
229 CreateSpdyHeadersFromHttpRequest(http_request_info,
230 http_request_info.extra_headers, HTTP2, true,
231 &headers);
232 size_t frame_len = stream_->WriteHeaders(
233 headers, request_info_->end_stream_on_headers, nullptr);
234 headers_bytes_sent_ += frame_len;
235 has_sent_headers_ = true;
236 delegate_->OnHeadersSent();
237 }
238
239 void BidirectionalStreamQuicImpl::NotifyError(int error) {
240 DCHECK_NE(OK, error);
241 DCHECK_NE(ERR_IO_PENDING, error);
242
243 response_status_ = error;
244 ResetStream();
245 delegate_->OnFailed(error);
246 }
247
248 void BidirectionalStreamQuicImpl::ResetStream() {
249 if (!stream_)
250 return;
251 closed_stream_received_bytes_ = stream_->stream_bytes_read();
252 closed_stream_sent_bytes_ = stream_->stream_bytes_written();
253 stream_->SetDelegate(nullptr);
254 stream_ = nullptr;
255 }
256
257 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698