ethon 0.18.0 → 0.19.1

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +705 -2
  3. data/README.md +183 -40
  4. data/lib/ethon/curl.rb +22 -0
  5. data/lib/ethon/curls/classes.rb +284 -12
  6. data/lib/ethon/curls/codes.rb +28 -9
  7. data/lib/ethon/curls/constants.rb +61 -4
  8. data/lib/ethon/curls/form_options.rb +2 -1
  9. data/lib/ethon/curls/functions.rb +60 -11
  10. data/lib/ethon/curls/infos.rb +104 -5
  11. data/lib/ethon/curls/introspection.rb +139 -0
  12. data/lib/ethon/curls/introspection_constants.rb +42 -0
  13. data/lib/ethon/curls/mime.rb +187 -0
  14. data/lib/ethon/curls/optional.rb +14 -0
  15. data/lib/ethon/curls/options.rb +298 -71
  16. data/lib/ethon/curls/settings.rb +12 -3
  17. data/lib/ethon/curls/share.rb +165 -0
  18. data/lib/ethon/curls/share_constants.rb +47 -0
  19. data/lib/ethon/curls/url.rb +171 -0
  20. data/lib/ethon/curls/url_constants.rb +78 -0
  21. data/lib/ethon/easy/callbacks.rb +177 -51
  22. data/lib/ethon/easy/features.rb +4 -1
  23. data/lib/ethon/easy/files.rb +113 -0
  24. data/lib/ethon/easy/form.rb +65 -6
  25. data/lib/ethon/easy/header.rb +57 -15
  26. data/lib/ethon/easy/headers_api.rb +79 -0
  27. data/lib/ethon/easy/http/actionable.rb +25 -3
  28. data/lib/ethon/easy/http/get.rb +5 -1
  29. data/lib/ethon/easy/http/post.rb +1 -0
  30. data/lib/ethon/easy/http/postable.rb +9 -2
  31. data/lib/ethon/easy/http/putable.rb +19 -4
  32. data/lib/ethon/easy/http.rb +16 -4
  33. data/lib/ethon/easy/informations.rb +51 -2
  34. data/lib/ethon/easy/mime.rb +29 -0
  35. data/lib/ethon/easy/mirror.rb +17 -4
  36. data/lib/ethon/easy/operations.rb +264 -11
  37. data/lib/ethon/easy/options.rb +327 -8
  38. data/lib/ethon/easy/queryable.rb +59 -14
  39. data/lib/ethon/easy/response_callbacks.rb +33 -12
  40. data/lib/ethon/easy/share.rb +28 -0
  41. data/lib/ethon/easy/url.rb +32 -0
  42. data/lib/ethon/easy/util.rb +19 -0
  43. data/lib/ethon/easy.rb +185 -10
  44. data/lib/ethon/errors/fork_safety.rb +10 -0
  45. data/lib/ethon/errors/form_add.rb +12 -0
  46. data/lib/ethon/errors/global_init.rb +1 -1
  47. data/lib/ethon/errors/header.rb +12 -0
  48. data/lib/ethon/errors/invalid_option.rb +3 -1
  49. data/lib/ethon/errors/invalid_value.rb +3 -1
  50. data/lib/ethon/errors/mime.rb +17 -0
  51. data/lib/ethon/errors/multi_add.rb +1 -1
  52. data/lib/ethon/errors/multi_assign.rb +12 -0
  53. data/lib/ethon/errors/multi_fdset.rb +1 -1
  54. data/lib/ethon/errors/multi_perform.rb +12 -0
  55. data/lib/ethon/errors/multi_poll.rb +12 -0
  56. data/lib/ethon/errors/multi_remove.rb +1 -1
  57. data/lib/ethon/errors/multi_timeout.rb +2 -2
  58. data/lib/ethon/errors/multi_wait.rb +12 -0
  59. data/lib/ethon/errors/multi_wakeup.rb +12 -0
  60. data/lib/ethon/errors/select.rb +1 -1
  61. data/lib/ethon/errors/set_option.rb +27 -0
  62. data/lib/ethon/errors/share.rb +17 -0
  63. data/lib/ethon/errors/unsupported_option.rb +23 -0
  64. data/lib/ethon/errors/url.rb +17 -0
  65. data/lib/ethon/errors.rb +13 -0
  66. data/lib/ethon/libc.rb +30 -1
  67. data/lib/ethon/loggable.rb +1 -1
  68. data/lib/ethon/multi/operations.rb +269 -25
  69. data/lib/ethon/multi/options.rb +114 -12
  70. data/lib/ethon/multi/stack.rb +181 -10
  71. data/lib/ethon/multi.rb +51 -15
  72. data/lib/ethon/version.rb +1 -1
  73. data/lib/ethon.rb +8 -9
  74. metadata +35 -6
@@ -1,10 +1,40 @@
1
1
  # frozen_string_literal: true
2
+ require 'ethon/easy/util'
2
3
  module Ethon
3
4
  module Curls
4
5
 
5
6
  # This module contains logic for setting options on
6
7
  # easy or multi interface.
7
8
  module Options
9
+ # libcurl writes these values verbatim into an HTTP request line, a
10
+ # protocol header, or a protocol command. A carriage return or newline
11
+ # would let a caller inject another header or command into the request.
12
+ #
13
+ # The URL is parsed later, but libcurl only rejects CR/LF at transfer
14
+ # time. Accepting it here would store an invalid value in Easy#url and
15
+ # write it to the debug log before the transfer fails.
16
+ LINE_BASED_OPTIONS = [
17
+ :accept_encoding,
18
+ :cookie,
19
+ :customrequest,
20
+ :encoding,
21
+ :ftp_account,
22
+ :ftp_alternative_to_user,
23
+ :haproxy_client_ip,
24
+ :krblevel,
25
+ :login_options,
26
+ :mail_auth,
27
+ :mail_from,
28
+ :range,
29
+ :referer,
30
+ :request_target,
31
+ :rtsp_session_id,
32
+ :rtsp_stream_uri,
33
+ :rtsp_transport,
34
+ :url,
35
+ :useragent,
36
+ :xoauth2_bearer
37
+ ].freeze
8
38
 
9
39
  OPTION_STRINGS = { :easy => 'easy_options', :multi => 'multi_options' }.freeze
10
40
  FOPTION_STRINGS = { :easy => 'EASY_OPTIONS', :multi => 'MULTI_OPTIONS' }.freeze
@@ -12,19 +42,27 @@ module Ethon
12
42
  # Sets appropriate option for easy, depending on value type.
13
43
  def set_option(option, value, handle, type = :easy)
14
44
  type = type.to_sym unless type.is_a?(Symbol)
15
- raise NameError, "Ethon::Curls::Options unknown type #{type}." unless respond_to?(OPTION_STRINGS[type])
45
+ raise NameError, "Ethon::Curls::Options unknown type #{type}." unless OPTION_STRINGS.key?(type)
16
46
  opthash=send(OPTION_STRINGS[type], nil)
17
47
  raise Errors::InvalidOption.new(option) unless opthash.include?(option)
18
48
 
49
+ # A freed wrapper still looks like a pointer, but libcurl would keep
50
+ # the dangling address. Reject it before the option reaches native
51
+ # state.
52
+ if defined?(Ethon::Curl::OwnedPointer) && value.is_a?(Ethon::Curl::OwnedPointer)
53
+ value.check_pid!
54
+ end
55
+
19
56
  case opthash[option][:type]
20
57
  when :none
21
- return if value.nil?
58
+ # These options take no value; false means "do not enable".
59
+ return unless value
22
60
  value=1
23
61
  va_type=:long
24
62
  when :int
25
63
  return if value.nil?
26
64
  va_type=:long
27
- value=value.to_i
65
+ value = Ethon::Curls::Options.integer_value(option, value)
28
66
  when :bool
29
67
  return if value.nil?
30
68
  va_type=:long
@@ -32,41 +70,55 @@ module Ethon
32
70
  when :time
33
71
  return if value.nil?
34
72
  va_type=:long
35
- value=value.to_i
73
+ value = Ethon::Curls::Options.integer_value(option, value)
36
74
  when :enum
37
75
  return if value.nil?
38
76
  va_type=:long
39
- value = case value
40
- when Symbol
41
- opthash[option][:opts][value]
42
- when String
43
- opthash[option][:opts][value.to_sym]
44
- else
45
- value
46
- end.to_i
77
+ value = named_option_value(option, value, opthash[option][:opts])
47
78
  when :bitmask
48
79
  return if value.nil?
49
80
  va_type=:long
50
- value = case value
51
- when Symbol
52
- opthash[option][:opts][value]
53
- when Array
54
- value.inject(0) { |res,v| res|opthash[option][:opts][v] }
55
- else
56
- value
57
- end.to_i
81
+ value = Array(value).inject(0) do |mask, item|
82
+ mask | named_option_value(option, item, opthash[option][:opts])
83
+ end
58
84
  when :string
59
85
  va_type=:string
60
- value=value.to_s unless value.nil?
86
+ unless value.nil?
87
+ string = value.to_s
88
+ raise Errors::InvalidValue.new(option, value) if string.include?("\0")
89
+ if LINE_BASED_OPTIONS.include?(option) &&
90
+ (string.include?("\r") || string.include?("\n"))
91
+ raise Errors::InvalidValue.new(option, value)
92
+ end
93
+ # libcurl writes CURLOPT_HAPROXY_CLIENT_IP into the
94
+ # space-separated PROXY protocol line, so whitespace could add
95
+ # fields or lines to the header.
96
+ if option == :haproxy_client_ip && string.match?(/[[:space:]]/)
97
+ raise Errors::InvalidValue.new(option, value)
98
+ end
99
+ value = string
100
+ end
101
+ when :binary_string
102
+ # The caller owns the buffer and passes its length separately. Ethon
103
+ # uses this for CURLOPT_POSTFIELDS, whose custom setter retains the
104
+ # buffer and sets CURLOPT_POSTFIELDSIZE.
105
+ va_type=:pointer
106
+ unless value.nil? || value.is_a?(::FFI::Pointer)
107
+ raise Errors::InvalidValue.new(option, value)
108
+ end
61
109
  when :string_as_pointer
62
110
  va_type = :pointer
63
- s = ''
64
- s = value.to_s unless value.nil?
65
- value = FFI::MemoryPointer.new(:char, s.bytesize)
66
- value.put_bytes(0, s)
111
+ unless value.nil?
112
+ s = value.to_s
113
+ # libcurl treats CURLOPT_*POSTFIELDS as a C string unless an
114
+ # explicit size is set, so reserve and write the terminator.
115
+ value = FFI::MemoryPointer.new(:char, s.bytesize + 1)
116
+ value.put_bytes(0, s)
117
+ value.put_char(s.bytesize, 0)
118
+ end
67
119
  when :string_escape_null
68
120
  va_type=:string
69
- value=Util.escape_zero_byte(value) unless value.nil?
121
+ value=Ethon::Easy::Util.escape_zero_byte(value) unless value.nil?
70
122
  when :ffipointer
71
123
  va_type=:pointer
72
124
  raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? FFI::Pointer
@@ -74,9 +126,18 @@ module Ethon
74
126
  va_type=:pointer
75
127
  raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? FFI::Pointer
76
128
  when :buffer
77
- raise NotImplementedError, "Ethon::Curls::Options option #{option} buffer type not implemented."
129
+ va_type=:pointer
130
+ raise Errors::InvalidValue.new(option,value) unless value.nil? or (value.is_a?(FFI::Pointer) and value.size >= opthash[option][:opts])
131
+ when :blob
132
+ va_type=:pointer
133
+ unless value.nil? || value.is_a?(FFI::Pointer) || value.is_a?(Ethon::Curl::Blob)
134
+ raise Errors::InvalidValue.new(option,value)
135
+ end
136
+ value = value.to_ptr if value.is_a?(Ethon::Curl::Blob)
78
137
  when :dontuse_object
79
138
  raise NotImplementedError, "Ethon::Curls::Options option #{option} type not implemented."
139
+ when :dontuse_callback
140
+ raise NotImplementedError, "Ethon::Curls::Options option #{option} callback type not implemented."
80
141
  when :cbdata
81
142
  raise NotImplementedError, "Ethon::Curls::Options option #{option} callback data type not implemented. Use Ruby closures."
82
143
  when :callback
@@ -94,25 +155,78 @@ module Ethon
94
155
  when :progress_callback
95
156
  va_type=:progress_callback
96
157
  raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? Proc
158
+ when :xferinfo_callback
159
+ va_type=:xferinfo_callback
160
+ raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? Proc
97
161
  when :off_t
98
162
  return if value.nil?
99
163
  va_type=:int64
100
- value=value.to_i
164
+ value = Ethon::Curls::Options.integer_value(option, value)
165
+ end
166
+
167
+ if va_type == :long || va_type == :int64
168
+ limit = 1 << (FFI.type_size(va_type) * 8 - 1)
169
+ unless value >= -limit && value < limit
170
+ raise Errors::InvalidValue.new(option, value)
171
+ end
172
+ end
173
+ result = send(FUNCS[type], handle, opthash[option][:opt], va_type, value)
174
+
175
+ # Silently ignored options are a correctness bug: on an older libcurl
176
+ # the request would run with a different configuration than requested.
177
+ case result
178
+ when :ok
179
+ result
180
+ when :unknown_option
181
+ raise Errors::UnsupportedOption.new(option)
182
+ else
183
+ raise Errors::SetOption.new(option, result, type)
101
184
  end
185
+ end
186
+
187
+ def named_option_value(option, value, values, seen = [])
188
+ return value if value.is_a?(Integer)
102
189
 
103
- if va_type==:long or va_type==:int64 then
104
- bits=FFI.type_size(va_type)*8
105
- tv=((value<0) ? value.abs-1 : value)
106
- raise Errors::InvalidValue.new(option,value) unless tv<(1<<bits)
190
+ name = value.is_a?(String) ? value.to_sym : value
191
+ raise Errors::InvalidValue.new(option, value) unless name.is_a?(Symbol) && values.key?(name)
192
+ raise Errors::InvalidValue.new(option, value) if seen.include?(name)
193
+
194
+ resolved = values[name]
195
+ if resolved.is_a?(Array)
196
+ resolved.inject(0) do |mask, item|
197
+ mask | named_option_value(option, item, values, seen + [name])
198
+ end
199
+ elsif resolved.is_a?(Symbol) || resolved.is_a?(String)
200
+ named_option_value(option, resolved, values, seen + [name])
201
+ else
202
+ resolved
107
203
  end
108
- send(FUNCS[type], handle, opthash[option][:opt], va_type, value)
204
+ end
205
+
206
+ def self.integer_value(option, value)
207
+ return value if value.is_a?(Integer)
208
+ return 1 if value == true
209
+ return 0 if value == false
210
+
211
+ begin
212
+ integer = Integer(value)
213
+ rescue ArgumentError, TypeError, RangeError
214
+ raise Errors::InvalidValue.new(option, value)
215
+ end
216
+
217
+ if value.is_a?(Numeric) && value != integer
218
+ raise Errors::InvalidValue.new(option, value)
219
+ end
220
+
221
+ integer
109
222
  end
110
223
 
111
224
  OPTION_TYPE_BASE = {
112
225
  :long => 0,
113
226
  :objectpoint => 10000,
114
227
  :functionpoint => 20000,
115
- :off_t => 30000
228
+ :off_t => 30000,
229
+ :blob => 40000
116
230
  }
117
231
  OPTION_TYPE_MAP = {
118
232
  :none => :long,
@@ -135,19 +249,23 @@ module Ethon
135
249
  # (See :protocols)
136
250
  # :all defaults to all bits set
137
251
  :string => :objectpoint,
252
+ :binary_string => :objectpoint,
138
253
  :string_escape_null => :objectpoint,
139
254
  :string_as_pointer => :objectpoint,
140
255
  :ffipointer => :objectpoint, # FFI::Pointer
141
256
  :curl_slist => :objectpoint,
142
257
  :buffer => :objectpoint, # A memory buffer of size defined in the options
143
- :dontuse_object => :objectpoint, # An object we don't support (e.g. FILE*)
258
+ :dontuse_object => :objectpoint, # An object we don't support
144
259
  :cbdata => :objectpoint,
145
260
  :callback => :functionpoint,
261
+ :dontuse_callback => :functionpoint,
146
262
  :socket_callback => :functionpoint,
147
263
  :timer_callback => :functionpoint,
148
264
  :debug_callback => :functionpoint,
149
265
  :progress_callback => :functionpoint,
266
+ :xferinfo_callback => :functionpoint,
150
267
  :off_t => :off_t,
268
+ :blob => :blob,
151
269
  }
152
270
 
153
271
  def self.option(ftype,name,type,num,opts=nil)
@@ -202,6 +320,12 @@ module Ethon
202
320
  aliases.each { |a| opthash[a]=opthash[name] }
203
321
  end
204
322
 
323
+ # Add named enum or bitmask values to an already defined option.
324
+ def self.option_value_aliases(ftype,name,values)
325
+ opthash=const_get(FOPTION_STRINGS[ftype])
326
+ opthash.fetch(name)[:opts].merge!(values)
327
+ end
328
+
205
329
  def self.option_type(type)
206
330
  cname = FOPTION_STRINGS[type]
207
331
  const_set(cname, {})
@@ -212,15 +336,15 @@ module Ethon
212
336
  end
213
337
 
214
338
  # Curl multi options, refer
215
- # Defined @ https://github.com/bagder/curl/blob/master/include/curl/multi.h
216
- # Documentation @ http://curl.haxx.se/libcurl/c/curl_multi_setopt.html
339
+ # Defined @ https://github.com/curl/curl/blob/master/include/curl/multi.h
340
+ # Documentation @ https://curl.se/libcurl/c/curl_multi_setopt.html
217
341
  option_type :multi
218
342
 
219
343
  option :multi, :socketfunction, :socket_callback, 1
220
- option :multi, :socketdata, :cbdata, 2
344
+ option :multi, :socketdata, :ffipointer, 2
221
345
  option :multi, :pipelining, :int, 3
222
346
  option :multi, :timerfunction, :timer_callback, 4
223
- option :multi, :timerdata, :cbdata, 5
347
+ option :multi, :timerdata, :ffipointer, 5
224
348
  option :multi, :maxconnects, :int, 6
225
349
  option :multi, :max_host_connections, :int, 7
226
350
  option :multi, :max_pipeline_length, :int, 8
@@ -228,11 +352,12 @@ module Ethon
228
352
  option :multi, :chunk_length_penalty_size, :off_t, 10
229
353
  option :multi, :pipelining_site_bl, :dontuse_object, 11
230
354
  option :multi, :pipelining_server_bl, :dontuse_object, 12
231
- option :multi, :max_total_connections, :int, 3
355
+ option :multi, :max_total_connections, :int, 13
356
+ option :multi, :max_concurrent_streams, :int, 16
232
357
 
233
358
  # Curl easy options
234
- # Defined @ https://github.com/bagder/curl/blob/master/include/curl/curl.h
235
- # Documentation @ http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
359
+ # Defined @ https://github.com/curl/curl/blob/master/include/curl/curl.h
360
+ # Documentation @ https://curl.se/libcurl/c/curl_easy_setopt.html
236
361
  ## BEHAVIOR OPTIONS
237
362
  option_type :easy
238
363
 
@@ -248,15 +373,15 @@ module Ethon
248
373
  option :easy, :readfunction, :callback, 12
249
374
  option :easy, :infile, :cbdata, 9
250
375
  option_alias :easy, :infile, :readdata
251
- option :easy, :ioctlfunction, :callback, 130
376
+ option :easy, :ioctlfunction, :dontuse_callback, 130
252
377
  option :easy, :ioctldata, :cbdata, 131
253
- option :easy, :seekfunction, :callback, 167
378
+ option :easy, :seekfunction, :dontuse_callback, 167
254
379
  option :easy, :seekdata, :cbdata, 168
255
- option :easy, :sockoptfunction, :callback, 148
380
+ option :easy, :sockoptfunction, :dontuse_callback, 148
256
381
  option :easy, :sockoptdata, :cbdata, 149
257
- option :easy, :opensocketfunction, :callback, 163
382
+ option :easy, :opensocketfunction, :dontuse_callback, 163
258
383
  option :easy, :opensocketdata, :cbdata, 164
259
- option :easy, :closesocketfunction, :callback, 208
384
+ option :easy, :closesocketfunction, :dontuse_callback, 208
260
385
  option :easy, :closesocketdata, :cbdata, 209
261
386
  option :easy, :path_as_is, :bool, 234
262
387
  option :easy, :progressfunction, :progress_callback, 56
@@ -266,19 +391,19 @@ module Ethon
266
391
  option_alias :easy, :writeheader, :headerdata
267
392
  option :easy, :debugfunction, :debug_callback, 94
268
393
  option :easy, :debugdata, :cbdata, 95
269
- option :easy, :ssl_ctx_function, :callback, 108
394
+ option :easy, :ssl_ctx_function, :dontuse_callback, 108
270
395
  option :easy, :ssl_ctx_data, :cbdata, 109
271
- option :easy, :conv_to_network_function, :callback, 143
272
- option :easy, :conv_from_network_function, :callback, 142
273
- option :easy, :conv_from_utf8_function, :callback, 144
396
+ option :easy, :conv_to_network_function, :dontuse_callback, 143
397
+ option :easy, :conv_from_network_function, :dontuse_callback, 142
398
+ option :easy, :conv_from_utf8_function, :dontuse_callback, 144
274
399
  option :easy, :interleavefunction, :callback, 196
275
400
  option :easy, :interleavedata, :cbdata, 195
276
- option :easy, :chunk_bgn_function, :callback, 198
277
- option :easy, :chunk_end_function, :callback, 199
401
+ option :easy, :chunk_bgn_function, :dontuse_callback, 198
402
+ option :easy, :chunk_end_function, :dontuse_callback, 199
278
403
  option :easy, :chunk_data, :cbdata, 201
279
- option :easy, :fnmatch_function, :callback, 200
404
+ option :easy, :fnmatch_function, :dontuse_callback, 200
280
405
  option :easy, :fnmatch_data, :cbdata, 202
281
- option :easy, :xferinfofunction, :progress_callback, 219
406
+ option :easy, :xferinfofunction, :xferinfo_callback, 219
282
407
  option :easy, :xferinfodata, :cbdata, 57
283
408
  ## ERROR OPTIONS
284
409
  option :easy, :errorbuffer, :buffer, 10, 256
@@ -286,11 +411,11 @@ module Ethon
286
411
  option :easy, :failonerror, :bool, 45
287
412
  ## NETWORK OPTIONS
288
413
  option :easy, :url, :string, 2
289
- option :easy, :protocols, :bitmask, 181, [nil, :http, :https, :ftp, :ftps, :scp, :sftp, :telnet, :ldap, :ldaps, :dict, :file, :tftp, :imap, :imaps, :pop3, :pop3s, :smtp, :smtps, :rtsp, :rtmp, :rtmpt, :rtmpe, :rtmpte, :rtmps, :rtmpts, :gopher]
290
- option :easy, :redir_protocols, :bitmask, 182, [nil, :http, :https, :ftp, :ftps, :scp, :sftp, :telnet, :ldap, :ldaps, :dict, :file, :tftp, :imap, :imaps, :pop3, :pop3s, :smtp, :smtps, :rtsp, :rtmp, :rtmpt, :rtmpe, :rtmpte, :rtmps, :rtmpts, :gopher]
414
+ option :easy, :protocols, :bitmask, 181, [nil, :http, :https, :ftp, :ftps, :scp, :sftp, :telnet, :ldap, :ldaps, :dict, :file, :tftp, :imap, :imaps, :pop3, :pop3s, :smtp, :smtps, :rtsp, :rtmp, :rtmpt, :rtmpe, :rtmpte, :rtmps, :rtmpts, :gopher, :smb, :smbs, :mqtt, :gophers]
415
+ option :easy, :redir_protocols, :bitmask, 182, [nil, :http, :https, :ftp, :ftps, :scp, :sftp, :telnet, :ldap, :ldaps, :dict, :file, :tftp, :imap, :imaps, :pop3, :pop3s, :smtp, :smtps, :rtsp, :rtmp, :rtmpt, :rtmpe, :rtmpte, :rtmps, :rtmpts, :gopher, :smb, :smbs, :mqtt, :gophers]
291
416
  option :easy, :proxy, :string, 4
292
417
  option :easy, :proxyport, :int, 59
293
- option :easy, :proxytype, :enum, 101, [:http, :http_1_0, :https, nil, :socks4, :socks5, :socks4a, :socks5_hostname]
418
+ option :easy, :proxytype, :enum, 101, [:http, :http_1_0, :https, :https2, :socks4, :socks5, :socks4a, :socks5_hostname, :https3]
294
419
  option :easy, :noproxy, :string, 177
295
420
  option :easy, :httpproxytunnel, :bool, 61
296
421
  option :easy, :socks5_gssapi_service, :string, 179
@@ -307,7 +432,7 @@ module Ethon
307
432
  option :easy, :port, :int, 3
308
433
  option :easy, :tcp_nodelay, :bool, 121
309
434
  option :easy, :address_scope, :int, 171
310
- option :easy, :tcp_fastopen, :bool, 212
435
+ option :easy, :tcp_fastopen, :bool, 244
311
436
  option :easy, :tcp_keepalive, :bool, 213
312
437
  option :easy, :tcp_keepidle, :int, 214
313
438
  option :easy, :tcp_keepintvl, :int, 215
@@ -320,11 +445,11 @@ module Ethon
320
445
  option :easy, :password, :string, 174
321
446
  option :easy, :proxyusername, :string, 175
322
447
  option :easy, :proxypassword, :string, 176
323
- option :easy, :httpauth, :bitmask, 107, [:none, :basic, :digest, :gssnegotiate, :ntlm, :digest_ie, :ntlm_wb, {:only => 1<<31, :any => ~0x10, :anysafe => ~0x11, :auto => 0x1f}]
324
- option :easy, :tlsauth_type, :enum, 206, [:none, :srp]
448
+ option :easy, :httpauth, :bitmask, 107, [:none, :basic, :digest, :gssnegotiate, :ntlm, :digest_ie, :ntlm_wb, {:only => 1<<31, :any => ~0x110, :anysafe => ~0x111, :auto => 0x1f}]
449
+ option :easy, :tlsauth_type, :string, 206
325
450
  option :easy, :tlsauth_username, :string, 204
326
451
  option :easy, :tlsauth_password, :string, 205
327
- option :easy, :proxyauth, :bitmask, 111, [:none, :basic, :digest, :gssnegotiate, :ntlm, :digest_ie, :ntlm_wb, {:only => 1<<31, :any => ~0x10, :anysafe => ~0x11, :auto => 0x1f}]
452
+ option :easy, :proxyauth, :bitmask, 111, [:none, :basic, :digest, :gssnegotiate, :ntlm, :digest_ie, :ntlm_wb, {:only => 1<<31, :any => ~0x110, :anysafe => ~0x111, :auto => 0x1f}]
328
453
  option :easy, :sasl_ir, :bool, 218
329
454
  ## HTTP OPTIONS
330
455
  option :easy, :autoreferer, :bool, 58
@@ -338,7 +463,10 @@ module Ethon
338
463
  option_alias :easy, :postredir, :post301
339
464
  option :easy, :put, :bool, 54
340
465
  option :easy, :post, :bool, 47
341
- option :easy, :postfields, :string, 15
466
+ # CURLOPT_POSTFIELDS is paired with CURLOPT_POSTFIELDSIZE, so the body
467
+ # may contain NUL bytes. The custom #postfields= setter always sets the
468
+ # length from the retained string.
469
+ option :easy, :postfields, :binary_string, 15
342
470
  option :easy, :postfieldsize, :int, 60
343
471
  option :easy, :postfieldsize_large, :off_t, 120
344
472
  option :easy, :copypostfields, :string_as_pointer, 165
@@ -353,7 +481,11 @@ module Ethon
353
481
  option :easy, :cookiesession, :bool, 96
354
482
  option :easy, :cookielist, :string, 135
355
483
  option :easy, :httpget, :bool, 80
356
- option :easy, :http_version, :enum, 84, [:none, :httpv1_0, :httpv1_1, :httpv2_0, :httpv2_tls, :httpv2_prior_knowledge]
484
+ option :easy, :http_version, :enum, 84, {
485
+ :none => 0, :httpv1_0 => 1, :httpv1_1 => 2, :httpv2_0 => 3,
486
+ :httpv2_tls => 4, :httpv2_prior_knowledge => 5,
487
+ :httpv3 => 30, :httpv3only => 31
488
+ }
357
489
  option :easy, :ignore_content_length, :bool, 136
358
490
  option :easy, :http_content_decoding, :bool, 158
359
491
  option :easy, :http_transfer_decoding, :bool, 157
@@ -453,7 +585,7 @@ module Ethon
453
585
  option :easy, :egdsocket, :string, 77
454
586
  option :easy, :ssl_cipher_list, :string, 83
455
587
  option :easy, :ssl_sessionid_cache, :bool, 150
456
- option :easy, :ssl_options, :bitmask, 216, [nil, :allow_beast]
588
+ option :easy, :ssl_options, :bitmask, 216, [nil, :allow_beast, :no_revoke, :no_partialchain, :revoke_best_effort, :native_ca, :auto_client_cert, :earlydata]
457
589
  option :easy, :krblevel, :string, 63
458
590
  option_alias :easy, :krblevel, :krb4level
459
591
  option :easy, :gssapi_delegation, :bitmask, 210, [:none, :policy_flag, :flag]
@@ -467,7 +599,7 @@ module Ethon
467
599
  option :easy, :proxy_sslversion, :enum, 250, [:default, :tlsv1, :sslv2, :sslv3, :tlsv1_0, :tlsv1_1, :tlsv1_2, :tlsv1_3]
468
600
  option :easy, :proxy_tlsauth_username, :string, 251
469
601
  option :easy, :proxy_tlsauth_password, :string, 252
470
- option :easy, :proxy_tlsauth_type, :enum, 253, [:none, :srp]
602
+ option :easy, :proxy_tlsauth_type, :string, 253
471
603
  option :easy, :proxy_sslcert, :string, 254
472
604
  option :easy, :proxy_sslcerttype, :string, 255
473
605
  option :easy, :proxy_sslkey, :string, 256
@@ -477,27 +609,122 @@ module Ethon
477
609
  option_alias :easy, :proxy_keypasswd, :proxy_sslkeypasswd
478
610
  option :easy, :proxy_ssl_cipher_list, :string, 259
479
611
  option :easy, :proxy_crlfile, :string, 260
480
- option :easy, :proxy_ssl_options, :bitmask, 261, [nil, :allow_beast]
612
+ option :easy, :proxy_ssl_options, :bitmask, 261, [nil, :allow_beast, :no_revoke, :no_partialchain, :revoke_best_effort, :native_ca, :auto_client_cert, :earlydata]
481
613
  option :easy, :pre_proxy, :string, 262
482
614
  option :easy, :proxy_pinnedpublickey, :string, 263
483
615
  option_alias :easy, :proxy_pinnedpublickey, :proxy_pinned_public_key
484
616
  option :easy, :proxy_issuercert, :string, 296
485
617
  ## SSH OPTIONS
486
- option :easy, :ssh_auth_types, :bitmask, 151, [:none, :publickey, :password, :host, :keyboard, :agent, {:any => [:all], :default => [:any]}]
618
+ option :easy, :ssh_auth_types, :bitmask, 151, [:none, :publickey, :password, :host, :keyboard, :agent, :gssapi, {:any => [:all], :default => [:any]}]
487
619
  option :easy, :ssh_host_public_key_md5, :string, 162
488
620
  option :easy, :ssh_public_keyfile, :string, 152
489
621
  option :easy, :ssh_private_keyfile, :string, 153
490
622
  option :easy, :ssh_knownhosts, :string, 183
491
- option :easy, :ssh_keyfunction, :callback, 184
492
- option :easy, :khstat, :enum, -1, [:fine_add_to_file, :fine, :reject, :defer] # Kludge to make this enum available... Access via CurL::EASY_OPTIONS[:khstat][:opt]
623
+ option :easy, :ssh_keyfunction, :dontuse_callback, 184
493
624
  option :easy, :ssh_keydata, :cbdata, 185
494
625
  ## OTHER OPTIONS
495
626
  option :easy, :private, :cbdata, 103
496
- option :easy, :share, :dontuse_object, 100
627
+ option :easy, :share, :ffipointer, 100
497
628
  option :easy, :new_file_perms, :int, 159
498
629
  option :easy, :new_directory_perms, :int, 160
630
+ ## NEWER OPTIONS
631
+ option :easy, :curlu, :ffipointer, 282
632
+ option :easy, :abstract_unix_socket, :string, 264
633
+ option :easy, :altsvc, :string, 287
634
+ option :easy, :altsvc_ctrl, :bitmask, 286, [nil, nil, nil, :readonlyfile, :h1, :h2, :h3]
635
+ option :easy, :aws_sigv4, :string, 305
636
+ option :easy, :ca_cache_timeout, :int, 321
637
+ option :easy, :cainfo_blob, :blob, 309
638
+ option :easy, :connect_to, :curl_slist, 243
639
+ option :easy, :default_protocol, :string, 238
640
+ option :easy, :disallow_username_in_url, :bool, 278
641
+ option :easy, :dns_local_ip6, :string, 223
642
+ option :easy, :doh_ssl_verifyhost, :int, 307
643
+ option :easy, :doh_ssl_verifypeer, :bool, 306
644
+ option :easy, :doh_ssl_verifystatus, :bool, 308
645
+ option :easy, :doh_url, :string, 279
646
+ option :easy, :ech, :string, 325
647
+ option :easy, :expect_100_timeout_ms, :int, 227
648
+ option :easy, :happy_eyeballs_timeout_ms, :int, 271
649
+ option :easy, :haproxy_client_ip, :string, 323
650
+ option :easy, :haproxyprotocol, :bool, 274
651
+ option :easy, :headeropt, :enum, 229, [:unified, :separate]
652
+ option :easy, :hsts, :string, 300
653
+ option :easy, :hsts_ctrl, :bitmask, 299, [nil, :enable, :readonlyfile]
654
+ option :easy, :hstsreaddata, :ffipointer, 302
655
+ option :easy, :hstsreadfunction, :dontuse_callback, 301
656
+ option :easy, :hstswritedata, :ffipointer, 304
657
+ option :easy, :hstswritefunction, :dontuse_callback, 303
658
+ option :easy, :http09_allowed, :bool, 285
659
+ option :easy, :httpsig_algorithm, :enum, 329, [:none, :ed25519, :hmac_sha256]
660
+ option :easy, :httpsig_headers, :string, 332
661
+ option :easy, :httpsig_key, :string, 330
662
+ option :easy, :httpsig_keyid, :string, 331
663
+ option :easy, :issuercert_blob, :blob, 295
664
+ option :easy, :keep_sending_on_error, :bool, 245
665
+ option :easy, :login_options, :string, 224
666
+ option :easy, :mail_rcpt_allowfails, :bool, 290
667
+ option :easy, :maxage_conn, :int, 288
668
+ option :easy, :maxlifetime_conn, :int, 314
669
+ option :easy, :mime_options, :bitmask, 315, [nil, :formescape]
670
+ option :easy, :mimepost, :ffipointer, 269
671
+ option :easy, :prereqdata, :ffipointer, 313
672
+ option :easy, :prereqfunction, :dontuse_callback, 312
673
+ option :easy, :protocols_str, :string, 318
674
+ option :easy, :proxy_cainfo_blob, :blob, 310
675
+ option :easy, :proxy_issuercert_blob, :blob, 297
676
+ option :easy, :proxy_service_name, :string, 235
677
+ option :easy, :proxy_sslcert_blob, :blob, 293
678
+ option :easy, :proxy_sslkey_blob, :blob, 294
679
+ option :easy, :proxy_tls13_ciphers, :string, 277
680
+ option :easy, :proxyheader, :curl_slist, 228
681
+ option :easy, :quick_exit, :bool, 322
682
+ option :easy, :redir_protocols_str, :string, 319
683
+ option :easy, :request_target, :string, 266
684
+ option :easy, :resolver_start_data, :ffipointer, 273
685
+ option :easy, :resolver_start_function, :dontuse_callback, 272
686
+ option :easy, :sasl_authzid, :string, 289
687
+ option :easy, :server_response_timeout_ms, :int, 324
688
+ option :easy, :service_name, :string, 236
689
+ option :easy, :socks5_auth, :bitmask, 267, {:none => 0, :basic => 1, :gssapi => 1<<2}
690
+ option :easy, :ssh_compression, :bool, 268
691
+ option :easy, :ssh_host_public_key_sha256, :string, 311
692
+ option :easy, :ssh_hostkeydata, :ffipointer, 317
693
+ option :easy, :ssh_hostkeyfunction, :dontuse_callback, 316
694
+ option :easy, :ssl_ec_curves, :string, 298
695
+ option :easy, :ssl_enable_alpn, :bool, 226
696
+ option :easy, :ssl_enable_npn, :bool, 225
697
+ option :easy, :ssl_falsestart, :bool, 233
698
+ option :easy, :ssl_signature_algorithms, :string, 328
699
+ option :easy, :ssl_verifystatus, :bool, 232
700
+ option :easy, :sslcert_blob, :blob, 291
701
+ option :easy, :sslkey_blob, :blob, 292
702
+ option :easy, :stream_depends, :ffipointer, 240
703
+ option :easy, :stream_depends_e, :ffipointer, 241
704
+ option :easy, :stream_weight, :int, 239
705
+ option :easy, :suppress_connect_headers, :bool, 265
706
+ option :easy, :tcp_keepcnt, :int, 326
707
+ option :easy, :tftp_no_options, :bool, 242
708
+ option :easy, :timevalue_large, :off_t, 270
709
+ option :easy, :tls13_ciphers, :string, 276
710
+ option :easy, :trailerdata, :ffipointer, 284
711
+ option :easy, :trailerfunction, :dontuse_callback, 283
712
+ option :easy, :upkeep_interval_ms, :int, 281
713
+ option :easy, :upload_buffersize, :int, 280
714
+ option :easy, :upload_flags, :bitmask, 327, [nil, :answered, :deleted, :draft, :flagged, :seen]
715
+ option :easy, :ws_options, :bitmask, 320, [nil, :raw_mode]
716
+ option :easy, :xoauth2_bearer, :string, 220
717
+
499
718
  ## TELNET OPTIONS
500
719
  option :easy, :telnetoptions, :curl_slist, 70
720
+
721
+ ## NAMED VALUE ADDITIONS
722
+ option_value_aliases :easy, :httpauth,
723
+ :negotiate => :gssnegotiate, :bearer => 1<<6, :aws_sigv4 => 1<<7,
724
+ :httpsig => 1<<8
725
+ option_value_aliases :easy, :proxyauth,
726
+ :negotiate => :gssnegotiate, :bearer => 1<<6, :aws_sigv4 => 1<<7,
727
+ :httpsig => 1<<8
501
728
  end
502
729
  end
503
730
  end
@@ -1,12 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
  module Ethon
3
3
  module Curl
4
+ if Curl.windows?
5
+ typedef :size_t, :curl_socket_t
6
+ else
7
+ typedef :int, :curl_socket_t
8
+ end
9
+
4
10
  callback :callback, [:pointer, :size_t, :size_t, :pointer], :size_t
5
- callback :socket_callback, [:pointer, :int, :poll_action, :pointer, :pointer], :multi_code
11
+ callback :socket_callback, [:pointer, :curl_socket_t, :poll_action, :pointer, :pointer], :multi_code
6
12
  callback :timer_callback, [:pointer, :long, :pointer], :multi_code
7
13
  callback :debug_callback, [:pointer, :debug_info_type, :pointer, :size_t, :pointer], :int
8
- callback :progress_callback, [:pointer, :long_long, :long_long, :long_long, :long_long], :int
14
+ # CURLOPT_PROGRESSFUNCTION uses doubles, while CURLOPT_XFERINFOFUNCTION uses
15
+ # curl_off_t. They are not ABI-compatible on all platforms.
16
+ callback :progress_callback, [:pointer, :double, :double, :double, :double], :int
17
+ callback :xferinfo_callback, [:pointer, :long_long, :long_long, :long_long, :long_long], :int
9
18
  ffi_lib_flags :now, :global
10
- ffi_lib ['libcurl', 'libcurl.so.4']
19
+ ffi_lib ENV.fetch('ETHON_CURL_LIBS', 'libcurl,libcurl.so.4,libcurl-4,libcurl-x64,libcurl-arm64').split(',')
11
20
  end
12
21
  end