1
#pragma once
2

            
3
#include <array>
4
#include <cstdint>
5
#include <vector>
6

            
7
#include "envoy/buffer/buffer.h"
8

            
9
#include "source/common/common/logger.h"
10

            
11
namespace Envoy {
12
namespace WebSocket {
13

            
14
// Opcodes (https://datatracker.ietf.org/doc/html/rfc6455#section-11.8)
15
constexpr uint8_t kFrameOpcodeContinuation = 0;
16
constexpr uint8_t kFrameOpcodeText = 1;
17
constexpr uint8_t kFrameOpcodeBinary = 2;
18
constexpr uint8_t kFrameOpcodeClose = 8;
19
constexpr uint8_t kFrameOpcodePing = 9;
20
constexpr uint8_t kFrameOpcodePong = 10;
21
constexpr std::array<uint8_t, 6> kFrameOpcodes = {kFrameOpcodeContinuation, kFrameOpcodeText,
22
                                                  kFrameOpcodeBinary,       kFrameOpcodeClose,
23
                                                  kFrameOpcodePing,         kFrameOpcodePong};
24

            
25
// Length of the masking key which is 4 bytes fixed size
26
constexpr uint8_t kMaskingKeyLength = 4;
27
// 16 bit payload length
28
constexpr uint8_t kPayloadLength16Bit = 2;
29
// 64 bit payload length
30
constexpr uint8_t kPayloadLength64Bit = 8;
31
// Maximum payload buffer length
32
constexpr uint64_t kMaxPayloadBufferLength = 0x7fffffffffffffff;
33

            
34
// Wire format (https://datatracker.ietf.org/doc/html/rfc6455#section-5.2)
35
// of WebSocket frame:
36
//
37
//   0                   1                   2                   3
38
//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
39
//  +-+-+-+-+-------+-+-------------+-------------------------------+
40
//  |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
41
//  |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
42
//  |N|V|V|V|       |S|             |   (if payload len==126/127)   |
43
//  | |1|2|3|       |K|             |                               |
44
//  +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
45
//  |     Extended payload length continued, if payload len == 127  |
46
//  + - - - - - - - - - - - - - - - +-------------------------------+
47
//  |                               | Masking-key, if MASK set to 1 |
48
//  +-------------------------------+-------------------------------+
49
//  | Masking-key (continued)       |          Payload Data         |
50
//  +-------------------------------- - - - - - - - - - - - - - - - +
51
//  : .... Payload Data continued .... Payload Data continued ..... :
52
//  + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
53
//  | .... Payload Data continued .... Payload Data continued ..... |
54
//  +---------------------------------------------------------------+
55

            
56
// In-memory representation of the contents of a WebSocket frame.
57
struct Frame {
58
  // Indicates that this is the final fragment in a message.
59
  bool final_fragment_;
60
  // Frame opcode.
61
  uint8_t opcode_;
62
  // The 4 byte fixed size masking key used to mask the payload. Masking/unmasking should be
63
  // performed as described in https://datatracker.ietf.org/doc/html/rfc6455#section-5.3
64
  absl::optional<uint32_t> masking_key_;
65
  // Length of the payload as the number of bytes.
66
  uint64_t payload_length_;
67
  // WebSocket payload data (extension data and application data).
68
  Buffer::InstancePtr payload_;
69
};
70

            
71
// Encoder encodes in memory WebSocket frames into frames in the wire format
72
class Encoder : public Logger::Loggable<Logger::Id::websocket> {
73
public:
74
  Encoder() = default;
75

            
76
  // Creates a new Websocket data frame header with the given frame data.
77
  // @param frame supplies the frame to be encoded.
78
  // @return std::vector<uint8_t> buffer with encoded header data.
79
  absl::optional<std::vector<uint8_t>> encodeFrameHeader(const Frame& frame);
80
};
81

            
82
// Decoder decodes bytes in input buffer into in-memory WebSocket frames.
83
class Decoder : public Logger::Loggable<Logger::Id::websocket> {
84
public:
85
  Decoder(uint64_t max_payload_length = 0)
86
37
      : max_payload_buffer_length_{std::min(max_payload_length, kMaxPayloadBufferLength)} {};
87
  // Decodes the given buffer into WebSocket frames. If the input is not sufficient to make a
88
  // complete WebSocket frame, then the decoder saves the state of halfway decoded WebSocket
89
  // frame until the next decode calls feed rest of the frame data.
90
  // @param input supplies the binary octets wrapped in a WebSocket frame.
91
  // @return the decoded frames.
92
  absl::optional<std::vector<Frame>> decode(const Buffer::Instance& input);
93

            
94
private:
95
  void resetDecoder();
96
  void frameDataStart();
97
  void frameData(const uint8_t* mem, uint64_t length);
98
  void frameDataEnd(std::vector<Frame>& output);
99

            
100
  uint8_t doDecodeFlagsAndOpcode(absl::Span<const uint8_t>& data);
101
  uint8_t doDecodeMaskFlagAndLength(absl::Span<const uint8_t>& data);
102
  uint8_t doDecodeExtendedLength(absl::Span<const uint8_t>& data);
103
  uint8_t doDecodeMaskingKey(absl::Span<const uint8_t>& data);
104
  uint64_t doDecodePayload(absl::Span<const uint8_t>& data);
105

            
106
  // Current state of the frame that is being processed.
107
  enum class State {
108
    // Decoding the first byte. Waiting for decoding the final frame flag (1 bit)
109
    // and reserved flags (3 bits) and opcode (4 bits) of the WebSocket data frame.
110
    FrameHeaderFlagsAndOpcode,
111
    // Decoding the second byte. Waiting for decoding the mask flag (1 bit) and
112
    // length/length flag (7 bit) of the WebSocket data frame.
113
    FrameHeaderMaskFlagAndLength,
114
    // Waiting for decoding the extended 16 bit length.
115
    FrameHeaderExtendedLength16Bit,
116
    // Waiting for decoding the extended 64 bit length.
117
    FrameHeaderExtendedLength64Bit,
118
    // Waiting for decoding the masking key (4 bytes) only if the mask bit is set.
119
    FrameHeaderMaskingKey,
120
    // Waiting for decoding the payload (both extension data and application data).
121
    FramePayload,
122
    // Frame has finished decoding.
123
    FrameFinished
124
  };
125
  uint64_t max_payload_buffer_length_;
126
  // Current frame that is being decoded.
127
  Frame frame_;
128
  State state_ = State::FrameHeaderFlagsAndOpcode;
129
  uint64_t length_ = 0;
130
  uint8_t num_remaining_extended_length_bytes_ = 0;
131
  uint8_t num_remaining_masking_key_bytes_ = 0;
132
};
133

            
134
} // namespace WebSocket
135
} // namespace Envoy