diff --git a/lib/websocket/extensions/parser.rb b/lib/websocket/extensions/parser.rb index f8d8891..ad65793 100644 --- a/lib/websocket/extensions/parser.rb +++ b/lib/websocket/extensions/parser.rb @@ -7,10 +7,11 @@ class Parser TOKEN = /([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)/ NOTOKEN = /([^!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z])/ QUOTED = /"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])*)"/ - PARAM = %r{#{ TOKEN.source }(?:=(?:#{ TOKEN.source }|#{ QUOTED.source }))?} - EXT = %r{#{ TOKEN.source }(?: *; *#{ PARAM.source })*} - EXT_LIST = %r{^#{ EXT.source }(?: *, *#{ EXT.source })*$} - NUMBER = /^-?(0|[1-9][0-9]*)(\.[0-9]+)?$/ + PARAM = %r{#{ TOKEN.source }(?:[ \t]*=[ \t]*(?:#{ TOKEN.source }|#{ QUOTED.source }))?} + EXT = %r{#{ TOKEN.source }(?:[ \t]*;[ \t]*#{ PARAM.source })*} + EXT_START = %r{[ \t]*#{ EXT.source }} + EXT_LIST = %r{\A[ \t]*#{ EXT.source }(?:[ \t]*,[ \t]*#{ EXT.source })*[ \t]*\z} + NUMBER = /\A-?(0|[1-9][0-9]*)(\.[0-9]+)?\z/ ParseError = Class.new(ArgumentError) @@ -23,7 +24,7 @@ def self.parse_header(header) end scanner = StringScanner.new(header) - value = scanner.scan(EXT) + value = scanner.scan(EXT_START) until value.nil? params = value.scan(PARAM) @@ -51,7 +52,7 @@ def self.parse_header(header) offers.push(name, offer) - scanner.scan(/ *, */) + scanner.skip(/[ \t]*,[ \t]*/) value = scanner.scan(EXT) end offers diff --git a/spec/websocket/extensions/parser_spec.rb b/spec/websocket/extensions/parser_spec.rb index 7458210..61904fa 100644 --- a/spec/websocket/extensions/parser_spec.rb +++ b/spec/websocket/extensions/parser_spec.rb @@ -24,6 +24,18 @@ def parse(string) ] end + it "parses HTTP whitespace around delimiters" do + expect(parse " \ta \t; mode \t= compress \t, other \t").to eq [ + { :name => "a", :params => { "mode" => "compress" } }, + { :name => "other", :params => {} } + ] + end + + it "rejects input outside the complete header value" do + expect { parse "\na" }.to raise_error(WebSocket::Extensions::Parser::ParseError) + expect { parse "a\n" }.to raise_error(WebSocket::Extensions::Parser::ParseError) + end + it "parses two offers with no params" do expect(parse 'a, b').to eq [ { :name => "a", :params => {} }, { :name => "b", :params => {} }