1 # -*- encoding: binary -*-
5 class IO < Struct.new(:to_io, :buf)
6 # most Web Socket messages from clients are expected to be small text
9 # maximum size of a UTF-8 buffer we'll allow in memory
10 # this is a soft limit and may be offset by the value of RD_SIZE
11 MAX_UTF8_SIZE = 1024 * 16
13 # maximum size of a binary buffer we'll allow in memory
14 # this is a soft limit and may be offset by the value of RD_SIZE
15 MAX_BINARY_SIZE = 1024 * 112
17 # Web Sockets usually uses UTF-8 when interfacing with the client
18 # Ruby Sockets always return strings of Encoding::Binary
19 ENC = defined?(Encoding::UTF_8) ? Encoding::UTF_8 : nil
23 def initialize(io, buf = Z.dup)
27 # iterates through each message until a client the connection is closed
35 # retrieves the next record, returns nil if client closes connection
39 buf.gsub!(/\A\x00(.*?)\xff/m, Z) and return utf8!($1)
40 rv = read_binary and return rv
41 buf.size > MAX_UTF8_SIZE and
42 raise ProtocolError, "buffer too large #{buf.size}"
52 rescue EOFError,Errno::ECONNRESET,Errno::EPIPE,
53 Errno::EINVAL,Errno::EBADF => e
54 raise ClientShutdown, e.message, []
58 syswrite("\0#{binary(buf)}\xff")
66 length.unshift((n % 128) | 0x80)
67 end while (n /= 128) > 0
70 syswrite("\x80#{length.pack("C*")}#{buf}")
82 valid_utf8?(buf) ? write_utf8(buf) : write_binary(buf)
86 buf.encoding == ENC ? write_utf8(buf) : write_binary(buf)
93 # read with no args for Revactor compat
94 i.respond_to?(:readpartial) ?
95 i.readpartial(size.nil? ? RD_SIZE : size) :
96 i.read(size.nil? ? nil : size)
101 valid_utf8?(buf) or raise ProtocolError, "not UTF-8: #{buf.inspect}"
104 def binary(buf); buf; end
107 buf.force_encoding(ENC)
108 buf.valid_encoding? or raise ProtocolError, "not UTF-8: #{buf.inspect}"
112 buf.encoding == Encoding::BINARY ?
113 buf : buf.dup.force_encoding(Encoding::BINARY)
117 if Z.respond_to?(:ord)
118 def ord(byte_str); byte_str.ord; end
120 def ord(byte_str); byte_str; end
124 (ord(buf[0]) & 0x80) == 0x80 or return
129 buf << read while (b = buf[i]).nil?
131 length = length * 128 + (b & 0x7f)
133 end while (b & 0x80) != 0
135 length > MAX_BINARY_SIZE and
136 raise ProtocolError, "chunk too large: #{length} bytes"
138 to_read = length - buf.size + i
144 buf.replace(buf[i+length, buf.size])