OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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/http2/hpack/decoder/hpack_entry_decoder.h" |
| 6 |
| 7 #include <stddef.h> |
| 8 |
| 9 #include "base/logging.h" |
| 10 #include "base/macros.h" |
| 11 |
| 12 namespace net { |
| 13 namespace { |
| 14 // Converts calls from HpackStringDecoder when decoding a header name into the |
| 15 // appropriate HpackEntryDecoderListener::OnName* calls. |
| 16 class NameDecoderListener { |
| 17 public: |
| 18 explicit NameDecoderListener(HpackEntryDecoderListener* listener) |
| 19 : listener_(listener) {} |
| 20 bool OnStringStart(bool huffman_encoded, size_t len) { |
| 21 listener_->OnNameStart(huffman_encoded, len); |
| 22 return true; |
| 23 } |
| 24 void OnStringData(const char* data, size_t len) { |
| 25 listener_->OnNameData(data, len); |
| 26 } |
| 27 void OnStringEnd() { listener_->OnNameEnd(); } |
| 28 |
| 29 private: |
| 30 HpackEntryDecoderListener* listener_; |
| 31 }; |
| 32 |
| 33 // Converts calls from HpackStringDecoder when decoding a header value into |
| 34 // the appropriate HpackEntryDecoderListener::OnValue* calls. |
| 35 class ValueDecoderListener { |
| 36 public: |
| 37 explicit ValueDecoderListener(HpackEntryDecoderListener* listener) |
| 38 : listener_(listener) {} |
| 39 bool OnStringStart(bool huffman_encoded, size_t len) { |
| 40 listener_->OnValueStart(huffman_encoded, len); |
| 41 return true; |
| 42 } |
| 43 void OnStringData(const char* data, size_t len) { |
| 44 listener_->OnValueData(data, len); |
| 45 } |
| 46 void OnStringEnd() { listener_->OnValueEnd(); } |
| 47 |
| 48 private: |
| 49 HpackEntryDecoderListener* listener_; |
| 50 }; |
| 51 } // namespace |
| 52 |
| 53 // Only call Resume if the previous call (Start or Resume) returned |
| 54 // kDecodeInProgress; Resume is also called from Start when it has succeeded |
| 55 // in decoding the entry type and its varint. |
| 56 DecodeStatus HpackEntryDecoder::Resume(DecodeBuffer* db, |
| 57 HpackEntryDecoderListener* listener) { |
| 58 DCHECK(db != nullptr); |
| 59 DCHECK(listener != nullptr); |
| 60 |
| 61 DecodeStatus status; |
| 62 |
| 63 do { |
| 64 switch (state_) { |
| 65 case EntryDecoderState::kResumeDecodingType: |
| 66 // entry_type_decoder_ returned kDecodeInProgress when last called. |
| 67 DVLOG(1) << "kResumeDecodingType: db->Remaining=" << db->Remaining(); |
| 68 status = entry_type_decoder_.Resume(db); |
| 69 if (status != DecodeStatus::kDecodeDone) { |
| 70 return status; |
| 71 } |
| 72 state_ = EntryDecoderState::kDecodedType; |
| 73 // FALLTHROUGH_INTENDED |
| 74 |
| 75 case EntryDecoderState::kDecodedType: |
| 76 // entry_type_decoder_ returned kDecodeDone, now need to decide how |
| 77 // to proceed. |
| 78 DVLOG(1) << "kDecodedType: db->Remaining=" << db->Remaining(); |
| 79 if (DispatchOnType(listener)) { |
| 80 // All done. |
| 81 return DecodeStatus::kDecodeDone; |
| 82 } |
| 83 continue; |
| 84 |
| 85 case EntryDecoderState::kStartDecodingName: |
| 86 DVLOG(1) << "kStartDecodingName: db->Remaining=" << db->Remaining(); |
| 87 { |
| 88 NameDecoderListener ncb(listener); |
| 89 status = string_decoder_.Start(db, &ncb); |
| 90 } |
| 91 if (status != DecodeStatus::kDecodeDone) { |
| 92 // On the assumption that the status is kDecodeInProgress, set |
| 93 // state_ accordingly; unnecessary if status is kDecodeError, but |
| 94 // that will only happen if the varint encoding the name's length |
| 95 // is too long. |
| 96 state_ = EntryDecoderState::kResumeDecodingName; |
| 97 return status; |
| 98 } |
| 99 state_ = EntryDecoderState::kStartDecodingValue; |
| 100 // FALLTHROUGH_INTENDED |
| 101 |
| 102 case EntryDecoderState::kStartDecodingValue: |
| 103 DVLOG(1) << "kStartDecodingValue: db->Remaining=" << db->Remaining(); |
| 104 { |
| 105 ValueDecoderListener vcb(listener); |
| 106 status = string_decoder_.Start(db, &vcb); |
| 107 } |
| 108 if (status == DecodeStatus::kDecodeDone) { |
| 109 // Done with decoding the literal value, so we've reached the |
| 110 // end of the header entry. |
| 111 return status; |
| 112 } |
| 113 // On the assumption that the status is kDecodeInProgress, set |
| 114 // state_ accordingly; unnecessary if status is kDecodeError, but |
| 115 // that will only happen if the varint encoding the value's length |
| 116 // is too long. |
| 117 state_ = EntryDecoderState::kResumeDecodingValue; |
| 118 return status; |
| 119 |
| 120 case EntryDecoderState::kResumeDecodingName: |
| 121 // The literal name was split across decode buffers. |
| 122 DVLOG(1) << "kResumeDecodingName: db->Remaining=" << db->Remaining(); |
| 123 { |
| 124 NameDecoderListener ncb(listener); |
| 125 status = string_decoder_.Resume(db, &ncb); |
| 126 } |
| 127 if (status != DecodeStatus::kDecodeDone) { |
| 128 // On the assumption that the status is kDecodeInProgress, set |
| 129 // state_ accordingly; unnecessary if status is kDecodeError, but |
| 130 // that will only happen if the varint encoding the name's length |
| 131 // is too long. |
| 132 state_ = EntryDecoderState::kResumeDecodingName; |
| 133 return status; |
| 134 } |
| 135 state_ = EntryDecoderState::kStartDecodingValue; |
| 136 break; |
| 137 |
| 138 case EntryDecoderState::kResumeDecodingValue: |
| 139 // The literal value was split across decode buffers. |
| 140 DVLOG(1) << "kResumeDecodingValue: db->Remaining=" << db->Remaining(); |
| 141 { |
| 142 ValueDecoderListener vcb(listener); |
| 143 status = string_decoder_.Resume(db, &vcb); |
| 144 } |
| 145 if (status == DecodeStatus::kDecodeDone) { |
| 146 // Done with decoding the value, therefore the entry as a whole. |
| 147 return status; |
| 148 } |
| 149 // On the assumption that the status is kDecodeInProgress, set |
| 150 // state_ accordingly; unnecessary if status is kDecodeError, but |
| 151 // that will only happen if the varint encoding the value's length |
| 152 // is too long. |
| 153 state_ = EntryDecoderState::kResumeDecodingValue; |
| 154 return status; |
| 155 } |
| 156 } while (true); |
| 157 } |
| 158 |
| 159 bool HpackEntryDecoder::DispatchOnType(HpackEntryDecoderListener* listener) { |
| 160 const HpackEntryType entry_type = entry_type_decoder_.entry_type(); |
| 161 const uint32_t varint = entry_type_decoder_.varint(); |
| 162 switch (entry_type) { |
| 163 case HpackEntryType::kIndexedHeader: |
| 164 // The entry consists solely of the entry type and varint. See: |
| 165 // http://httpwg.org/specs/rfc7541.html#indexed.header.representation |
| 166 listener->OnIndexedHeader(varint); |
| 167 return true; |
| 168 |
| 169 case HpackEntryType::kIndexedLiteralHeader: |
| 170 case HpackEntryType::kUnindexedLiteralHeader: |
| 171 case HpackEntryType::kNeverIndexedLiteralHeader: |
| 172 // The entry has a literal value, and if the varint is zero also has a |
| 173 // literal name preceding the value. See: |
| 174 // http://httpwg.org/specs/rfc7541.html#literal.header.representation |
| 175 listener->OnStartLiteralHeader(entry_type, varint); |
| 176 if (varint == 0) { |
| 177 state_ = EntryDecoderState::kStartDecodingName; |
| 178 } else { |
| 179 state_ = EntryDecoderState::kStartDecodingValue; |
| 180 } |
| 181 return false; |
| 182 |
| 183 case HpackEntryType::kDynamicTableSizeUpdate: |
| 184 // The entry consists solely of the entry type and varint. FWIW, I've |
| 185 // never seen this type of entry in production (primarily browser |
| 186 // traffic) so if you're designing an HPACK successor someday, consider |
| 187 // dropping it or giving it a much longer prefix. See: |
| 188 // http://httpwg.org/specs/rfc7541.html#encoding.context.update |
| 189 listener->OnDynamicTableSizeUpdate(varint); |
| 190 return true; |
| 191 } |
| 192 |
| 193 NOTREACHED(); |
| 194 return true; |
| 195 } |
| 196 |
| 197 void HpackEntryDecoder::OutputDebugString(std::ostream& out) const { |
| 198 out << "HpackEntryDecoder(state=" << state_ << ", " << entry_type_decoder_ |
| 199 << ", " << string_decoder_ << ")"; |
| 200 } |
| 201 |
| 202 std::string HpackEntryDecoder::DebugString() const { |
| 203 std::stringstream s; |
| 204 s << *this; |
| 205 return s.str(); |
| 206 } |
| 207 |
| 208 std::ostream& operator<<(std::ostream& out, const HpackEntryDecoder& v) { |
| 209 v.OutputDebugString(out); |
| 210 return out; |
| 211 } |
| 212 |
| 213 std::ostream& operator<<(std::ostream& out, |
| 214 HpackEntryDecoder::EntryDecoderState state) { |
| 215 typedef HpackEntryDecoder::EntryDecoderState EntryDecoderState; |
| 216 switch (state) { |
| 217 case EntryDecoderState::kResumeDecodingType: |
| 218 return out << "kResumeDecodingType"; |
| 219 case EntryDecoderState::kDecodedType: |
| 220 return out << "kDecodedType"; |
| 221 case EntryDecoderState::kStartDecodingName: |
| 222 return out << "kStartDecodingName"; |
| 223 case EntryDecoderState::kResumeDecodingName: |
| 224 return out << "kResumeDecodingName"; |
| 225 case EntryDecoderState::kStartDecodingValue: |
| 226 return out << "kStartDecodingValue"; |
| 227 case EntryDecoderState::kResumeDecodingValue: |
| 228 return out << "kResumeDecodingValue"; |
| 229 } |
| 230 return out << static_cast<int>(state); |
| 231 } |
| 232 |
| 233 } // namespace net |
OLD | NEW |