lib/http/protocol/http1/connection.rb in http-protocol-0.16.0 vs lib/http/protocol/http1/connection.rb in http-protocol-0.17.0

- old
+ new

@@ -30,22 +30,32 @@ def initialize(stream, persistent = true) @stream = stream @persistent = persistent + @upgrade = nil @count = 0 end attr :stream # Whether the connection is persistent. attr :persistent + # Whether the connection has been upgraded, and to what. + attr :upgrade + # The number of requests processed. attr :count + def upgrade?(headers) + if upgrade = headers[UPGRADE] + return upgrade.first + end + end + def persistent?(version, headers) if version == HTTP10 if connection = headers[CONNECTION] return connection.include?(KEEP_ALIVE) else @@ -58,22 +68,33 @@ return true end end end + def upgrade!(protocol) + @upgrade = protocol + @persistent = false + + return @stream + end + # Write the appropriate header for connection persistence. - def write_persistent_header(version) - if version == HTTP10 - @stream.write("connection: keep-alive\r\n") if @persistent + def write_connection_header(version) + if @upgrade + @stream.write("connection: upgrade\r\nupgrade: #{@upgrade}\r\n") else - @stream.write("connection: close\r\n") unless @persistent + if version == HTTP10 + @stream.write("connection: keep-alive\r\n") if @persistent + else + @stream.write("connection: close\r\n") unless @persistent + end end end # Effectively close the connection and return the underlying IO. # @return [IO] the underlying non-blocking IO. - def hijack + def hijack! @persistent = false @stream.flush return @stream @@ -87,18 +108,18 @@ def write_request(authority, method, path, version, headers) @stream.write("#{method} #{path} #{version}\r\n") @stream.write("host: #{authority}\r\n") write_headers(headers) - write_persistent_header(version) + write_connection_header(version) end def write_response(version, status, headers, body = nil, head = false) @stream.write("#{version} #{status}\r\n") write_headers(headers) - write_persistent_header(version) + write_connection_header(version) write_body(body, version == HTTP11, head) end def write_headers(headers) headers.each do |name, value| @@ -111,24 +132,19 @@ yield line end end def read_line - # To support Ruby 2.3, we do the following which is pretty inefficient. Ruby 2.4+ can do the following: - # @stream.gets(CRLF, chomp: true) or raise EOFError - if line = @stream.gets(CRLF) - return line.chomp!(CRLF) - else - raise EOFError - end + @stream.gets(CRLF, chomp: true) or raise EOFError end def read_request method, path, version = read_line.split(/\s+/, 3) headers = read_headers @persistent = persistent?(version, headers) + @upgrade = upgrade?(headers) body = read_request_body(headers) @count += 1 @@ -181,10 +197,23 @@ @stream.read(2) return chunk end + def write_upgrade_body + @stream.write("\r\n") + @stream.flush + + return @stream unless block_given? + + begin + yield @stream + rescue + @stream.close_write + end + end + def write_empty_body(body) @stream.write("content-length: 0\r\n\r\n") @stream.flush if body @@ -262,9 +291,11 @@ end def write_body(body, chunked = true, head = false) if body.nil? or body.empty? write_empty_body(body) + # elsif body.respond_to?(:call) + # write_upgrade_body(&body) elsif length = body.length write_fixed_length_body(body, length, head) elsif @persistent and chunked # We specifically ensure that non-persistent connections do not use chunked response, so that hijacking works as expected. write_chunked_body(body, head)