Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / net / spdy / spdy_headers_block_parser.cc
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 <memory>
8
9 #include "base/sys_byteorder.h"
10
11 namespace net {
12
13 SpdyHeadersBlockParserReader::SpdyHeadersBlockParserReader(
14     base::StringPiece prefix,
15     base::StringPiece suffix)
16       : prefix_(prefix),
17         suffix_(suffix),
18         in_suffix_(false),
19         offset_(0) {}
20
21 size_t SpdyHeadersBlockParserReader::Available() {
22   if (in_suffix_) {
23     return suffix_.length() - offset_;
24   } else {
25     return prefix_.length() + suffix_.length() - offset_;
26   }
27 }
28
29 bool SpdyHeadersBlockParserReader::ReadN(size_t count, char* out) {
30   if (Available() < count)
31     return false;
32
33   if (!in_suffix_ && count > (prefix_.length() - offset_)) {
34     count -= prefix_.length() - offset_;
35     out = std::copy(prefix_.begin() + offset_, prefix_.end(), out);
36     in_suffix_ = true;
37     offset_ = 0;
38     // Fallthrough to suffix read.
39   } else if (!in_suffix_) {
40     // Read is satisfied by the prefix.
41     DCHECK_GE(prefix_.length() - offset_, count);
42     std::copy(prefix_.begin() + offset_,
43               prefix_.begin() + offset_ + count,
44               out);
45     offset_ += count;
46     return true;
47   }
48   // Read is satisfied by the suffix.
49   DCHECK(in_suffix_);
50   DCHECK_GE(suffix_.length() - offset_, count);
51   std::copy(suffix_.begin() + offset_,
52             suffix_.begin() + offset_ + count,
53             out);
54   offset_ += count;
55   return true;
56 }
57
58 std::vector<char> SpdyHeadersBlockParserReader::Remainder() {
59   std::vector<char> remainder(Available(), '\0');
60   if (remainder.size()) {
61     ReadN(remainder.size(), &remainder[0]);
62   }
63   DCHECK_EQ(0u, Available());
64   return remainder;
65 }
66
67 SpdyHeadersBlockParser::SpdyHeadersBlockParser(
68     SpdyHeadersHandlerInterface* handler) : state_(READING_HEADER_BLOCK_LEN),
69     remaining_key_value_pairs_for_frame_(0), next_field_len_(0),
70     handler_(handler) {
71 }
72
73 SpdyHeadersBlockParser::~SpdyHeadersBlockParser() {}
74
75 bool SpdyHeadersBlockParser::ParseUInt32(Reader* reader,
76                                          uint32_t* parsed_value) {
77   // Are there enough bytes available?
78   if (reader->Available() < sizeof(uint32_t)) {
79     return false;
80   }
81
82   // Read the required bytes, convert from network to host
83   // order and return the parsed out integer.
84   char buf[sizeof(uint32_t)];
85   reader->ReadN(sizeof(uint32_t), buf);
86   *parsed_value = base::NetToHost32(*reinterpret_cast<const uint32_t *>(buf));
87   return true;
88 }
89
90 void SpdyHeadersBlockParser::Reset() {
91   // Clear any saved state about the last headers block.
92   headers_block_prefix_.clear();
93   state_ = READING_HEADER_BLOCK_LEN;
94 }
95
96 void SpdyHeadersBlockParser::HandleControlFrameHeadersData(
97     const char* headers_data, size_t len) {
98   // Only do something if we received anything new.
99   if (len == 0) {
100     return;
101   }
102
103   // Reader avoids copying data.
104   base::StringPiece prefix;
105   if (headers_block_prefix_.size()) {
106     prefix.set(&headers_block_prefix_[0], headers_block_prefix_.size());
107   }
108   Reader reader(prefix, base::StringPiece(headers_data, len));
109
110   // If we didn't parse out yet the number of key-value pairs in this
111   // headers block, try to do it now (succeeds if we received enough bytes).
112   if (state_ == READING_HEADER_BLOCK_LEN) {
113     if (ParseUInt32(&reader, &remaining_key_value_pairs_for_frame_)) {
114       handler_->OnHeaderBlock(remaining_key_value_pairs_for_frame_);
115       state_ = READING_KEY_LEN;
116     } else {
117       headers_block_prefix_ = reader.Remainder();
118       return;
119     }
120   }
121
122   // Parse out and handle the key-value pairs.
123   while (remaining_key_value_pairs_for_frame_ > 0) {
124     // Parse the key-value length, in case we don't already have it.
125     if ((state_ == READING_KEY_LEN) || (state_ == READING_VALUE_LEN)) {
126       if (ParseUInt32(&reader, &next_field_len_)) {
127         state_ == READING_KEY_LEN ? state_ = READING_KEY :
128                                     state_ = READING_VALUE;
129       } else {
130         // Did not receive enough bytes.
131         break;
132       }
133     }
134
135     // Parse the next field if we received enough bytes.
136     if (reader.Available() >= next_field_len_) {
137       // Copy the field from the cord.
138       char* key_value_buf(new char[next_field_len_]);
139       reader.ReadN(next_field_len_, key_value_buf);
140
141       // Is this field a key?
142       if (state_ == READING_KEY) {
143         current_key.reset(key_value_buf);
144         key_len_ = next_field_len_;
145         state_ = READING_VALUE_LEN;
146
147       } else if (state_ == READING_VALUE) {
148         // We already had the key, now we got its value.
149         current_value.reset(key_value_buf);
150
151         // Call the handler for the key-value pair that we received.
152         handler_->OnKeyValuePair(
153             base::StringPiece(current_key.get(), key_len_),
154             base::StringPiece(current_value.get(), next_field_len_));
155
156         // Free allocated key and value strings.
157         current_key.reset();
158         current_value.reset();
159
160         // Finished handling a key-value pair.
161         remaining_key_value_pairs_for_frame_--;
162
163         // Finished handling a header, prepare for the next one.
164         state_ = READING_KEY_LEN;
165       }
166     } else {
167       // Did not receive enough bytes.
168       break;
169     }
170   }
171
172   // Unread suffix becomes the prefix upon next invocation.
173   headers_block_prefix_ = reader.Remainder();
174
175   // Did we finish handling the current block?
176   if (remaining_key_value_pairs_for_frame_ == 0) {
177     handler_->OnHeaderBlockEnd();
178     Reset();
179   }
180 }
181
182 }  // namespace net