Class: HTTPX::Channel
- Inherits:
-
Object
- Object
- HTTPX::Channel
- Extended by:
- Forwardable
- Defined in:
- lib/httpx/channel.rb
Overview
The Channel entity can be watched for IO events.
It contains the io object to read/write from, and knows what to do when it can.
It defers connecting until absolutely necessary. Connection should be triggered from the IO selector (until then, any request will be queued).
A channel boots up its parser after connection is established. All pending requests will be redirected there after connection.
A channel can be prevented from closing by the parser, that is, if there are pending requests. This will signal that the channel was prematurely closed, due to a possible number of conditions:
-
Remote peer closed the connection (“Connection: close”);
-
Remote peer doesn’t support pipelining;
A channel may also route requests for a different host for which the io was connected to, provided that the IP is the same and the port and scheme as well. This will allow to share the same socket to send HTTP/2 requests to different hosts. TODO: For this to succeed, the certificates sent by the servers to the client must be
identical (or match both hosts).
Direct Known Subclasses
Defined Under Namespace
Constant Summary collapse
- BUFFER_SIZE =
1 << 14
Constants included from Loggable
Constants included from Registry
Instance Attribute Summary collapse
-
#state ⇒ Object
readonly
Returns the value of attribute state.
-
#uri ⇒ Object
readonly
Returns the value of attribute uri.
Class Method Summary collapse
Instance Method Summary collapse
- #addresses=(addrs) ⇒ Object
- #call ⇒ Object
- #close ⇒ Object
-
#coalescable?(channel) ⇒ Boolean
coalescable channels need to be mergeable! but internally, #mergeable? is called before #coalescable?.
-
#initialize(type, uri, options) ⇒ Channel
constructor
A new instance of Channel.
- #interests ⇒ Object
- #match?(uri) ⇒ Boolean
- #merge(channel) ⇒ Object
- #mergeable?(addresses) ⇒ Boolean
- #reset ⇒ Object
- #send(request, **args) ⇒ Object
- #to_io ⇒ Object
- #unmerge(channel) ⇒ Object
- #upgrade_parser(protocol) ⇒ Object
Methods included from Callbacks
Methods included from Loggable
Methods included from Registry
Constructor Details
#initialize(type, uri, options) ⇒ Channel
Returns a new instance of Channel.
63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/httpx/channel.rb', line 63 def initialize(type, uri, ) @type = type @uri = uri @hostnames = [@uri.host] @options = Options.new() @window_size = @options.window_size @read_buffer = Buffer.new(BUFFER_SIZE) @write_buffer = Buffer.new(BUFFER_SIZE) @pending = [] @state = :idle on(:error) { |ex| on_error(ex) } end |
Instance Attribute Details
#state ⇒ Object (readonly)
Returns the value of attribute state.
61 62 63 |
# File 'lib/httpx/channel.rb', line 61 def state @state end |
#uri ⇒ Object (readonly)
Returns the value of attribute uri.
61 62 63 |
# File 'lib/httpx/channel.rb', line 61 def uri @uri end |
Class Method Details
.by(uri, options) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/httpx/channel.rb', line 44 def by(uri, ) type = .transport || begin case uri.scheme when "http" then "tcp" when "https" then "ssl" else raise Error, "#{uri}: #{uri.scheme}: unrecognized channel" end end new(type, uri, ) end |
Instance Method Details
#addresses=(addrs) ⇒ Object
76 77 78 |
# File 'lib/httpx/channel.rb', line 76 def addresses=(addrs) @io = IO.registry(@type).new(@uri, addrs, @options) end |
#call ⇒ Object
166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/httpx/channel.rb', line 166 def call case @state when :closed return when :closing dwrite transition(:closed) emit(:close) when :open consume end nil end |
#close ⇒ Object
145 146 147 148 |
# File 'lib/httpx/channel.rb', line 145 def close @parser.close if @parser transition(:closing) end |
#coalescable?(channel) ⇒ Boolean
coalescable channels need to be mergeable! but internally, #mergeable? is called before #coalescable?
87 88 89 90 91 92 93 94 95 |
# File 'lib/httpx/channel.rb', line 87 def coalescable?(channel) if @io.protocol == "h2" && @uri.scheme == "https" @io.verify_hostname(channel.uri.host) else @uri.host == channel.uri.host && @uri.port == channel.uri.port && @uri.scheme == channel.uri.scheme end end |
#interests ⇒ Object
126 127 128 129 130 131 132 133 134 135 |
# File 'lib/httpx/channel.rb', line 126 def interests return :w if @state == :idle readable = !@read_buffer.full? writable = !@write_buffer.empty? if readable writable ? :rw : :r else writable ? :w : :r end end |
#match?(uri) ⇒ Boolean
118 119 120 121 122 123 124 |
# File 'lib/httpx/channel.rb', line 118 def match?(uri) return false if @state == :closing @hostnames.include?(uri.host) && uri.port == @uri.port && uri.scheme == @uri.scheme end |
#merge(channel) ⇒ Object
97 98 99 100 101 102 103 |
# File 'lib/httpx/channel.rb', line 97 def merge(channel) @hostnames += channel.instance_variable_get(:@hostnames) pending = channel.instance_variable_get(:@pending) pending.each do |req, args| send(req, args) end end |
#mergeable?(addresses) ⇒ Boolean
80 81 82 83 |
# File 'lib/httpx/channel.rb', line 80 def mergeable?(addresses) return false if @state == :closing || !@io !(@io.addresses & addresses).empty? end |
#reset ⇒ Object
150 151 152 153 154 |
# File 'lib/httpx/channel.rb', line 150 def reset transition(:closing) transition(:closed) emit(:close) end |
#send(request, **args) ⇒ Object
156 157 158 159 160 161 162 163 164 |
# File 'lib/httpx/channel.rb', line 156 def send(request, **args) if @error_response emit(:response, request, @error_response) elsif @parser && !@write_buffer.full? parser.send(request, **args) else @pending << [request, args] end end |
#to_io ⇒ Object
137 138 139 140 141 142 143 |
# File 'lib/httpx/channel.rb', line 137 def to_io case @state when :idle transition(:open) end @io.to_io end |
#unmerge(channel) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/httpx/channel.rb', line 105 def unmerge(channel) @hostnames -= channel.instance_variable_get(:@hostnames) [@parser.pending, @pending].each do |pending| pending.reject! do |request| request.uri == channel.uri && begin request.transition(:idle) channel.send(request) true end end end end |
#upgrade_parser(protocol) ⇒ Object
180 181 182 183 |
# File 'lib/httpx/channel.rb', line 180 def upgrade_parser(protocol) @parser.reset if @parser @parser = build_parser(protocol) end |