protocol-websocket 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c93940911ada80aa95de9bf5a1412dd20248a77855f4b9bd523a06b699294795
4
- data.tar.gz: f7fd77275a0d1269e3586e56b08f18f2e10f18c816085e8bea7de95da4d282b0
3
+ metadata.gz: 03d416a8b81559d07517a00db06f2740b42c1a4e311ab2b1cbc22fcd58041f49
4
+ data.tar.gz: af5e7dcf5f2a3d28a7b21a959827462753b5af2f28e9b5f2b41af03c9a09f590
5
5
  SHA512:
6
- metadata.gz: 2d54e303617a6ff069bf7ee5e8cb5539c3217bfa0613e2290203edca66695ad926ff40959c2edf694a82b05485a403ec96bedccf76587ae47e3107ff8ccd49ec
7
- data.tar.gz: 8d07512b928d9060af02945caf8cc1680154f220c4f741ee23fc9520f5d8e3f1ae99470aa28d390b9c9611de667eed0e6c58ffb59b705d356b117a51fc3908ee
6
+ metadata.gz: 0ce48f4ee999d45de148dab68f3b5c7adaca5c35d0d67a2f4cf5a24a80428de545620c9c4eae7c0e96c8950da49b48c34fd98fcde3fb558b0e8111edd971e418
7
+ data.tar.gz: 20a33a6c1b1a58cff116973575cf5de64778e9a4a3c5ce74c7de2310c3b4f1ee37e290d6cac705c3e2698cb4452bad9f9de2494104b0b04daa0deab0ab589a4c
checksums.yaml.gz.sig CHANGED
@@ -1,2 +1 @@
1
- ���y*���
2
- �%��1�dGHjW�� j��n�k��l��{�@9�������8������R�/,Z�e7u��I���Y��7)������,�����r(
1
+ DN�3D�*�_C�CZwꌆ#�>��ׂKί�Z���X�$u�v��C�UFu�^1m�'�)��+�t�@�����ϝ�J�&���C�Bg�����i���ȿ:�-�U��mu=7�b}1��`�|�����y����F6��{��k�3rgE��TЪ!]vi6?{q��Ψ�Ƅ� �| ���F�J�PD�Y��` W�B��5R�'�"-,gV�6�g_���`K�i�b�`p���8�L��+�3���\���Ҥd�}|��2kn�ޢ�TܬH��Jq�)��6��o�����-��GhT�iv����f|�6-�k�ױ�z�{�fK�mo�?��<*3�V���v/�2��� V��ZlԤN�z��.���iۧ�����L
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
  # Copyright, 2021, by Aurora Nockert.
6
6
 
7
7
  require_relative 'frame'
@@ -9,17 +9,22 @@ require_relative 'message'
9
9
 
10
10
  module Protocol
11
11
  module WebSocket
12
+ # Represents a binary frame that is sent or received by a WebSocket connection.
12
13
  class BinaryFrame < Frame
13
14
  OPCODE = 0x2
14
15
 
16
+ # @returns [Boolean] if the frame contains data.
15
17
  def data?
16
18
  true
17
19
  end
18
20
 
21
+ # Decode the binary buffer into a suitable binary message.
22
+ # @parameter buffer [String] The binary data to unpack.
19
23
  def read_message(buffer)
20
24
  return BinaryMessage.new(buffer)
21
25
  end
22
26
 
27
+ # Apply this frame to the specified connection.
23
28
  def apply(connection)
24
29
  connection.receive_binary(self)
25
30
  end
@@ -1,17 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
  # Copyright, 2021, by Aurora Nockert.
6
6
 
7
7
  require_relative 'frame'
8
8
 
9
9
  module Protocol
10
10
  module WebSocket
11
+ # Represents a close frame that is sent or received by a WebSocket connection.
11
12
  class CloseFrame < Frame
12
13
  OPCODE = 0x8
13
14
  FORMAT = "na*"
14
15
 
16
+ # Unpack the frame data into a close code and reason.
17
+ # @returns [Tuple(Integer, String)] The close code and reason.
15
18
  def unpack
16
19
  data = super
17
20
 
@@ -40,7 +43,10 @@ module Protocol
40
43
  end
41
44
  end
42
45
 
46
+ # Pack a close code and reason into the frame data.
43
47
  # If code is missing, reason is ignored.
48
+ # @parameter code [Integer | Nil] The close code.
49
+ # @parameter reason [String | Nil] The close reason.
44
50
  def pack(code = nil, reason = nil)
45
51
  if code
46
52
  if reason and reason.encoding != Encoding::UTF_8
@@ -53,6 +59,7 @@ module Protocol
53
59
  end
54
60
  end
55
61
 
62
+ # Apply this frame to the specified connection.
56
63
  def apply(connection)
57
64
  connection.receive_close(self)
58
65
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ require 'json'
7
+
8
+ module Protocol
9
+ module WebSocket
10
+ module Coder
11
+ # A JSON coder that uses the standard JSON library.
12
+ class JSON
13
+ def initialize(**options)
14
+ @options = options
15
+ end
16
+
17
+ # Parse a JSON buffer into an object.
18
+ def parse(buffer)
19
+ ::JSON.parse(buffer, **@options)
20
+ end
21
+
22
+ # Generate a JSON buffer from an object.
23
+ def generate(object)
24
+ ::JSON.generate(object, **@options)
25
+ end
26
+
27
+ # The default JSON coder. This coder will symbolize names.
28
+ DEFAULT = new(symbolize_names: true)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ require_relative 'coder/json'
7
+
8
+ module Protocol
9
+ module WebSocket
10
+ module Coder
11
+ # The default coder for WebSocket messages.
12
+ DEFAULT = JSON::DEFAULT
13
+ end
14
+ end
15
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
  # Copyright, 2019, by William T. Nelson.
6
6
  # Copyright, 2021, by Aurora Nockert.
7
7
 
@@ -26,21 +26,26 @@ module Protocol
26
26
  @writer = self
27
27
  end
28
28
 
29
- # The framer which is used for reading and writing frames.
29
+ # @attribute [Framer] The framer which is used for reading and writing frames.
30
30
  attr :framer
31
31
 
32
- # The (optional) mask which is used when generating frames.
32
+ # @attribte [String | Nil] The optional mask which is used when generating frames.
33
33
  attr :mask
34
34
 
35
- # The allowed reserved bits:
35
+ # @attribute [Integer] The allowed reserved bits.
36
36
  attr :reserved
37
37
 
38
- # Buffered frames which form part of a complete message.
38
+ # @attribute [Array(Frame)] Buffered frames which form part of a complete message.
39
39
  attr_accessor :frames
40
40
 
41
+ # @attribute [Object] The reader which is used to unpack frames into messages.
41
42
  attr_accessor :reader
43
+
44
+ # @attribute [Object] The writer which is used to pack messages into frames.
42
45
  attr_accessor :writer
43
46
 
47
+ # Reserve a bit in the reserved flags for an extension.
48
+ # @parameter bit [Integer] The bit to reserve, see {Frame::RESERVED} for more details.
44
49
  def reserve!(bit)
45
50
  if (@reserved & bit).zero?
46
51
  raise ArgumentError, "Unable to use #{bit}!"
@@ -51,10 +56,12 @@ module Protocol
51
56
  return true
52
57
  end
53
58
 
59
+ # Flush the underlying framer to ensure all buffered data is written to the connection.
54
60
  def flush
55
61
  @framer.flush
56
62
  end
57
63
 
64
+ # Transition the connection to the open state (the default for new connections).
58
65
  def open!
59
66
  @state = :open
60
67
 
@@ -62,6 +69,7 @@ module Protocol
62
69
  end
63
70
 
64
71
  # If not already closed, transition the connection to the closed state and send a close frame.
72
+ # Will try to send a close frame with the specified code and reason, but will ignore any errors that occur while sending.
65
73
  def close!(...)
66
74
  unless @state == :closed
67
75
  @state = :closed
@@ -76,17 +84,19 @@ module Protocol
76
84
  return self
77
85
  end
78
86
 
87
+ # @returns [Boolean] if the connection is in the closed state.
79
88
  def closed?
80
89
  @state == :closed
81
90
  end
82
91
 
83
- # Immediately transition the connection to the closed state and close the underlying connection.
92
+ # Immediately transition the connection to the closed state *and* close the underlying connection.
84
93
  def close(...)
85
94
  close!(...)
86
95
 
87
96
  @framer.close
88
97
  end
89
98
 
99
+ # Read a frame from the framer, and apply it to the connection.
90
100
  def read_frame
91
101
  return nil if closed?
92
102
 
@@ -109,12 +119,15 @@ module Protocol
109
119
  raise
110
120
  end
111
121
 
122
+ # Write a frame to the framer.
123
+ # Note: This does not immediately write the frame to the connection, you must call {#flush} to ensure the frame is written.
112
124
  def write_frame(frame)
113
125
  @framer.write_frame(frame)
114
126
 
115
127
  return frame
116
128
  end
117
129
 
130
+ # Receive a text frame from the connection.
118
131
  def receive_text(frame)
119
132
  if @frames.empty?
120
133
  @frames << frame
@@ -123,6 +136,7 @@ module Protocol
123
136
  end
124
137
  end
125
138
 
139
+ # Receive a binary frame for the connection.
126
140
  def receive_binary(frame)
127
141
  if @frames.empty?
128
142
  @frames << frame
@@ -131,6 +145,7 @@ module Protocol
131
145
  end
132
146
  end
133
147
 
148
+ # Receive a continuation frame for the connection.
134
149
  def receive_continuation(frame)
135
150
  if @frames.any?
136
151
  @frames << frame
@@ -138,7 +153,8 @@ module Protocol
138
153
  raise ProtocolError, "Received unexpected continuation!"
139
154
  end
140
155
  end
141
-
156
+
157
+ # Receive a close frame from the connection.
142
158
  def receive_close(frame)
143
159
  code, reason = frame.unpack
144
160
 
@@ -150,6 +166,8 @@ module Protocol
150
166
  end
151
167
  end
152
168
 
169
+ # Send a ping frame with the specified data.
170
+ # @parameter data [String] The data to send in the ping frame.
153
171
  def send_ping(data = "")
154
172
  if @state != :closed
155
173
  frame = PingFrame.new(mask: @mask)
@@ -161,6 +179,7 @@ module Protocol
161
179
  end
162
180
  end
163
181
 
182
+ # Receive a ping frame from the connection.
164
183
  def receive_ping(frame)
165
184
  if @state != :closed
166
185
  write_frame(frame.reply(mask: @mask))
@@ -169,14 +188,19 @@ module Protocol
169
188
  end
170
189
  end
171
190
 
191
+ # Receive a pong frame from the connection. By default, this method does nothing.
172
192
  def receive_pong(frame)
173
193
  # Ignore.
174
194
  end
175
195
 
196
+ # Receive a frame that is not a control frame. By default, this method raises a {ProtocolError}.
176
197
  def receive_frame(frame)
177
198
  raise ProtocolError, "Unhandled frame: #{frame}"
178
199
  end
179
200
 
201
+ # Pack a text frame with the specified buffer. This is used by the {#writer} interface.
202
+ # @parameter buffer [String] The text to pack into the frame.
203
+ # @returns [TextFrame] The packed frame.
180
204
  def pack_text_frame(buffer, **options)
181
205
  frame = TextFrame.new(mask: @mask)
182
206
  frame.pack(buffer)
@@ -184,10 +208,15 @@ module Protocol
184
208
  return frame
185
209
  end
186
210
 
211
+ # Send a text frame with the specified buffer.
212
+ # @parameter buffer [String] The text to send.
187
213
  def send_text(buffer, **options)
188
214
  write_frame(@writer.pack_text_frame(buffer, **options))
189
215
  end
190
216
 
217
+ # Pack a binary frame with the specified buffer. This is used by the {#writer} interface.
218
+ # @parameter buffer [String] The binary data to pack into the frame.
219
+ # @returns [BinaryFrame] The packed frame.
191
220
  def pack_binary_frame(buffer, **options)
192
221
  frame = BinaryFrame.new(mask: @mask)
193
222
  frame.pack(buffer)
@@ -195,11 +224,15 @@ module Protocol
195
224
  return frame
196
225
  end
197
226
 
227
+ # Send a binary frame with the specified buffer.
228
+ # @parameter buffer [String] The binary data to send.
198
229
  def send_binary(buffer, **options)
199
230
  write_frame(@writer.pack_binary_frame(buffer, **options))
200
231
  end
201
232
 
202
233
  # Send a control frame with data containing a specified control sequence to begin the closing handshake. Does not close the connection, until the remote end responds with a close frame.
234
+ # @parameter code [Integer] The close code to send.
235
+ # @parameter reason [String] The reason for closing the connection.
203
236
  def send_close(code = Error::NO_ERROR, reason = "")
204
237
  frame = CloseFrame.new(mask: @mask)
205
238
  frame.pack(code, reason)
@@ -223,12 +256,15 @@ module Protocol
223
256
  message.send(self, **options)
224
257
  end
225
258
 
226
- # The default implementation for reading a message buffer.
259
+ # The default implementation for reading a message buffer. This is used by the {#reader} interface.
227
260
  def unpack_frames(frames)
228
261
  frames.map(&:unpack).join("")
229
262
  end
230
263
 
231
- # Read a message from the connection.
264
+ # Read a message from the connection. If an error occurs while reading the message, the connection will be closed.
265
+ #
266
+ # If the message is fragmented, this method will buffer the frames until a complete message is received.
267
+ #
232
268
  # @returns message [Message] The received message.
233
269
  def read(**options)
234
270
  @framer.flush
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'frame'
7
7
 
8
8
  module Protocol
9
9
  module WebSocket
10
+ # Represents a continuation frame that is sent or received by a WebSocket connection when a message is split into multiple frames.
10
11
  class ContinuationFrame < Frame
11
12
  OPCODE = 0x0
12
13
 
14
+ # Apply this frame to the specified connection.
13
15
  def apply(connection)
14
16
  connection.receive_continuation(self)
15
17
  end
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  require 'protocol/http/error'
7
7
 
8
8
  module Protocol
9
9
  module WebSocket
10
+ # Represents an error that occurred during the WebSocket protocol negotiation or communication.
10
11
  # Status codes as defined by <https://tools.ietf.org/html/rfc6455#section-7.4.1>.
11
12
  class Error < HTTP::Error
12
13
  # Indicates a normal closure, meaning that the purpose for which the connection was established has been fulfilled.
@@ -24,9 +25,7 @@ module Protocol
24
25
  # There are other status codes but most of them are "implementation specific".
25
26
  end
26
27
 
27
- # Raised by stream or connection handlers, results in GOAWAY frame
28
- # which signals termination of the current connection. You *cannot*
29
- # recover from this exception, or any exceptions subclassed from it.
28
+ # Raised by stream or connection handlers, results in GOAWAY frame which signals termination of the current connection. You *cannot* recover from this exception, or any exceptions subclassed from it.
30
29
  class ProtocolError < Error
31
30
  def initialize(message, code = PROTOCOL_ERROR)
32
31
  super(message)
@@ -34,6 +33,7 @@ module Protocol
34
33
  @code = code
35
34
  end
36
35
 
36
+ # @attribute [Integer] The status code associated with the error.
37
37
  attr :code
38
38
  end
39
39
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2023, by Samuel Williams.
4
+ # Copyright, 2022-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'compression/constants'
7
7
  require_relative 'compression/inflate'
@@ -10,6 +10,7 @@ require_relative 'compression/deflate'
10
10
  module Protocol
11
11
  module WebSocket
12
12
  module Extension
13
+ # Provides support for the permessage-deflate extension.
13
14
  module Compression
14
15
  # Client offer to server, construct a list of requested compression parameters suitable for the `Sec-WebSocket-Extensions` header.
15
16
  # @returns [Array(String)] a list of compression parameters suitable to send to the server.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2023, by Samuel Williams.
4
+ # Copyright, 2022-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'extension/compression'
7
7
  require_relative 'headers'
@@ -65,6 +65,8 @@ module Protocol
65
65
  @accepted << [klass, options]
66
66
  end
67
67
  end
68
+
69
+ return @accepted
68
70
  end
69
71
 
70
72
  def apply(connection)
@@ -112,14 +114,14 @@ module Protocol
112
114
  # The extension is accepted and no further offers will be considered:
113
115
  named.delete(name)
114
116
 
115
- yield header
117
+ yield header if block_given?
116
118
 
117
119
  @accepted << [klass, options]
118
120
  end
119
121
  end
120
122
  end
121
123
 
122
- return headers
124
+ return @accepted
123
125
  end
124
126
 
125
127
  def apply(connection)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
  # Copyright, 2019, by Soumya.
6
6
  # Copyright, 2021, by Aurora Nockert.
7
7
 
@@ -50,6 +50,7 @@ module Protocol
50
50
  @opcode & 0x8 != 0
51
51
  end
52
52
 
53
+ # @returns [Boolean] if the frame contains data.
53
54
  def data?
54
55
  false
55
56
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'frame'
7
7
 
@@ -34,16 +34,18 @@ module Protocol
34
34
  @frames = frames
35
35
  end
36
36
 
37
+ # Close the underlying stream.
37
38
  def close
38
39
  @stream.close
39
40
  end
40
41
 
42
+ # Flush the underlying stream.
41
43
  def flush
42
44
  @stream.flush
43
45
  end
44
46
 
45
47
  # Read a frame from the underlying stream.
46
- # @returns [Frame]
48
+ # @returns [Frame] the frame read from the stream.
47
49
  def read_frame(maximum_frame_size = MAXIMUM_ALLOWED_FRAME_SIZE)
48
50
  # Read the header:
49
51
  finished, flags, opcode = read_header
@@ -55,10 +57,12 @@ module Protocol
55
57
  return frame
56
58
  end
57
59
 
60
+ # Write a frame to the underlying stream.
58
61
  def write_frame(frame)
59
62
  frame.write(@stream)
60
63
  end
61
64
 
65
+ # Read the header of the frame.
62
66
  def read_header
63
67
  if buffer = @stream.read(1) and buffer.bytesize == 1
64
68
  return Frame.parse_header(buffer)
@@ -1,32 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2023, by Samuel Williams.
5
-
6
- require 'json'
4
+ # Copyright, 2022-2024, by Samuel Williams.
7
5
 
8
6
  require_relative 'message'
9
7
 
8
+ warn "Protocol::WebSocket::JSONMessage is deprecated. Use Protocol::WebSocket::TextMessage instead."
9
+
10
10
  module Protocol
11
11
  module WebSocket
12
+ # @deprecated Use {TextMessage} instead.
12
13
  class JSONMessage < TextMessage
13
14
  def self.wrap(message)
14
- if message.is_a?(TextMessage)
15
- self.new(message.buffer)
16
- end
15
+ message
17
16
  end
18
17
 
19
18
  def self.generate(object)
20
19
  self.new(JSON.generate(object))
21
20
  end
22
-
23
- def parse(symbolize_names: true, **options)
24
- JSON.parse(@buffer, symbolize_names: symbolize_names, **options)
25
- end
26
-
27
- def to_h
28
- parse.to_h
29
- end
30
21
  end
31
22
  end
32
23
  end
@@ -1,43 +1,71 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2023, by Samuel Williams.
4
+ # Copyright, 2022-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'frame'
7
+ require_relative 'coder'
7
8
 
8
9
  module Protocol
9
10
  module WebSocket
11
+ # Represents a message that can be sent or received over a WebSocket connection.
10
12
  class Message
13
+ # Create a new message from a buffer.
14
+ # @attribute buffer [String] The message buffer.
11
15
  def initialize(buffer)
12
16
  @buffer = buffer
13
17
  end
14
18
 
19
+ # @attribute [String] The message buffer.
15
20
  attr :buffer
16
21
 
22
+ # @returns [Integer] The size of the message buffer.
17
23
  def size
18
24
  @buffer.bytesize
19
25
  end
20
26
 
21
- # This can be helpful for writing tests.
27
+ # Compare this message to another message or buffer.
22
28
  def == other
23
29
  @buffer == other.to_str
24
30
  end
25
31
 
32
+ # A message is implicitly convertible to it's buffer.
26
33
  def to_str
27
34
  @buffer
28
35
  end
29
36
 
37
+ # The encoding of the message buffer.
38
+ # @returns [Encoding]
30
39
  def encoding
31
40
  @buffer.encoding
32
41
  end
42
+
43
+ # Generate a message from a value using the given coder.
44
+ # @property value [Object] The value to encode.
45
+ # @property coder [Coder] The coder to use. Defaults to JSON.
46
+ def self.generate(value, coder = Coder::DEFAULT)
47
+ new(coder.generate(value))
48
+ end
49
+
50
+ # Parse the message buffer using the given coder. Defaults to JSON.
51
+ def parse(coder = Coder::DEFAULT)
52
+ coder.parse(@buffer)
53
+ end
54
+
55
+ # Convert the message buffer to a hash using the given coder. Defaults to JSON.
56
+ def to_h(...)
57
+ parse(...).to_h
58
+ end
33
59
  end
34
60
 
61
+ # Represents a text message that can be sent or received over a WebSocket connection.
35
62
  class TextMessage < Message
36
63
  def send(connection, **options)
37
64
  connection.send_text(@buffer, **options)
38
65
  end
39
66
  end
40
67
 
68
+ # Represents a binary message that can be sent or received over a WebSocket connection.
41
69
  class BinaryMessage < Message
42
70
  def send(connection, **options)
43
71
  connection.send_binary(@buffer, **options)
@@ -1,13 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'frame'
7
7
  require_relative 'pong_frame'
8
8
 
9
9
  module Protocol
10
10
  module WebSocket
11
+ # Represents a ping frame that is sent or received by a WebSocket connection.
11
12
  class PingFrame < Frame
12
13
  OPCODE = 0x9
13
14
 
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'frame'
7
7
 
8
8
  module Protocol
9
9
  module WebSocket
10
+ # Represents a pong frame that is sent or received by a WebSocket connection.
10
11
  class PongFrame < Frame
11
12
  OPCODE = 0xA
12
13
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
  # Copyright, 2021, by Aurora Nockert.
6
6
 
7
7
  require_relative 'frame'
@@ -9,10 +9,11 @@ require_relative 'message'
9
9
 
10
10
  module Protocol
11
11
  module WebSocket
12
- # Implements the text frame for sending and receiving text.
12
+ # Represents a text frame that is sent or received by a WebSocket connection.
13
13
  class TextFrame < Frame
14
14
  OPCODE = 0x1
15
15
 
16
+ # @returns [Boolean] if the frame contains data.
16
17
  def data?
17
18
  true
18
19
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  module Protocol
7
7
  module WebSocket
8
- VERSION = "0.13.0"
8
+ VERSION = "0.14.0"
9
9
  end
10
10
  end
data/readme.md CHANGED
@@ -6,7 +6,11 @@ Provides a low-level implementation of the WebSocket protocol according to [RFC6
6
6
 
7
7
  ## Usage
8
8
 
9
- Please see the [project documentation](https://socketry.github.io/protocol-websocket).
9
+ Please see the [project documentation](https://socketry.github.io/protocol-websocket/) for more details.
10
+
11
+ - [Getting Started](https://socketry.github.io/protocol-websocket/guides/getting-started/index) - This guide explains how to use `protocol-websocket` for implementing a websocket client and server.
12
+
13
+ - [Extensions](https://socketry.github.io/protocol-websocket/guides/extensions/index) - This guide explains how to use `protocol-websocket` for implementing a websocket client and server using extensions.
10
14
 
11
15
  ## Contributing
12
16
 
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protocol-websocket
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -41,7 +41,7 @@ cert_chain:
41
41
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
42
42
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
43
43
  -----END CERTIFICATE-----
44
- date: 2024-05-17 00:00:00.000000000 Z
44
+ date: 2024-06-20 00:00:00.000000000 Z
45
45
  dependencies:
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: protocol-http
@@ -66,6 +66,8 @@ files:
66
66
  - lib/protocol/websocket.rb
67
67
  - lib/protocol/websocket/binary_frame.rb
68
68
  - lib/protocol/websocket/close_frame.rb
69
+ - lib/protocol/websocket/coder.rb
70
+ - lib/protocol/websocket/coder/json.rb
69
71
  - lib/protocol/websocket/connection.rb
70
72
  - lib/protocol/websocket/continuation_frame.rb
71
73
  - lib/protocol/websocket/error.rb
@@ -73,7 +75,6 @@ files:
73
75
  - lib/protocol/websocket/extension/compression/constants.rb
74
76
  - lib/protocol/websocket/extension/compression/deflate.rb
75
77
  - lib/protocol/websocket/extension/compression/inflate.rb
76
- - lib/protocol/websocket/extensions.md
77
78
  - lib/protocol/websocket/extensions.rb
78
79
  - lib/protocol/websocket/frame.rb
79
80
  - lib/protocol/websocket/framer.rb
@@ -107,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
108
  - !ruby/object:Gem::Version
108
109
  version: '0'
109
110
  requirements: []
110
- rubygems_version: 3.3.7
111
+ rubygems_version: 3.5.9
111
112
  signing_key:
112
113
  specification_version: 4
113
114
  summary: A low level implementation of the WebSocket protocol.
metadata.gz.sig CHANGED
Binary file
@@ -1,13 +0,0 @@
1
- # Extensions
2
-
3
- WebSockets have a mechanism for implementing extensions. The only published extension is for per-message compression. It operates on complete messages rather than individual frames.
4
-
5
- ## Setup
6
-
7
- Clients need to define a set of extensions they want to support. The server then receives this via the `Sec-WebSocket-Extensions` header which includes a list of:
8
-
9
- Name, Options
10
-
11
- The server processes this and returns a subset of accepted `(Name, Options)`. It also instantiates the extensions and applies them to the server connection object.
12
-
13
- The client receives a list of accepted `(Name, Options)` and instantiates the extensions and applies them to the client connection object.