websocket-driver 0.7.7 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f871879972966e5137b9e1d791df17db7e6186e35bbf326e156682c7cc092410
4
- data.tar.gz: a96b99173f63da1fe2769af05e78a40a51137f7e48cac2ec01d88bb883724c0f
3
+ metadata.gz: 29e86447ce1bcb8a90f93a8d93b8a80322f3c36e655f9a1a4e32415eddaeb129
4
+ data.tar.gz: 07c2dccd9d940048a1be5f8459f2c0d3214762f4bdd28f2096406e4df7725184
5
5
  SHA512:
6
- metadata.gz: 41df0469a3e829b6a13ddbbacdd39f81d80f433a14248f0748dc8831848de7c5c4db65539fdc5905d91fdd7fd2bcfaae08048f1ee6652603e79ced492230bab6
7
- data.tar.gz: 1920877851a371d6d5493c94bd413fff3ce7f918166506aaa0a3b1a6fcae3961e1da06c315d0fd1bfc94a6c2bd0798f77f6e42429b86ccd9e25c6ad8dcedfa80
6
+ metadata.gz: 105e1d610de90d7b934b88ce141b1aff0496afc22b2599b56d046304b09c9476a122e0eb04f8cddc5303d6f38204334ad2b36113c46d28fbbb486292870eb870
7
+ data.tar.gz: 63e4ab5cd1ffadd35797b0dd713b5a3da3e6eed3e8c3cf09b0ebff18d7e3c931c6ed2b45e992dc26cf77a96e5a8be349318bcafe51bd80498ae389dc8a0f9d9f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ### 0.8.1 / 2026-06-04
2
+
3
+ - Close a draft-75/76 connection if a length header grows to exceed the
4
+ configured max length
5
+ - Fail the connection if a message is larger than the configured max length
6
+ after extension processing
7
+ - Limit the total HTTP request line and headers size to 32K
8
+
9
+ ### 0.8.0 / 2025-05-25
10
+
11
+ - Emit binary message as a string with `Encoding::BINARY` instead of an array
12
+ - Add the option `:binary_data_format` to force the previous behaviour
13
+
1
14
  ### 0.7.7 / 2025-01-04
2
15
 
3
16
  - Add `base64` gem to the dependencies to support Ruby 3.4
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2010-2025 James Coglan
1
+ Copyright 2010-2026 James Coglan
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4
4
  this file except in compliance with the License. You may obtain a copy of the
data/README.md CHANGED
@@ -275,6 +275,10 @@ keys:
275
275
  - `:protocols` - an array of strings representing acceptable subprotocols for
276
276
  use over the socket. The driver will negotiate one of these to use via the
277
277
  `Sec-WebSocket-Protocol` header if supported by the other peer.
278
+ - `:binary_data_format` - in older versions of this library, binary messages
279
+ were represented as arrays of bytes, whereas they're now represented as
280
+ strings with `Encoding::BINARY` for performance reasons. Set this option to
281
+ `:array` to restore the old behaviour.
278
282
 
279
283
  All drivers respond to the following API methods, but some of them are no-ops
280
284
  depending on whether the client supports the behaviour.
@@ -290,8 +294,8 @@ Adds a callback block to execute when the socket becomes open.
290
294
  #### `driver.on :message, -> (event) {}`
291
295
 
292
296
  Adds a callback block to execute when a message is received. `event` will have a
293
- `data` attribute containing either a string in the case of a text message or an
294
- array of integers in the case of a binary message.
297
+ `data` attribute whose value is a string with the encoding `Encoding::UTF_8` for
298
+ text message, and `Encoding::BINARY` for binary message.
295
299
 
296
300
  #### `driver.on :error, -> (event) {}`
297
301
 
@@ -346,11 +350,12 @@ Sends a text message over the socket. If the socket handshake is not yet
346
350
  complete, the message will be queued until it is. Returns `true` if the message
347
351
  was sent or queued, and `false` if the socket can no longer send messages.
348
352
 
349
- #### `driver.binary(array)`
353
+ #### `driver.binary(buffer)`
350
354
 
351
- Takes an array of byte-sized integers and sends them as a binary message. Will
352
- queue and return `true` or `false` the same way as the `text` method. It will
353
- also return `false` if the driver does not support binary messages.
355
+ Takes either a string with encoding `Encoding::BINARY`, or an array of
356
+ byte-sized integers, and sends it as a binary message. Will queue and return
357
+ `true` or `false` the same way as the `text` method. It will also return `false`
358
+ if the driver does not support binary messages.
354
359
 
355
360
  #### `driver.ping(string = '', &callback)`
356
361
 
@@ -41,6 +41,7 @@ module WebSocket
41
41
 
42
42
  when 1 then
43
43
  @length = (octet & 0x7F) + 128 * @length
44
+ return close if @length > @max_length
44
45
 
45
46
  if @closing and @length.zero?
46
47
  return close
@@ -163,11 +163,13 @@ module WebSocket
163
163
  message = Message.new
164
164
  frame = Frame.new
165
165
 
166
- message.rsv1 = message.rsv2 = message.rsv3 = false
167
- message.opcode = OPCODES[type || (String === buffer ? :text : :binary)]
166
+ is_binary = (Array === buffer or buffer.encoding == Encoding::BINARY)
167
+ payload = Driver.encode(buffer, is_binary ? nil : Encoding::UTF_8)
168
+ payload = [code, payload].pack('S>a*') if code
169
+ type ||= is_binary ? :binary : :text
168
170
 
169
- payload = Driver.encode(buffer)
170
- payload = [code, payload].pack('S>a*') if code
171
+ message.rsv1 = message.rsv2 = message.rsv3 = false
172
+ message.opcode = OPCODES[type]
171
173
  message.data = payload
172
174
 
173
175
  if MESSAGE_OPCODES.include?(message.opcode)
@@ -398,12 +400,20 @@ module WebSocket
398
400
 
399
401
  payload = message.data
400
402
 
403
+ if payload.bytesize > @max_length
404
+ return fail(:too_large, 'WebSocket frame length too large')
405
+ end
406
+
401
407
  case message.opcode
402
408
  when OPCODES[:text] then
403
409
  payload = Driver.encode(payload, Encoding::UTF_8)
404
410
  payload = nil unless payload.valid_encoding?
405
411
  when OPCODES[:binary]
406
- payload = payload.bytes.to_a
412
+ if @binary_data_format == :array
413
+ payload = payload.bytes.to_a
414
+ else
415
+ payload = Driver.encode(payload, Encoding::BINARY)
416
+ end
407
417
  end
408
418
 
409
419
  if payload
@@ -71,7 +71,7 @@ module WebSocket
71
71
 
72
72
  def initialize(socket, options = {})
73
73
  super()
74
- Driver.validate_options(options, [:max_length, :masking, :require_masking, :protocols])
74
+ Driver.validate_options(options, [:max_length, :masking, :require_masking, :protocols, :binary_data_format])
75
75
 
76
76
  @socket = socket
77
77
  @reader = StreamReader.new
@@ -80,6 +80,8 @@ module WebSocket
80
80
  @headers = Headers.new
81
81
  @queue = []
82
82
  @ready_state = 0
83
+
84
+ @binary_data_format = options[:binary_data_format] || :string
83
85
  end
84
86
 
85
87
  def state
@@ -197,17 +199,18 @@ module WebSocket
197
199
 
198
200
  def self.encode(data, encoding = nil)
199
201
  if Array === data
202
+ data = data.pack('C*')
200
203
  encoding ||= Encoding::BINARY
201
- return data.pack('C*').force_encoding(encoding)
202
204
  end
203
205
 
204
- encoding ||= Encoding::UTF_8
205
-
206
- return data if data.encoding == encoding
207
- return data.encode(encoding) unless data.encoding == Encoding::BINARY
206
+ return data if encoding.nil? or data.encoding == encoding
208
207
 
209
- data = data.dup if data.frozen?
210
- data.force_encoding(encoding)
208
+ if data.encoding == Encoding::BINARY
209
+ data = data.dup if data.frozen?
210
+ data.force_encoding(encoding)
211
+ else
212
+ data.encode(encoding)
213
+ end
211
214
  end
212
215
 
213
216
  def self.host_header(uri)
@@ -224,6 +227,12 @@ module WebSocket
224
227
  raise ConfigurationError, "Unrecognized option: #{ key.inspect }"
225
228
  end
226
229
  end
230
+
231
+ if options[:binary_data_format]
232
+ unless [:array, :string].include?(options[:binary_data_format])
233
+ raise ConfigurationError, "Invalid :binary_data_format: #{options[:binary_data_format].inspect}"
234
+ end
235
+ end
227
236
  end
228
237
 
229
238
  def self.websocket?(env)
@@ -2,7 +2,7 @@ module WebSocket
2
2
  module HTTP
3
3
 
4
4
  module Headers
5
- MAX_LINE_LENGTH = 4096
5
+ MAX_REQUEST_SIZE = 32768
6
6
  CR = 0x0D
7
7
  LF = 0x0A
8
8
 
@@ -38,6 +38,7 @@ module WebSocket
38
38
  attr_reader :headers
39
39
 
40
40
  def initialize
41
+ @size = 0
41
42
  @buffer = []
42
43
  @env = {}
43
44
  @headers = {}
@@ -54,6 +55,9 @@ module WebSocket
54
55
 
55
56
  def parse(chunk)
56
57
  chunk.each_byte do |octet|
58
+ @size += 1
59
+ return error if @size > MAX_REQUEST_SIZE
60
+
57
61
  if octet == LF and @stage < 2
58
62
  @buffer.pop if @buffer.last == CR
59
63
  if @buffer.empty?
@@ -71,9 +75,8 @@ module WebSocket
71
75
  end
72
76
  end
73
77
  @buffer = []
74
- else
75
- @buffer << octet if @stage >= 0
76
- error if @stage < 2 and @buffer.size > MAX_LINE_LENGTH
78
+ elsif @stage >= 0
79
+ @buffer << octet
77
80
  end
78
81
  end
79
82
  @env['rack.input'] = StringIO.new(string_buffer)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: websocket-driver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.7
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Coglan
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-01-04 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: base64
@@ -127,7 +127,8 @@ files:
127
127
  homepage: https://github.com/faye/websocket-driver-ruby
128
128
  licenses:
129
129
  - Apache-2.0
130
- metadata: {}
130
+ metadata:
131
+ changelog_uri: https://github.com/faye/websocket-driver-ruby/blob/main/CHANGELOG.md
131
132
  rdoc_options:
132
133
  - "--main"
133
134
  - README.md
@@ -146,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
147
  - !ruby/object:Gem::Version
147
148
  version: '0'
148
149
  requirements: []
149
- rubygems_version: 3.6.2
150
+ rubygems_version: 3.6.9
150
151
  specification_version: 4
151
152
  summary: WebSocket protocol handler with pluggable I/O
152
153
  test_files: []