httpx 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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