lib/httpx/plugins/h2c.rb in httpx-0.12.0 vs lib/httpx/plugins/h2c.rb in httpx-0.13.0
- old
+ new
@@ -4,72 +4,57 @@
module Plugins
#
# This plugin adds support for upgrading a plaintext HTTP/1.1 connection to HTTP/2
# (https://tools.ietf.org/html/rfc7540#section-3.2)
#
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Follow-Redirects
+ # https://gitlab.com/honeyryderchuck/httpx/wikis/Upgrade#h2c
#
module H2C
- def self.load_dependencies(*)
- require "base64"
+ VALID_H2C_VERBS = %i[get options head].freeze
+
+ class << self
+ def load_dependencies(*)
+ require "base64"
+ end
+
+ def configure(klass)
+ klass.plugin(:upgrade)
+ klass.default_options.upgrade_handlers.register "h2c", self
+ end
+
+ def call(connection, request, response)
+ connection.upgrade_to_h2c(request, response)
+ end
end
module InstanceMethods
- def request(*args, **options)
- h2c_options = options.merge(fallback_protocol: "h2c")
+ def send_requests(*requests, options)
+ upgrade_request, *remainder = requests
- requests = build_requests(*args, h2c_options)
+ return super unless VALID_H2C_VERBS.include?(upgrade_request.verb) && upgrade_request.scheme == "http"
- upgrade_request = requests.first
- return super unless valid_h2c_upgrade_request?(upgrade_request)
+ connection = pool.find_connection(upgrade_request.uri, @options.merge(options))
+ return super if connection && connection.upgrade_protocol == :h2c
+
+ # build upgrade request
upgrade_request.headers.add("connection", "upgrade")
upgrade_request.headers.add("connection", "http2-settings")
upgrade_request.headers["upgrade"] = "h2c"
upgrade_request.headers["http2-settings"] = HTTP2Next::Client.settings_header(upgrade_request.options.http2_settings)
- wrap { send_requests(*upgrade_request, h2c_options).first }
- responses = send_requests(*requests, h2c_options)
-
- responses.size == 1 ? responses.first : responses
+ super(upgrade_request, *remainder, options.merge(max_concurrent_requests: 1))
end
-
- private
-
- def fetch_response(request, connections, options)
- response = super
- if response && valid_h2c_upgrade?(request, response, options)
- log { "upgrading to h2c..." }
- connection = find_connection(request, connections, options)
- connections << connection unless connections.include?(connection)
- connection.upgrade(request, response)
- end
- response
- end
-
- VALID_H2C_METHODS = %i[get options head].freeze
- private_constant :VALID_H2C_METHODS
-
- def valid_h2c_upgrade_request?(request)
- VALID_H2C_METHODS.include?(request.verb) &&
- request.scheme == "http"
- end
-
- def valid_h2c_upgrade?(request, response, options)
- options.fallback_protocol == "h2c" &&
- request.headers.get("connection").include?("upgrade") &&
- request.headers.get("upgrade").include?("h2c") &&
- response.status == 101
- end
end
class H2CParser < Connection::HTTP2
def upgrade(request, response)
- @connection.send_connection_preface
# skip checks, it is assumed that this is the first
# request in the connection
stream = @connection.upgrade
+
+ # on_settings
handle_stream(stream, request)
@streams[request] = stream
# clean up data left behind in the buffer, if the server started
# sending frames
@@ -79,32 +64,32 @@
end
module ConnectionMethods
using URIExtensions
- def match?(uri, options)
- return super unless uri.scheme == "http" && @options.fallback_protocol == "h2c"
+ def upgrade_to_h2c(request, response)
+ prev_parser = @parser
- super && options.fallback_protocol == "h2c"
- end
+ if prev_parser
+ prev_parser.reset
+ @inflight -= prev_parser.requests.size
+ end
- def coalescable?(connection)
- return super unless @options.fallback_protocol == "h2c" && @origin.scheme == "http"
-
- @origin == connection.origin && connection.options.fallback_protocol == "h2c"
- end
-
- def upgrade(request, response)
- @parser.reset if @parser
- @parser = H2CParser.new(@write_buffer, @options)
+ parser_options = @options.merge(max_concurrent_requests: request.options.max_concurrent_requests)
+ @parser = H2CParser.new(@write_buffer, parser_options)
set_parser_callbacks(@parser)
+ @inflight += 1
@parser.upgrade(request, response)
- end
+ @upgrade_protocol = :h2c
- def build_parser(*)
- return super unless @origin.scheme == "http"
+ if request.options.max_concurrent_requests != @options.max_concurrent_requests
+ @options = @options.merge(max_concurrent_requests: nil)
+ end
- super("http/1.1")
+ prev_parser.requests.each do |req|
+ req.transition(:idle)
+ send(req)
+ end
end
end
end
register_plugin(:h2c, H2C)
end