WebSocket compression update with new classes to
parse the compression header.
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
note
|
||||
description: "{COMPRESSION_EXTENSIONS_PARSER} Parse the SEC_WEBSOCKET_EXTENSION header as par of websocket opening handshake."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
EIS: "name=Compression Extension for WebSocket"
|
||||
|
||||
class
|
||||
COMPRESSION_EXTENSIONS_PARSER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialize
|
||||
|
||||
make (a_header: STRING_32)
|
||||
do
|
||||
header := a_header
|
||||
create {ARRAYED_LIST [WEBSOCKET_PCME]} last_offers.make (0)
|
||||
ensure
|
||||
header_set: header = a_header
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
header: STRING_32
|
||||
-- Content raw header `Sec-Websocket-Extensions'.
|
||||
|
||||
last_offers: LIST [WEBSOCKET_PCME]
|
||||
-- List of potential offered PMCE
|
||||
--| From Sec-Websocket-Extensions header.
|
||||
--| The order of elements is important as it specifies the client's preferences.
|
||||
|
||||
feature -- Parse
|
||||
|
||||
parse
|
||||
-- Parse `SEC-WEBSOCKET-EXTENSIONS' header.
|
||||
-- The result is available in `last_offer'.
|
||||
local
|
||||
l_offers: ARRAYED_LIST [WEBSOCKET_PCME]
|
||||
l_pcme: WEBSOCKET_PCME
|
||||
do
|
||||
create l_offers.make (1)
|
||||
if attached header.split (',') as l_list then
|
||||
-- Multiple offers separated by ',', if l_list.count > 1
|
||||
across l_list as ic loop
|
||||
-- Shared code extract to an external feature.
|
||||
l_offers.force (parse_parameters (ic.item))
|
||||
end
|
||||
else
|
||||
-- we should raise an Issue.
|
||||
end
|
||||
last_offers := l_offers
|
||||
end
|
||||
|
||||
feature {NONE}-- Parse Compression Extension.
|
||||
|
||||
parse_parameters (a_string: STRING_32): WEBSOCKET_PCME
|
||||
local
|
||||
l_first: BOOLEAN
|
||||
l_str: STRING_32
|
||||
l_key: STRING_32
|
||||
l_value: STRING_32
|
||||
do
|
||||
if attached a_string.split (';') as l_parameters then
|
||||
-- parameters for the current offer.
|
||||
create Result
|
||||
across
|
||||
l_parameters as ip
|
||||
from
|
||||
l_first := True
|
||||
loop
|
||||
if l_first then
|
||||
l_str := ip.item
|
||||
l_str.adjust
|
||||
Result.set_name (l_str)
|
||||
l_first := False
|
||||
else
|
||||
l_str := ip.item
|
||||
l_str.adjust
|
||||
if l_str.has ('=') then
|
||||
-- The parameter has a value
|
||||
-- server_max_window_bits = 10
|
||||
l_key := l_str.substring (1, l_str.index_of ('=', 1) - 1) -- Exclude =
|
||||
l_value := l_str.substring (l_str.index_of ('=', 1) + 1, l_str.count) -- Exclude =
|
||||
Result.force (l_value, l_key)
|
||||
else
|
||||
Result.force (Void, l_str)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Compression Extension simple
|
||||
--| like
|
||||
--| permessage-deflate
|
||||
l_str := a_string
|
||||
l_str.adjust
|
||||
create Result
|
||||
Result.set_name (l_str)
|
||||
end
|
||||
end
|
||||
note
|
||||
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,65 @@
|
||||
note
|
||||
description: "[Object that validate a PMCE permessage defalate extension,
|
||||
using the DEFLATE algorithm
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WEB_SOCKET_PMCE_DEFLATE_VALIDATOR
|
||||
|
||||
|
||||
feature -- Validate
|
||||
|
||||
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: STRING = "permessage-deflate"
|
||||
-- registered extension name.
|
||||
|
||||
|
||||
parameters: STRING_TABLE [BOOLEAN]
|
||||
-- extension parameters
|
||||
note
|
||||
EIS: "name=Extension Parameters", "src=https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-28#section-7.1", "protocol=url"
|
||||
once
|
||||
create Result.make_caseless (4)
|
||||
Result.force (False, "server_no_context_takeover")
|
||||
Result.force (False, "client_no_context_takeover")
|
||||
Result.force (True, "server_max_windows_bits")
|
||||
Result.force (True, "client_max_windows_bits")
|
||||
end
|
||||
|
||||
|
||||
sliding_windows_size: STRING_TABLE [INTEGER]
|
||||
-- LZ77 sliding window size.
|
||||
--! Map with valid windows and the
|
||||
--! context parameter, and integer value
|
||||
--! between 8 and 15.
|
||||
note
|
||||
EIS:"name=Limiting the LZ77 sliding window size", "src=https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-28#section-7.1.2", "protocol=url"
|
||||
once
|
||||
create Result.make (7)
|
||||
Result.force (256, "8")
|
||||
Result.force (512, "9")
|
||||
Result.force (1024, "10")
|
||||
Result.force (2048, "11")
|
||||
Result.force (4096, "12")
|
||||
Result.force (8192, "13")
|
||||
Result.force (16384, "14")
|
||||
Result.force (32768, "15")
|
||||
end
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,52 @@
|
||||
note
|
||||
description: "{WEBSOCKET_PCME}, object that represent a websocket per-message compression extension."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WEBSOCKET_PCME
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: detachable STRING_32
|
||||
-- Compression extension name.
|
||||
|
||||
parameters: detachable STRING_TABLE [detachable STRING_32]
|
||||
-- Compression extensions parameter.
|
||||
|
||||
feature -- Change Element
|
||||
|
||||
set_name (a_name: STRING_32)
|
||||
-- Set name with `a_name'.
|
||||
do
|
||||
name := a_name
|
||||
ensure
|
||||
name_set: name = a_name
|
||||
end
|
||||
|
||||
force (a_value: detachable STRING_32; a_key: STRING_32)
|
||||
-- Update table `parameters' so that `a_value' will be the item associated
|
||||
-- with `a_key'.
|
||||
local
|
||||
l_parameters: like parameters
|
||||
do
|
||||
l_parameters := parameters
|
||||
if attached l_parameters then
|
||||
l_parameters.force (a_value, a_key)
|
||||
else
|
||||
create l_parameters.make_caseless (1)
|
||||
l_parameters.force (a_value, a_key)
|
||||
end
|
||||
parameters := l_parameters
|
||||
end
|
||||
note
|
||||
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -93,6 +93,9 @@ feature -- Access
|
||||
is_fin: BOOLEAN
|
||||
-- is the final fragment in a message?
|
||||
|
||||
is_rsv1: BOOLEAN
|
||||
-- is extension negotiation in a message?
|
||||
|
||||
fragment_count: INTEGER
|
||||
|
||||
payload_length: NATURAL_64
|
||||
@@ -132,6 +135,11 @@ feature -- Operation
|
||||
is_fin := a_flag_is_fin
|
||||
end
|
||||
|
||||
update_rsv1 (a_flag_rsv1: BOOLEAN)
|
||||
do
|
||||
is_rsv1 := a_flag_rsv1
|
||||
end
|
||||
|
||||
feature {WEB_SOCKET_FRAME} -- Change: injected control frames
|
||||
|
||||
add_injected_control_frame (f: WEB_SOCKET_FRAME)
|
||||
@@ -434,4 +442,14 @@ feature {NONE} -- Helper
|
||||
end
|
||||
end
|
||||
end
|
||||
note
|
||||
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
|
||||
@@ -44,6 +44,11 @@ feature {NONE} -- Initialization
|
||||
end
|
||||
end
|
||||
|
||||
set_pcme_deflate
|
||||
do
|
||||
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
socket: HTTPD_STREAM_SOCKET
|
||||
@@ -114,6 +119,14 @@ feature -- Element change
|
||||
verbose_level := lev
|
||||
end
|
||||
|
||||
mark_pcme_supported
|
||||
-- Set the websocket to handle pcme.
|
||||
do
|
||||
is_pcme_supported := True
|
||||
ensure
|
||||
pmce_supported_true: is_pcme_supported
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
put_error (a_message: READABLE_STRING_8)
|
||||
@@ -142,10 +155,13 @@ feature -- Basic Operation
|
||||
-- Host: server.example.com
|
||||
-- Upgrade: websocket
|
||||
-- Connection: Upgrade
|
||||
--! Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits
|
||||
-- Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
||||
-- Origin: http://example.com
|
||||
-- Sec-WebSocket-Protocol: chat, superchat
|
||||
-- Sec-WebSocket-Version: 13
|
||||
note
|
||||
EIS: "name=Compression Extensions for WebSocket", "src=https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-28", "protocol=url"
|
||||
local
|
||||
l_sha1: SHA1
|
||||
l_key : STRING
|
||||
@@ -155,6 +171,7 @@ feature -- Basic Operation
|
||||
-- Reset values.
|
||||
is_websocket := False
|
||||
has_error := False
|
||||
on_handshake:= True
|
||||
|
||||
-- Local cache.
|
||||
req := request
|
||||
@@ -184,9 +201,20 @@ feature -- Basic Operation
|
||||
l_version_key.is_case_insensitive_equal ("13") and then
|
||||
attached req.http_host -- Host header must be present
|
||||
then
|
||||
-- here we can check for Sec-WebSocket-Extensions, it could be a collection of extensions.
|
||||
if is_pcme_supported and then attached req.meta_string_variable ("HTTP_SEC_WEBSOCKET_EXTENSIONS") as l_ws_extension then
|
||||
-- at the moment we only handle web socket compression extension (PMCE permessage-deflate).
|
||||
--| We need a way to define which compression algorithm the server support.
|
||||
--|
|
||||
handle_extensions (l_ws_extension)
|
||||
end
|
||||
if is_verbose then
|
||||
log ("key " + l_ws_key, debug_level)
|
||||
end
|
||||
--! Before to send the response we need to check the Sec-Web-Socket extension.
|
||||
--! We can write the compression extension here or just build
|
||||
--! a set of classes and call them where it's needed.
|
||||
|
||||
-- Sending the server's opening handshake
|
||||
create l_sha1.make
|
||||
l_sha1.update_from_string (l_ws_key + magic_guid)
|
||||
@@ -195,6 +223,13 @@ feature -- Basic Operation
|
||||
res.header.add_header_key_value ("Connection", "Upgrade")
|
||||
res.header.add_header_key_value ("Sec-WebSocket-Accept", l_key)
|
||||
|
||||
-- Sec-WebSocket-Extensions
|
||||
if is_pcme_supported and then attached accepted_offer as l_offer
|
||||
and then attached extension_response(l_offer) as l_extension_response
|
||||
then
|
||||
res.header.add_header_key_value ("Sec-WebSocket-Extensions", l_extension_response)
|
||||
end
|
||||
|
||||
if is_verbose then
|
||||
log ("%N================> Send Handshake", debug_level)
|
||||
if attached {HTTP_HEADER} res.header as h then
|
||||
@@ -228,14 +263,25 @@ feature -- Response!
|
||||
l_message_count: INTEGER
|
||||
n: NATURAL_64
|
||||
retried: BOOLEAN
|
||||
l_message: STRING_8
|
||||
l_opcode: NATURAL_32
|
||||
do
|
||||
l_message := a_message
|
||||
if attached accepted_offer and then not on_handshake then
|
||||
l_message := compress_string (l_message)
|
||||
end
|
||||
debug ("ws")
|
||||
print (">>do_send (..., "+ opcode_name (a_opcode) +", ..)%N")
|
||||
end
|
||||
if not retried then
|
||||
create l_header_message.make_empty
|
||||
if attached accepted_offer and then not on_handshake then
|
||||
l_opcode := (0x80 | a_opcode).to_natural_32
|
||||
l_header_message.append_code ((l_opcode.bit_xor (0b1000000)))
|
||||
else
|
||||
l_header_message.append_code ((0x80 | a_opcode).to_natural_32)
|
||||
l_message_count := a_message.count
|
||||
end
|
||||
l_message_count := l_message.count
|
||||
n := l_message_count.to_natural_64
|
||||
if l_message_count > 0xffff then
|
||||
--! Improve. this code needs to be checked.
|
||||
@@ -259,7 +305,7 @@ feature -- Response!
|
||||
|
||||
l_chunk_size := 16_384 -- 16K TODO: see if we should make it customizable.
|
||||
if l_message_count < l_chunk_size then
|
||||
socket.put_string (a_message)
|
||||
socket.put_string (l_message)
|
||||
else
|
||||
from
|
||||
i := 0
|
||||
@@ -269,7 +315,7 @@ feature -- Response!
|
||||
debug ("ws")
|
||||
print ("Sending chunk " + (i + 1).out + " -> " + (i + l_chunk_size).out +" / " + l_message_count.out + "%N")
|
||||
end
|
||||
l_chunk := a_message.substring (i + 1, l_message_count.min (i + l_chunk_size))
|
||||
l_chunk := l_message.substring (i + 1, l_message_count.min (i + l_chunk_size))
|
||||
socket.put_string (l_chunk)
|
||||
if l_chunk.count < l_chunk_size then
|
||||
l_chunk_size := 0
|
||||
@@ -285,7 +331,7 @@ feature -- Response!
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
io.put_string ("Internal error in " + generator + ".do_send (conn, a_opcode=" + a_opcode.out + ", a_message) !%N")
|
||||
io.put_string ("Internal error in " + generator + ".do_send (conn, a_opcode=" + a_opcode.out + ", l_message) !%N")
|
||||
retry
|
||||
end
|
||||
|
||||
@@ -341,6 +387,7 @@ feature -- Response!
|
||||
s: STRING
|
||||
is_data_frame_ok: BOOLEAN -- Is the last process data framing ok?
|
||||
retried: BOOLEAN
|
||||
l_frame_rsv: INTEGER
|
||||
do
|
||||
if not retried then
|
||||
l_socket := socket
|
||||
@@ -368,6 +415,7 @@ feature -- Response!
|
||||
end
|
||||
l_fin := l_byte & (0b10000000) /= 0
|
||||
l_rsv := l_byte & (0b01110000) = 0
|
||||
l_frame_rsv := (l_byte & 0x70) |>> 4
|
||||
l_opcode := l_byte & 0b00001111
|
||||
if Result /= Void then
|
||||
if l_opcode = Result.opcode then
|
||||
@@ -402,7 +450,15 @@ feature -- Response!
|
||||
end
|
||||
|
||||
-- rsv validation
|
||||
if not l_rsv then
|
||||
if l_frame_rsv /= 0 then
|
||||
if attached accepted_offer and then l_frame_rsv = 4 then
|
||||
if Result.is_continuation then
|
||||
Result.report_error (protocol_error, "RSV is set and no extension is negotiated")
|
||||
else
|
||||
on_handshake := False
|
||||
Result.update_rsv1 (True)
|
||||
end
|
||||
elseif not l_rsv then
|
||||
-- RSV1, RSV2, RSV3: 1 bit each
|
||||
|
||||
-- MUST be 0 unless an extension is negotiated that defines meanings
|
||||
@@ -414,6 +470,7 @@ feature -- Response!
|
||||
-- FIXME: add support for extension ?
|
||||
Result.report_error (protocol_error, "RSV values MUST be 0 unless an extension is negotiated that defines meanings for non-zero values")
|
||||
end
|
||||
end
|
||||
else
|
||||
if is_verbose then
|
||||
log ("+ INVALID frame " + opcode_name (l_opcode) + " (fin=" + l_fin.out + ")", debug_level)
|
||||
@@ -538,7 +595,13 @@ feature -- Response!
|
||||
end
|
||||
end
|
||||
l_fetch_count := l_fetch_count + l_bytes_read
|
||||
|
||||
if attached accepted_offer then
|
||||
-- Uncompress data.
|
||||
Result.append_payload_data_chop (uncompress_string (l_chunk), l_bytes_read, l_remaining_len = 0)
|
||||
else
|
||||
Result.append_payload_data_chop (l_chunk, l_bytes_read, l_remaining_len = 0)
|
||||
end
|
||||
else
|
||||
Result.report_error (internal_error, "Issue reading payload data...")
|
||||
end
|
||||
@@ -792,7 +855,166 @@ feature {NONE} -- Debug
|
||||
end
|
||||
|
||||
|
||||
note
|
||||
feature -- PCME
|
||||
|
||||
uncompress_string (a_string: STRING): STRING
|
||||
local
|
||||
di: ZLIB_STRING_UNCOMPRESS
|
||||
l_string: STRING
|
||||
l_array: ARRAY [NATURAL_8]
|
||||
l_byte: SPECIAL [INTEGER_8]
|
||||
do
|
||||
create l_string.make_from_string (a_string)
|
||||
--Prepend 0x78 and 09c
|
||||
l_string.prepend_character ((156).to_character_8)
|
||||
l_string.prepend_character ((120).to_character_8)
|
||||
|
||||
-- Append 4 octects 0x00 0x00 0xff 0xff to the tail of the paiload message
|
||||
l_string.append_character ((0x00).to_character_8)
|
||||
l_string.append_character ((0x00).to_character_8)
|
||||
l_string.append_character ((0xff).to_character_8)
|
||||
l_string.append_character ((0xff).to_character_8)
|
||||
|
||||
l_array := string_to_array (l_string)
|
||||
l_byte := byte_array (l_array)
|
||||
|
||||
|
||||
|
||||
|
||||
create di.string_stream (l_string)
|
||||
Result := di.to_string
|
||||
debug ("ws")
|
||||
print ("%NBytes uncompresses:" + di.total_bytes_uncompressed.out)
|
||||
print ("%NUncompress message:" + Result)
|
||||
end
|
||||
end
|
||||
|
||||
compress_string (a_string: STRING): STRING
|
||||
local
|
||||
dc: ZLIB_STRING_COMPRESS
|
||||
l_string: STRING
|
||||
do
|
||||
create Result.make_empty
|
||||
create dc.string_stream (Result)
|
||||
dc.mark_sync_flush
|
||||
dc.put_string (a_string)
|
||||
|
||||
Result := Result.substring (3, Result.count - 4)
|
||||
|
||||
debug ("ws")
|
||||
print ("%NBytes uncompresses:" + dc.total_bytes_compressed.out )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
byte_array (a_bytes: SPECIAL [NATURAL_8]) : SPECIAL [INTEGER_8]
|
||||
local
|
||||
i: INTEGER
|
||||
do
|
||||
|
||||
create Result.make_filled (0,a_bytes.count)
|
||||
across a_bytes as c
|
||||
loop
|
||||
Result.put(to_byte(c.item.as_integer_8), i)
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
to_byte (a_val : INTEGER) : INTEGER_8
|
||||
-- takes a value between 0 and 255
|
||||
-- Result :-128 to 127
|
||||
do
|
||||
if a_val >= 128 then
|
||||
Result := (-256 + a_val).to_integer_8
|
||||
else
|
||||
Result := a_val.to_integer_8
|
||||
end
|
||||
ensure
|
||||
result_value : 127 >= Result and Result >= -128
|
||||
end
|
||||
|
||||
|
||||
|
||||
string_to_array (s: STRING): ARRAY [NATURAL_8]
|
||||
local
|
||||
i, n: INTEGER
|
||||
c: INTEGER
|
||||
do
|
||||
n := s.count
|
||||
create Result.make_empty
|
||||
if n > 0 then
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
c := s [i].code
|
||||
check
|
||||
c <= 0xFF
|
||||
end
|
||||
Result.force (c.as_natural_8, i)
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature {NONE} -- Extensions
|
||||
|
||||
is_pcme_supported: BOOLEAN
|
||||
--| Temporary hack to test websocket compression
|
||||
|
||||
on_handshake: BOOLEAN
|
||||
|
||||
permessage_compression: STRING = "permessage-deflate"
|
||||
--| Temporary hack to test websocket compression
|
||||
|
||||
extension_response (a_offer: WEBSOCKET_PCME): detachable STRING_8
|
||||
do
|
||||
if attached a_offer.name as l_name then
|
||||
create Result.make_from_string (l_name)
|
||||
end
|
||||
end
|
||||
|
||||
handle_extensions (a_extension: READABLE_STRING_32)
|
||||
-- handle WebSocket extensions.
|
||||
local
|
||||
l_parse: COMPRESSION_EXTENSIONS_PARSER
|
||||
l_offers: LIST [WEBSOCKET_PCME]
|
||||
l_accepted: BOOLEAN
|
||||
l_offer: WEBSOCKET_PCME
|
||||
do
|
||||
-- TODO improve handle
|
||||
-- at the moment only check we have permessage_compression
|
||||
--| TODO add validation and select the best offer.
|
||||
|
||||
create l_parse.make (a_extension)
|
||||
l_parse.parse
|
||||
l_offers := l_parse.last_offers
|
||||
if not l_offers.is_empty then
|
||||
-- filter by permessage-deflate.
|
||||
--| TODO: validate if it's a valid extension.
|
||||
--| validate params.
|
||||
across l_offers as ic
|
||||
until
|
||||
l_accepted
|
||||
loop
|
||||
if attached {STRING_32} ic.item.name as l_name and then
|
||||
l_name.is_case_insensitive_equal_general (permessage_compression)
|
||||
then
|
||||
l_accepted := True
|
||||
create l_offer
|
||||
l_offer.set_name (permessage_compression)
|
||||
end
|
||||
end
|
||||
accepted_offer := l_offer
|
||||
end
|
||||
end
|
||||
|
||||
accepted_offer: detachable WEBSOCKET_PCME
|
||||
-- Accepted compression extension.
|
||||
|
||||
;note
|
||||
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
|
||||
@@ -29,6 +29,7 @@ feature -- Execution
|
||||
ws_h: like new_websocket_handler
|
||||
do
|
||||
create ws.make (request, response)
|
||||
initialize_websocket_options (ws)
|
||||
ws.open_ws_handshake
|
||||
if ws.is_websocket then
|
||||
if ws.has_error then
|
||||
@@ -51,6 +52,18 @@ feature -- Execution
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- WebSocket Options
|
||||
|
||||
initialize_websocket_options (ws: WEB_SOCKET)
|
||||
-- Set web socket options (extensions) to be used as part of the ws opem handshake
|
||||
--| for example set pcme algorithm etc.
|
||||
--| Other option is create a new Class WEB_SOCKET_OPTION/ or
|
||||
--| WEB_SOCKET_EXTENTIONS
|
||||
--| defining all potenial extensions to the protocol.
|
||||
do
|
||||
-- To be redefined
|
||||
end
|
||||
|
||||
feature -- Factory
|
||||
|
||||
new_websocket_handler (ws: WEB_SOCKET): WEB_SOCKET_HANDLER
|
||||
|
||||
Reference in New Issue
Block a user