| OLD | NEW |
| (Empty) |
| 1 // Copyright 2017 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/hpack_decoder3.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "net/http2/decoder/decode_buffer.h" | |
| 9 #include "net/http2/decoder/decode_status.h" | |
| 10 #include "net/spdy/platform/api/spdy_estimate_memory_usage.h" | |
| 11 #include "net/spdy/spdy_flags.h" | |
| 12 | |
| 13 namespace net { | |
| 14 namespace { | |
| 15 const size_t kMaxDecodeBufferSizeBytes = 32 * 1024; // 32 KB | |
| 16 } // namespace | |
| 17 | |
| 18 HpackDecoder3::HpackDecoder3() | |
| 19 : hpack_decoder_(&listener_adapter_, kMaxDecodeBufferSizeBytes), | |
| 20 max_decode_buffer_size_bytes_(kMaxDecodeBufferSizeBytes), | |
| 21 header_block_started_(false) {} | |
| 22 | |
| 23 HpackDecoder3::~HpackDecoder3() {} | |
| 24 | |
| 25 void HpackDecoder3::ApplyHeaderTableSizeSetting(size_t size_setting) { | |
| 26 DVLOG(2) << "HpackDecoder3::ApplyHeaderTableSizeSetting"; | |
| 27 hpack_decoder_.ApplyHeaderTableSizeSetting(size_setting); | |
| 28 } | |
| 29 | |
| 30 void HpackDecoder3::HandleControlFrameHeadersStart( | |
| 31 SpdyHeadersHandlerInterface* handler) { | |
| 32 DVLOG(2) << "HpackDecoder3::HandleControlFrameHeadersStart"; | |
| 33 DCHECK(!header_block_started_); | |
| 34 listener_adapter_.set_handler(handler); | |
| 35 } | |
| 36 | |
| 37 bool HpackDecoder3::HandleControlFrameHeadersData(const char* headers_data, | |
| 38 size_t headers_data_length) { | |
| 39 DVLOG(2) << "HpackDecoder3::HandleControlFrameHeadersData: len=" | |
| 40 << headers_data_length; | |
| 41 if (!header_block_started_) { | |
| 42 // Initialize the decoding process here rather than in | |
| 43 // HandleControlFrameHeadersStart because that method is not always called. | |
| 44 header_block_started_ = true; | |
| 45 if (!hpack_decoder_.StartDecodingBlock()) { | |
| 46 header_block_started_ = false; | |
| 47 return false; | |
| 48 } | |
| 49 } | |
| 50 | |
| 51 // Sometimes we get a call with headers_data==nullptr and | |
| 52 // headers_data_length==0, in which case we need to avoid creating | |
| 53 // a DecodeBuffer, which would otherwise complain. | |
| 54 if (headers_data_length > 0) { | |
| 55 DCHECK_NE(headers_data, nullptr); | |
| 56 if (headers_data_length > max_decode_buffer_size_bytes_) { | |
| 57 DVLOG(1) << "max_decode_buffer_size_bytes_ < headers_data_length: " | |
| 58 << max_decode_buffer_size_bytes_ << " < " << headers_data_length; | |
| 59 return false; | |
| 60 } | |
| 61 listener_adapter_.AddToTotalHpackBytes(headers_data_length); | |
| 62 DecodeBuffer db(headers_data, headers_data_length); | |
| 63 bool ok = hpack_decoder_.DecodeFragment(&db); | |
| 64 DCHECK(!ok || db.Empty()) << "Remaining=" << db.Remaining(); | |
| 65 return ok; | |
| 66 } | |
| 67 return true; | |
| 68 } | |
| 69 | |
| 70 // TODO(jamessynge): Determine if compressed_len is needed; it is used to | |
| 71 // produce UUMA stat Net.SpdyHpackDecompressionPercentage, but only for | |
| 72 // SPDY3, not HTTP2. | |
| 73 bool HpackDecoder3::HandleControlFrameHeadersComplete(size_t* compressed_len) { | |
| 74 DVLOG(2) << "HpackDecoder3::HandleControlFrameHeadersComplete"; | |
| 75 if (compressed_len != nullptr) { | |
| 76 *compressed_len = listener_adapter_.total_hpack_bytes(); | |
| 77 } | |
| 78 if (!hpack_decoder_.EndDecodingBlock()) { | |
| 79 DVLOG(3) << "EndDecodingBlock returned false"; | |
| 80 return false; | |
| 81 } | |
| 82 header_block_started_ = false; | |
| 83 return true; | |
| 84 } | |
| 85 | |
| 86 const SpdyHeaderBlock& HpackDecoder3::decoded_block() const { | |
| 87 return listener_adapter_.decoded_block(); | |
| 88 } | |
| 89 | |
| 90 void HpackDecoder3::SetHeaderTableDebugVisitor( | |
| 91 std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) { | |
| 92 DVLOG(2) << "HpackDecoder3::SetHeaderTableDebugVisitor"; | |
| 93 if (visitor != nullptr) { | |
| 94 listener_adapter_.SetHeaderTableDebugVisitor(std::move(visitor)); | |
| 95 hpack_decoder_.set_tables_debug_listener(&listener_adapter_); | |
| 96 } else { | |
| 97 hpack_decoder_.set_tables_debug_listener(nullptr); | |
| 98 listener_adapter_.SetHeaderTableDebugVisitor(nullptr); | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 void HpackDecoder3::set_max_decode_buffer_size_bytes( | |
| 103 size_t max_decode_buffer_size_bytes) { | |
| 104 DVLOG(2) << "HpackDecoder3::set_max_decode_buffer_size_bytes"; | |
| 105 max_decode_buffer_size_bytes_ = max_decode_buffer_size_bytes; | |
| 106 hpack_decoder_.set_max_string_size_bytes(max_decode_buffer_size_bytes); | |
| 107 } | |
| 108 | |
| 109 size_t HpackDecoder3::EstimateMemoryUsage() const { | |
| 110 return SpdyEstimateMemoryUsage(hpack_decoder_); | |
| 111 } | |
| 112 | |
| 113 HpackDecoder3::ListenerAdapter::ListenerAdapter() : handler_(nullptr) {} | |
| 114 HpackDecoder3::ListenerAdapter::~ListenerAdapter() {} | |
| 115 | |
| 116 void HpackDecoder3::ListenerAdapter::set_handler( | |
| 117 SpdyHeadersHandlerInterface* handler) { | |
| 118 handler_ = handler; | |
| 119 } | |
| 120 | |
| 121 void HpackDecoder3::ListenerAdapter::SetHeaderTableDebugVisitor( | |
| 122 std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) { | |
| 123 visitor_ = std::move(visitor); | |
| 124 } | |
| 125 | |
| 126 void HpackDecoder3::ListenerAdapter::OnHeaderListStart() { | |
| 127 DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnHeaderListStart"; | |
| 128 total_hpack_bytes_ = 0; | |
| 129 total_uncompressed_bytes_ = 0; | |
| 130 decoded_block_.clear(); | |
| 131 if (handler_ != nullptr) { | |
| 132 handler_->OnHeaderBlockStart(); | |
| 133 } | |
| 134 } | |
| 135 | |
| 136 void HpackDecoder3::ListenerAdapter::OnHeader(HpackEntryType entry_type, | |
| 137 const HpackString& name, | |
| 138 const HpackString& value) { | |
| 139 DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnHeader:\n name: " << name | |
| 140 << "\n value: " << value; | |
| 141 total_uncompressed_bytes_ += name.size() + value.size(); | |
| 142 if (handler_ == nullptr) { | |
| 143 DVLOG(3) << "Adding to decoded_block"; | |
| 144 decoded_block_.AppendValueOrAddHeader(name, value); | |
| 145 } else { | |
| 146 DVLOG(3) << "Passing to handler"; | |
| 147 handler_->OnHeader(name, value); | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 void HpackDecoder3::ListenerAdapter::OnHeaderListEnd() { | |
| 152 DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnHeaderListEnd"; | |
| 153 // We don't clear the SpdyHeaderBlock here to allow access to it until the | |
| 154 // next HPACK block is decoded. | |
| 155 if (handler_ != nullptr) { | |
| 156 if (FLAGS_chromium_http2_flag_log_compressed_size) { | |
| 157 handler_->OnHeaderBlockEnd(total_uncompressed_bytes_, total_hpack_bytes_); | |
| 158 } else { | |
| 159 handler_->OnHeaderBlockEnd(total_uncompressed_bytes_); | |
| 160 } | |
| 161 handler_ = nullptr; | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 void HpackDecoder3::ListenerAdapter::OnHeaderErrorDetected( | |
| 166 SpdyStringPiece error_message) { | |
| 167 VLOG(1) << error_message; | |
| 168 } | |
| 169 | |
| 170 int64_t HpackDecoder3::ListenerAdapter::OnEntryInserted( | |
| 171 const HpackStringPair& sp, | |
| 172 size_t insert_count) { | |
| 173 DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnEntryInserted: " << sp | |
| 174 << ", insert_count=" << insert_count; | |
| 175 if (visitor_ == nullptr) { | |
| 176 return 0; | |
| 177 } | |
| 178 HpackEntry entry(sp.name, sp.value, /*is_static*/ false, insert_count); | |
| 179 int64_t time_added = visitor_->OnNewEntry(entry); | |
| 180 DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnEntryInserted: time_added=" | |
| 181 << time_added; | |
| 182 return time_added; | |
| 183 } | |
| 184 | |
| 185 void HpackDecoder3::ListenerAdapter::OnUseEntry(const HpackStringPair& sp, | |
| 186 size_t insert_count, | |
| 187 int64_t time_added) { | |
| 188 DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnUseEntry: " << sp | |
| 189 << ", insert_count=" << insert_count | |
| 190 << ", time_added=" << time_added; | |
| 191 if (visitor_ != nullptr) { | |
| 192 HpackEntry entry(sp.name, sp.value, /*is_static*/ false, insert_count); | |
| 193 entry.set_time_added(time_added); | |
| 194 visitor_->OnUseEntry(entry); | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 } // namespace net | |
| OLD | NEW |