httparty 0.16.4 → 0.20.0

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.

Potentially problematic release.


This version of httparty might be problematic. Click here for more details.

Files changed (87) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +23 -0
  3. data/.rubocop_todo.yml +1 -1
  4. data/Changelog.md +55 -0
  5. data/Gemfile +5 -0
  6. data/README.md +4 -4
  7. data/docs/README.md +70 -5
  8. data/examples/README.md +6 -0
  9. data/examples/aaws.rb +6 -2
  10. data/examples/idn.rb +10 -0
  11. data/examples/peer_cert.rb +9 -0
  12. data/httparty.gemspec +1 -2
  13. data/lib/httparty/connection_adapter.rb +41 -10
  14. data/lib/httparty/cookie_hash.rb +10 -8
  15. data/lib/httparty/decompressor.rb +92 -0
  16. data/lib/httparty/exceptions.rb +3 -1
  17. data/lib/httparty/hash_conversions.rb +4 -2
  18. data/lib/httparty/headers_processor.rb +32 -0
  19. data/lib/httparty/logger/apache_formatter.rb +4 -2
  20. data/lib/httparty/logger/curl_formatter.rb +6 -4
  21. data/lib/httparty/logger/logger.rb +2 -0
  22. data/lib/httparty/logger/logstash_formatter.rb +4 -2
  23. data/lib/httparty/module_inheritable_attributes.rb +3 -1
  24. data/lib/httparty/net_digest_auth.rb +9 -10
  25. data/lib/httparty/parser.rb +9 -5
  26. data/lib/httparty/request/body.rb +24 -10
  27. data/lib/httparty/request/multipart_boundary.rb +2 -0
  28. data/lib/httparty/request.rb +67 -96
  29. data/lib/httparty/response/headers.rb +2 -0
  30. data/lib/httparty/response.rb +24 -4
  31. data/lib/httparty/{fragment_with_response.rb → response_fragment.rb} +6 -5
  32. data/lib/httparty/text_encoder.rb +72 -0
  33. data/lib/httparty/utils.rb +2 -0
  34. data/lib/httparty/version.rb +3 -1
  35. data/lib/httparty.rb +58 -35
  36. metadata +12 -108
  37. data/.travis.yml +0 -11
  38. data/features/basic_authentication.feature +0 -20
  39. data/features/command_line.feature +0 -95
  40. data/features/deals_with_http_error_codes.feature +0 -26
  41. data/features/digest_authentication.feature +0 -30
  42. data/features/handles_compressed_responses.feature +0 -27
  43. data/features/handles_multiple_formats.feature +0 -57
  44. data/features/steps/env.rb +0 -27
  45. data/features/steps/httparty_response_steps.rb +0 -56
  46. data/features/steps/httparty_steps.rb +0 -43
  47. data/features/steps/mongrel_helper.rb +0 -127
  48. data/features/steps/remote_service_steps.rb +0 -92
  49. data/features/supports_read_timeout_option.feature +0 -13
  50. data/features/supports_redirection.feature +0 -22
  51. data/features/supports_timeout_option.feature +0 -13
  52. data/spec/fixtures/delicious.xml +0 -23
  53. data/spec/fixtures/empty.xml +0 -0
  54. data/spec/fixtures/example.html +0 -10
  55. data/spec/fixtures/ssl/generate.sh +0 -29
  56. data/spec/fixtures/ssl/generated/bogushost.crt +0 -13
  57. data/spec/fixtures/ssl/generated/ca.crt +0 -16
  58. data/spec/fixtures/ssl/generated/ca.key +0 -15
  59. data/spec/fixtures/ssl/generated/selfsigned.crt +0 -14
  60. data/spec/fixtures/ssl/generated/server.crt +0 -13
  61. data/spec/fixtures/ssl/generated/server.key +0 -15
  62. data/spec/fixtures/ssl/openssl-exts.cnf +0 -9
  63. data/spec/fixtures/tiny.gif +0 -0
  64. data/spec/fixtures/twitter.csv +0 -2
  65. data/spec/fixtures/twitter.json +0 -1
  66. data/spec/fixtures/twitter.xml +0 -403
  67. data/spec/fixtures/undefined_method_add_node_for_nil.xml +0 -2
  68. data/spec/httparty/connection_adapter_spec.rb +0 -502
  69. data/spec/httparty/cookie_hash_spec.rb +0 -100
  70. data/spec/httparty/exception_spec.rb +0 -45
  71. data/spec/httparty/fragment_with_response_spec.rb +0 -14
  72. data/spec/httparty/hash_conversions_spec.rb +0 -58
  73. data/spec/httparty/logger/apache_formatter_spec.rb +0 -40
  74. data/spec/httparty/logger/curl_formatter_spec.rb +0 -119
  75. data/spec/httparty/logger/logger_spec.rb +0 -43
  76. data/spec/httparty/logger/logstash_formatter_spec.rb +0 -44
  77. data/spec/httparty/net_digest_auth_spec.rb +0 -270
  78. data/spec/httparty/parser_spec.rb +0 -190
  79. data/spec/httparty/request/body_spec.rb +0 -165
  80. data/spec/httparty/request_spec.rb +0 -1367
  81. data/spec/httparty/response_spec.rb +0 -368
  82. data/spec/httparty/ssl_spec.rb +0 -74
  83. data/spec/httparty_spec.rb +0 -923
  84. data/spec/spec_helper.rb +0 -56
  85. data/spec/support/ssl_test_helper.rb +0 -47
  86. data/spec/support/ssl_test_server.rb +0 -80
  87. data/spec/support/stub_response.rb +0 -49
@@ -1,190 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe HTTParty::Parser do
4
- describe ".SupportedFormats" do
5
- it "returns a hash" do
6
- expect(HTTParty::Parser::SupportedFormats).to be_instance_of(Hash)
7
- end
8
- end
9
-
10
- describe ".call" do
11
- it "generates an HTTParty::Parser instance with the given body and format" do
12
- expect(HTTParty::Parser).to receive(:new).with('body', :plain).and_return(double(parse: nil))
13
- HTTParty::Parser.call('body', :plain)
14
- end
15
-
16
- it "calls #parse on the parser" do
17
- parser = double('Parser')
18
- expect(parser).to receive(:parse)
19
- allow(HTTParty::Parser).to receive_messages(new: parser)
20
- parser = HTTParty::Parser.call('body', :plain)
21
- end
22
- end
23
-
24
- describe ".formats" do
25
- it "returns the SupportedFormats constant" do
26
- expect(HTTParty::Parser.formats).to eq(HTTParty::Parser::SupportedFormats)
27
- end
28
-
29
- it "returns the SupportedFormats constant for subclasses" do
30
- klass = Class.new(HTTParty::Parser)
31
- klass::SupportedFormats = { "application/atom+xml" => :atom }
32
-
33
- expect(klass.formats).to eq({"application/atom+xml" => :atom})
34
- end
35
- end
36
-
37
- describe ".format_from_mimetype" do
38
- it "returns a symbol representing the format mimetype" do
39
- expect(HTTParty::Parser.format_from_mimetype("text/plain")).to eq(:plain)
40
- end
41
-
42
- it "returns nil when the mimetype is not supported" do
43
- expect(HTTParty::Parser.format_from_mimetype("application/atom+xml")).to be_nil
44
- end
45
- end
46
-
47
- describe ".supported_formats" do
48
- it "returns a unique set of supported formats represented by symbols" do
49
- expect(HTTParty::Parser.supported_formats).to eq(HTTParty::Parser::SupportedFormats.values.uniq)
50
- end
51
- end
52
-
53
- describe ".supports_format?" do
54
- it "returns true for a supported format" do
55
- allow(HTTParty::Parser).to receive_messages(supported_formats: [:json])
56
- expect(HTTParty::Parser.supports_format?(:json)).to be_truthy
57
- end
58
-
59
- it "returns false for an unsupported format" do
60
- allow(HTTParty::Parser).to receive_messages(supported_formats: [])
61
- expect(HTTParty::Parser.supports_format?(:json)).to be_falsey
62
- end
63
- end
64
-
65
- describe "#parse" do
66
- it "attempts to parse supported formats" do
67
- parser = HTTParty::Parser.new('body', :json)
68
- allow(parser).to receive_messages(supports_format?: true)
69
-
70
- expect(parser).to receive(:parse_supported_format)
71
- parser.parse
72
- end
73
-
74
- it "returns the unparsed body when the format is unsupported" do
75
- parser = HTTParty::Parser.new('body', :json)
76
- allow(parser).to receive_messages(supports_format?: false)
77
-
78
- expect(parser.parse).to eq(parser.body)
79
- end
80
-
81
- it "returns nil for an empty body" do
82
- parser = HTTParty::Parser.new('', :json)
83
- expect(parser.parse).to be_nil
84
- end
85
-
86
- it "returns nil for a nil body" do
87
- parser = HTTParty::Parser.new(nil, :json)
88
- expect(parser.parse).to be_nil
89
- end
90
-
91
- it "returns nil for a 'null' body" do
92
- parser = HTTParty::Parser.new("null", :json)
93
- expect(parser.parse).to be_nil
94
- end
95
-
96
- it "returns nil for a body with spaces only" do
97
- parser = HTTParty::Parser.new(" ", :json)
98
- expect(parser.parse).to be_nil
99
- end
100
-
101
- it "does not raise exceptions for bodies with invalid encodings" do
102
- parser = HTTParty::Parser.new("\x80", :invalid_format)
103
- expect(parser.parse).to_not be_nil
104
- end
105
-
106
- it "ignores utf-8 bom" do
107
- parser = HTTParty::Parser.new("\xEF\xBB\xBF\{\"hi\":\"yo\"\}", :json)
108
- expect(parser.parse).to eq({"hi"=>"yo"})
109
- end
110
-
111
- it "parses ascii 8bit encoding" do
112
- parser = HTTParty::Parser.new(
113
- "{\"currency\":\"\xE2\x82\xAC\"}".force_encoding('ASCII-8BIT'),
114
- :json
115
- )
116
- expect(parser.parse).to eq({"currency" => "€"})
117
- end
118
-
119
- it "parses frozen strings" do
120
- parser = HTTParty::Parser.new('{"a":1}'.freeze, :json)
121
- expect(parser.parse).to eq("a" => 1)
122
- end
123
- end
124
-
125
- describe "#supports_format?" do
126
- it "utilizes the class method to determine if the format is supported" do
127
- expect(HTTParty::Parser).to receive(:supports_format?).with(:json)
128
- parser = HTTParty::Parser.new('body', :json)
129
- parser.send(:supports_format?)
130
- end
131
- end
132
-
133
- describe "#parse_supported_format" do
134
- it "calls the parser for the given format" do
135
- parser = HTTParty::Parser.new('body', :json)
136
- expect(parser).to receive(:json)
137
- parser.send(:parse_supported_format)
138
- end
139
-
140
- context "when a parsing method does not exist for the given format" do
141
- it "raises an exception" do
142
- parser = HTTParty::Parser.new('body', :atom)
143
- expect do
144
- parser.send(:parse_supported_format)
145
- end.to raise_error(NotImplementedError, "HTTParty::Parser has not implemented a parsing method for the :atom format.")
146
- end
147
-
148
- it "raises a useful exception message for subclasses" do
149
- atom_parser = Class.new(HTTParty::Parser) do
150
- def self.name
151
- 'AtomParser'
152
- end
153
- end
154
- parser = atom_parser.new 'body', :atom
155
- expect do
156
- parser.send(:parse_supported_format)
157
- end.to raise_error(NotImplementedError, "AtomParser has not implemented a parsing method for the :atom format.")
158
- end
159
- end
160
- end
161
-
162
- context "parsers" do
163
- subject do
164
- HTTParty::Parser.new('body', nil)
165
- end
166
-
167
- it "parses xml with MultiXml" do
168
- expect(MultiXml).to receive(:parse).with('body')
169
- subject.send(:xml)
170
- end
171
-
172
- it "parses json with JSON" do
173
- expect(JSON).to receive(:parse).with('body', :quirks_mode => true, :allow_nan => true)
174
- subject.send(:json)
175
- end
176
-
177
- it "parses html by simply returning the body" do
178
- expect(subject.send(:html)).to eq('body')
179
- end
180
-
181
- it "parses plain text by simply returning the body" do
182
- expect(subject.send(:plain)).to eq('body')
183
- end
184
-
185
- it "parses csv with CSV" do
186
- expect(CSV).to receive(:parse).with('body')
187
- subject.send(:csv)
188
- end
189
- end
190
- end
@@ -1,165 +0,0 @@
1
- require 'spec_helper'
2
- require 'tempfile'
3
-
4
- RSpec.describe HTTParty::Request::Body do
5
- describe '#call' do
6
- let(:options) { {} }
7
-
8
- subject { described_class.new(params, options).call }
9
-
10
- context 'when params is string' do
11
- let(:params) { 'name=Bob%20Jones' }
12
-
13
- it { is_expected.to eq params }
14
- end
15
-
16
- context 'when params is hash' do
17
- let(:params) { { people: ["Bob Jones", "Mike Smith"] } }
18
- let(:converted_params) { "people[]=Bob%20Jones&people[]=Mike%20Smith"}
19
-
20
- it { is_expected.to eq converted_params }
21
-
22
- context 'when params has file' do
23
- before do
24
- allow(HTTParty::Request::MultipartBoundary)
25
- .to receive(:generate).and_return("------------------------c772861a5109d5ef")
26
- end
27
-
28
- let(:file) { File.open('spec/fixtures/tiny.gif') }
29
- let(:params) do
30
- {
31
- user: {
32
- avatar: file,
33
- first_name: 'John',
34
- last_name: 'Doe',
35
- enabled: true
36
- }
37
- }
38
- end
39
- let(:expected_file_name) { 'tiny.gif' }
40
- let(:expected_file_contents) { "GIF89a\u0001\u0000\u0001\u0000\u0000\xFF\u0000,\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0000\u0002\u0000;" }
41
- let(:expected_content_type) { 'image/gif' }
42
- let(:multipart_params) do
43
- "--------------------------c772861a5109d5ef\r\n" \
44
- "Content-Disposition: form-data; name=\"user[avatar]\"; filename=\"#{expected_file_name}\"\r\n" \
45
- "Content-Type: #{expected_content_type}\r\n" \
46
- "\r\n" \
47
- "#{expected_file_contents}\r\n" \
48
- "--------------------------c772861a5109d5ef\r\n" \
49
- "Content-Disposition: form-data; name=\"user[first_name]\"\r\n" \
50
- "\r\n" \
51
- "John\r\n" \
52
- "--------------------------c772861a5109d5ef\r\n" \
53
- "Content-Disposition: form-data; name=\"user[last_name]\"\r\n" \
54
- "\r\n" \
55
- "Doe\r\n" \
56
- "--------------------------c772861a5109d5ef\r\n" \
57
- "Content-Disposition: form-data; name=\"user[enabled]\"\r\n" \
58
- "\r\n" \
59
- "true\r\n" \
60
- "--------------------------c772861a5109d5ef--\r\n"
61
- end
62
-
63
- it { is_expected.to eq multipart_params }
64
-
65
- context 'when passing multipart as an option' do
66
- let(:options) { { force_multipart: true } }
67
- let(:params) do
68
- {
69
- user: {
70
- first_name: 'John',
71
- last_name: 'Doe',
72
- enabled: true
73
- }
74
- }
75
- end
76
- let(:multipart_params) do
77
- "--------------------------c772861a5109d5ef\r\n" \
78
- "Content-Disposition: form-data; name=\"user[first_name]\"\r\n" \
79
- "\r\n" \
80
- "John\r\n" \
81
- "--------------------------c772861a5109d5ef\r\n" \
82
- "Content-Disposition: form-data; name=\"user[last_name]\"\r\n" \
83
- "\r\n" \
84
- "Doe\r\n" \
85
- "--------------------------c772861a5109d5ef\r\n" \
86
- "Content-Disposition: form-data; name=\"user[enabled]\"\r\n" \
87
- "\r\n" \
88
- "true\r\n" \
89
- "--------------------------c772861a5109d5ef--\r\n"
90
- end
91
-
92
- it { is_expected.to eq multipart_params }
93
-
94
- end
95
-
96
- context 'file object responds to original_filename' do
97
- let(:some_temp_file) { Tempfile.new(['some_temp_file','.gif']) }
98
- let(:expected_file_name) { "some_temp_file.gif" }
99
- let(:expected_file_contents) { "Hello" }
100
- let(:file) { double(:mocked_action_dispatch, path: some_temp_file.path, original_filename: 'some_temp_file.gif', read: expected_file_contents) }
101
-
102
- before { some_temp_file.write('Hello') }
103
-
104
- it { is_expected.to eq multipart_params }
105
- end
106
- end
107
- end
108
- end
109
-
110
- describe '#multipart?' do
111
- let(:force_multipart) { false }
112
- let(:file) { File.open('spec/fixtures/tiny.gif') }
113
-
114
- subject { described_class.new(params, force_multipart: force_multipart).multipart? }
115
-
116
- context 'when params does not respond to to_hash' do
117
- let(:params) { 'name=Bob%20Jones' }
118
-
119
- it { is_expected.to be false }
120
- end
121
-
122
- context 'when params responds to to_hash' do
123
- class HashLike
124
- def initialize(hash)
125
- @hash = hash
126
- end
127
-
128
- def to_hash
129
- @hash
130
- end
131
- end
132
-
133
- class ArrayLike
134
- def initialize(ary)
135
- @ary = ary
136
- end
137
-
138
- def to_ary
139
- @ary
140
- end
141
- end
142
-
143
- context 'when force_multipart is true' do
144
- let(:params) { { name: 'Bob Jones' } }
145
- let(:force_multipart) { true }
146
-
147
- it { is_expected.to be true }
148
- end
149
-
150
- context 'when it does not contain a file' do
151
- let(:hash_like_param) { HashLike.new(first: 'Bob', last: ArrayLike.new(['Jones'])) }
152
- let(:params) { { name: ArrayLike.new([hash_like_param]) } }
153
-
154
- it { is_expected.to eq false }
155
- end
156
-
157
- context 'when it contains file' do
158
- let(:hash_like_param) { HashLike.new(first: 'Bob', last: 'Jones', file: ArrayLike.new([file])) }
159
- let(:params) { { name: ArrayLike.new([hash_like_param]) } }
160
-
161
- it { is_expected.to be true }
162
- end
163
- end
164
- end
165
- end