• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     detailed_error_ = decoder_state_.detailed_error();
106   }
107 
108   return error_ != HpackDecodingError::kOk;
109 }
110 
ReportError(HpackDecodingError error,std::string detailed_error)111 void HpackDecoder::ReportError(HpackDecodingError error,
112                                std::string detailed_error) {
113   QUICHE_DVLOG(3) << "HpackDecoder::ReportError is new="
114                   << (error_ == HpackDecodingError::kOk ? "true" : "false")
115                   << ", error: " << HpackDecodingErrorToString(error);
116   if (error_ == HpackDecodingError::kOk) {
117     error_ = error;
118     detailed_error_ = detailed_error;
119     decoder_state_.listener()->OnHeaderErrorDetected(
120         HpackDecodingErrorToString(error));
121   }
122 }
123 
124 }  // namespace http2
125