Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1010)

Side by Side Diff: net/spdy/http2_decompressor.cc

Issue 22074002: DO NOT COMMIT: Implement HPACK (draft 03) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update for httpbis-draft-06 / hpack-draft-03 Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/spdy/http2_decompressor.h ('k') | net/spdy/http2_decompressor_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013 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/http2_decompressor.h"
6
7 #include <cstddef>
8
9 #include "base/logging.h"
10
11 namespace net {
12
13 namespace {
14
15 class Http2Decoder {
16 public:
17 Http2Decoder(const char* buffer,
18 size_t buffer_size,
19 EncodingContext* encoding_context,
20 SpdyNameValueBlock* out);
21
22 bool HasMoreData() const;
23
24 void EmitHeader(const std::string& name, const std::string& value);
25
26 bool ProcessNextHeaderRepresentation();
27
28 private:
29 bool PeekNextOctet(uint8* next_octet);
30
31 bool DecodeNextOctet(uint8* next_octet);
32
33 bool DecodeNextInteger(uint8 N, uint32* I);
34
35 bool DecodeNextOctetSequence(std::string* str);
36
37 bool DecodeNextName(uint8 N, std::string* next_name);
38
39 bool DecodeNextValue(std::string* next_value);
40
41 const char* const buffer_;
42 const size_t buffer_size_;
43 EncodingContext* const encoding_context_;
44 SpdyNameValueBlock* out_;
45 size_t i_;
46
47 DISALLOW_COPY_AND_ASSIGN(Http2Decoder);
48 };
49
50 Http2Decoder::Http2Decoder(const char* buffer,
51 size_t buffer_size,
52 EncodingContext* encoding_context,
53 SpdyNameValueBlock* out)
54 : buffer_(buffer),
55 buffer_size_(buffer_size),
56 encoding_context_(encoding_context),
57 out_(out),
58 i_(0) {}
59
60 bool Http2Decoder::HasMoreData() const {
61 return i_ < buffer_size_;
62 }
63
64 void Http2Decoder::EmitHeader(const std::string& name,
65 const std::string& value) {
66 VLOG(1) << "Emitting " << name << " " << value;
67 if (out_->find(name) == out_->end()) {
68 (*out_)[name] = value;
69 } else {
70 std::string new_value = (*out_)[name];
71 new_value.append(1, '\0'); // +=() doesn't append 0's
72 new_value += value;
73 (*out_)[name] = new_value;
74 }
75 }
76
77 bool Http2Decoder::ProcessNextHeaderRepresentation() {
78 uint8 next_octet = 0;
79 if (!PeekNextOctet(&next_octet))
80 return false;
81
82 if ((next_octet >> kIndexN) == kIndexOpcode) {
83 uint32 index = 0;
84 DecodeNextInteger(7, &index);
85 encoding_context_->ProcessIndexedHeader(index);
86 if (!encoding_context_->IsReferenced(index)) {
87 return true;
88 }
89 encoding_context_->AddTouches(index, 0);
90 std::string name;
91 if (!encoding_context_->GetIndexedHeaderName(index, &name)) {
92 return false;
93 }
94 std::string value;
95 if (!encoding_context_->GetIndexedHeaderValue(index, &value)) {
96 return false;
97 }
98 EmitHeader(name, value);
99 return true;
100 }
101
102 if ((next_octet >> kLiteralNoIndexN) == kLiteralNoIndexOpcode) {
103 std::string name;
104 if (!DecodeNextName(kLiteralNoIndexN, &name))
105 return false;
106 std::string value;
107 if (!DecodeNextValue(&value))
108 return false;
109 EmitHeader(name, value);
110 return true;
111 }
112
113 if ((next_octet >> kLiteralIncrementalN) == kLiteralIncrementalOpcode) {
114 std::string name;
115 if (!DecodeNextName(kLiteralIncrementalN, &name))
116 return false;
117 std::string value;
118 if (!DecodeNextValue(&value))
119 return false;
120 int32 index = 0;
121 std::vector<uint32> removed_referenced_indices;
122 encoding_context_->ProcessLiteralHeaderWithIncrementalIndexing(
123 name, value, &index, &removed_referenced_indices);
124 if (index >= 0) {
125 encoding_context_->AddTouches(index, 0);
126 }
127 EmitHeader(name, value);
128 return true;
129 }
130
131 if ((next_octet >> kLiteralSubstitutionN) == kLiteralSubstitutionOpcode) {
132 std::string name;
133 if (!DecodeNextName(kLiteralSubstitutionN, &name))
134 return false;
135 uint32 substituted_index = 0;
136 if (!DecodeNextInteger(0, &substituted_index))
137 return false;
138 std::string value;
139 if (!DecodeNextValue(&value))
140 return false;
141 int32 index = 0;
142 std::vector<uint32> removed_referenced_indices;
143 encoding_context_->ProcessLiteralHeaderWithSubstitutionIndexing(
144 name, substituted_index, value, &index, &removed_referenced_indices);
145 if (index >= 0) {
146 encoding_context_->AddTouches(index, 0);
147 }
148 EmitHeader(name, value);
149 return true;
150 }
151
152 LOG(ERROR) << "Invalid opcode 0x" << std::hex << static_cast<int>(next_octet);
153 return false;
154 }
155
156 bool Http2Decoder::PeekNextOctet(uint8* next_octet) {
157 if (!HasMoreData()) {
158 LOG(ERROR) << "HasMoreData returned false in PeekNextOctet";
159 return false;
160 }
161
162 *next_octet = buffer_[i_];
163 return true;
164 }
165
166 bool Http2Decoder::DecodeNextOctet(uint8* next_octet) {
167 if (!PeekNextOctet(next_octet))
168 return false;
169
170 ++i_;
171 return true;
172 }
173
174 bool Http2Decoder::DecodeNextInteger(uint8 N, uint32* I) {
175 *I = 0;
176 bool has_more = true;
177 uint8 shift = N;
178
179 if (N > 0) {
180 uint8 next_marker = (1 << N) - 1;
181 uint8 next_octet = 0;
182 if (!DecodeNextOctet(&next_octet))
183 return false;
184 *I = next_octet & next_marker;
185 has_more = (*I == next_marker);
186 }
187
188 while (has_more) {
189 uint8 next_octet = 0;
190 if (!DecodeNextOctet(&next_octet))
191 return false;
192 has_more = (next_octet & 0x80) != 0;
193 *I += (next_octet % 128) << shift;
194 shift += 7;
195 }
196
197 return true;
198 }
199
200 bool Http2Decoder::DecodeNextOctetSequence(std::string* str) {
201 uint32 size = 0;
202 if (!DecodeNextInteger(0, &size)) {
203 return false;
204 }
205 if ((i_ + size) > buffer_size_) {
206 LOG(ERROR) << "Invalid size " << size;
207 return false;
208 }
209 str->assign(buffer_ + i_, size);
210 i_ += size;
211 return true;
212 }
213
214 bool Http2Decoder::DecodeNextName(uint8 N, std::string* next_name) {
215 uint32 index_plus_one_or_zero = 0;
216 if (!DecodeNextInteger(N, &index_plus_one_or_zero))
217 return false;
218 if (index_plus_one_or_zero == 0) {
219 if (!DecodeNextOctetSequence(next_name))
220 return false;
221 } else {
222 uint32 index = index_plus_one_or_zero - 1;
223 if (!encoding_context_->GetIndexedHeaderName(index, next_name)) {
224 LOG(ERROR) << "Invalid index " << index;
225 return false;
226 }
227 }
228 if (!IsValidHeaderName(*next_name)) {
229 LOG(ERROR) << "Invalid name " << *next_name;
230 return false;
231 }
232 return true;
233 }
234
235 bool Http2Decoder::DecodeNextValue(std::string* next_value) {
236 if (!DecodeNextOctetSequence(next_value))
237 return false;
238 if (!IsValidHeaderValue(*next_value)) {
239 LOG(ERROR) << "Invalid value " << *next_value;
240 return false;
241 }
242 return true;
243 }
244
245 } // namespace
246
247 Http2Decompressor::Http2Decompressor() : encoding_context_(HTTP2_REQUEST) {}
248
249 Http2Decompressor::~Http2Decompressor() {}
250
251 bool Http2Decompressor::DecodeNameValueBlock(const char* data, size_t len,
252 SpdyNameValueBlock* out) {
253 Http2Decoder decoder(data, len, &encoding_context_, out);
254 while (decoder.HasMoreData()) {
255 if (!decoder.ProcessNextHeaderRepresentation()) {
256 LOG(INFO) << "Error processing next header representation";
257 return false;
258 }
259 }
260
261 for (size_t i = 0; i < encoding_context_.GetEntryCount(); ++i) {
262 HeaderTableEntry* entry = encoding_context_.GetMutableEntry(i);
263 if (entry->referenced && (entry->touch_count == kUntouched)) {
264 decoder.EmitHeader(entry->name, entry->value);
265 }
266 entry->touch_count = kUntouched;
267 }
268
269 return true;
270 }
271
272 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/http2_decompressor.h ('k') | net/spdy/http2_decompressor_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698