scnr-ethon 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +379 -0
  3. data/LICENSE +20 -0
  4. data/README.md +118 -0
  5. data/ethon.gemspec +29 -0
  6. data/lib/ethon/curl.rb +90 -0
  7. data/lib/ethon/curls/classes.rb +65 -0
  8. data/lib/ethon/curls/codes.rb +122 -0
  9. data/lib/ethon/curls/constants.rb +80 -0
  10. data/lib/ethon/curls/form_options.rb +37 -0
  11. data/lib/ethon/curls/functions.rb +58 -0
  12. data/lib/ethon/curls/infos.rb +151 -0
  13. data/lib/ethon/curls/messages.rb +19 -0
  14. data/lib/ethon/curls/options.rb +503 -0
  15. data/lib/ethon/curls/settings.rb +12 -0
  16. data/lib/ethon/easy/callbacks.rb +149 -0
  17. data/lib/ethon/easy/debug_info.rb +47 -0
  18. data/lib/ethon/easy/features.rb +31 -0
  19. data/lib/ethon/easy/form.rb +107 -0
  20. data/lib/ethon/easy/header.rb +61 -0
  21. data/lib/ethon/easy/http/actionable.rb +157 -0
  22. data/lib/ethon/easy/http/custom.rb +29 -0
  23. data/lib/ethon/easy/http/delete.rb +25 -0
  24. data/lib/ethon/easy/http/get.rb +24 -0
  25. data/lib/ethon/easy/http/head.rb +24 -0
  26. data/lib/ethon/easy/http/options.rb +24 -0
  27. data/lib/ethon/easy/http/patch.rb +24 -0
  28. data/lib/ethon/easy/http/post.rb +26 -0
  29. data/lib/ethon/easy/http/postable.rb +32 -0
  30. data/lib/ethon/easy/http/put.rb +27 -0
  31. data/lib/ethon/easy/http/putable.rb +25 -0
  32. data/lib/ethon/easy/http.rb +68 -0
  33. data/lib/ethon/easy/informations.rb +116 -0
  34. data/lib/ethon/easy/mirror.rb +36 -0
  35. data/lib/ethon/easy/operations.rb +65 -0
  36. data/lib/ethon/easy/options.rb +50 -0
  37. data/lib/ethon/easy/params.rb +29 -0
  38. data/lib/ethon/easy/queryable.rb +154 -0
  39. data/lib/ethon/easy/response_callbacks.rb +136 -0
  40. data/lib/ethon/easy/util.rb +28 -0
  41. data/lib/ethon/easy.rb +315 -0
  42. data/lib/ethon/errors/ethon_error.rb +9 -0
  43. data/lib/ethon/errors/global_init.rb +13 -0
  44. data/lib/ethon/errors/invalid_option.rb +13 -0
  45. data/lib/ethon/errors/invalid_value.rb +13 -0
  46. data/lib/ethon/errors/multi_add.rb +12 -0
  47. data/lib/ethon/errors/multi_fdset.rb +12 -0
  48. data/lib/ethon/errors/multi_remove.rb +12 -0
  49. data/lib/ethon/errors/multi_timeout.rb +13 -0
  50. data/lib/ethon/errors/select.rb +13 -0
  51. data/lib/ethon/errors.rb +17 -0
  52. data/lib/ethon/libc.rb +21 -0
  53. data/lib/ethon/loggable.rb +59 -0
  54. data/lib/ethon/multi/operations.rb +228 -0
  55. data/lib/ethon/multi/options.rb +117 -0
  56. data/lib/ethon/multi/stack.rb +49 -0
  57. data/lib/ethon/multi.rb +126 -0
  58. data/lib/ethon/version.rb +6 -0
  59. data/lib/ethon.rb +36 -0
  60. metadata +117 -0
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+ class Multi # :nodoc
4
+ # This module contains logic to run a multi.
5
+ module Operations
6
+ STARTED_MULTI = "ETHON: started MULTI"
7
+ PERFORMED_MULTI = "ETHON: performed MULTI"
8
+
9
+ # Return the multi handle. Inititialize multi handle,
10
+ # in case it didn't happened already.
11
+ #
12
+ # @example Return multi handle.
13
+ # multi.handle
14
+ #
15
+ # @return [ FFI::Pointer ] The multi handle.
16
+ def handle
17
+ @handle ||= FFI::AutoPointer.new(Curl.multi_init, Curl.method(:multi_cleanup))
18
+ end
19
+
20
+ # Initialize variables.
21
+ #
22
+ # @example Initialize variables.
23
+ # multi.init_vars
24
+ #
25
+ # @return [ void ]
26
+ def init_vars
27
+ if @execution_mode == :perform
28
+ @timeout = ::FFI::MemoryPointer.new(:long)
29
+ @timeval = Curl::Timeval.new
30
+ @fd_read = Curl::FDSet.new
31
+ @fd_write = Curl::FDSet.new
32
+ @fd_excep = Curl::FDSet.new
33
+ @max_fd = ::FFI::MemoryPointer.new(:int)
34
+ elsif @execution_mode == :socket_action
35
+ @running_count_pointer = FFI::MemoryPointer.new(:int)
36
+ end
37
+ end
38
+
39
+ # Perform multi.
40
+ #
41
+ # @return [ nil ]
42
+ #
43
+ # @example Perform multi.
44
+ # multi.perform
45
+ def perform
46
+ ensure_execution_mode(:perform)
47
+
48
+ Ethon.logger.debug(STARTED_MULTI)
49
+ while ongoing?
50
+ run
51
+ timeout = get_timeout
52
+ next if timeout == 0
53
+ reset_fds
54
+ set_fds(timeout)
55
+ end
56
+ Ethon.logger.debug(PERFORMED_MULTI)
57
+ nil
58
+ end
59
+
60
+ # Prepare multi.
61
+ #
62
+ # @return [ nil ]
63
+ #
64
+ # @example Prepare multi.
65
+ # multi.prepare
66
+ #
67
+ # @deprecated It is no longer necessary to call prepare.
68
+ def prepare
69
+ Ethon.logger.warn(
70
+ "ETHON: It is no longer necessay to call "+
71
+ "Multi#prepare. Its going to be removed "+
72
+ "in future versions."
73
+ )
74
+ end
75
+
76
+ # Continue execution with an external IO loop.
77
+ #
78
+ # @example When no sockets are ready yet, or to begin.
79
+ # multi.socket_action
80
+ #
81
+ # @example When a socket is readable
82
+ # multi.socket_action(io_object, [:in])
83
+ #
84
+ # @example When a socket is readable and writable
85
+ # multi.socket_action(io_object, [:in, :out])
86
+ #
87
+ # @return [ Symbol ] The Curl.multi_socket_action return code.
88
+ def socket_action(io = nil, readiness = 0)
89
+ ensure_execution_mode(:socket_action)
90
+
91
+ fd = if io.nil?
92
+ ::Ethon::Curl::SOCKET_TIMEOUT
93
+ elsif io.is_a?(Integer)
94
+ io
95
+ else
96
+ io.fileno
97
+ end
98
+
99
+ code = Curl.multi_socket_action(handle, fd, readiness, @running_count_pointer)
100
+ @running_count = @running_count_pointer.read_int
101
+
102
+ check
103
+
104
+ code
105
+ end
106
+
107
+ # Return whether the multi still contains requests or not.
108
+ #
109
+ # @example Return if ongoing.
110
+ # multi.ongoing?
111
+ #
112
+ # @return [ Boolean ] True if ongoing, else false.
113
+ def ongoing?
114
+ easy_handles.size > 0 || (!defined?(@running_count) || running_count > 0)
115
+ end
116
+
117
+ private
118
+
119
+ # Get timeout.
120
+ #
121
+ # @example Get timeout.
122
+ # multi.get_timeout
123
+ #
124
+ # @return [ Integer ] The timeout.
125
+ #
126
+ # @raise [ Ethon::Errors::MultiTimeout ] If getting the timeout fails.
127
+ def get_timeout
128
+ code = Curl.multi_timeout(handle, @timeout)
129
+ raise Errors::MultiTimeout.new(code) unless code == :ok
130
+ timeout = @timeout.read_long
131
+ timeout = 1 if timeout < 0
132
+ timeout
133
+ end
134
+
135
+ # Reset file describtors.
136
+ #
137
+ # @example Reset fds.
138
+ # multi.reset_fds
139
+ #
140
+ # @return [ void ]
141
+ def reset_fds
142
+ @fd_read.clear
143
+ @fd_write.clear
144
+ @fd_excep.clear
145
+ end
146
+
147
+ # Set fds.
148
+ #
149
+ # @example Set fds.
150
+ # multi.set_fds
151
+ #
152
+ # @return [ void ]
153
+ #
154
+ # @raise [ Ethon::Errors::MultiFdset ] If setting the file descriptors fails.
155
+ # @raise [ Ethon::Errors::Select ] If select fails.
156
+ def set_fds(timeout)
157
+ code = Curl.multi_fdset(handle, @fd_read, @fd_write, @fd_excep, @max_fd)
158
+ raise Errors::MultiFdset.new(code) unless code == :ok
159
+ max_fd = @max_fd.read_int
160
+ if max_fd == -1
161
+ sleep(0.001)
162
+ else
163
+ @timeval[:sec] = timeout / 1000
164
+ @timeval[:usec] = (timeout * 1000) % 1000000
165
+ loop do
166
+ code = Curl.select(max_fd + 1, @fd_read, @fd_write, @fd_excep, @timeval)
167
+ break unless code < 0 && ::FFI.errno == Errno::EINTR::Errno
168
+ end
169
+ raise Errors::Select.new(::FFI.errno) if code < 0
170
+ end
171
+ end
172
+
173
+ # Check.
174
+ #
175
+ # @example Check.
176
+ # multi.check
177
+ #
178
+ # @return [ void ]
179
+ def check
180
+ msgs_left = ::FFI::MemoryPointer.new(:int)
181
+ while true
182
+ msg = Curl.multi_info_read(handle, msgs_left)
183
+ break if msg.null?
184
+ next if msg[:code] != :done
185
+ easy = easy_handles.find{ |e| e.handle == msg[:easy_handle] }
186
+ easy.return_code = msg[:data][:code]
187
+ Ethon.logger.debug { "ETHON: performed #{easy.log_inspect}" }
188
+ delete(easy)
189
+ easy.complete
190
+ end
191
+ end
192
+
193
+ # Run.
194
+ #
195
+ # @example Run
196
+ # multi.run
197
+ #
198
+ # @return [ void ]
199
+ def run
200
+ running_count_pointer = FFI::MemoryPointer.new(:int)
201
+ begin code = trigger(running_count_pointer) end while code == :call_multi_perform
202
+ check
203
+ end
204
+
205
+ # Trigger.
206
+ #
207
+ # @example Trigger.
208
+ # multi.trigger
209
+ #
210
+ # @return [ Symbol ] The Curl.multi_perform return code.
211
+ def trigger(running_count_pointer)
212
+ code = Curl.multi_perform(handle, running_count_pointer)
213
+ @running_count = running_count_pointer.read_int
214
+ code
215
+ end
216
+
217
+ # Return number of running requests.
218
+ #
219
+ # @example Return count.
220
+ # multi.running_count
221
+ #
222
+ # @return [ Integer ] Number running requests.
223
+ def running_count
224
+ @running_count ||= nil
225
+ end
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+ class Multi
4
+
5
+ # This module contains the logic and knowledge about the
6
+ # available options on multi.
7
+ module Options
8
+
9
+ # Sets max_total_connections option.
10
+ #
11
+ # @example Set max_total_connections option.
12
+ # multi.max_total_conections = $value
13
+ #
14
+ # @param [ String ] value The value to set.
15
+ #
16
+ # @return [ void ]
17
+ def max_total_connections=(value)
18
+ Curl.set_option(:max_total_connections, value_for(value, :int), handle, :multi)
19
+ end
20
+
21
+ # Sets maxconnects option.
22
+ #
23
+ # @example Set maxconnects option.
24
+ # multi.maxconnects = $value
25
+ #
26
+ # @param [ String ] value The value to set.
27
+ #
28
+ # @return [ void ]
29
+ def maxconnects=(value)
30
+ Curl.set_option(:maxconnects, value_for(value, :int), handle, :multi)
31
+ end
32
+
33
+ # Sets pipelining option.
34
+ #
35
+ # @example Set pipelining option.
36
+ # multi.pipelining = $value
37
+ #
38
+ # @param [ String ] value The value to set.
39
+ #
40
+ # @return [ void ]
41
+ def pipelining=(value)
42
+ Curl.set_option(:pipelining, value_for(value, :int), handle, :multi)
43
+ end
44
+
45
+ # Sets socketdata option.
46
+ #
47
+ # @example Set socketdata option.
48
+ # multi.socketdata = $value
49
+ #
50
+ # @param [ String ] value The value to set.
51
+ #
52
+ # @return [ void ]
53
+ def socketdata=(value)
54
+ Curl.set_option(:socketdata, value_for(value, :string), handle, :multi)
55
+ end
56
+
57
+ # Sets socketfunction option.
58
+ #
59
+ # @example Set socketfunction option.
60
+ # multi.socketfunction = $value
61
+ #
62
+ # @param [ String ] value The value to set.
63
+ #
64
+ # @return [ void ]
65
+ def socketfunction=(value)
66
+ Curl.set_option(:socketfunction, value_for(value, :string), handle, :multi)
67
+ end
68
+
69
+ # Sets timerdata option.
70
+ #
71
+ # @example Set timerdata option.
72
+ # multi.timerdata = $value
73
+ #
74
+ # @param [ String ] value The value to set.
75
+ #
76
+ # @return [ void ]
77
+ def timerdata=(value)
78
+ Curl.set_option(:timerdata, value_for(value, :string), handle, :multi)
79
+ end
80
+
81
+ # Sets timerfunction option.
82
+ #
83
+ # @example Set timerfunction option.
84
+ # multi.timerfunction = $value
85
+ #
86
+ # @param [ String ] value The value to set.
87
+ #
88
+ # @return [ void ]
89
+ def timerfunction=(value)
90
+ Curl.set_option(:timerfunction, value_for(value, :string), handle, :multi)
91
+ end
92
+
93
+ private
94
+
95
+ # Return the value to set to multi handle. It is converted with the help
96
+ # of bool_options, enum_options and int_options.
97
+ #
98
+ # @example Return casted the value.
99
+ # multi.value_for(:verbose)
100
+ #
101
+ # @return [ Object ] The casted value.
102
+ def value_for(value, type, option = nil)
103
+ return nil if value.nil?
104
+
105
+ if type == :bool
106
+ value ? 1 : 0
107
+ elsif type == :int
108
+ value.to_i
109
+ elsif value.is_a?(String)
110
+ Ethon::Easy::Util.escape_zero_byte(value)
111
+ else
112
+ value
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+ class Multi
4
+
5
+ # This module provides the multi stack behaviour.
6
+ module Stack
7
+
8
+ # Return easy handles.
9
+ #
10
+ # @example Return easy handles.
11
+ # multi.easy_handles
12
+ #
13
+ # @return [ Array ] The easy handles.
14
+ def easy_handles
15
+ @easy_handles ||= []
16
+ end
17
+
18
+ # Add an easy to the stack.
19
+ #
20
+ # @example Add easy.
21
+ # multi.add(easy)
22
+ #
23
+ # @param [ Easy ] easy The easy to add.
24
+ #
25
+ # @raise [ Ethon::Errors::MultiAdd ] If adding an easy failed.
26
+ def add(easy)
27
+ return nil if easy_handles.include?(easy)
28
+
29
+ code = Curl.multi_add_handle(handle, easy.handle)
30
+ raise Errors::MultiAdd.new(code, easy) unless code == :ok
31
+ easy_handles << easy
32
+ end
33
+
34
+ # Delete an easy from stack.
35
+ #
36
+ # @example Delete easy from stack.
37
+ #
38
+ # @param [ Easy ] easy The easy to delete.
39
+ #
40
+ # @raise [ Ethon::Errors::MultiRemove ] If removing an easy failed.
41
+ def delete(easy)
42
+ if easy_handles.delete(easy)
43
+ code = Curl.multi_remove_handle(handle, easy.handle)
44
+ raise Errors::MultiRemove.new(code, handle) unless code == :ok
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+ require 'ethon/easy/util'
3
+ require 'ethon/multi/stack'
4
+ require 'ethon/multi/operations'
5
+ require 'ethon/multi/options'
6
+
7
+ module Ethon
8
+
9
+ # This class represents libcurl multi.
10
+ class Multi
11
+ include Ethon::Multi::Stack
12
+ include Ethon::Multi::Operations
13
+ include Ethon::Multi::Options
14
+
15
+ # Create a new multi. Initialize curl in case
16
+ # it didn't happen before.
17
+ #
18
+ # @example Create a new Multi.
19
+ # Multi.new
20
+ #
21
+ # @param [ Hash ] options The options.
22
+ #
23
+ # @option options :socketdata [String]
24
+ # Pass a pointer to whatever you want passed to the
25
+ # curl_socket_callback's forth argument, the userp pointer. This is not
26
+ # used by libcurl but only passed-thru as-is. Set the callback pointer
27
+ # with CURLMOPT_SOCKETFUNCTION.
28
+ # @option options :pipelining [Boolean]
29
+ # Pass a long set to 1 to enable or 0 to disable. Enabling pipelining
30
+ # on a multi handle will make it attempt to perform HTTP Pipelining as
31
+ # far as possible for transfers using this handle. This means that if
32
+ # you add a second request that can use an already existing connection,
33
+ # the second request will be "piped" on the same connection rather than
34
+ # being executed in parallel. (Added in 7.16.0)
35
+ # @option options :timerfunction [Proc]
36
+ # Pass a pointer to a function matching the curl_multi_timer_callback
37
+ # prototype. This function will then be called when the timeout value
38
+ # changes. The timeout value is at what latest time the application
39
+ # should call one of the "performing" functions of the multi interface
40
+ # (curl_multi_socket_action(3) and curl_multi_perform(3)) - to allow
41
+ # libcurl to keep timeouts and retries etc to work. A timeout value of
42
+ # -1 means that there is no timeout at all, and 0 means that the
43
+ # timeout is already reached. Libcurl attempts to limit calling this
44
+ # only when the fixed future timeout time actually changes. See also
45
+ # CURLMOPT_TIMERDATA. This callback can be used instead of, or in
46
+ # addition to, curl_multi_timeout(3). (Added in 7.16.0)
47
+ # @option options :timerdata [String]
48
+ # Pass a pointer to whatever you want passed to the
49
+ # curl_multi_timer_callback's third argument, the userp pointer. This
50
+ # is not used by libcurl but only passed-thru as-is. Set the callback
51
+ # pointer with CURLMOPT_TIMERFUNCTION. (Added in 7.16.0)
52
+ # @option options :maxconnects [Integer]
53
+ # Pass a long. The set number will be used as the maximum amount of
54
+ # simultaneously open connections that libcurl may cache. Default is
55
+ # 10, and libcurl will enlarge the size for each added easy handle to
56
+ # make it fit 4 times the number of added easy handles.
57
+ # By setting this option, you can prevent the cache size from growing
58
+ # beyond the limit set by you.
59
+ # When the cache is full, curl closes the oldest one in the cache to
60
+ # prevent the number of open connections from increasing.
61
+ # This option is for the multi handle's use only, when using the easy
62
+ # interface you should instead use the CURLOPT_MAXCONNECTS option.
63
+ # (Added in 7.16.3)
64
+ # @option options :max_total_connections [Integer]
65
+ # Pass a long. The set number will be used as the maximum amount of
66
+ # simultaneously open connections in total. For each new session,
67
+ # libcurl will open a new connection up to the limit set by
68
+ # CURLMOPT_MAX_TOTAL_CONNECTIONS. When the limit is reached, the
69
+ # sessions will be pending until there are available connections.
70
+ # If CURLMOPT_PIPELINING is 1, libcurl will try to pipeline if the host
71
+ # is capable of it.
72
+ # The default value is 0, which means that there is no limit. However,
73
+ # for backwards compatibility, setting it to 0 when CURLMOPT_PIPELINING
74
+ # is 1 will not be treated as unlimited. Instead it will open only 1
75
+ # connection and try to pipeline on it.
76
+ # (Added in 7.30.0)
77
+ # @option options :execution_mode [Boolean]
78
+ # Either :perform (default) or :socket_action, specifies the usage
79
+ # method that will be used on this multi object. The default :perform
80
+ # mode provides a #perform function that uses curl_multi_perform
81
+ # behind the scenes to automatically continue execution until all
82
+ # requests have completed. The :socket_action mode provides an API
83
+ # that allows the {Multi} object to be integrated into an external
84
+ # IO loop, by calling #socket_action and responding to the
85
+ # socketfunction and timerfunction callbacks, using the underlying
86
+ # curl_multi_socket_action semantics.
87
+ #
88
+ # @return [ Multi ] The new multi.
89
+ def initialize(options = {})
90
+ Curl.init
91
+ @execution_mode = options.delete(:execution_mode) || :perform
92
+ set_attributes(options)
93
+ init_vars
94
+ end
95
+
96
+ # Set given options.
97
+ #
98
+ # @example Set options.
99
+ # multi.set_attributes(options)
100
+ #
101
+ # @raise InvalidOption
102
+ #
103
+ # @see initialize
104
+ #
105
+ # @api private
106
+ def set_attributes(options)
107
+ options.each_pair do |key, value|
108
+ unless respond_to?("#{key}=")
109
+ raise Errors::InvalidOption.new(key)
110
+ end
111
+ method("#{key}=").call(value)
112
+ end
113
+ end
114
+
115
+ private
116
+
117
+ # Internal function to gate functions to a specific execution mode
118
+ #
119
+ # @raise ArgumentError
120
+ #
121
+ # @api private
122
+ def ensure_execution_mode(expected_mode)
123
+ raise ArgumentError, "Expected the Multi to be in #{expected_mode} but it was in #{@execution_mode}" if expected_mode != @execution_mode
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+
4
+ # Ethon version.
5
+ VERSION = '0.15.0'
6
+ end
data/lib/ethon.rb ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ require 'logger'
3
+ require 'ffi'
4
+ require 'thread'
5
+ begin
6
+ require 'mime/types/columnar'
7
+ rescue LoadError
8
+ begin
9
+ require 'mime/types'
10
+ rescue LoadError
11
+ end
12
+ end
13
+ require 'tempfile'
14
+
15
+ require 'ethon/libc'
16
+ require 'ethon/curl'
17
+ require 'ethon/easy'
18
+ require 'ethon/errors'
19
+ require 'ethon/loggable'
20
+ require 'ethon/multi'
21
+ require 'ethon/version'
22
+
23
+ # Ethon is a very simple libcurl.
24
+ # It provides direct access to libcurl functionality
25
+ # as well as some helpers for doing http requests.
26
+ #
27
+ # Ethon was extracted from Typhoeus. If you want to
28
+ # see how others use Ethon look at the Typhoeus code.
29
+ #
30
+ # @see https://www.github.com/typhoeus/typhoeus Typhoeus
31
+ #
32
+ # @note Please update to the latest libcurl version in order
33
+ # to benefit from all features and bugfixes.
34
+ # http://curl.haxx.se/download.html
35
+ module Ethon
36
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: scnr-ethon
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.15.0
5
+ platform: ruby
6
+ authors:
7
+ - Tasos Laskos
8
+ - Hans Hasselberg
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2024-01-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ffi
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 1.15.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 1.15.0
28
+ description: Very lightweight libcurl wrapper.
29
+ email:
30
+ - tasos.laskos@gmail.com
31
+ - me@hans.io
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - CHANGELOG.md
37
+ - LICENSE
38
+ - README.md
39
+ - ethon.gemspec
40
+ - lib/ethon.rb
41
+ - lib/ethon/curl.rb
42
+ - lib/ethon/curls/classes.rb
43
+ - lib/ethon/curls/codes.rb
44
+ - lib/ethon/curls/constants.rb
45
+ - lib/ethon/curls/form_options.rb
46
+ - lib/ethon/curls/functions.rb
47
+ - lib/ethon/curls/infos.rb
48
+ - lib/ethon/curls/messages.rb
49
+ - lib/ethon/curls/options.rb
50
+ - lib/ethon/curls/settings.rb
51
+ - lib/ethon/easy.rb
52
+ - lib/ethon/easy/callbacks.rb
53
+ - lib/ethon/easy/debug_info.rb
54
+ - lib/ethon/easy/features.rb
55
+ - lib/ethon/easy/form.rb
56
+ - lib/ethon/easy/header.rb
57
+ - lib/ethon/easy/http.rb
58
+ - lib/ethon/easy/http/actionable.rb
59
+ - lib/ethon/easy/http/custom.rb
60
+ - lib/ethon/easy/http/delete.rb
61
+ - lib/ethon/easy/http/get.rb
62
+ - lib/ethon/easy/http/head.rb
63
+ - lib/ethon/easy/http/options.rb
64
+ - lib/ethon/easy/http/patch.rb
65
+ - lib/ethon/easy/http/post.rb
66
+ - lib/ethon/easy/http/postable.rb
67
+ - lib/ethon/easy/http/put.rb
68
+ - lib/ethon/easy/http/putable.rb
69
+ - lib/ethon/easy/informations.rb
70
+ - lib/ethon/easy/mirror.rb
71
+ - lib/ethon/easy/operations.rb
72
+ - lib/ethon/easy/options.rb
73
+ - lib/ethon/easy/params.rb
74
+ - lib/ethon/easy/queryable.rb
75
+ - lib/ethon/easy/response_callbacks.rb
76
+ - lib/ethon/easy/util.rb
77
+ - lib/ethon/errors.rb
78
+ - lib/ethon/errors/ethon_error.rb
79
+ - lib/ethon/errors/global_init.rb
80
+ - lib/ethon/errors/invalid_option.rb
81
+ - lib/ethon/errors/invalid_value.rb
82
+ - lib/ethon/errors/multi_add.rb
83
+ - lib/ethon/errors/multi_fdset.rb
84
+ - lib/ethon/errors/multi_remove.rb
85
+ - lib/ethon/errors/multi_timeout.rb
86
+ - lib/ethon/errors/select.rb
87
+ - lib/ethon/libc.rb
88
+ - lib/ethon/loggable.rb
89
+ - lib/ethon/multi.rb
90
+ - lib/ethon/multi/operations.rb
91
+ - lib/ethon/multi/options.rb
92
+ - lib/ethon/multi/stack.rb
93
+ - lib/ethon/version.rb
94
+ homepage: https://github.com/typhoeus/ethon/tree/thread-safe-easy-handle-cleanup
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: 1.3.6
112
+ requirements: []
113
+ rubygems_version: 3.4.22
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Libcurl wrapper.
117
+ test_files: []