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

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

Issue 2193073003: Move shared files in net/quic/ into net/quic/core/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: io_thread_unittest.cc Created 4 years, 4 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
« no previous file with comments | « net/quic/quic_spdy_stream.h ('k') | net/quic/quic_spdy_stream_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 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/quic_spdy_stream.h"
6
7 #include <utility>
8
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "net/quic/quic_bug_tracker.h"
12 #include "net/quic/quic_spdy_session.h"
13 #include "net/quic/quic_utils.h"
14 #include "net/quic/quic_write_blocked_list.h"
15 #include "net/quic/spdy_utils.h"
16
17 using base::IntToString;
18 using base::StringPiece;
19 using std::min;
20 using std::string;
21
22 namespace net {
23
24 #define ENDPOINT \
25 (session()->perspective() == Perspective::IS_SERVER ? "Server: " : "Client:" \
26 " ")
27
28 QuicSpdyStream::QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session)
29 : ReliableQuicStream(id, spdy_session),
30 spdy_session_(spdy_session),
31 visitor_(nullptr),
32 headers_decompressed_(false),
33 priority_(kDefaultPriority),
34 trailers_decompressed_(false),
35 trailers_delivered_(false) {
36 DCHECK_NE(kCryptoStreamId, id);
37 // Don't receive any callbacks from the sequencer until headers
38 // are complete.
39 sequencer()->SetBlockedUntilFlush();
40 spdy_session_->RegisterStreamPriority(id, priority_);
41 }
42
43 QuicSpdyStream::~QuicSpdyStream() {
44 if (spdy_session_ != nullptr) {
45 spdy_session_->UnregisterStreamPriority(id());
46 }
47 }
48
49 void QuicSpdyStream::CloseWriteSide() {
50 if (!fin_received() && !rst_received() && sequencer()->ignore_read_data() &&
51 !rst_sent()) {
52 DCHECK(fin_sent());
53 // Tell the peer to stop sending further data.
54 DVLOG(1) << ENDPOINT << "Send QUIC_STREAM_NO_ERROR on stream " << id();
55 Reset(QUIC_STREAM_NO_ERROR);
56 }
57
58 ReliableQuicStream::CloseWriteSide();
59 }
60
61 void QuicSpdyStream::StopReading() {
62 if (!fin_received() && !rst_received() && write_side_closed() &&
63 !rst_sent()) {
64 DCHECK(fin_sent());
65 // Tell the peer to stop sending further data.
66 DVLOG(1) << ENDPOINT << "Send QUIC_STREAM_NO_ERROR on stream " << id();
67 Reset(QUIC_STREAM_NO_ERROR);
68 }
69 ReliableQuicStream::StopReading();
70 }
71
72 size_t QuicSpdyStream::WriteHeaders(
73 SpdyHeaderBlock header_block,
74 bool fin,
75 QuicAckListenerInterface* ack_notifier_delegate) {
76 size_t bytes_written = spdy_session_->WriteHeaders(
77 id(), std::move(header_block), fin, priority_, ack_notifier_delegate);
78 if (fin) {
79 // TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent.
80 set_fin_sent(true);
81 CloseWriteSide();
82 }
83 return bytes_written;
84 }
85
86 void QuicSpdyStream::WriteOrBufferBody(
87 const string& data,
88 bool fin,
89 QuicAckListenerInterface* ack_notifier_delegate) {
90 WriteOrBufferData(data, fin, ack_notifier_delegate);
91 }
92
93 size_t QuicSpdyStream::WriteTrailers(
94 SpdyHeaderBlock trailer_block,
95 QuicAckListenerInterface* ack_notifier_delegate) {
96 if (fin_sent()) {
97 QUIC_BUG << "Trailers cannot be sent after a FIN.";
98 return 0;
99 }
100
101 // The header block must contain the final offset for this stream, as the
102 // trailers may be processed out of order at the peer.
103 DVLOG(1) << "Inserting trailer: (" << kFinalOffsetHeaderKey << ", "
104 << stream_bytes_written() + queued_data_bytes() << ")";
105 trailer_block.insert(std::make_pair(
106 kFinalOffsetHeaderKey,
107 IntToString(stream_bytes_written() + queued_data_bytes())));
108
109 // Write the trailing headers with a FIN, and close stream for writing:
110 // trailers are the last thing to be sent on a stream.
111 const bool kFin = true;
112 size_t bytes_written = spdy_session_->WriteHeaders(
113 id(), std::move(trailer_block), kFin, priority_, ack_notifier_delegate);
114 set_fin_sent(kFin);
115
116 // Trailers are the last thing to be sent on a stream, but if there is still
117 // queued data then CloseWriteSide() will cause it never to be sent.
118 if (queued_data_bytes() == 0) {
119 CloseWriteSide();
120 }
121
122 return bytes_written;
123 }
124
125 size_t QuicSpdyStream::Readv(const struct iovec* iov, size_t iov_len) {
126 DCHECK(FinishedReadingHeaders());
127 return sequencer()->Readv(iov, iov_len);
128 }
129
130 int QuicSpdyStream::GetReadableRegions(iovec* iov, size_t iov_len) const {
131 DCHECK(FinishedReadingHeaders());
132 return sequencer()->GetReadableRegions(iov, iov_len);
133 }
134
135 void QuicSpdyStream::MarkConsumed(size_t num_bytes) {
136 DCHECK(FinishedReadingHeaders());
137 return sequencer()->MarkConsumed(num_bytes);
138 }
139
140 bool QuicSpdyStream::IsDoneReading() const {
141 bool done_reading_headers = FinishedReadingHeaders();
142 bool done_reading_body = sequencer()->IsClosed();
143 bool done_reading_trailers = FinishedReadingTrailers();
144 return done_reading_headers && done_reading_body && done_reading_trailers;
145 }
146
147 bool QuicSpdyStream::HasBytesToRead() const {
148 bool headers_to_read = !decompressed_headers_.empty();
149 bool body_to_read = sequencer()->HasBytesToRead();
150 bool trailers_to_read = !decompressed_trailers_.empty();
151 return headers_to_read || body_to_read || trailers_to_read;
152 }
153
154 void QuicSpdyStream::MarkHeadersConsumed(size_t bytes_consumed) {
155 decompressed_headers_.erase(0, bytes_consumed);
156 if (FinishedReadingHeaders()) {
157 sequencer()->SetUnblocked();
158 }
159 }
160
161 void QuicSpdyStream::MarkTrailersConsumed(size_t bytes_consumed) {
162 decompressed_trailers_.erase(0, bytes_consumed);
163 }
164
165 void QuicSpdyStream::MarkTrailersDelivered() {
166 trailers_delivered_ = true;
167 }
168
169 void QuicSpdyStream::ConsumeHeaderList() {
170 header_list_.Clear();
171 if (FinishedReadingHeaders()) {
172 sequencer()->SetUnblocked();
173 }
174 }
175
176 void QuicSpdyStream::SetPriority(SpdyPriority priority) {
177 DCHECK_EQ(0u, stream_bytes_written());
178 spdy_session_->UpdateStreamPriority(id(), priority);
179 priority_ = priority;
180 }
181
182 void QuicSpdyStream::OnStreamHeaders(StringPiece headers_data) {
183 if (!headers_decompressed_) {
184 headers_data.AppendToString(&decompressed_headers_);
185 } else {
186 DCHECK(!trailers_decompressed_);
187 headers_data.AppendToString(&decompressed_trailers_);
188 }
189 }
190
191 void QuicSpdyStream::OnStreamHeadersPriority(SpdyPriority priority) {
192 DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective());
193 SetPriority(priority);
194 }
195
196 void QuicSpdyStream::OnStreamHeadersComplete(bool fin, size_t frame_len) {
197 if (!headers_decompressed_) {
198 OnInitialHeadersComplete(fin, frame_len);
199 } else {
200 OnTrailingHeadersComplete(fin, frame_len);
201 }
202 }
203
204 void QuicSpdyStream::OnStreamHeaderList(bool fin,
205 size_t frame_len,
206 const QuicHeaderList& header_list) {
207 if (!headers_decompressed_) {
208 OnInitialHeadersComplete(fin, frame_len, header_list);
209 } else {
210 OnTrailingHeadersComplete(fin, frame_len, header_list);
211 }
212 }
213
214 void QuicSpdyStream::OnInitialHeadersComplete(bool fin, size_t /*frame_len*/) {
215 headers_decompressed_ = true;
216 if (fin) {
217 OnStreamFrame(QuicStreamFrame(id(), fin, 0, StringPiece()));
218 }
219 if (FinishedReadingHeaders()) {
220 sequencer()->SetUnblocked();
221 }
222 }
223
224 void QuicSpdyStream::OnInitialHeadersComplete(
225 bool fin,
226 size_t /*frame_len*/,
227 const QuicHeaderList& header_list) {
228 headers_decompressed_ = true;
229 header_list_ = header_list;
230 if (fin) {
231 OnStreamFrame(QuicStreamFrame(id(), fin, 0, StringPiece()));
232 }
233 if (FinishedReadingHeaders()) {
234 sequencer()->SetUnblocked();
235 }
236 }
237
238 void QuicSpdyStream::OnPromiseHeaders(StringPiece headers_data) {
239 headers_data.AppendToString(&decompressed_headers_);
240 }
241
242 void QuicSpdyStream::OnPromiseHeadersComplete(
243 QuicStreamId /* promised_stream_id */,
244 size_t /* frame_len */) {
245 // To be overridden in QuicSpdyClientStream. Not supported on
246 // server side.
247 session()->connection()->CloseConnection(
248 QUIC_INVALID_HEADERS_STREAM_DATA, "Promise headers received by server",
249 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
250 return;
251 }
252
253 void QuicSpdyStream::OnPromiseHeaderList(
254 QuicStreamId /* promised_id */,
255 size_t /* frame_len */,
256 const QuicHeaderList& /*header_list */) {
257 // To be overridden in QuicSpdyClientStream. Not supported on
258 // server side.
259 session()->connection()->CloseConnection(
260 QUIC_INVALID_HEADERS_STREAM_DATA, "Promise headers received by server",
261 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
262 return;
263 }
264
265 void QuicSpdyStream::OnTrailingHeadersComplete(bool fin, size_t /*frame_len*/) {
266 DCHECK(!trailers_decompressed_);
267 if (fin_received()) {
268 DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id();
269 session()->connection()->CloseConnection(
270 QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin",
271 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
272 return;
273 }
274 if (!fin) {
275 DLOG(ERROR) << "Trailers must have FIN set, on stream: " << id();
276 session()->connection()->CloseConnection(
277 QUIC_INVALID_HEADERS_STREAM_DATA, "Fin missing from trailers",
278 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
279 return;
280 }
281
282 size_t final_byte_offset = 0;
283 if (!SpdyUtils::ParseTrailers(decompressed_trailers().data(),
284 decompressed_trailers().length(),
285 &final_byte_offset, &received_trailers_)) {
286 DLOG(ERROR) << "Trailers are malformed: " << id();
287 session()->connection()->CloseConnection(
288 QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers are malformed",
289 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
290 return;
291 }
292
293 // The data on this stream ends at |final_byte_offset|.
294 DVLOG(1) << "Stream ends at byte offset: " << final_byte_offset
295 << " currently read: " << stream_bytes_read();
296
297 OnStreamFrame(QuicStreamFrame(id(), fin, final_byte_offset, StringPiece()));
298 trailers_decompressed_ = true;
299 }
300
301 void QuicSpdyStream::OnTrailingHeadersComplete(
302 bool fin,
303 size_t /*frame_len*/,
304 const QuicHeaderList& header_list) {
305 DCHECK(!trailers_decompressed_);
306 if (fin_received()) {
307 DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id();
308 session()->connection()->CloseConnection(
309 QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin",
310 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
311 return;
312 }
313 if (!fin) {
314 DLOG(ERROR) << "Trailers must have FIN set, on stream: " << id();
315 session()->connection()->CloseConnection(
316 QUIC_INVALID_HEADERS_STREAM_DATA, "Fin missing from trailers",
317 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
318 return;
319 }
320
321 size_t final_byte_offset = 0;
322 if (!SpdyUtils::CopyAndValidateTrailers(header_list, &final_byte_offset,
323 &received_trailers_)) {
324 DLOG(ERROR) << "Trailers are malformed: " << id();
325 session()->connection()->CloseConnection(
326 QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers are malformed",
327 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
328 return;
329 }
330 OnStreamFrame(QuicStreamFrame(id(), fin, final_byte_offset, StringPiece()));
331 trailers_decompressed_ = true;
332 }
333
334 void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) {
335 if (frame.error_code != QUIC_STREAM_NO_ERROR) {
336 ReliableQuicStream::OnStreamReset(frame);
337 return;
338 }
339 DVLOG(1) << "Received QUIC_STREAM_NO_ERROR, not discarding response";
340 set_rst_received(true);
341 MaybeIncreaseHighestReceivedOffset(frame.byte_offset);
342 set_stream_error(frame.error_code);
343 CloseWriteSide();
344 }
345
346 void QuicSpdyStream::OnClose() {
347 ReliableQuicStream::OnClose();
348
349 if (visitor_) {
350 Visitor* visitor = visitor_;
351 // Calling Visitor::OnClose() may result the destruction of the visitor,
352 // so we need to ensure we don't call it again.
353 visitor_ = nullptr;
354 visitor->OnClose(this);
355 }
356 }
357
358 bool QuicSpdyStream::FinishedReadingHeaders() const {
359 return headers_decompressed_ && decompressed_headers_.empty() &&
360 header_list_.empty();
361 }
362
363 bool QuicSpdyStream::ParseHeaderStatusCode(const SpdyHeaderBlock& header,
364 int* status_code) const {
365 SpdyHeaderBlock::const_iterator it = header.find(":status");
366 if (it == header.end()) {
367 return false;
368 }
369 const StringPiece status(it->second);
370 if (status.size() != 3) {
371 return false;
372 }
373 // First character must be an integer in range [1,5].
374 if (status[0] < '1' || status[0] > '5') {
375 return false;
376 }
377 // The remaining two characters must be integers.
378 if (!isdigit(status[1]) || !isdigit(status[2])) {
379 return false;
380 }
381 return StringToInt(status, status_code);
382 }
383
384 bool QuicSpdyStream::FinishedReadingTrailers() const {
385 // If no further trailing headers are expected, and the decompressed trailers
386 // (if any) have been consumed, then reading of trailers is finished.
387 if (!fin_received()) {
388 return false;
389 } else if (!trailers_decompressed_) {
390 return true;
391 } else {
392 return trailers_delivered_ && decompressed_trailers_.empty();
393 }
394 }
395
396 SpdyPriority QuicSpdyStream::priority() const {
397 return priority_;
398 }
399
400 void QuicSpdyStream::ClearSession() {
401 spdy_session_ = nullptr;
402 }
403
404 QuicConsumedData QuicSpdyStream::WritevDataInner(
405 QuicIOVector iov,
406 QuicStreamOffset offset,
407 bool fin,
408 QuicAckListenerInterface* ack_notifier_delegate) {
409 if (spdy_session_->headers_stream() != nullptr &&
410 spdy_session_->force_hol_blocking()) {
411 return spdy_session_->headers_stream()->WritevStreamData(
412 id(), iov, offset, fin, ack_notifier_delegate);
413 }
414 return ReliableQuicStream::WritevDataInner(iov, offset, fin,
415 ack_notifier_delegate);
416 }
417
418 } // namespace net
OLDNEW
« no previous file with comments | « net/quic/quic_spdy_stream.h ('k') | net/quic/quic_spdy_stream_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698