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
9 namespace net {
10
11 const size_t SpdyHeadersBlockParser::kMaximumFieldLength = 16 * 1024;
12
SpdyHeadersBlockParser(SpdyMajorVersion spdy_version,SpdyHeadersHandlerInterface * handler)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);
25 }
26
~SpdyHeadersBlockParser()27 SpdyHeadersBlockParser::~SpdyHeadersBlockParser() {}
28
HandleControlFrameHeadersData(SpdyStreamId stream_id,const char * headers_data,size_t headers_data_length)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;
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
ParseBlockLength(Reader * reader)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;
130 }
131 if (error_ == OK) {
132 handler_->OnHeaderBlock(stream_id_, remaining_key_value_pairs_for_frame_);
133 }
134 }
135
ParseFieldLength(Reader * reader)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;
141 }
142 }
143
ParseLength(Reader * reader,uint32_t * parsed_length)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;
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
Reset()159 void 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
LengthFieldSizeForVersion(SpdyMajorVersion spdy_version)174 size_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
MaxNumberOfHeadersForVersion(SpdyMajorVersion spdy_version)182 size_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