httpx 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +191 -0
  3. data/README.md +119 -0
  4. data/lib/httpx.rb +50 -0
  5. data/lib/httpx/buffer.rb +34 -0
  6. data/lib/httpx/callbacks.rb +32 -0
  7. data/lib/httpx/chainable.rb +51 -0
  8. data/lib/httpx/channel.rb +222 -0
  9. data/lib/httpx/channel/http1.rb +220 -0
  10. data/lib/httpx/channel/http2.rb +224 -0
  11. data/lib/httpx/client.rb +173 -0
  12. data/lib/httpx/connection.rb +74 -0
  13. data/lib/httpx/errors.rb +7 -0
  14. data/lib/httpx/extensions.rb +52 -0
  15. data/lib/httpx/headers.rb +152 -0
  16. data/lib/httpx/io.rb +240 -0
  17. data/lib/httpx/loggable.rb +11 -0
  18. data/lib/httpx/options.rb +138 -0
  19. data/lib/httpx/plugins/authentication.rb +14 -0
  20. data/lib/httpx/plugins/basic_authentication.rb +20 -0
  21. data/lib/httpx/plugins/compression.rb +123 -0
  22. data/lib/httpx/plugins/compression/brotli.rb +55 -0
  23. data/lib/httpx/plugins/compression/deflate.rb +50 -0
  24. data/lib/httpx/plugins/compression/gzip.rb +59 -0
  25. data/lib/httpx/plugins/cookies.rb +63 -0
  26. data/lib/httpx/plugins/digest_authentication.rb +141 -0
  27. data/lib/httpx/plugins/follow_redirects.rb +72 -0
  28. data/lib/httpx/plugins/h2c.rb +85 -0
  29. data/lib/httpx/plugins/proxy.rb +108 -0
  30. data/lib/httpx/plugins/proxy/http.rb +115 -0
  31. data/lib/httpx/plugins/proxy/socks4.rb +110 -0
  32. data/lib/httpx/plugins/proxy/socks5.rb +152 -0
  33. data/lib/httpx/plugins/push_promise.rb +67 -0
  34. data/lib/httpx/plugins/stream.rb +33 -0
  35. data/lib/httpx/registry.rb +88 -0
  36. data/lib/httpx/request.rb +222 -0
  37. data/lib/httpx/response.rb +225 -0
  38. data/lib/httpx/selector.rb +155 -0
  39. data/lib/httpx/timeout.rb +68 -0
  40. data/lib/httpx/transcoder.rb +12 -0
  41. data/lib/httpx/transcoder/body.rb +56 -0
  42. data/lib/httpx/transcoder/chunker.rb +38 -0
  43. data/lib/httpx/transcoder/form.rb +41 -0
  44. data/lib/httpx/transcoder/json.rb +36 -0
  45. data/lib/httpx/version.rb +5 -0
  46. metadata +150 -0
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HTTPX::Selector
4
+ #
5
+ # I/O monitor
6
+ #
7
+ class Monitor
8
+ attr_accessor :value, :interests, :readiness
9
+
10
+ def initialize(io, interests, reactor)
11
+ @io = io
12
+ @interests = interests
13
+ @reactor = reactor
14
+ @closed = false
15
+ end
16
+
17
+ def readable?
18
+ @interests == :rw || @interests == :r
19
+ end
20
+
21
+ def writable?
22
+ @interests == :rw || @interests == :w
23
+ end
24
+
25
+ # closes +@io+, deregisters from reactor (unless +deregister+ is false)
26
+ def close(deregister = true)
27
+ return if @closed
28
+ @closed = true
29
+ @reactor.deregister(@io) if deregister
30
+ end
31
+
32
+ def closed?
33
+ @closed
34
+ end
35
+
36
+ # :nocov:
37
+ def to_s
38
+ "#<#{self.class}: #{@io}(closed:#{@closed}) #{@interests} #{object_id.to_s(16)}>"
39
+ end
40
+ # :nocov:
41
+ end
42
+
43
+ def initialize
44
+ @readers = {}
45
+ @writers = {}
46
+ @lock = Mutex.new
47
+ @__r__, @__w__ = IO.pipe
48
+ @closed = false
49
+ end
50
+
51
+ def empty?
52
+ @readers.empty? && @writers.empty?
53
+ end
54
+
55
+ # deregisters +io+ from selectables.
56
+ def deregister(io)
57
+ @lock.synchronize do
58
+ rmonitor = @readers.delete(io)
59
+ wmonitor = @writers.delete(io)
60
+ monitor = rmonitor || wmonitor
61
+ monitor.close(false) if monitor
62
+ end
63
+ end
64
+
65
+ # register +io+ for +interests+ events.
66
+ def register(io, interests)
67
+ readable = interests == :r || interests == :rw
68
+ writable = interests == :w || interests == :rw
69
+ @lock.synchronize do
70
+ if readable
71
+ monitor = @readers[io]
72
+ if monitor
73
+ monitor.interests = interests
74
+ else
75
+ monitor = Monitor.new(io, interests, self)
76
+ end
77
+ @readers[io] = monitor
78
+ @writers.delete(io) unless writable
79
+ end
80
+ if writable
81
+ monitor = @writers[io]
82
+ if monitor
83
+ monitor.interests = interests
84
+ else
85
+ # reuse object
86
+ monitor = readable ? @readers[io] : Monitor.new(io, interests, self)
87
+ end
88
+ @writers[io] = monitor
89
+ @readers.delete(io) unless readable
90
+ end
91
+ monitor
92
+ end
93
+ end
94
+
95
+ # waits for read/write events for +interval+. Yields for monitors of
96
+ # selected IO objects.
97
+ #
98
+ def select(interval)
99
+ begin
100
+ r = nil
101
+ w = nil
102
+ @lock.synchronize do
103
+ r = @readers.keys
104
+ w = @writers.keys
105
+ end
106
+ r.unshift(@__r__)
107
+
108
+ readers, writers = IO.select(r, w, nil, interval)
109
+
110
+ raise HTTPX::TimeoutError, "timed out while waiting on select" if readers.nil? && writers.nil?
111
+ rescue IOError, SystemCallError
112
+ @lock.synchronize do
113
+ @readers.reject! { |io, _| io.closed? }
114
+ @writers.reject! { |io, _| io.closed? }
115
+ end
116
+ retry
117
+ end
118
+
119
+ readers.each do |io|
120
+ if io == @__r__
121
+ # clean up wakeups
122
+ @__r__.read(@__r__.stat.size)
123
+ else
124
+ monitor = io.closed? ? @readers.delete(io) : @readers[io]
125
+ next unless monitor
126
+ monitor.readiness = writers.delete(io) ? :rw : :r
127
+ yield monitor
128
+ end
129
+ end if readers
130
+
131
+ writers.each do |io|
132
+ monitor = io.closed? ? @writers.delete(io) : @writers[io]
133
+ next unless monitor
134
+ # don't double run this, the last iteration might have run this task already
135
+ monitor.readiness = :w
136
+ yield monitor
137
+ end if writers
138
+ end
139
+
140
+ # Closes the selector.
141
+ #
142
+ def close
143
+ return if @closed
144
+ @__r__.close
145
+ @__w__.close
146
+ rescue IOError
147
+ ensure
148
+ @closed = true
149
+ end
150
+
151
+ # interrupts the select call.
152
+ def wakeup
153
+ @__w__.write_nonblock("\0", exception: false)
154
+ end
155
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "timeout"
4
+
5
+ module HTTPX
6
+ class Timeout
7
+ LOOP_TIMEOUT = 5
8
+
9
+ def self.new(opts = {})
10
+ return opts if opts.is_a?(Timeout)
11
+ super
12
+ end
13
+
14
+ def initialize(loop_timeout: 5, total_timeout: nil)
15
+ @loop_timeout = loop_timeout
16
+ @total_timeout = total_timeout
17
+ reset_counter
18
+ end
19
+
20
+ def timeout
21
+ @loop_timeout || @total_timeout
22
+ ensure
23
+ log_time
24
+ end
25
+
26
+ def ==(other)
27
+ if other.is_a?(Timeout)
28
+ @loop_timeout == other.instance_variable_get(:@loop_timeout) &&
29
+ @total_timeout == other.instance_variable_get(:@total_timeout)
30
+ else
31
+ super
32
+ end
33
+ end
34
+
35
+ def merge(other)
36
+ case other
37
+ when Hash
38
+ timeout = Timeout.new(other)
39
+ merge(timeout)
40
+ when Timeout
41
+ loop_timeout = other.instance_variable_get(:@loop_timeout) || @loop_timeout
42
+ total_timeout = other.instance_variable_get(:@total_timeout) || @total_timeout
43
+ Timeout.new(loop_timeout: loop_timeout, total_timeout: total_timeout)
44
+ else
45
+ raise ArgumentError, "can't merge with #{other.class}"
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def reset_counter
52
+ @time_left = @total_timeout
53
+ end
54
+
55
+ def reset_timer
56
+ @started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
57
+ end
58
+
59
+ def log_time
60
+ return unless @time_left
61
+ return reset_timer unless @started
62
+ @time_left -= (Process.clock_gettime(Process::CLOCK_MONOTONIC) - @started)
63
+ raise TimeoutError, "Timed out after #{@total_timeout} seconds" if @time_left <= 0
64
+
65
+ reset_timer
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ module Transcoder
5
+ extend Registry
6
+ end
7
+ end
8
+
9
+ require "httpx/transcoder/body"
10
+ require "httpx/transcoder/form"
11
+ require "httpx/transcoder/json"
12
+ require "httpx/transcoder/chunker"
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ module HTTPX::Transcoder
6
+ module Body
7
+ module_function
8
+
9
+ class Encoder
10
+ extend Forwardable
11
+
12
+ def_delegator :@raw, :to_s
13
+
14
+ def initialize(body)
15
+ @raw = body
16
+ end
17
+
18
+ def bytesize
19
+ if @raw.respond_to?(:bytesize)
20
+ @raw.bytesize
21
+ elsif @raw.respond_to?(:to_ary)
22
+ @raw.map(&:bytesize).reduce(0, :+)
23
+ elsif @raw.respond_to?(:size)
24
+ @raw.size || Float::INFINITY
25
+ elsif @raw.respond_to?(:each)
26
+ Float::INFINITY
27
+ else
28
+ raise Error, "cannot determine size of body: #{@raw.inspect}"
29
+ end
30
+ end
31
+
32
+ def content_type
33
+ "application/octet-stream"
34
+ end
35
+
36
+ private
37
+
38
+ def respond_to_missing?(meth, *args)
39
+ @raw.respond_to?(meth, *args) || super
40
+ end
41
+
42
+ def method_missing(meth, *args, &block)
43
+ if @raw.respond_to?(meth)
44
+ @raw.__send__(meth, *args, &block)
45
+ else
46
+ super
47
+ end
48
+ end
49
+ end
50
+
51
+ def encode(body)
52
+ Encoder.new(body)
53
+ end
54
+ end
55
+ register "body", Body
56
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ module HTTPX::Transcoder
6
+ module Chunker
7
+ module_function
8
+
9
+ class Encoder
10
+ extend Forwardable
11
+
12
+ def_delegator :@raw, :readpartial
13
+
14
+ CRLF = "\r\n"
15
+
16
+ def initialize(body)
17
+ @raw = body
18
+ end
19
+
20
+ def each
21
+ return enum_for(__method__) unless block_given?
22
+ @raw.each do |chunk|
23
+ yield "#{chunk.bytesize.to_s(16)}#{CRLF}#{chunk}#{CRLF}"
24
+ end
25
+ yield "0#{CRLF}#{CRLF}"
26
+ end
27
+
28
+ def respond_to_missing?(meth, *args)
29
+ @raw.respond_to?(meth, *args) || super
30
+ end
31
+ end
32
+
33
+ def encode(chunks)
34
+ Encoder.new(chunks)
35
+ end
36
+ end
37
+ register "chunker", Chunker
38
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require "http/form_data"
5
+
6
+ module HTTPX::Transcoder
7
+ module Form
8
+ module_function
9
+
10
+ class Encoder
11
+ extend Forwardable
12
+
13
+ def_delegator :@raw, :content_type
14
+
15
+ def_delegator :@raw, :to_s
16
+
17
+ def_delegator :@raw, :read
18
+
19
+ def initialize(form)
20
+ @raw = HTTP::FormData.create(form)
21
+ end
22
+
23
+ def bytesize
24
+ @raw.content_length
25
+ end
26
+
27
+ def force_encoding(*args)
28
+ @raw.to_s.force_encoding(*args)
29
+ end
30
+
31
+ def to_str
32
+ @raw.to_s
33
+ end
34
+ end
35
+
36
+ def encode(form)
37
+ Encoder.new(form)
38
+ end
39
+ end
40
+ register "form", Form
41
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require "json"
5
+
6
+ module HTTPX::Transcoder
7
+ module JSON
8
+ module_function
9
+
10
+ class Encoder
11
+ extend Forwardable
12
+
13
+ def_delegator :@raw, :to_str
14
+
15
+ def_delegator :@raw, :to_s
16
+
17
+ def_delegator :@raw, :bytesize
18
+
19
+ def_delegator :@raw, :force_encoding
20
+
21
+ def initialize(json)
22
+ @raw = ::JSON.dump(json)
23
+ @charset = @raw.encoding.name.downcase
24
+ end
25
+
26
+ def content_type
27
+ "application/json; charset=#{@charset}"
28
+ end
29
+ end
30
+
31
+ def encode(json)
32
+ Encoder.new(json)
33
+ end
34
+ end
35
+ register "json", JSON
36
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ VERSION = "0.0.1"
5
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: httpx
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tiago Cardoso
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-02-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: http-2
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.9.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.9.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: http-form_data
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.0
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '3'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.0.0
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
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
+ - !ruby/object:Gem::Dependency
62
+ name: http-cookie
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.0'
75
+ description: A client library for making HTTP requests from Ruby.
76
+ email:
77
+ - cardoso_tiago@hotmail.com
78
+ executables: []
79
+ extensions: []
80
+ extra_rdoc_files: []
81
+ files:
82
+ - LICENSE.txt
83
+ - README.md
84
+ - lib/httpx.rb
85
+ - lib/httpx/buffer.rb
86
+ - lib/httpx/callbacks.rb
87
+ - lib/httpx/chainable.rb
88
+ - lib/httpx/channel.rb
89
+ - lib/httpx/channel/http1.rb
90
+ - lib/httpx/channel/http2.rb
91
+ - lib/httpx/client.rb
92
+ - lib/httpx/connection.rb
93
+ - lib/httpx/errors.rb
94
+ - lib/httpx/extensions.rb
95
+ - lib/httpx/headers.rb
96
+ - lib/httpx/io.rb
97
+ - lib/httpx/loggable.rb
98
+ - lib/httpx/options.rb
99
+ - lib/httpx/plugins/authentication.rb
100
+ - lib/httpx/plugins/basic_authentication.rb
101
+ - lib/httpx/plugins/compression.rb
102
+ - lib/httpx/plugins/compression/brotli.rb
103
+ - lib/httpx/plugins/compression/deflate.rb
104
+ - lib/httpx/plugins/compression/gzip.rb
105
+ - lib/httpx/plugins/cookies.rb
106
+ - lib/httpx/plugins/digest_authentication.rb
107
+ - lib/httpx/plugins/follow_redirects.rb
108
+ - lib/httpx/plugins/h2c.rb
109
+ - lib/httpx/plugins/proxy.rb
110
+ - lib/httpx/plugins/proxy/http.rb
111
+ - lib/httpx/plugins/proxy/socks4.rb
112
+ - lib/httpx/plugins/proxy/socks5.rb
113
+ - lib/httpx/plugins/push_promise.rb
114
+ - lib/httpx/plugins/stream.rb
115
+ - lib/httpx/registry.rb
116
+ - lib/httpx/request.rb
117
+ - lib/httpx/response.rb
118
+ - lib/httpx/selector.rb
119
+ - lib/httpx/timeout.rb
120
+ - lib/httpx/transcoder.rb
121
+ - lib/httpx/transcoder/body.rb
122
+ - lib/httpx/transcoder/chunker.rb
123
+ - lib/httpx/transcoder/form.rb
124
+ - lib/httpx/transcoder/json.rb
125
+ - lib/httpx/version.rb
126
+ homepage: https://gitlab.com/honeyryderchuck/httpx
127
+ licenses:
128
+ - Apache 2.0
129
+ metadata: {}
130
+ post_install_message:
131
+ rdoc_options: []
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubyforge_project:
146
+ rubygems_version: 2.7.6
147
+ signing_key:
148
+ specification_version: 4
149
+ summary: HTTPX, to the future, and beyond
150
+ test_files: []