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

Side by Side Diff: net/spdy/spdy_stream.cc

Issue 2675593002: Spdy{RstStream,GoAway}Status -> SpdyErrorCode. (Closed)
Patch Set: Merged master, which includes 145087791. Created 3 years, 10 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/spdy/spdy_session_unittest.cc ('k') | net/spdy/spdy_stream_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/spdy/spdy_stream.h" 5 #include "net/spdy/spdy_stream.h"
6 6
7 #include <algorithm>
7 #include <limits> 8 #include <limits>
8 #include <utility> 9 #include <utility>
9 10
10 #include "base/bind.h" 11 #include "base/bind.h"
11 #include "base/compiler_specific.h" 12 #include "base/compiler_specific.h"
12 #include "base/location.h" 13 #include "base/location.h"
13 #include "base/logging.h" 14 #include "base/logging.h"
14 #include "base/metrics/histogram_macros.h" 15 #include "base/metrics/histogram_macros.h"
15 #include "base/single_thread_task_runner.h" 16 #include "base/single_thread_task_runner.h"
16 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 89
89 bool ContainsUppercaseAscii(base::StringPiece str) { 90 bool ContainsUppercaseAscii(base::StringPiece str) {
90 return std::any_of(str.begin(), str.end(), base::IsAsciiUpper<char>); 91 return std::any_of(str.begin(), str.end(), base::IsAsciiUpper<char>);
91 } 92 }
92 93
93 } // namespace 94 } // namespace
94 95
95 // A wrapper around a stream that calls into ProduceHeadersFrame(). 96 // A wrapper around a stream that calls into ProduceHeadersFrame().
96 class SpdyStream::HeadersBufferProducer : public SpdyBufferProducer { 97 class SpdyStream::HeadersBufferProducer : public SpdyBufferProducer {
97 public: 98 public:
98 HeadersBufferProducer(const base::WeakPtr<SpdyStream>& stream) 99 explicit HeadersBufferProducer(const base::WeakPtr<SpdyStream>& stream)
99 : stream_(stream) { 100 : stream_(stream) {
100 DCHECK(stream_.get()); 101 DCHECK(stream_.get());
101 } 102 }
102 103
103 ~HeadersBufferProducer() override {} 104 ~HeadersBufferProducer() override {}
104 105
105 std::unique_ptr<SpdyBuffer> ProduceBuffer() override { 106 std::unique_ptr<SpdyBuffer> ProduceBuffer() override {
106 if (!stream_.get()) { 107 if (!stream_.get()) {
107 NOTREACHED(); 108 NOTREACHED();
108 return std::unique_ptr<SpdyBuffer>(); 109 return std::unique_ptr<SpdyBuffer>();
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
282 283
283 if (send_window_size_ > 0) { 284 if (send_window_size_ > 0) {
284 // Check for overflow. 285 // Check for overflow.
285 int32_t max_delta_window_size = 286 int32_t max_delta_window_size =
286 std::numeric_limits<int32_t>::max() - send_window_size_; 287 std::numeric_limits<int32_t>::max() - send_window_size_;
287 if (delta_window_size > max_delta_window_size) { 288 if (delta_window_size > max_delta_window_size) {
288 std::string desc = base::StringPrintf( 289 std::string desc = base::StringPrintf(
289 "Received WINDOW_UPDATE [delta: %d] for stream %d overflows " 290 "Received WINDOW_UPDATE [delta: %d] for stream %d overflows "
290 "send_window_size_ [current: %d]", delta_window_size, stream_id_, 291 "send_window_size_ [current: %d]", delta_window_size, stream_id_,
291 send_window_size_); 292 send_window_size_);
292 session_->ResetStream(stream_id_, RST_STREAM_FLOW_CONTROL_ERROR, desc); 293 session_->ResetStream(stream_id_, ERROR_CODE_FLOW_CONTROL_ERROR, desc);
293 return; 294 return;
294 } 295 }
295 } 296 }
296 297
297 send_window_size_ += delta_window_size; 298 send_window_size_ += delta_window_size;
298 299
299 net_log_.AddEvent( 300 net_log_.AddEvent(
300 NetLogEventType::HTTP2_STREAM_UPDATE_SEND_WINDOW, 301 NetLogEventType::HTTP2_STREAM_UPDATE_SEND_WINDOW,
301 base::Bind(&NetLogSpdyStreamWindowUpdateCallback, stream_id_, 302 base::Bind(&NetLogSpdyStreamWindowUpdateCallback, stream_id_,
302 delta_window_size, send_window_size_)); 303 delta_window_size, send_window_size_));
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 364
364 void SpdyStream::DecreaseRecvWindowSize(int32_t delta_window_size) { 365 void SpdyStream::DecreaseRecvWindowSize(int32_t delta_window_size) {
365 DCHECK(session_->IsStreamActive(stream_id_)); 366 DCHECK(session_->IsStreamActive(stream_id_));
366 DCHECK_GE(delta_window_size, 1); 367 DCHECK_GE(delta_window_size, 1);
367 368
368 // The receiving window size as the peer knows it is 369 // The receiving window size as the peer knows it is
369 // |recv_window_size_ - unacked_recv_window_bytes_|, if more data are sent by 370 // |recv_window_size_ - unacked_recv_window_bytes_|, if more data are sent by
370 // the peer, that means that the receive window is not being respected. 371 // the peer, that means that the receive window is not being respected.
371 if (delta_window_size > recv_window_size_ - unacked_recv_window_bytes_) { 372 if (delta_window_size > recv_window_size_ - unacked_recv_window_bytes_) {
372 session_->ResetStream( 373 session_->ResetStream(
373 stream_id_, RST_STREAM_FLOW_CONTROL_ERROR, 374 stream_id_, ERROR_CODE_FLOW_CONTROL_ERROR,
374 "delta_window_size is " + base::IntToString(delta_window_size) + 375 "delta_window_size is " + base::IntToString(delta_window_size) +
375 " in DecreaseRecvWindowSize, which is larger than the receive " + 376 " in DecreaseRecvWindowSize, which is larger than the receive " +
376 "window size of " + base::IntToString(recv_window_size_)); 377 "window size of " + base::IntToString(recv_window_size_));
377 return; 378 return;
378 } 379 }
379 380
380 recv_window_size_ -= delta_window_size; 381 recv_window_size_ -= delta_window_size;
381 net_log_.AddEvent( 382 net_log_.AddEvent(
382 NetLogEventType::HTTP2_STREAM_UPDATE_RECV_WINDOW, 383 NetLogEventType::HTTP2_STREAM_UPDATE_RECV_WINDOW,
383 base::Bind(&NetLogSpdyStreamWindowUpdateCallback, stream_id_, 384 base::Bind(&NetLogSpdyStreamWindowUpdateCallback, stream_id_,
(...skipping 25 matching lines...) Expand all
409 base::TimeTicks recv_first_byte_time) { 410 base::TimeTicks recv_first_byte_time) {
410 switch (response_state_) { 411 switch (response_state_) {
411 case READY_FOR_HEADERS: { 412 case READY_FOR_HEADERS: {
412 // No header block has been received yet. 413 // No header block has been received yet.
413 DCHECK(response_headers_.empty()); 414 DCHECK(response_headers_.empty());
414 int status; 415 int status;
415 switch (ParseStatusHeader(response_headers, &status)) { 416 switch (ParseStatusHeader(response_headers, &status)) {
416 case STATUS_HEADER_NOT_INCLUDED: { 417 case STATUS_HEADER_NOT_INCLUDED: {
417 const std::string error("Response headers do not include :status."); 418 const std::string error("Response headers do not include :status.");
418 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 419 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
419 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error); 420 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
420 return; 421 return;
421 } 422 }
422 case STATUS_HEADER_DOES_NOT_START_WITH_NUMBER: { 423 case STATUS_HEADER_DOES_NOT_START_WITH_NUMBER: {
423 const std::string error("Cannot parse :status."); 424 const std::string error("Cannot parse :status.");
424 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 425 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
425 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error); 426 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
426 return; 427 return;
427 } 428 }
428 // Intentional fallthrough for the following two cases, 429 // Intentional fallthrough for the following two cases,
429 // to maintain compatibility with broken servers that include 430 // to maintain compatibility with broken servers that include
430 // status text in the response. 431 // status text in the response.
431 case STATUS_HEADER_IS_NUMBER: 432 case STATUS_HEADER_IS_NUMBER:
432 case STATUS_HEADER_HAS_STATUS_TEXT: 433 case STATUS_HEADER_HAS_STATUS_TEXT:
433 // Ignore informational headers. 434 // Ignore informational headers.
434 // TODO(bnc): Add support for 103 Early Hints, 435 // TODO(bnc): Add support for 103 Early Hints,
435 // https://crbug.com/671310. 436 // https://crbug.com/671310.
436 if (status / 100 == 1) { 437 if (status / 100 == 1) {
437 return; 438 return;
438 } 439 }
439 } 440 }
440 441
441 response_state_ = READY_FOR_DATA_OR_TRAILERS; 442 response_state_ = READY_FOR_DATA_OR_TRAILERS;
442 443
443 switch (type_) { 444 switch (type_) {
444 case SPDY_BIDIRECTIONAL_STREAM: 445 case SPDY_BIDIRECTIONAL_STREAM:
445 case SPDY_REQUEST_RESPONSE_STREAM: 446 case SPDY_REQUEST_RESPONSE_STREAM:
446 // A bidirectional stream or a request/response stream is ready for 447 // A bidirectional stream or a request/response stream is ready for
447 // the response headers only after request headers are sent. 448 // the response headers only after request headers are sent.
448 if (io_state_ == STATE_IDLE) { 449 if (io_state_ == STATE_IDLE) {
449 const std::string error("Response received before request sent."); 450 const std::string error("Response received before request sent.");
450 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 451 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
451 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error); 452 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
452 return; 453 return;
453 } 454 }
454 break; 455 break;
455 456
456 case SPDY_PUSH_STREAM: 457 case SPDY_PUSH_STREAM:
457 // Push streams transition to a locally half-closed state upon 458 // Push streams transition to a locally half-closed state upon
458 // headers. We must continue to buffer data while waiting for a call 459 // headers. We must continue to buffer data while waiting for a call
459 // to SetDelegate() (which may not ever happen). 460 // to SetDelegate() (which may not ever happen).
460 DCHECK_EQ(io_state_, STATE_RESERVED_REMOTE); 461 DCHECK_EQ(io_state_, STATE_RESERVED_REMOTE);
461 if (!delegate_) { 462 if (!delegate_) {
(...skipping 10 matching lines...) Expand all
472 recv_first_byte_time_ = recv_first_byte_time; 473 recv_first_byte_time_ = recv_first_byte_time;
473 SaveResponseHeaders(response_headers); 474 SaveResponseHeaders(response_headers);
474 475
475 break; 476 break;
476 } 477 }
477 case READY_FOR_DATA_OR_TRAILERS: 478 case READY_FOR_DATA_OR_TRAILERS:
478 // Second header block is trailers. 479 // Second header block is trailers.
479 if (type_ == SPDY_PUSH_STREAM) { 480 if (type_ == SPDY_PUSH_STREAM) {
480 const std::string error("Trailers not supported for push stream."); 481 const std::string error("Trailers not supported for push stream.");
481 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 482 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
482 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error); 483 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
483 return; 484 return;
484 } 485 }
485 486
486 response_state_ = TRAILERS_RECEIVED; 487 response_state_ = TRAILERS_RECEIVED;
487 delegate_->OnTrailers(response_headers); 488 delegate_->OnTrailers(response_headers);
488 break; 489 break;
489 490
490 case TRAILERS_RECEIVED: 491 case TRAILERS_RECEIVED:
491 // No further header blocks are allowed after trailers. 492 // No further header blocks are allowed after trailers.
492 const std::string error("Header block received after trailers."); 493 const std::string error("Header block received after trailers.");
493 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 494 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
494 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error); 495 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
495 break; 496 break;
496 } 497 }
497 } 498 }
498 499
499 void SpdyStream::OnPushPromiseHeadersReceived(SpdyHeaderBlock headers) { 500 void SpdyStream::OnPushPromiseHeadersReceived(SpdyHeaderBlock headers) {
500 CHECK(!request_headers_valid_); 501 CHECK(!request_headers_valid_);
501 CHECK_EQ(io_state_, STATE_IDLE); 502 CHECK_EQ(io_state_, STATE_IDLE);
502 CHECK_EQ(type_, SPDY_PUSH_STREAM); 503 CHECK_EQ(type_, SPDY_PUSH_STREAM);
503 DCHECK(!delegate_); 504 DCHECK(!delegate_);
504 505
505 io_state_ = STATE_RESERVED_REMOTE; 506 io_state_ = STATE_RESERVED_REMOTE;
506 request_headers_ = std::move(headers); 507 request_headers_ = std::move(headers);
507 request_headers_valid_ = true; 508 request_headers_valid_ = true;
508 url_from_header_block_ = GetUrlFromHeaderBlock(request_headers_); 509 url_from_header_block_ = GetUrlFromHeaderBlock(request_headers_);
509 } 510 }
510 511
511 void SpdyStream::OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) { 512 void SpdyStream::OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) {
512 DCHECK(session_->IsStreamActive(stream_id_)); 513 DCHECK(session_->IsStreamActive(stream_id_));
513 514
514 if (response_state_ == READY_FOR_HEADERS) { 515 if (response_state_ == READY_FOR_HEADERS) {
515 const std::string error("DATA received before headers."); 516 const std::string error("DATA received before headers.");
516 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 517 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
517 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error); 518 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
518 return; 519 return;
519 } 520 }
520 521
521 if (response_state_ == TRAILERS_RECEIVED && buffer) { 522 if (response_state_ == TRAILERS_RECEIVED && buffer) {
522 const std::string error("DATA received after trailers."); 523 const std::string error("DATA received after trailers.");
523 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 524 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
524 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error); 525 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
525 return; 526 return;
526 } 527 }
527 528
528 // Track our bandwidth. 529 // Track our bandwidth.
529 recv_bytes_ += buffer ? buffer->GetRemainingSize() : 0; 530 recv_bytes_ += buffer ? buffer->GetRemainingSize() : 0;
530 recv_last_byte_time_ = base::TimeTicks::Now(); 531 recv_last_byte_time_ = base::TimeTicks::Now();
531 532
532 // If we're still buffering data for a push stream, we will do the check for 533 // If we're still buffering data for a push stream, we will do the check for
533 // data received with incomplete headers in PushedStreamReplay(). 534 // data received with incomplete headers in PushedStreamReplay().
534 if (io_state_ == STATE_HALF_CLOSED_LOCAL_UNCLAIMED) { 535 if (io_state_ == STATE_HALF_CLOSED_LOCAL_UNCLAIMED) {
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
689 // Unset |stream_id_| last so that the delegate can look it up. 690 // Unset |stream_id_| last so that the delegate can look it up.
690 stream_id_ = 0; 691 stream_id_ = 0;
691 } 692 }
692 693
693 void SpdyStream::Cancel() { 694 void SpdyStream::Cancel() {
694 // We may be called again from a delegate's OnClose(). 695 // We may be called again from a delegate's OnClose().
695 if (io_state_ == STATE_CLOSED) 696 if (io_state_ == STATE_CLOSED)
696 return; 697 return;
697 698
698 if (stream_id_ != 0) { 699 if (stream_id_ != 0) {
699 session_->ResetStream(stream_id_, RST_STREAM_CANCEL, std::string()); 700 session_->ResetStream(stream_id_, ERROR_CODE_CANCEL, std::string());
700 } else { 701 } else {
701 session_->CloseCreatedStream(GetWeakPtr(), RST_STREAM_CANCEL); 702 session_->CloseCreatedStream(GetWeakPtr(), ERROR_CODE_CANCEL);
702 } 703 }
703 // |this| is invalid at this point. 704 // |this| is invalid at this point.
704 } 705 }
705 706
706 void SpdyStream::Close() { 707 void SpdyStream::Close() {
707 // We may be called again from a delegate's OnClose(). 708 // We may be called again from a delegate's OnClose().
708 if (io_state_ == STATE_CLOSED) 709 if (io_state_ == STATE_CLOSED)
709 return; 710 return;
710 711
711 if (stream_id_ != 0) { 712 if (stream_id_ != 0) {
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
892 893
893 session_->EnqueueStreamWrite( 894 session_->EnqueueStreamWrite(
894 GetWeakPtr(), DATA, 895 GetWeakPtr(), DATA,
895 std::unique_ptr<SpdyBufferProducer>( 896 std::unique_ptr<SpdyBufferProducer>(
896 new SimpleBufferProducer(std::move(data_buffer)))); 897 new SimpleBufferProducer(std::move(data_buffer))));
897 } 898 }
898 899
899 void SpdyStream::SaveResponseHeaders(const SpdyHeaderBlock& response_headers) { 900 void SpdyStream::SaveResponseHeaders(const SpdyHeaderBlock& response_headers) {
900 DCHECK(response_headers_.empty()); 901 DCHECK(response_headers_.empty());
901 if (response_headers.find("transfer-encoding") != response_headers.end()) { 902 if (response_headers.find("transfer-encoding") != response_headers.end()) {
902 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, 903 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR,
903 "Received transfer-encoding header"); 904 "Received transfer-encoding header");
904 return; 905 return;
905 } 906 }
906 907
907 for (SpdyHeaderBlock::const_iterator it = response_headers.begin(); 908 for (SpdyHeaderBlock::const_iterator it = response_headers.begin();
908 it != response_headers.end(); ++it) { 909 it != response_headers.end(); ++it) {
909 // Disallow uppercase headers. 910 // Disallow uppercase headers.
910 if (ContainsUppercaseAscii(it->first)) { 911 if (ContainsUppercaseAscii(it->first)) {
911 session_->ResetStream( 912 session_->ResetStream(
912 stream_id_, RST_STREAM_PROTOCOL_ERROR, 913 stream_id_, ERROR_CODE_PROTOCOL_ERROR,
913 "Upper case characters in header: " + it->first.as_string()); 914 "Upper case characters in header: " + it->first.as_string());
914 return; 915 return;
915 } 916 }
916 917
917 response_headers_.insert(*it); 918 response_headers_.insert(*it);
918 } 919 }
919 920
920 // If delegate is not yet attached, OnHeadersReceived() will be called after 921 // If delegate is not yet attached, OnHeadersReceived() will be called after
921 // the delegate gets attached to the stream. 922 // the delegate gets attached to the stream.
922 if (delegate_) 923 if (delegate_)
(...skipping 17 matching lines...) Expand all
940 description = base::StringPrintf("Unknown state 0x%08X (%u)", state, 941 description = base::StringPrintf("Unknown state 0x%08X (%u)", state,
941 state); 942 state);
942 break; 943 break;
943 } 944 }
944 return description; 945 return description;
945 } 946 }
946 947
947 #undef STATE_CASE 948 #undef STATE_CASE
948 949
949 } // namespace net 950 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/spdy_session_unittest.cc ('k') | net/spdy/spdy_stream_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698