ruflet_server 0.0.7 → 0.0.8

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: 34a06b652824d1837a37bc693722bcaeea85ff0ce8be5e3ec6bd71a3535ea520
4
- data.tar.gz: 8430980c8a035a0a5b9bb7c844469473018b1f51a8385207a1dca0902686a1da
3
+ metadata.gz: f0ec355d06e9fb730a851fa6b085bc97b74bd1231aa682bfc03a93ed3078f762
4
+ data.tar.gz: 2c3af4192affd015f59bfc0a49dc4fe3af264f1da38f5914c78af3d8602ace57
5
5
  SHA512:
6
- metadata.gz: 0b2d54fa5da1a3c653364d90fa40ae856504565ff98959b7bce46e696e4ae5997d8f46e356c64b6f850a2cefc587bb8ab11f56cd2b357015a93b1e089e9723ae
7
- data.tar.gz: 64298fa102ecdcdb25c5829998f839511a1f22f78cda4608b5257a849a16d63bcb78b6efbb552e087587972316ecf2a6c525b1b75bfb2c9634cd4e4099936eb7
6
+ metadata.gz: 250363621bf1bfaefb04a2a2a89f30336590272250239c21061d96c60cac1ae5464f5a5442a42fab0f415bea3085a5921be8bb073e59d7d968b5bc537635eac9
7
+ data.tar.gz: 14d25116e02035b24646f73577aa3780b5f990473191725636324d26c53cccd3a65da53d84db3d2534a4a60450aac5ce7c79799f70b44703db271819c8f8f687
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Ruflet
4
4
  class WebSocketConnection
5
+ # Ruflet control messages are small; anything much larger is invalid or hostile.
6
+ MAX_FRAME_PAYLOAD_BYTES = 16 * 1024 * 1024
7
+
5
8
  def initialize(socket)
6
9
  @socket = socket
7
10
  @write_mutex = Mutex.new
@@ -70,10 +73,20 @@ module Ruflet
70
73
  masked = (b2 & 0x80) != 0
71
74
  payload_len = b2 & 0x7f
72
75
 
73
- payload_len = read_exact(2).unpack1("n") if payload_len == 126
74
- payload_len = read_exact(8).unpack1("Q>") if payload_len == 127
76
+ if payload_len == 126
77
+ ext = read_exact(2)
78
+ return nil if ext.nil?
79
+ payload_len = ext.unpack1("n")
80
+ elsif payload_len == 127
81
+ ext = read_exact(8)
82
+ return nil if ext.nil?
83
+ payload_len = ext.unpack1("Q>")
84
+ end
85
+
86
+ return nil if payload_len.negative? || payload_len > MAX_FRAME_PAYLOAD_BYTES
75
87
 
76
88
  masking_key = masked ? read_exact(4) : nil
89
+ return nil if masked && masking_key.nil?
77
90
  payload = payload_len.zero? ? "".b : read_exact(payload_len)
78
91
  return nil if payload.nil?
79
92
 
@@ -112,6 +125,9 @@ module Ruflet
112
125
  end
113
126
 
114
127
  def read_exact(length)
128
+ return nil unless length.is_a?(Integer)
129
+ return nil if length.negative? || length > MAX_FRAME_PAYLOAD_BYTES
130
+
115
131
  chunk = +""
116
132
  chunk.force_encoding(Encoding::BINARY)
117
133
 
@@ -123,6 +139,8 @@ module Ruflet
123
139
  end
124
140
 
125
141
  chunk
142
+ rescue IOError, SystemCallError
143
+ nil
126
144
  end
127
145
  end
128
146
  end
@@ -128,10 +128,23 @@ module Ruflet
128
128
  when 0xd9 then reader.read_string(reader.read_u8)
129
129
  when 0xda then reader.read_string(reader.read_u16)
130
130
  when 0xdb then reader.read_string(reader.read_u32)
131
+ when 0xc4 then reader.read_binary(reader.read_u8)
132
+ when 0xc5 then reader.read_binary(reader.read_u16)
133
+ when 0xc6 then reader.read_binary(reader.read_u32)
131
134
  when 0xdc then read_array(reader, reader.read_u16)
132
135
  when 0xdd then read_array(reader, reader.read_u32)
133
136
  when 0xde then read_map(reader, reader.read_u16)
134
137
  when 0xdf then read_map(reader, reader.read_u32)
138
+ when 0xd4
139
+ read_ext(reader, 1)
140
+ when 0xd5
141
+ read_ext(reader, 2)
142
+ when 0xd6
143
+ read_ext(reader, 4)
144
+ when 0xd7
145
+ read_ext(reader, 8)
146
+ when 0xd8
147
+ read_ext(reader, 16)
135
148
  when 0xc7
136
149
  read_ext(reader, reader.read_u8)
137
150
  when 0xc8
@@ -231,6 +244,10 @@ module Ruflet
231
244
  def read_string(size)
232
245
  read_exact(size).force_encoding("UTF-8")
233
246
  end
247
+
248
+ def read_binary(size)
249
+ read_exact(size)
250
+ end
234
251
  end
235
252
  end
236
253
  end
data/lib/ruflet/server.rb CHANGED
@@ -186,6 +186,8 @@ module Ruflet
186
186
  ws = nil
187
187
  begin
188
188
  path, headers = read_http_upgrade_request(socket)
189
+ return if path.nil?
190
+
189
191
  if websocket_upgrade_request?(path, headers)
190
192
  send_handshake_response(socket, headers["sec-websocket-key"])
191
193
  ws = Ruflet::WebSocketConnection.new(socket)
@@ -194,6 +196,8 @@ module Ruflet
194
196
  handle_http_request(socket, path)
195
197
  end
196
198
  rescue StandardError => e
199
+ return if disconnect_error?(e)
200
+
197
201
  warn "server error: #{e.class}: #{e.message}"
198
202
  warn e.backtrace.join("\n") if e.backtrace
199
203
  send_message(ws, Protocol::ACTIONS[:session_crashed], { "message" => e.message.to_s.dup.force_encoding("UTF-8") }) if ws
@@ -209,6 +213,8 @@ module Ruflet
209
213
  handle_message(ws, raw)
210
214
  end
211
215
  rescue StandardError => e
216
+ return if disconnect_error?(e)
217
+
212
218
  warn "server error: #{e.class}: #{e.message}"
213
219
  warn e.backtrace.join("\n") if e.backtrace
214
220
  send_message(ws, Protocol::ACTIONS[:session_crashed], { "message" => e.message.to_s.dup.force_encoding("UTF-8") })
@@ -224,10 +230,12 @@ module Ruflet
224
230
 
225
231
  def read_http_upgrade_request(socket)
226
232
  request_line = socket.gets("\r\n")
227
- raise "Invalid HTTP request" if request_line.nil?
233
+ return [nil, {}] if request_line.nil?
234
+ return [nil, {}] unless request_line.include?(" ")
228
235
 
229
236
  method, path, _version = request_line.strip.split(" ", 3)
230
- raise "Unsupported HTTP method: #{method}" unless method == "GET"
237
+ return [nil, {}] unless method == "GET"
238
+ return [nil, {}] if path.to_s.empty?
231
239
 
232
240
  headers = {}
233
241
  loop do
@@ -509,10 +517,30 @@ module Ruflet
509
517
  end
510
518
 
511
519
  def send_message(ws, action, payload)
520
+ return if ws.nil? || ws.closed?
521
+
512
522
  message = [action, payload]
513
523
  ws.send_binary(Ruflet::WireCodec.pack(message))
514
524
  rescue StandardError => e
515
- warn "send error: #{e.class}: #{e.message}"
525
+ unless disconnect_error?(e)
526
+ warn "send error: #{e.class}: #{e.message}"
527
+ end
528
+ remove_session(ws)
529
+ unregister_connection(ws)
530
+ ws&.close
531
+ end
532
+
533
+ def disconnect_error?(error)
534
+ return true if error.is_a?(IOError)
535
+ return true if error.is_a?(Errno::EPIPE)
536
+ return true if error.is_a?(Errno::ECONNRESET)
537
+ return true if error.is_a?(Errno::ECONNABORTED)
538
+ return true if error.is_a?(Errno::ENOTCONN)
539
+ return true if error.is_a?(Errno::ESHUTDOWN)
540
+ return true if error.is_a?(Errno::EBADF)
541
+ return true if error.is_a?(Errno::EINVAL)
542
+
543
+ false
516
544
  end
517
545
 
518
546
  def pseudo_uuid
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ruflet
4
- VERSION = "0.0.7" unless const_defined?(:VERSION)
4
+ VERSION = "0.0.8" unless const_defined?(:VERSION)
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruflet_server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - AdamMusa
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.0.7
18
+ version: 0.0.8
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.0.7
25
+ version: 0.0.8
26
26
  description: Ruflet WebSocket server runtime compatible with Flet protocol.
27
27
  email:
28
28
  - adammusa2222@gmail.com