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

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

Issue 992733002: Remove //net (except for Android test stuff) and sdch (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 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
« no previous file with comments | « net/spdy/hpack_encoder.h ('k') | net/spdy/hpack_encoder_test.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 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/hpack_encoder.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "net/spdy/hpack_header_table.h"
11 #include "net/spdy/hpack_huffman_table.h"
12 #include "net/spdy/hpack_output_stream.h"
13
14 namespace net {
15
16 using base::StringPiece;
17 using std::string;
18
19 HpackEncoder::HpackEncoder(const HpackHuffmanTable& table)
20 : output_stream_(),
21 allow_huffman_compression_(true),
22 huffman_table_(table),
23 char_counts_(NULL),
24 total_char_counts_(NULL) {}
25
26 HpackEncoder::~HpackEncoder() {}
27
28 bool HpackEncoder::EncodeHeaderSet(const std::map<string, string>& header_set,
29 string* output) {
30 // Separate header set into pseudo-headers and regular headers.
31 Representations pseudo_headers;
32 Representations regular_headers;
33 for (std::map<string, string>::const_iterator it = header_set.begin();
34 it != header_set.end(); ++it) {
35 if (it->first == "cookie") {
36 // Note that there can only be one "cookie" header, because header_set is
37 // a map.
38 CookieToCrumbs(*it, &regular_headers);
39 } else if (it->first[0] == kPseudoHeaderPrefix) {
40 DecomposeRepresentation(*it, &pseudo_headers);
41 } else {
42 DecomposeRepresentation(*it, &regular_headers);
43 }
44 }
45
46 // Encode pseudo-headers.
47 for (Representations::const_iterator it = pseudo_headers.begin();
48 it != pseudo_headers.end(); ++it) {
49 const HpackEntry* entry =
50 header_table_.GetByNameAndValue(it->first, it->second);
51 if (entry != NULL) {
52 EmitIndex(entry);
53 } else {
54 if (it->first == ":authority") {
55 // :authority is always present and rarely changes, and has moderate
56 // length, therefore it makes a lot of sense to index (insert in the
57 // header table).
58 EmitIndexedLiteral(*it);
59 } else {
60 // Most common pseudo-header fields are represented in the static table,
61 // while uncommon ones are small, so do not index them.
62 EmitNonIndexedLiteral(*it);
63 }
64 }
65 }
66
67 // Encode regular headers.
68 for (Representations::const_iterator it = regular_headers.begin();
69 it != regular_headers.end(); ++it) {
70 const HpackEntry* entry =
71 header_table_.GetByNameAndValue(it->first, it->second);
72 if (entry != NULL) {
73 EmitIndex(entry);
74 } else {
75 EmitIndexedLiteral(*it);
76 }
77 }
78
79 output_stream_.TakeString(output);
80 return true;
81 }
82
83 bool HpackEncoder::EncodeHeaderSetWithoutCompression(
84 const std::map<string, string>& header_set,
85 string* output) {
86
87 allow_huffman_compression_ = false;
88 for (std::map<string, string>::const_iterator it = header_set.begin();
89 it != header_set.end(); ++it) {
90 // Note that cookies are not crumbled in this case.
91 EmitNonIndexedLiteral(*it);
92 }
93 allow_huffman_compression_ = true;
94 output_stream_.TakeString(output);
95 return true;
96 }
97
98 void HpackEncoder::EmitIndex(const HpackEntry* entry) {
99 output_stream_.AppendPrefix(kIndexedOpcode);
100 output_stream_.AppendUint32(header_table_.IndexOf(entry));
101 }
102
103 void HpackEncoder::EmitIndexedLiteral(const Representation& representation) {
104 output_stream_.AppendPrefix(kLiteralIncrementalIndexOpcode);
105 EmitLiteral(representation);
106 header_table_.TryAddEntry(representation.first, representation.second);
107 }
108
109 void HpackEncoder::EmitNonIndexedLiteral(
110 const Representation& representation) {
111 output_stream_.AppendPrefix(kLiteralNoIndexOpcode);
112 output_stream_.AppendUint32(0);
113 EmitString(representation.first);
114 EmitString(representation.second);
115 }
116
117 void HpackEncoder::EmitLiteral(const Representation& representation) {
118 const HpackEntry* name_entry = header_table_.GetByName(representation.first);
119 if (name_entry != NULL) {
120 output_stream_.AppendUint32(header_table_.IndexOf(name_entry));
121 } else {
122 output_stream_.AppendUint32(0);
123 EmitString(representation.first);
124 }
125 EmitString(representation.second);
126 }
127
128 void HpackEncoder::EmitString(StringPiece str) {
129 size_t encoded_size = (!allow_huffman_compression_ ? str.size()
130 : huffman_table_.EncodedSize(str));
131 if (encoded_size < str.size()) {
132 output_stream_.AppendPrefix(kStringLiteralHuffmanEncoded);
133 output_stream_.AppendUint32(encoded_size);
134 huffman_table_.EncodeString(str, &output_stream_);
135 } else {
136 output_stream_.AppendPrefix(kStringLiteralIdentityEncoded);
137 output_stream_.AppendUint32(str.size());
138 output_stream_.AppendBytes(str);
139 }
140 UpdateCharacterCounts(str);
141 }
142
143 void HpackEncoder::SetCharCountsStorage(std::vector<size_t>* char_counts,
144 size_t* total_char_counts) {
145 CHECK_LE(256u, char_counts->size());
146 char_counts_ = char_counts;
147 total_char_counts_ = total_char_counts;
148 }
149
150 void HpackEncoder::UpdateCharacterCounts(base::StringPiece str) {
151 if (char_counts_ == NULL || total_char_counts_ == NULL) {
152 return;
153 }
154 for (StringPiece::const_iterator it = str.begin(); it != str.end(); ++it) {
155 ++(*char_counts_)[static_cast<uint8>(*it)];
156 }
157 (*total_char_counts_) += str.size();
158 }
159
160 // static
161 void HpackEncoder::CookieToCrumbs(const Representation& cookie,
162 Representations* out) {
163 size_t prior_size = out->size();
164
165 // See Section 8.1.2.5. "Compressing the Cookie Header Field" in the HTTP/2
166 // specification at https://tools.ietf.org/html/draft-ietf-httpbis-http2-14.
167 // Cookie values are split into individually-encoded HPACK representations.
168 for (size_t pos = 0;;) {
169 size_t end = cookie.second.find(";", pos);
170
171 if (end == StringPiece::npos) {
172 out->push_back(make_pair(
173 cookie.first,
174 cookie.second.substr(pos)));
175 break;
176 }
177 out->push_back(make_pair(
178 cookie.first,
179 cookie.second.substr(pos, end - pos)));
180
181 // Consume next space if present.
182 pos = end + 1;
183 if (pos != cookie.second.size() && cookie.second[pos] == ' ') {
184 pos++;
185 }
186 }
187 // Sort crumbs and remove duplicates.
188 std::sort(out->begin() + prior_size, out->end());
189 out->erase(std::unique(out->begin() + prior_size, out->end()),
190 out->end());
191 }
192
193 // static
194 void HpackEncoder::DecomposeRepresentation(const Representation& header_field,
195 Representations* out) {
196 size_t pos = 0;
197 size_t end = 0;
198 while (end != StringPiece::npos) {
199 end = header_field.second.find('\0', pos);
200 out->push_back(make_pair(header_field.first,
201 header_field.second.substr(pos, end - pos)));
202 pos = end + 1;
203 }
204 }
205
206 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/hpack_encoder.h ('k') | net/spdy/hpack_encoder_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698