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 | |
| 8 | #include <cstddef> |
| 9 | |
| 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" |
| 12 | #include "net/third_party/quiche/src/quic/core/quic_types.h" |
| 13 | #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" |
| 14 | #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" |
| 15 | |
| 16 | namespace quic { |
| 17 | |
| 18 | class QuicDataReader; |
| 19 | |
bnc | 62446bc | 2019-03-14 06:11:25 -0700 | [diff] [blame] | 20 | // Struct that stores meta data of an HTTP/3 frame. |
| 21 | // |header_length| is frame header length in bytes. |
| 22 | // |payload_length| is frame payload length in bytes. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 23 | struct QUIC_EXPORT_PRIVATE Http3FrameLengths { |
| 24 | Http3FrameLengths(QuicByteCount header, QuicByteCount payload) |
| 25 | : header_length(header), payload_length(payload) {} |
| 26 | |
| 27 | bool operator==(const Http3FrameLengths& other) const { |
| 28 | return (header_length == other.header_length) && |
| 29 | (payload_length == other.payload_length); |
| 30 | } |
| 31 | |
| 32 | QuicByteCount header_length; |
| 33 | QuicByteCount payload_length; |
| 34 | }; |
| 35 | |
| 36 | // A class for decoding the HTTP frames that are exchanged in an HTTP over QUIC |
| 37 | // session. |
| 38 | class QUIC_EXPORT_PRIVATE HttpDecoder { |
| 39 | public: |
| 40 | class QUIC_EXPORT_PRIVATE Visitor { |
| 41 | public: |
| 42 | virtual ~Visitor() {} |
| 43 | |
| 44 | // Called if an error is detected. |
| 45 | virtual void OnError(HttpDecoder* decoder) = 0; |
| 46 | |
| 47 | // Called when a PRIORITY frame has been successfully parsed. |
| 48 | virtual void OnPriorityFrame(const PriorityFrame& frame) = 0; |
| 49 | |
| 50 | // Called when a CANCEL_PUSH frame has been successfully parsed. |
| 51 | virtual void OnCancelPushFrame(const CancelPushFrame& frame) = 0; |
| 52 | |
| 53 | // Called when a MAX_PUSH_ID frame has been successfully parsed. |
| 54 | virtual void OnMaxPushIdFrame(const MaxPushIdFrame& frame) = 0; |
| 55 | |
| 56 | // Called when a GOAWAY frame has been successfully parsed. |
| 57 | virtual void OnGoAwayFrame(const GoAwayFrame& frame) = 0; |
| 58 | |
| 59 | // Called when a SETTINGS frame has been successfully parsed. |
| 60 | virtual void OnSettingsFrame(const SettingsFrame& frame) = 0; |
| 61 | |
| 62 | // Called when a DUPLICATE_PUSH frame has been successfully parsed. |
| 63 | virtual void OnDuplicatePushFrame(const DuplicatePushFrame& frame) = 0; |
| 64 | |
bnc | 62446bc | 2019-03-14 06:11:25 -0700 | [diff] [blame] | 65 | // Called when a DATA frame has been received. |
| 66 | // |frame_length| contains DATA frame length and payload length. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 67 | virtual void OnDataFrameStart(Http3FrameLengths frame_length) = 0; |
bnc | 7091426 | 2019-03-16 12:49:50 -0700 | [diff] [blame] | 68 | // Called when part of the payload of a DATA frame has been read. May be |
| 69 | // called multiple times for a single frame. |payload| is guaranteed to be |
| 70 | // non-empty. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 71 | virtual void OnDataFramePayload(QuicStringPiece payload) = 0; |
| 72 | // Called when a DATA frame has been completely processed. |
| 73 | virtual void OnDataFrameEnd() = 0; |
| 74 | |
| 75 | // Called when a HEADERS frame has been recevied. |
bnc | 62446bc | 2019-03-14 06:11:25 -0700 | [diff] [blame] | 76 | // |frame_length| contains HEADERS frame length and payload length. |
| 77 | virtual void OnHeadersFrameStart(Http3FrameLengths frame_length) = 0; |
bnc | 7091426 | 2019-03-16 12:49:50 -0700 | [diff] [blame] | 78 | // Called when part of the payload of a HEADERS frame has been read. May be |
| 79 | // called multiple times for a single frame. |payload| is guaranteed to be |
| 80 | // non-empty. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 81 | virtual void OnHeadersFramePayload(QuicStringPiece payload) = 0; |
| 82 | // Called when a HEADERS frame has been completely processed. |
| 83 | // |frame_len| is the length of the HEADERS frame payload. |
| 84 | virtual void OnHeadersFrameEnd(QuicByteCount frame_len) = 0; |
| 85 | |
| 86 | // Called when a PUSH_PROMISE frame has been recevied for |push_id|. |
| 87 | virtual void OnPushPromiseFrameStart(PushId push_id) = 0; |
bnc | 7091426 | 2019-03-16 12:49:50 -0700 | [diff] [blame] | 88 | // Called when part of the payload of a PUSH_PROMISE frame has been read. |
| 89 | // May be called multiple times for a single frame. |payload| is guaranteed |
| 90 | // to be non-empty. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 91 | virtual void OnPushPromiseFramePayload(QuicStringPiece payload) = 0; |
| 92 | // Called when a PUSH_PROMISE frame has been completely processed. |
| 93 | virtual void OnPushPromiseFrameEnd() = 0; |
| 94 | |
| 95 | // TODO(rch): Consider adding methods like: |
| 96 | // OnUnknownFrame{Start,Payload,End}() |
| 97 | // to allow callers to handle unknown frames. |
| 98 | }; |
| 99 | |
| 100 | HttpDecoder(); |
| 101 | |
| 102 | ~HttpDecoder(); |
| 103 | |
| 104 | // Set callbacks to be called from the decoder. A visitor must be set, or |
| 105 | // else the decoder will crash. It is acceptable for the visitor to do |
| 106 | // nothing. If this is called multiple times, only the last visitor |
| 107 | // will be used. |visitor| will be owned by the caller. |
| 108 | void set_visitor(Visitor* visitor) { visitor_ = visitor; } |
| 109 | |
| 110 | // Processes the input and invokes the visitor for any frames. |
| 111 | // Returns the number of bytes consumed, or 0 if there was an error, in which |
| 112 | // case error() should be consulted. |
| 113 | QuicByteCount ProcessInput(const char* data, QuicByteCount len); |
| 114 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 115 | QuicErrorCode error() const { return error_; } |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 116 | const std::string& error_detail() const { return error_detail_; } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 117 | |
| 118 | private: |
| 119 | // Represents the current state of the parsing state machine. |
| 120 | enum HttpDecoderState { |
| 121 | STATE_READING_FRAME_LENGTH, |
| 122 | STATE_READING_FRAME_TYPE, |
| 123 | STATE_READING_FRAME_PAYLOAD, |
bnc | 7091426 | 2019-03-16 12:49:50 -0700 | [diff] [blame] | 124 | STATE_FINISH_PARSING, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 125 | STATE_ERROR |
| 126 | }; |
| 127 | |
| 128 | // Reads the length of a frame from |reader|. Sets error_ and error_detail_ |
| 129 | // if there are any errors. |
| 130 | void ReadFrameLength(QuicDataReader* reader); |
| 131 | |
| 132 | // Reads the type of a frame from |reader|. Sets error_ and error_detail_ |
bnc | 7091426 | 2019-03-16 12:49:50 -0700 | [diff] [blame] | 133 | // if there are any errors. Also calls OnDataFrameStart() or |
| 134 | // OnHeadersFrameStart() for appropriate frame types. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 135 | void ReadFrameType(QuicDataReader* reader); |
| 136 | |
| 137 | // Reads the payload of the current frame from |reader| and processes it, |
| 138 | // possibly buffering the data or invoking the visitor. |
| 139 | void ReadFramePayload(QuicDataReader* reader); |
| 140 | |
bnc | 7091426 | 2019-03-16 12:49:50 -0700 | [diff] [blame] | 141 | // Optionally parses buffered data; calls visitor method to signal that frame |
| 142 | // had been parsed completely. |
| 143 | void FinishParsing(); |
| 144 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 145 | // Discards any remaining frame payload from |reader|. |
| 146 | void DiscardFramePayload(QuicDataReader* reader); |
| 147 | |
| 148 | // Buffers any remaining frame payload from |reader| into |buffer_|. |
| 149 | void BufferFramePayload(QuicDataReader* reader); |
| 150 | |
| 151 | // Buffers any remaining frame length field from |reader| into |
| 152 | // |length_buffer_| |
| 153 | void BufferFrameLength(QuicDataReader* reader); |
| 154 | |
| 155 | // Sets |error_| and |error_detail_| accordingly. |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 156 | void RaiseError(QuicErrorCode error, std::string error_detail); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 157 | |
| 158 | // Parses the payload of a PRIORITY frame from |reader| into |frame|. |
| 159 | bool ParsePriorityFrame(QuicDataReader* reader, PriorityFrame* frame); |
| 160 | |
| 161 | // Parses the payload of a SETTINGS frame from |reader| into |frame|. |
| 162 | bool ParseSettingsFrame(QuicDataReader* reader, SettingsFrame* frame); |
| 163 | |
| 164 | // Visitor to invoke when messages are parsed. |
| 165 | Visitor* visitor_; // Unowned. |
| 166 | // Current state of the parsing. |
| 167 | HttpDecoderState state_; |
| 168 | // Type of the frame currently being parsed. |
| 169 | uint8_t current_frame_type_; |
| 170 | // Size of the frame's length field. |
| 171 | QuicByteCount current_length_field_size_; |
| 172 | // Remaining length that's needed for the frame's length field. |
| 173 | QuicByteCount remaining_length_field_length_; |
| 174 | // Length of the payload of the frame currently being parsed. |
| 175 | QuicByteCount current_frame_length_; |
| 176 | // Remaining payload bytes to be parsed. |
| 177 | QuicByteCount remaining_frame_length_; |
| 178 | // Last error. |
| 179 | QuicErrorCode error_; |
| 180 | // The issue which caused |error_| |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 181 | std::string error_detail_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 182 | // Remaining unparsed data. |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 183 | std::string buffer_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 184 | // Remaining unparsed length field data. |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 185 | std::string length_buffer_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 186 | }; |
| 187 | |
| 188 | } // namespace quic |
| 189 | |
| 190 | #endif // QUICHE_QUIC_CORE_HTTP_HTTP_DECODER_H_ |