Methods
Public Class
Public Instance
Included modules
Public Class methods
new(origin, addresses, options)
[show source]
# File lib/httpx/io/tcp.rb 15 def initialize(origin, addresses, options) 16 @state = :idle 17 @keep_open = false 18 @addresses = [] 19 @ip_index = -1 20 @ip = nil 21 @hostname = origin.host 22 @options = options 23 @fallback_protocol = @options.fallback_protocol 24 @port = origin.port 25 @interests = :w 26 if @options.io 27 @io = case @options.io 28 when Hash 29 @options.io[origin.authority] 30 else 31 @options.io 32 end 33 raise Error, "Given IO objects do not match the request authority" unless @io 34 35 _, _, _, ip = @io.addr 36 @ip = Resolver::Entry.new(ip) 37 @addresses << @ip 38 @keep_open = true 39 @state = :connected 40 else 41 add_addresses(addresses) 42 end 43 @ip_index = @addresses.size - 1 44 end
Public Instance methods
add_addresses(addrs)
[show source]
# File lib/httpx/io/tcp.rb 50 def add_addresses(addrs) 51 return if addrs.empty? 52 53 ip_index = @ip_index || (@addresses.size - 1) 54 if addrs.first.ipv6? 55 # should be the next in line 56 @addresses = [*@addresses[0, ip_index], *addrs, *@addresses[ip_index..-1]] 57 else 58 @addresses.unshift(*addrs) 59 end 60 @ip_index += addrs.size 61 end
addresses?()
eliminates expired entries and returns whether there are still any left.
[show source]
# File lib/httpx/io/tcp.rb 64 def addresses? 65 prev_addr_size = @addresses.size 66 67 @addresses.delete_if(&:expired?).sort! do |addr1, addr2| 68 if addr1.ipv6? 69 addr2.ipv6? ? 0 : 1 70 else 71 addr2.ipv6? ? -1 : 0 72 end 73 end 74 75 @ip_index = @addresses.size - 1 if prev_addr_size != @addresses.size 76 77 @addresses.any? 78 end
close()
[show source]
# File lib/httpx/io/tcp.rb 181 def close 182 return if @keep_open || closed? 183 184 begin 185 @io.close 186 ensure 187 transition(:closed) 188 end 189 end
closed?()
[show source]
# File lib/httpx/io/tcp.rb 195 def closed? 196 @state == :idle || @state == :closed 197 end
connect()
[show source]
# File lib/httpx/io/tcp.rb 88 def connect 89 return unless closed? 90 91 if @addresses.empty? 92 # an idle connection trying to connect with no available addresses is a connection 93 # out of the initial context which is back to the DNS resolution loop. This may 94 # happen in a fiber-aware context where a connection reconnects with expired addresses, 95 # and context is passed back to a fiber on the same connection while waiting for the 96 # DNS answer. 97 log { "tried connecting while resolving, skipping..." } 98 99 return 100 end 101 102 if !@io || @io.closed? 103 transition(:idle) 104 @io = build_socket 105 end 106 try_connect 107 rescue Errno::EHOSTUNREACH, 108 Errno::ENETUNREACH => e 109 @ip_index -= 1 110 111 raise e if @ip_index.negative? 112 113 log { "failed connecting to #{@ip} (#{e.message}), evict from cache and trying next..." } 114 Resolver.cached_lookup_evict(@hostname, @ip) 115 116 @io = build_socket 117 retry 118 rescue Errno::ECONNREFUSED, 119 Errno::EADDRNOTAVAIL, 120 SocketError, 121 IOError => e 122 @ip_index -= 1 123 124 raise e if @ip_index.negative? 125 126 log { "failed connecting to #{@ip} (#{e.message}), trying next..." } 127 @io = build_socket 128 retry 129 rescue Errno::ETIMEDOUT => e 130 @ip_index -= 1 131 132 raise ConnectTimeoutError.new(@options.timeout[:connect_timeout], e.message) if @ip_index.negative? 133 134 log { "failed connecting to #{@ip} (#{e.message}), trying next..." } 135 136 @io = build_socket 137 retry 138 end
connected?()
[show source]
# File lib/httpx/io/tcp.rb 191 def connected? 192 @state == :connected 193 end
inspect()
:nocov:
[show source]
# File lib/httpx/io/tcp.rb 200 def inspect 201 "#<#{self.class}:#{object_id} " \ 202 "#{@ip}:#{@port} " \ 203 "@state=#{@state} " \ 204 "@hostname=#{@hostname} " \ 205 "@addresses=#{@addresses} " \ 206 "@state=#{@state}>" 207 end
read(size, buffer)
[show source]
# File lib/httpx/io/tcp.rb 158 def read(size, buffer) 159 ret = @io.read_nonblock(size, buffer, exception: false) 160 if ret == :wait_readable 161 buffer.clear 162 return 0 163 end 164 return if ret.nil? 165 166 log { "READ: #{buffer.bytesize} bytes..." } 167 buffer.bytesize 168 end
write(buffer)
[show source]
# File lib/httpx/io/tcp.rb 170 def write(buffer) 171 siz = @io.write_nonblock(buffer, exception: false) 172 return 0 if siz == :wait_writable 173 return if siz.nil? 174 175 log { "WRITE: #{siz} bytes..." } 176 177 buffer.shift!(siz) 178 siz 179 end