httparty 0.16.4 → 0.20.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 (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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d8ea06db7242bc4bea719ac28217cb7a03643277
4
- data.tar.gz: 3341968702712ab91fc1348f000337afe1bf4047
2
+ SHA256:
3
+ metadata.gz: bde34a85d8b010341759c1b2b42dfe58cad693c39f047b9803ac90afbc13290b
4
+ data.tar.gz: b5248420c90ea545dfa9e6e234d6c597b4c7306dfc8d58ff94dca82e405e0ed1
5
5
  SHA512:
6
- metadata.gz: bfd0717ef9adb117bc7568a35648b0bc295d0f92210696a423c268be80b7ef12d06d84d2d94ed33a24d31367fd03c3fae3cabc6afbc5cc5b0446f15f01feff79
7
- data.tar.gz: 853d4aa140b4717e36ae0baeeb6c1ba113567242398abd56a944bcf29543f74e3a0a3430c0f8823b9fe9c00d8a4bdb2c3a3ff53c59cf9263e080ac7002013f4e
6
+ metadata.gz: 13316910a85a75d1204c64be41e995475b26abf9aad1165c06349c296d0b3f0f6ae644b00d8bcf14adc3d9a11659bffd060a5101dc88718af74d0324adde9e30
7
+ data.tar.gz: 668fac0ca6a513e64dead9b633ecb12c4ff926cb017e4e7e244249cfb361f93e1aa515ef3fb6b80e6245264e7da38d0599abec9931c5b33b88d7235b966b0aa1
@@ -0,0 +1,23 @@
1
+ name: CI
2
+ on: [push, pull_request]
3
+ jobs:
4
+ build:
5
+ runs-on: ubuntu-latest
6
+ strategy:
7
+ matrix:
8
+ ruby:
9
+ - 2.3
10
+ - 2.4
11
+ - 2.5
12
+ - 2.6
13
+ - 2.7
14
+ steps:
15
+ - name: Check out repository code
16
+ uses: actions/checkout@v2
17
+ - name: Set up Ruby
18
+ uses: ruby/setup-ruby@v1
19
+ with:
20
+ ruby-version: ${{ matrix.ruby }}
21
+ bundler-cache: true # Run "bundle install", and cache the result automatically.
22
+ - name: Run Rake
23
+ run: bundle exec rake
data/.rubocop_todo.yml CHANGED
@@ -15,7 +15,7 @@ Lint/EndAlignment:
15
15
  Enabled: false
16
16
 
17
17
  # Offense count: 1
18
- Lint/HandleExceptions:
18
+ Lint/SuppressedException:
19
19
  Enabled: false
20
20
 
21
21
  # Offense count: 5
data/Changelog.md CHANGED
@@ -1,3 +1,58 @@
1
+ ## 0.20.0
2
+
3
+ Breaking changes
4
+
5
+ * Require Ruby >= 2.3.0
6
+
7
+ Fixes
8
+
9
+ * [`Marshal.dump` fails on response objects when request option `:logger` is set or `:parser` is a proc](https://github.com/jnunemaker/httparty/pull/714)
10
+ * [Switch `:pem` option to to `OpenSSL::PKey.read` to support other algorithms](https://github.com/jnunemaker/httparty/pull/720)
11
+
12
+ ## 0.19.1
13
+
14
+ * [Remove use of unary + method for creating non-frozen string to increase compatibility with older versions of ruby](https://github.com/jnunemaker/httparty/commit/4416141d37fd71bdba4f37589ec265f55aa446ce)
15
+
16
+ ## 0.19.0
17
+
18
+ * [Multipart/Form-Data: rewind files after read](https://github.com/jnunemaker/httparty/pull/709)
19
+ * [add frozen_string_literal pragma to all files](https://github.com/jnunemaker/httparty/pull/711)
20
+ * [Better handling of Accept-Encoding / Content-Encoding decompression (fixes #562)](https://github.com/jnunemaker/httparty/pull/729)
21
+
22
+ ## 0.18.1
23
+
24
+ * [Rename cop Lint/HandleExceptions to Lint/SuppressedException](https://github.com/jnunemaker/httparty/pull/699).
25
+ * [Encode keys in query params](https://github.com/jnunemaker/httparty/pull/698).
26
+ * [Fixed SSL doc example](https://github.com/jnunemaker/httparty/pull/692).
27
+ * [Add a build status badge](https://github.com/jnunemaker/httparty/pull/701).
28
+
29
+
30
+ ## 0.18.0
31
+
32
+ * [Support gzip/deflate transfer encoding when explicit headers are set](https://github.com/jnunemaker/httparty/pull/678).
33
+ * [Support edge case cookie format with a blank attribute](https://github.com/jnunemaker/httparty/pull/685).
34
+
35
+ ## 0.17.3
36
+
37
+ 0.17.2 is broken https://github.com/jnunemaker/httparty/issues/681
38
+
39
+ ## 0.17.2
40
+
41
+ * [Add Response#nil? deprecetion warning](https://github.com/jnunemaker/httparty/pull/680)
42
+
43
+ ## 0.17.1
44
+
45
+ * [Pass options to dynamic block headers](https://github.com/jnunemaker/httparty/pull/661)
46
+ * [Normalize urls with URI adapter to allow International Domain Names support](https://github.com/jnunemaker/httparty/pull/668)
47
+ * [Add max_retries support](https://github.com/jnunemaker/httparty/pull/660)
48
+ * [Minize gem size by removing test files](https://github.com/jnunemaker/httparty/pull/658)
49
+
50
+ ## 0.17.0
51
+
52
+ * [Fix encoding of streamed chunk](https://github.com/jnunemaker/httparty/pull/644)
53
+ * [Avoid modifying frozen strings](https://github.com/jnunemaker/httparty/pull/649)
54
+ * [Expose .connection on fragment block param](https://github.com/jnunemaker/httparty/pull/648)
55
+ * [Add support for `Net::HTTP#write_timeout` method (Ruby 2.6.0)](https://github.com/jnunemaker/httparty/pull/647)
1
56
 
2
57
  ## 0.16.4
3
58
  * [Add support for Ruby 2.6](https://github.com/jnunemaker/httparty/pull/636)
data/Gemfile CHANGED
@@ -16,4 +16,9 @@ group :test do
16
16
  gem 'aruba'
17
17
  gem 'cucumber', '~> 2.3'
18
18
  gem 'webmock'
19
+ gem 'addressable'
20
+ end
21
+
22
+ group :development, :test do
23
+ gem 'pry'
19
24
  end
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # httparty
2
2
 
3
+ [![Build Status](https://travis-ci.org/jnunemaker/httparty.svg?branch=master)](https://travis-ci.org/jnunemaker/httparty)
4
+
3
5
  Makes http fun again! Ain't no party like a httparty, because a httparty don't stop.
4
6
 
5
7
  ## Install
@@ -10,7 +12,7 @@ gem install httparty
10
12
 
11
13
  ## Requirements
12
14
 
13
- * Ruby 2.0.0 or higher
15
+ * Ruby 2.3.0 or higher
14
16
  * multi_xml
15
17
  * You like to party!
16
18
 
@@ -46,7 +48,6 @@ puts stack_exchange.users
46
48
  ```
47
49
 
48
50
  See the [examples directory](http://github.com/jnunemaker/httparty/tree/master/examples) for even more goodies.
49
-
50
51
  ## Command Line Interface
51
52
 
52
53
  httparty also includes the executable `httparty` which can be
@@ -63,9 +64,8 @@ httparty "https://api.stackexchange.com/2.2/questions?site=stackoverflow"
63
64
  ## Help and Docs
64
65
 
65
66
  * [Docs](https://github.com/jnunemaker/httparty/tree/master/docs)
66
- * https://groups.google.com/forum/#!forum/httparty-gem
67
+ * https://github.com/jnunemaker/httparty/discussions
67
68
  * https://www.rubydoc.info/github/jnunemaker/httparty
68
- * http://stackoverflow.com/questions/tagged/httparty
69
69
 
70
70
  ## Contributing
71
71
 
data/docs/README.md CHANGED
@@ -9,7 +9,7 @@ Makes http fun again!
9
9
  ## Parsing JSON
10
10
  If the response Content Type is `application/json`, HTTParty will parse the response and return Ruby objects such as a hash or array. The default behavior for parsing JSON will return keys as strings. This can be supressed with the `format` option. To get hash keys as symbols:
11
11
 
12
- ```
12
+ ```ruby
13
13
  response = HTTParty.get('http://example.com', format: :plain)
14
14
  JSON.parse response, symbolize_names: true
15
15
  ```
@@ -70,7 +70,7 @@ class Client
70
70
  end
71
71
  ```
72
72
 
73
- You can also include this options with the call:
73
+ You can also include all of these options with the call:
74
74
 
75
75
  ```ruby
76
76
  class Client
@@ -79,14 +79,14 @@ class Client
79
79
  base_uri "https://example.com"
80
80
 
81
81
  def self.fetch
82
- get("/resources", pem: (File.read("#{File.expand_path('.')}/path/to/certs/cert.pem"), "123456")
82
+ get("/resources", pem: File.read("#{File.expand_path('.')}/path/to/certs/cert.pem"), pem_password: "123456")
83
83
  end
84
84
  end
85
85
  ```
86
86
 
87
87
  ### Avoid SSL verification
88
88
 
89
- In some cases you may want to skip SSL verification, because the entity that issue the certificate is not a valid one, but you still want to work with it. You can achieve this through:
89
+ In some cases you may want to skip SSL verification, because the entity that issued the certificate is not a valid one, but you still want to work with it. You can achieve this through:
90
90
 
91
91
  ```ruby
92
92
  # Skips SSL certificate verification
@@ -103,4 +103,69 @@ class Client
103
103
  # get("resources", verify_peer: false)
104
104
  end
105
105
  end
106
- ```
106
+ ```
107
+
108
+ ### HTTP Compression
109
+
110
+ The `Accept-Encoding` request header and `Content-Encoding` response header
111
+ are used to control compression (gzip, etc.) over the wire. Refer to
112
+ [RFC-2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) for details.
113
+ (For clarity: these headers are **not** used for character encoding i.e. `utf-8`
114
+ which is specified in the `Accept` and `Content-Type` headers.)
115
+
116
+ Unless you have specific requirements otherwise, we recommend to **not** set
117
+ set the `Accept-Encoding` header on HTTParty requests. In this case, `Net::HTTP`
118
+ will set a sensible default compression scheme and automatically decompress the response.
119
+
120
+ If you explicitly set `Accept-Encoding`, there be dragons:
121
+
122
+ * If the HTTP response `Content-Encoding` received on the wire is `gzip` or `deflate`,
123
+ `Net::HTTP` will automatically decompress it, and will omit `Content-Encoding`
124
+ from your `HTTParty::Response` headers.
125
+
126
+ * For encodings `br` (Brotli) or `compress` (LZW), HTTParty will automatically
127
+ decompress if you include the `brotli` or `ruby-lzws` gems respectively into your project.
128
+ **Warning:** Support for these encodings is experimental and not fully battle-tested.
129
+ Similar to above, if decompression succeeds, `Content-Encoding` will be omitted
130
+ from your `HTTParty::Response` headers.
131
+
132
+ * For other encodings, `HTTParty::Response#body` will return the raw uncompressed byte string,
133
+ and you'll need to inspect the `Content-Encoding` response header and decompress it yourself.
134
+ In this case, `HTTParty::Response#parsed_response` will be `nil`.
135
+
136
+ * Lastly, you may use the `skip_decompression` option to disable all automatic decompression
137
+ and always get `HTTParty::Response#body` in its raw form along with the `Content-Encoding` header.
138
+
139
+ ```ruby
140
+ # Accept-Encoding=gzip,deflate can be safely assumed to be auto-decompressed
141
+
142
+ res = HTTParty.get('https://example.com/test.json', headers: { 'Accept-Encoding' => 'gzip,deflate,identity' })
143
+ JSON.parse(res.body) # safe
144
+
145
+
146
+ # Accept-Encoding=br,compress requires third-party gems
147
+
148
+ require 'brotli'
149
+ require 'lzws'
150
+ res = HTTParty.get('https://example.com/test.json', headers: { 'Accept-Encoding' => 'br,compress' })
151
+ JSON.parse(res.body)
152
+
153
+
154
+ # Accept-Encoding=* may return unhandled Content-Encoding
155
+
156
+ res = HTTParty.get('https://example.com/test.json', headers: { 'Accept-Encoding' => '*' })
157
+ encoding = res.headers['Content-Encoding']
158
+ if encoding
159
+ JSON.parse(your_decompression_handling(res.body, encoding))
160
+ else
161
+ # Content-Encoding not present implies decompressed
162
+ JSON.parse(res.body)
163
+ end
164
+
165
+
166
+ # Gimme the raw data!
167
+
168
+ res = HTTParty.get('https://example.com/test.json', skip_decompression: true)
169
+ encoding = res.headers['Content-Encoding']
170
+ JSON.parse(your_decompression_handling(res.body, encoding))
171
+ ```
data/examples/README.md CHANGED
@@ -81,3 +81,9 @@
81
81
 
82
82
  * [Uploading File](body_stream.rb)
83
83
  * Uses `body_stream` to upload file
84
+
85
+ * [Accessing x509 Peer Certificate](peer_cert.rb)
86
+ * Provides access to the server's TLS certificate
87
+
88
+ * [Accessing IDNs](idn.rb)
89
+ * Uses a `get` request with an International domain names, which are Urls with emojis and non-ASCII characters such as accented letters.
data/examples/aaws.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'active_support'
3
+ require 'active_support/core_ext/hash'
4
+ require 'active_support/core_ext/string'
3
5
 
4
6
  dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
5
7
  require File.join(dir, 'httparty')
@@ -13,14 +15,16 @@ module AAWS
13
15
  default_params Service: 'AWSECommerceService', Operation: 'ItemSearch', SearchIndex: 'Books'
14
16
 
15
17
  def initialize(key)
16
- self.class.default_params AWSAccessKeyId: key
18
+ @auth = { AWSAccessKeyId: key }
17
19
  end
18
20
 
19
21
  def search(options = {})
20
22
  raise ArgumentError, 'You must search for something' if options[:query].blank?
21
23
 
22
24
  # amazon uses nasty camelized query params
23
- options[:query] = options[:query].inject({}) { |h, q| h[q[0].to_s.camelize] = q[1]; h }
25
+ options[:query] = options[:query]
26
+ .reverse_merge(@auth)
27
+ .transform_keys { |k| k.to_s.camelize }
24
28
 
25
29
  # make a request and return the items (NOTE: this doesn't handle errors at this point)
26
30
  self.class.get('/onca/xml', options)['ItemSearchResponse']['Items']
data/examples/idn.rb ADDED
@@ -0,0 +1,10 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'pp'
4
+
5
+ class Idn
6
+ include HTTParty
7
+ uri_adapter Addressable::URI
8
+ end
9
+
10
+ pp Idn.get("https://i❤️.ws/emojidomain/💎?format=json")
@@ -0,0 +1,9 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+
4
+ peer_cert = nil
5
+ HTTParty.get("https://www.example.com") do |fragment|
6
+ peer_cert ||= fragment.connection.peer_cert
7
+ end
8
+
9
+ puts "The server's certificate expires #{peer_cert.not_after}"
data/httparty.gemspec CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
13
13
  s.summary = 'Makes http fun! Also, makes consuming restful web services dead easy.'
14
14
  s.description = 'Makes http fun! Also, makes consuming restful web services dead easy.'
15
15
 
16
- s.required_ruby_version = '>= 2.0.0'
16
+ s.required_ruby_version = '>= 2.3.0'
17
17
 
18
18
  s.add_dependency 'multi_xml', ">= 0.5.2"
19
19
  s.add_dependency('mime-types', "~> 3.0")
@@ -25,7 +25,6 @@ Gem::Specification.new do |s|
25
25
  test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
26
 
27
27
  s.files = all_files - test_files
28
- s.test_files = test_files
29
28
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
30
29
  s.require_paths = ["lib"]
31
30
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HTTParty
2
4
  # Default connection adapter that returns a new Net::HTTP each time
3
5
  #
@@ -42,6 +44,7 @@ module HTTParty
42
44
  # * :+timeout+: timeout in seconds
43
45
  # * :+open_timeout+: http connection open_timeout in seconds, overrides timeout if set
44
46
  # * :+read_timeout+: http connection read_timeout in seconds, overrides timeout if set
47
+ # * :+write_timeout+: http connection write_timeout in seconds, overrides timeout if set (Ruby >= 2.6.0 required)
45
48
  # * :+debug_output+: see HTTParty::ClassMethods.debug_output.
46
49
  # * :+cert_store+: contains certificate data. see method 'attach_ssl_certificates'
47
50
  # * :+pem+: contains pem client certificate data. see method 'attach_ssl_certificates'
@@ -113,19 +116,35 @@ module HTTParty
113
116
 
114
117
  attach_ssl_certificates(http, options)
115
118
 
116
- if options[:timeout] && (options[:timeout].is_a?(Integer) || options[:timeout].is_a?(Float))
119
+ if add_timeout?(options[:timeout])
117
120
  http.open_timeout = options[:timeout]
118
121
  http.read_timeout = options[:timeout]
122
+
123
+ from_ruby_version('2.6.0', option: :write_timeout, warn: false) do
124
+ http.write_timeout = options[:timeout]
125
+ end
119
126
  end
120
127
 
121
- if options[:read_timeout] && (options[:read_timeout].is_a?(Integer) || options[:read_timeout].is_a?(Float))
128
+ if add_timeout?(options[:read_timeout])
122
129
  http.read_timeout = options[:read_timeout]
123
130
  end
124
131
 
125
- if options[:open_timeout] && (options[:open_timeout].is_a?(Integer) || options[:open_timeout].is_a?(Float))
132
+ if add_timeout?(options[:open_timeout])
126
133
  http.open_timeout = options[:open_timeout]
127
134
  end
128
135
 
136
+ if add_timeout?(options[:write_timeout])
137
+ from_ruby_version('2.6.0', option: :write_timeout) do
138
+ http.write_timeout = options[:write_timeout]
139
+ end
140
+ end
141
+
142
+ if add_max_retries?(options[:max_retries])
143
+ from_ruby_version('2.5.0', option: :max_retries) do
144
+ http.max_retries = options[:max_retries]
145
+ end
146
+ end
147
+
129
148
  if options[:debug_output]
130
149
  http.set_debug_output(options[:debug_output])
131
150
  end
@@ -138,18 +157,14 @@ module HTTParty
138
157
  #
139
158
  # @see https://bugs.ruby-lang.org/issues/6617
140
159
  if options[:local_host]
141
- if RUBY_VERSION >= "2.0.0"
160
+ from_ruby_version('2.0.0', option: :local_host) do
142
161
  http.local_host = options[:local_host]
143
- else
144
- Kernel.warn("Warning: option :local_host requires Ruby version 2.0 or later")
145
162
  end
146
163
  end
147
164
 
148
165
  if options[:local_port]
149
- if RUBY_VERSION >= "2.0.0"
166
+ from_ruby_version('2.0.0', option: :local_port) do
150
167
  http.local_port = options[:local_port]
151
- else
152
- Kernel.warn("Warning: option :local_port requires Ruby version 2.0 or later")
153
168
  end
154
169
  end
155
170
 
@@ -158,6 +173,22 @@ module HTTParty
158
173
 
159
174
  private
160
175
 
176
+ def from_ruby_version(ruby_version, option: nil, warn: true)
177
+ if RUBY_VERSION >= ruby_version
178
+ yield
179
+ elsif warn
180
+ Kernel.warn("Warning: option #{ option } requires Ruby version #{ ruby_version } or later")
181
+ end
182
+ end
183
+
184
+ def add_timeout?(timeout)
185
+ timeout && (timeout.is_a?(Integer) || timeout.is_a?(Float))
186
+ end
187
+
188
+ def add_max_retries?(max_retries)
189
+ max_retries && max_retries.is_a?(Integer) && max_retries >= 0
190
+ end
191
+
161
192
  def clean_host(host)
162
193
  strip_ipv6_brackets(host)
163
194
  end
@@ -192,7 +223,7 @@ module HTTParty
192
223
  # Note: options[:pem] must contain the content of a PEM file having the private key appended
193
224
  if options[:pem]
194
225
  http.cert = OpenSSL::X509::Certificate.new(options[:pem])
195
- http.key = OpenSSL::PKey::RSA.new(options[:pem], options[:pem_password])
226
+ http.key = OpenSSL::PKey.read(options[:pem], options[:pem_password])
196
227
  http.verify_mode = verify_ssl_certificate? ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
197
228
  end
198
229
 
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class HTTParty::CookieHash < Hash #:nodoc:
2
- CLIENT_COOKIES = %w(path expires domain path secure httponly)
4
+ CLIENT_COOKIES = %w(path expires domain path secure httponly samesite)
3
5
 
4
- def add_cookies(value)
5
- case value
6
+ def add_cookies(data)
7
+ case data
6
8
  when Hash
7
- merge!(value)
9
+ merge!(data)
8
10
  when String
9
- value.split('; ').each do |cookie|
10
- array = cookie.split('=', 2)
11
- self[array[0].to_sym] = array[1]
11
+ data.split('; ').each do |cookie|
12
+ key, value = cookie.split('=', 2)
13
+ self[key.to_sym] = value if key
12
14
  end
13
15
  else
14
16
  raise "add_cookies only takes a Hash or a String"
@@ -16,6 +18,6 @@ class HTTParty::CookieHash < Hash #:nodoc:
16
18
  end
17
19
 
18
20
  def to_cookie_string
19
- select { |k, v| !CLIENT_COOKIES.include?(k.to_s.downcase) }.collect { |k, v| "#{k}=#{v}" }.join("; ")
21
+ select { |k, v| !CLIENT_COOKIES.include?(k.to_s.downcase) }.collect { |k, v| "#{k}=#{v}" }.join('; ')
20
22
  end
21
23
  end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTParty
4
+ # Decompresses the response body based on the Content-Encoding header.
5
+ #
6
+ # Net::HTTP automatically decompresses Content-Encoding values "gzip" and "deflate".
7
+ # This class will handle "br" (Brotli) and "compress" (LZW) if the requisite
8
+ # gems are installed. Otherwise, it returns nil if the body data cannot be
9
+ # decompressed.
10
+ #
11
+ # @abstract Read the HTTP Compression section for more information.
12
+ class Decompressor
13
+
14
+ # "gzip" and "deflate" are handled by Net::HTTP
15
+ # hence they do not need to be handled by HTTParty
16
+ SupportedEncodings = {
17
+ 'none' => :none,
18
+ 'identity' => :none,
19
+ 'br' => :brotli,
20
+ 'compress' => :lzw
21
+ }.freeze
22
+
23
+ # The response body of the request
24
+ # @return [String]
25
+ attr_reader :body
26
+
27
+ # The Content-Encoding algorithm used to encode the body
28
+ # @return [Symbol] e.g. :gzip
29
+ attr_reader :encoding
30
+
31
+ # @param [String] body - the response body of the request
32
+ # @param [Symbol] encoding - the Content-Encoding algorithm used to encode the body
33
+ def initialize(body, encoding)
34
+ @body = body
35
+ @encoding = encoding
36
+ end
37
+
38
+ # Perform decompression on the response body
39
+ # @return [String] the decompressed body
40
+ # @return [nil] when the response body is nil or cannot decompressed
41
+ def decompress
42
+ return nil if body.nil?
43
+ return body if encoding.nil? || encoding.strip.empty?
44
+
45
+ if supports_encoding?
46
+ decompress_supported_encoding
47
+ else
48
+ nil
49
+ end
50
+ end
51
+
52
+ protected
53
+
54
+ def supports_encoding?
55
+ SupportedEncodings.keys.include?(encoding)
56
+ end
57
+
58
+ def decompress_supported_encoding
59
+ method = SupportedEncodings[encoding]
60
+ if respond_to?(method, true)
61
+ send(method)
62
+ else
63
+ raise NotImplementedError, "#{self.class.name} has not implemented a decompression method for #{encoding.inspect} encoding."
64
+ end
65
+ end
66
+
67
+ def none
68
+ body
69
+ end
70
+
71
+ def brotli
72
+ return nil unless defined?(::Brotli)
73
+ begin
74
+ ::Brotli.inflate(body)
75
+ rescue StandardError
76
+ nil
77
+ end
78
+ end
79
+
80
+ def lzw
81
+ begin
82
+ if defined?(::LZWS::String)
83
+ ::LZWS::String.decompress(body)
84
+ elsif defined?(::LZW::Simple)
85
+ ::LZW::Simple.new.decompress(body)
86
+ end
87
+ rescue StandardError
88
+ nil
89
+ end
90
+ end
91
+ end
92
+ end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HTTParty
2
- # @abstact Exceptions raised by HTTParty inherit from Error
4
+ # @abstract Exceptions raised by HTTParty inherit from Error
3
5
  class Error < StandardError; end
4
6
 
5
7
  # Exception raised when you attempt to set a non-existent format
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'erb'
2
4
 
3
5
  module HTTParty
@@ -26,8 +28,8 @@ module HTTParty
26
28
  def self.normalize_param(key, value)
27
29
  normalized_keys = normalize_keys(key, value)
28
30
 
29
- normalized_keys.flatten.each_slice(2).inject('') do |string, (k, v)|
30
- string + "#{k}=#{ERB::Util.url_encode(v.to_s)}&"
31
+ normalized_keys.flatten.each_slice(2).inject(''.dup) do |string, (k, v)|
32
+ string << "#{ERB::Util.url_encode(k)}=#{ERB::Util.url_encode(v.to_s)}&"
31
33
  end
32
34
  end
33
35
 
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTParty
4
+ class HeadersProcessor
5
+ attr_reader :headers, :options
6
+
7
+ def initialize(headers, options)
8
+ @headers = headers
9
+ @options = options
10
+ end
11
+
12
+ def call
13
+ return unless options[:headers]
14
+
15
+ options[:headers] = headers.merge(options[:headers]) if headers.any?
16
+ options[:headers] = Utils.stringify_keys(process_dynamic_headers)
17
+ end
18
+
19
+ private
20
+
21
+ def process_dynamic_headers
22
+ options[:headers].each_with_object({}) do |header, processed_headers|
23
+ key, value = header
24
+ processed_headers[key] = if value.respond_to?(:call)
25
+ value.arity == 0 ? value.call : value.call(options)
26
+ else
27
+ value
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HTTParty
2
4
  module Logger
3
5
  class ApacheFormatter #:nodoc:
@@ -26,11 +28,11 @@ module HTTParty
26
28
  end
27
29
 
28
30
  def current_time
29
- Time.now.strftime("%Y-%m-%d %H:%M:%S %z")
31
+ Time.now.strftime('%Y-%m-%d %H:%M:%S %z')
30
32
  end
31
33
 
32
34
  def http_method
33
- request.http_method.name.split("::").last.upcase
35
+ request.http_method.name.split('::').last.upcase
34
36
  end
35
37
 
36
38
  def path