// 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 { 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), error_(OK) { // 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_ = OK; } CHECK_EQ(error_, OK); // If this is the first call with the current header block, // save its stream id. if (state_ == READING_HEADER_BLOCK_LEN) { stream_id_ = stream_id; } CHECK_EQ(stream_id_, stream_id); 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_ == OK) { 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(stream_id, 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(stream_id, total_bytes_received_); // Expect to have consumed all buffer. if (reader.Available() != 0) { error_ = TOO_MUCH_DATA; } } break; default: CHECK(false) << "Not reached."; } if (error_ == OK) { 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_ == OK; } void SpdyHeadersBlockParser::ParseBlockLength(Reader* reader) { ParseLength(reader, &remaining_key_value_pairs_for_frame_); if (error_ == OK && remaining_key_value_pairs_for_frame_ > max_headers_in_block_) { error_ = HEADER_BLOCK_TOO_LARGE; } if (error_ == OK) { handler_->OnHeaderBlock(stream_id_, remaining_key_value_pairs_for_frame_); } } void SpdyHeadersBlockParser::ParseFieldLength(Reader* reader) { ParseLength(reader, &next_field_length_); if (error_ == OK && 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)); } } void SpdyHeadersBlockParser::Reset() { { SpdyPinnableBufferPiece empty; headers_block_prefix_.Swap(&empty); } { SpdyPinnableBufferPiece empty; key_.Swap(&empty); } error_ = OK; state_ = READING_HEADER_BLOCK_LEN; stream_id_ = 0; total_bytes_received_ = 0; } 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