httpx 0.2.1 → 0.3.0
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.rb +1 -0
- data/lib/httpx/altsvc.rb +76 -0
- data/lib/httpx/chainable.rb +4 -0
- data/lib/httpx/channel.rb +72 -20
- data/lib/httpx/channel/http1.rb +71 -52
- data/lib/httpx/channel/http2.rb +43 -5
- data/lib/httpx/client.rb +32 -1
- data/lib/httpx/connection.rb +21 -8
- data/lib/httpx/errors.rb +18 -1
- data/lib/httpx/extensions.rb +72 -41
- data/lib/httpx/parser/http1.rb +171 -0
- data/lib/httpx/plugins/multipart.rb +50 -0
- data/lib/httpx/plugins/proxy.rb +6 -1
- data/lib/httpx/request.rb +8 -3
- data/lib/httpx/response.rb +15 -6
- data/lib/httpx/selector.rb +1 -1
- data/lib/httpx/timeout.rb +37 -8
- data/lib/httpx/transcoder/chunker.rb +76 -3
- data/lib/httpx/transcoder/form.rb +7 -11
- data/lib/httpx/version.rb +1 -1
- metadata +7 -18
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HTTPX
|
4
|
+
module Plugins
|
5
|
+
module Multipart
|
6
|
+
module FormTranscoder
|
7
|
+
module_function
|
8
|
+
|
9
|
+
class Encoder
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
def_delegator :@raw, :content_type
|
13
|
+
|
14
|
+
def_delegator :@raw, :to_s
|
15
|
+
|
16
|
+
def_delegator :@raw, :read
|
17
|
+
|
18
|
+
def initialize(form)
|
19
|
+
@raw = HTTP::FormData.create(form)
|
20
|
+
end
|
21
|
+
|
22
|
+
def bytesize
|
23
|
+
@raw.content_length
|
24
|
+
end
|
25
|
+
|
26
|
+
def force_encoding(*args)
|
27
|
+
@raw.to_s.force_encoding(*args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_str
|
31
|
+
@raw.to_s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def encode(form)
|
36
|
+
Encoder.new(form)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.load_dependencies(*)
|
41
|
+
require "http/form_data"
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.configure(*)
|
45
|
+
Transcoder.register("form", FormTranscoder)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
register_plugin :multipart, Multipart
|
49
|
+
end
|
50
|
+
end
|
data/lib/httpx/plugins/proxy.rb
CHANGED
@@ -50,11 +50,12 @@ module HTTPX
|
|
50
50
|
def find_channel(request, **options)
|
51
51
|
uri = URI(request.uri)
|
52
52
|
proxy = proxy_params(uri)
|
53
|
-
|
53
|
+
raise Error, "Failed to connect to proxy" unless proxy
|
54
54
|
@connection.find_channel(proxy) || build_channel(proxy, options)
|
55
55
|
end
|
56
56
|
|
57
57
|
def build_channel(proxy, options)
|
58
|
+
return super if proxy.is_a?(URI::Generic)
|
58
59
|
channel = build_proxy_channel(proxy, **options)
|
59
60
|
set_channel_callbacks(channel, options)
|
60
61
|
channel
|
@@ -118,6 +119,10 @@ module HTTPX
|
|
118
119
|
@pending << [request, args]
|
119
120
|
end
|
120
121
|
|
122
|
+
def connecting?
|
123
|
+
super || @state == :connecting || @state == :connected
|
124
|
+
end
|
125
|
+
|
121
126
|
def to_io
|
122
127
|
case @state
|
123
128
|
when :idle
|
data/lib/httpx/request.rb
CHANGED
@@ -5,6 +5,7 @@ require "forwardable"
|
|
5
5
|
module HTTPX
|
6
6
|
class Request
|
7
7
|
extend Forwardable
|
8
|
+
using URIExtensions
|
8
9
|
|
9
10
|
METHODS = [
|
10
11
|
# RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1
|
@@ -71,10 +72,14 @@ module HTTPX
|
|
71
72
|
path
|
72
73
|
end
|
73
74
|
|
75
|
+
# https://bugs.ruby-lang.org/issues/15278
|
74
76
|
def authority
|
75
|
-
|
76
|
-
|
77
|
-
|
77
|
+
@uri.authority
|
78
|
+
end
|
79
|
+
|
80
|
+
# https://bugs.ruby-lang.org/issues/15278
|
81
|
+
def origin
|
82
|
+
@uri.origin
|
78
83
|
end
|
79
84
|
|
80
85
|
def query
|
data/lib/httpx/response.rb
CHANGED
@@ -41,11 +41,7 @@ module HTTPX
|
|
41
41
|
|
42
42
|
def bodyless?
|
43
43
|
@request.verb == :head ||
|
44
|
-
|
45
|
-
@status == 201 ||
|
46
|
-
@status == 204 ||
|
47
|
-
@status == 205 ||
|
48
|
-
@status == 304
|
44
|
+
no_data?
|
49
45
|
end
|
50
46
|
|
51
47
|
def content_type
|
@@ -65,6 +61,19 @@ module HTTPX
|
|
65
61
|
raise HTTPError, self
|
66
62
|
end
|
67
63
|
|
64
|
+
private
|
65
|
+
|
66
|
+
def no_data?
|
67
|
+
@status < 200 ||
|
68
|
+
@status == 204 ||
|
69
|
+
@status == 205 ||
|
70
|
+
@status == 304 || begin
|
71
|
+
content_length = @headers["content-length"]
|
72
|
+
return false if content_length.nil?
|
73
|
+
content_length == "0"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
68
77
|
class Body
|
69
78
|
def initialize(response, threshold_size:, window_size: 1 << 14)
|
70
79
|
@response = response
|
@@ -170,7 +179,7 @@ module HTTPX
|
|
170
179
|
when :memory
|
171
180
|
if @length > @threshold_size
|
172
181
|
aux = @buffer
|
173
|
-
@buffer = Tempfile.new("
|
182
|
+
@buffer = Tempfile.new("httpx", encoding: @encoding, mode: File::RDWR)
|
174
183
|
aux.rewind
|
175
184
|
::IO.copy_stream(aux, @buffer)
|
176
185
|
# TODO: remove this if/when minor ruby is 2.3
|
data/lib/httpx/selector.rb
CHANGED
@@ -109,7 +109,7 @@ class HTTPX::Selector
|
|
109
109
|
|
110
110
|
readers, writers = IO.select(r, w, nil, interval)
|
111
111
|
|
112
|
-
raise HTTPX::TimeoutError, "timed out while waiting on select" if readers.nil? && writers.nil?
|
112
|
+
raise HTTPX::TimeoutError.new(interval, "timed out while waiting on select") if readers.nil? && writers.nil?
|
113
113
|
rescue IOError, SystemCallError
|
114
114
|
@lock.synchronize do
|
115
115
|
@readers.reject! { |io, _| io.closed? }
|
data/lib/httpx/timeout.rb
CHANGED
@@ -4,28 +4,42 @@ require "timeout"
|
|
4
4
|
|
5
5
|
module HTTPX
|
6
6
|
class Timeout
|
7
|
-
|
7
|
+
CONNECT_TIMEOUT = 60
|
8
|
+
OPERATION_TIMEOUT = 60
|
8
9
|
|
9
10
|
def self.new(opts = {})
|
10
11
|
return opts if opts.is_a?(Timeout)
|
11
12
|
super
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
attr_reader :connect_timeout, :operation_timeout
|
16
|
+
|
17
|
+
def initialize(connect_timeout: CONNECT_TIMEOUT,
|
18
|
+
operation_timeout: OPERATION_TIMEOUT,
|
19
|
+
total_timeout: nil,
|
20
|
+
loop_timeout: nil)
|
21
|
+
@connect_timeout = connect_timeout
|
22
|
+
@operation_timeout = operation_timeout
|
16
23
|
@total_timeout = total_timeout
|
24
|
+
if loop_timeout
|
25
|
+
warn ":loop_timeout is deprecated, use :operation_timeout instead"
|
26
|
+
@operation_timeout = loop_timeout
|
27
|
+
end
|
17
28
|
reset_counter
|
29
|
+
@state = :idle # this is here not to trigger the log
|
30
|
+
transition(:idle)
|
18
31
|
end
|
19
32
|
|
20
33
|
def timeout
|
21
|
-
@
|
34
|
+
@timeout || @total_timeout
|
22
35
|
ensure
|
23
36
|
log_time
|
24
37
|
end
|
25
38
|
|
26
39
|
def ==(other)
|
27
40
|
if other.is_a?(Timeout)
|
28
|
-
@
|
41
|
+
@connect_timeout == other.instance_variable_get(:@connect_timeout) &&
|
42
|
+
@operation_timeout == other.instance_variable_get(:@operation_timeout) &&
|
29
43
|
@total_timeout == other.instance_variable_get(:@total_timeout)
|
30
44
|
else
|
31
45
|
super
|
@@ -38,14 +52,29 @@ module HTTPX
|
|
38
52
|
timeout = Timeout.new(other)
|
39
53
|
merge(timeout)
|
40
54
|
when Timeout
|
41
|
-
|
55
|
+
connect_timeout = other.instance_variable_get(:@connect_timeout) || @connect_timeout
|
56
|
+
operation_timeout = other.instance_variable_get(:@operation_timeout) || @operation_timeout
|
42
57
|
total_timeout = other.instance_variable_get(:@total_timeout) || @total_timeout
|
43
|
-
Timeout.new(
|
58
|
+
Timeout.new(connect_timeout: connect_timeout,
|
59
|
+
operation_timeout: operation_timeout,
|
60
|
+
total_timeout: total_timeout)
|
44
61
|
else
|
45
62
|
raise ArgumentError, "can't merge with #{other.class}"
|
46
63
|
end
|
47
64
|
end
|
48
65
|
|
66
|
+
def transition(nextstate)
|
67
|
+
return if @state == nextstate
|
68
|
+
case nextstate
|
69
|
+
# when :idle
|
70
|
+
when :idle
|
71
|
+
@timeout = @connect_timeout
|
72
|
+
when :open
|
73
|
+
@timeout = @operation_timeout
|
74
|
+
end
|
75
|
+
@state = nextstate
|
76
|
+
end
|
77
|
+
|
49
78
|
private
|
50
79
|
|
51
80
|
def reset_counter
|
@@ -60,7 +89,7 @@ module HTTPX
|
|
60
89
|
return unless @time_left
|
61
90
|
return reset_timer unless @started
|
62
91
|
@time_left -= (Process.clock_gettime(Process::CLOCK_MONOTONIC) - @started)
|
63
|
-
raise TimeoutError, "Timed out after #{@total_timeout} seconds" if @time_left <= 0
|
92
|
+
raise TimeoutError.new(@total_timeout, "Timed out after #{@total_timeout} seconds") if @time_left <= 0
|
64
93
|
|
65
94
|
reset_timer
|
66
95
|
end
|
@@ -4,15 +4,14 @@ require "forwardable"
|
|
4
4
|
|
5
5
|
module HTTPX::Transcoder
|
6
6
|
module Chunker
|
7
|
-
|
7
|
+
Error = Class.new(HTTPX::Error)
|
8
|
+
CRLF = "\r\n".b
|
8
9
|
|
9
10
|
class Encoder
|
10
11
|
extend Forwardable
|
11
12
|
|
12
13
|
def_delegator :@raw, :readpartial
|
13
14
|
|
14
|
-
CRLF = "\r\n"
|
15
|
-
|
16
15
|
def initialize(body)
|
17
16
|
@raw = body
|
18
17
|
end
|
@@ -30,6 +29,80 @@ module HTTPX::Transcoder
|
|
30
29
|
end
|
31
30
|
end
|
32
31
|
|
32
|
+
class Decoder
|
33
|
+
extend Forwardable
|
34
|
+
|
35
|
+
def_delegator :@buffer, :empty?
|
36
|
+
|
37
|
+
def_delegator :@buffer, :<<
|
38
|
+
|
39
|
+
def_delegator :@buffer, :clear
|
40
|
+
|
41
|
+
def initialize(buffer, trailers = false)
|
42
|
+
@buffer = buffer
|
43
|
+
@chunk_length = nil
|
44
|
+
@chunk_buffer = "".b
|
45
|
+
@finished = false
|
46
|
+
@state = :length
|
47
|
+
@trailers = trailers
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_s
|
51
|
+
@buffer
|
52
|
+
end
|
53
|
+
|
54
|
+
def each
|
55
|
+
loop do
|
56
|
+
case @state
|
57
|
+
when :length
|
58
|
+
index = @buffer.index(CRLF)
|
59
|
+
return unless index && index.positive?
|
60
|
+
# Read hex-length
|
61
|
+
hexlen = @buffer.slice!(0, index)
|
62
|
+
hexlen[/\h/] || raise(Error, "wrong chunk size line: #{hexlen}")
|
63
|
+
@chunk_length = hexlen.hex
|
64
|
+
# check if is last chunk
|
65
|
+
@finished = @chunk_length.zero?
|
66
|
+
nextstate(:crlf)
|
67
|
+
when :crlf
|
68
|
+
crlf_size = @finished && !@trailers ? 4 : 2
|
69
|
+
# consume CRLF
|
70
|
+
return if @buffer.bytesize < crlf_size
|
71
|
+
raise Error, "wrong chunked encoding format" unless @buffer.start_with?(CRLF * (crlf_size / 2))
|
72
|
+
@buffer.slice!(0, crlf_size)
|
73
|
+
if @chunk_length.nil?
|
74
|
+
nextstate(:length)
|
75
|
+
else
|
76
|
+
return if @finished
|
77
|
+
nextstate(:data)
|
78
|
+
end
|
79
|
+
when :data
|
80
|
+
@chunk_buffer << (slice = @buffer.slice!(0, @chunk_length))
|
81
|
+
@chunk_length -= slice.bytesize
|
82
|
+
if @chunk_length.zero?
|
83
|
+
yield @chunk_buffer unless @chunk_buffer.empty?
|
84
|
+
@chunk_buffer.clear
|
85
|
+
@chunk_length = nil
|
86
|
+
nextstate(:crlf)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
break if @buffer.empty?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def finished?
|
94
|
+
@finished
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def nextstate(state)
|
100
|
+
@state = state
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
module_function
|
105
|
+
|
33
106
|
def encode(chunks)
|
34
107
|
Encoder.new(chunks)
|
35
108
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "forwardable"
|
4
|
-
require "
|
4
|
+
require "uri"
|
5
5
|
|
6
6
|
module HTTPX::Transcoder
|
7
7
|
module Form
|
@@ -10,22 +10,18 @@ module HTTPX::Transcoder
|
|
10
10
|
class Encoder
|
11
11
|
extend Forwardable
|
12
12
|
|
13
|
-
def_delegator :@raw, :content_type
|
14
|
-
|
15
13
|
def_delegator :@raw, :to_s
|
16
14
|
|
17
|
-
def_delegator :@raw, :
|
15
|
+
def_delegator :@raw, :bytesize
|
18
16
|
|
19
|
-
|
20
|
-
@raw = HTTP::FormData.create(form)
|
21
|
-
end
|
17
|
+
def_delegator :@raw, :force_encoding
|
22
18
|
|
23
|
-
def
|
24
|
-
@raw.
|
19
|
+
def initialize(form)
|
20
|
+
@raw = URI.encode_www_form(form)
|
25
21
|
end
|
26
22
|
|
27
|
-
def
|
28
|
-
|
23
|
+
def content_type
|
24
|
+
"application/x-www-form-urlencoded"
|
29
25
|
end
|
30
26
|
|
31
27
|
def to_str
|
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.
|
4
|
+
version: 0.3.0
|
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-
|
11
|
+
date: 2018-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: http-2
|
@@ -34,7 +34,7 @@ dependencies:
|
|
34
34
|
- - "<"
|
35
35
|
- !ruby/object:Gem::Version
|
36
36
|
version: '3'
|
37
|
-
type: :
|
37
|
+
type: :development
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
@@ -44,20 +44,6 @@ dependencies:
|
|
44
44
|
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '3'
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: http_parser.rb
|
49
|
-
requirement: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - ">="
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: 0.6.0
|
54
|
-
type: :runtime
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - ">="
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: 0.6.0
|
61
47
|
- !ruby/object:Gem::Dependency
|
62
48
|
name: http-cookie
|
63
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,6 +68,7 @@ files:
|
|
82
68
|
- LICENSE.txt
|
83
69
|
- README.md
|
84
70
|
- lib/httpx.rb
|
71
|
+
- lib/httpx/altsvc.rb
|
85
72
|
- lib/httpx/buffer.rb
|
86
73
|
- lib/httpx/callbacks.rb
|
87
74
|
- lib/httpx/chainable.rb
|
@@ -100,6 +87,7 @@ files:
|
|
100
87
|
- lib/httpx/io/unix.rb
|
101
88
|
- lib/httpx/loggable.rb
|
102
89
|
- lib/httpx/options.rb
|
90
|
+
- lib/httpx/parser/http1.rb
|
103
91
|
- lib/httpx/plugins/authentication.rb
|
104
92
|
- lib/httpx/plugins/basic_authentication.rb
|
105
93
|
- lib/httpx/plugins/compression.rb
|
@@ -110,6 +98,7 @@ files:
|
|
110
98
|
- lib/httpx/plugins/digest_authentication.rb
|
111
99
|
- lib/httpx/plugins/follow_redirects.rb
|
112
100
|
- lib/httpx/plugins/h2c.rb
|
101
|
+
- lib/httpx/plugins/multipart.rb
|
113
102
|
- lib/httpx/plugins/proxy.rb
|
114
103
|
- lib/httpx/plugins/proxy/http.rb
|
115
104
|
- lib/httpx/plugins/proxy/socks4.rb
|
@@ -154,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
143
|
version: '0'
|
155
144
|
requirements: []
|
156
145
|
rubyforge_project:
|
157
|
-
rubygems_version: 2.7.
|
146
|
+
rubygems_version: 2.7.8
|
158
147
|
signing_key:
|
159
148
|
specification_version: 4
|
160
149
|
summary: HTTPX, to the future, and beyond
|