xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_decoder.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 "quiche/http2/hpack/decoder/hpack_decoder.h"
6 
7 #include "quiche/http2/decoder/decode_status.h"
8 #include "quiche/common/platform/api/quiche_flag_utils.h"
9 #include "quiche/common/platform/api/quiche_logging.h"
10 
11 namespace http2 {
12 
HpackDecoder(HpackDecoderListener * listener,size_t max_string_size)13 HpackDecoder::HpackDecoder(HpackDecoderListener* listener,
14                            size_t max_string_size)
15     : decoder_state_(listener),
16       entry_buffer_(&decoder_state_, max_string_size),
17       block_decoder_(&entry_buffer_),
18       error_(HpackDecodingError::kOk) {}
19 
20 HpackDecoder::~HpackDecoder() = default;
21 
set_max_string_size_bytes(size_t max_string_size_bytes)22 void HpackDecoder::set_max_string_size_bytes(size_t max_string_size_bytes) {
23   entry_buffer_.set_max_string_size_bytes(max_string_size_bytes);
24 }
25 
ApplyHeaderTableSizeSetting(uint32_t max_header_table_size)26 void HpackDecoder::ApplyHeaderTableSizeSetting(uint32_t max_header_table_size) {
27   decoder_state_.ApplyHeaderTableSizeSetting(max_header_table_size);
28 }
29 
StartDecodingBlock()30 bool HpackDecoder::StartDecodingBlock() {
31   QUICHE_DVLOG(3) << "HpackDecoder::StartDecodingBlock, error_detected="
32                   << (DetectError() ? "true" : "false");
33   if (DetectError()) {
34     return false;
35   }
36   // TODO(jamessynge): Eliminate Reset(), which shouldn't be necessary
37   // if there are no errors, and shouldn't be necessary with errors if
38   // we never resume decoding after an error has been detected.
39   block_decoder_.Reset();
40   decoder_state_.OnHeaderBlockStart();
41   return true;
42 }
43 
DecodeFragment(DecodeBuffer * db)44 bool HpackDecoder::DecodeFragment(DecodeBuffer* db) {
45   QUICHE_DVLOG(3) << "HpackDecoder::DecodeFragment, error_detected="
46                   << (DetectError() ? "true" : "false")
47                   << ", size=" << db->Remaining();
48   if (DetectError()) {
49     QUICHE_CODE_COUNT_N(decompress_failure_3, 3, 23);
50     return false;
51   }
52   // Decode contents of db as an HPACK block fragment, forwards the decoded
53   // entries to entry_buffer_, which in turn forwards them to decode_state_,
54   // which finally forwards them to the HpackDecoderListener.
55   DecodeStatus status = block_decoder_.Decode(db);
56   if (status == DecodeStatus::kDecodeError) {
57     ReportError(block_decoder_.error());
58     QUICHE_CODE_COUNT_N(decompress_failure_3, 4, 23);
59     return false;
60   } else if (DetectError()) {
61     QUICHE_CODE_COUNT_N(decompress_failure_3, 5, 23);
62     return false;
63   }
64   // Should be positioned between entries iff decoding is complete.
65   QUICHE_DCHECK_EQ(block_decoder_.before_entry(),
66                    status == DecodeStatus::kDecodeDone)
67       << status;
68   if (!block_decoder_.before_entry()) {
69     entry_buffer_.BufferStringsIfUnbuffered();
70   }
71   return true;
72 }
73 
EndDecodingBlock()74 bool HpackDecoder::EndDecodingBlock() {
75   QUICHE_DVLOG(3) << "HpackDecoder::EndDecodingBlock, error_detected="
76                   << (DetectError() ? "true" : "false");
77   if (DetectError()) {
78     QUICHE_CODE_COUNT_N(decompress_failure_3, 6, 23);
79     return false;
80   }
81   if (!block_decoder_.before_entry()) {
82     // The HPACK block ended in the middle of an entry.
83     ReportError(HpackDecodingError::kTruncatedBlock);
84     QUICHE_CODE_COUNT_N(decompress_failure_3, 7, 23);
85     return false;
86   }
87   decoder_state_.OnHeaderBlockEnd();
88   if (DetectError()) {
89     // HpackDecoderState will have reported the error.
90     QUICHE_CODE_COUNT_N(decompress_failure_3, 8, 23);
91     return false;
92   }
93   return true;
94 }
95 
DetectError()96 bool HpackDecoder::DetectError() {
97   if (error_ != HpackDecodingError::kOk) {
98     return true;
99   }
100 
101   if (decoder_state_.error() != HpackDecodingError::kOk) {
102     QUICHE_DVLOG(2) << "Error detected in decoder_state_";
103     QUICHE_CODE_COUNT_N(decompress_failure_3, 10, 23);
104     error_ = decoder_state_.error();
105   }
106 
107   return error_ != HpackDecodingError::kOk;
108 }
109 
ReportError(HpackDecodingError error)110 void HpackDecoder::ReportError(HpackDecodingError error) {
111   QUICHE_DVLOG(3) << "HpackDecoder::ReportError is new="
112                   << (error_ == HpackDecodingError::kOk ? "true" : "false")
113                   << ", error: " << HpackDecodingErrorToString(error);
114   if (error_ == HpackDecodingError::kOk) {
115     error_ = error;
116     decoder_state_.listener()->OnHeaderErrorDetected(
117         HpackDecodingErrorToString(error));
118   }
119 }
120 
121 }  // namespace http2
122