httparty 0.16.2 → 0.16.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of httparty might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.editorconfig +18 -0
- data/.gitignore +1 -0
- data/Changelog.md +11 -0
- data/README.md +1 -1
- data/examples/README.md +22 -11
- data/examples/body_stream.rb +14 -0
- data/examples/microsoft_graph.rb +52 -0
- data/examples/multipart.rb +22 -0
- data/features/steps/mongrel_helper.rb +3 -3
- data/httparty.gemspec +2 -1
- data/lib/httparty.rb +21 -1
- data/lib/httparty/connection_adapter.rb +11 -4
- data/lib/httparty/hash_conversions.rb +6 -2
- data/lib/httparty/logger/apache_formatter.rb +29 -6
- data/lib/httparty/logger/curl_formatter.rb +4 -4
- data/lib/httparty/logger/logger.rb +3 -1
- data/lib/httparty/logger/logstash_formatter.rb +59 -0
- data/lib/httparty/module_inheritable_attributes.rb +3 -3
- data/lib/httparty/net_digest_auth.rb +6 -5
- data/lib/httparty/request.rb +8 -1
- data/lib/httparty/request/body.rb +16 -5
- data/lib/httparty/response.rb +19 -5
- data/lib/httparty/response/headers.rb +2 -2
- data/lib/httparty/utils.rb +11 -0
- data/lib/httparty/version.rb +1 -1
- data/spec/httparty/connection_adapter_spec.rb +7 -3
- data/spec/httparty/cookie_hash_spec.rb +1 -1
- data/spec/httparty/exception_spec.rb +1 -1
- data/spec/httparty/hash_conversions_spec.rb +2 -0
- data/spec/httparty/logger/apache_formatter_spec.rb +1 -2
- data/spec/httparty/logger/curl_formatter_spec.rb +1 -1
- data/spec/httparty/logger/logger_spec.rb +6 -1
- data/spec/httparty/logger/logstash_formatter_spec.rb +44 -0
- data/spec/httparty/net_digest_auth_spec.rb +22 -22
- data/spec/httparty/parser_spec.rb +1 -1
- data/spec/httparty/request/body_spec.rb +57 -8
- data/spec/httparty/request_spec.rb +68 -13
- data/spec/httparty/response_spec.rb +32 -20
- data/spec/httparty/ssl_spec.rb +1 -1
- data/spec/httparty_spec.rb +28 -7
- data/website/css/common.css +1 -1
- metadata +25 -3
@@ -20,7 +20,7 @@ module HTTParty
|
|
20
20
|
log_request
|
21
21
|
log_response
|
22
22
|
|
23
|
-
logger.
|
23
|
+
logger.public_send level, messages.join("\n")
|
24
24
|
end
|
25
25
|
|
26
26
|
private
|
@@ -80,11 +80,11 @@ module HTTParty
|
|
80
80
|
end
|
81
81
|
|
82
82
|
def log(direction, line = '')
|
83
|
-
messages << "[#{TAG_NAME}] [#{
|
83
|
+
messages << "[#{TAG_NAME}] [#{current_time}] #{direction} #{line}"
|
84
84
|
end
|
85
85
|
|
86
|
-
def
|
87
|
-
|
86
|
+
def current_time
|
87
|
+
Time.now.strftime("%Y-%m-%d %H:%M:%S %z")
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'httparty/logger/apache_formatter'
|
2
2
|
require 'httparty/logger/curl_formatter'
|
3
|
+
require 'httparty/logger/logstash_formatter'
|
3
4
|
|
4
5
|
module HTTParty
|
5
6
|
module Logger
|
6
7
|
def self.formatters
|
7
8
|
@formatters ||= {
|
8
9
|
:curl => Logger::CurlFormatter,
|
9
|
-
:apache => Logger::ApacheFormatter
|
10
|
+
:apache => Logger::ApacheFormatter,
|
11
|
+
:logstash => Logger::LogstashFormatter,
|
10
12
|
}
|
11
13
|
end
|
12
14
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module HTTParty
|
2
|
+
module Logger
|
3
|
+
class LogstashFormatter #:nodoc:
|
4
|
+
TAG_NAME = HTTParty.name
|
5
|
+
|
6
|
+
attr_accessor :level, :logger
|
7
|
+
|
8
|
+
def initialize(logger, level)
|
9
|
+
@logger = logger
|
10
|
+
@level = level.to_sym
|
11
|
+
end
|
12
|
+
|
13
|
+
def format(request, response)
|
14
|
+
@request = request
|
15
|
+
@response = response
|
16
|
+
|
17
|
+
logger.public_send level, logstash_message
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :request, :response
|
23
|
+
|
24
|
+
def logstash_message
|
25
|
+
{
|
26
|
+
'@timestamp' => current_time,
|
27
|
+
'@version' => 1,
|
28
|
+
'content_length' => content_length || '-',
|
29
|
+
'http_method' => http_method,
|
30
|
+
'message' => message,
|
31
|
+
'path' => path,
|
32
|
+
'response_code' => response.code,
|
33
|
+
'severity' => level,
|
34
|
+
'tags' => [TAG_NAME],
|
35
|
+
}.to_json
|
36
|
+
end
|
37
|
+
|
38
|
+
def message
|
39
|
+
"[#{TAG_NAME}] #{response.code} \"#{http_method} #{path}\" #{content_length || '-'} "
|
40
|
+
end
|
41
|
+
|
42
|
+
def current_time
|
43
|
+
Time.now.strftime("%Y-%m-%d %H:%M:%S %z")
|
44
|
+
end
|
45
|
+
|
46
|
+
def http_method
|
47
|
+
@http_method ||= request.http_method.name.split("::").last.upcase
|
48
|
+
end
|
49
|
+
|
50
|
+
def path
|
51
|
+
@path ||= request.path.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def content_length
|
55
|
+
@content_length ||= response.respond_to?(:headers) ? response.headers['Content-Length'] : response['Content-Length']
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -9,12 +9,12 @@ module HTTParty
|
|
9
9
|
duplicate = hash.dup
|
10
10
|
|
11
11
|
duplicate.each_pair do |key, value|
|
12
|
-
|
13
|
-
|
12
|
+
if value.is_a?(Hash)
|
13
|
+
duplicate[key] = hash_deep_dup(value)
|
14
14
|
elsif value.is_a?(Proc)
|
15
15
|
duplicate[key] = value.dup
|
16
16
|
else
|
17
|
-
value
|
17
|
+
duplicate[key] = value
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -14,11 +14,11 @@ module Net
|
|
14
14
|
|
15
15
|
authenticator.authorization_header.each do |v|
|
16
16
|
add_field('Authorization', v)
|
17
|
-
end
|
17
|
+
end
|
18
18
|
|
19
19
|
authenticator.cookie_header.each do |v|
|
20
20
|
add_field('Cookie', v)
|
21
|
-
end
|
21
|
+
end
|
22
22
|
end
|
23
23
|
|
24
24
|
class DigestAuthenticator
|
@@ -64,7 +64,8 @@ module Net
|
|
64
64
|
|
65
65
|
def parse(response_header)
|
66
66
|
header = response_header['www-authenticate']
|
67
|
-
|
67
|
+
|
68
|
+
header = header.gsub(/qop=(auth(?:-int)?)/, 'qop="\\1"')
|
68
69
|
|
69
70
|
header =~ /Digest (.*)/
|
70
71
|
params = {}
|
@@ -113,11 +114,11 @@ module Net
|
|
113
114
|
def algorithm_present?
|
114
115
|
@response.key?('algorithm') && !@response['algorithm'].empty?
|
115
116
|
end
|
116
|
-
|
117
|
+
|
117
118
|
def use_md5_sess?
|
118
119
|
algorithm_present? && @response['algorithm'] == 'MD5-sess'
|
119
120
|
end
|
120
|
-
|
121
|
+
|
121
122
|
def a1
|
122
123
|
a1_user_realm_pwd = [@username, @response['realm'], @password].join(':')
|
123
124
|
if use_md5_sess?
|
data/lib/httparty/request.rb
CHANGED
@@ -14,6 +14,8 @@ module HTTParty
|
|
14
14
|
Net::HTTP::Move,
|
15
15
|
Net::HTTP::Copy,
|
16
16
|
Net::HTTP::Mkcol,
|
17
|
+
Net::HTTP::Lock,
|
18
|
+
Net::HTTP::Unlock,
|
17
19
|
]
|
18
20
|
|
19
21
|
SupportedURISchemes = ['http', 'https', 'webcal', nil]
|
@@ -219,7 +221,12 @@ module HTTParty
|
|
219
221
|
end
|
220
222
|
|
221
223
|
if options[:body]
|
222
|
-
body = Body.new(
|
224
|
+
body = Body.new(
|
225
|
+
options[:body],
|
226
|
+
query_string_normalizer: query_string_normalizer,
|
227
|
+
force_multipart: options[:multipart]
|
228
|
+
)
|
229
|
+
|
223
230
|
if body.multipart?
|
224
231
|
content_type = "multipart/form-data; boundary=#{body.boundary}"
|
225
232
|
@raw_request['Content-Type'] = content_type
|
@@ -3,9 +3,10 @@ require_relative 'multipart_boundary'
|
|
3
3
|
module HTTParty
|
4
4
|
class Request
|
5
5
|
class Body
|
6
|
-
def initialize(params, query_string_normalizer: nil)
|
6
|
+
def initialize(params, query_string_normalizer: nil, force_multipart: false)
|
7
7
|
@params = params
|
8
8
|
@query_string_normalizer = query_string_normalizer
|
9
|
+
@force_multipart = force_multipart
|
9
10
|
end
|
10
11
|
|
11
12
|
def call
|
@@ -21,7 +22,7 @@ module HTTParty
|
|
21
22
|
end
|
22
23
|
|
23
24
|
def multipart?
|
24
|
-
params.respond_to?(:to_hash) && has_file?(params.to_hash)
|
25
|
+
params.respond_to?(:to_hash) && (force_multipart || has_file?(params.to_hash))
|
25
26
|
end
|
26
27
|
|
27
28
|
private
|
@@ -34,9 +35,9 @@ module HTTParty
|
|
34
35
|
memo += %(Content-Disposition: form-data; name="#{key}")
|
35
36
|
# value.path is used to support ActionDispatch::Http::UploadedFile
|
36
37
|
# https://github.com/jnunemaker/httparty/pull/585
|
37
|
-
memo += %(; filename="#{
|
38
|
+
memo += %(; filename="#{file_name(value)}") if file?(value)
|
38
39
|
memo += "\r\n"
|
39
|
-
memo += "Content-Type:
|
40
|
+
memo += "Content-Type: #{content_type(value)}\r\n" if file?(value)
|
40
41
|
memo += "\r\n"
|
41
42
|
memo += file?(value) ? value.read : value.to_s
|
42
43
|
memo += "\r\n"
|
@@ -73,7 +74,17 @@ module HTTParty
|
|
73
74
|
end
|
74
75
|
end
|
75
76
|
|
76
|
-
|
77
|
+
def content_type(object)
|
78
|
+
return object.content_type if object.respond_to?(:content_type)
|
79
|
+
mime = MIME::Types.type_for(object.path)
|
80
|
+
mime.empty? ? 'application/octet-stream' : mime[0].content_type
|
81
|
+
end
|
82
|
+
|
83
|
+
def file_name(object)
|
84
|
+
object.respond_to?(:original_filename) ? object.original_filename : File.basename(object.path)
|
85
|
+
end
|
86
|
+
|
87
|
+
attr_reader :params, :query_string_normalizer, :force_multipart
|
77
88
|
end
|
78
89
|
end
|
79
90
|
end
|
data/lib/httparty/response.rb
CHANGED
@@ -4,6 +4,12 @@ module HTTParty
|
|
4
4
|
string.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z])([A-Z])/, '\1_\2').downcase
|
5
5
|
end
|
6
6
|
|
7
|
+
def self._load(data)
|
8
|
+
req, resp, parsed_resp, resp_body = Marshal.load(data)
|
9
|
+
|
10
|
+
new(req, resp, -> { parsed_resp }, body: resp_body)
|
11
|
+
end
|
12
|
+
|
7
13
|
attr_reader :request, :response, :body, :headers
|
8
14
|
|
9
15
|
def initialize(request, response, parsed_block, options = {})
|
@@ -14,7 +20,11 @@ module HTTParty
|
|
14
20
|
@headers = Headers.new(response.to_hash)
|
15
21
|
|
16
22
|
if request.options[:logger]
|
17
|
-
logger = ::HTTParty::Logger.build(
|
23
|
+
logger = ::HTTParty::Logger.build(
|
24
|
+
request.options[:logger],
|
25
|
+
request.options[:log_level],
|
26
|
+
request.options[:log_format]
|
27
|
+
)
|
18
28
|
logger.format(request, self)
|
19
29
|
end
|
20
30
|
|
@@ -59,10 +69,10 @@ module HTTParty
|
|
59
69
|
response.nil? || response.body.nil? || response.body.empty?
|
60
70
|
end
|
61
71
|
|
62
|
-
def to_s
|
72
|
+
def to_s
|
63
73
|
if !response.nil? && !response.body.nil? && response.body.respond_to?(:to_s)
|
64
74
|
response.body.to_s
|
65
|
-
else
|
75
|
+
else
|
66
76
|
inspect
|
67
77
|
end
|
68
78
|
end
|
@@ -80,7 +90,7 @@ module HTTParty
|
|
80
90
|
parsed_response.display(port)
|
81
91
|
elsif !response.nil? && !response.body.nil? && response.body.respond_to?(:display)
|
82
92
|
response.body.display(port)
|
83
|
-
else
|
93
|
+
else
|
84
94
|
port.write(inspect)
|
85
95
|
end
|
86
96
|
end
|
@@ -89,7 +99,11 @@ module HTTParty
|
|
89
99
|
return true if super
|
90
100
|
parsed_response.respond_to?(name) || response.respond_to?(name)
|
91
101
|
end
|
92
|
-
|
102
|
+
|
103
|
+
def _dump(_level)
|
104
|
+
Marshal.dump([request, response, parsed_response, body])
|
105
|
+
end
|
106
|
+
|
93
107
|
protected
|
94
108
|
|
95
109
|
def method_missing(name, *args, &block)
|
@@ -22,10 +22,10 @@ module HTTParty
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def ==(other)
|
25
|
-
if other.is_a?(::Net::HTTPHeader)
|
25
|
+
if other.is_a?(::Net::HTTPHeader)
|
26
26
|
@header == other.instance_variable_get(:@header)
|
27
27
|
elsif other.is_a?(Hash)
|
28
|
-
@header == other || @header == Headers.new(other).instance_variable_get(:@header)
|
28
|
+
@header == other || @header == Headers.new(other).instance_variable_get(:@header)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
data/lib/httparty/version.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe HTTParty::ConnectionAdapter do
|
4
4
|
describe "initialization" do
|
@@ -312,8 +312,12 @@ RSpec.describe HTTParty::ConnectionAdapter do
|
|
312
312
|
|
313
313
|
context 'as well as proxy user and password' do
|
314
314
|
let(:options) do
|
315
|
-
{
|
316
|
-
|
315
|
+
{
|
316
|
+
http_proxyaddr: '1.2.3.4',
|
317
|
+
http_proxyport: 8080,
|
318
|
+
http_proxyuser: 'user',
|
319
|
+
http_proxypass: 'pass'
|
320
|
+
}
|
317
321
|
end
|
318
322
|
|
319
323
|
describe '#proxy_user' do
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe HTTParty::Logger::ApacheFormatter do
|
4
4
|
let(:subject) { described_class.new(logger_double, :info) }
|
@@ -7,7 +7,6 @@ RSpec.describe HTTParty::Logger::ApacheFormatter do
|
|
7
7
|
let(:request_time) { Time.new.strftime("%Y-%m-%d %H:%M:%S %z") }
|
8
8
|
|
9
9
|
before do
|
10
|
-
subject.current_time = request_time
|
11
10
|
expect(logger_double).to receive(:info).with(log_message)
|
12
11
|
end
|
13
12
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe HTTParty::Logger do
|
4
4
|
describe ".build" do
|
@@ -19,6 +19,11 @@ RSpec.describe HTTParty::Logger do
|
|
19
19
|
expect(subject.build(logger_double, nil, :curl)).to be_an_instance_of(HTTParty::Logger::CurlFormatter)
|
20
20
|
end
|
21
21
|
|
22
|
+
it "builds :logstash style logger" do
|
23
|
+
logger_double = double
|
24
|
+
expect(subject.build(logger_double, nil, :logstash)).to be_an_instance_of(HTTParty::Logger::LogstashFormatter)
|
25
|
+
end
|
26
|
+
|
22
27
|
it "builds :custom style logger" do
|
23
28
|
CustomFormatter = Class.new(HTTParty::Logger::CurlFormatter)
|
24
29
|
HTTParty::Logger.add_formatter(:custom, CustomFormatter)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe HTTParty::Logger::LogstashFormatter do
|
4
|
+
let(:severity) { :info }
|
5
|
+
let(:http_method) { 'GET' }
|
6
|
+
let(:path) { 'http://my.domain.com/my_path' }
|
7
|
+
let(:logger_double) { double('Logger') }
|
8
|
+
let(:request_double) { double('Request', http_method: Net::HTTP::Get, path: "#{path}") }
|
9
|
+
let(:request_time) { Time.new.strftime("%Y-%m-%d %H:%M:%S %z") }
|
10
|
+
let(:log_message) do
|
11
|
+
{
|
12
|
+
'@timestamp' => request_time,
|
13
|
+
'@version' => 1,
|
14
|
+
'content_length' => content_length || '-',
|
15
|
+
'http_method' => http_method,
|
16
|
+
'message' => message,
|
17
|
+
'path' => path,
|
18
|
+
'response_code' => response_code,
|
19
|
+
'severity' => severity,
|
20
|
+
'tags' => ['HTTParty'],
|
21
|
+
}.to_json
|
22
|
+
end
|
23
|
+
|
24
|
+
subject { described_class.new(logger_double, severity) }
|
25
|
+
|
26
|
+
before do
|
27
|
+
expect(logger_double).to receive(:info).with(log_message)
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#format" do
|
31
|
+
let(:response_code) { 302 }
|
32
|
+
let(:content_length) { '-' }
|
33
|
+
let(:message) { "[HTTParty] #{response_code} \"#{http_method} #{path}\" #{content_length} " }
|
34
|
+
|
35
|
+
it "formats a response to be compatible with Logstash" do
|
36
|
+
response_double = double(
|
37
|
+
code: response_code,
|
38
|
+
:[] => nil
|
39
|
+
)
|
40
|
+
|
41
|
+
subject.format(request_double, response_double)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|