httpx 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f092c95882dd48ff10a25b77c08b7dec71acc31
4
- data.tar.gz: fc75a3d72c8151c28b2f24ea4617d64e92b56488
3
+ metadata.gz: 79f53c62644d9e645ab5aeb91d897e0537c3160c
4
+ data.tar.gz: 7a9cb5c745c6b02ada9d0d76930372201150dba3
5
5
  SHA512:
6
- metadata.gz: 1cb99410118ac67eb35bbaf212fda20e95745a77fa026b1ce6712e742ca985728b88e087fd397fd38310496f20fd15cd039827a104220b479a4c471e645b8ea8
7
- data.tar.gz: b593dfe0b0b433d1d12fc8695581158ddcb2a3558d693df07f821efd160cdb61beac1a00fcc78da10fdda608f03464f3cb1bd3e6d32386be318cb5fea44dbd5e
6
+ metadata.gz: c623d4faf4e590b757f5e883a62c337364d76da0d01dfb170f47580331edd915abddee82b867a92f86b59d0ea7eefb5c7405554ee7269cc01e12e144a47ec849
7
+ data.tar.gz: 40ce7074c72b32de7255e5af941e6a8e38c2f026aa3d1e367fb09ca0d63186a5d71c9b5011ced31ff7e28b446a41508f68ea578ab339872baa0ac5de6b82be53
data/lib/httpx/channel.rb CHANGED
@@ -69,6 +69,7 @@ module HTTPX
69
69
  end
70
70
 
71
71
  def match?(uri)
72
+ return false if @state == :closing
72
73
  ips = begin
73
74
  Resolv.getaddresses(uri.host)
74
75
  rescue StandardError
@@ -126,12 +127,8 @@ module HTTPX
126
127
  dwrite
127
128
  transition(:closed)
128
129
  emit(:close)
129
- else
130
- catch(:called) do
131
- dread
132
- dwrite
133
- parser.consume
134
- end
130
+ when :open
131
+ consume
135
132
  end
136
133
  nil
137
134
  end
@@ -143,6 +140,14 @@ module HTTPX
143
140
 
144
141
  private
145
142
 
143
+ def consume
144
+ catch(:called) do
145
+ dread
146
+ dwrite
147
+ parser.consume
148
+ end
149
+ end
150
+
146
151
  def dread(wsize = @window_size)
147
152
  loop do
148
153
  siz = @io.read(wsize, @read_buffer)
@@ -201,7 +206,7 @@ module HTTPX
201
206
  when :open
202
207
  return if @state == :closed
203
208
  @io.connect
204
- return if @io.closed?
209
+ return unless @io.connected?
205
210
  send_pending
206
211
  when :closing
207
212
  return unless @state == :open
@@ -212,6 +217,18 @@ module HTTPX
212
217
  @read_buffer.clear
213
218
  end
214
219
  @state = nextstate
220
+ rescue Errno::ECONNREFUSED,
221
+ Errno::EADDRNOTAVAIL => e
222
+ emit_error(e)
223
+ @state = :closed
224
+ emit(:close)
225
+ end
226
+
227
+ def emit_error(e)
228
+ response = ErrorResponse.new(e, 0, @options)
229
+ @pending.each do |request, _| # rubocop:disable Performance/HashEachMethods
230
+ emit(:response, request, response)
231
+ end
215
232
  end
216
233
  end
217
234
  end
@@ -102,7 +102,7 @@ module HTTPX
102
102
 
103
103
  response << chunk
104
104
 
105
- dispatch if response.complete?
105
+ # dispatch if response.complete?
106
106
  end
107
107
 
108
108
  def on_message_complete
@@ -151,7 +151,7 @@ module HTTPX
151
151
 
152
152
  def on_stream_close(stream, request, error)
153
153
  return handle(request, stream) if request.expects?
154
- response = request.response || ErrorResponse.new(error, @retries)
154
+ response = request.response || ErrorResponse.new(Error.new(error), @retries, @options)
155
155
  emit(:response, request, response)
156
156
  log(2, "#{stream.id}: ") { "closing stream" }
157
157
 
data/lib/httpx/client.rb CHANGED
@@ -5,10 +5,14 @@ module HTTPX
5
5
  include Loggable
6
6
  include Chainable
7
7
 
8
- def initialize(options = {})
8
+ def initialize(options = {}, &blk)
9
9
  @options = self.class.default_options.merge(options)
10
10
  @connection = Connection.new(@options)
11
11
  @responses = {}
12
+ wrap(&blk) if block_given?
13
+ end
14
+
15
+ def wrap
12
16
  return unless block_given?
13
17
  begin
14
18
  @keep_open = true
@@ -107,7 +111,7 @@ module HTTPX
107
111
 
108
112
  break if requests.empty?
109
113
  rescue TimeoutError => e
110
- responses << ErrorResponse.new(e.message, 0) while requests.shift
114
+ responses << ErrorResponse.new(e, 0, @options) while requests.shift
111
115
  @connection.reset
112
116
  break
113
117
  end
data/lib/httpx/errors.rb CHANGED
@@ -4,4 +4,13 @@ module HTTPX
4
4
  Error = Class.new(StandardError)
5
5
 
6
6
  TimeoutError = Class.new(Error)
7
+
8
+ HTTPError = Class.new(Error) do
9
+ attr_reader :status
10
+
11
+ def initialize(status)
12
+ @status = status
13
+ super("HTTP Error: #{status}")
14
+ end
15
+ end
7
16
  end
data/lib/httpx/io.rb CHANGED
@@ -175,6 +175,10 @@ module HTTPX
175
175
  @negotiated = false
176
176
  end
177
177
 
178
+ def connected?
179
+ @state == :negotiated
180
+ end
181
+
178
182
  def connect
179
183
  super
180
184
  if @keep_open
@@ -183,11 +187,16 @@ module HTTPX
183
187
  end
184
188
  return if @state == :negotiated ||
185
189
  @state != :connected
186
- @io = OpenSSL::SSL::SSLSocket.new(@io, @ctx)
187
- @io.hostname = @hostname
188
- @io.sync_close = true
189
- @io.connect
190
+ unless @io.is_a?(OpenSSL::SSL::SSLSocket)
191
+ @io = OpenSSL::SSL::SSLSocket.new(@io, @ctx)
192
+ @io.hostname = @hostname
193
+ @io.sync_close = true
194
+ end
195
+ # TODO: this might block it all
196
+ @io.connect_nonblock
190
197
  transition(:negotiated)
198
+ rescue ::IO::WaitReadable,
199
+ ::IO::WaitWritable
191
200
  end
192
201
 
193
202
  if RUBY_VERSION < "2.3"
@@ -28,7 +28,7 @@ module HTTPX
28
28
  @options = Options.new(options)
29
29
  # early return for edge case when there are no nameservers configured
30
30
  # but we still want to be able to static lookups using #resolve_hostname
31
- @nameservers = self.class.nameservers or return
31
+ (@nameservers = self.class.nameservers) || return
32
32
  server = IPAddr.new(@nameservers.sample)
33
33
  @io = UDP.new(server, DNS_PORT)
34
34
  @read_buffer = "".b
@@ -55,7 +55,7 @@ module HTTPX
55
55
  query = build_query(hostname).encode
56
56
  log { "resolving #{hostname}: #{query.inspect}" }
57
57
  siz = @io.write(query)
58
- log { "WRITE: #{siz} bytes..."}
58
+ log { "WRITE: #{siz} bytes..." }
59
59
  end
60
60
 
61
61
  def call
@@ -69,7 +69,7 @@ module HTTPX
69
69
  siz = @io.read(wsize, @read_buffer)
70
70
  throw(:close, self) unless siz
71
71
  return if siz.zero?
72
- log { "READ: #{siz} bytes..."}
72
+ log { "READ: #{siz} bytes..." }
73
73
  addrs = parse(@read_buffer)
74
74
  @read_buffer.clear
75
75
  next if addrs.empty?
@@ -77,7 +77,7 @@ module HTTPX
77
77
  hostname = @hostnames.shift
78
78
  callback = @callbacks.shift
79
79
  addr = addrs.index(addrs.rand(addrs.size))
80
- log { "resolved #{hostname}: #{addr.to_s}"}
80
+ log { "resolved #{hostname}: #{addr}" }
81
81
  @addresses[hostname] = addr
82
82
  callback.call(addr)
83
83
  end
@@ -91,9 +91,9 @@ module HTTPX
91
91
  addrs = []
92
92
  # The answer might include IN::CNAME entries so filters them out
93
93
  # to include IN::A & IN::AAAA entries only.
94
- response.each_answer { |name, ttl, value| addrs << value.address if value.respond_to?(:address) }
94
+ response.each_answer { |_name, _ttl, value| addrs << value.address if value.respond_to?(:address) }
95
95
 
96
- return addrs
96
+ addrs
97
97
  end
98
98
 
99
99
  def resolve_hostname(hostname)
@@ -101,7 +101,7 @@ module HTTPX
101
101
  # so since we want the first occurance, simply
102
102
  # pop off the stack.
103
103
  resolv.getaddresses(hostname).pop
104
- rescue
104
+ rescue StandardError
105
105
  end
106
106
 
107
107
  def resolv
@@ -129,7 +129,7 @@ module HTTPX
129
129
 
130
130
  def get_address(host)
131
131
  Resolv::Hosts.new(host).getaddress
132
- rescue
132
+ rescue StandardError
133
133
  end
134
134
  end
135
135
  end
data/lib/httpx/io/udp.rb CHANGED
@@ -62,4 +62,4 @@ module HTTPX
62
62
  "#<(fd: #{@io.fileno}): #{@ip}:#{@port})>"
63
63
  end
64
64
  end
65
- end
65
+ end
@@ -92,9 +92,22 @@ module HTTPX
92
92
  end
93
93
 
94
94
  def to_io
95
- transition(:connecting) if @state == :idle
95
+ case @state
96
+ when :idle
97
+ transition(:connecting)
98
+ when :connected
99
+ transition(:open)
100
+ end
96
101
  @io.to_io
97
102
  end
103
+
104
+ def call
105
+ super
106
+ case @state
107
+ when :connecting
108
+ consume
109
+ end
110
+ end
98
111
  end
99
112
 
100
113
  class ProxySSL < SSL
@@ -22,7 +22,7 @@ module HTTPX
22
22
  end
23
23
  parser.send(connect_request)
24
24
  else
25
- transition(:open)
25
+ transition(:connected)
26
26
  end
27
27
  end
28
28
 
@@ -31,13 +31,14 @@ module HTTPX
31
31
  when :connecting
32
32
  return unless @state == :idle
33
33
  @io.connect
34
- return if @io.closed?
34
+ return unless @io.connected?
35
35
  @parser = ConnectProxyParser.new(@write_buffer, @options.merge(max_concurrent_requests: 1))
36
36
  @parser.once(:response, &method(:on_connect))
37
37
  @parser.on(:close) { transition(:closing) }
38
38
  proxy_connect
39
- return if @state == :open
40
- when :open
39
+ return if @state == :connected
40
+ when :connected
41
+ return unless @state == :idle || @state == :connecting
41
42
  case @state
42
43
  when :connecting
43
44
  @parser.close
@@ -56,7 +57,7 @@ module HTTPX
56
57
  req, _ = @pending.first
57
58
  request_uri = req.uri
58
59
  @io = ProxySSL.new(@io, request_uri, @options)
59
- transition(:open)
60
+ transition(:connected)
60
61
  throw(:called)
61
62
  else
62
63
  pending = @pending.map(&:first) + @parser.pending
@@ -27,10 +27,10 @@ module HTTPX
27
27
  req, _ = @pending.first
28
28
  request_uri = req.uri
29
29
  @io = ProxySSL.new(@io, request_uri, @options) if request_uri.scheme == "https"
30
- transition(:open)
30
+ transition(:connected)
31
31
  throw(:called)
32
32
  else
33
- response = ErrorResponse.new("socks error: #{status}", 0)
33
+ response = ErrorResponse.new(Error.new("socks error: #{status}"), 0, @options)
34
34
  until @pending.empty?
35
35
  req, _ = @pending.shift
36
36
  emit(:response, req, response)
@@ -43,13 +43,13 @@ module HTTPX
43
43
  when :connecting
44
44
  return unless @state == :idle
45
45
  @io.connect
46
- return if @io.closed?
46
+ return unless @io.connected?
47
47
  req, _ = @pending.first
48
48
  return unless req
49
49
  request_uri = req.uri
50
50
  @write_buffer << Packet.connect(@parameters, request_uri)
51
51
  proxy_connect
52
- when :open
52
+ when :connected
53
53
  return unless @state == :connecting
54
54
  @parser = nil
55
55
  end
@@ -17,6 +17,16 @@ module HTTPX
17
17
  Error = Class.new(Error)
18
18
 
19
19
  class Socks5ProxyChannel < ProxyChannel
20
+ def call
21
+ super
22
+ case @state
23
+ when :connecting,
24
+ :negotiating,
25
+ :authenticating
26
+ consume
27
+ end
28
+ end
29
+
20
30
  private
21
31
 
22
32
  def proxy_connect
@@ -51,7 +61,7 @@ module HTTPX
51
61
  req, _ = @pending.first
52
62
  request_uri = req.uri
53
63
  @io = ProxySSL.new(@io, request_uri, @options) if request_uri.scheme == "https"
54
- transition(:open)
64
+ transition(:connected)
55
65
  throw(:called)
56
66
  end
57
67
  end
@@ -61,7 +71,7 @@ module HTTPX
61
71
  when :connecting
62
72
  return unless @state == :idle
63
73
  @io.connect
64
- return if @io.closed?
74
+ return unless @io.connected?
65
75
  @write_buffer << Packet.negotiate(@parameters)
66
76
  proxy_connect
67
77
  when :authenticating
@@ -72,7 +82,7 @@ module HTTPX
72
82
  req, _ = @pending.first
73
83
  request_uri = req.uri
74
84
  @write_buffer << Packet.connect(request_uri)
75
- when :open
85
+ when :connected
76
86
  return unless @state == :negotiating
77
87
  @parser = nil
78
88
  end
@@ -85,7 +95,7 @@ module HTTPX
85
95
  end
86
96
 
87
97
  def on_error_response(error)
88
- response = ErrorResponse.new(error, 0)
98
+ response = ErrorResponse.new(Error.new(error), 0, @options)
89
99
  until @pending.empty?
90
100
  req, _ = @pending.shift
91
101
  emit(:response, req, response)
data/lib/httpx/request.rb CHANGED
@@ -192,7 +192,7 @@ module HTTPX
192
192
  # deallocate
193
193
  @response = nil
194
194
  when 417
195
- @response = ErrorResponse.new("Expectation Failed", 0)
195
+ @response = @response
196
196
  return
197
197
  end
198
198
  end
@@ -60,6 +60,11 @@ module HTTPX
60
60
  "#<Response:#{object_id} @status=#{@status} @headers=#{@headers}>"
61
61
  end
62
62
 
63
+ def raise_for_status
64
+ return if @status < 400
65
+ raise HTTPError, @status
66
+ end
67
+
63
68
  class Body
64
69
  def initialize(response, threshold_size:, window_size: 1 << 14)
65
70
  @response = response
@@ -209,13 +214,24 @@ module HTTPX
209
214
  end
210
215
 
211
216
  class ErrorResponse
212
- attr_reader :error, :retries
217
+ include Loggable
213
218
 
214
- alias_method :status, :error
219
+ attr_reader :error, :retries
215
220
 
216
- def initialize(error, retries)
221
+ def initialize(error, retries, options)
217
222
  @error = error
218
223
  @retries = retries
224
+ @options = Options.new(options)
225
+ log { "#{error.class}: #{error}" }
226
+ log { caller.join("\n") }
227
+ end
228
+
229
+ def status
230
+ @error.message
231
+ end
232
+
233
+ def raise_for_status
234
+ raise @error
219
235
  end
220
236
 
221
237
  def retryable?
data/lib/httpx/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTPX
4
- VERSION = "0.0.2"
4
+ VERSION = "0.0.3"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: httpx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Cardoso
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-20 00:00:00.000000000 Z
11
+ date: 2018-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http-2