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,11 +1,11 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
2
 
3
- describe Net::HTTPHeader::DigestAuthenticator do
3
+ RSpec.describe Net::HTTPHeader::DigestAuthenticator do
4
4
  def setup_digest(response)
5
5
  digest = Net::HTTPHeader::DigestAuthenticator.new("Mufasa",
6
- "Circle Of Life", "GET", "/dir/index.html", response)
7
- digest.stub(:random).and_return("deadbeef")
8
- Digest::MD5.stub(:hexdigest) { |str| "md5(#{str})" }
6
+ "Circle Of Life", "GET", "/dir/index.html", response)
7
+ allow(digest).to receive(:random).and_return("deadbeef")
8
+ allow(Digest::MD5).to receive(:hexdigest) { |str| "md5(#{str})" }
9
9
  digest
10
10
  end
11
11
 
@@ -13,6 +13,34 @@ describe Net::HTTPHeader::DigestAuthenticator do
13
13
  @digest.authorization_header.join(", ")
14
14
  end
15
15
 
16
+ def cookie_header
17
+ @digest.cookie_header
18
+ end
19
+
20
+ context "with a cookie value in the response header" do
21
+ before do
22
+ @digest = setup_digest({
23
+ 'www-authenticate' => 'Digest realm="myhost@testrealm.com"',
24
+ 'Set-Cookie' => 'custom-cookie=1234567'
25
+ })
26
+ end
27
+
28
+ it "should set cookie header" do
29
+ expect(cookie_header).to include('custom-cookie=1234567')
30
+ end
31
+ end
32
+
33
+ context "without a cookie value in the response header" do
34
+ before do
35
+ @digest = setup_digest({
36
+ 'www-authenticate' => 'Digest realm="myhost@testrealm.com"'
37
+ })
38
+ end
39
+
40
+ it "should set empty cookie header array" do
41
+ expect(cookie_header).to eql []
42
+ end
43
+ end
16
44
 
17
45
  context "with an opaque value in the response header" do
18
46
  before do
@@ -22,7 +50,7 @@ describe Net::HTTPHeader::DigestAuthenticator do
22
50
  end
23
51
 
24
52
  it "should set opaque" do
25
- authorization_header.should include(%Q(opaque="solid"))
53
+ expect(authorization_header).to include('opaque="solid"')
26
54
  end
27
55
  end
28
56
 
@@ -34,119 +62,179 @@ describe Net::HTTPHeader::DigestAuthenticator do
34
62
  end
35
63
 
36
64
  it "should not set opaque" do
37
- authorization_header.should_not include(%Q(opaque=))
65
+ expect(authorization_header).not_to include("opaque=")
38
66
  end
39
67
  end
40
68
 
41
69
  context "with specified quality of protection (qop)" do
42
70
  before do
43
71
  @digest = setup_digest({
44
- 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth"',
72
+ 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth"'
45
73
  })
46
74
  end
47
75
 
48
76
  it "should set prefix" do
49
- authorization_header.should =~ /^Digest /
77
+ expect(authorization_header).to match(/^Digest /)
50
78
  end
51
79
 
52
80
  it "should set username" do
53
- authorization_header.should include(%Q(username="Mufasa"))
81
+ expect(authorization_header).to include('username="Mufasa"')
54
82
  end
55
83
 
56
84
  it "should set digest-uri" do
57
- authorization_header.should include(%Q(uri="/dir/index.html"))
85
+ expect(authorization_header).to include('uri="/dir/index.html"')
58
86
  end
59
87
 
60
88
  it "should set qop" do
61
- authorization_header.should include(%Q(qop="auth"))
89
+ expect(authorization_header).to include('qop="auth"')
62
90
  end
63
91
 
64
92
  it "should set cnonce" do
65
- authorization_header.should include(%Q(cnonce="md5(deadbeef)"))
93
+ expect(authorization_header).to include('cnonce="md5(deadbeef)"')
66
94
  end
67
95
 
68
96
  it "should set nonce-count" do
69
- authorization_header.should include(%Q(nc=00000001))
97
+ expect(authorization_header).to include("nc=00000001")
70
98
  end
71
99
 
72
100
  it "should set response" do
73
101
  request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))"
74
- authorization_header.should include(%Q(response="#{request_digest}"))
102
+ expect(authorization_header).to include(%(response="#{request_digest}"))
75
103
  end
76
104
  end
77
105
 
106
+ context "when quality of protection (qop) is unquoted" do
107
+ before do
108
+ @digest = setup_digest({
109
+ 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop=auth'
110
+ })
111
+ end
112
+
113
+ it "should still set qop" do
114
+ expect(authorization_header).to include('qop="auth"')
115
+ end
116
+ end
78
117
 
79
118
  context "with unspecified quality of protection (qop)" do
80
119
  before do
81
120
  @digest = setup_digest({
82
- 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE"',
121
+ 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE"'
83
122
  })
84
123
  end
85
124
 
86
125
  it "should set prefix" do
87
- authorization_header.should =~ /^Digest /
126
+ expect(authorization_header).to match(/^Digest /)
88
127
  end
89
128
 
90
129
  it "should set username" do
91
- authorization_header.should include(%Q(username="Mufasa"))
130
+ expect(authorization_header).to include('username="Mufasa"')
92
131
  end
93
132
 
94
133
  it "should set digest-uri" do
95
- authorization_header.should include(%Q(uri="/dir/index.html"))
134
+ expect(authorization_header).to include('uri="/dir/index.html"')
96
135
  end
97
136
 
98
137
  it "should not set qop" do
99
- authorization_header.should_not include(%Q(qop=))
138
+ expect(authorization_header).not_to include("qop=")
100
139
  end
101
140
 
102
141
  it "should not set cnonce" do
103
- authorization_header.should_not include(%Q(cnonce=))
142
+ expect(authorization_header).not_to include("cnonce=")
104
143
  end
105
144
 
106
145
  it "should not set nonce-count" do
107
- authorization_header.should_not include(%Q(nc=))
146
+ expect(authorization_header).not_to include("nc=")
108
147
  end
109
148
 
110
149
  it "should set response" do
111
150
  request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:md5(GET:/dir/index.html))"
112
- authorization_header.should include(%Q(response="#{request_digest}"))
151
+ expect(authorization_header).to include(%(response="#{request_digest}"))
152
+ end
153
+ end
154
+
155
+ context "with http basic auth response when net digest auth expected" do
156
+ it "should not fail" do
157
+ @digest = setup_digest({
158
+ 'www-authenticate' => 'WWW-Authenticate: Basic realm="testrealm.com""'
159
+ })
160
+
161
+ expect(authorization_header).to include("Digest")
113
162
  end
114
163
  end
115
164
 
116
165
  context "with multiple authenticate headers" do
117
166
  before do
118
167
  @digest = setup_digest({
119
- 'www-authenticate' => 'NTLM, Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth"',
168
+ 'www-authenticate' => 'NTLM, Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth"'
120
169
  })
121
170
  end
122
171
 
123
172
  it "should set prefix" do
124
- authorization_header.should =~ /^Digest /
173
+ expect(authorization_header).to match(/^Digest /)
125
174
  end
126
175
 
127
176
  it "should set username" do
128
- authorization_header.should include(%Q(username="Mufasa"))
177
+ expect(authorization_header).to include('username="Mufasa"')
129
178
  end
130
179
 
131
180
  it "should set digest-uri" do
132
- authorization_header.should include(%Q(uri="/dir/index.html"))
181
+ expect(authorization_header).to include('uri="/dir/index.html"')
133
182
  end
134
183
 
135
184
  it "should set qop" do
136
- authorization_header.should include(%Q(qop="auth"))
185
+ expect(authorization_header).to include('qop="auth"')
137
186
  end
138
187
 
139
188
  it "should set cnonce" do
140
- authorization_header.should include(%Q(cnonce="md5(deadbeef)"))
189
+ expect(authorization_header).to include('cnonce="md5(deadbeef)"')
141
190
  end
142
191
 
143
192
  it "should set nonce-count" do
144
- authorization_header.should include(%Q(nc=00000001))
193
+ expect(authorization_header).to include("nc=00000001")
145
194
  end
146
195
 
147
196
  it "should set response" do
148
197
  request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))"
149
- authorization_header.should include(%Q(response="#{request_digest}"))
198
+ expect(authorization_header).to include(%(response="#{request_digest}"))
199
+ end
200
+ end
201
+
202
+ context "with algorithm specified" do
203
+ before do
204
+ @digest = setup_digest({
205
+ 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth", algorithm=MD5'
206
+ })
207
+ end
208
+
209
+ it "should recognise algorithm was specified" do
210
+ expect( @digest.send :algorithm_present? ).to be(true)
211
+ end
212
+
213
+ it "should set the algorithm header" do
214
+ expect(authorization_header).to include('algorithm="MD5"')
215
+ end
216
+ end
217
+
218
+ context "with md5-sess algorithm specified" do
219
+ before do
220
+ @digest = setup_digest({
221
+ 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth", algorithm=MD5-sess'
222
+ })
223
+ end
224
+
225
+ it "should recognise algorithm was specified" do
226
+ expect( @digest.send :algorithm_present? ).to be(true)
227
+ end
228
+
229
+ it "should set the algorithm header" do
230
+ expect(authorization_header).to include('algorithm="MD5-sess"')
231
+ end
232
+
233
+ it "should set response using md5-sess algorithm" do
234
+ request_digest = "md5(md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:md5(deadbeef)):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))"
235
+ expect(authorization_header).to include(%(response="#{request_digest}"))
150
236
  end
237
+
151
238
  end
239
+
152
240
  end
@@ -1,64 +1,64 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
2
 
3
- describe HTTParty::Parser do
3
+ RSpec.describe HTTParty::Parser do
4
4
  describe ".SupportedFormats" do
5
5
  it "returns a hash" do
6
- HTTParty::Parser::SupportedFormats.should be_instance_of(Hash)
6
+ expect(HTTParty::Parser::SupportedFormats).to be_instance_of(Hash)
7
7
  end
8
8
  end
9
9
 
10
10
  describe ".call" do
11
11
  it "generates an HTTParty::Parser instance with the given body and format" do
12
- HTTParty::Parser.should_receive(:new).with('body', :plain).and_return(stub(:parse => nil))
12
+ expect(HTTParty::Parser).to receive(:new).with('body', :plain).and_return(double(parse: nil))
13
13
  HTTParty::Parser.call('body', :plain)
14
14
  end
15
15
 
16
16
  it "calls #parse on the parser" do
17
- parser = mock('Parser')
18
- parser.should_receive(:parse)
19
- HTTParty::Parser.stub(:new => parser)
17
+ parser = double('Parser')
18
+ expect(parser).to receive(:parse)
19
+ allow(HTTParty::Parser).to receive_messages(new: parser)
20
20
  parser = HTTParty::Parser.call('body', :plain)
21
21
  end
22
22
  end
23
23
 
24
24
  describe ".formats" do
25
25
  it "returns the SupportedFormats constant" do
26
- HTTParty::Parser.formats.should == HTTParty::Parser::SupportedFormats
26
+ expect(HTTParty::Parser.formats).to eq(HTTParty::Parser::SupportedFormats)
27
27
  end
28
28
 
29
29
  it "returns the SupportedFormats constant for subclasses" do
30
30
  class MyParser < HTTParty::Parser
31
31
  SupportedFormats = {"application/atom+xml" => :atom}
32
32
  end
33
- MyParser.formats.should == {"application/atom+xml" => :atom}
33
+ expect(MyParser.formats).to eq({"application/atom+xml" => :atom})
34
34
  end
35
35
  end
36
36
 
37
37
  describe ".format_from_mimetype" do
38
38
  it "returns a symbol representing the format mimetype" do
39
- HTTParty::Parser.format_from_mimetype("text/plain").should == :plain
39
+ expect(HTTParty::Parser.format_from_mimetype("text/plain")).to eq(:plain)
40
40
  end
41
41
 
42
42
  it "returns nil when the mimetype is not supported" do
43
- HTTParty::Parser.format_from_mimetype("application/atom+xml").should be_nil
43
+ expect(HTTParty::Parser.format_from_mimetype("application/atom+xml")).to be_nil
44
44
  end
45
45
  end
46
46
 
47
47
  describe ".supported_formats" do
48
48
  it "returns a unique set of supported formats represented by symbols" do
49
- HTTParty::Parser.supported_formats.should == HTTParty::Parser::SupportedFormats.values.uniq
49
+ expect(HTTParty::Parser.supported_formats).to eq(HTTParty::Parser::SupportedFormats.values.uniq)
50
50
  end
51
51
  end
52
52
 
53
53
  describe ".supports_format?" do
54
54
  it "returns true for a supported format" do
55
- HTTParty::Parser.stub(:supported_formats => [:json])
56
- HTTParty::Parser.supports_format?(:json).should be_true
55
+ allow(HTTParty::Parser).to receive_messages(supported_formats: [:json])
56
+ expect(HTTParty::Parser.supports_format?(:json)).to be_truthy
57
57
  end
58
58
 
59
59
  it "returns false for an unsupported format" do
60
- HTTParty::Parser.stub(:supported_formats => [])
61
- HTTParty::Parser.supports_format?(:json).should be_false
60
+ allow(HTTParty::Parser).to receive_messages(supported_formats: [])
61
+ expect(HTTParty::Parser.supports_format?(:json)).to be_falsey
62
62
  end
63
63
  end
64
64
 
@@ -68,40 +68,46 @@ describe HTTParty::Parser do
68
68
  end
69
69
 
70
70
  it "attempts to parse supported formats" do
71
- @parser.stub(:supports_format? => true)
72
- @parser.should_receive(:parse_supported_format)
71
+ allow(@parser).to receive_messages(supports_format?: true)
72
+ expect(@parser).to receive(:parse_supported_format)
73
73
  @parser.parse
74
74
  end
75
75
 
76
76
  it "returns the unparsed body when the format is unsupported" do
77
- @parser.stub(:supports_format? => false)
78
- @parser.parse.should == @parser.body
77
+ allow(@parser).to receive_messages(supports_format?: false)
78
+ expect(@parser.parse).to eq(@parser.body)
79
79
  end
80
80
 
81
81
  it "returns nil for an empty body" do
82
- @parser.stub(:body => '')
83
- @parser.parse.should be_nil
82
+ allow(@parser).to receive_messages(body: '')
83
+ expect(@parser.parse).to be_nil
84
84
  end
85
85
 
86
86
  it "returns nil for a nil body" do
87
- @parser.stub(:body => nil)
88
- @parser.parse.should be_nil
87
+ allow(@parser).to receive_messages(body: nil)
88
+ expect(@parser.parse).to be_nil
89
89
  end
90
90
 
91
91
  it "returns nil for a 'null' body" do
92
- @parser.stub(:body => "null")
93
- @parser.parse.should be_nil
92
+ allow(@parser).to receive_messages(body: "null")
93
+ expect(@parser.parse).to be_nil
94
94
  end
95
95
 
96
96
  it "returns nil for a body with spaces only" do
97
- @parser.stub(:body => " ")
98
- @parser.parse.should be_nil
97
+ allow(@parser).to receive_messages(body: " ")
98
+ expect(@parser.parse).to be_nil
99
+ end
100
+
101
+ it "does not raise exceptions for bodies with invalid encodings" do
102
+ allow(@parser).to receive_messages(body: "\x80")
103
+ allow(@parser).to receive_messages(supports_format?: false)
104
+ expect(@parser.parse).to_not be_nil
99
105
  end
100
106
  end
101
107
 
102
108
  describe "#supports_format?" do
103
109
  it "utilizes the class method to determine if the format is supported" do
104
- HTTParty::Parser.should_receive(:supports_format?).with(:json)
110
+ expect(HTTParty::Parser).to receive(:supports_format?).with(:json)
105
111
  parser = HTTParty::Parser.new('body', :json)
106
112
  parser.send(:supports_format?)
107
113
  end
@@ -110,7 +116,7 @@ describe HTTParty::Parser do
110
116
  describe "#parse_supported_format" do
111
117
  it "calls the parser for the given format" do
112
118
  parser = HTTParty::Parser.new('body', :json)
113
- parser.should_receive(:json)
119
+ expect(parser).to receive(:json)
114
120
  parser.send(:parse_supported_format)
115
121
  end
116
122
 
@@ -124,7 +130,9 @@ describe HTTParty::Parser do
124
130
 
125
131
  it "raises a useful exception message for subclasses" do
126
132
  atom_parser = Class.new(HTTParty::Parser) do
127
- def self.name; 'AtomParser'; end
133
+ def self.name
134
+ 'AtomParser'
135
+ end
128
136
  end
129
137
  parser = atom_parser.new 'body', :atom
130
138
  expect do
@@ -140,25 +148,25 @@ describe HTTParty::Parser do
140
148
  end
141
149
 
142
150
  it "parses xml with MultiXml" do
143
- MultiXml.should_receive(:parse).with('body')
151
+ expect(MultiXml).to receive(:parse).with('body')
144
152
  subject.send(:xml)
145
153
  end
146
154
 
147
155
  it "parses json with JSON" do
148
- JSON.should_receive(:load).with('body', nil)
156
+ expect(JSON).to receive(:parse).with('body', :quirks_mode => true, :allow_nan => true)
149
157
  subject.send(:json)
150
158
  end
151
159
 
152
160
  it "parses html by simply returning the body" do
153
- subject.send(:html).should == 'body'
161
+ expect(subject.send(:html)).to eq('body')
154
162
  end
155
163
 
156
164
  it "parses plain text by simply returning the body" do
157
- subject.send(:plain).should == 'body'
165
+ expect(subject.send(:plain)).to eq('body')
158
166
  end
159
167
 
160
168
  it "parses csv with CSV" do
161
- CSV.should_receive(:parse).with('body')
169
+ expect(CSV).to receive(:parse).with('body')
162
170
  subject.send(:csv)
163
171
  end
164
172
  end