| // Copyright 2014 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "net/spdy/spdy_headers_block_parser.h" | 
 |  | 
 | #include "base/sys_byteorder.h" | 
 |  | 
 | namespace net { | 
 | namespace { | 
 |  | 
 | // 0 is invalid according to both the SPDY 3.1 and HTTP/2 specifications. | 
 | const SpdyStreamId kInvalidStreamId = 0; | 
 |  | 
 | }  // anonymous namespace | 
 |  | 
 | const size_t SpdyHeadersBlockParser::kMaximumFieldLength = 16 * 1024; | 
 |  | 
 | SpdyHeadersBlockParser::SpdyHeadersBlockParser( | 
 |     SpdyMajorVersion spdy_version, | 
 |     SpdyHeadersHandlerInterface* handler) | 
 |     : state_(READING_HEADER_BLOCK_LEN), | 
 |       length_field_size_(LengthFieldSizeForVersion(spdy_version)), | 
 |       max_headers_in_block_(MaxNumberOfHeadersForVersion(spdy_version)), | 
 |       total_bytes_received_(0), | 
 |       remaining_key_value_pairs_for_frame_(0), | 
 |       handler_(handler), | 
 |       stream_id_(kInvalidStreamId), | 
 |       error_(NO_PARSER_ERROR), | 
 |       spdy_version_(spdy_version) { | 
 |   // The handler that we set must not be NULL. | 
 |   DCHECK(handler_ != NULL); | 
 | } | 
 |  | 
 | SpdyHeadersBlockParser::~SpdyHeadersBlockParser() {} | 
 |  | 
 | bool SpdyHeadersBlockParser::HandleControlFrameHeadersData( | 
 |     SpdyStreamId stream_id, | 
 |     const char* headers_data, | 
 |     size_t headers_data_length) { | 
 |   if (error_ == NEED_MORE_DATA) { | 
 |     error_ = NO_PARSER_ERROR; | 
 |   } | 
 |   if (error_ != NO_PARSER_ERROR) { | 
 |     LOG(DFATAL) << "Unexpected error: " << error_; | 
 |     return false; | 
 |   } | 
 |  | 
 |   // If this is the first call with the current header block, | 
 |   // save its stream id. | 
 |   if (state_ == READING_HEADER_BLOCK_LEN && stream_id_ == kInvalidStreamId) { | 
 |     stream_id_ = stream_id; | 
 |   } | 
 |   if (stream_id != stream_id_) { | 
 |     LOG(DFATAL) << "Unexpected stream id: " << stream_id << " (expected " | 
 |                 << stream_id_ << ")"; | 
 |     error_ = UNEXPECTED_STREAM_ID; | 
 |     return false; | 
 |   } | 
 |   if (stream_id_ == kInvalidStreamId) { | 
 |     LOG(DFATAL) << "Expected nonzero stream id, saw: " << stream_id_; | 
 |     error_ = UNEXPECTED_STREAM_ID; | 
 |     return false; | 
 |   } | 
 |   total_bytes_received_ += headers_data_length; | 
 |  | 
 |   SpdyPinnableBufferPiece prefix, key, value; | 
 |   // Simultaneously tie lifetimes to the stack, and clear member variables. | 
 |   prefix.Swap(&headers_block_prefix_); | 
 |   key.Swap(&key_); | 
 |  | 
 |   // Apply the parsing state machine to the remaining prefix | 
 |   // from last invocation, plus newly-available headers data. | 
 |   Reader reader(prefix.buffer(), prefix.length(), | 
 |                 headers_data, headers_data_length); | 
 |   while (error_ == NO_PARSER_ERROR) { | 
 |     ParserState next_state(FINISHED_HEADER); | 
 |  | 
 |     switch (state_) { | 
 |       case READING_HEADER_BLOCK_LEN: | 
 |         next_state = READING_KEY_LEN; | 
 |         ParseBlockLength(&reader); | 
 |         break; | 
 |       case READING_KEY_LEN: | 
 |         next_state = READING_KEY; | 
 |         ParseFieldLength(&reader); | 
 |         break; | 
 |       case READING_KEY: | 
 |         next_state = READING_VALUE_LEN; | 
 |         if (!reader.ReadN(next_field_length_, &key)) { | 
 |           error_ = NEED_MORE_DATA; | 
 |         } | 
 |         break; | 
 |       case READING_VALUE_LEN: | 
 |         next_state = READING_VALUE; | 
 |         ParseFieldLength(&reader); | 
 |         break; | 
 |       case READING_VALUE: | 
 |         next_state = FINISHED_HEADER; | 
 |         if (!reader.ReadN(next_field_length_, &value)) { | 
 |           error_ = NEED_MORE_DATA; | 
 |         } else { | 
 |           handler_->OnHeader(key, value); | 
 |         } | 
 |         break; | 
 |       case FINISHED_HEADER: | 
 |         // Prepare for next header or block. | 
 |         if (--remaining_key_value_pairs_for_frame_ > 0) { | 
 |           next_state = READING_KEY_LEN; | 
 |         } else { | 
 |           next_state = READING_HEADER_BLOCK_LEN; | 
 |           handler_->OnHeaderBlockEnd(total_bytes_received_); | 
 |           stream_id_ = kInvalidStreamId; | 
 |           // Expect to have consumed all buffer. | 
 |           if (reader.Available() != 0) { | 
 |             error_ = TOO_MUCH_DATA; | 
 |           } | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     if (error_ == NO_PARSER_ERROR) { | 
 |       state_ = next_state; | 
 |  | 
 |       if (next_state == READING_HEADER_BLOCK_LEN) { | 
 |         // We completed reading a full header block. Return to caller. | 
 |         total_bytes_received_ = 0; | 
 |         break; | 
 |       } | 
 |     } else if (error_ == NEED_MORE_DATA) { | 
 |       // We can't continue parsing until more data is available. Make copies of | 
 |       // the key and buffer remainder, in preperation for the next invocation. | 
 |       if (state_ > READING_KEY) { | 
 |         key_.Swap(&key); | 
 |         key_.Pin(); | 
 |       } | 
 |       reader.ReadN(reader.Available(), &headers_block_prefix_); | 
 |       headers_block_prefix_.Pin(); | 
 |     } | 
 |   } | 
 |   return error_ == NO_PARSER_ERROR; | 
 | } | 
 |  | 
 | void SpdyHeadersBlockParser::ParseBlockLength(Reader* reader) { | 
 |   ParseLength(reader, &remaining_key_value_pairs_for_frame_); | 
 |   if (error_ == NO_PARSER_ERROR && | 
 |       remaining_key_value_pairs_for_frame_ > max_headers_in_block_) { | 
 |     error_ = HEADER_BLOCK_TOO_LARGE; | 
 |   } | 
 |   if (error_ == NO_PARSER_ERROR) { | 
 |     handler_->OnHeaderBlock(remaining_key_value_pairs_for_frame_); | 
 |   } | 
 | } | 
 |  | 
 | void SpdyHeadersBlockParser::ParseFieldLength(Reader* reader) { | 
 |   ParseLength(reader, &next_field_length_); | 
 |   if (error_ == NO_PARSER_ERROR && next_field_length_ > kMaximumFieldLength) { | 
 |     error_ = HEADER_FIELD_TOO_LARGE; | 
 |   } | 
 | } | 
 |  | 
 | void SpdyHeadersBlockParser::ParseLength(Reader* reader, | 
 |                                          uint32_t* parsed_length) { | 
 |   char buffer[] = {0, 0, 0, 0}; | 
 |   if (!reader->ReadN(length_field_size_, buffer)) { | 
 |     error_ = NEED_MORE_DATA; | 
 |     return; | 
 |   } | 
 |   // Convert from network to host order and return the parsed out integer. | 
 |   if (length_field_size_ == sizeof(uint32_t)) { | 
 |     *parsed_length = ntohl(*reinterpret_cast<const uint32_t *>(buffer)); | 
 |   } else { | 
 |     *parsed_length = ntohs(*reinterpret_cast<const uint16_t *>(buffer)); | 
 |   } | 
 | } | 
 |  | 
 | size_t SpdyHeadersBlockParser::LengthFieldSizeForVersion( | 
 |     SpdyMajorVersion spdy_version) { | 
 |   if (spdy_version < SPDY3) { | 
 |     return sizeof(uint16_t); | 
 |   } | 
 |   return sizeof(uint32_t); | 
 | } | 
 |  | 
 | size_t SpdyHeadersBlockParser::MaxNumberOfHeadersForVersion( | 
 |     SpdyMajorVersion spdy_version) { | 
 |   // Account for the length of the header block field. | 
 |   size_t max_bytes_for_headers = | 
 |       kMaximumFieldLength - LengthFieldSizeForVersion(spdy_version); | 
 |  | 
 |   // A minimal size header is twice the length field size (and has a | 
 |   // zero-lengthed key and a zero-lengthed value). | 
 |   return max_bytes_for_headers / (2 * LengthFieldSizeForVersion(spdy_version)); | 
 | } | 
 |  | 
 | }  // namespace net |