| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |