class HTTPX::TCP

  1. lib/httpx/io/tcp.rb
Superclass: Object

Included modules

  1. Loggable

Attributes

addresses [R]
host [R]
interests [R]
ip [R]
port [R]
state [R]

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 (io = @options.io)
27     io =
28       case io
29       when Hash
30         io[origin.authority]
31       else
32         io
33       end
34     raise Error, "Given IO objects do not match the request authority" unless io
35 
36     # @type var io: TCPSocket | OpenSSL::SSL::SSLSocket
37 
38     _, _, _, ip = io.addr
39     @io = io
40     @addresses << (@ip = Resolver::Entry.new(ip))
41     @keep_open = true
42     @state = :connected
43   else
44     add_addresses(addresses)
45   end
46   @ip_index = @addresses.size - 1
47 end

Public Instance methods

add_addresses(addrs)
[show source]
   # File lib/httpx/io/tcp.rb
53 def add_addresses(addrs)
54   return if addrs.empty?
55 
56   ip_index = @ip_index || (@addresses.size - 1)
57   if addrs.first.ipv6?
58     # should be the next in line
59     @addresses = [*@addresses[0, ip_index], *addrs, *@addresses[ip_index..-1]]
60   else
61     @addresses.unshift(*addrs)
62   end
63   @ip_index += addrs.size
64 end
addresses?()

eliminates expired entries and returns whether there are still any left.

[show source]
   # File lib/httpx/io/tcp.rb
67 def addresses?
68   prev_addr_size = @addresses.size
69 
70   @addresses.delete_if(&:expired?).sort! do |addr1, addr2|
71     if addr1.ipv6?
72       addr2.ipv6? ? 0 : 1
73     else
74       addr2.ipv6? ? -1 : 0
75     end
76   end
77 
78   @ip_index = @addresses.size - 1 if prev_addr_size != @addresses.size
79 
80   @addresses.any?
81 end
can_disconnect?()

signals that the connection that contains this IO can be checked back into the pool. that includes sockets opened outside of the scope of the session, or closed IOs.

[show source]
    # File lib/httpx/io/tcp.rb
213 def can_disconnect?
214   @keep_open || @state == :closed
215 end
close()
[show source]
    # File lib/httpx/io/tcp.rb
187 def close
188   return if @keep_open
189 
190   # mark tcp as closed, so that it can be disconnected.
191   # this bypasses the state machine API as not not allow the transition
192   # from idle to closed in normal circumstances.
193   @state = :closed if @state == :idle
194 
195   return if closed?
196 
197   begin
198     @io.close
199   rescue IOError => e
200     log { "error closing socket" }
201     log { e.full_message(highlight: false) }
202   ensure
203     # @fiber-switch-guard
204     # ensure that all :closed IOs don't leave dangling sockets
205     # behind. This may happen in a fiber scheduler scenario where
206     # connection is reused across fibers.
207     transition(:closed) if @io.closed?
208   end
209 end
closed?()
[show source]
    # File lib/httpx/io/tcp.rb
221 def closed?
222   @state == :idle || @state == :closed
223 end
connect()
[show source]
    # File lib/httpx/io/tcp.rb
 91 def connect
 92   return unless closed?
 93 
 94   if @addresses.empty?
 95     # an idle connection trying to connect with no available addresses is a connection
 96     # out of the initial context which is back to the DNS resolution loop. This may
 97     # happen in a fiber-aware context where a connection reconnects with expired addresses,
 98     # and context is passed back to a fiber on the same connection while waiting for the
 99     # DNS answer.
100     log { "tried connecting while resolving, skipping..." }
101 
102     return
103   end
104 
105   if !@io || @io.closed?
106     transition(:idle)
107     @io = build_socket
108   end
109   try_connect
110 rescue Errno::EHOSTUNREACH,
111        Errno::ENETUNREACH => e
112   @ip_index -= 1
113 
114   raise e if @ip_index.negative?
115 
116   log { "failed connecting to #{@ip} (#{e.message}), evict from cache and trying next..." }
117   @options.resolver_cache.evict(@hostname, @ip)
118 
119   @io = build_socket
120   retry
121 rescue Errno::ECONNREFUSED,
122        Errno::EADDRNOTAVAIL,
123        SocketError,
124        IOError => e
125   @ip_index -= 1
126 
127   raise e if @ip_index.negative?
128 
129   log { "failed connecting to #{@ip} (#{e.message}), trying next..." }
130   @io = build_socket
131   retry
132 rescue Errno::ETIMEDOUT => e
133   @ip_index -= 1
134 
135   raise ConnectTimeoutError.new(@options.timeout.connect_timeout, e.message) if @ip_index.negative?
136 
137   log { "failed connecting to #{@ip} (#{e.message}), trying next..." }
138 
139   @io = build_socket
140   retry
141 end
connected?()
[show source]
    # File lib/httpx/io/tcp.rb
217 def connected?
218   @state == :connected
219 end
inspect()

simplecov:disable

[show source]
    # File lib/httpx/io/tcp.rb
226 def inspect
227   "#<#{self.class}:#{object_id} " \
228     "#{@ip}:#{@port} " \
229     "@state=#{@state} " \
230     "@hostname=#{@hostname} " \
231     "@addresses=#{@addresses} " \
232     "@state=#{@state}>"
233 end
protocol()
[show source]
   # File lib/httpx/io/tcp.rb
87 def protocol
88   @fallback_protocol
89 end
read(size, buffer)
[show source]
    # File lib/httpx/io/tcp.rb
161 def read(size, buffer)
162   siz = @io.read_nonblock(size, buffer, exception: false)
163 
164   case siz
165   when String
166     log { "READ: #{buffer.bytesize} bytes..." }
167     buffer.bytesize
168   when :wait_readable, :wait_writable
169     buffer.clear
170     0
171   end
172 end
socket()
[show source]
   # File lib/httpx/io/tcp.rb
49 def socket
50   @io
51 end
to_io()
[show source]
   # File lib/httpx/io/tcp.rb
83 def to_io
84   @io.to_io
85 end
write(buffer)
[show source]
    # File lib/httpx/io/tcp.rb
174 def write(buffer)
175   siz = @io.write_nonblock(buffer, exception: false)
176 
177   case siz
178   when Integer
179     log { "WRITE: #{siz} bytes..." }
180     buffer.shift!(siz)
181     siz
182   when :wait_readable, :wait_writable
183     0
184   end
185 end