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

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

Issue 2779763005: Reset stream if HTTP/2 response status is invalid. (Closed)
Patch Set: Created 3 years, 8 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 | « no previous file | 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 <algorithm>
8 #include <limits> 8 #include <limits>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 14 matching lines...) Expand all
25 #include "net/spdy/platform/api/spdy_estimate_memory_usage.h" 25 #include "net/spdy/platform/api/spdy_estimate_memory_usage.h"
26 #include "net/spdy/platform/api/spdy_string_piece.h" 26 #include "net/spdy/platform/api/spdy_string_piece.h"
27 #include "net/spdy/spdy_buffer_producer.h" 27 #include "net/spdy/spdy_buffer_producer.h"
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 enum StatusHeader {
36 STATUS_HEADER_NOT_INCLUDED = 0,
37 STATUS_HEADER_DOES_NOT_START_WITH_NUMBER = 1,
38 STATUS_HEADER_IS_NUMBER = 2,
39 STATUS_HEADER_HAS_STATUS_TEXT = 3,
40 STATUS_HEADER_MAX = STATUS_HEADER_HAS_STATUS_TEXT
41 };
42
43 StatusHeader ParseStatusHeaderImpl(const SpdyHeaderBlock& response_headers,
44 int* status) {
45 SpdyHeaderBlock::const_iterator it = response_headers.find(":status");
46 if (it == response_headers.end())
47 return STATUS_HEADER_NOT_INCLUDED;
48
49 // Save status in |*status| even if some text follows the status code.
50 SpdyStringPiece status_string = it->second;
51 SpdyStringPiece::size_type end = status_string.find(' ');
52 if (!StringToInt(status_string.substr(0, end), status))
53 return STATUS_HEADER_DOES_NOT_START_WITH_NUMBER;
54
55 return end == SpdyStringPiece::npos ? STATUS_HEADER_IS_NUMBER
56 : STATUS_HEADER_HAS_STATUS_TEXT;
57 }
58
59 StatusHeader ParseStatusHeader(const SpdyHeaderBlock& response_headers,
60 int* status) {
61 StatusHeader status_header = ParseStatusHeaderImpl(response_headers, status);
62 UMA_HISTOGRAM_ENUMERATION("Net.Http2ResponseStatusHeader", status_header,
63 STATUS_HEADER_MAX + 1);
64 return status_header;
65 }
66
67 std::unique_ptr<base::Value> NetLogSpdyStreamErrorCallback( 35 std::unique_ptr<base::Value> NetLogSpdyStreamErrorCallback(
68 SpdyStreamId stream_id, 36 SpdyStreamId stream_id,
69 int status, 37 int status,
70 const std::string* description, 38 const std::string* description,
71 NetLogCaptureMode /* capture_mode */) { 39 NetLogCaptureMode /* capture_mode */) {
72 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); 40 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
73 dict->SetInteger("stream_id", static_cast<int>(stream_id)); 41 dict->SetInteger("stream_id", static_cast<int>(stream_id));
74 dict->SetInteger("status", status); 42 dict->SetInteger("status", status);
75 dict->SetString("description", *description); 43 dict->SetString("description", *description);
76 return std::move(dict); 44 return std::move(dict);
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 } 372 }
405 373
406 void SpdyStream::SetRequestTime(base::Time t) { 374 void SpdyStream::SetRequestTime(base::Time t) {
407 request_time_ = t; 375 request_time_ = t;
408 } 376 }
409 377
410 void SpdyStream::OnHeadersReceived(const SpdyHeaderBlock& response_headers, 378 void SpdyStream::OnHeadersReceived(const SpdyHeaderBlock& response_headers,
411 base::Time response_time, 379 base::Time response_time,
412 base::TimeTicks recv_first_byte_time) { 380 base::TimeTicks recv_first_byte_time) {
413 switch (response_state_) { 381 switch (response_state_) {
414 case READY_FOR_HEADERS: { 382 case READY_FOR_HEADERS:
415 // No header block has been received yet. 383 // No header block has been received yet.
416 DCHECK(response_headers_.empty()); 384 DCHECK(response_headers_.empty());
417 int status; 385
418 switch (ParseStatusHeader(response_headers, &status)) { 386 {
419 case STATUS_HEADER_NOT_INCLUDED: { 387 SpdyHeaderBlock::const_iterator it = response_headers.find(":status");
388 if (it == response_headers.end()) {
420 const std::string error("Response headers do not include :status."); 389 const std::string error("Response headers do not include :status.");
421 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 390 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
422 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); 391 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
423 return; 392 return;
424 } 393 }
425 case STATUS_HEADER_DOES_NOT_START_WITH_NUMBER: { 394
395 int status;
396 if (!StringToInt(it->second, &status)) {
426 const std::string error("Cannot parse :status."); 397 const std::string error("Cannot parse :status.");
427 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 398 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
428 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); 399 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
429 return; 400 return;
430 } 401 }
431 // Intentional fallthrough for the following two cases, 402
432 // to maintain compatibility with broken servers that include 403 // Ignore informational headers.
433 // status text in the response. 404 // TODO(bnc): Add support for 103 Early Hints, https://crbug.com/671310.
434 case STATUS_HEADER_IS_NUMBER: 405 if (status / 100 == 1) {
435 case STATUS_HEADER_HAS_STATUS_TEXT: 406 return;
436 // Ignore informational headers. 407 }
437 // TODO(bnc): Add support for 103 Early Hints,
438 // https://crbug.com/671310.
439 if (status / 100 == 1) {
440 return;
441 }
442 } 408 }
443 409
444 response_state_ = READY_FOR_DATA_OR_TRAILERS; 410 response_state_ = READY_FOR_DATA_OR_TRAILERS;
445 411
446 switch (type_) { 412 switch (type_) {
447 case SPDY_BIDIRECTIONAL_STREAM: 413 case SPDY_BIDIRECTIONAL_STREAM:
448 case SPDY_REQUEST_RESPONSE_STREAM: 414 case SPDY_REQUEST_RESPONSE_STREAM:
449 // A bidirectional stream or a request/response stream is ready for 415 // A bidirectional stream or a request/response stream is ready for
450 // the response headers only after request headers are sent. 416 // the response headers only after request headers are sent.
451 if (io_state_ == STATE_IDLE) { 417 if (io_state_ == STATE_IDLE) {
(...skipping 17 matching lines...) Expand all
469 break; 435 break;
470 } 436 }
471 437
472 DCHECK_NE(io_state_, STATE_IDLE); 438 DCHECK_NE(io_state_, STATE_IDLE);
473 439
474 response_time_ = response_time; 440 response_time_ = response_time;
475 recv_first_byte_time_ = recv_first_byte_time; 441 recv_first_byte_time_ = recv_first_byte_time;
476 SaveResponseHeaders(response_headers); 442 SaveResponseHeaders(response_headers);
477 443
478 break; 444 break;
479 } 445
480 case READY_FOR_DATA_OR_TRAILERS: 446 case READY_FOR_DATA_OR_TRAILERS:
481 // Second header block is trailers. 447 // Second header block is trailers.
482 if (type_ == SPDY_PUSH_STREAM) { 448 if (type_ == SPDY_PUSH_STREAM) {
483 const std::string error("Trailers not supported for push stream."); 449 const std::string error("Trailers not supported for push stream.");
484 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 450 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
485 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error); 451 session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
486 return; 452 return;
487 } 453 }
488 454
489 response_state_ = TRAILERS_RECEIVED; 455 response_state_ = TRAILERS_RECEIVED;
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after
953 description = base::StringPrintf("Unknown state 0x%08X (%u)", state, 919 description = base::StringPrintf("Unknown state 0x%08X (%u)", state,
954 state); 920 state);
955 break; 921 break;
956 } 922 }
957 return description; 923 return description;
958 } 924 }
959 925
960 #undef STATE_CASE 926 #undef STATE_CASE
961 927
962 } // namespace net 928 } // namespace net
OLDNEW
« no previous file with comments | « no previous file | net/spdy/spdy_stream_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698