httparty 0.13.0 → 0.14.0

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.

Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +92 -0
  4. data/.rubocop_todo.yml +124 -0
  5. data/.simplecov +1 -0
  6. data/.travis.yml +4 -2
  7. data/CONTRIBUTING.md +23 -0
  8. data/Gemfile +8 -3
  9. data/Guardfile +3 -3
  10. data/History +106 -11
  11. data/README.md +19 -20
  12. data/Rakefile +5 -7
  13. data/bin/httparty +18 -14
  14. data/docs/README.md +100 -0
  15. data/examples/README.md +67 -0
  16. data/examples/aaws.rb +5 -5
  17. data/examples/basic.rb +6 -10
  18. data/examples/crack.rb +2 -2
  19. data/examples/custom_parsers.rb +1 -4
  20. data/examples/delicious.rb +8 -8
  21. data/examples/google.rb +2 -2
  22. data/examples/headers_and_user_agents.rb +1 -1
  23. data/examples/logging.rb +36 -0
  24. data/examples/nokogiri_html_parser.rb +0 -3
  25. data/examples/rescue_json.rb +17 -0
  26. data/examples/rubyurl.rb +3 -3
  27. data/examples/stackexchange.rb +24 -0
  28. data/examples/tripit_sign_in.rb +20 -9
  29. data/examples/twitter.rb +7 -7
  30. data/examples/whoismyrep.rb +1 -1
  31. data/features/command_line.feature +90 -2
  32. data/features/digest_authentication.feature +10 -0
  33. data/features/steps/env.rb +16 -11
  34. data/features/steps/httparty_response_steps.rb +18 -14
  35. data/features/steps/httparty_steps.rb +10 -2
  36. data/features/steps/mongrel_helper.rb +35 -2
  37. data/features/steps/remote_service_steps.rb +26 -8
  38. data/features/supports_read_timeout_option.feature +13 -0
  39. data/httparty.gemspec +6 -5
  40. data/lib/httparty/connection_adapter.rb +36 -13
  41. data/lib/httparty/cookie_hash.rb +3 -4
  42. data/lib/httparty/exceptions.rb +4 -1
  43. data/lib/httparty/hash_conversions.rb +17 -15
  44. data/lib/httparty/logger/{apache_logger.rb → apache_formatter.rb} +3 -3
  45. data/lib/httparty/logger/curl_formatter.rb +91 -0
  46. data/lib/httparty/logger/logger.rb +18 -10
  47. data/lib/httparty/module_inheritable_attributes.rb +1 -1
  48. data/lib/httparty/net_digest_auth.rb +69 -18
  49. data/lib/httparty/parser.rb +4 -2
  50. data/lib/httparty/request.rb +105 -48
  51. data/lib/httparty/response.rb +31 -6
  52. data/lib/httparty/version.rb +1 -1
  53. data/lib/httparty.rb +132 -72
  54. data/spec/httparty/connection_adapter_spec.rb +285 -88
  55. data/spec/httparty/cookie_hash_spec.rb +46 -29
  56. data/spec/httparty/exception_spec.rb +29 -7
  57. data/spec/httparty/hash_conversions_spec.rb +49 -0
  58. data/spec/httparty/logger/apache_formatter_spec.rb +41 -0
  59. data/spec/httparty/logger/curl_formatter_spec.rb +119 -0
  60. data/spec/httparty/logger/logger_spec.rb +23 -7
  61. data/spec/httparty/net_digest_auth_spec.rb +118 -30
  62. data/spec/httparty/parser_spec.rb +43 -35
  63. data/spec/httparty/request_spec.rb +734 -182
  64. data/spec/httparty/response_spec.rb +139 -69
  65. data/spec/httparty/ssl_spec.rb +22 -22
  66. data/spec/httparty_spec.rb +307 -199
  67. data/spec/spec_helper.rb +34 -12
  68. data/spec/support/ssl_test_helper.rb +6 -6
  69. data/spec/support/ssl_test_server.rb +21 -21
  70. data/spec/support/stub_response.rb +20 -14
  71. data/website/index.html +3 -3
  72. metadata +30 -33
  73. data/lib/httparty/core_extensions.rb +0 -32
  74. data/lib/httparty/logger/curl_logger.rb +0 -48
  75. data/spec/httparty/logger/apache_logger_spec.rb +0 -26
  76. data/spec/httparty/logger/curl_logger_spec.rb +0 -18
  77. data/spec/spec.opts +0 -2
@@ -1,6 +1,6 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
2
 
3
- describe HTTParty::CookieHash do
3
+ RSpec.describe HTTParty::CookieHash do
4
4
  before(:each) do
5
5
  @cookie_hash = HTTParty::CookieHash.new
6
6
  end
@@ -8,47 +8,47 @@ describe HTTParty::CookieHash do
8
8
  describe "#add_cookies" do
9
9
  describe "with a hash" do
10
10
  it "should add new key/value pairs to the hash" do
11
- @cookie_hash.add_cookies(:foo => "bar")
12
- @cookie_hash.add_cookies(:rofl => "copter")
13
- @cookie_hash.length.should eql(2)
11
+ @cookie_hash.add_cookies(foo: "bar")
12
+ @cookie_hash.add_cookies(rofl: "copter")
13
+ expect(@cookie_hash.length).to eql(2)
14
14
  end
15
15
 
16
16
  it "should overwrite any existing key" do
17
- @cookie_hash.add_cookies(:foo => "bar")
18
- @cookie_hash.add_cookies(:foo => "copter")
19
- @cookie_hash.length.should eql(1)
20
- @cookie_hash[:foo].should eql("copter")
17
+ @cookie_hash.add_cookies(foo: "bar")
18
+ @cookie_hash.add_cookies(foo: "copter")
19
+ expect(@cookie_hash.length).to eql(1)
20
+ expect(@cookie_hash[:foo]).to eql("copter")
21
21
  end
22
22
  end
23
23
 
24
24
  describe "with a string" do
25
25
  it "should add new key/value pairs to the hash" do
26
26
  @cookie_hash.add_cookies("first=one; second=two; third")
27
- @cookie_hash[:first].should == 'one'
28
- @cookie_hash[:second].should == 'two'
29
- @cookie_hash[:third].should == nil
27
+ expect(@cookie_hash[:first]).to eq('one')
28
+ expect(@cookie_hash[:second]).to eq('two')
29
+ expect(@cookie_hash[:third]).to eq(nil)
30
30
  end
31
31
 
32
32
  it "should overwrite any existing key" do
33
33
  @cookie_hash[:foo] = 'bar'
34
34
  @cookie_hash.add_cookies("foo=tar")
35
- @cookie_hash.length.should eql(1)
36
- @cookie_hash[:foo].should eql("tar")
35
+ expect(@cookie_hash.length).to eql(1)
36
+ expect(@cookie_hash[:foo]).to eql("tar")
37
37
  end
38
38
 
39
39
  it "should handle '=' within cookie value" do
40
- @cookie_hash.add_cookies("first=one=1; second=two=2==")
41
- @cookie_hash.keys.should include(:first, :second)
42
- @cookie_hash[:first].should == 'one=1'
43
- @cookie_hash[:second].should == 'two=2=='
40
+ @cookie_hash.add_cookies("first=one=1; second=two=2==")
41
+ expect(@cookie_hash.keys).to include(:first, :second)
42
+ expect(@cookie_hash[:first]).to eq('one=1')
43
+ expect(@cookie_hash[:second]).to eq('two=2==')
44
44
  end
45
45
  end
46
46
 
47
47
  describe 'with other class' do
48
48
  it "should error" do
49
- lambda {
50
- @cookie_hash.add_cookies(Array.new)
51
- }.should raise_error
49
+ expect {
50
+ @cookie_hash.add_cookies([])
51
+ }.to raise_error(RuntimeError)
52
52
  end
53
53
  end
54
54
  end
@@ -57,27 +57,44 @@ describe HTTParty::CookieHash do
57
57
  # a hardcoded string was randomly failing.
58
58
  describe "#to_cookie_string" do
59
59
  before(:each) do
60
- @cookie_hash.add_cookies(:foo => "bar")
61
- @cookie_hash.add_cookies(:rofl => "copter")
60
+ @cookie_hash.add_cookies(foo: "bar")
61
+ @cookie_hash.add_cookies(rofl: "copter")
62
62
  @s = @cookie_hash.to_cookie_string
63
63
  end
64
64
 
65
65
  it "should format the key/value pairs, delimited by semi-colons" do
66
- @s.should match(/foo=bar/)
67
- @s.should match(/rofl=copter/)
68
- @s.should match(/^\w+=\w+; \w+=\w+$/)
66
+ expect(@s).to match(/foo=bar/)
67
+ expect(@s).to match(/rofl=copter/)
68
+ expect(@s).to match(/^\w+=\w+; \w+=\w+$/)
69
69
  end
70
70
 
71
71
  it "should not include client side only cookies" do
72
- @cookie_hash.add_cookies(:path => "/")
72
+ @cookie_hash.add_cookies(path: "/")
73
73
  @s = @cookie_hash.to_cookie_string
74
- @s.should_not match(/path=\//)
74
+ expect(@s).not_to match(/path=\//)
75
75
  end
76
76
 
77
77
  it "should not include client side only cookies even when attributes use camal case" do
78
- @cookie_hash.add_cookies(:Path => "/")
78
+ @cookie_hash.add_cookies(Path: "/")
79
79
  @s = @cookie_hash.to_cookie_string
80
- @s.should_not match(/Path=\//)
80
+ expect(@s).not_to match(/Path=\//)
81
+ end
82
+
83
+ it "should not mutate the hash" do
84
+ original_hash = {
85
+ "session" => "91e25e8b-6e32-418d-c72f-2d18adf041cd",
86
+ "Max-Age" => "15552000",
87
+ "cart" => "91e25e8b-6e32-418d-c72f-2d18adf041cd",
88
+ "httponly" => nil,
89
+ "Path" => "/",
90
+ "secure" => nil,
91
+ }
92
+
93
+ cookie_hash = HTTParty::CookieHash[original_hash]
94
+
95
+ cookie_hash.to_cookie_string
96
+
97
+ expect(cookie_hash).to eq(original_hash)
81
98
  end
82
99
  end
83
100
  end
@@ -1,23 +1,45 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
2
 
3
- describe HTTParty::Error do
3
+ RSpec.describe HTTParty::Error do
4
4
  subject { described_class }
5
5
 
6
- its(:ancestors) { should include(StandardError) }
6
+ describe '#ancestors' do
7
+ subject { super().ancestors }
8
+ it { is_expected.to include(StandardError) }
9
+ end
7
10
 
8
11
  describe HTTParty::UnsupportedFormat do
9
- its(:ancestors) { should include(HTTParty::Error) }
12
+ describe '#ancestors' do
13
+ subject { super().ancestors }
14
+ it { is_expected.to include(HTTParty::Error) }
15
+ end
10
16
  end
11
-
17
+
12
18
  describe HTTParty::UnsupportedURIScheme do
13
- its(:ancestors) { should include(HTTParty::Error) }
19
+ describe '#ancestors' do
20
+ subject { super().ancestors }
21
+ it { is_expected.to include(HTTParty::Error) }
22
+ end
14
23
  end
15
24
 
16
25
  describe HTTParty::ResponseError do
17
- its(:ancestors) { should include(HTTParty::Error) }
26
+ describe '#ancestors' do
27
+ subject { super().ancestors }
28
+ it { is_expected.to include(HTTParty::Error) }
29
+ end
18
30
  end
19
31
 
20
32
  describe HTTParty::RedirectionTooDeep do
21
- its(:ancestors) { should include(HTTParty::ResponseError) }
33
+ describe '#ancestors' do
34
+ subject { super().ancestors }
35
+ it { is_expected.to include(HTTParty::ResponseError) }
36
+ end
37
+ end
38
+
39
+ describe HTTParty::DuplicateLocationHeader do
40
+ describe '#ancestors' do
41
+ subject { super().ancestors }
42
+ it { is_expected.to include(HTTParty::ResponseError) }
43
+ end
22
44
  end
23
45
  end
@@ -0,0 +1,49 @@
1
+ RSpec.describe HTTParty::HashConversions do
2
+ describe ".to_params" do
3
+ it "creates a params string from a hash" do
4
+ hash = {
5
+ name: "bob",
6
+ address: {
7
+ street: '111 ruby ave.',
8
+ city: 'ruby central',
9
+ phones: ['111-111-1111', '222-222-2222']
10
+ }
11
+ }
12
+ expect(HTTParty::HashConversions.to_params(hash)).to eq("name=bob&address[street]=111%20ruby%20ave.&address[city]=ruby%20central&address[phones][]=111-111-1111&address[phones][]=222-222-2222")
13
+ end
14
+ end
15
+
16
+ describe ".normalize_param" do
17
+ context "value is an array" do
18
+ it "creates a params string" do
19
+ expect(
20
+ HTTParty::HashConversions.normalize_param(:people, ["Bob Jones", "Mike Smith"])
21
+ ).to eq("people[]=Bob%20Jones&people[]=Mike%20Smith&")
22
+ end
23
+ end
24
+
25
+ context "value is an empty array" do
26
+ it "creates a params string" do
27
+ expect(
28
+ HTTParty::HashConversions.normalize_param(:people, [])
29
+ ).to eq("people[]=&")
30
+ end
31
+ end
32
+
33
+ context "value is hash" do
34
+ it "creates a params string" do
35
+ expect(
36
+ HTTParty::HashConversions.normalize_param(:person, { name: "Bob Jones" })
37
+ ).to eq("person[name]=Bob%20Jones&")
38
+ end
39
+ end
40
+
41
+ context "value is a string" do
42
+ it "creates a params string" do
43
+ expect(
44
+ HTTParty::HashConversions.normalize_param(:name, "Bob Jones")
45
+ ).to eq("name=Bob%20Jones&")
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,41 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
+
3
+ RSpec.describe HTTParty::Logger::ApacheFormatter do
4
+ let(:subject) { described_class.new(logger_double, :info) }
5
+ let(:logger_double) { double('Logger') }
6
+ let(:request_double) { double('Request', http_method: Net::HTTP::Get, path: "http://my.domain.com/my_path") }
7
+ let(:request_time) { Time.new.strftime("%Y-%m-%d %H:%M:%S %z") }
8
+
9
+ before do
10
+ subject.current_time = request_time
11
+ expect(logger_double).to receive(:info).with(log_message)
12
+ end
13
+
14
+ describe "#format" do
15
+ let(:log_message) { "[HTTParty] [#{request_time}] 302 \"GET http://my.domain.com/my_path\" - " }
16
+
17
+ it "formats a response in a style that resembles apache's access log" do
18
+ response_double = double(
19
+ code: 302,
20
+ :[] => nil
21
+ )
22
+
23
+ subject.format(request_double, response_double)
24
+ end
25
+
26
+ context 'when there is a parsed response' do
27
+ let(:log_message) { "[HTTParty] [#{request_time}] 200 \"GET http://my.domain.com/my_path\" 512 "}
28
+
29
+ it "can handle the Content-Length header" do
30
+ # Simulate a parsed response that is an array, where accessing a string key will raise an error. See Issue #299.
31
+ response_double = double(
32
+ code: 200,
33
+ headers: { 'Content-Length' => 512 }
34
+ )
35
+ allow(response_double).to receive(:[]).with('Content-Length').and_raise(TypeError.new('no implicit conversion of String into Integer'))
36
+
37
+ subject.format(request_double, response_double)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,119 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
+
3
+ RSpec.describe HTTParty::Logger::CurlFormatter do
4
+ describe "#format" do
5
+ let(:logger) { double('Logger') }
6
+ let(:response_object) { Net::HTTPOK.new('1.1', 200, 'OK') }
7
+ let(:parsed_response) { lambda { {"foo" => "bar"} } }
8
+
9
+ let(:response) do
10
+ HTTParty::Response.new(request, response_object, parsed_response)
11
+ end
12
+
13
+ let(:request) do
14
+ HTTParty::Request.new(Net::HTTP::Get, 'http://foo.bar.com/')
15
+ end
16
+
17
+ subject { described_class.new(logger, :info) }
18
+
19
+ before do
20
+ allow(logger).to receive(:info)
21
+ allow(request).to receive(:raw_body).and_return('content')
22
+ allow(response_object).to receive_messages(body: "{foo:'bar'}")
23
+ response_object['header-key'] = 'header-value'
24
+
25
+ subject.format request, response
26
+ end
27
+
28
+ context 'when request is logged' do
29
+ context "and request's option 'base_uri' is not present" do
30
+ it 'logs url' do
31
+ expect(logger).to have_received(:info).with(/\[HTTParty\] \[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\ [+-]\d{4}\] > GET http:\/\/foo.bar.com/)
32
+ end
33
+ end
34
+
35
+ context "and request's option 'base_uri' is present" do
36
+ let(:request) do
37
+ HTTParty::Request.new(Net::HTTP::Get, '/path', base_uri: 'http://foo.bar.com')
38
+ end
39
+
40
+ it 'logs url' do
41
+ expect(logger).to have_received(:info).with(/\[HTTParty\] \[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\ [+-]\d{4}\] > GET http:\/\/foo.bar.com\/path/)
42
+ end
43
+ end
44
+
45
+ context 'and headers are not present' do
46
+ it 'not log Headers' do
47
+ expect(logger).not_to have_received(:info).with(/Headers/)
48
+ end
49
+ end
50
+
51
+ context 'and headers are present' do
52
+ let(:request) do
53
+ HTTParty::Request.new(Net::HTTP::Get, '/path', base_uri: 'http://foo.bar.com', headers: { key: 'value' })
54
+ end
55
+
56
+ it 'logs Headers' do
57
+ expect(logger).to have_received(:info).with(/Headers/)
58
+ end
59
+
60
+ it 'logs headers keys' do
61
+ expect(logger).to have_received(:info).with(/key: value/)
62
+ end
63
+ end
64
+
65
+ context 'and query is not present' do
66
+ it 'not logs Query' do
67
+ expect(logger).not_to have_received(:info).with(/Query/)
68
+ end
69
+ end
70
+
71
+ context 'and query is present' do
72
+ let(:request) do
73
+ HTTParty::Request.new(Net::HTTP::Get, '/path', query: { key: 'value' })
74
+ end
75
+
76
+ it 'logs Query' do
77
+ expect(logger).to have_received(:info).with(/Query/)
78
+ end
79
+
80
+ it 'logs query params' do
81
+ expect(logger).to have_received(:info).with(/key: value/)
82
+ end
83
+ end
84
+
85
+ context 'when request raw_body is present' do
86
+ it 'not logs request body' do
87
+ expect(logger).to have_received(:info).with(/content/)
88
+ end
89
+ end
90
+ end
91
+
92
+ context 'when response is logged' do
93
+ it 'logs http version and response code' do
94
+ expect(logger).to have_received(:info).with(/HTTP\/1.1 200/)
95
+ end
96
+
97
+ it 'logs headers' do
98
+ expect(logger).to have_received(:info).with(/Header-key: header-value/)
99
+ end
100
+
101
+ it 'logs body' do
102
+ expect(logger).to have_received(:info).with(/{foo:'bar'}/)
103
+ end
104
+ end
105
+
106
+ it "formats a response in a style that resembles a -v curl" do
107
+ logger_double = double
108
+ expect(logger_double).to receive(:info).with(
109
+ /\[HTTParty\] \[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\ [+-]\d{4}\] > GET http:\/\/localhost/)
110
+
111
+ subject = described_class.new(logger_double, :info)
112
+
113
+ stub_http_response_with("google.html")
114
+
115
+ response = HTTParty::Request.new.perform
116
+ subject.format(response.request, response)
117
+ end
118
+ end
119
+ end
@@ -1,22 +1,38 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
2
 
3
- describe HTTParty::Logger do
3
+ RSpec.describe HTTParty::Logger do
4
4
  describe ".build" do
5
5
  subject { HTTParty::Logger }
6
6
 
7
7
  it "defaults level to :info" do
8
- logger_double = double()
9
- subject.build(logger_double, nil, nil).level.should == :info
8
+ logger_double = double
9
+ expect(subject.build(logger_double, nil, nil).level).to eq(:info)
10
10
  end
11
11
 
12
12
  it "defaults format to :apache" do
13
- logger_double = double()
14
- subject.build(logger_double, nil, nil).should be_an_instance_of(HTTParty::Logger::ApacheLogger)
13
+ logger_double = double
14
+ expect(subject.build(logger_double, nil, nil)).to be_an_instance_of(HTTParty::Logger::ApacheFormatter)
15
15
  end
16
16
 
17
17
  it "builds :curl style logger" do
18
- logger_double = double()
19
- subject.build(logger_double, nil, :curl).should be_an_instance_of(HTTParty::Logger::CurlLogger)
18
+ logger_double = double
19
+ expect(subject.build(logger_double, nil, :curl)).to be_an_instance_of(HTTParty::Logger::CurlFormatter)
20
+ end
21
+
22
+ it "builds :custom style logger" do
23
+ CustomFormatter = Class.new(HTTParty::Logger::CurlFormatter)
24
+ HTTParty::Logger.add_formatter(:custom, CustomFormatter)
25
+
26
+ logger_double = double
27
+ expect(subject.build(logger_double, nil, :custom)).
28
+ to be_an_instance_of(CustomFormatter)
29
+ end
30
+ it "raises error when formatter exists" do
31
+ CustomFormatter2= Class.new(HTTParty::Logger::CurlFormatter)
32
+ HTTParty::Logger.add_formatter(:custom2, CustomFormatter2)
33
+
34
+ expect{ HTTParty::Logger.add_formatter(:custom2, CustomFormatter2) }.
35
+ to raise_error HTTParty::Error
20
36
  end
21
37
  end
22
38
  end