http 5.0.0.pre → 5.0.0.pre2

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +17 -1
  3. data/.travis.yml +6 -4
  4. data/CHANGES.md +83 -0
  5. data/Gemfile +2 -1
  6. data/README.md +7 -6
  7. data/http.gemspec +11 -4
  8. data/lib/http/chainable.rb +8 -3
  9. data/lib/http/client.rb +32 -34
  10. data/lib/http/connection.rb +5 -5
  11. data/lib/http/content_type.rb +2 -2
  12. data/lib/http/feature.rb +3 -0
  13. data/lib/http/features/auto_deflate.rb +13 -7
  14. data/lib/http/features/auto_inflate.rb +6 -5
  15. data/lib/http/features/normalize_uri.rb +17 -0
  16. data/lib/http/headers.rb +48 -11
  17. data/lib/http/headers/known.rb +3 -0
  18. data/lib/http/mime_type/adapter.rb +1 -1
  19. data/lib/http/mime_type/json.rb +1 -0
  20. data/lib/http/options.rb +4 -7
  21. data/lib/http/redirector.rb +3 -1
  22. data/lib/http/request.rb +32 -29
  23. data/lib/http/request/body.rb +26 -1
  24. data/lib/http/request/writer.rb +3 -2
  25. data/lib/http/response.rb +17 -15
  26. data/lib/http/response/body.rb +1 -0
  27. data/lib/http/response/parser.rb +20 -6
  28. data/lib/http/response/status.rb +2 -1
  29. data/lib/http/timeout/global.rb +1 -3
  30. data/lib/http/timeout/per_operation.rb +1 -0
  31. data/lib/http/uri.rb +13 -0
  32. data/lib/http/version.rb +1 -1
  33. data/spec/lib/http/client_spec.rb +96 -14
  34. data/spec/lib/http/connection_spec.rb +8 -5
  35. data/spec/lib/http/features/auto_inflate_spec.rb +4 -2
  36. data/spec/lib/http/features/instrumentation_spec.rb +7 -6
  37. data/spec/lib/http/features/logging_spec.rb +6 -5
  38. data/spec/lib/http/headers_spec.rb +52 -17
  39. data/spec/lib/http/options/headers_spec.rb +1 -1
  40. data/spec/lib/http/options/merge_spec.rb +16 -16
  41. data/spec/lib/http/redirector_spec.rb +15 -1
  42. data/spec/lib/http/request/body_spec.rb +22 -0
  43. data/spec/lib/http/request/writer_spec.rb +13 -1
  44. data/spec/lib/http/request_spec.rb +5 -5
  45. data/spec/lib/http/response/parser_spec.rb +45 -0
  46. data/spec/lib/http/response/status_spec.rb +3 -3
  47. data/spec/lib/http/response_spec.rb +11 -22
  48. data/spec/lib/http_spec.rb +30 -1
  49. data/spec/support/black_hole.rb +1 -1
  50. data/spec/support/dummy_server.rb +6 -6
  51. data/spec/support/dummy_server/servlet.rb +8 -4
  52. data/spec/support/http_handling_shared.rb +4 -4
  53. data/spec/support/ssl_helper.rb +4 -4
  54. metadata +23 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2825a470cfdf9fd2d231cfe42a5d9aa54286a5cd13e402a5988f9ebfccd5fea9
4
- data.tar.gz: ae9fbde0feda802b51bdb9926179d5c449d8ef9694d2c131eaf3226899236a7e
3
+ metadata.gz: cbaa69332ed43468d3388aa291c39b50104981ab648b25b3de6afe9f6272242d
4
+ data.tar.gz: 4d8aa977a340af1da8b7ce8386c66a37a48a13c4d50f36fdfc0ef7db09837132
5
5
  SHA512:
6
- metadata.gz: 7734a21527150dcf3e987d37c815930470e7a2620ceee1177b0885e6a23c10a571b040e16d1b2c6153c6a35c8e54aa89be1737a7e3d00c9e306caf33e4d199a2
7
- data.tar.gz: 1ce3516a9928a62f852d3e995686a44c9ad1cd837e63c4862d7680a70b3d435b05f153f8a602f6f555dfadb431bd6567649512e596e56f54ba5c19fa040408ff
6
+ metadata.gz: 12fdc45dc637e65dcda24a1e3c056a3f215d87229d60c8997b2c4c63754d4ac21c5872f4dddd03b2061b5ee2767e3558370fe7e0506b73444e09f730f5e6101d
7
+ data.tar.gz: 45af15139df31af3f99b31c5b554ad225c793d65c2b8506dd8b6469ee79be201832cdaa1bd22c510671fcdd3febf2b9844b168d18ef5b0ed9cc2cff7f83975f9
@@ -1,9 +1,15 @@
1
+ require: rubocop-performance
2
+
1
3
  AllCops:
2
4
  TargetRubyVersion: 2.3
3
5
  DisplayCopNames: true
4
6
 
5
7
  ## Layout ######################################################################
6
8
 
9
+ Layout/AlignHash:
10
+ EnforcedColonStyle: table
11
+ EnforcedHashRocketStyle: table
12
+
7
13
  Layout/DotPosition:
8
14
  EnforcedStyle: trailing
9
15
 
@@ -20,7 +26,8 @@ Metrics/AbcSize:
20
26
 
21
27
  Metrics/BlockLength:
22
28
  Exclude:
23
- - spec/**/*
29
+ - "spec/**/*"
30
+ - "**/*.gemspec"
24
31
 
25
32
  Metrics/BlockNesting:
26
33
  Max: 2
@@ -60,6 +67,9 @@ Metrics/ParameterLists:
60
67
  Performance/RegexpMatch:
61
68
  Enabled: false
62
69
 
70
+ Performance/UnfreezeString:
71
+ Enabled: false
72
+
63
73
  ## Style #######################################################################
64
74
 
65
75
  Style/CollectionMethods:
@@ -109,3 +119,9 @@ Style/TrivialAccessors:
109
119
 
110
120
  Style/YodaCondition:
111
121
  Enabled: false
122
+
123
+ Style/FormatStringToken:
124
+ EnforcedStyle: unannotated
125
+
126
+ Style/RescueStandardError:
127
+ EnforcedStyle: implicit
@@ -17,20 +17,22 @@ env: JRUBY_OPTS="$JRUBY_OPTS --debug"
17
17
 
18
18
  rvm:
19
19
  # Include JRuby first because it takes the longest
20
- - jruby-9.1.16.0
21
- - 2.3
20
+ - jruby-9.2.5.0
22
21
  - 2.4
23
22
  - 2.5
23
+ - 2.6
24
+ - 2.7
24
25
 
25
26
  matrix:
26
27
  fast_finish: true
27
28
  include:
28
29
  # Only run RuboCop and Yardstick metrics on the latest Ruby
29
- - rvm: 2.5
30
+ - rvm: 2.7
30
31
  env: SUITE="rubocop"
31
- - rvm: 2.5
32
+ - rvm: 2.7
32
33
  env: SUITE="yardstick"
33
34
 
34
35
  branches:
35
36
  only:
36
37
  - master
38
+ - 4-x-stable
data/CHANGES.md CHANGED
@@ -1,9 +1,89 @@
1
1
  ## future is unwritten (master)
2
2
 
3
+ * [#590](https://github.com/httprb/http/pull/590)
4
+ [#589](https://github.com/httprb/http/issues/589)
5
+ Fix response headers paring.
6
+ ([@Bonias])
7
+
8
+ * [#587](https://github.com/httprb/http/pull/587)
9
+ [#585](https://github.com/httprb/http/issues/585)
10
+ Fix redirections when server responds with multiple Location headers.
11
+ ([@ixti])
12
+
13
+ * [#581](https://github.com/httprb/http/pull/581)
14
+ [#582](https://github.com/httprb/http/issues/582)
15
+ Add Ruby 2.7.x support.
16
+ ([@janko])
17
+
18
+ * [#577](https://github.com/httprb/http/pull/577)
19
+ Fix `Chainable#timeout` with frozen Hash.
20
+ ([@antonvolkoff])
21
+
22
+ * [#576](https://github.com/httprb/http/pull/576)
23
+ [#524](https://github.com/httprb/http/issues/524)
24
+ Preserve header names casing.
25
+ ([@joshuaflanagan])
26
+
27
+ * [#532](https://github.com/httprb/http/pull/532)
28
+ Fix pipes support in request bodies.
29
+ ([@ixti])
30
+
31
+ * [#530](https://github.com/httprb/http/pull/530)
32
+ Improve header fields name/value validation.
33
+ ([@Bonias])
34
+
35
+ * [#506](https://github.com/httprb/http/pull/506)
36
+ [#521](https://github.com/httprb/http/issues/521)
37
+ Skip auto-deflate when there is no body.
38
+ ([@Bonias])
39
+
3
40
  * [#489](https://github.com/httprb/http/pull/489)
4
41
  Fix HTTP parser.
5
42
  ([@ixti], [@fxposter])
6
43
 
44
+ * [#546](https://github.com/httprb/http/pull/546)
45
+ **BREAKING CHANGE**
46
+ Provide initiating `HTTP::Request` object on `HTTP::Response`.
47
+ ([@joshuaflanagan])
48
+
49
+ * [#571](https://github.com/httprb/http/pull/571)
50
+ Drop Ruby 2.3.x support.
51
+ ([@ixti])
52
+
53
+
54
+ ## 4.2.0 (2019-10-22)
55
+
56
+ * Backport [#489](https://github.com/httprb/http/pull/489)
57
+ Fix HTTP parser.
58
+ ([@ixti], [@fxposter])
59
+
60
+
61
+ ## 4.1.1 (2019-03-12)
62
+
63
+ * Add `HTTP::Headers::ACCEPT_ENCODING` constant.
64
+ ([@ixti])
65
+
66
+
67
+ ## 4.1.0 (2019-03-11)
68
+
69
+ * [#533](https://github.com/httprb/http/pull/533)
70
+ Add URI normalizer feature that allows to swap default URI normalizer.
71
+ ([@mamoonraja])
72
+
73
+
74
+ ## 4.0.5 (2019-02-15)
75
+
76
+ * Backport [#532](https://github.com/httprb/http/pull/532) from master.
77
+ Fix pipes support in request bodies.
78
+ ([@ixti])
79
+
80
+
81
+ ## 4.0.4 (2019-02-12)
82
+
83
+ * Backport [#506](https://github.com/httprb/http/pull/506) from master.
84
+ Skip auto-deflate when there is no body.
85
+ ([@Bonias])
86
+
7
87
 
8
88
  ## 4.0.3 (2019-01-18)
9
89
 
@@ -752,3 +832,6 @@ end
752
832
  [@paul]: https://github.com/paul
753
833
  [@RickCSong]: https://github.com/RickCSong
754
834
  [@fxposter]: https://github.com/fxposter
835
+ [@mamoonraja]: https://github.com/mamoonraja
836
+ [@joshuaflanagan]: https://github.com/joshuaflanagan
837
+ [@antonvolkoff]: https://github.com/antonvolkoff
data/Gemfile CHANGED
@@ -28,7 +28,8 @@ group :test do
28
28
  gem "rspec", "~> 3.0"
29
29
  gem "rspec-its"
30
30
 
31
- gem "rubocop", "= 0.49.1"
31
+ gem "rubocop", "= 0.68.1"
32
+ gem "rubocop-performance"
32
33
 
33
34
  gem "yardstick"
34
35
  end
data/README.md CHANGED
@@ -18,13 +18,14 @@ HTTP (The Gem! a.k.a. http.rb) is an easy-to-use client library for making reque
18
18
  from Ruby. It uses a simple method chaining system for building requests, similar to
19
19
  Python's [Requests].
20
20
 
21
- Under the hood, http.rb uses [http_parser.rb], a fast HTTP parsing native
22
- extension based on the Node.js parser and a Java port thereof. This library
21
+ Under the hood, via [Ruby FFI bindings][http-parser-ffi], http.rb uses the Node.js
22
+ [http-parser], a fast HTTP parsing native extension. This library
23
23
  isn't just yet another wrapper around Net::HTTP. It implements the HTTP protocol
24
24
  natively and outsources the parsing to native extensions.
25
25
 
26
26
  [requests]: http://docs.python-requests.org/en/latest/
27
- [http_parser.rb]: https://github.com/tmm1/http_parser.rb
27
+ [http-parser]: https://github.com/nodejs/http-parser
28
+ [http-parser-ffi]: https://github.com/cotag/http-parser
28
29
 
29
30
 
30
31
  ## Another Ruby HTTP library? Why should I care?
@@ -164,10 +165,10 @@ and call `#readpartial` on it repeatedly until it returns `nil`:
164
165
  This library aims to support and is [tested against][travis] the following Ruby
165
166
  versions:
166
167
 
167
- * Ruby 2.3.x
168
168
  * Ruby 2.4.x
169
169
  * Ruby 2.5.x
170
- * JRuby 9.1.x.x
170
+ * Ruby 2.6.x
171
+ * JRuby 9.2.x.x
171
172
 
172
173
  If something doesn't work on one of these versions, it's a bug.
173
174
 
@@ -197,5 +198,5 @@ dropped.
197
198
 
198
199
  ## Copyright
199
200
 
200
- Copyright (c) 2011-2018 Tony Arcieri, Alexey V. Zapparov, Erik Michaels-Ober, Zachary Anker.
201
+ Copyright (c) 2011-2019 Tony Arcieri, Alexey V. Zapparov, Erik Michaels-Ober, Zachary Anker.
201
202
  See LICENSE.txt for further details.
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path("../lib", __FILE__)
3
+ lib = File.expand_path("lib", __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "http/version"
6
6
 
@@ -27,10 +27,17 @@ Gem::Specification.new do |gem|
27
27
 
28
28
  gem.required_ruby_version = ">= 2.3"
29
29
 
30
- gem.add_runtime_dependency "http-parser", "~> 1.2.0"
31
- gem.add_runtime_dependency "http-form_data", "~> 2.0"
32
- gem.add_runtime_dependency "http-cookie", "~> 1.0"
33
30
  gem.add_runtime_dependency "addressable", "~> 2.3"
31
+ gem.add_runtime_dependency "http-cookie", "~> 1.0"
32
+ gem.add_runtime_dependency "http-form_data", "~> 2.2"
33
+ gem.add_runtime_dependency "http-parser", "~> 1.2.0"
34
34
 
35
35
  gem.add_development_dependency "bundler", "~> 2.0"
36
+
37
+ gem.metadata = {
38
+ "source_code_uri" => "https://github.com/httprb/http",
39
+ "wiki_uri" => "https://github.com/httprb/http/wiki",
40
+ "bug_tracker_uri" => "https://github.com/httprb/http/issues",
41
+ "changelog_uri" => "https://github.com/httprb/http/blob/v#{HTTP::VERSION}/CHANGES.md"
42
+ }
36
43
  end
@@ -93,7 +93,7 @@ module HTTP
93
93
  def timeout(options)
94
94
  klass, options = case options
95
95
  when Numeric then [HTTP::Timeout::Global, {:global => options}]
96
- when Hash then [HTTP::Timeout::PerOperation, options]
96
+ when Hash then [HTTP::Timeout::PerOperation, options.dup]
97
97
  when :null then [HTTP::Timeout::Null, {}]
98
98
  else raise ArgumentError, "Use `.timeout(global_timeout_in_seconds)` or `.timeout(connect: x, write: y, read: z)`."
99
99
 
@@ -101,11 +101,12 @@ module HTTP
101
101
 
102
102
  %i[global read write connect].each do |k|
103
103
  next unless options.key? k
104
+
104
105
  options["#{k}_timeout".to_sym] = options.delete k
105
106
  end
106
107
 
107
108
  branch default_options.merge(
108
- :timeout_class => klass,
109
+ :timeout_class => klass,
109
110
  :timeout_options => options
110
111
  )
111
112
  end
@@ -144,6 +145,7 @@ module HTTP
144
145
  options = {:keep_alive_timeout => timeout}
145
146
  p_client = branch default_options.merge(options).with_persistent host
146
147
  return p_client unless block_given?
148
+
147
149
  yield p_client
148
150
  ensure
149
151
  p_client.close if p_client
@@ -168,7 +170,7 @@ module HTTP
168
170
  alias through via
169
171
 
170
172
  # Make client follow redirects.
171
- # @param opts
173
+ # @param options
172
174
  # @return [HTTP::Client]
173
175
  # @see Redirector#initialize
174
176
  def follow(options = {}) # rubocop:disable Style/OptionHash
@@ -236,6 +238,9 @@ module HTTP
236
238
  # Turn on given features. Available features are:
237
239
  # * auto_inflate
238
240
  # * auto_deflate
241
+ # * instrumentation
242
+ # * logging
243
+ # * normalize_uri
239
244
  # @param features
240
245
  def use(*features)
241
246
  branch default_options.with_features(features)
@@ -16,7 +16,7 @@ module HTTP
16
16
  extend Forwardable
17
17
  include Chainable
18
18
 
19
- HTTP_OR_HTTPS_RE = %r{^https?://}i
19
+ HTTP_OR_HTTPS_RE = %r{^https?://}i.freeze
20
20
 
21
21
  def initialize(default_options = {})
22
22
  @default_options = HTTP::Options.new(default_options)
@@ -42,14 +42,14 @@ module HTTP
42
42
  uri = make_request_uri(uri, opts)
43
43
  headers = make_request_headers(opts)
44
44
  body = make_request_body(opts, headers)
45
- proxy = opts.proxy
46
45
 
47
46
  req = HTTP::Request.new(
48
- :verb => verb,
49
- :uri => uri,
50
- :headers => headers,
51
- :proxy => proxy,
52
- :body => body
47
+ :verb => verb,
48
+ :uri => uri,
49
+ :uri_normalizer => opts.feature(:normalize_uri)&.normalizer,
50
+ :proxy => opts.proxy,
51
+ :headers => headers,
52
+ :body => body
53
53
  )
54
54
 
55
55
  opts.features.inject(req) do |request, (_name, feature)|
@@ -70,20 +70,18 @@ module HTTP
70
70
 
71
71
  @connection ||= HTTP::Connection.new(req, options)
72
72
 
73
- unless @connection.failed_proxy_connect?
74
- @connection.send_request(req)
75
- @connection.read_headers!
73
+ begin
74
+ unless @connection.failed_proxy_connect?
75
+ @connection.send_request(req)
76
+ @connection.read_headers!
77
+ end
78
+ rescue Error => e
79
+ options.features.each_value do |feature|
80
+ feature.on_error(req, e)
81
+ end
82
+ raise
76
83
  end
77
-
78
- res = Response.new(
79
- :status => @connection.status_code,
80
- :version => @connection.http_version,
81
- :headers => @connection.headers,
82
- :proxy_headers => @connection.proxy_response_headers,
83
- :connection => @connection,
84
- :encoding => options.encoding,
85
- :uri => req.uri
86
- )
84
+ res = build_response(req, options)
87
85
 
88
86
  res = options.features.inject(res) do |response, (_name, feature)|
89
87
  feature.wrap_response(response)
@@ -106,6 +104,18 @@ module HTTP
106
104
 
107
105
  private
108
106
 
107
+ def build_response(req, options)
108
+ Response.new(
109
+ :status => @connection.status_code,
110
+ :version => @connection.http_version,
111
+ :headers => @connection.headers,
112
+ :proxy_headers => @connection.proxy_response_headers,
113
+ :connection => @connection,
114
+ :encoding => options.encoding,
115
+ :request => req
116
+ )
117
+ end
118
+
109
119
  # Verify our request isn't going to be made against another URI
110
120
  def verify_connection!(uri)
111
121
  if default_options.persistent? && uri.origin != default_options.persistent
@@ -128,15 +138,11 @@ module HTTP
128
138
  def make_request_uri(uri, opts)
129
139
  uri = uri.to_s
130
140
 
131
- if default_options.persistent? && uri !~ HTTP_OR_HTTPS_RE
132
- uri = "#{default_options.persistent}#{uri}"
133
- end
141
+ uri = "#{default_options.persistent}#{uri}" if default_options.persistent? && uri !~ HTTP_OR_HTTPS_RE
134
142
 
135
143
  uri = HTTP::URI.parse uri
136
144
 
137
- if opts.params && !opts.params.empty?
138
- uri.query_values = uri.query_values(Array).to_a.concat(opts.params.to_a)
139
- end
145
+ uri.query_values = uri.query_values(Array).to_a.concat(opts.params.to_a) if opts.params && !opts.params.empty?
140
146
 
141
147
  # Some proxies (seen on WEBRick) fail if URL has
142
148
  # empty path (e.g. `http://example.com`) while it's RFC-complaint:
@@ -160,14 +166,6 @@ module HTTP
160
166
  headers[Headers::COOKIE] = cookies
161
167
  end
162
168
 
163
- if (auto_deflate = opts.feature(:auto_deflate))
164
- # We need to delete Content-Length header. It will be set automatically
165
- # by HTTP::Request::Writer
166
- headers.delete(Headers::CONTENT_LENGTH)
167
-
168
- headers[Headers::CONTENT_ENCODING] = auto_deflate.method
169
- end
170
-
171
169
  headers
172
170
  end
173
171
 
@@ -45,8 +45,8 @@ module HTTP
45
45
  send_proxy_connect_request(req)
46
46
  start_tls(req, options)
47
47
  reset_timer
48
- rescue IOError, SocketError, SystemCallError => ex
49
- raise ConnectionError, "failed to connect: #{ex}", ex.backtrace
48
+ rescue IOError, SocketError, SystemCallError => e
49
+ raise ConnectionError, "failed to connect: #{e}", e.backtrace
50
50
  end
51
51
 
52
52
  # @see (HTTP::Response::Parser#status_code)
@@ -93,7 +93,7 @@ module HTTP
93
93
  chunk = @parser.read(size)
94
94
  finish_response if finished
95
95
 
96
- chunk.to_s
96
+ chunk || "".b
97
97
  end
98
98
 
99
99
  # Reads data from socket up until headers are loaded
@@ -216,8 +216,8 @@ module HTTP
216
216
  elsif value
217
217
  @parser << value
218
218
  end
219
- rescue IOError, SocketError, SystemCallError => ex
220
- raise ConnectionError, "error reading from socket: #{ex}", ex.backtrace
219
+ rescue IOError, SocketError, SystemCallError => e
220
+ raise ConnectionError, "error reading from socket: #{e}", e.backtrace
221
221
  end
222
222
  end
223
223
  end