rest-man 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/{multi-matrix-test.yml → ci.yml} +10 -1
- data/.github/workflows/single-matrix-test.yml +1 -0
- data/.gitignore +2 -0
- data/.rubocop-disables.yml +4 -29
- data/AUTHORS +5 -1
- data/CHANGELOG.md +14 -0
- data/Gemfile +3 -0
- data/README.md +30 -37
- data/Rakefile +1 -59
- data/_doc/lib/restman/abstract_response/_follow_redirection.rdoc +7 -0
- data/_doc/lib/restman/abstract_response/beautify_headers.rdoc +24 -0
- data/_doc/lib/restman/abstract_response/cookie_jar.rdoc +4 -0
- data/_doc/lib/restman/abstract_response/cookies.rdoc +12 -0
- data/_doc/lib/restman/abstract_response/follow_get_redirection.rdoc +2 -0
- data/_doc/lib/restman/abstract_response/follow_redirection.rdoc +2 -0
- data/_doc/lib/restman/abstract_response/headers.rdoc +2 -0
- data/_doc/lib/restman/abstract_response/response_set_vars.rdoc +5 -0
- data/_doc/lib/restman/abstract_response/return.rdoc +9 -0
- data/_doc/lib/restman/add_before_execution_proc.rdoc +2 -0
- data/_doc/lib/restman/create_log.rdoc +2 -0
- data/_doc/lib/restman/exception.rdoc +6 -0
- data/_doc/lib/restman/exceptions/timeout.rdoc +4 -0
- data/_doc/lib/restman/exceptions.rdoc +4 -0
- data/_doc/lib/restman/log=.rdoc +3 -0
- data/_doc/lib/restman/params_array/new.rdoc +20 -0
- data/_doc/lib/restman/params_array/process_pair.rdoc +4 -0
- data/_doc/lib/restman/params_array.rdoc +11 -0
- data/_doc/lib/restman/platform/jruby?.rdoc +4 -0
- data/_doc/lib/restman/platform/mac_mri?.rdoc +5 -0
- data/_doc/lib/restman/proxy.rdoc +2 -0
- data/_doc/lib/restman/proxy_set?.rdoc +5 -0
- data/_doc/lib/restman/raw_response/new.rdoc +6 -0
- data/_doc/lib/restman/raw_response.rdoc +10 -0
- data/_doc/lib/restman/request/cookie_jar.rdoc +3 -0
- data/_doc/lib/restman/request/cookies.rdoc +11 -0
- data/_doc/lib/restman/request/default_headers.rdoc +5 -0
- data/_doc/lib/restman/request/default_ssl_cert_store.rdoc +8 -0
- data/_doc/lib/restman/request/init/cookie_jar.rdoc +55 -0
- data/_doc/lib/restman/request/init/http_method.rdoc +15 -0
- data/_doc/lib/restman/request/make_cookie_header.rdoc +8 -0
- data/_doc/lib/restman/request/make_headers.rdoc +25 -0
- data/_doc/lib/restman/request/maybe_convert_extension.rdoc +18 -0
- data/_doc/lib/restman/request/process_result.rdoc +4 -0
- data/_doc/lib/restman/request/proxy_uri.rdoc +7 -0
- data/_doc/lib/restman/request/stringify_headers.rdoc +9 -0
- data/_doc/lib/restman/request/use_ssl.rdoc +4 -0
- data/_doc/lib/restman/request.rdoc +46 -0
- data/_doc/lib/restman/reset_before_execution_procs.rdoc +1 -0
- data/_doc/lib/restman/resource/[].rdoc +25 -0
- data/_doc/lib/restman/resource.rdoc +33 -0
- data/_doc/lib/restman/response/body.rdoc +7 -0
- data/_doc/lib/restman/response/create.rdoc +10 -0
- data/_doc/lib/restman/response/fix_encoding.rdoc +2 -0
- data/_doc/lib/restman/statuses.rdoc +11 -0
- data/_doc/lib/restman/utils/cgi_parse_header.rdoc +6 -0
- data/_doc/lib/restman/utils/encode_query_string.rdoc +90 -0
- data/_doc/lib/restman/utils/escape.rdoc +11 -0
- data/_doc/lib/restman/utils/flatten_params.rdoc +16 -0
- data/_doc/lib/restman/utils/get_encoding_from_headers.rdoc +24 -0
- data/_doc/lib/restman.rdoc +43 -0
- data/bin/console +15 -0
- data/lib/restman/abstract_response.rb +13 -60
- data/lib/restman/exception.rb +43 -0
- data/lib/restman/exceptions/exception_with_response.rb +7 -0
- data/lib/restman/exceptions/exceptions_map.rb +26 -0
- data/lib/restman/exceptions/request_failed.rb +15 -0
- data/lib/restman/exceptions/server_broke_connection.rb +13 -0
- data/lib/restman/exceptions/timeout.rb +37 -0
- data/lib/restman/params_array/process_pair.rb +39 -0
- data/lib/restman/params_array.rb +3 -48
- data/lib/restman/payload/base.rb +57 -0
- data/lib/restman/payload/multipart/write_content_disposition.rb +88 -0
- data/lib/restman/payload/multipart.rb +56 -0
- data/lib/restman/payload/streamed.rb +22 -0
- data/lib/restman/payload/url_encoded.rb +14 -0
- data/lib/restman/payload.rb +14 -196
- data/lib/restman/platform.rb +2 -18
- data/lib/restman/raw_response.rb +2 -14
- data/lib/restman/request/default_ssl_cert_store.rb +13 -0
- data/lib/restman/request/fetch_body_to_tempfile.rb +58 -0
- data/lib/restman/request/init/cookie_jar.rb +65 -0
- data/lib/restman/request/init/ssl_opts.rb +70 -0
- data/lib/restman/request/init/url/add_query_from_headers.rb +51 -0
- data/lib/restman/request/init/url/normalize_url.rb +19 -0
- data/lib/restman/request/init/url.rb +40 -0
- data/lib/restman/request/init.rb +106 -0
- data/lib/restman/request/log_request.rb +46 -0
- data/lib/restman/request/make_cookie_header.rb +16 -0
- data/lib/restman/request/make_headers.rb +39 -0
- data/lib/restman/request/maybe_convert_extension.rb +28 -0
- data/lib/restman/request/net_http_object.rb +25 -0
- data/lib/restman/request/process_result.rb +36 -0
- data/lib/restman/request/proxy_uri.rb +31 -0
- data/lib/restman/request/stringify_headers.rb +36 -0
- data/lib/restman/request/transmit.rb +152 -0
- data/lib/restman/request.rb +60 -745
- data/lib/restman/resource.rb +2 -60
- data/lib/restman/response.rb +3 -21
- data/lib/restman/statuses.rb +75 -0
- data/lib/restman/statuses_compatibility.rb +18 -0
- data/lib/restman/utils.rb +10 -206
- data/lib/restman/version.rb +1 -1
- data/lib/restman.rb +24 -62
- data/matrixeval.yml +19 -1
- data/rest-man.gemspec +4 -10
- data/spec/integration/capath_digicert/ce5e74ef.0 +1 -1
- data/spec/integration/request_spec.rb +13 -1
- data/spec/spec_helper.rb +11 -0
- data/spec/unit/abstract_response_spec.rb +14 -0
- data/spec/unit/exception_spec.rb +64 -0
- data/spec/unit/exceptions/backwards_campatibility_spec.rb +29 -0
- data/spec/unit/exceptions/exceptions_map_spec.rb +89 -0
- data/spec/unit/exceptions/request_failed_spec.rb +51 -0
- data/spec/unit/exceptions/server_broke_connection_spec.rb +8 -0
- data/spec/unit/exceptions/timeout_spec.rb +59 -0
- data/spec/unit/params_array/process_pair_spec.rb +59 -0
- data/spec/unit/params_array_spec.rb +15 -10
- data/spec/unit/payload/multipart_spec.rb +116 -0
- data/spec/unit/payload/streamed_spec.rb +48 -0
- data/spec/unit/payload/url_encoded_spec.rb +65 -0
- data/spec/unit/payload_spec.rb +0 -208
- data/spec/unit/request/init/url/add_query_from_headers_spec.rb +40 -0
- data/spec/unit/request/init/url/normalize_url_spec.rb +25 -0
- data/spec/unit/request/init_spec.rb +83 -0
- data/spec/unit/request_spec.rb +143 -151
- data/spec/unit/utils_spec.rb +96 -104
- metadata +132 -16
- data/lib/restman/exceptions.rb +0 -238
- data/lib/restman/windows/root_certs.rb +0 -105
- data/lib/restman/windows.rb +0 -8
- data/spec/unit/exceptions_spec.rb +0 -108
- data/spec/unit/windows/root_certs_spec.rb +0 -22
data/lib/restman/payload.rb
CHANGED
@@ -1,13 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'securerandom'
|
3
|
-
require 'stringio'
|
4
|
-
|
5
|
-
begin
|
6
|
-
# Use mime/types/columnar if available, for reduced memory usage
|
7
|
-
require 'mime/types/columnar'
|
8
|
-
rescue LoadError
|
9
|
-
require 'mime/types'
|
10
|
-
end
|
1
|
+
require 'mime/types/columnar'
|
11
2
|
|
12
3
|
module RestMan
|
13
4
|
module Payload
|
@@ -15,220 +6,47 @@ module RestMan
|
|
15
6
|
|
16
7
|
def generate(params)
|
17
8
|
if params.is_a?(RestMan::Payload::Base)
|
18
|
-
# pass through Payload objects unchanged
|
19
9
|
params
|
10
|
+
|
20
11
|
elsif params.is_a?(String)
|
21
12
|
Base.new(params)
|
13
|
+
|
22
14
|
elsif params.is_a?(Hash)
|
23
15
|
if params.delete(:multipart) == true || has_file?(params)
|
24
16
|
Multipart.new(params)
|
17
|
+
|
25
18
|
else
|
26
19
|
UrlEncoded.new(params)
|
27
20
|
end
|
21
|
+
|
28
22
|
elsif params.is_a?(ParamsArray)
|
29
|
-
if
|
23
|
+
if has_file?(params)
|
30
24
|
Multipart.new(params)
|
25
|
+
|
31
26
|
else
|
32
27
|
UrlEncoded.new(params)
|
28
|
+
|
33
29
|
end
|
34
30
|
elsif params.respond_to?(:read)
|
35
31
|
Streamed.new(params)
|
32
|
+
|
36
33
|
else
|
37
34
|
nil
|
38
35
|
end
|
39
36
|
end
|
40
37
|
|
41
|
-
def has_file?(
|
42
|
-
unless params.is_a?(Hash)
|
43
|
-
raise ArgumentError.new("Must pass Hash, not #{params.inspect}")
|
44
|
-
end
|
45
|
-
_has_file?(params)
|
46
|
-
end
|
47
|
-
|
48
|
-
def _has_file?(obj)
|
38
|
+
def has_file?(obj)
|
49
39
|
case obj
|
50
40
|
when Hash, ParamsArray
|
51
|
-
obj.any? {|_, v|
|
41
|
+
obj.any? {|_, v| has_file?(v) }
|
42
|
+
|
52
43
|
when Array
|
53
|
-
obj.any? {|v|
|
44
|
+
obj.any? {|v| has_file?(v) }
|
45
|
+
|
54
46
|
else
|
55
47
|
obj.respond_to?(:path) && obj.respond_to?(:read)
|
56
48
|
end
|
57
49
|
end
|
58
50
|
|
59
|
-
class Base
|
60
|
-
def initialize(params)
|
61
|
-
build_stream(params)
|
62
|
-
end
|
63
|
-
|
64
|
-
def build_stream(params)
|
65
|
-
@stream = StringIO.new(params)
|
66
|
-
@stream.seek(0)
|
67
|
-
end
|
68
|
-
|
69
|
-
def read(*args)
|
70
|
-
@stream.read(*args)
|
71
|
-
end
|
72
|
-
|
73
|
-
def to_s
|
74
|
-
result = read
|
75
|
-
@stream.seek(0)
|
76
|
-
result
|
77
|
-
end
|
78
|
-
|
79
|
-
def headers
|
80
|
-
{'Content-Length' => size.to_s}
|
81
|
-
end
|
82
|
-
|
83
|
-
def size
|
84
|
-
@stream.size
|
85
|
-
end
|
86
|
-
|
87
|
-
alias :length :size
|
88
|
-
|
89
|
-
def close
|
90
|
-
@stream.close unless @stream.closed?
|
91
|
-
end
|
92
|
-
|
93
|
-
def closed?
|
94
|
-
@stream.closed?
|
95
|
-
end
|
96
|
-
|
97
|
-
def to_s_inspect
|
98
|
-
to_s.inspect
|
99
|
-
end
|
100
|
-
|
101
|
-
def short_inspect
|
102
|
-
if size && size > 500
|
103
|
-
"#{size} byte(s) length"
|
104
|
-
else
|
105
|
-
to_s_inspect
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
class Streamed < Base
|
112
|
-
def build_stream(params = nil)
|
113
|
-
@stream = params
|
114
|
-
end
|
115
|
-
|
116
|
-
def size
|
117
|
-
if @stream.respond_to?(:size)
|
118
|
-
@stream.size
|
119
|
-
elsif @stream.is_a?(IO)
|
120
|
-
@stream.stat.size
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
# TODO (breaks compatibility): ought to use mime_for() to autodetect the
|
125
|
-
# Content-Type for stream objects that have a filename.
|
126
|
-
|
127
|
-
alias :length :size
|
128
|
-
end
|
129
|
-
|
130
|
-
class UrlEncoded < Base
|
131
|
-
def build_stream(params = nil)
|
132
|
-
@stream = StringIO.new(Utils.encode_query_string(params))
|
133
|
-
@stream.seek(0)
|
134
|
-
end
|
135
|
-
|
136
|
-
def headers
|
137
|
-
super.merge({'Content-Type' => 'application/x-www-form-urlencoded'})
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
class Multipart < Base
|
142
|
-
EOL = "\r\n"
|
143
|
-
|
144
|
-
def build_stream(params)
|
145
|
-
b = '--' + boundary
|
146
|
-
|
147
|
-
@stream = Tempfile.new('rest-man.multipart.')
|
148
|
-
@stream.binmode
|
149
|
-
@stream.write(b + EOL)
|
150
|
-
|
151
|
-
case params
|
152
|
-
when Hash, ParamsArray
|
153
|
-
x = Utils.flatten_params(params)
|
154
|
-
else
|
155
|
-
x = params
|
156
|
-
end
|
157
|
-
|
158
|
-
last_index = x.length - 1
|
159
|
-
x.each_with_index do |a, index|
|
160
|
-
k, v = * a
|
161
|
-
if v.respond_to?(:read) && v.respond_to?(:path)
|
162
|
-
create_file_field(@stream, k, v)
|
163
|
-
else
|
164
|
-
create_regular_field(@stream, k, v)
|
165
|
-
end
|
166
|
-
@stream.write(EOL + b)
|
167
|
-
@stream.write(EOL) unless last_index == index
|
168
|
-
end
|
169
|
-
@stream.write('--')
|
170
|
-
@stream.write(EOL)
|
171
|
-
@stream.seek(0)
|
172
|
-
end
|
173
|
-
|
174
|
-
def create_regular_field(s, k, v)
|
175
|
-
s.write("Content-Disposition: form-data; name=\"#{k}\"")
|
176
|
-
s.write(EOL)
|
177
|
-
s.write(EOL)
|
178
|
-
s.write(v)
|
179
|
-
end
|
180
|
-
|
181
|
-
def create_file_field(s, k, v)
|
182
|
-
begin
|
183
|
-
s.write("Content-Disposition: form-data;")
|
184
|
-
s.write(" name=\"#{k}\";") unless (k.nil? || k=='')
|
185
|
-
s.write(" filename=\"#{v.respond_to?(:original_filename) ? v.original_filename : File.basename(v.path)}\"#{EOL}")
|
186
|
-
s.write("Content-Type: #{v.respond_to?(:content_type) ? v.content_type : mime_for(v.path)}#{EOL}")
|
187
|
-
s.write(EOL)
|
188
|
-
while (data = v.read(8124))
|
189
|
-
s.write(data)
|
190
|
-
end
|
191
|
-
ensure
|
192
|
-
v.close if v.respond_to?(:close)
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
def mime_for(path)
|
197
|
-
mime = MIME::Types.type_for path
|
198
|
-
mime.empty? ? 'text/plain' : mime[0].content_type
|
199
|
-
end
|
200
|
-
|
201
|
-
def boundary
|
202
|
-
return @boundary if defined?(@boundary) && @boundary
|
203
|
-
|
204
|
-
# Use the same algorithm used by WebKit: generate 16 random
|
205
|
-
# alphanumeric characters, replacing `+` `/` with `A` `B` (included in
|
206
|
-
# the list twice) to round out the set of 64.
|
207
|
-
s = SecureRandom.base64(12)
|
208
|
-
s.tr!('+/', 'AB')
|
209
|
-
|
210
|
-
@boundary = '----RubyFormBoundary' + s
|
211
|
-
end
|
212
|
-
|
213
|
-
# for Multipart do not escape the keys
|
214
|
-
#
|
215
|
-
# Ostensibly multipart keys MAY be percent encoded per RFC 7578, but in
|
216
|
-
# practice no major browser that I'm aware of uses percent encoding.
|
217
|
-
#
|
218
|
-
# Further discussion of multipart encoding:
|
219
|
-
# https://github.com/rest-man/rest-man/pull/403#issuecomment-156976930
|
220
|
-
#
|
221
|
-
def handle_key key
|
222
|
-
key
|
223
|
-
end
|
224
|
-
|
225
|
-
def headers
|
226
|
-
super.merge({'Content-Type' => %Q{multipart/form-data; boundary=#{boundary}}})
|
227
|
-
end
|
228
|
-
|
229
|
-
def close
|
230
|
-
@stream.close!
|
231
|
-
end
|
232
|
-
end
|
233
51
|
end
|
234
52
|
end
|
data/lib/restman/platform.rb
CHANGED
@@ -2,28 +2,12 @@ require 'rbconfig'
|
|
2
2
|
|
3
3
|
module RestMan
|
4
4
|
module Platform
|
5
|
-
#
|
6
|
-
# be false for jruby even on OS X.
|
7
|
-
#
|
8
|
-
# @return [Boolean]
|
5
|
+
# :include: _doc/lib/restman/platform/mac_mri?.rdoc
|
9
6
|
def self.mac_mri?
|
10
7
|
RUBY_PLATFORM.include?('darwin')
|
11
8
|
end
|
12
9
|
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# @return [Boolean]
|
16
|
-
#
|
17
|
-
def self.windows?
|
18
|
-
# Ruby only sets File::ALT_SEPARATOR on Windows, and the Ruby standard
|
19
|
-
# library uses that to test what platform it's on.
|
20
|
-
!!File::ALT_SEPARATOR
|
21
|
-
end
|
22
|
-
|
23
|
-
# Return true if we are running on jruby.
|
24
|
-
#
|
25
|
-
# @return [Boolean]
|
26
|
-
#
|
10
|
+
# :include: _doc/lib/restman/platform/jruby?.rdoc
|
27
11
|
def self.jruby?
|
28
12
|
# defined on mri >= 1.9
|
29
13
|
RUBY_ENGINE == 'jruby'
|
data/lib/restman/raw_response.rb
CHANGED
@@ -1,14 +1,5 @@
|
|
1
1
|
module RestMan
|
2
|
-
#
|
3
|
-
# actually one of these. 99% of the time you're making a rest call all you
|
4
|
-
# care about is the body, but on the occasion you want to fetch the
|
5
|
-
# headers you can:
|
6
|
-
#
|
7
|
-
# RestMan.get('http://example.com').headers[:content_type]
|
8
|
-
#
|
9
|
-
# In addition, if you do not use the response as a string, you can access
|
10
|
-
# a Tempfile object at res.file, which contains the path to the raw
|
11
|
-
# downloaded request body.
|
2
|
+
# :include: _doc/lib/restman/raw_response.rdoc
|
12
3
|
class RawResponse
|
13
4
|
|
14
5
|
include AbstractResponse
|
@@ -19,10 +10,7 @@ module RestMan
|
|
19
10
|
"<RestMan::RawResponse @code=#{code.inspect}, @file=#{file.inspect}, @request=#{request.inspect}>"
|
20
11
|
end
|
21
12
|
|
22
|
-
#
|
23
|
-
# @param [Net::HTTPResponse] net_http_res
|
24
|
-
# @param [RestMan::Request] request
|
25
|
-
# @param [Time] start_time
|
13
|
+
# :include: _doc/lib/restman/raw_response/new.rdoc
|
26
14
|
def initialize(tempfile, net_http_res, request, start_time=nil)
|
27
15
|
@file = tempfile
|
28
16
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module RestMan
|
2
|
+
class Request
|
3
|
+
class FetchBodyToTempfile < ActiveMethod::Base
|
4
|
+
|
5
|
+
argument :http_response
|
6
|
+
|
7
|
+
def call
|
8
|
+
# Taken from Chef, which as in turn...
|
9
|
+
# Stolen from http://www.ruby-forum.com/topic/166423
|
10
|
+
# Kudos to _why!
|
11
|
+
tf = Tempfile.new('rest-man.')
|
12
|
+
tf.binmode
|
13
|
+
|
14
|
+
size = 0
|
15
|
+
total = http_response['Content-Length'].to_i
|
16
|
+
stream_log_bucket = nil
|
17
|
+
|
18
|
+
http_response.read_body do |chunk|
|
19
|
+
tf.write chunk
|
20
|
+
size += chunk.size
|
21
|
+
if log
|
22
|
+
if total == 0
|
23
|
+
log << "streaming %s %s (%d of unknown) [0 Content-Length]\n" % [method.upcase, url, size]
|
24
|
+
else
|
25
|
+
percent = (size * 100) / total
|
26
|
+
current_log_bucket, _ = percent.divmod(stream_log_percent)
|
27
|
+
if current_log_bucket != stream_log_bucket
|
28
|
+
stream_log_bucket = current_log_bucket
|
29
|
+
log << "streaming %s %s %d%% done (%d of %d)\n" % [method.upcase, url, (size * 100) / total, size, total]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
tf.close
|
35
|
+
tf
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def log
|
41
|
+
request.log
|
42
|
+
end
|
43
|
+
|
44
|
+
def method
|
45
|
+
request.method
|
46
|
+
end
|
47
|
+
|
48
|
+
def url
|
49
|
+
request.url
|
50
|
+
end
|
51
|
+
|
52
|
+
def stream_log_percent
|
53
|
+
request.stream_log_percent
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module RestMan
|
2
|
+
class Request
|
3
|
+
module Init
|
4
|
+
# :include: _doc/lib/restman/request/init/cookie_jar.rdoc
|
5
|
+
class CookieJar < ActiveMethod::Base
|
6
|
+
|
7
|
+
argument :uri
|
8
|
+
argument :headers
|
9
|
+
argument :args
|
10
|
+
|
11
|
+
def call
|
12
|
+
duplicated_cookies_check
|
13
|
+
return cookies.dup if cookies.is_a?(HTTP::CookieJar)
|
14
|
+
|
15
|
+
cookies.each do |key, value|
|
16
|
+
cookie_jar.add cookie(key, value)
|
17
|
+
end
|
18
|
+
|
19
|
+
cookie_jar
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Avoid ambiguity in whether options from headers or options from
|
25
|
+
# Request#initialize should take precedence by raising ArgumentError when
|
26
|
+
# both are present. Prior versions of rest-man claimed to give
|
27
|
+
# precedence to init options, but actually gave precedence to headers.
|
28
|
+
# Avoid that mess by erroring out instead.
|
29
|
+
def duplicated_cookies_check
|
30
|
+
if headers[:cookies] && args[:cookies]
|
31
|
+
raise ArgumentError.new(
|
32
|
+
"Cannot pass :cookies in Request.new() and in headers hash at the same time")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def cookies
|
37
|
+
@cookies ||= headers.delete(:cookies) || args[:cookies] || []
|
38
|
+
end
|
39
|
+
|
40
|
+
# Support for Array<HTTP::Cookie> mode:
|
41
|
+
# If key is a cookie object, add it to the jar directly and assert that
|
42
|
+
# there is no separate val.
|
43
|
+
def cookie(key, value)
|
44
|
+
if key.is_a?(HTTP::Cookie)
|
45
|
+
raise ArgumentError.new("extra cookie val: #{value.inspect}") if value
|
46
|
+
|
47
|
+
key # cookie
|
48
|
+
else
|
49
|
+
HTTP::Cookie.new(
|
50
|
+
key.to_s, value,
|
51
|
+
domain: uri.hostname.downcase,
|
52
|
+
path: '/',
|
53
|
+
for_domain: true
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def cookie_jar
|
59
|
+
@cookie_jar ||= HTTP::CookieJar.new
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module RestMan
|
2
|
+
class Request
|
3
|
+
module Init
|
4
|
+
class SSLOpts < ActiveMethod::Base
|
5
|
+
|
6
|
+
argument :args
|
7
|
+
argument :uri
|
8
|
+
|
9
|
+
def call
|
10
|
+
ssl_opts[:verify_ssl] = verify_ssl
|
11
|
+
|
12
|
+
Request::SSLOptionList.each do |key|
|
13
|
+
ssl_key = ('ssl_' + key).to_sym
|
14
|
+
|
15
|
+
if args.key?(ssl_key)
|
16
|
+
ssl_opts[key.to_sym] = args.fetch(ssl_key)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
set_cert_store
|
21
|
+
|
22
|
+
ssl_opts
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def verify_ssl
|
28
|
+
return default_ssl_verify unless args.key?(:verify_ssl)
|
29
|
+
return ssl_verify_none unless args[:verify_ssl]
|
30
|
+
|
31
|
+
if args[:verify_ssl] == true
|
32
|
+
default_ssl_verify
|
33
|
+
else
|
34
|
+
args[:verify_ssl]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def default_ssl_verify
|
39
|
+
ssl_verify_peer
|
40
|
+
end
|
41
|
+
|
42
|
+
def ssl_verify_peer
|
43
|
+
OpenSSL::SSL::VERIFY_PEER
|
44
|
+
end
|
45
|
+
|
46
|
+
def ssl_verify_none
|
47
|
+
OpenSSL::SSL::VERIFY_NONE
|
48
|
+
end
|
49
|
+
|
50
|
+
def set_cert_store
|
51
|
+
return unless use_ssl?
|
52
|
+
|
53
|
+
# If there's no CA file, CA path, or cert store provided, use default
|
54
|
+
if !ssl_opts[:ca_file] && !ssl_opts[:ca_path] && !ssl_opts.include?(:cert_store)
|
55
|
+
ssl_opts[:cert_store] = Request.default_ssl_cert_store
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def use_ssl?
|
60
|
+
uri.is_a?(URI::HTTPS)
|
61
|
+
end
|
62
|
+
|
63
|
+
def ssl_opts
|
64
|
+
@ssl_opts ||= {}
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module RestMan
|
2
|
+
class Request
|
3
|
+
module Init
|
4
|
+
class Url
|
5
|
+
class AddQueryFromHeaders < ActiveMethod::Base
|
6
|
+
|
7
|
+
argument :url
|
8
|
+
argument :headers
|
9
|
+
|
10
|
+
def call
|
11
|
+
url_params = params_from_headers
|
12
|
+
|
13
|
+
if url_params && !url_params.empty?
|
14
|
+
query_string = RestMan::Utils.encode_query_string(url_params)
|
15
|
+
|
16
|
+
if url.include?('?')
|
17
|
+
url + "&#{query_string}"
|
18
|
+
else
|
19
|
+
url + "?#{query_string}"
|
20
|
+
end
|
21
|
+
else
|
22
|
+
url
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def params_from_headers
|
29
|
+
params = nil
|
30
|
+
|
31
|
+
# find and extract/remove "params" key if the value is a Hash/ParamsArray
|
32
|
+
headers.delete_if do |key, value|
|
33
|
+
if key.to_s.downcase == 'params' && (value.is_a?(Hash) || value.is_a?(RestMan::ParamsArray))
|
34
|
+
if params
|
35
|
+
raise ArgumentError.new("Multiple 'params' options passed")
|
36
|
+
end
|
37
|
+
params = value
|
38
|
+
true
|
39
|
+
else
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
params
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RestMan
|
2
|
+
class Request
|
3
|
+
module Init
|
4
|
+
class Url
|
5
|
+
class NormalizeUrl < ActiveMethod::Base
|
6
|
+
argument :url
|
7
|
+
|
8
|
+
def call
|
9
|
+
if url.match(%r{\A[a-z][a-z0-9+.-]*://}i)
|
10
|
+
url
|
11
|
+
else
|
12
|
+
"http://#{url}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module RestMan
|
2
|
+
class Request
|
3
|
+
module Init
|
4
|
+
class Url < ActiveMethod::Base
|
5
|
+
|
6
|
+
autoload :AddQueryFromHeaders, "restman/request/init/url/add_query_from_headers"
|
7
|
+
autoload :NormalizeUrl, "restman/request/init/url/normalize_url"
|
8
|
+
|
9
|
+
argument :args
|
10
|
+
argument :headers
|
11
|
+
|
12
|
+
attr_accessor :url
|
13
|
+
|
14
|
+
def call
|
15
|
+
raise ArgumentError, "must pass :url" unless url
|
16
|
+
|
17
|
+
add_http_scheme
|
18
|
+
add_query_from_headers
|
19
|
+
|
20
|
+
url
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def add_http_scheme
|
26
|
+
self.url = NormalizeUrl.call(url)
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_query_from_headers
|
30
|
+
self.url = AddQueryFromHeaders.call(url, headers)
|
31
|
+
end
|
32
|
+
|
33
|
+
def url
|
34
|
+
@url ||= args[:url].dup
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|