ethon-impersonate 0.17.9-arm64-darwin

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 (68) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +391 -0
  3. data/LICENSE +20 -0
  4. data/README.md +116 -0
  5. data/config/puma.rb +1 -0
  6. data/ethon-impersonate.gemspec +29 -0
  7. data/ext/libcurl-impersonate.4.dylib +0 -0
  8. data/lib/ethon-impersonate.rb +1 -0
  9. data/lib/ethon_impersonate/curl.rb +90 -0
  10. data/lib/ethon_impersonate/curls/classes.rb +65 -0
  11. data/lib/ethon_impersonate/curls/codes.rb +122 -0
  12. data/lib/ethon_impersonate/curls/constants.rb +81 -0
  13. data/lib/ethon_impersonate/curls/form_options.rb +37 -0
  14. data/lib/ethon_impersonate/curls/functions.rb +59 -0
  15. data/lib/ethon_impersonate/curls/infos.rb +151 -0
  16. data/lib/ethon_impersonate/curls/messages.rb +19 -0
  17. data/lib/ethon_impersonate/curls/options.rb +503 -0
  18. data/lib/ethon_impersonate/curls/settings.rb +13 -0
  19. data/lib/ethon_impersonate/easy/callbacks.rb +149 -0
  20. data/lib/ethon_impersonate/easy/debug_info.rb +49 -0
  21. data/lib/ethon_impersonate/easy/features.rb +31 -0
  22. data/lib/ethon_impersonate/easy/form.rb +107 -0
  23. data/lib/ethon_impersonate/easy/header.rb +65 -0
  24. data/lib/ethon_impersonate/easy/http/actionable.rb +157 -0
  25. data/lib/ethon_impersonate/easy/http/custom.rb +29 -0
  26. data/lib/ethon_impersonate/easy/http/delete.rb +25 -0
  27. data/lib/ethon_impersonate/easy/http/get.rb +24 -0
  28. data/lib/ethon_impersonate/easy/http/head.rb +24 -0
  29. data/lib/ethon_impersonate/easy/http/options.rb +24 -0
  30. data/lib/ethon_impersonate/easy/http/patch.rb +24 -0
  31. data/lib/ethon_impersonate/easy/http/post.rb +26 -0
  32. data/lib/ethon_impersonate/easy/http/postable.rb +32 -0
  33. data/lib/ethon_impersonate/easy/http/put.rb +27 -0
  34. data/lib/ethon_impersonate/easy/http/putable.rb +25 -0
  35. data/lib/ethon_impersonate/easy/http.rb +68 -0
  36. data/lib/ethon_impersonate/easy/informations.rb +118 -0
  37. data/lib/ethon_impersonate/easy/mirror.rb +38 -0
  38. data/lib/ethon_impersonate/easy/operations.rb +64 -0
  39. data/lib/ethon_impersonate/easy/options.rb +50 -0
  40. data/lib/ethon_impersonate/easy/params.rb +29 -0
  41. data/lib/ethon_impersonate/easy/queryable.rb +154 -0
  42. data/lib/ethon_impersonate/easy/response_callbacks.rb +136 -0
  43. data/lib/ethon_impersonate/easy/util.rb +28 -0
  44. data/lib/ethon_impersonate/easy.rb +332 -0
  45. data/lib/ethon_impersonate/errors/ethon_error.rb +9 -0
  46. data/lib/ethon_impersonate/errors/global_init.rb +13 -0
  47. data/lib/ethon_impersonate/errors/invalid_option.rb +13 -0
  48. data/lib/ethon_impersonate/errors/invalid_value.rb +13 -0
  49. data/lib/ethon_impersonate/errors/multi_add.rb +12 -0
  50. data/lib/ethon_impersonate/errors/multi_fdset.rb +12 -0
  51. data/lib/ethon_impersonate/errors/multi_remove.rb +12 -0
  52. data/lib/ethon_impersonate/errors/multi_timeout.rb +13 -0
  53. data/lib/ethon_impersonate/errors/select.rb +13 -0
  54. data/lib/ethon_impersonate/errors.rb +17 -0
  55. data/lib/ethon_impersonate/impersonate/fingerprints.rb +16 -0
  56. data/lib/ethon_impersonate/impersonate/settings.rb +85 -0
  57. data/lib/ethon_impersonate/impersonate/targets.rb +99 -0
  58. data/lib/ethon_impersonate/impersonate/tls.rb +189 -0
  59. data/lib/ethon_impersonate/impersonate.rb +10 -0
  60. data/lib/ethon_impersonate/libc.rb +21 -0
  61. data/lib/ethon_impersonate/loggable.rb +59 -0
  62. data/lib/ethon_impersonate/multi/operations.rb +228 -0
  63. data/lib/ethon_impersonate/multi/options.rb +117 -0
  64. data/lib/ethon_impersonate/multi/stack.rb +49 -0
  65. data/lib/ethon_impersonate/multi.rb +126 -0
  66. data/lib/ethon_impersonate/version.rb +6 -0
  67. data/lib/ethon_impersonate.rb +28 -0
  68. metadata +122 -0
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+
5
+ # This class is used to store and retreive debug information,
6
+ # which is only saved when verbose is set to true.
7
+ #
8
+ # @api private
9
+ class DebugInfo
10
+
11
+ MESSAGE_TYPES = EthonImpersonate::Curl::DebugInfoType.to_h.keys
12
+
13
+ class Message
14
+ attr_reader :type, :message
15
+
16
+ def initialize(type, message)
17
+ @type = type
18
+ @message = message
19
+ end
20
+ end
21
+
22
+ def initialize
23
+ @messages = []
24
+ end
25
+
26
+ def add(type, message)
27
+ @messages << Message.new(type, message)
28
+ end
29
+
30
+ def messages_for(type)
31
+ @messages.select {|m| m.type == type }.map(&:message)
32
+ end
33
+
34
+ MESSAGE_TYPES.each do |type|
35
+ define_method(type) do
36
+ messages_for(type.to_sym)
37
+ end
38
+ end
39
+
40
+ def to_a
41
+ @messages.map(&:message)
42
+ end
43
+
44
+ def to_h
45
+ Hash[MESSAGE_TYPES.map {|k| [k, send(k)] }]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+
5
+ # This module contains class methods for feature checks
6
+ module Features
7
+ # Returns true if this curl version supports zlib.
8
+ #
9
+ # @example Return wether zlib is supported.
10
+ # EthonImpersonate::Easy.supports_zlib?
11
+ #
12
+ # @return [ Boolean ] True if supported, else false.
13
+ def supports_zlib?
14
+ !!(Curl.version_info[:features] & Curl::VERSION_LIBZ)
15
+ end
16
+
17
+ # Returns true if this curl version supports AsynchDNS.
18
+ #
19
+ # @example
20
+ # EthonImpersonate::Easy.supports_asynch_dns?
21
+ #
22
+ # @return [ Boolean ] True if supported, else false.
23
+ def supports_asynch_dns?
24
+ !!(Curl.version_info[:features] & Curl::VERSION_ASYNCHDNS)
25
+ end
26
+
27
+ alias :supports_timeout_ms? :supports_asynch_dns?
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+ require 'ethon_impersonate/easy/util'
3
+ require 'ethon_impersonate/easy/queryable'
4
+
5
+ module EthonImpersonate
6
+ class Easy
7
+
8
+ # This class represents a form and is used to send a payload in the
9
+ # request body via POST/PUT.
10
+ # It handles multipart forms, too.
11
+ #
12
+ # @api private
13
+ class Form
14
+ include EthonImpersonate::Easy::Util
15
+ include EthonImpersonate::Easy::Queryable
16
+
17
+ # Return a new Form.
18
+ #
19
+ # @example Return a new Form.
20
+ # Form.new({})
21
+ #
22
+ # @param [ Hash ] params The parameter with which to initialize the form.
23
+ #
24
+ # @return [ Form ] A new Form.
25
+ def initialize(easy, params, multipart = nil)
26
+ @easy = easy
27
+ @params = params || {}
28
+ @multipart = multipart
29
+ end
30
+
31
+ # Return a pointer to the first form element in libcurl.
32
+ #
33
+ # @example Return the first form element.
34
+ # form.first
35
+ #
36
+ # @return [ FFI::Pointer ] The first element.
37
+ def first
38
+ @first ||= FFI::MemoryPointer.new(:pointer)
39
+ end
40
+
41
+ # Return a pointer to the last form element in libcurl.
42
+ #
43
+ # @example Return the last form element.
44
+ # form.last
45
+ #
46
+ # @return [ FFI::Pointer ] The last element.
47
+ def last
48
+ @last ||= FFI::MemoryPointer.new(:pointer)
49
+ end
50
+
51
+ # Return if form is multipart. The form is multipart
52
+ # when it contains a file or multipart option is set on the form during creation.
53
+ #
54
+ # @example Return if form is multipart.
55
+ # form.multipart?
56
+ #
57
+ # @return [ Boolean ] True if form is multipart, else false.
58
+ def multipart?
59
+ return true if @multipart
60
+ query_pairs.any?{|pair| pair.respond_to?(:last) && pair.last.is_a?(Array)}
61
+ end
62
+
63
+ # Add form elements to libcurl.
64
+ #
65
+ # @example Add form to libcurl.
66
+ # form.materialize
67
+ def materialize
68
+ query_pairs.each { |pair| form_add(pair.first.to_s, pair.last) }
69
+ end
70
+
71
+ private
72
+
73
+ def form_add(name, content)
74
+ case content
75
+ when Array
76
+ Curl.formadd(first, last,
77
+ :form_option, :copyname, :pointer, name,
78
+ :form_option, :namelength, :long, name.bytesize,
79
+ :form_option, :file, :string, content[2],
80
+ :form_option, :filename, :string, content[0],
81
+ :form_option, :contenttype, :string, content[1],
82
+ :form_option, :end
83
+ )
84
+ else
85
+ Curl.formadd(first, last,
86
+ :form_option, :copyname, :pointer, name,
87
+ :form_option, :namelength, :long, name.bytesize,
88
+ :form_option, :copycontents, :pointer, content.to_s,
89
+ :form_option, :contentslength, :long, content ? content.to_s.bytesize : 0,
90
+ :form_option, :end
91
+ )
92
+ end
93
+
94
+ setup_garbage_collection
95
+ end
96
+
97
+ def setup_garbage_collection
98
+ # first is a pointer to a pointer. Since it's a MemoryPointer it will
99
+ # auto clean itself up, but we need to clean up the object it points
100
+ # to. So this results in (pseudo-c):
101
+ # form_data_cleanup_handler = *first
102
+ # curl_form_free(form_data_cleanup_handler)
103
+ @form_data_cleanup_handler ||= FFI::AutoPointer.new(@first.get_pointer(0), Curl.method(:formfree))
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+ # This module contains the logic around adding headers to libcurl.
5
+ #
6
+ # @api private
7
+ module Header
8
+ # Return headers, return empty hash if none.
9
+ #
10
+ # @example Return the headers.
11
+ # easy.headers
12
+ #
13
+ # @return [ Hash ] The headers.
14
+ def headers
15
+ @headers ||= {}
16
+ end
17
+
18
+ # Set the headers.
19
+ #
20
+ # @example Set the headers.
21
+ # easy.headers = {'User-Agent' => 'EthonImpersonate'}
22
+ #
23
+ # @param [ Hash ] headers The headers.
24
+ def headers=(headers)
25
+ headers ||= {}
26
+ header_list = nil
27
+ headers.each do |k, v|
28
+ v_list = v.is_a?(Array) ? v : [v]
29
+
30
+ v_list.each do |v_item|
31
+ header_list = Curl.slist_append(header_list, compose_header(k,v_item))
32
+ end
33
+ end
34
+ Curl.set_option(:httpheader, header_list, handle)
35
+
36
+ @header_list = header_list && FFI::AutoPointer.new(header_list, Curl.method(:slist_free_all))
37
+ end
38
+
39
+ # Return header_list.
40
+ #
41
+ # @example Return header_list.
42
+ # easy.header_list
43
+ #
44
+ # @return [ FFI::Pointer ] The header list.
45
+ def header_list
46
+ @header_list
47
+ end
48
+
49
+ # Compose libcurl header string from key and value.
50
+ # Also replaces null bytes, because libcurl will complain
51
+ # otherwise.
52
+ #
53
+ # @example Compose header.
54
+ # easy.compose_header('User-Agent', 'EthonImpersonate')
55
+ #
56
+ # @param [ String ] key The header name.
57
+ # @param [ String ] value The header value.
58
+ #
59
+ # @return [ String ] The composed header.
60
+ def compose_header(key, value)
61
+ Util.escape_zero_byte("#{key}: #{value}")
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+ require 'ethon_impersonate/easy/http/putable'
3
+ require 'ethon_impersonate/easy/http/postable'
4
+
5
+ module EthonImpersonate
6
+ class Easy
7
+ module Http
8
+ # This module represents a Http Action and is a factory
9
+ # for more real actions like GET, HEAD, POST and PUT.
10
+ module Actionable
11
+
12
+ QUERY_OPTIONS = [ :params, :body, :params_encoding ]
13
+
14
+ # Create a new action.
15
+ #
16
+ # @example Create a new action.
17
+ # Action.new("www.example.com", {})
18
+ #
19
+ # @param [ String ] url The url.
20
+ # @param [ Hash ] options The options.
21
+ #
22
+ # @return [ Action ] A new action.
23
+ def initialize(url, options)
24
+ @url = url
25
+ @options, @query_options = parse_options(options)
26
+ end
27
+
28
+ # Return the url.
29
+ #
30
+ # @example Return url.
31
+ # action.url
32
+ #
33
+ # @return [ String ] The url.
34
+ def url
35
+ @url
36
+ end
37
+
38
+ # Return the options hash.
39
+ #
40
+ # @example Return options.
41
+ # action.options
42
+ #
43
+ # @return [ Hash ] The options.
44
+ def options
45
+ @options
46
+ end
47
+
48
+ # Returns the query options hash.
49
+ #
50
+ # @example Return query options.
51
+ # action.query_options
52
+ #
53
+ # @return [ Hash ] The query options.
54
+ def query_options
55
+ @query_options
56
+ end
57
+
58
+ # Return the params.
59
+ #
60
+ # @example Return params.
61
+ # action.params
62
+ #
63
+ # @return [ Params ] The params.
64
+ def params
65
+ @params ||= Params.new(@easy, query_options.fetch(:params, nil))
66
+ end
67
+
68
+ # Return the form.
69
+ #
70
+ # @example Return form.
71
+ # action.form
72
+ #
73
+ # @return [ Form ] The form.
74
+ def form
75
+ @form ||= Form.new(@easy, query_options.fetch(:body, nil), options.fetch(:multipart, nil))
76
+ end
77
+
78
+ # Get the requested array encoding. By default it's
79
+ # :typhoeus, but it can also be set to :rack.
80
+ #
81
+ # @example Get encoding from options
82
+ # action.params_encoding
83
+ #
84
+ def params_encoding
85
+ @params_encoding ||= query_options.fetch(:params_encoding, :typhoeus)
86
+ end
87
+
88
+ # Setup everything necessary for a proper request.
89
+ #
90
+ # @example setup.
91
+ # action.setup(easy)
92
+ #
93
+ # @param [ easy ] easy the easy to setup.
94
+ def setup(easy)
95
+ @easy = easy
96
+
97
+ # Order is important, @easy will be used to provide access to options
98
+ # relevant to the following operations (like whether or not to escape
99
+ # values).
100
+ easy.set_attributes(options)
101
+
102
+ set_form(easy) unless form.empty?
103
+
104
+ if params.empty?
105
+ easy.url = url
106
+ else
107
+ set_params(easy)
108
+ end
109
+ end
110
+
111
+ # Setup request with params.
112
+ #
113
+ # @example Setup nothing.
114
+ # action.set_params(easy)
115
+ #
116
+ # @param [ Easy ] easy The easy to setup.
117
+ def set_params(easy)
118
+ params.escape = easy.escape?
119
+ params.params_encoding = params_encoding
120
+
121
+ base_url, base_params = url.split('?')
122
+ base_url << '?'
123
+ base_url << base_params.to_s
124
+ base_url << '&' if base_params
125
+ base_url << params.to_s
126
+
127
+ easy.url = base_url
128
+ end
129
+
130
+ # Setup request with form.
131
+ #
132
+ # @example Setup nothing.
133
+ # action.set_form(easy)
134
+ #
135
+ # @param [ Easy ] easy The easy to setup.
136
+ def set_form(easy)
137
+ end
138
+
139
+ private
140
+
141
+ def parse_options(options)
142
+ query_options = {}
143
+ options = options.dup
144
+
145
+ QUERY_OPTIONS.each do |query_option|
146
+ if options.key?(query_option)
147
+ query_options[query_option] = options.delete(query_option)
148
+ end
149
+ end
150
+
151
+ return options, query_options
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+ module Http
5
+
6
+ # This class knows everything about making requests for custom HTTP verbs.
7
+ class Custom
8
+ include EthonImpersonate::Easy::Http::Actionable
9
+ include EthonImpersonate::Easy::Http::Postable
10
+
11
+ def initialize(verb, url, options)
12
+ @verb = verb
13
+ super(url, options)
14
+ end
15
+
16
+ # Setup easy to make a request.
17
+ #
18
+ # @example Setup.
19
+ # custom.set_params(easy)
20
+ #
21
+ # @param [ Easy ] easy The easy to setup.
22
+ def setup(easy)
23
+ super
24
+ easy.customrequest = @verb
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+ module Http
5
+
6
+ # This class knows everything about making DELETE requests.
7
+ class Delete
8
+ include EthonImpersonate::Easy::Http::Actionable
9
+ include EthonImpersonate::Easy::Http::Postable
10
+
11
+ # Setup easy to make a DELETE request.
12
+ #
13
+ # @example Setup customrequest.
14
+ # delete.setup(easy)
15
+ #
16
+ # @param [ Easy ] easy The easy to setup.
17
+ def setup(easy)
18
+ super
19
+ easy.customrequest = "DELETE"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+ module Http
5
+
6
+ # This class knows everything about making GET requests.
7
+ class Get
8
+ include EthonImpersonate::Easy::Http::Actionable
9
+ include EthonImpersonate::Easy::Http::Postable
10
+
11
+ # Setup easy to make a GET request.
12
+ #
13
+ # @example Setup.
14
+ # get.set_params(easy)
15
+ #
16
+ # @param [ Easy ] easy The easy to setup.
17
+ def setup(easy)
18
+ super
19
+ easy.customrequest = "GET" unless form.empty?
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+ module Http
5
+
6
+ # This class knows everything about making HEAD requests.
7
+ class Head
8
+ include EthonImpersonate::Easy::Http::Actionable
9
+ include EthonImpersonate::Easy::Http::Postable
10
+
11
+ # Setup easy to make a HEAD request.
12
+ #
13
+ # @example Setup.
14
+ # get.set_params(easy)
15
+ #
16
+ # @param [ Easy ] easy The easy to setup.
17
+ def setup(easy)
18
+ super
19
+ easy.nobody = true
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+ module Http
5
+
6
+ # This class knows everything about making OPTIONS requests.
7
+ class Options
8
+ include EthonImpersonate::Easy::Http::Actionable
9
+ include EthonImpersonate::Easy::Http::Postable
10
+
11
+ # Setup easy to make a OPTIONS request.
12
+ #
13
+ # @example Setup.
14
+ # options.setup(easy)
15
+ #
16
+ # @param [ Easy ] easy The easy to setup.
17
+ def setup(easy)
18
+ super
19
+ easy.customrequest = "OPTIONS"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+ module Http
5
+
6
+ # This class knows everything about making PATCH requests.
7
+ class Patch
8
+ include EthonImpersonate::Easy::Http::Actionable
9
+ include EthonImpersonate::Easy::Http::Postable
10
+
11
+ # Setup easy to make a PATCH request.
12
+ #
13
+ # @example Setup.
14
+ # patch.setup(easy)
15
+ #
16
+ # @param [ Easy ] easy The easy to setup.
17
+ def setup(easy)
18
+ super
19
+ easy.customrequest = "PATCH"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+ module Http
5
+ # This class knows everything about making POST requests.
6
+ class Post
7
+ include EthonImpersonate::Easy::Http::Actionable
8
+ include EthonImpersonate::Easy::Http::Postable
9
+
10
+ # Setup easy to make a POST request.
11
+ #
12
+ # @example Setup.
13
+ # post.setup(easy)
14
+ #
15
+ # @param [ Easy ] easy The easy to setup.
16
+ def setup(easy)
17
+ super
18
+ if form.empty?
19
+ easy.postfieldsize = 0
20
+ easy.copypostfields = ""
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+ module Http
5
+
6
+ # This module contains logic for setting up a [multipart] POST body.
7
+ module Postable
8
+
9
+ # Set things up when form is provided.
10
+ # Deals with multipart forms.
11
+ #
12
+ # @example Setup.
13
+ # post.set_form(easy)
14
+ #
15
+ # @param [ Easy ] easy The easy to setup.
16
+ def set_form(easy)
17
+ easy.url ||= url
18
+ form.params_encoding = params_encoding
19
+ if form.multipart?
20
+ form.escape = false
21
+ form.materialize
22
+ easy.httppost = form.first.read_pointer
23
+ else
24
+ form.escape = easy.escape?
25
+ easy.postfieldsize = form.to_s.bytesize
26
+ easy.copypostfields = form.to_s
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+ module Http
5
+
6
+ # This class knows everything about making PUT requests.
7
+ class Put
8
+ include EthonImpersonate::Easy::Http::Actionable
9
+ include EthonImpersonate::Easy::Http::Putable
10
+
11
+ # Setup easy to make a PUT request.
12
+ #
13
+ # @example Setup.
14
+ # put.setup(easy)
15
+ #
16
+ # @param [ Easy ] easy The easy to setup.
17
+ def setup(easy)
18
+ super
19
+ if form.empty?
20
+ easy.upload = true
21
+ easy.infilesize = 0
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ module EthonImpersonate
3
+ class Easy
4
+ module Http
5
+
6
+ # This module contains logic about setting up a PUT body.
7
+ module Putable
8
+ # Set things up when form is provided.
9
+ # Deals with multipart forms.
10
+ #
11
+ # @example Setup.
12
+ # put.set_form(easy)
13
+ #
14
+ # @param [ Easy ] easy The easy to setup.
15
+ def set_form(easy)
16
+ easy.upload = true
17
+ form.escape = true
18
+ form.params_encoding = params_encoding
19
+ easy.infilesize = form.to_s.bytesize
20
+ easy.set_read_callback(form.to_s)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end