| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/spdy/hpack/hpack_encoder.h" | 5 #include "net/spdy/hpack/hpack_encoder.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 } | 75 } |
| 76 | 76 |
| 77 } // namespace | 77 } // namespace |
| 78 | 78 |
| 79 HpackEncoder::HpackEncoder(const HpackHuffmanTable& table) | 79 HpackEncoder::HpackEncoder(const HpackHuffmanTable& table) |
| 80 : output_stream_(), | 80 : output_stream_(), |
| 81 huffman_table_(table), | 81 huffman_table_(table), |
| 82 min_table_size_setting_received_(std::numeric_limits<size_t>::max()), | 82 min_table_size_setting_received_(std::numeric_limits<size_t>::max()), |
| 83 listener_(NoOpListener), | 83 listener_(NoOpListener), |
| 84 should_index_(DefaultPolicy), | 84 should_index_(DefaultPolicy), |
| 85 allow_huffman_compression_(true), | 85 enable_compression_(true), |
| 86 should_emit_table_size_(false) {} | 86 should_emit_table_size_(false) {} |
| 87 | 87 |
| 88 HpackEncoder::~HpackEncoder() {} | 88 HpackEncoder::~HpackEncoder() {} |
| 89 | 89 |
| 90 void HpackEncoder::EncodeHeaderSet(const Representations& representations, | 90 void HpackEncoder::EncodeHeaderSet(const Representations& representations, |
| 91 string* output) { | 91 string* output) { |
| 92 RepresentationIterator iter(representations); | 92 RepresentationIterator iter(representations); |
| 93 EncodeRepresentations(&iter, output); | 93 EncodeRepresentations(&iter, output); |
| 94 } | 94 } |
| 95 | 95 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 113 } | 113 } |
| 114 } | 114 } |
| 115 | 115 |
| 116 { | 116 { |
| 117 RepresentationIterator iter(pseudo_headers, regular_headers); | 117 RepresentationIterator iter(pseudo_headers, regular_headers); |
| 118 EncodeRepresentations(&iter, output); | 118 EncodeRepresentations(&iter, output); |
| 119 } | 119 } |
| 120 return true; | 120 return true; |
| 121 } | 121 } |
| 122 | 122 |
| 123 bool HpackEncoder::EncodeHeaderSetWithoutCompression( | |
| 124 const SpdyHeaderBlock& header_set, | |
| 125 string* output) { | |
| 126 allow_huffman_compression_ = false; | |
| 127 MaybeEmitTableSize(); | |
| 128 for (const auto& header : header_set) { | |
| 129 listener_(header.first, header.second); | |
| 130 // Note that cookies are not crumbled in this case. | |
| 131 EmitNonIndexedLiteral(header); | |
| 132 } | |
| 133 allow_huffman_compression_ = true; | |
| 134 output_stream_.TakeString(output); | |
| 135 return true; | |
| 136 } | |
| 137 | |
| 138 void HpackEncoder::ApplyHeaderTableSizeSetting(size_t size_setting) { | 123 void HpackEncoder::ApplyHeaderTableSizeSetting(size_t size_setting) { |
| 139 if (size_setting == header_table_.settings_size_bound()) { | 124 if (size_setting == header_table_.settings_size_bound()) { |
| 140 return; | 125 return; |
| 141 } | 126 } |
| 142 if (size_setting < header_table_.settings_size_bound()) { | 127 if (size_setting < header_table_.settings_size_bound()) { |
| 143 min_table_size_setting_received_ = | 128 min_table_size_setting_received_ = |
| 144 std::min(size_setting, min_table_size_setting_received_); | 129 std::min(size_setting, min_table_size_setting_received_); |
| 145 } | 130 } |
| 146 header_table_.SetSettingsHeaderTableSize(size_setting); | 131 header_table_.SetSettingsHeaderTableSize(size_setting); |
| 147 should_emit_table_size_ = true; | 132 should_emit_table_size_ = true; |
| 148 } | 133 } |
| 149 | 134 |
| 150 void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter, | 135 void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter, |
| 151 string* output) { | 136 string* output) { |
| 152 MaybeEmitTableSize(); | 137 MaybeEmitTableSize(); |
| 153 while (iter->HasNext()) { | 138 while (iter->HasNext()) { |
| 154 const auto header = iter->Next(); | 139 const auto header = iter->Next(); |
| 155 listener_(header.first, header.second); | 140 listener_(header.first, header.second); |
| 156 const HpackEntry* entry = | 141 if (enable_compression_) { |
| 157 header_table_.GetByNameAndValue(header.first, header.second); | 142 const HpackEntry* entry = |
| 158 if (entry != nullptr) { | 143 header_table_.GetByNameAndValue(header.first, header.second); |
| 159 EmitIndex(entry); | 144 if (entry != nullptr) { |
| 160 } else if (should_index_(header.first, header.second)) { | 145 EmitIndex(entry); |
| 161 EmitIndexedLiteral(header); | 146 } else if (should_index_(header.first, header.second)) { |
| 147 EmitIndexedLiteral(header); |
| 148 } else { |
| 149 EmitNonIndexedLiteral(header); |
| 150 } |
| 162 } else { | 151 } else { |
| 163 EmitNonIndexedLiteral(header); | 152 EmitNonIndexedLiteral(header); |
| 164 } | 153 } |
| 165 } | 154 } |
| 166 | 155 |
| 167 output_stream_.TakeString(output); | 156 output_stream_.TakeString(output); |
| 168 } | 157 } |
| 169 | 158 |
| 170 void HpackEncoder::EmitIndex(const HpackEntry* entry) { | 159 void HpackEncoder::EmitIndex(const HpackEntry* entry) { |
| 171 output_stream_.AppendPrefix(kIndexedOpcode); | 160 output_stream_.AppendPrefix(kIndexedOpcode); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 191 output_stream_.AppendUint32(header_table_.IndexOf(name_entry)); | 180 output_stream_.AppendUint32(header_table_.IndexOf(name_entry)); |
| 192 } else { | 181 } else { |
| 193 output_stream_.AppendUint32(0); | 182 output_stream_.AppendUint32(0); |
| 194 EmitString(representation.first); | 183 EmitString(representation.first); |
| 195 } | 184 } |
| 196 EmitString(representation.second); | 185 EmitString(representation.second); |
| 197 } | 186 } |
| 198 | 187 |
| 199 void HpackEncoder::EmitString(StringPiece str) { | 188 void HpackEncoder::EmitString(StringPiece str) { |
| 200 size_t encoded_size = | 189 size_t encoded_size = |
| 201 (!allow_huffman_compression_ ? str.size() | 190 enable_compression_ ? huffman_table_.EncodedSize(str) : str.size(); |
| 202 : huffman_table_.EncodedSize(str)); | |
| 203 if (encoded_size < str.size()) { | 191 if (encoded_size < str.size()) { |
| 204 output_stream_.AppendPrefix(kStringLiteralHuffmanEncoded); | 192 output_stream_.AppendPrefix(kStringLiteralHuffmanEncoded); |
| 205 output_stream_.AppendUint32(encoded_size); | 193 output_stream_.AppendUint32(encoded_size); |
| 206 huffman_table_.EncodeString(str, &output_stream_); | 194 huffman_table_.EncodeString(str, &output_stream_); |
| 207 } else { | 195 } else { |
| 208 output_stream_.AppendPrefix(kStringLiteralIdentityEncoded); | 196 output_stream_.AppendPrefix(kStringLiteralIdentityEncoded); |
| 209 output_stream_.AppendUint32(str.size()); | 197 output_stream_.AppendUint32(str.size()); |
| 210 output_stream_.AppendBytes(str); | 198 output_stream_.AppendBytes(str); |
| 211 } | 199 } |
| 212 } | 200 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 | 267 |
| 280 // static | 268 // static |
| 281 void HpackEncoder::GatherRepresentation(const Representation& header_field, | 269 void HpackEncoder::GatherRepresentation(const Representation& header_field, |
| 282 Representations* out) { | 270 Representations* out) { |
| 283 out->push_back(std::make_pair(header_field.first, header_field.second)); | 271 out->push_back(std::make_pair(header_field.first, header_field.second)); |
| 284 } | 272 } |
| 285 | 273 |
| 286 // Iteratively encodes a SpdyHeaderBlock. | 274 // Iteratively encodes a SpdyHeaderBlock. |
| 287 class HpackEncoder::Encoderator : public ProgressiveEncoder { | 275 class HpackEncoder::Encoderator : public ProgressiveEncoder { |
| 288 public: | 276 public: |
| 289 Encoderator(const SpdyHeaderBlock& header_set, | 277 Encoderator(const SpdyHeaderBlock& header_set, HpackEncoder* encoder); |
| 290 HpackEncoder* encoder, | |
| 291 bool use_compression); | |
| 292 | 278 |
| 293 // Encoderator is neither copyable nor movable. | 279 // Encoderator is neither copyable nor movable. |
| 294 Encoderator(const Encoderator&) = delete; | 280 Encoderator(const Encoderator&) = delete; |
| 295 Encoderator& operator=(const Encoderator&) = delete; | 281 Encoderator& operator=(const Encoderator&) = delete; |
| 296 | 282 |
| 297 // Returns true iff more remains to encode. | 283 // Returns true iff more remains to encode. |
| 298 bool HasNext() const override { return has_next_; } | 284 bool HasNext() const override { return has_next_; } |
| 299 | 285 |
| 300 // Encodes up to max_encoded_bytes of the current header block into the | 286 // Encodes up to max_encoded_bytes of the current header block into the |
| 301 // given output string. | 287 // given output string. |
| 302 void Next(size_t max_encoded_bytes, string* output) override; | 288 void Next(size_t max_encoded_bytes, string* output) override; |
| 303 | 289 |
| 304 private: | 290 private: |
| 305 HpackEncoder* encoder_; | 291 HpackEncoder* encoder_; |
| 306 std::unique_ptr<RepresentationIterator> header_it_; | 292 std::unique_ptr<RepresentationIterator> header_it_; |
| 307 Representations pseudo_headers_; | 293 Representations pseudo_headers_; |
| 308 Representations regular_headers_; | 294 Representations regular_headers_; |
| 309 bool has_next_; | 295 bool has_next_; |
| 310 bool use_compression_; | |
| 311 }; | 296 }; |
| 312 | 297 |
| 313 HpackEncoder::Encoderator::Encoderator(const SpdyHeaderBlock& header_set, | 298 HpackEncoder::Encoderator::Encoderator(const SpdyHeaderBlock& header_set, |
| 314 HpackEncoder* encoder, | 299 HpackEncoder* encoder) |
| 315 bool use_compression) | 300 : encoder_(encoder), has_next_(true) { |
| 316 : encoder_(encoder), has_next_(true), use_compression_(use_compression) { | |
| 317 // Separate header set into pseudo-headers and regular headers. | 301 // Separate header set into pseudo-headers and regular headers. |
| 302 const bool use_compression = encoder_->enable_compression_; |
| 318 bool found_cookie = false; | 303 bool found_cookie = false; |
| 319 for (const auto& header : header_set) { | 304 for (const auto& header : header_set) { |
| 320 if (!found_cookie && header.first == "cookie") { | 305 if (!found_cookie && header.first == "cookie") { |
| 321 // Note that there can only be one "cookie" header, because header_set | 306 // Note that there can only be one "cookie" header, because header_set |
| 322 // is a map. | 307 // is a map. |
| 323 found_cookie = true; | 308 found_cookie = true; |
| 324 use_compression_ ? CookieToCrumbs(header, ®ular_headers_) | 309 CookieToCrumbs(header, ®ular_headers_); |
| 325 : GatherRepresentation(header, ®ular_headers_); | |
| 326 } else if (!header.first.empty() && | 310 } else if (!header.first.empty() && |
| 327 header.first[0] == kPseudoHeaderPrefix) { | 311 header.first[0] == kPseudoHeaderPrefix) { |
| 328 use_compression_ ? DecomposeRepresentation(header, &pseudo_headers_) | 312 use_compression ? DecomposeRepresentation(header, &pseudo_headers_) |
| 329 : GatherRepresentation(header, &pseudo_headers_); | 313 : GatherRepresentation(header, &pseudo_headers_); |
| 330 } else { | 314 } else { |
| 331 use_compression_ ? DecomposeRepresentation(header, ®ular_headers_) | 315 use_compression ? DecomposeRepresentation(header, ®ular_headers_) |
| 332 : GatherRepresentation(header, ®ular_headers_); | 316 : GatherRepresentation(header, ®ular_headers_); |
| 333 } | 317 } |
| 334 } | 318 } |
| 335 header_it_ = base::MakeUnique<RepresentationIterator>(pseudo_headers_, | 319 header_it_ = base::MakeUnique<RepresentationIterator>(pseudo_headers_, |
| 336 regular_headers_); | 320 regular_headers_); |
| 337 | 321 |
| 338 encoder_->MaybeEmitTableSize(); | 322 encoder_->MaybeEmitTableSize(); |
| 339 } | 323 } |
| 340 | 324 |
| 341 void HpackEncoder::Encoderator::Next(size_t max_encoded_bytes, string* output) { | 325 void HpackEncoder::Encoderator::Next(size_t max_encoded_bytes, string* output) { |
| 342 SPDY_BUG_IF(!has_next_) | 326 SPDY_BUG_IF(!has_next_) |
| 343 << "Encoderator::Next called with nothing left to encode."; | 327 << "Encoderator::Next called with nothing left to encode."; |
| 328 const bool use_compression = encoder_->enable_compression_; |
| 344 | 329 |
| 345 // Encode up to max_encoded_bytes of headers. | 330 // Encode up to max_encoded_bytes of headers. |
| 346 while (header_it_->HasNext() && | 331 while (header_it_->HasNext() && |
| 347 encoder_->output_stream_.size() <= max_encoded_bytes) { | 332 encoder_->output_stream_.size() <= max_encoded_bytes) { |
| 348 const Representation header = header_it_->Next(); | 333 const Representation header = header_it_->Next(); |
| 349 encoder_->listener_(header.first, header.second); | 334 encoder_->listener_(header.first, header.second); |
| 350 if (use_compression_) { | 335 if (use_compression) { |
| 351 const HpackEntry* entry = encoder_->header_table_.GetByNameAndValue( | 336 const HpackEntry* entry = encoder_->header_table_.GetByNameAndValue( |
| 352 header.first, header.second); | 337 header.first, header.second); |
| 353 if (entry != nullptr) { | 338 if (entry != nullptr) { |
| 354 encoder_->EmitIndex(entry); | 339 encoder_->EmitIndex(entry); |
| 355 } else if (encoder_->should_index_(header.first, header.second)) { | 340 } else if (encoder_->should_index_(header.first, header.second)) { |
| 356 encoder_->EmitIndexedLiteral(header); | 341 encoder_->EmitIndexedLiteral(header); |
| 357 } else { | 342 } else { |
| 358 encoder_->EmitNonIndexedLiteral(header); | 343 encoder_->EmitNonIndexedLiteral(header); |
| 359 } | 344 } |
| 360 } else { | 345 } else { |
| 361 encoder_->allow_huffman_compression_ = false; | |
| 362 encoder_->EmitNonIndexedLiteral(header); | 346 encoder_->EmitNonIndexedLiteral(header); |
| 363 encoder_->allow_huffman_compression_ = true; | |
| 364 } | 347 } |
| 365 } | 348 } |
| 366 | 349 |
| 367 has_next_ = encoder_->output_stream_.size() > max_encoded_bytes; | 350 has_next_ = encoder_->output_stream_.size() > max_encoded_bytes; |
| 368 encoder_->output_stream_.BoundedTakeString(max_encoded_bytes, output); | 351 encoder_->output_stream_.BoundedTakeString(max_encoded_bytes, output); |
| 369 } | 352 } |
| 370 | 353 |
| 371 std::unique_ptr<HpackEncoder::ProgressiveEncoder> HpackEncoder::EncodeHeaderSet( | 354 std::unique_ptr<HpackEncoder::ProgressiveEncoder> HpackEncoder::EncodeHeaderSet( |
| 372 const SpdyHeaderBlock& header_set, | 355 const SpdyHeaderBlock& header_set) { |
| 373 bool use_compression) { | 356 return base::MakeUnique<Encoderator>(header_set, this); |
| 374 return base::MakeUnique<Encoderator>(header_set, this, use_compression); | |
| 375 } | 357 } |
| 376 | 358 |
| 377 } // namespace net | 359 } // namespace net |
| OLD | NEW |