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 <algorithm> |
8 #include <limits> | 8 #include <limits> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 17 matching lines...) Expand all Loading... |
28 #include "net/spdy/spdy_http_utils.h" | 28 #include "net/spdy/spdy_http_utils.h" |
29 #include "net/spdy/spdy_session.h" | 29 #include "net/spdy/spdy_session.h" |
30 | 30 |
31 namespace net { | 31 namespace net { |
32 | 32 |
33 namespace { | 33 namespace { |
34 | 34 |
35 std::unique_ptr<base::Value> NetLogSpdyStreamErrorCallback( | 35 std::unique_ptr<base::Value> NetLogSpdyStreamErrorCallback( |
36 SpdyStreamId stream_id, | 36 SpdyStreamId stream_id, |
37 int status, | 37 int status, |
38 const std::string* description, | 38 const SpdyString* description, |
39 NetLogCaptureMode /* capture_mode */) { | 39 NetLogCaptureMode /* capture_mode */) { |
40 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 40 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
41 dict->SetInteger("stream_id", static_cast<int>(stream_id)); | 41 dict->SetInteger("stream_id", static_cast<int>(stream_id)); |
42 dict->SetInteger("status", status); | 42 dict->SetInteger("status", status); |
43 dict->SetString("description", *description); | 43 dict->SetString("description", *description); |
44 return std::move(dict); | 44 return std::move(dict); |
45 } | 45 } |
46 | 46 |
47 std::unique_ptr<base::Value> NetLogSpdyStreamWindowUpdateCallback( | 47 std::unique_ptr<base::Value> NetLogSpdyStreamWindowUpdateCallback( |
48 SpdyStreamId stream_id, | 48 SpdyStreamId stream_id, |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 | 250 |
251 // Ignore late WINDOW_UPDATEs. | 251 // Ignore late WINDOW_UPDATEs. |
252 if (IsClosed()) | 252 if (IsClosed()) |
253 return; | 253 return; |
254 | 254 |
255 if (send_window_size_ > 0) { | 255 if (send_window_size_ > 0) { |
256 // Check for overflow. | 256 // Check for overflow. |
257 int32_t max_delta_window_size = | 257 int32_t max_delta_window_size = |
258 std::numeric_limits<int32_t>::max() - send_window_size_; | 258 std::numeric_limits<int32_t>::max() - send_window_size_; |
259 if (delta_window_size > max_delta_window_size) { | 259 if (delta_window_size > max_delta_window_size) { |
260 std::string desc = SpdyStringPrintf( | 260 SpdyString desc = SpdyStringPrintf( |
261 "Received WINDOW_UPDATE [delta: %d] for stream %d overflows " | 261 "Received WINDOW_UPDATE [delta: %d] for stream %d overflows " |
262 "send_window_size_ [current: %d]", | 262 "send_window_size_ [current: %d]", |
263 delta_window_size, stream_id_, send_window_size_); | 263 delta_window_size, stream_id_, send_window_size_); |
264 session_->ResetStream(stream_id_, ERROR_CODE_FLOW_CONTROL_ERROR, desc); | 264 session_->ResetStream(stream_id_, ERROR_CODE_FLOW_CONTROL_ERROR, desc); |
265 return; | 265 return; |
266 } | 266 } |
267 } | 267 } |
268 | 268 |
269 send_window_size_ += delta_window_size; | 269 send_window_size_ += delta_window_size; |
270 | 270 |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 base::Time response_time, | 380 base::Time response_time, |
381 base::TimeTicks recv_first_byte_time) { | 381 base::TimeTicks recv_first_byte_time) { |
382 switch (response_state_) { | 382 switch (response_state_) { |
383 case READY_FOR_HEADERS: | 383 case READY_FOR_HEADERS: |
384 // No header block has been received yet. | 384 // No header block has been received yet. |
385 DCHECK(response_headers_.empty()); | 385 DCHECK(response_headers_.empty()); |
386 | 386 |
387 { | 387 { |
388 SpdyHeaderBlock::const_iterator it = response_headers.find(":status"); | 388 SpdyHeaderBlock::const_iterator it = response_headers.find(":status"); |
389 if (it == response_headers.end()) { | 389 if (it == response_headers.end()) { |
390 const std::string error("Response headers do not include :status."); | 390 const SpdyString error("Response headers do not include :status."); |
391 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); | 391 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); |
392 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); | 392 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); |
393 return; | 393 return; |
394 } | 394 } |
395 | 395 |
396 int status; | 396 int status; |
397 if (!StringToInt(it->second, &status)) { | 397 if (!StringToInt(it->second, &status)) { |
398 const std::string error("Cannot parse :status."); | 398 const SpdyString error("Cannot parse :status."); |
399 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); | 399 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); |
400 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); | 400 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); |
401 return; | 401 return; |
402 } | 402 } |
403 | 403 |
404 // Ignore informational headers. | 404 // Ignore informational headers. |
405 // TODO(bnc): Add support for 103 Early Hints, https://crbug.com/671310. | 405 // TODO(bnc): Add support for 103 Early Hints, https://crbug.com/671310. |
406 if (status / 100 == 1) { | 406 if (status / 100 == 1) { |
407 return; | 407 return; |
408 } | 408 } |
409 } | 409 } |
410 | 410 |
411 response_state_ = READY_FOR_DATA_OR_TRAILERS; | 411 response_state_ = READY_FOR_DATA_OR_TRAILERS; |
412 | 412 |
413 switch (type_) { | 413 switch (type_) { |
414 case SPDY_BIDIRECTIONAL_STREAM: | 414 case SPDY_BIDIRECTIONAL_STREAM: |
415 case SPDY_REQUEST_RESPONSE_STREAM: | 415 case SPDY_REQUEST_RESPONSE_STREAM: |
416 // A bidirectional stream or a request/response stream is ready for | 416 // A bidirectional stream or a request/response stream is ready for |
417 // the response headers only after request headers are sent. | 417 // the response headers only after request headers are sent. |
418 if (io_state_ == STATE_IDLE) { | 418 if (io_state_ == STATE_IDLE) { |
419 const std::string error("Response received before request sent."); | 419 const SpdyString error("Response received before request sent."); |
420 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); | 420 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); |
421 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); | 421 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); |
422 return; | 422 return; |
423 } | 423 } |
424 break; | 424 break; |
425 | 425 |
426 case SPDY_PUSH_STREAM: | 426 case SPDY_PUSH_STREAM: |
427 // Push streams transition to a locally half-closed state upon | 427 // Push streams transition to a locally half-closed state upon |
428 // headers. We must continue to buffer data while waiting for a call | 428 // headers. We must continue to buffer data while waiting for a call |
429 // to SetDelegate() (which may not ever happen). | 429 // to SetDelegate() (which may not ever happen). |
(...skipping 10 matching lines...) Expand all Loading... |
440 | 440 |
441 response_time_ = response_time; | 441 response_time_ = response_time; |
442 recv_first_byte_time_ = recv_first_byte_time; | 442 recv_first_byte_time_ = recv_first_byte_time; |
443 SaveResponseHeaders(response_headers); | 443 SaveResponseHeaders(response_headers); |
444 | 444 |
445 break; | 445 break; |
446 | 446 |
447 case READY_FOR_DATA_OR_TRAILERS: | 447 case READY_FOR_DATA_OR_TRAILERS: |
448 // Second header block is trailers. | 448 // Second header block is trailers. |
449 if (type_ == SPDY_PUSH_STREAM) { | 449 if (type_ == SPDY_PUSH_STREAM) { |
450 const std::string error("Trailers not supported for push stream."); | 450 const SpdyString error("Trailers not supported for push stream."); |
451 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); | 451 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); |
452 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); | 452 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); |
453 return; | 453 return; |
454 } | 454 } |
455 | 455 |
456 response_state_ = TRAILERS_RECEIVED; | 456 response_state_ = TRAILERS_RECEIVED; |
457 delegate_->OnTrailers(response_headers); | 457 delegate_->OnTrailers(response_headers); |
458 break; | 458 break; |
459 | 459 |
460 case TRAILERS_RECEIVED: | 460 case TRAILERS_RECEIVED: |
461 // No further header blocks are allowed after trailers. | 461 // No further header blocks are allowed after trailers. |
462 const std::string error("Header block received after trailers."); | 462 const SpdyString error("Header block received after trailers."); |
463 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); | 463 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); |
464 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); | 464 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); |
465 break; | 465 break; |
466 } | 466 } |
467 } | 467 } |
468 | 468 |
469 void SpdyStream::OnPushPromiseHeadersReceived(SpdyHeaderBlock headers) { | 469 void SpdyStream::OnPushPromiseHeadersReceived(SpdyHeaderBlock headers) { |
470 CHECK(!request_headers_valid_); | 470 CHECK(!request_headers_valid_); |
471 CHECK_EQ(io_state_, STATE_IDLE); | 471 CHECK_EQ(io_state_, STATE_IDLE); |
472 CHECK_EQ(type_, SPDY_PUSH_STREAM); | 472 CHECK_EQ(type_, SPDY_PUSH_STREAM); |
473 DCHECK(!delegate_); | 473 DCHECK(!delegate_); |
474 | 474 |
475 io_state_ = STATE_RESERVED_REMOTE; | 475 io_state_ = STATE_RESERVED_REMOTE; |
476 request_headers_ = std::move(headers); | 476 request_headers_ = std::move(headers); |
477 request_headers_valid_ = true; | 477 request_headers_valid_ = true; |
478 url_from_header_block_ = GetUrlFromHeaderBlock(request_headers_); | 478 url_from_header_block_ = GetUrlFromHeaderBlock(request_headers_); |
479 } | 479 } |
480 | 480 |
481 void SpdyStream::OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) { | 481 void SpdyStream::OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) { |
482 DCHECK(session_->IsStreamActive(stream_id_)); | 482 DCHECK(session_->IsStreamActive(stream_id_)); |
483 | 483 |
484 if (response_state_ == READY_FOR_HEADERS) { | 484 if (response_state_ == READY_FOR_HEADERS) { |
485 const std::string error("DATA received before headers."); | 485 const SpdyString error("DATA received before headers."); |
486 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); | 486 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); |
487 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); | 487 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); |
488 return; | 488 return; |
489 } | 489 } |
490 | 490 |
491 if (response_state_ == TRAILERS_RECEIVED && buffer) { | 491 if (response_state_ == TRAILERS_RECEIVED && buffer) { |
492 const std::string error("DATA received after trailers."); | 492 const SpdyString error("DATA received after trailers."); |
493 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); | 493 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); |
494 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); | 494 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); |
495 return; | 495 return; |
496 } | 496 } |
497 | 497 |
498 // Track our bandwidth. | 498 // Track our bandwidth. |
499 recv_bytes_ += buffer ? buffer->GetRemainingSize() : 0; | 499 recv_bytes_ += buffer ? buffer->GetRemainingSize() : 0; |
500 recv_last_byte_time_ = base::TimeTicks::Now(); | 500 recv_last_byte_time_ = base::TimeTicks::Now(); |
501 | 501 |
502 // If we're still buffering data for a push stream, we will do the check for | 502 // If we're still buffering data for a push stream, we will do the check for |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
629 pending_send_data_->DidConsume(frame_payload_size); | 629 pending_send_data_->DidConsume(frame_payload_size); |
630 if (pending_send_data_->BytesRemaining() > 0) { | 630 if (pending_send_data_->BytesRemaining() > 0) { |
631 QueueNextDataFrame(); | 631 QueueNextDataFrame(); |
632 return ERR_IO_PENDING; | 632 return ERR_IO_PENDING; |
633 } else { | 633 } else { |
634 pending_send_data_ = NULL; | 634 pending_send_data_ = NULL; |
635 return OK; | 635 return OK; |
636 } | 636 } |
637 } | 637 } |
638 | 638 |
639 void SpdyStream::LogStreamError(int status, const std::string& description) { | 639 void SpdyStream::LogStreamError(int status, const SpdyString& description) { |
640 net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_ERROR, | 640 net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_ERROR, |
641 base::Bind(&NetLogSpdyStreamErrorCallback, stream_id_, | 641 base::Bind(&NetLogSpdyStreamErrorCallback, stream_id_, |
642 status, &description)); | 642 status, &description)); |
643 } | 643 } |
644 | 644 |
645 void SpdyStream::OnClose(int status) { | 645 void SpdyStream::OnClose(int status) { |
646 // In most cases, the stream should already be CLOSED. The exception is when a | 646 // In most cases, the stream should already be CLOSED. The exception is when a |
647 // SpdySession is shutting down while the stream is in an intermediate state. | 647 // SpdySession is shutting down while the stream is in an intermediate state. |
648 io_state_ = STATE_CLOSED; | 648 io_state_ = STATE_CLOSED; |
649 if (status == ERR_SPDY_RST_STREAM_NO_ERROR_RECEIVED) { | 649 if (status == ERR_SPDY_RST_STREAM_NO_ERROR_RECEIVED) { |
(...skipping 11 matching lines...) Expand all Loading... |
661 // Unset |stream_id_| last so that the delegate can look it up. | 661 // Unset |stream_id_| last so that the delegate can look it up. |
662 stream_id_ = 0; | 662 stream_id_ = 0; |
663 } | 663 } |
664 | 664 |
665 void SpdyStream::Cancel() { | 665 void SpdyStream::Cancel() { |
666 // We may be called again from a delegate's OnClose(). | 666 // We may be called again from a delegate's OnClose(). |
667 if (io_state_ == STATE_CLOSED) | 667 if (io_state_ == STATE_CLOSED) |
668 return; | 668 return; |
669 | 669 |
670 if (stream_id_ != 0) { | 670 if (stream_id_ != 0) { |
671 session_->ResetStream(stream_id_, ERROR_CODE_CANCEL, std::string()); | 671 session_->ResetStream(stream_id_, ERROR_CODE_CANCEL, SpdyString()); |
672 } else { | 672 } else { |
673 session_->CloseCreatedStream(GetWeakPtr(), ERROR_CODE_CANCEL); | 673 session_->CloseCreatedStream(GetWeakPtr(), ERROR_CODE_CANCEL); |
674 } | 674 } |
675 // |this| is invalid at this point. | 675 // |this| is invalid at this point. |
676 } | 676 } |
677 | 677 |
678 void SpdyStream::Close() { | 678 void SpdyStream::Close() { |
679 // We may be called again from a delegate's OnClose(). | 679 // We may be called again from a delegate's OnClose(). |
680 if (io_state_ == STATE_CLOSED) | 680 if (io_state_ == STATE_CLOSED) |
681 return; | 681 return; |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
903 // the delegate gets attached to the stream. | 903 // the delegate gets attached to the stream. |
904 if (delegate_) | 904 if (delegate_) |
905 delegate_->OnHeadersReceived(response_headers_); | 905 delegate_->OnHeadersReceived(response_headers_); |
906 } | 906 } |
907 | 907 |
908 #define STATE_CASE(s) \ | 908 #define STATE_CASE(s) \ |
909 case s: \ | 909 case s: \ |
910 description = SpdyStringPrintf("%s (0x%08X)", #s, s); \ | 910 description = SpdyStringPrintf("%s (0x%08X)", #s, s); \ |
911 break | 911 break |
912 | 912 |
913 std::string SpdyStream::DescribeState(State state) { | 913 SpdyString SpdyStream::DescribeState(State state) { |
914 std::string description; | 914 SpdyString description; |
915 switch (state) { | 915 switch (state) { |
916 STATE_CASE(STATE_IDLE); | 916 STATE_CASE(STATE_IDLE); |
917 STATE_CASE(STATE_OPEN); | 917 STATE_CASE(STATE_OPEN); |
918 STATE_CASE(STATE_HALF_CLOSED_LOCAL_UNCLAIMED); | 918 STATE_CASE(STATE_HALF_CLOSED_LOCAL_UNCLAIMED); |
919 STATE_CASE(STATE_HALF_CLOSED_LOCAL); | 919 STATE_CASE(STATE_HALF_CLOSED_LOCAL); |
920 STATE_CASE(STATE_CLOSED); | 920 STATE_CASE(STATE_CLOSED); |
921 default: | 921 default: |
922 description = SpdyStringPrintf("Unknown state 0x%08X (%u)", state, state); | 922 description = SpdyStringPrintf("Unknown state 0x%08X (%u)", state, state); |
923 break; | 923 break; |
924 } | 924 } |
925 return description; | 925 return description; |
926 } | 926 } |
927 | 927 |
928 #undef STATE_CASE | 928 #undef STATE_CASE |
929 | 929 |
930 } // namespace net | 930 } // namespace net |
OLD | NEW |