http 5.0.0.pre → 5.0.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
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