httpx 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
- return super unless proxy
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
@@ -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
- host = @uri.host
76
- port_string = @uri.port == @uri.default_port ? nil : ":#{@uri.port}"
77
- "#{host}#{port_string}"
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
@@ -41,11 +41,7 @@ module HTTPX
41
41
 
42
42
  def bodyless?
43
43
  @request.verb == :head ||
44
- @status < 200 ||
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("palanca", encoding: @encoding, mode: File::RDWR)
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
@@ -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? }
@@ -4,28 +4,42 @@ require "timeout"
4
4
 
5
5
  module HTTPX
6
6
  class Timeout
7
- LOOP_TIMEOUT = 5
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
- def initialize(loop_timeout: LOOP_TIMEOUT, total_timeout: nil)
15
- @loop_timeout = loop_timeout
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
- @loop_timeout || @total_timeout
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
- @loop_timeout == other.instance_variable_get(:@loop_timeout) &&
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
- loop_timeout = other.instance_variable_get(:@loop_timeout) || @loop_timeout
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(loop_timeout: loop_timeout, total_timeout: total_timeout)
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
- module_function
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 "http/form_data"
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, :read
15
+ def_delegator :@raw, :bytesize
18
16
 
19
- def initialize(form)
20
- @raw = HTTP::FormData.create(form)
21
- end
17
+ def_delegator :@raw, :force_encoding
22
18
 
23
- def bytesize
24
- @raw.content_length
19
+ def initialize(form)
20
+ @raw = URI.encode_www_form(form)
25
21
  end
26
22
 
27
- def force_encoding(*args)
28
- @raw.to_s.force_encoding(*args)
23
+ def content_type
24
+ "application/x-www-form-urlencoded"
29
25
  end
30
26
 
31
27
  def to_str
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTPX
4
- VERSION = "0.2.1"
4
+ VERSION = "0.3.0"
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.2.1
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-10-24 00:00:00.000000000 Z
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: :runtime
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.6
146
+ rubygems_version: 2.7.8
158
147
  signing_key:
159
148
  specification_version: 4
160
149
  summary: HTTPX, to the future, and beyond