| 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 14 matching lines...) Expand all  Loading... | 
|   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  Loading... | 
|  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  Loading... | 
|  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  Loading... | 
|  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 | 
| OLD | NEW |