http 3.3.0 → 4.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +3 -1
  4. data/.travis.yml +10 -7
  5. data/CHANGES.md +135 -0
  6. data/README.md +14 -10
  7. data/Rakefile +1 -1
  8. data/http.gemspec +12 -5
  9. data/lib/http.rb +1 -2
  10. data/lib/http/chainable.rb +20 -29
  11. data/lib/http/client.rb +25 -19
  12. data/lib/http/connection.rb +5 -9
  13. data/lib/http/feature.rb +14 -0
  14. data/lib/http/features/auto_deflate.rb +27 -6
  15. data/lib/http/features/auto_inflate.rb +33 -6
  16. data/lib/http/features/instrumentation.rb +64 -0
  17. data/lib/http/features/logging.rb +55 -0
  18. data/lib/http/features/normalize_uri.rb +17 -0
  19. data/lib/http/headers/known.rb +3 -0
  20. data/lib/http/options.rb +27 -21
  21. data/lib/http/redirector.rb +2 -1
  22. data/lib/http/request.rb +38 -30
  23. data/lib/http/request/body.rb +30 -1
  24. data/lib/http/request/writer.rb +21 -7
  25. data/lib/http/response.rb +7 -15
  26. data/lib/http/response/parser.rb +56 -16
  27. data/lib/http/timeout/global.rb +12 -14
  28. data/lib/http/timeout/per_operation.rb +5 -7
  29. data/lib/http/uri.rb +13 -0
  30. data/lib/http/version.rb +1 -1
  31. data/spec/lib/http/client_spec.rb +34 -7
  32. data/spec/lib/http/features/auto_inflate_spec.rb +38 -22
  33. data/spec/lib/http/features/instrumentation_spec.rb +56 -0
  34. data/spec/lib/http/features/logging_spec.rb +67 -0
  35. data/spec/lib/http/redirector_spec.rb +13 -0
  36. data/spec/lib/http/request/body_spec.rb +51 -0
  37. data/spec/lib/http/request/writer_spec.rb +20 -0
  38. data/spec/lib/http/request_spec.rb +6 -0
  39. data/spec/lib/http/response/parser_spec.rb +45 -0
  40. data/spec/lib/http/response_spec.rb +3 -4
  41. data/spec/lib/http_spec.rb +45 -65
  42. data/spec/regression_specs.rb +7 -0
  43. data/spec/support/dummy_server/servlet.rb +5 -0
  44. data/spec/support/http_handling_shared.rb +60 -64
  45. metadata +32 -21
  46. data/.ruby-version +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 853087de359024f397422b0563f0232edfa247c2f201a060c10b7b8ea9aff00b
4
- data.tar.gz: b07ad1d88da70f9d76c5e272923dab3ce763077a8f8f7cb9ee6c37602acb6bb5
3
+ metadata.gz: cce9a8685f3b60f994e77174f79c2306f607d62016bf64b74fcebc4f86377ec0
4
+ data.tar.gz: 353702b62a1b9d3b2ea86ac5ac3ad88e9efa734c77e180128fa06c6c301895d3
5
5
  SHA512:
6
- metadata.gz: 654f47604b4e77c1138f9b82b5b902bf5d47f3bdc73979594633fc1d15c991eab5d933f001f1e6671bd432c498127f9b3ddb89cc2dc93fd3b792461961f1f1a0
7
- data.tar.gz: 4f8e97ea9830b1f36d5a0d636807e3f1296176640c2876d0f66c59d0643954e663d5c35ab14a538220b5f669195109a367b70d6ad281898ecb3830ce573cd485
6
+ metadata.gz: 84ddc4cf98e603d175a9ecb8db03abd32187888070abd96a437c4121750ac2b86b6cada5d00d527b398ff4a403c2b6448d45bed61c45dbd3be8658f4ad38b121
7
+ data.tar.gz: 750edced9ae715483d750f0b18777f84a4ee24848ec761c67d2c5b89d00ebbc99fbc1e02932d3d30a33eaea43e1d081ba97bcacaf2231f6693e50d218ee24e87
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  .bundle
3
3
  .config
4
4
  .rvmrc
5
+ .ruby-version
5
6
  .yardoc
6
7
  Gemfile.lock
7
8
  InstalledFiles
data/.rubocop.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  AllCops:
2
+ TargetRubyVersion: 2.3
2
3
  DisplayCopNames: true
3
4
 
4
5
  ## Layout ######################################################################
@@ -19,7 +20,8 @@ Metrics/AbcSize:
19
20
 
20
21
  Metrics/BlockLength:
21
22
  Exclude:
22
- - spec/**/*
23
+ - "spec/**/*"
24
+ - "**/*.gemspec"
23
25
 
24
26
  Metrics/BlockNesting:
25
27
  Max: 2
data/.travis.yml CHANGED
@@ -6,7 +6,7 @@ cache: bundler
6
6
  before_install:
7
7
  - gem update --system
8
8
  - gem --version
9
- - gem install bundler --no-rdoc --no-ri
9
+ - gem install bundler --no-document
10
10
  - bundle --version
11
11
 
12
12
  install: bundle install --without development doc
@@ -17,20 +17,23 @@ 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.13.0
21
- - 2.2
22
- - 2.3.4
23
- - 2.4.1
20
+ - jruby-9.2.5.0
21
+ - 2.3
22
+ - 2.4
23
+ - 2.5
24
+ - 2.6
25
+ - 2.7
24
26
 
25
27
  matrix:
26
28
  fast_finish: true
27
29
  include:
28
30
  # Only run RuboCop and Yardstick metrics on the latest Ruby
29
- - rvm: 2.4.1
31
+ - rvm: 2.7
30
32
  env: SUITE="rubocop"
31
- - rvm: 2.4.1
33
+ - rvm: 2.7
32
34
  env: SUITE="yardstick"
33
35
 
34
36
  branches:
35
37
  only:
36
38
  - master
39
+ - 4-x-stable
data/CHANGES.md CHANGED
@@ -1,3 +1,134 @@
1
+ ## 4.4.1 (2020-03-29)
2
+
3
+ * Backport [#590](https://github.com/httprb/http/pull/590)
4
+ Fix parser failing on some edge cases.
5
+ ([@ixti])
6
+
7
+ ## 4.4.0 (2020-03-25)
8
+
9
+ * Backport [#587](https://github.com/httprb/http/pull/587)
10
+ Fix redirections when server responds with multiple Location headers.
11
+ ([@ixti])
12
+
13
+ * Backport [#599](https://github.com/httprb/http/pull/599)
14
+ Allow passing HTTP::FormData::{Multipart,UrlEncoded} object directly.
15
+ ([@ixti])
16
+
17
+ ## 4.3.0 (2020-01-09)
18
+
19
+ * Backport [#581](https://github.com/httprb/http/pull/581)
20
+ Add Ruby-2.7 compatibility.
21
+ ([@ixti], [@janko])
22
+
23
+
24
+ ## 4.2.0 (2019-10-22)
25
+
26
+ * Backport [#489](https://github.com/httprb/http/pull/489)
27
+ Fix HTTP parser.
28
+ ([@ixti], [@fxposter])
29
+
30
+
31
+ ## 4.1.1 (2019-03-12)
32
+
33
+ * Add `HTTP::Headers::ACCEPT_ENCODING` constant.
34
+ ([@ixti])
35
+
36
+
37
+ ## 4.1.0 (2019-03-11)
38
+
39
+ * [#533](https://github.com/httprb/http/pull/533)
40
+ Add URI normalizer feature that allows to swap default URI normalizer.
41
+ ([@mamoonraja])
42
+
43
+
44
+ ## 4.0.5 (2019-02-15)
45
+
46
+ * Backport [#532](https://github.com/httprb/http/pull/532) from master.
47
+ Fix pipes support in request bodies.
48
+ ([@ixti])
49
+
50
+
51
+ ## 4.0.4 (2019-02-12)
52
+
53
+ * Backport [#506](https://github.com/httprb/http/pull/506) from master.
54
+ Skip auto-deflate when there is no body.
55
+ ([@Bonias])
56
+
57
+
58
+ ## 4.0.3 (2019-01-18)
59
+
60
+ * Fix missing URL in response wrapped by auto inflate.
61
+ ([@ixti])
62
+
63
+ * Provide `HTTP::Request#inspect` method for debugging purposes.
64
+ ([@ixti])
65
+
66
+
67
+ ## 4.0.2 (2019-01-15)
68
+
69
+ * [#506](https://github.com/httprb/http/pull/506)
70
+ Fix instrumentation feature.
71
+ ([@paul])
72
+
73
+
74
+ ## 4.0.1 (2019-01-14)
75
+
76
+ * [#515](https://github.com/httprb/http/pull/515)
77
+ Fix `#build_request` and `#request` to respect default options.
78
+ ([@RickCSong])
79
+
80
+
81
+ ## 4.0.0 (2018-10-15)
82
+
83
+ * [#482](https://github.com/httprb/http/pull/482)
84
+ [#499](https://github.com/httprb/http/pull/499)
85
+ Introduce new features injection API with 2 new feaures: instrumentation
86
+ (compatible with ActiveSupport::Notification) and logging.
87
+ ([@paul])
88
+
89
+ * [#473](https://github.com/httprb/http/pull/473)
90
+ Handle early responses.
91
+ ([@janko-m])
92
+
93
+ * [#468](https://github.com/httprb/http/pull/468)
94
+ Rewind `HTTP::Request::Body#source` once `#each` is complete.
95
+ ([@ixti])
96
+
97
+ * [#467](https://github.com/httprb/http/pull/467)
98
+ Drop Ruby 2.2 support.
99
+ ([@ixti])
100
+
101
+ * [#436](https://github.com/httprb/http/pull/436)
102
+ Raise ConnectionError when writing to socket fails.
103
+ ([@janko-m])
104
+
105
+ * [#438](https://github.com/httprb/http/pull/438)
106
+ Expose `HTTP::Request::Body#source`.
107
+ ([@janko-m])
108
+
109
+ * [#446](https://github.com/httprb/http/pull/446)
110
+ Simplify setting a timeout.
111
+ ([@mikegee])
112
+
113
+ * [#451](https://github.com/httprb/http/pull/451)
114
+ Reduce memory usage when reading response body.
115
+ ([@janko-m])
116
+
117
+ * [#458](https://github.com/httprb/http/pull/458)
118
+ Extract HTTP::Client#build_request method.
119
+ ([@tycoon])
120
+
121
+ * [#462](https://github.com/httprb/http/pull/462)
122
+ Fix HTTP::Request#headline to allow two leading slashes in path.
123
+ ([@scarfacedeb])
124
+
125
+ * [#454](https://github.com/httprb/http/pull/454)
126
+ [#464](https://github.com/httprb/http/pull/464)
127
+ [#384](https://github.com/httprb/http/issues/384)
128
+ Fix #readpartial not respecting max length argument.
129
+ ([@janko-m], [@marshall-lee])
130
+
131
+
1
132
  ## 3.3.0 (2018-04-25)
2
133
 
3
134
  This version backports some of the fixes and improvements made to development
@@ -668,3 +799,7 @@ end
668
799
  [@scarfacedeb]: https://github.com/scarfacedeb
669
800
  [@mikegee]: https://github.com/mikegee
670
801
  [@tycoon]: https://github.com/tycooon
802
+ [@paul]: https://github.com/paul
803
+ [@RickCSong]: https://github.com/RickCSong
804
+ [@fxposter]: https://github.com/fxposter
805
+ [@mamoonraja]: https://github.com/mamoonraja
data/README.md CHANGED
@@ -1,15 +1,16 @@
1
1
  # ![http.rb](https://raw.github.com/httprb/http.rb/master/logo.png)
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/http.svg)](https://rubygems.org/gems/http)
4
- [![Build Status](https://secure.travis-ci.org/httprb/http.svg?branch=master)](https://travis-ci.org/httprb/http)
5
- [![Code Climate](https://codeclimate.com/github/httprb/http.svg?branch=master)](https://codeclimate.com/github/httprb/http)
6
- [![Coverage Status](https://coveralls.io/repos/httprb/http/badge.svg?branch=master)](https://coveralls.io/r/httprb/http)
7
- [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/httprb/http/blob/master/LICENSE.txt)
4
+ [![Build Status](https://secure.travis-ci.org/httprb/http.svg?branch=4-x-stable)](https://travis-ci.org/httprb/http)
5
+ [![Code Climate](https://codeclimate.com/github/httprb/http.svg?branch=4-x-stable)](https://codeclimate.com/github/httprb/http)
6
+ [![Coverage Status](https://coveralls.io/repos/httprb/http/badge.svg?branch=4-x-stable)](https://coveralls.io/r/httprb/http)
7
+ [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/httprb/http/blob/4-x-stable/LICENSE.txt)
8
8
 
9
- _NOTE: This is the 3.x **stable** branch. For the 4.x **development** branch, please see:_
9
+ [Documentation]
10
10
 
11
- https://github.com/httprb/http/
11
+ _NOTE: This is the 4.x **stable** branch. For the 3.x **stable** branch, please see:_
12
12
 
13
+ https://github.com/httprb/http/tree/3-x-stable
13
14
 
14
15
  ## About
15
16
 
@@ -108,7 +109,7 @@ require "http"
108
109
 
109
110
  ## Documentation
110
111
 
111
- [Please see the http.rb wiki](https://github.com/httprb/http/wiki)
112
+ [Please see the http.rb wiki][documentation]
112
113
  for more detailed documentation and usage notes.
113
114
 
114
115
  The following API documentation is also available:
@@ -116,6 +117,8 @@ The following API documentation is also available:
116
117
  * [YARD API documentation](http://www.rubydoc.info/gems/http/frames)
117
118
  * [Chainable module (all chainable methods)](http://www.rubydoc.info/gems/http/HTTP/Chainable)
118
119
 
120
+ [documentation]: https://github.com/httprb/http/wiki
121
+
119
122
  ### Basic Usage
120
123
 
121
124
  Here's some simple examples to get you started:
@@ -161,10 +164,11 @@ and call `#readpartial` on it repeatedly until it returns `nil`:
161
164
  This library aims to support and is [tested against][travis] the following Ruby
162
165
  versions:
163
166
 
164
- * Ruby 2.2.x
165
167
  * Ruby 2.3.x
166
168
  * Ruby 2.4.x
167
- * JRuby 9.1.x.x
169
+ * Ruby 2.5.x
170
+ * Ruby 2.6.x
171
+ * JRuby 9.2.x.x
168
172
 
169
173
  If something doesn't work on one of these versions, it's a bug.
170
174
 
@@ -194,5 +198,5 @@ dropped.
194
198
 
195
199
  ## Copyright
196
200
 
197
- 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.
198
202
  See LICENSE.txt for further details.
data/Rakefile CHANGED
@@ -25,7 +25,7 @@ task :generate_status_codes do
25
25
 
26
26
  url = "http://www.iana.org/assignments/http-status-codes/http-status-codes.xml"
27
27
  xml = Nokogiri::XML HTTP.get url
28
- arr = xml.xpath("//xmlns:record").reduce [] do |a, e|
28
+ arr = xml.xpath("//xmlns:record").reduce([]) do |a, e|
29
29
  code = e.xpath("xmlns:value").text.to_s
30
30
  desc = e.xpath("xmlns:description").text.to_s
31
31
 
data/http.gemspec CHANGED
@@ -25,12 +25,19 @@ Gem::Specification.new do |gem|
25
25
  gem.require_paths = ["lib"]
26
26
  gem.version = HTTP::VERSION
27
27
 
28
- gem.required_ruby_version = ">= 2.2"
28
+ gem.required_ruby_version = ">= 2.3"
29
29
 
30
- gem.add_runtime_dependency "http_parser.rb", "~> 0.6.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
+
35
+ gem.add_development_dependency "bundler", "~> 2.0"
34
36
 
35
- gem.add_development_dependency "bundler", "~> 1.0"
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
data/lib/http.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "http/parser"
4
-
5
3
  require "http/errors"
6
4
  require "http/timeout/null"
7
5
  require "http/timeout/per_operation"
@@ -10,6 +8,7 @@ require "http/chainable"
10
8
  require "http/client"
11
9
  require "http/connection"
12
10
  require "http/options"
11
+ require "http/feature"
13
12
  require "http/request"
14
13
  require "http/request/writer"
15
14
  require "http/response"
@@ -70,45 +70,36 @@ module HTTP
70
70
  end
71
71
 
72
72
  # Make an HTTP request with the given verb
73
- # @param verb
74
- # @param uri
75
- # @option options [Hash]
76
- def request(verb, uri, options = {}) # rubocop:disable Style/OptionHash
77
- branch(options).request verb, uri
73
+ # @param (see Client#request)
74
+ def request(*args)
75
+ branch(default_options).request(*args)
78
76
  end
79
77
 
80
78
  # Prepare an HTTP request with the given verb
81
- # @param verb
82
- # @param uri
83
- # @option options [Hash]
84
- def build_request(verb, uri, options = {}) # rubocop:disable Style/OptionHash
85
- branch(options).build_request verb, uri
79
+ # @param (see Client#build_request)
80
+ def build_request(*args)
81
+ branch(default_options).build_request(*args)
86
82
  end
87
83
 
88
84
  # @overload timeout(options = {})
89
- # Syntax sugar for `timeout(:per_operation, options)`
90
- # @overload timeout(klass, options = {})
91
- # Adds a timeout to the request.
92
- # @param [#to_sym] klass
93
- # either :null, :global, or :per_operation
85
+ # Adds per operation timeouts to the request
94
86
  # @param [Hash] options
95
87
  # @option options [Float] :read Read timeout
96
88
  # @option options [Float] :write Write timeout
97
89
  # @option options [Float] :connect Connect timeout
98
- def timeout(klass, options = {}) # rubocop:disable Style/OptionHash
99
- if klass.is_a? Hash
100
- options = klass
101
- klass = :per_operation
102
- end
103
-
104
- klass = case klass.to_sym
105
- when :null then HTTP::Timeout::Null
106
- when :global then HTTP::Timeout::Global
107
- when :per_operation then HTTP::Timeout::PerOperation
108
- else raise ArgumentError, "Unsupported Timeout class: #{klass}"
109
- end
110
-
111
- %i[read write connect].each do |k|
90
+ # @overload timeout(global_timeout)
91
+ # Adds a global timeout to the full request
92
+ # @param [Numeric] global_timeout
93
+ def timeout(options)
94
+ klass, options = case options
95
+ when Numeric then [HTTP::Timeout::Global, {:global => options}]
96
+ when Hash then [HTTP::Timeout::PerOperation, options]
97
+ when :null then [HTTP::Timeout::Null, {}]
98
+ else raise ArgumentError, "Use `.timeout(global_timeout_in_seconds)` or `.timeout(connect: x, write: y, read: z)`."
99
+
100
+ end
101
+
102
+ %i[global read write connect].each do |k|
112
103
  next unless options.key? k
113
104
  options["#{k}_timeout".to_sym] = options.delete k
114
105
  end
data/lib/http/client.rb CHANGED
@@ -4,6 +4,7 @@ require "forwardable"
4
4
 
5
5
  require "http/form_data"
6
6
  require "http/options"
7
+ require "http/feature"
7
8
  require "http/headers"
8
9
  require "http/connection"
9
10
  require "http/redirector"
@@ -41,16 +42,19 @@ module HTTP
41
42
  uri = make_request_uri(uri, opts)
42
43
  headers = make_request_headers(opts)
43
44
  body = make_request_body(opts, headers)
44
- proxy = opts.proxy
45
-
46
- HTTP::Request.new(
47
- :verb => verb,
48
- :uri => uri,
49
- :headers => headers,
50
- :proxy => proxy,
51
- :body => body,
52
- :auto_deflate => opts.feature(:auto_deflate)
45
+
46
+ req = HTTP::Request.new(
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
+
55
+ opts.features.inject(req) do |request, (_name, feature)|
56
+ feature.wrap_request(request)
57
+ end
54
58
  end
55
59
 
56
60
  # @!method persistent?
@@ -78,10 +82,13 @@ module HTTP
78
82
  :proxy_headers => @connection.proxy_response_headers,
79
83
  :connection => @connection,
80
84
  :encoding => options.encoding,
81
- :auto_inflate => options.feature(:auto_inflate),
82
85
  :uri => req.uri
83
86
  )
84
87
 
88
+ res = options.features.inject(res) do |response, (_name, feature)|
89
+ feature.wrap_response(response)
90
+ end
91
+
85
92
  @connection.finish_response if req.verb == :head
86
93
  @state = :clean
87
94
 
@@ -153,14 +160,6 @@ module HTTP
153
160
  headers[Headers::COOKIE] = cookies
154
161
  end
155
162
 
156
- if (auto_deflate = opts.feature(:auto_deflate))
157
- # We need to delete Content-Length header. It will be set automatically
158
- # by HTTP::Request::Writer
159
- headers.delete(Headers::CONTENT_LENGTH)
160
-
161
- headers[Headers::CONTENT_ENCODING] = auto_deflate.method
162
- end
163
-
164
163
  headers
165
164
  end
166
165
 
@@ -170,7 +169,7 @@ module HTTP
170
169
  when opts.body
171
170
  opts.body
172
171
  when opts.form
173
- form = HTTP::FormData.create opts.form
172
+ form = make_form_data(opts.form)
174
173
  headers[Headers::CONTENT_TYPE] ||= form.content_type
175
174
  form
176
175
  when opts.json
@@ -179,5 +178,12 @@ module HTTP
179
178
  body
180
179
  end
181
180
  end
181
+
182
+ def make_form_data(form)
183
+ return form if form.is_a? HTTP::FormData::Multipart
184
+ return form if form.is_a? HTTP::FormData::Urlencoded
185
+
186
+ HTTP::FormData.create(form)
187
+ end
182
188
  end
183
189
  end