prune resources in MemoryCache
[chromium-blink-merge.git] / net / spdy / spdy_headers_block_parser.cc
blob231533fbe322b50c267e425fde4c9685006124d1
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.
5 #include "net/spdy/spdy_headers_block_parser.h"
7 #include "base/sys_byteorder.h"
9 namespace net {
11 const size_t SpdyHeadersBlockParser::kMaximumFieldLength = 16 * 1024;
13 SpdyHeadersBlockParser::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);
27 SpdyHeadersBlockParser::~SpdyHeadersBlockParser() {}
29 bool 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;
36 CHECK_EQ(error_, OK);
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;
43 CHECK_EQ(stream_id_, stream_id);
45 total_bytes_received_ += headers_data_length;
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_);
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);
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;
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);
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;
98 break;
99 default:
100 CHECK(false) << "Not reached.";
103 if (error_ == OK) {
104 state_ = next_state;
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;
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();
118 reader.ReadN(reader.Available(), &headers_block_prefix_);
119 headers_block_prefix_.Pin();
122 return error_ == OK;
125 void 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;
131 if (error_ == OK) {
132 handler_->OnHeaderBlock(stream_id_, remaining_key_value_pairs_for_frame_);
136 void 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;
144 void 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;
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));
159 size_t SpdyHeadersBlockParser::LengthFieldSizeForVersion(
160 SpdyMajorVersion spdy_version) {
161 if (spdy_version < SPDY3) {
162 return sizeof(uint16_t);
164 return sizeof(uint32_t);
167 size_t SpdyHeadersBlockParser::MaxNumberOfHeadersForVersion(
168 SpdyMajorVersion spdy_version) {
169 // Account for the length of the header block field.
170 size_t max_bytes_for_headers =
171 kMaximumFieldLength - LengthFieldSizeForVersion(spdy_version);
173 // A minimal size header is twice the length field size (and has a
174 // zero-lengthed key and a zero-lengthed value).
175 return max_bytes_for_headers / (2 * LengthFieldSizeForVersion(spdy_version));
178 } // namespace net