xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/decoder/frame_decoder_state.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 #ifndef QUICHE_HTTP2_DECODER_FRAME_DECODER_STATE_H_
6 #define QUICHE_HTTP2_DECODER_FRAME_DECODER_STATE_H_
7 
8 // FrameDecoderState provides state and behaviors in support of decoding
9 // the common frame header and the payload of all frame types.
10 // It is an input to all of the payload decoders.
11 
12 // TODO(jamessynge): Since FrameDecoderState has far more than state in it,
13 // rename to FrameDecoderHelper, or similar.
14 
15 #include <stddef.h>
16 
17 #include <cstdint>
18 
19 #include "quiche/http2/decoder/decode_buffer.h"
20 #include "quiche/http2/decoder/decode_status.h"
21 #include "quiche/http2/decoder/http2_frame_decoder_listener.h"
22 #include "quiche/http2/decoder/http2_structure_decoder.h"
23 #include "quiche/http2/http2_constants.h"
24 #include "quiche/http2/http2_structures.h"
25 #include "quiche/common/platform/api/quiche_export.h"
26 #include "quiche/common/platform/api/quiche_logging.h"
27 
28 namespace http2 {
29 namespace test {
30 class FrameDecoderStatePeer;
31 }  // namespace test
32 
33 class QUICHE_EXPORT FrameDecoderState {
34  public:
FrameDecoderState()35   FrameDecoderState() {}
36 
37   // Sets the listener which the decoders should call as they decode HTTP/2
38   // frames. The listener can be changed at any time, which allows for replacing
39   // it with a no-op listener when an error is detected, either by the payload
40   // decoder (OnPaddingTooLong or OnFrameSizeError) or by the "real" listener.
41   // That in turn allows us to define Http2FrameDecoderListener such that all
42   // methods have return type void, with no direct way to indicate whether the
43   // decoder should stop, and to eliminate from the decoder all checks of the
44   // return value. Instead the listener/caller can simply replace the current
45   // listener with a no-op listener implementation.
46   // TODO(jamessynge): Make set_listener private as only Http2FrameDecoder
47   // and tests need to set it, so it doesn't need to be public.
set_listener(Http2FrameDecoderListener * listener)48   void set_listener(Http2FrameDecoderListener* listener) {
49     listener_ = listener;
50   }
listener()51   Http2FrameDecoderListener* listener() const { return listener_; }
52 
53   // The most recently decoded frame header.
frame_header()54   const Http2FrameHeader& frame_header() const { return frame_header_; }
55 
56   // Decode a structure in the payload, adjusting remaining_payload_ to account
57   // for the consumed portion of the payload. Returns kDecodeDone when fully
58   // decoded, kDecodeError if it ran out of payload before decoding completed,
59   // and kDecodeInProgress if the decode buffer didn't have enough of the
60   // remaining payload.
61   template <class S>
StartDecodingStructureInPayload(S * out,DecodeBuffer * db)62   DecodeStatus StartDecodingStructureInPayload(S* out, DecodeBuffer* db) {
63     QUICHE_DVLOG(2) << __func__ << "\n\tdb->Remaining=" << db->Remaining()
64                     << "\n\tremaining_payload_=" << remaining_payload_
65                     << "\n\tneed=" << S::EncodedSize();
66     DecodeStatus status =
67         structure_decoder_.Start(out, db, &remaining_payload_);
68     if (status != DecodeStatus::kDecodeError) {
69       return status;
70     }
71     QUICHE_DVLOG(2)
72         << "StartDecodingStructureInPayload: detected frame size error";
73     return ReportFrameSizeError();
74   }
75 
76   // Resume decoding of a structure that has been split across buffers,
77   // adjusting remaining_payload_ to account for the consumed portion of
78   // the payload. Returns values are as for StartDecodingStructureInPayload.
79   template <class S>
ResumeDecodingStructureInPayload(S * out,DecodeBuffer * db)80   DecodeStatus ResumeDecodingStructureInPayload(S* out, DecodeBuffer* db) {
81     QUICHE_DVLOG(2) << __func__ << "\n\tdb->Remaining=" << db->Remaining()
82                     << "\n\tremaining_payload_=" << remaining_payload_;
83     if (structure_decoder_.Resume(out, db, &remaining_payload_)) {
84       return DecodeStatus::kDecodeDone;
85     } else if (remaining_payload_ > 0) {
86       return DecodeStatus::kDecodeInProgress;
87     } else {
88       QUICHE_DVLOG(2)
89           << "ResumeDecodingStructureInPayload: detected frame size error";
90       return ReportFrameSizeError();
91     }
92   }
93 
94   // Initializes the two remaining* fields, which is needed if the frame's
95   // payload is split across buffers, or the decoder calls ReadPadLength or
96   // StartDecodingStructureInPayload, and of course the methods below which
97   // read those fields, as their names imply.
InitializeRemainders()98   void InitializeRemainders() {
99     remaining_payload_ = frame_header().payload_length;
100     // Note that remaining_total_payload() relies on remaining_padding_ being
101     // zero for frames that have no padding.
102     remaining_padding_ = 0;
103   }
104 
105   // Returns the number of bytes of the frame's payload that remain to be
106   // decoded, including any trailing padding. This method must only be called
107   // after the variables have been initialized, which in practice means once a
108   // payload decoder has called InitializeRemainders and/or ReadPadLength.
remaining_total_payload()109   size_t remaining_total_payload() const {
110     QUICHE_DCHECK(IsPaddable() || remaining_padding_ == 0) << frame_header();
111     return remaining_payload_ + remaining_padding_;
112   }
113 
114   // Returns the number of bytes of the frame's payload that remain to be
115   // decoded, excluding any trailing padding. This method must only be called
116   // after the variable has been initialized, which in practice means once a
117   // payload decoder has called InitializeRemainders; ReadPadLength will deduct
118   // the total number of padding bytes from remaining_payload_, including the
119   // size of the Pad Length field itself (1 byte).
remaining_payload()120   size_t remaining_payload() const { return remaining_payload_; }
121 
122   // Returns the number of bytes of the frame's payload that remain to be
123   // decoded, including any trailing padding. This method must only be called if
124   // the frame type allows padding, and after the variable has been initialized,
125   // which in practice means once a payload decoder has called
126   // InitializeRemainders and/or ReadPadLength.
remaining_payload_and_padding()127   size_t remaining_payload_and_padding() const {
128     QUICHE_DCHECK(IsPaddable()) << frame_header();
129     return remaining_payload_ + remaining_padding_;
130   }
131 
132   // Returns the number of bytes of trailing padding after the payload that
133   // remain to be decoded. This method must only be called if the frame type
134   // allows padding, and after the variable has been initialized, which in
135   // practice means once a payload decoder has called InitializeRemainders,
136   // and isn't set to a non-zero value until ReadPadLength has been called.
remaining_padding()137   uint32_t remaining_padding() const {
138     QUICHE_DCHECK(IsPaddable()) << frame_header();
139     return remaining_padding_;
140   }
141 
142   // How many bytes of the remaining payload are in db?
AvailablePayload(DecodeBuffer * db)143   size_t AvailablePayload(DecodeBuffer* db) const {
144     return db->MinLengthRemaining(remaining_payload_);
145   }
146 
147   // How many bytes of the remaining payload and padding are in db?
148   // Call only for frames whose type is paddable.
AvailablePayloadAndPadding(DecodeBuffer * db)149   size_t AvailablePayloadAndPadding(DecodeBuffer* db) const {
150     QUICHE_DCHECK(IsPaddable()) << frame_header();
151     return db->MinLengthRemaining(remaining_payload_ + remaining_padding_);
152   }
153 
154   // How many bytes of the padding that have not yet been skipped are in db?
155   // Call only after remaining_padding_ has been set (for padded frames), or
156   // been cleared (for unpadded frames); and after all of the non-padding
157   // payload has been decoded.
AvailablePadding(DecodeBuffer * db)158   size_t AvailablePadding(DecodeBuffer* db) const {
159     QUICHE_DCHECK(IsPaddable()) << frame_header();
160     QUICHE_DCHECK_EQ(remaining_payload_, 0u);
161     return db->MinLengthRemaining(remaining_padding_);
162   }
163 
164   // Reduces remaining_payload_ by amount. To be called by a payload decoder
165   // after it has passed a variable length portion of the payload to the
166   // listener; remaining_payload_ will be automatically reduced when fixed
167   // size structures and padding, including the Pad Length field, are decoded.
ConsumePayload(size_t amount)168   void ConsumePayload(size_t amount) {
169     QUICHE_DCHECK_LE(amount, remaining_payload_);
170     remaining_payload_ -= amount;
171   }
172 
173   // Reads the Pad Length field into remaining_padding_, and appropriately sets
174   // remaining_payload_. When present, the Pad Length field is always the first
175   // field in the payload, which this method relies on so that the caller need
176   // not set remaining_payload_ before calling this method.
177   // If report_pad_length is true, calls the listener's OnPadLength method when
178   // it decodes the Pad Length field.
179   // Returns kDecodeDone if the decode buffer was not empty (i.e. because the
180   // field is only a single byte long, it can always be decoded if the buffer is
181   // not empty).
182   // Returns kDecodeError if the buffer is empty because the frame has no
183   // payload (i.e. payload_length() == 0).
184   // Returns kDecodeInProgress if the buffer is empty but the frame has a
185   // payload.
186   DecodeStatus ReadPadLength(DecodeBuffer* db, bool report_pad_length);
187 
188   // Skip the trailing padding bytes; only call once remaining_payload_==0.
189   // Returns true when the padding has been skipped.
190   // Does NOT check that the padding is all zeroes.
191   bool SkipPadding(DecodeBuffer* db);
192 
193   // Calls the listener's OnFrameSizeError method and returns kDecodeError.
194   DecodeStatus ReportFrameSizeError();
195 
196  private:
197   friend class Http2FrameDecoder;
198   friend class test::FrameDecoderStatePeer;
199 
200   // Starts the decoding of a common frame header. Returns true if completed the
201   // decoding, false if the decode buffer didn't have enough data in it, in
202   // which case the decode buffer will have been drained and the caller should
203   // call ResumeDecodingFrameHeader when more data is available. This is called
204   // from Http2FrameDecoder, a friend class.
StartDecodingFrameHeader(DecodeBuffer * db)205   bool StartDecodingFrameHeader(DecodeBuffer* db) {
206     return structure_decoder_.Start(&frame_header_, db);
207   }
208 
209   // Resumes decoding the common frame header after the preceding call to
210   // StartDecodingFrameHeader returned false, as did any subsequent calls to
211   // ResumeDecodingFrameHeader. This is called from Http2FrameDecoder,
212   // a friend class.
ResumeDecodingFrameHeader(DecodeBuffer * db)213   bool ResumeDecodingFrameHeader(DecodeBuffer* db) {
214     return structure_decoder_.Resume(&frame_header_, db);
215   }
216 
217   // Clear any of the flags in the frame header that aren't set in valid_flags.
RetainFlags(uint8_t valid_flags)218   void RetainFlags(uint8_t valid_flags) {
219     frame_header_.RetainFlags(valid_flags);
220   }
221 
222   // Clear all of the flags in the frame header; for use with frame types that
223   // don't define any flags, such as WINDOW_UPDATE.
ClearFlags()224   void ClearFlags() { frame_header_.flags = Http2FrameFlag(); }
225 
226   // Returns true if the type of frame being decoded can have padding.
IsPaddable()227   bool IsPaddable() const {
228     return frame_header().type == Http2FrameType::DATA ||
229            frame_header().type == Http2FrameType::HEADERS ||
230            frame_header().type == Http2FrameType::PUSH_PROMISE;
231   }
232 
233   Http2FrameDecoderListener* listener_ = nullptr;
234   Http2FrameHeader frame_header_;
235 
236   // Number of bytes remaining to be decoded, if set; does not include the
237   // trailing padding once the length of padding has been determined.
238   // See ReadPadLength.
239   uint32_t remaining_payload_;
240 
241   // The amount of trailing padding after the payload that remains to be
242   // decoded. See ReadPadLength.
243   uint32_t remaining_padding_;
244 
245   // Generic decoder of structures, which takes care of buffering the needed
246   // bytes if the encoded structure is split across decode buffers.
247   Http2StructureDecoder structure_decoder_;
248 };
249 
250 }  // namespace http2
251 
252 #endif  // QUICHE_HTTP2_DECODER_FRAME_DECODER_STATE_H_
253