1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/spdy/spdy_headers_block_parser.h"
6
7#include "base/sys_byteorder.h"
8
9namespace net {
10
11const size_t SpdyHeadersBlockParser::kMaximumFieldLength = 16 * 1024;
12
13SpdyHeadersBlockParser::SpdyHeadersBlockParser(
14    SpdyMajorVersion spdy_version,
15    SpdyHeadersHandlerInterface* handler) :
16    state_(READING_HEADER_BLOCK_LEN),
17    length_field_size_(LengthFieldSizeForVersion(spdy_version)),
18    max_headers_in_block_(MaxNumberOfHeadersForVersion(spdy_version)),
19    total_bytes_received_(0),
20    remaining_key_value_pairs_for_frame_(0),
21    handler_(handler),
22    error_(OK) {
23  // The handler that we set must not be NULL.
24  DCHECK(handler_ != NULL);
25}
26
27SpdyHeadersBlockParser::~SpdyHeadersBlockParser() {}
28
29bool SpdyHeadersBlockParser::HandleControlFrameHeadersData(
30    SpdyStreamId stream_id,
31    const char* headers_data,
32    size_t headers_data_length) {
33  if (error_ == NEED_MORE_DATA) {
34    error_ = OK;
35  }
36  CHECK_EQ(error_, OK);
37
38  // If this is the first call with the current header block,
39  // save its stream id.
40  if (state_ == READING_HEADER_BLOCK_LEN) {
41    stream_id_ = stream_id;
42  }
43  CHECK_EQ(stream_id_, stream_id);
44
45  total_bytes_received_ += headers_data_length;
46
47  SpdyPinnableBufferPiece prefix, key, value;
48  // Simultaneously tie lifetimes to the stack, and clear member variables.
49  prefix.Swap(&headers_block_prefix_);
50  key.Swap(&key_);
51
52  // Apply the parsing state machine to the remaining prefix
53  // from last invocation, plus newly-available headers data.
54  Reader reader(prefix.buffer(), prefix.length(),
55                headers_data, headers_data_length);
56  while (error_ == OK) {
57    ParserState next_state(FINISHED_HEADER);
58
59    switch (state_) {
60      case READING_HEADER_BLOCK_LEN:
61        next_state = READING_KEY_LEN;
62        ParseBlockLength(&reader);
63        break;
64      case READING_KEY_LEN:
65        next_state = READING_KEY;
66        ParseFieldLength(&reader);
67        break;
68      case READING_KEY:
69        next_state = READING_VALUE_LEN;
70        if (!reader.ReadN(next_field_length_, &key)) {
71          error_ = NEED_MORE_DATA;
72        }
73        break;
74      case READING_VALUE_LEN:
75        next_state = READING_VALUE;
76        ParseFieldLength(&reader);
77        break;
78      case READING_VALUE:
79        next_state = FINISHED_HEADER;
80        if (!reader.ReadN(next_field_length_, &value)) {
81          error_ = NEED_MORE_DATA;
82        } else {
83          handler_->OnHeader(stream_id, key, value);
84        }
85        break;
86      case FINISHED_HEADER:
87        // Prepare for next header or block.
88        if (--remaining_key_value_pairs_for_frame_ > 0) {
89          next_state = READING_KEY_LEN;
90        } else {
91          next_state = READING_HEADER_BLOCK_LEN;
92          handler_->OnHeaderBlockEnd(stream_id, total_bytes_received_);
93          // Expect to have consumed all buffer.
94          if (reader.Available() != 0) {
95            error_ = TOO_MUCH_DATA;
96          }
97        }
98        break;
99      default:
100        CHECK(false) << "Not reached.";
101    }
102
103    if (error_ == OK) {
104      state_ = next_state;
105
106      if (next_state == READING_HEADER_BLOCK_LEN) {
107        // We completed reading a full header block. Return to caller.
108        total_bytes_received_ = 0;
109        break;
110      }
111    } else if (error_ == NEED_MORE_DATA) {
112      // We can't continue parsing until more data is available. Make copies of
113      // the key and buffer remainder, in preperation for the next invocation.
114      if (state_ > READING_KEY) {
115        key_.Swap(&key);
116        key_.Pin();
117      }
118      reader.ReadN(reader.Available(), &headers_block_prefix_);
119      headers_block_prefix_.Pin();
120    }
121  }
122  return error_ == OK;
123}
124
125void SpdyHeadersBlockParser::ParseBlockLength(Reader* reader) {
126  ParseLength(reader, &remaining_key_value_pairs_for_frame_);
127  if (error_ == OK &&
128    remaining_key_value_pairs_for_frame_ > max_headers_in_block_) {
129    error_ = HEADER_BLOCK_TOO_LARGE;
130  }
131  if (error_ == OK) {
132    handler_->OnHeaderBlock(stream_id_, remaining_key_value_pairs_for_frame_);
133  }
134}
135
136void SpdyHeadersBlockParser::ParseFieldLength(Reader* reader) {
137  ParseLength(reader, &next_field_length_);
138  if (error_ == OK &&
139      next_field_length_ > kMaximumFieldLength) {
140    error_ = HEADER_FIELD_TOO_LARGE;
141  }
142}
143
144void SpdyHeadersBlockParser::ParseLength(Reader* reader,
145                                         uint32_t* parsed_length) {
146  char buffer[] = {0, 0, 0, 0};
147  if (!reader->ReadN(length_field_size_, buffer)) {
148    error_ = NEED_MORE_DATA;
149    return;
150  }
151  // Convert from network to host order and return the parsed out integer.
152  if (length_field_size_ == sizeof(uint32_t)) {
153    *parsed_length = ntohl(*reinterpret_cast<const uint32_t *>(buffer));
154  } else {
155    *parsed_length = ntohs(*reinterpret_cast<const uint16_t *>(buffer));
156  }
157}
158
159void SpdyHeadersBlockParser::Reset() {
160  {
161    SpdyPinnableBufferPiece empty;
162    headers_block_prefix_.Swap(&empty);
163  }
164  {
165    SpdyPinnableBufferPiece empty;
166    key_.Swap(&empty);
167  }
168  error_ = OK;
169  state_ = READING_HEADER_BLOCK_LEN;
170  stream_id_ = 0;
171  total_bytes_received_ = 0;
172}
173
174size_t SpdyHeadersBlockParser::LengthFieldSizeForVersion(
175    SpdyMajorVersion spdy_version) {
176  if (spdy_version < SPDY3) {
177    return sizeof(uint16_t);
178  }
179  return sizeof(uint32_t);
180}
181
182size_t SpdyHeadersBlockParser::MaxNumberOfHeadersForVersion(
183    SpdyMajorVersion spdy_version) {
184  // Account for the length of the header block field.
185  size_t max_bytes_for_headers =
186      kMaximumFieldLength - LengthFieldSizeForVersion(spdy_version);
187
188  // A minimal size header is twice the length field size (and has a
189  // zero-lengthed key and a zero-lengthed value).
190  return max_bytes_for_headers / (2 * LengthFieldSizeForVersion(spdy_version));
191}
192
193}  // namespace net
194