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 #ifndef NET_HTTP2_DECODER_FRAME_DECODER_STATE_H_ | |
6 #define NET_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 "base/logging.h" | |
18 #include "net/base/net_export.h" | |
19 #include "net/http2/decoder/decode_buffer.h" | |
20 #include "net/http2/decoder/decode_status.h" | |
21 #include "net/http2/decoder/http2_frame_decoder_listener.h" | |
22 #include "net/http2/decoder/http2_structure_decoder.h" | |
23 #include "net/http2/http2_constants.h" | |
24 #include "net/http2/http2_structures.h" | |
25 | |
26 namespace net { | |
27 namespace test { | |
28 class FrameDecoderStatePeer; | |
29 } // namespace test | |
30 | |
31 class NET_EXPORT_PRIVATE FrameDecoderState { | |
32 public: | |
33 FrameDecoderState() {} | |
34 | |
35 // Sets the listener which the decoders should call as they decode HTTP/2 | |
36 // frames. The listener can be changed at any time, which allows for replacing | |
37 // it with a no-op listener when an error is detected, either by the payload | |
38 // decoder (OnPaddingTooLong or OnFrameSizeError) or by the "real" listener. | |
39 // That in turn allows us to define Http2FrameDecoderListener such that all | |
40 // methods have return type void, with no direct way to indicate whether the | |
41 // decoder should stop, and to eliminate from the decoder all checks of the | |
42 // return value. Instead the listener/caller can simply replace the current | |
43 // listener with a no-op listener implementation. | |
44 // TODO(jamessynge): Make set_listener private as only Http2FrameDecoder | |
45 // and tests need to set it, so it doesn't need to be public. | |
46 void set_listener(Http2FrameDecoderListener* listener) { | |
47 listener_ = listener; | |
48 } | |
49 Http2FrameDecoderListener* listener() const { return listener_; } | |
50 | |
51 // The most recently decoded frame header. | |
52 const Http2FrameHeader& frame_header() const { return frame_header_; } | |
53 | |
54 // Decode a structure in the payload, adjusting remaining_payload_ to account | |
55 // for the consumed portion of the payload. Returns kDecodeDone when fully | |
56 // decoded, kDecodeError if it ran out of payload before decoding completed, | |
57 // and kDecodeInProgress if the decode buffer didn't have enough of the | |
58 // remaining payload. | |
59 template <class S> | |
60 DecodeStatus StartDecodingStructureInPayload(S* out, DecodeBuffer* db) { | |
61 DVLOG(2) << __func__ << "\n\tdb->Remaining=" << db->Remaining() | |
62 << "\n\tremaining_payload_=" << remaining_payload_ | |
63 << "\n\tneed=" << S::EncodedSize(); | |
64 DecodeStatus status = | |
65 structure_decoder_.Start(out, db, &remaining_payload_); | |
66 if (status != DecodeStatus::kDecodeError) { | |
67 return status; | |
68 } | |
69 DVLOG(2) << "StartDecodingStructureInPayload: detected frame size error"; | |
70 return ReportFrameSizeError(); | |
71 } | |
72 | |
73 // Resume decoding of a structure that has been split across buffers, | |
74 // adjusting remaining_payload_ to account for the consumed portion of | |
75 // the payload. Returns values are as for StartDecodingStructureInPayload. | |
76 template <class S> | |
77 DecodeStatus ResumeDecodingStructureInPayload(S* out, DecodeBuffer* db) { | |
78 DVLOG(2) << __func__ << "\n\tdb->Remaining=" << db->Remaining() | |
79 << "\n\tremaining_payload_=" << remaining_payload_; | |
80 if (structure_decoder_.Resume(out, db, &remaining_payload_)) { | |
81 return DecodeStatus::kDecodeDone; | |
82 } else if (remaining_payload_ > 0) { | |
83 return DecodeStatus::kDecodeInProgress; | |
84 } else { | |
85 DVLOG(2) << "ResumeDecodingStructureInPayload: detected frame size error"; | |
86 return ReportFrameSizeError(); | |
87 } | |
88 } | |
89 | |
90 // Initializes the two remaining* fields, which is needed if the frame's | |
91 // payload is split across buffers, or the decoder calls ReadPadLength or | |
92 // StartDecodingStructureInPayload, and of course the methods below which | |
93 // read those fields, as their names imply. | |
94 void InitializeRemainders() { | |
95 remaining_payload_ = frame_header().payload_length; | |
96 // Note that remaining_total_payload() relies on remaining_padding_ being | |
97 // zero for frames that have no padding. | |
98 remaining_padding_ = 0; | |
99 } | |
100 | |
101 // Returns the number of bytes of the frame's payload that remain to be | |
102 // decoded, including any trailing padding. This method must only be called | |
103 // after the variables have been initialized, which in practice means once a | |
104 // payload decoder has called InitializeRemainders and/or ReadPadLength. | |
105 size_t remaining_total_payload() const { | |
106 DCHECK(IsPaddable() || remaining_padding_ == 0) << frame_header(); | |
107 return remaining_payload_ + remaining_padding_; | |
108 } | |
109 | |
110 // Returns the number of bytes of the frame's payload that remain to be | |
111 // decoded, excluding any trailing padding. This method must only be called | |
112 // after the variable has been initialized, which in practice means once a | |
113 // payload decoder has called InitializeRemainders; ReadPadLength will deduct | |
114 // the total number of padding bytes from remaining_payload_, including the | |
115 // size of the Pad Length field itself (1 byte). | |
116 size_t remaining_payload() const { return remaining_payload_; } | |
117 | |
118 // Returns the number of bytes of the frame's payload that remain to be | |
119 // decoded, including any trailing padding. This method must only be called if | |
120 // the frame type allows padding, and after the variable has been initialized, | |
121 // which in practice means once a payload decoder has called | |
122 // InitializeRemainders and/or ReadPadLength. | |
123 size_t remaining_payload_and_padding() const { | |
124 DCHECK(IsPaddable()) << frame_header(); | |
125 return remaining_payload_ + remaining_padding_; | |
126 } | |
127 | |
128 // Returns the number of bytes of trailing padding after the payload that | |
129 // remain to be decoded. This method must only be called if the frame type | |
130 // allows padding, and after the variable has been initialized, which in | |
131 // practice means once a payload decoder has called InitializeRemainders, | |
132 // and isn't set to a non-zero value until ReadPadLength has been called. | |
133 uint32_t remaining_padding() const { | |
134 DCHECK(IsPaddable()) << frame_header(); | |
135 return remaining_padding_; | |
136 } | |
137 | |
138 // Returns the amount of trailing padding after the payload that remains to be | |
139 // decoded. | |
140 uint32_t remaining_padding_for_test() const { return remaining_padding_; } | |
141 | |
142 // How many bytes of the remaining payload are in 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. | |
149 size_t AvailablePayloadAndPadding(DecodeBuffer* db) const { | |
150 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. | |
158 size_t AvailablePadding(DecodeBuffer* db) const { | |
159 DCHECK(IsPaddable()) << frame_header(); | |
160 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. | |
168 void ConsumePayload(size_t amount) { | |
169 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. | |
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. | |
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. | |
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. | |
224 void ClearFlags() { frame_header_.flags = Http2FrameFlag(); } | |
225 | |
226 // Returns true if the type of frame being decoded can have padding. | |
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 net | |
251 | |
252 #endif // NET_HTTP2_DECODER_FRAME_DECODER_STATE_H_ | |
OLD | NEW |