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 +4 -4
- data/lib/httpx/channel.rb +24 -7
- data/lib/httpx/channel/http1.rb +1 -1
- data/lib/httpx/channel/http2.rb +1 -1
- data/lib/httpx/client.rb +6 -2
- data/lib/httpx/errors.rb +9 -0
- data/lib/httpx/io.rb +13 -4
- data/lib/httpx/io/resolver.rb +8 -8
- data/lib/httpx/io/udp.rb +1 -1
- data/lib/httpx/plugins/proxy.rb +14 -1
- data/lib/httpx/plugins/proxy/http.rb +6 -5
- data/lib/httpx/plugins/proxy/socks4.rb +4 -4
- data/lib/httpx/plugins/proxy/socks5.rb +14 -4
- data/lib/httpx/request.rb +1 -1
- data/lib/httpx/response.rb +19 -3
- data/lib/httpx/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79f53c62644d9e645ab5aeb91d897e0537c3160c
|
4
|
+
data.tar.gz: 7a9cb5c745c6b02ada9d0d76930372201150dba3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
130
|
-
|
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
|
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
|
data/lib/httpx/channel/http1.rb
CHANGED
data/lib/httpx/channel/http2.rb
CHANGED
@@ -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
|
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
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
|
187
|
-
|
188
|
-
|
189
|
-
|
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"
|
data/lib/httpx/io/resolver.rb
CHANGED
@@ -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
|
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
|
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 { |
|
94
|
+
response.each_answer { |_name, _ttl, value| addrs << value.address if value.respond_to?(:address) }
|
95
95
|
|
96
|
-
|
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
data/lib/httpx/plugins/proxy.rb
CHANGED
@@ -92,9 +92,22 @@ module HTTPX
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def to_io
|
95
|
-
|
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(:
|
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
|
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 == :
|
40
|
-
when :
|
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(:
|
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(:
|
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
|
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 :
|
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(:
|
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
|
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 :
|
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
data/lib/httpx/response.rb
CHANGED
@@ -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
|
-
|
217
|
+
include Loggable
|
213
218
|
|
214
|
-
|
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
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.
|
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-
|
11
|
+
date: 2018-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: http-2
|