QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1 | // Copyright (c) 2018 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_QUIC_CORE_HTTP_HTTP_DECODER_H_ |
| 6 | #define QUICHE_QUIC_CORE_HTTP_HTTP_DECODER_H_ |
| 7 | |
renjietang | 857362b | 2019-08-09 09:52:35 -0700 | [diff] [blame] | 8 | #include <cstdint> |
| 9 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 10 | #include "net/third_party/quiche/src/quic/core/http/http_frames.h" |
| 11 | #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" |
renjietang | 857362b | 2019-08-09 09:52:35 -0700 | [diff] [blame] | 12 | #include "net/third_party/quiche/src/quic/core/quic_types.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 13 | #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" |
dmcardle | ba2fb7e | 2019-12-13 07:44:34 -0800 | [diff] [blame] | 14 | #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 15 | |
| 16 | namespace quic { |
| 17 | |
bnc | 62c32b4 | 2019-06-24 16:06:41 -0700 | [diff] [blame] | 18 | namespace test { |
| 19 | |
| 20 | class HttpDecoderPeer; |
| 21 | |
| 22 | } // namespace test |
| 23 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 24 | class QuicDataReader; |
| 25 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 26 | // A class for decoding the HTTP frames that are exchanged in an HTTP over QUIC |
| 27 | // session. |
| 28 | class QUIC_EXPORT_PRIVATE HttpDecoder { |
| 29 | public: |
| 30 | class QUIC_EXPORT_PRIVATE Visitor { |
| 31 | public: |
| 32 | virtual ~Visitor() {} |
| 33 | |
| 34 | // Called if an error is detected. |
| 35 | virtual void OnError(HttpDecoder* decoder) = 0; |
| 36 | |
bnc | b9d07d9 | 2019-06-25 17:43:49 -0700 | [diff] [blame] | 37 | // All the following methods return true to continue decoding, |
| 38 | // and false to pause it. |
bnc | e5f9c03 | 2019-07-25 11:30:40 -0700 | [diff] [blame] | 39 | // On*FrameStart() methods are called after the frame header is completely |
bnc | f0db654 | 2019-09-23 11:18:28 -0700 | [diff] [blame] | 40 | // processed. At that point it is safe to consume |header_length| bytes. |
bnc | b9d07d9 | 2019-06-25 17:43:49 -0700 | [diff] [blame] | 41 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 42 | // Called when a CANCEL_PUSH frame has been successfully parsed. |
renjietang | 546a628 | 2019-06-03 10:21:21 -0700 | [diff] [blame] | 43 | virtual bool OnCancelPushFrame(const CancelPushFrame& frame) = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 44 | |
| 45 | // Called when a MAX_PUSH_ID frame has been successfully parsed. |
renjietang | 546a628 | 2019-06-03 10:21:21 -0700 | [diff] [blame] | 46 | virtual bool OnMaxPushIdFrame(const MaxPushIdFrame& frame) = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 47 | |
| 48 | // Called when a GOAWAY frame has been successfully parsed. |
renjietang | 546a628 | 2019-06-03 10:21:21 -0700 | [diff] [blame] | 49 | virtual bool OnGoAwayFrame(const GoAwayFrame& frame) = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 50 | |
renjietang | f41bf64 | 2019-04-02 11:45:34 -0700 | [diff] [blame] | 51 | // Called when a SETTINGS frame has been received. |
bnc | a2b13be | 2019-07-31 12:04:20 -0700 | [diff] [blame] | 52 | virtual bool OnSettingsFrameStart(QuicByteCount header_length) = 0; |
renjietang | f41bf64 | 2019-04-02 11:45:34 -0700 | [diff] [blame] | 53 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 54 | // Called when a SETTINGS frame has been successfully parsed. |
renjietang | 546a628 | 2019-06-03 10:21:21 -0700 | [diff] [blame] | 55 | virtual bool OnSettingsFrame(const SettingsFrame& frame) = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 56 | |
| 57 | // Called when a DUPLICATE_PUSH frame has been successfully parsed. |
renjietang | 546a628 | 2019-06-03 10:21:21 -0700 | [diff] [blame] | 58 | virtual bool OnDuplicatePushFrame(const DuplicatePushFrame& frame) = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 59 | |
bnc | 62446bc | 2019-03-14 06:11:25 -0700 | [diff] [blame] | 60 | // Called when a DATA frame has been received. |
bnc | f0db654 | 2019-09-23 11:18:28 -0700 | [diff] [blame] | 61 | // |header_length| contains DATA frame length and payload length. |
bnc | a2b13be | 2019-07-31 12:04:20 -0700 | [diff] [blame] | 62 | virtual bool OnDataFrameStart(QuicByteCount header_length) = 0; |
bnc | 7091426 | 2019-03-16 12:49:50 -0700 | [diff] [blame] | 63 | // Called when part of the payload of a DATA frame has been read. May be |
| 64 | // called multiple times for a single frame. |payload| is guaranteed to be |
| 65 | // non-empty. |
dmcardle | ba2fb7e | 2019-12-13 07:44:34 -0800 | [diff] [blame] | 66 | virtual bool OnDataFramePayload(quiche::QuicheStringPiece payload) = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 67 | // Called when a DATA frame has been completely processed. |
renjietang | 546a628 | 2019-06-03 10:21:21 -0700 | [diff] [blame] | 68 | virtual bool OnDataFrameEnd() = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 69 | |
bnc | e433f53 | 2019-04-16 13:05:27 -0700 | [diff] [blame] | 70 | // Called when a HEADERS frame has been received. |
bnc | f0db654 | 2019-09-23 11:18:28 -0700 | [diff] [blame] | 71 | // |header_length| contains HEADERS frame length and payload length. |
bnc | a2b13be | 2019-07-31 12:04:20 -0700 | [diff] [blame] | 72 | virtual bool OnHeadersFrameStart(QuicByteCount header_length) = 0; |
bnc | 7091426 | 2019-03-16 12:49:50 -0700 | [diff] [blame] | 73 | // Called when part of the payload of a HEADERS frame has been read. May be |
| 74 | // called multiple times for a single frame. |payload| is guaranteed to be |
| 75 | // non-empty. |
dmcardle | ba2fb7e | 2019-12-13 07:44:34 -0800 | [diff] [blame] | 76 | virtual bool OnHeadersFramePayload(quiche::QuicheStringPiece payload) = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 77 | // Called when a HEADERS frame has been completely processed. |
| 78 | // |frame_len| is the length of the HEADERS frame payload. |
renjietang | 546a628 | 2019-06-03 10:21:21 -0700 | [diff] [blame] | 79 | virtual bool OnHeadersFrameEnd() = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 80 | |
bnc | f0db654 | 2019-09-23 11:18:28 -0700 | [diff] [blame] | 81 | // Called when a PUSH_PROMISE frame has been received. |
| 82 | virtual bool OnPushPromiseFrameStart(QuicByteCount header_length) = 0; |
| 83 | // Called when the Push ID field of a PUSH_PROMISE frame has been parsed. |
| 84 | // Called exactly once for a valid PUSH_PROMISE frame. |
| 85 | virtual bool OnPushPromiseFramePushId(PushId push_id, |
| 86 | QuicByteCount push_id_length) = 0; |
| 87 | // Called when part of the header block of a PUSH_PROMISE frame has been |
| 88 | // read. May be called multiple times for a single frame. |payload| is |
| 89 | // guaranteed to be non-empty. |
dmcardle | ba2fb7e | 2019-12-13 07:44:34 -0800 | [diff] [blame] | 90 | virtual bool OnPushPromiseFramePayload( |
| 91 | quiche::QuicheStringPiece payload) = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 92 | // Called when a PUSH_PROMISE frame has been completely processed. |
renjietang | 546a628 | 2019-06-03 10:21:21 -0700 | [diff] [blame] | 93 | virtual bool OnPushPromiseFrameEnd() = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 94 | |
bnc | 51e8962 | 2020-01-10 10:40:32 -0800 | [diff] [blame] | 95 | // Called when a PRIORITY_UPDATE frame has been received. |
| 96 | // |header_length| contains PRIORITY_UPDATE frame length and payload length. |
| 97 | virtual bool OnPriorityUpdateFrameStart(QuicByteCount header_length) = 0; |
| 98 | |
| 99 | // Called when a PRIORITY_UPDATE frame has been successfully parsed. |
| 100 | virtual bool OnPriorityUpdateFrame(const PriorityUpdateFrame& frame) = 0; |
| 101 | |
bnc | bf3dbe5 | 2019-07-17 05:17:41 -0700 | [diff] [blame] | 102 | // Called when a frame of unknown type |frame_type| has been received. |
| 103 | // Frame type might be reserved, Visitor must make sure to ignore. |
bnc | f0db654 | 2019-09-23 11:18:28 -0700 | [diff] [blame] | 104 | // |header_length| contains frame length and payload length. |
bnc | bf3dbe5 | 2019-07-17 05:17:41 -0700 | [diff] [blame] | 105 | virtual bool OnUnknownFrameStart(uint64_t frame_type, |
bnc | a2b13be | 2019-07-31 12:04:20 -0700 | [diff] [blame] | 106 | QuicByteCount header_length) = 0; |
bnc | bf3dbe5 | 2019-07-17 05:17:41 -0700 | [diff] [blame] | 107 | // Called when part of the payload of the unknown frame has been read. May |
| 108 | // be called multiple times for a single frame. |payload| is guaranteed to |
| 109 | // be non-empty. |
dmcardle | ba2fb7e | 2019-12-13 07:44:34 -0800 | [diff] [blame] | 110 | virtual bool OnUnknownFramePayload(quiche::QuicheStringPiece payload) = 0; |
bnc | bf3dbe5 | 2019-07-17 05:17:41 -0700 | [diff] [blame] | 111 | // Called when the unknown frame has been completely processed. |
| 112 | virtual bool OnUnknownFrameEnd() = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 113 | }; |
| 114 | |
bnc | a9bb469 | 2019-07-09 17:29:48 -0700 | [diff] [blame] | 115 | // |visitor| must be non-null, and must outlive HttpDecoder. |
| 116 | explicit HttpDecoder(Visitor* visitor); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 117 | |
| 118 | ~HttpDecoder(); |
| 119 | |
bnc | b9d07d9 | 2019-06-25 17:43:49 -0700 | [diff] [blame] | 120 | // Processes the input and invokes the appropriate visitor methods, until a |
| 121 | // visitor method returns false or an error occurs. Returns the number of |
| 122 | // bytes processed. Does not process any input if called after an error. |
| 123 | // Paused processing can be resumed by calling ProcessInput() again with the |
bnc | 620095a | 2019-06-26 05:31:05 -0700 | [diff] [blame] | 124 | // unprocessed portion of data. Must not be called after an error has |
| 125 | // occurred. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 126 | QuicByteCount ProcessInput(const char* data, QuicByteCount len); |
| 127 | |
bnc | 620095a | 2019-06-26 05:31:05 -0700 | [diff] [blame] | 128 | // Returns an error code other than QUIC_NO_ERROR if and only if |
| 129 | // Visitor::OnError() has been called. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 130 | QuicErrorCode error() const { return error_; } |
bnc | 620095a | 2019-06-26 05:31:05 -0700 | [diff] [blame] | 131 | |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 132 | const std::string& error_detail() const { return error_detail_; } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 133 | |
| 134 | private: |
bnc | 62c32b4 | 2019-06-24 16:06:41 -0700 | [diff] [blame] | 135 | friend test::HttpDecoderPeer; |
| 136 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 137 | // Represents the current state of the parsing state machine. |
| 138 | enum HttpDecoderState { |
| 139 | STATE_READING_FRAME_LENGTH, |
| 140 | STATE_READING_FRAME_TYPE, |
| 141 | STATE_READING_FRAME_PAYLOAD, |
bnc | 7091426 | 2019-03-16 12:49:50 -0700 | [diff] [blame] | 142 | STATE_FINISH_PARSING, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 143 | STATE_ERROR |
| 144 | }; |
| 145 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 146 | // Reads the type of a frame from |reader|. Sets error_ and error_detail_ |
bnc | 7091426 | 2019-03-16 12:49:50 -0700 | [diff] [blame] | 147 | // if there are any errors. Also calls OnDataFrameStart() or |
| 148 | // OnHeadersFrameStart() for appropriate frame types. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 149 | void ReadFrameType(QuicDataReader* reader); |
| 150 | |
renjietang | fcd91c0 | 2019-04-22 10:40:35 -0700 | [diff] [blame] | 151 | // Reads the length of a frame from |reader|. Sets error_ and error_detail_ |
bnc | b9d07d9 | 2019-06-25 17:43:49 -0700 | [diff] [blame] | 152 | // if there are any errors. Returns whether processing should continue. |
| 153 | bool ReadFrameLength(QuicDataReader* reader); |
renjietang | fcd91c0 | 2019-04-22 10:40:35 -0700 | [diff] [blame] | 154 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 155 | // Reads the payload of the current frame from |reader| and processes it, |
bnc | b9d07d9 | 2019-06-25 17:43:49 -0700 | [diff] [blame] | 156 | // possibly buffering the data or invoking the visitor. Returns whether |
| 157 | // processing should continue. |
| 158 | bool ReadFramePayload(QuicDataReader* reader); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 159 | |
bnc | 7091426 | 2019-03-16 12:49:50 -0700 | [diff] [blame] | 160 | // Optionally parses buffered data; calls visitor method to signal that frame |
bnc | b9d07d9 | 2019-06-25 17:43:49 -0700 | [diff] [blame] | 161 | // had been parsed completely. Returns whether processing should continue. |
| 162 | bool FinishParsing(); |
bnc | 7091426 | 2019-03-16 12:49:50 -0700 | [diff] [blame] | 163 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 164 | // Discards any remaining frame payload from |reader|. |
| 165 | void DiscardFramePayload(QuicDataReader* reader); |
| 166 | |
| 167 | // Buffers any remaining frame payload from |reader| into |buffer_|. |
| 168 | void BufferFramePayload(QuicDataReader* reader); |
| 169 | |
| 170 | // Buffers any remaining frame length field from |reader| into |
renjietang | 2d475cf | 2019-04-18 17:03:37 -0700 | [diff] [blame] | 171 | // |length_buffer_|. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 172 | void BufferFrameLength(QuicDataReader* reader); |
| 173 | |
renjietang | 2d475cf | 2019-04-18 17:03:37 -0700 | [diff] [blame] | 174 | // Buffers any remaining frame type field from |reader| into |type_buffer_|. |
| 175 | void BufferFrameType(QuicDataReader* reader); |
| 176 | |
renjietang | 857362b | 2019-08-09 09:52:35 -0700 | [diff] [blame] | 177 | // Buffers at most |remaining_push_id_length_| from |reader| to |
| 178 | // |push_id_buffer_|. |
| 179 | void BufferPushId(QuicDataReader* reader); |
| 180 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 181 | // Sets |error_| and |error_detail_| accordingly. |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 182 | void RaiseError(QuicErrorCode error, std::string error_detail); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 183 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 184 | // Parses the payload of a SETTINGS frame from |reader| into |frame|. |
| 185 | bool ParseSettingsFrame(QuicDataReader* reader, SettingsFrame* frame); |
| 186 | |
bnc | 51e8962 | 2020-01-10 10:40:32 -0800 | [diff] [blame] | 187 | // Parses the payload of a PRIORITY_UPDATE frame from |reader| into |frame|. |
| 188 | bool ParsePriorityUpdateFrame(QuicDataReader* reader, |
| 189 | PriorityUpdateFrame* frame); |
| 190 | |
renjietang | 4ab9d9f | 2019-04-10 14:30:26 -0700 | [diff] [blame] | 191 | // Returns the max frame size of a given |frame_type|. |
bnc | 95fb6b6 | 2019-07-21 11:20:47 -0700 | [diff] [blame] | 192 | QuicByteCount MaxFrameLength(uint64_t frame_type); |
renjietang | 4ab9d9f | 2019-04-10 14:30:26 -0700 | [diff] [blame] | 193 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 194 | // Visitor to invoke when messages are parsed. |
bnc | a9bb469 | 2019-07-09 17:29:48 -0700 | [diff] [blame] | 195 | Visitor* const visitor_; // Unowned. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 196 | // Current state of the parsing. |
| 197 | HttpDecoderState state_; |
| 198 | // Type of the frame currently being parsed. |
renjietang | 2d475cf | 2019-04-18 17:03:37 -0700 | [diff] [blame] | 199 | uint64_t current_frame_type_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 200 | // Size of the frame's length field. |
renjietang | bb98cbc | 2019-04-23 13:13:56 -0700 | [diff] [blame] | 201 | QuicByteCount current_length_field_length_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 202 | // Remaining length that's needed for the frame's length field. |
| 203 | QuicByteCount remaining_length_field_length_; |
| 204 | // Length of the payload of the frame currently being parsed. |
| 205 | QuicByteCount current_frame_length_; |
| 206 | // Remaining payload bytes to be parsed. |
| 207 | QuicByteCount remaining_frame_length_; |
renjietang | 2d475cf | 2019-04-18 17:03:37 -0700 | [diff] [blame] | 208 | // Length of the frame's type field. |
| 209 | QuicByteCount current_type_field_length_; |
| 210 | // Remaining length that's needed for the frame's type field. |
| 211 | QuicByteCount remaining_type_field_length_; |
renjietang | 857362b | 2019-08-09 09:52:35 -0700 | [diff] [blame] | 212 | // Length of PUSH_PROMISE frame's push id. |
| 213 | QuicByteCount current_push_id_length_; |
| 214 | // Remaining length that's needed for PUSH_PROMISE frame's push id field. |
| 215 | QuicByteCount remaining_push_id_length_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 216 | // Last error. |
| 217 | QuicErrorCode error_; |
| 218 | // The issue which caused |error_| |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 219 | std::string error_detail_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 220 | // Remaining unparsed data. |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 221 | std::string buffer_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 222 | // Remaining unparsed length field data. |
renjietang | bb98cbc | 2019-04-23 13:13:56 -0700 | [diff] [blame] | 223 | std::array<char, sizeof(uint64_t)> length_buffer_; |
renjietang | 2d475cf | 2019-04-18 17:03:37 -0700 | [diff] [blame] | 224 | // Remaining unparsed type field data. |
| 225 | std::array<char, sizeof(uint64_t)> type_buffer_; |
renjietang | 857362b | 2019-08-09 09:52:35 -0700 | [diff] [blame] | 226 | // Remaining unparsed push id data. |
| 227 | std::array<char, sizeof(uint64_t)> push_id_buffer_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 228 | }; |
| 229 | |
| 230 | } // namespace quic |
| 231 | |
| 232 | #endif // QUICHE_QUIC_CORE_HTTP_HTTP_DECODER_H_ |