ethon 0.9.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ruby.yml +41 -0
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +20 -1
  5. data/Gemfile +14 -4
  6. data/Guardfile +1 -0
  7. data/README.md +4 -1
  8. data/Rakefile +1 -0
  9. data/ethon.gemspec +2 -1
  10. data/lib/ethon.rb +2 -0
  11. data/lib/ethon/curl.rb +1 -0
  12. data/lib/ethon/curls/classes.rb +2 -1
  13. data/lib/ethon/curls/codes.rb +1 -1
  14. data/lib/ethon/curls/constants.rb +1 -0
  15. data/lib/ethon/curls/form_options.rb +1 -0
  16. data/lib/ethon/curls/functions.rb +4 -12
  17. data/lib/ethon/curls/infos.rb +4 -3
  18. data/lib/ethon/curls/messages.rb +1 -0
  19. data/lib/ethon/curls/options.rb +35 -23
  20. data/lib/ethon/curls/settings.rb +2 -0
  21. data/lib/ethon/easy.rb +3 -1
  22. data/lib/ethon/easy/callbacks.rb +25 -3
  23. data/lib/ethon/easy/debug_info.rb +1 -0
  24. data/lib/ethon/easy/features.rb +1 -0
  25. data/lib/ethon/easy/form.rb +7 -4
  26. data/lib/ethon/easy/header.rb +1 -0
  27. data/lib/ethon/easy/http.rb +1 -0
  28. data/lib/ethon/easy/http/actionable.rb +2 -1
  29. data/lib/ethon/easy/http/custom.rb +1 -0
  30. data/lib/ethon/easy/http/delete.rb +1 -0
  31. data/lib/ethon/easy/http/get.rb +1 -0
  32. data/lib/ethon/easy/http/head.rb +1 -0
  33. data/lib/ethon/easy/http/options.rb +1 -0
  34. data/lib/ethon/easy/http/patch.rb +1 -0
  35. data/lib/ethon/easy/http/post.rb +1 -0
  36. data/lib/ethon/easy/http/postable.rb +1 -0
  37. data/lib/ethon/easy/http/put.rb +1 -0
  38. data/lib/ethon/easy/http/putable.rb +1 -0
  39. data/lib/ethon/easy/informations.rb +1 -0
  40. data/lib/ethon/easy/mirror.rb +1 -0
  41. data/lib/ethon/easy/operations.rb +16 -1
  42. data/lib/ethon/easy/options.rb +11 -2
  43. data/lib/ethon/easy/params.rb +1 -0
  44. data/lib/ethon/easy/queryable.rb +4 -1
  45. data/lib/ethon/easy/response_callbacks.rb +27 -0
  46. data/lib/ethon/easy/util.rb +1 -0
  47. data/lib/ethon/errors.rb +1 -0
  48. data/lib/ethon/errors/ethon_error.rb +1 -0
  49. data/lib/ethon/errors/global_init.rb +1 -0
  50. data/lib/ethon/errors/invalid_option.rb +1 -0
  51. data/lib/ethon/errors/invalid_value.rb +1 -0
  52. data/lib/ethon/errors/multi_add.rb +1 -0
  53. data/lib/ethon/errors/multi_fdset.rb +1 -0
  54. data/lib/ethon/errors/multi_remove.rb +1 -0
  55. data/lib/ethon/errors/multi_timeout.rb +1 -0
  56. data/lib/ethon/errors/select.rb +1 -0
  57. data/lib/ethon/libc.rb +16 -1
  58. data/lib/ethon/loggable.rb +1 -0
  59. data/lib/ethon/multi.rb +1 -0
  60. data/lib/ethon/multi/operations.rb +1 -0
  61. data/lib/ethon/multi/options.rb +2 -1
  62. data/lib/ethon/multi/stack.rb +1 -0
  63. data/lib/ethon/version.rb +2 -1
  64. data/profile/benchmarks.rb +1 -0
  65. data/profile/memory_leaks.rb +1 -0
  66. data/profile/perf_spec_helper.rb +1 -0
  67. data/profile/support/memory_test_helpers.rb +1 -0
  68. data/profile/support/os_memory_leak_tracker.rb +1 -0
  69. data/profile/support/ruby_object_leak_tracker.rb +1 -0
  70. data/spec/ethon/curl_spec.rb +1 -0
  71. data/spec/ethon/easy/callbacks_spec.rb +8 -1
  72. data/spec/ethon/easy/debug_info_spec.rb +2 -0
  73. data/spec/ethon/easy/features_spec.rb +1 -0
  74. data/spec/ethon/easy/form_spec.rb +28 -0
  75. data/spec/ethon/easy/header_spec.rb +1 -0
  76. data/spec/ethon/easy/http/custom_spec.rb +1 -0
  77. data/spec/ethon/easy/http/delete_spec.rb +1 -0
  78. data/spec/ethon/easy/http/get_spec.rb +1 -0
  79. data/spec/ethon/easy/http/head_spec.rb +1 -0
  80. data/spec/ethon/easy/http/options_spec.rb +1 -0
  81. data/spec/ethon/easy/http/patch_spec.rb +1 -0
  82. data/spec/ethon/easy/http/post_spec.rb +1 -0
  83. data/spec/ethon/easy/http/put_spec.rb +1 -0
  84. data/spec/ethon/easy/http_spec.rb +1 -0
  85. data/spec/ethon/easy/informations_spec.rb +1 -0
  86. data/spec/ethon/easy/mirror_spec.rb +1 -0
  87. data/spec/ethon/easy/operations_spec.rb +1 -0
  88. data/spec/ethon/easy/options_spec.rb +31 -1
  89. data/spec/ethon/easy/queryable_spec.rb +14 -3
  90. data/spec/ethon/easy/response_callbacks_spec.rb +58 -1
  91. data/spec/ethon/easy/util_spec.rb +1 -0
  92. data/spec/ethon/easy_spec.rb +8 -2
  93. data/spec/ethon/libc_spec.rb +4 -3
  94. data/spec/ethon/loggable_spec.rb +1 -0
  95. data/spec/ethon/multi/operations_spec.rb +1 -0
  96. data/spec/ethon/multi/options_spec.rb +1 -0
  97. data/spec/ethon/multi/stack_spec.rb +1 -0
  98. data/spec/ethon/multi_spec.rb +1 -0
  99. data/spec/spec_helper.rb +1 -0
  100. data/spec/support/localhost_server.rb +2 -1
  101. data/spec/support/server.rb +1 -0
  102. metadata +6 -7
  103. data/.travis.yml +0 -27
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  module Curl
3
4
  callback :callback, [:pointer, :size_t, :size_t, :pointer], :size_t
4
5
  callback :debug_callback, [:pointer, :debug_info_type, :pointer, :size_t, :pointer], :int
6
+ callback :progress_callback, [:pointer, :long_long, :long_long, :long_long, :long_long], :int
5
7
  ffi_lib_flags :now, :global
6
8
  ffi_lib ['libcurl', 'libcurl.so.4']
7
9
  end
data/lib/ethon/easy.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'ethon/easy/informations'
2
3
  require 'ethon/easy/features'
3
4
  require 'ethon/easy/callbacks'
@@ -159,7 +160,6 @@ module Ethon
159
160
  # * :recv_error: Failure with receiving network data.
160
161
  # * :ssl_certproblem: problem with the local client certificate.
161
162
  # * :ssl_cipher: Couldn't use specified cipher.
162
- # * :ssl_cacert: Peer certificate cannot be authenticated with known CA certificates.
163
163
  # * :bad_content_encoding: Unrecognized transfer encoding.
164
164
  # * :ldap_invalid_url: Invalid LDAP URL.
165
165
  # * :filesize_exceeded: Maximum file size exceeded.
@@ -253,6 +253,7 @@ module Ethon
253
253
  @on_complete = nil
254
254
  @on_headers = nil
255
255
  @on_body = nil
256
+ @on_progress = nil
256
257
  @procs = nil
257
258
  @mirror = nil
258
259
  Curl.easy_reset(handle)
@@ -267,6 +268,7 @@ module Ethon
267
268
  e.instance_variable_set(:@body_write_callback, nil)
268
269
  e.instance_variable_set(:@header_write_callback, nil)
269
270
  e.instance_variable_set(:@debug_callback, nil)
271
+ e.instance_variable_set(:@progress_callback, nil)
270
272
  e.set_callbacks
271
273
  e
272
274
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
 
@@ -22,8 +23,8 @@ module Ethon
22
23
  Curl.set_option(:writefunction, body_write_callback, handle)
23
24
  Curl.set_option(:headerfunction, header_write_callback, handle)
24
25
  Curl.set_option(:debugfunction, debug_callback, handle)
25
- @response_body = ""
26
- @response_headers = ""
26
+ @response_body = String.new
27
+ @response_headers = String.new
27
28
  @headers_called = false
28
29
  @debug_info = Ethon::Easy::DebugInfo.new
29
30
  end
@@ -60,7 +61,7 @@ module Ethon
60
61
  # write the raw http request headers.
61
62
  #
62
63
  # @example Return the callback.
63
- # easy.body_write_callback
64
+ # easy.debug_callback
64
65
  #
65
66
  # @return [ Proc ] The callback.
66
67
  def debug_callback
@@ -72,6 +73,27 @@ module Ethon
72
73
  }
73
74
  end
74
75
 
76
+ def set_progress_callback
77
+ if Curl.version_info[:version] >= "7.32.0"
78
+ Curl.set_option(:xferinfofunction, progress_callback, handle)
79
+ else
80
+ Curl.set_option(:progressfunction, progress_callback, handle)
81
+ end
82
+ end
83
+
84
+ # Returns the progress callback.
85
+ #
86
+ # @example Return the callback.
87
+ # easy.progress_callback
88
+ #
89
+ # @return [ Proc ] The callback.
90
+ def progress_callback
91
+ @progress_callback ||= proc { |_, dltotal, dlnow, ultotal, ulnow|
92
+ progress(dltotal, dlnow, ultotal, ulnow)
93
+ 0
94
+ }
95
+ end
96
+
75
97
  # Set the read callback. This callback is used by libcurl to
76
98
  # read data when performing a PUT request.
77
99
  #
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'ethon/easy/util'
2
3
  require 'ethon/easy/queryable'
3
4
 
@@ -21,9 +22,10 @@ module Ethon
21
22
  # @param [ Hash ] params The parameter with which to initialize the form.
22
23
  #
23
24
  # @return [ Form ] A new Form.
24
- def initialize(easy, params)
25
+ def initialize(easy, params, multipart = nil)
25
26
  @easy = easy
26
27
  @params = params || {}
28
+ @multipart = multipart
27
29
  end
28
30
 
29
31
  # Return a pointer to the first form element in libcurl.
@@ -47,13 +49,14 @@ module Ethon
47
49
  end
48
50
 
49
51
  # Return if form is multipart. The form is multipart
50
- # when it contains a file.
52
+ # when it contains a file or multipart option is set on the form during creation.
51
53
  #
52
54
  # @example Return if form is multipart.
53
55
  # form.multipart?
54
56
  #
55
57
  # @return [ Boolean ] True if form is multipart, else false.
56
58
  def multipart?
59
+ return true if @multipart
57
60
  query_pairs.any?{|pair| pair.respond_to?(:last) && pair.last.is_a?(Array)}
58
61
  end
59
62
 
@@ -82,8 +85,8 @@ module Ethon
82
85
  Curl.formadd(first, last,
83
86
  :form_option, :copyname, :pointer, name,
84
87
  :form_option, :namelength, :long, name.bytesize,
85
- :form_option, :copycontents, :pointer, content,
86
- :form_option, :contentslength, :long, content ? content.bytesize : 0,
88
+ :form_option, :copycontents, :pointer, content.to_s,
89
+ :form_option, :contentslength, :long, content ? content.to_s.bytesize : 0,
87
90
  :form_option, :end
88
91
  )
89
92
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  # This module contains the logic around adding headers to libcurl.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'ethon/easy/http/actionable'
2
3
  require 'ethon/easy/http/post'
3
4
  require 'ethon/easy/http/get'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'ethon/easy/http/putable'
2
3
  require 'ethon/easy/http/postable'
3
4
 
@@ -71,7 +72,7 @@ module Ethon
71
72
  #
72
73
  # @return [ Form ] The form.
73
74
  def form
74
- @form ||= Form.new(@easy, query_options.fetch(:body, nil))
75
+ @form ||= Form.new(@easy, query_options.fetch(:body, nil), options.fetch(:multipart, nil))
75
76
  end
76
77
 
77
78
  # Get the requested array encoding. By default it's
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  module Http
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  module Http
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  module Http
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  module Http
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  module Http
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  module Http
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  module Http
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  module Http
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  module Http
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  module Http
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  class Mirror
@@ -1,8 +1,23 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
  # This module contains the logic to prepare and perform
4
5
  # an easy.
5
6
  module Operations
7
+
8
+ class PointerHelper
9
+ class<<self
10
+ def synchronize( &block )
11
+ (@mutex ||= Mutex.new).synchronize( &block )
12
+ end
13
+
14
+ def release( pointer )
15
+ synchronize { Curl.easy_cleanup pointer }
16
+ end
17
+ end
18
+ synchronize{}
19
+ end
20
+
6
21
  # Returns a pointer to the curl easy handle.
7
22
  #
8
23
  # @example Return the handle.
@@ -10,7 +25,7 @@ module Ethon
10
25
  #
11
26
  # @return [ FFI::Pointer ] A pointer to the curl easy handle.
12
27
  def handle
13
- @handle ||= FFI::AutoPointer.new(Curl.easy_init, Curl.method(:easy_cleanup))
28
+ @handle ||= FFI::AutoPointer.new(Curl.easy_init, PointerHelper.method(:release) )
14
29
  end
15
30
 
16
31
  # Sets a pointer to the curl easy handle.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
 
@@ -16,8 +17,16 @@ module Ethon
16
17
  end
17
18
 
18
19
  def escape?
19
- return true if @escape
20
- @escape.nil? ? true : false
20
+ return true if !defined?(@escape) || @escape.nil?
21
+ @escape
22
+ end
23
+
24
+ def multipart=(b)
25
+ @multipart = b
26
+ end
27
+
28
+ def multipart?
29
+ !!@multipart
21
30
  end
22
31
 
23
32
  Curl.easy_options(nil).each do |opt, props|
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'ethon/easy/util'
2
3
  require 'ethon/easy/queryable'
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
 
@@ -102,6 +103,8 @@ module Ethon
102
103
  encode_rack_array_pairs(h, prefix, pairs)
103
104
  elsif params_encoding == :multi
104
105
  encode_multi_array_pairs(h, prefix, pairs)
106
+ elsif params_encoding == :none
107
+ pairs << [prefix, h]
105
108
  else
106
109
  encode_indexed_array_pairs(h, prefix, pairs)
107
110
  end
@@ -128,7 +131,7 @@ module Ethon
128
131
  pairs_for(v, key, pairs)
129
132
  end
130
133
  end
131
-
134
+
132
135
  def encode_multi_array_pairs(h, prefix, pairs)
133
136
  h.each_with_index do |v, i|
134
137
  key = prefix
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy
3
4
 
@@ -69,6 +70,32 @@ module Ethon
69
70
  end
70
71
  end
71
72
 
73
+ # Set on_progress callback.
74
+ #
75
+ # @example Set on_progress.
76
+ # request.on_progress {|dltotal, dlnow, ultotal, ulnow| p "#{dltotal} #{dlnow} #{ultotal} #{ulnow}" }
77
+ #
78
+ # @param [ Block ] block The block to execute.
79
+ def on_progress(&block)
80
+ @on_progress ||= []
81
+ if block_given?
82
+ @on_progress << block
83
+ set_progress_callback
84
+ self.noprogress = 0
85
+ end
86
+ @on_progress
87
+ end
88
+
89
+ # Execute on_progress callbacks.
90
+ #
91
+ # @example Execute on_progress.
92
+ # request.body(1, 1, 1, 1)
93
+ def progress(dltotal, dlnow, ultotal, ulnow)
94
+ if defined?(@on_progress) and not @on_progress.nil?
95
+ @on_progress.each{ |callback| callback.call(dltotal, dlnow, ultotal, ulnow) }
96
+ end
97
+ end
98
+
72
99
  # Set on_body callback.
73
100
  #
74
101
  # @example Set on_body.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  class Easy # :nodoc:
3
4
 
data/lib/ethon/errors.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'ethon/errors/ethon_error'
2
3
  require 'ethon/errors/global_init'
3
4
  require 'ethon/errors/multi_timeout'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  module Errors
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  module Errors
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  module Errors
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  module Errors
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  module Errors
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  module Errors
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  module Errors
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  module Errors
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Ethon
2
3
  module Errors
3
4