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

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

Issue 2555183002: Do not reset stream if HTTP/2 response contains status text. (Closed)
Patch Set: Created 4 years 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 <limits> 7 #include <limits>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 12 matching lines...) Expand all
23 #include "net/log/net_log_capture_mode.h" 23 #include "net/log/net_log_capture_mode.h"
24 #include "net/log/net_log_event_type.h" 24 #include "net/log/net_log_event_type.h"
25 #include "net/spdy/spdy_buffer_producer.h" 25 #include "net/spdy/spdy_buffer_producer.h"
26 #include "net/spdy/spdy_http_utils.h" 26 #include "net/spdy/spdy_http_utils.h"
27 #include "net/spdy/spdy_session.h" 27 #include "net/spdy/spdy_session.h"
28 28
29 namespace net { 29 namespace net {
30 30
31 namespace { 31 namespace {
32 32
33 enum StatusHeader {
34 STATUS_HEADER_NOT_INCLUDED = 0,
35 STATUS_HEADER_DOES_NOT_START_WITH_NUMBER = 1,
36 STATUS_HEADER_IS_NUMBER = 2,
37 STATUS_HEADER_HAS_STATUS_TEXT = 3,
38 STATUS_HEADER_MAX = STATUS_HEADER_HAS_STATUS_TEXT
39 };
40
41 StatusHeader ParseStatusHeaderImpl(const SpdyHeaderBlock& response_headers,
42 int* status) {
43 SpdyHeaderBlock::const_iterator it = response_headers.find(":status");
44 if (it == response_headers.end())
45 return STATUS_HEADER_NOT_INCLUDED;
46
47 // Save status in |*status| even if some text follows the status code.
48 base::StringPiece status_string = it->second;
49 base::StringPiece::size_type end = status_string.find(' ');
50 if (!StringToInt(status_string.substr(0, end), status))
51 return STATUS_HEADER_DOES_NOT_START_WITH_NUMBER;
52
53 // Check if status header could be parsed as a single number,
54 // but keep |*status| correct even if it cannot.
55 int unused;
56 if (StringToInt(status_string, &unused))
Ryan Hamilton 2016/12/07 19:11:39 nit: Instead of calling StringToInt twice, it seem
Bence 2016/12/07 20:33:18 Done.
57 return STATUS_HEADER_IS_NUMBER;
58
59 return STATUS_HEADER_HAS_STATUS_TEXT;
60 }
61
62 StatusHeader ParseStatusHeader(const SpdyHeaderBlock& response_headers,
63 int* status) {
64 StatusHeader status_header = ParseStatusHeaderImpl(response_headers, status);
65 UMA_HISTOGRAM_ENUMERATION("Net.Http2ResponseStatusHeader", status_header,
66 STATUS_HEADER_MAX + 1);
67 return status_header;
68 }
69
33 std::unique_ptr<base::Value> NetLogSpdyStreamErrorCallback( 70 std::unique_ptr<base::Value> NetLogSpdyStreamErrorCallback(
34 SpdyStreamId stream_id, 71 SpdyStreamId stream_id,
35 int status, 72 int status,
36 const std::string* description, 73 const std::string* description,
37 NetLogCaptureMode /* capture_mode */) { 74 NetLogCaptureMode /* capture_mode */) {
38 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); 75 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
39 dict->SetInteger("stream_id", static_cast<int>(stream_id)); 76 dict->SetInteger("stream_id", static_cast<int>(stream_id));
40 dict->SetInteger("status", status); 77 dict->SetInteger("status", status);
41 dict->SetString("description", *description); 78 dict->SetString("description", *description);
42 return std::move(dict); 79 return std::move(dict);
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 } 406 }
370 407
371 void SpdyStream::SetRequestTime(base::Time t) { 408 void SpdyStream::SetRequestTime(base::Time t) {
372 request_time_ = t; 409 request_time_ = t;
373 } 410 }
374 411
375 void SpdyStream::OnHeadersReceived(const SpdyHeaderBlock& response_headers, 412 void SpdyStream::OnHeadersReceived(const SpdyHeaderBlock& response_headers,
376 base::Time response_time, 413 base::Time response_time,
377 base::TimeTicks recv_first_byte_time) { 414 base::TimeTicks recv_first_byte_time) {
378 switch (response_state_) { 415 switch (response_state_) {
379 case READY_FOR_HEADERS: 416 case READY_FOR_HEADERS: {
380 // No header block has been received yet. 417 // No header block has been received yet.
381 DCHECK(response_headers_.empty()); 418 DCHECK(response_headers_.empty());
382 419 int status;
383 { 420 switch (ParseStatusHeader(response_headers, &status)) {
384 SpdyHeaderBlock::const_iterator it = response_headers.find(":status"); 421 case STATUS_HEADER_NOT_INCLUDED: {
385 if (it == response_headers.end()) {
386 const std::string error("Response headers do not include :status."); 422 const std::string error("Response headers do not include :status.");
387 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 423 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
388 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error); 424 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error);
389 return; 425 return;
390 } 426 }
391 427 case STATUS_HEADER_DOES_NOT_START_WITH_NUMBER: {
392 int status;
393 if (!StringToInt(it->second, &status)) {
394 const std::string error("Cannot parse :status."); 428 const std::string error("Cannot parse :status.");
395 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 429 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
396 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error); 430 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error);
397 return; 431 return;
398 } 432 }
399 433 // Intentional fallthrough for the following two cases,
400 // Ignore informational headers. 434 // to maintain compatibility with broken servers that include
401 // TODO(bnc): Add support for 103 Early Hints, https://crbug.com/671310. 435 // status text in the response.
402 if (status / 100 == 1) { 436 case STATUS_HEADER_IS_NUMBER:
403 return; 437 case STATUS_HEADER_HAS_STATUS_TEXT:
404 } 438 // Ignore informational headers.
439 // TODO(bnc): Add support for 103 Early Hints,
440 // https://crbug.com/671310.
441 if (status / 100 == 1) {
442 return;
443 }
405 } 444 }
406 445
407 response_state_ = READY_FOR_DATA_OR_TRAILERS; 446 response_state_ = READY_FOR_DATA_OR_TRAILERS;
408 447
409 switch (type_) { 448 switch (type_) {
410 case SPDY_BIDIRECTIONAL_STREAM: 449 case SPDY_BIDIRECTIONAL_STREAM:
411 case SPDY_REQUEST_RESPONSE_STREAM: 450 case SPDY_REQUEST_RESPONSE_STREAM:
412 // A bidirectional stream or a request/response stream is ready for 451 // A bidirectional stream or a request/response stream is ready for
413 // the response headers only after request headers are sent. 452 // the response headers only after request headers are sent.
414 if (io_state_ == STATE_IDLE) { 453 if (io_state_ == STATE_IDLE) {
(...skipping 17 matching lines...) Expand all
432 break; 471 break;
433 } 472 }
434 473
435 DCHECK_NE(io_state_, STATE_IDLE); 474 DCHECK_NE(io_state_, STATE_IDLE);
436 475
437 response_time_ = response_time; 476 response_time_ = response_time;
438 recv_first_byte_time_ = recv_first_byte_time; 477 recv_first_byte_time_ = recv_first_byte_time;
439 SaveResponseHeaders(response_headers); 478 SaveResponseHeaders(response_headers);
440 479
441 break; 480 break;
442 481 }
443 case READY_FOR_DATA_OR_TRAILERS: 482 case READY_FOR_DATA_OR_TRAILERS:
444 // Second header block is trailers. 483 // Second header block is trailers.
445 if (type_ == SPDY_PUSH_STREAM) { 484 if (type_ == SPDY_PUSH_STREAM) {
446 const std::string error("Trailers not supported for push stream."); 485 const std::string error("Trailers not supported for push stream.");
447 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); 486 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
448 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error); 487 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error);
449 return; 488 return;
450 } 489 }
451 490
452 response_state_ = TRAILERS_RECEIVED; 491 response_state_ = TRAILERS_RECEIVED;
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after
901 description = base::StringPrintf("Unknown state 0x%08X (%u)", state, 940 description = base::StringPrintf("Unknown state 0x%08X (%u)", state,
902 state); 941 state);
903 break; 942 break;
904 } 943 }
905 return description; 944 return description;
906 } 945 }
907 946
908 #undef STATE_CASE 947 #undef STATE_CASE
909 948
910 } // namespace net 949 } // 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