http 0.7.4 → 0.8.0.pre

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/.rubocop.yml +5 -2
  4. data/CHANGES.md +24 -7
  5. data/CONTRIBUTING.md +25 -0
  6. data/Gemfile +24 -22
  7. data/Guardfile +2 -2
  8. data/README.md +34 -4
  9. data/Rakefile +7 -7
  10. data/examples/parallel_requests_with_celluloid.rb +2 -2
  11. data/http.gemspec +12 -12
  12. data/lib/http.rb +11 -10
  13. data/lib/http/cache.rb +146 -0
  14. data/lib/http/cache/headers.rb +100 -0
  15. data/lib/http/cache/null_cache.rb +13 -0
  16. data/lib/http/chainable.rb +14 -3
  17. data/lib/http/client.rb +64 -80
  18. data/lib/http/connection.rb +139 -0
  19. data/lib/http/content_type.rb +2 -2
  20. data/lib/http/errors.rb +7 -1
  21. data/lib/http/headers.rb +21 -8
  22. data/lib/http/headers/mixin.rb +1 -1
  23. data/lib/http/mime_type.rb +2 -2
  24. data/lib/http/mime_type/adapter.rb +2 -2
  25. data/lib/http/mime_type/json.rb +4 -4
  26. data/lib/http/options.rb +65 -74
  27. data/lib/http/redirector.rb +3 -3
  28. data/lib/http/request.rb +20 -13
  29. data/lib/http/request/caching.rb +95 -0
  30. data/lib/http/request/writer.rb +5 -5
  31. data/lib/http/response.rb +15 -9
  32. data/lib/http/response/body.rb +21 -8
  33. data/lib/http/response/caching.rb +142 -0
  34. data/lib/http/response/io_body.rb +63 -0
  35. data/lib/http/response/parser.rb +1 -1
  36. data/lib/http/response/status.rb +4 -12
  37. data/lib/http/response/status/reasons.rb +53 -53
  38. data/lib/http/response/string_body.rb +53 -0
  39. data/lib/http/version.rb +1 -1
  40. data/spec/lib/http/cache/headers_spec.rb +77 -0
  41. data/spec/lib/http/cache_spec.rb +182 -0
  42. data/spec/lib/http/client_spec.rb +123 -95
  43. data/spec/lib/http/content_type_spec.rb +25 -25
  44. data/spec/lib/http/headers/mixin_spec.rb +8 -8
  45. data/spec/lib/http/headers_spec.rb +213 -173
  46. data/spec/lib/http/options/body_spec.rb +5 -5
  47. data/spec/lib/http/options/form_spec.rb +3 -3
  48. data/spec/lib/http/options/headers_spec.rb +7 -7
  49. data/spec/lib/http/options/json_spec.rb +3 -3
  50. data/spec/lib/http/options/merge_spec.rb +26 -22
  51. data/spec/lib/http/options/new_spec.rb +10 -10
  52. data/spec/lib/http/options/proxy_spec.rb +8 -8
  53. data/spec/lib/http/options_spec.rb +2 -2
  54. data/spec/lib/http/redirector_spec.rb +32 -32
  55. data/spec/lib/http/request/caching_spec.rb +133 -0
  56. data/spec/lib/http/request/writer_spec.rb +26 -26
  57. data/spec/lib/http/request_spec.rb +63 -58
  58. data/spec/lib/http/response/body_spec.rb +13 -13
  59. data/spec/lib/http/response/caching_spec.rb +201 -0
  60. data/spec/lib/http/response/io_body_spec.rb +35 -0
  61. data/spec/lib/http/response/status_spec.rb +25 -25
  62. data/spec/lib/http/response/string_body_spec.rb +35 -0
  63. data/spec/lib/http/response_spec.rb +64 -45
  64. data/spec/lib/http_spec.rb +103 -76
  65. data/spec/spec_helper.rb +10 -12
  66. data/spec/support/connection_reuse_shared.rb +100 -0
  67. data/spec/support/create_certs.rb +12 -12
  68. data/spec/support/dummy_server.rb +11 -11
  69. data/spec/support/dummy_server/servlet.rb +43 -31
  70. data/spec/support/proxy_server.rb +31 -25
  71. metadata +57 -8
  72. data/spec/support/example_server.rb +0 -30
  73. data/spec/support/example_server/servlet.rb +0 -102
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2dc204ae6f2c91cf31abb8704b2ca61ffde46eaf
4
- data.tar.gz: 0daaaf5280369bb67b9c0fa457e89617d6c44c07
3
+ metadata.gz: a705cb32b18d35b7b100eea0ac6f6687c8e9140e
4
+ data.tar.gz: fff73981101e4bc7a80faeded4d8bde937dd0fa4
5
5
  SHA512:
6
- metadata.gz: a120df1c2722cdb5e2021f4c5022c81096d8014f0b78a932335127b7a9c721a7ace19cd64afc5c65846ebd1d890f3db0203e474c248752b693d6775986a32b90
7
- data.tar.gz: bfbbcde564743cb8e30147ed58a19f6ae154d6bdd512e106334ce4d8bb4f4c2bd101170f4acb72259896d3a37f64ffed206e9d52e1807d42755732d569759e6d
6
+ metadata.gz: 32e0571165aff841356c98fdea9135c6e746a36527f7f7db566effb2321d58dc287b26efbd9651c961cb675fc0621333a12cd0608e3b9cc5a57b0259f220d13d
7
+ data.tar.gz: 7b90b9fba3136f9732667dbae22a561b3f338a11f86e70878494d11b657d7cc64e19403ceb1a5898a844c886e384ae31752cf894527404279d3c5d6b79a4cf96
data/.rspec CHANGED
@@ -3,4 +3,3 @@
3
3
  --format=documentation
4
4
  --order random
5
5
  --require spec_helper
6
- --warnings
data/.rubocop.yml CHANGED
@@ -20,8 +20,8 @@ Metrics/ParameterLists:
20
20
  Max: 3
21
21
  CountKeywordArgs: true
22
22
 
23
- Style/AccessModifierIndentation:
24
- EnforcedStyle: outdent
23
+ Metrics/AbcSize:
24
+ Enabled: false
25
25
 
26
26
  Style/CollectionMethods:
27
27
  PreferredMethods:
@@ -57,5 +57,8 @@ Style/SingleSpaceBeforeFirstArg:
57
57
  Style/SpaceInsideHashLiteralBraces:
58
58
  EnforcedStyle: no_space
59
59
 
60
+ Style/StringLiterals:
61
+ EnforcedStyle: double_quotes
62
+
60
63
  Style/TrivialAccessors:
61
64
  Enabled: false
data/CHANGES.md CHANGED
@@ -1,14 +1,20 @@
1
- ## 0.7.4 (2015-03-31)
2
-
3
- * Re-packed and re-released gem with correct file permissions.
1
+ ## 0.8.0.pre (2015-03-26)
2
+
3
+ * Support for persistent HTTP connections
4
+ * Improve servers used in specs boot up. Issue was initially raised up
5
+ by @olegkovalenko. See #176.
6
+ * Reflect FormData rename changes (FormData -> HTTP::FormData). (@ixti)
7
+ * `HTTP::Headers` now raises `HTTP::InvalidHeaderNameError` in case of
8
+ (surprise) invalid HTTP header field name (e.g.`"Foo:Bar"`). See #173.
9
+ (@ixti)
4
10
 
5
11
 
6
12
  ## 0.7.3 (2015-03-24)
7
13
 
8
- * SECURITY FIX: http.rb failed to call the #post_connection_check method
9
- on SSL connections. This method implements hostname verification, and
10
- without it http.rb was vulnerable to MitM attacks. The problem was
11
- corrected by calling #post_connection_check (CVE-2015-1828)
14
+ * SECURITY FIX: http.rb failed to call the `#post_connection_check` method on
15
+ SSL connections. This method implements hostname verification, and without it
16
+ `http.rb` was vulnerable to MitM attacks. The problem was corrected by calling
17
+ `#post_connection_check` (CVE-2015-1828) (@zanker)
12
18
 
13
19
 
14
20
  ## 0.7.2 (2015-03-02)
@@ -24,6 +30,9 @@
24
30
 
25
31
  ## 0.7.0 (2015-01-02)
26
32
 
33
+ * Add support of multipart form data. See #73, #167. (@ixti)
34
+ * Fix URI path normalization: `https://github.com` -> `https://github.com/`.
35
+ (@ixti)
27
36
  * Fix handling of EOF which caused infinite loop. See #163, #166 and #152. (@mickm, @ixti)
28
37
  * Drop Ruby 1.8.7 support. (@ixti)
29
38
  * Fix default Host header value. See #150. (@ixti)
@@ -46,6 +55,14 @@
46
55
  * Delegate `HTTP::Response#readpartial` to `HTTP::Response::Body` (@ixti)
47
56
 
48
57
 
58
+ ## 0.6.4 (2015-03-25)
59
+
60
+ * SECURITY FIX: http.rb failed to call the `#post_connection_check` method on
61
+ SSL connections. This method implements hostname verification, and without it
62
+ `http.rb` was vulnerable to MitM attacks. The problem was corrected by calling
63
+ `#post_connection_check` (CVE-2015-1828) (@zanker, backported by @nicoolas25)
64
+
65
+
49
66
  ## 0.6.3 (2014-11-14)
50
67
 
51
68
  * Backported EOF fix from master branch. See #166. (@ixti)
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,25 @@
1
+ # Help and Discussion
2
+
3
+ If you need help or just want to talk about the http.rb,
4
+ visit the http.rb Google Group:
5
+
6
+ https://groups.google.com/forum/#!forum/httprb
7
+
8
+ You can join by email by sending a message to:
9
+
10
+ [httprb+subscribe@googlegroups.com](mailto:httprb+subscribe@googlegroups.com)
11
+
12
+
13
+ # Reporting bugs
14
+
15
+ The best way to report a bug is by providing a reproduction script. A half
16
+ working script with comments for the parts you were unable to automate is still
17
+ appreciated.
18
+
19
+ In any case, specify following info in description of your issue:
20
+
21
+ - What you're trying to accomplish
22
+ - What you expected to happen
23
+ - What actually happened
24
+ - The exception backtrace(s), if any
25
+ - Version of gem or commit ref you are using
data/Gemfile CHANGED
@@ -1,37 +1,39 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
- gem 'jruby-openssl' if defined? JRUBY_VERSION
4
- gem 'rake'
3
+ gem "jruby-openssl" if defined? JRUBY_VERSION
4
+ gem "rake"
5
+
6
+ gem "rack-cache", "~> 1.2"
5
7
 
6
8
  group :development do
7
- gem 'celluloid-io'
8
- gem 'guard'
9
- gem 'guard-rspec'
10
- gem 'pry'
9
+ gem "celluloid-io"
10
+ gem "guard"
11
+ gem "guard-rspec", :require => false
12
+ gem "pry"
11
13
 
12
14
  platforms :ruby_19, :ruby_20 do
13
- gem 'pry-debugger'
14
- gem 'pry-stack_explorer'
15
+ gem "pry-debugger"
16
+ gem "pry-stack_explorer"
15
17
  end
16
18
  end
17
19
 
18
20
  group :test do
19
- gem 'backports'
20
- gem 'coveralls'
21
- gem 'json', '>= 1.8.1'
22
- gem 'mime-types', '~> 1.25', :platforms => [:jruby]
23
- gem 'rest-client', '~> 1.6.0', :platforms => [:jruby]
24
- gem 'rspec', '~> 3.0'
25
- gem 'rspec-its'
26
- gem 'rubocop', '~> 0.25.0'
27
- gem 'simplecov', '>= 0.9'
28
- gem 'yardstick'
29
- gem 'certificate_authority'
21
+ gem "backports"
22
+ gem "coveralls"
23
+ gem "simplecov", ">= 0.9"
24
+ gem "json", ">= 1.8.1"
25
+ gem "mime-types", "~> 1.25", :platforms => [:jruby]
26
+ gem "rest-client", "~> 1.6.0", :platforms => [:jruby]
27
+ gem "rspec", "~> 3.0"
28
+ gem "rspec-its"
29
+ gem "rubocop"
30
+ gem "yardstick"
31
+ gem "certificate_authority"
30
32
  end
31
33
 
32
34
  group :doc do
33
- gem 'redcarpet'
34
- gem 'yard'
35
+ gem "redcarpet"
36
+ gem "yard"
35
37
  end
36
38
 
37
39
  # Specify your gem's dependencies in http.gemspec
data/Guardfile CHANGED
@@ -1,7 +1,7 @@
1
1
  # More info at https://github.com/guard/guard#readme
2
2
 
3
- guard :rspec, :cmd => 'bundle exec rspec' do
4
- require 'guard/rspec/dsl'
3
+ guard :rspec, :cmd => "GUARD_RSPEC=1 bundle exec rspec --no-profile" do
4
+ require "guard/rspec/dsl"
5
5
  dsl = Guard::RSpec::Dsl.new(self)
6
6
 
7
7
  # RSpec files
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  ![http.rb](https://raw.github.com/httprb/http.rb/master/logo.png)
2
2
  ==============
3
- [![Gem Version](https://badge.fury.io/rb/http.png)](http://rubygems.org/gems/http)
4
- [![Build Status](https://secure.travis-ci.org/httprb/http.rb.png?branch=master)](http://travis-ci.org/httprb/http.rb)
5
- [![Code Climate](https://codeclimate.com/github/httprb/http.rb.png)](https://codeclimate.com/github/httprb/http.rb)
6
- [![Coverage Status](https://coveralls.io/repos/httprb/http.rb/badge.png?branch=master)](https://coveralls.io/r/httprb/http.rb)
3
+ [![Gem Version](https://badge.fury.io/rb/http.svg)](http://rubygems.org/gems/http)
4
+ [![Build Status](https://secure.travis-ci.org/httprb/http.rb.svg?branch=master)](http://travis-ci.org/httprb/http.rb)
5
+ [![Code Climate](https://codeclimate.com/github/httprb/http.rb.svg?branch=master)](https://codeclimate.com/github/httprb/http.rb)
6
+ [![Coverage Status](https://coveralls.io/repos/httprb/http.rb/badge.svg?branch=master)](https://coveralls.io/r/httprb/http.rb)
7
7
 
8
8
  About
9
9
  -----
@@ -125,6 +125,15 @@ Or just a plain body?
125
125
  HTTP.post('http://example.com/resource', :body => 'foo=42&bar=baz')
126
126
  ```
127
127
 
128
+ Posting a file?
129
+
130
+ ``` ruby
131
+ HTTP.post('http://examplc.com/resource', :form => {
132
+ :username => 'ixti',
133
+ :avatar => HTTP::FormData::File.new('/home/ixit/avatar.png')
134
+ })
135
+ ```
136
+
128
137
  It's easy!
129
138
 
130
139
  ### Proxy Support
@@ -240,6 +249,27 @@ There's a little more to it, but that's the core idea!
240
249
  * [Full parallel HTTP fetcher example](https://github.com/httprb/http.rb/wiki/Parallel-requests-with-Celluloid%3A%3AIO)
241
250
  * See also: [Celluloid::IO](https://github.com/celluloid/celluloid-io)
242
251
 
252
+ ### Caching
253
+
254
+ http.rb provides caching of HTTP request (per
255
+ [RFC 7234](https://tools.ietf.org/html/rfc7234)) when configured to do
256
+ so.
257
+
258
+ ```ruby
259
+ require 'http'
260
+
261
+ http = HTTP.with_cache(metastore: "file:/var/cache/my-app-http/meta",
262
+ entitystore: "file:/var/cache/my-app-http/entity")
263
+
264
+ http.get("http://example.com/") # makes request
265
+ http.get("http://example.com/") # skips making request and returns
266
+ # previously cached response
267
+ ```
268
+
269
+ http.rb's caching is backed by
270
+ [rack-cache's excellent storage subsystem](http://rtomayko.github.io/rack-cache/storage.html). Any
271
+ storage URL supported by rack-cache is supported by http.rb's cache.
272
+
243
273
  Supported Ruby Versions
244
274
  -----------------------
245
275
 
data/Rakefile CHANGED
@@ -1,26 +1,26 @@
1
1
  #!/usr/bin/env rake
2
- require 'bundler/gem_tasks'
2
+ require "bundler/gem_tasks"
3
3
 
4
- require 'rspec/core/rake_task'
4
+ require "rspec/core/rake_task"
5
5
  RSpec::Core::RakeTask.new
6
6
 
7
7
  task :test => :spec
8
8
 
9
9
  begin
10
- require 'rubocop/rake_task'
10
+ require "rubocop/rake_task"
11
11
  RuboCop::RakeTask.new
12
12
  rescue LoadError
13
13
  task :rubocop do
14
- $stderr.puts 'RuboCop is disabled'
14
+ $stderr.puts "RuboCop is disabled"
15
15
  end
16
16
  end
17
17
 
18
- require 'yardstick/rake/measurement'
18
+ require "yardstick/rake/measurement"
19
19
  Yardstick::Rake::Measurement.new do |measurement|
20
- measurement.output = 'measurement/report.txt'
20
+ measurement.output = "measurement/report.txt"
21
21
  end
22
22
 
23
- require 'yardstick/rake/verify'
23
+ require "yardstick/rake/verify"
24
24
  Yardstick::Rake::Verify.new do |verify|
25
25
  verify.require_exact_threshold = false
26
26
  verify.threshold = 58
@@ -6,8 +6,8 @@
6
6
  # Run as: bundle exec examples/parallel_requests_with_celluloid.rb
7
7
  #
8
8
 
9
- require 'celluloid/io'
10
- require 'http'
9
+ require "celluloid/io"
10
+ require "http"
11
11
 
12
12
  class HttpFetcher
13
13
  include Celluloid::IO
data/http.gemspec CHANGED
@@ -1,29 +1,29 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/http/version', __FILE__)
2
+ require File.expand_path("../lib/http/version", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
- gem.authors = ['Tony Arcieri', 'Erik Michaels-Ober', 'Aleksey V. Zapparov']
6
- gem.email = ['bascule@gmail.com']
5
+ gem.authors = ["Tony Arcieri", "Erik Michaels-Ober", "Aleksey V. Zapparov"]
6
+ gem.email = ["bascule@gmail.com"]
7
7
 
8
- gem.description = <<-DESCRIPTION.strip.gsub(/\s+/, ' ')
8
+ gem.description = <<-DESCRIPTION.strip.gsub(/\s+/, " ")
9
9
  An easy-to-use client library for making requests from Ruby.
10
10
  It uses a simple method chaining system for building requests,
11
11
  similar to Python's Requests.
12
12
  DESCRIPTION
13
13
 
14
- gem.summary = 'HTTP should be easy'
15
- gem.homepage = 'https://github.com/httprb/http.rb'
16
- gem.licenses = ['MIT']
14
+ gem.summary = "HTTP should be easy"
15
+ gem.homepage = "https://github.com/httprb/http.rb"
16
+ gem.licenses = ["MIT"]
17
17
 
18
18
  gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
19
19
  gem.files = `git ls-files`.split("\n")
20
20
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
- gem.name = 'http'
22
- gem.require_paths = ['lib']
21
+ gem.name = "http"
22
+ gem.require_paths = ["lib"]
23
23
  gem.version = HTTP::VERSION
24
24
 
25
- gem.add_runtime_dependency 'http_parser.rb', '~> 0.6.0'
26
- gem.add_runtime_dependency 'http-form_data', '~> 1.0.0'
25
+ gem.add_runtime_dependency "http_parser.rb", "~> 0.6.0"
26
+ gem.add_runtime_dependency "http-form_data", "~> 1.0.0"
27
27
 
28
- gem.add_development_dependency 'bundler', '~> 1.0'
28
+ gem.add_development_dependency "bundler", "~> 1.0"
29
29
  end
data/lib/http.rb CHANGED
@@ -1,14 +1,15 @@
1
- require 'http/parser'
1
+ require "http/parser"
2
2
 
3
- require 'http/errors'
4
- require 'http/chainable'
5
- require 'http/client'
6
- require 'http/options'
7
- require 'http/request'
8
- require 'http/request/writer'
9
- require 'http/response'
10
- require 'http/response/body'
11
- require 'http/response/parser'
3
+ require "http/errors"
4
+ require "http/chainable"
5
+ require "http/client"
6
+ require "http/connection"
7
+ require "http/options"
8
+ require "http/request"
9
+ require "http/request/writer"
10
+ require "http/response"
11
+ require "http/response/body"
12
+ require "http/response/parser"
12
13
 
13
14
  # HTTP should be easy
14
15
  module HTTP
data/lib/http/cache.rb ADDED
@@ -0,0 +1,146 @@
1
+ require "time"
2
+ require "rack-cache"
3
+
4
+ module HTTP
5
+ class Cache
6
+ # NoOp logger.
7
+ class NullLogger
8
+ def error(_msg = nil)
9
+ end
10
+
11
+ def debug(_msg = nil)
12
+ end
13
+
14
+ def info(_msg = nil)
15
+ end
16
+
17
+ def warn(_msg = nil)
18
+ end
19
+ end
20
+
21
+ # @return [Response] a cached response that is valid for the request or
22
+ # the result of executing the provided block
23
+ #
24
+ # @yield [request, options] on cache miss so that an actual
25
+ # request can be made
26
+ def perform(request, options, &request_performer)
27
+ req = request.caching
28
+
29
+ invalidate_cache(req) if req.invalidates_cache?
30
+
31
+ get_response(req, options, request_performer)
32
+ end
33
+
34
+ protected
35
+
36
+ # @return [Response] the response to the request, either from the
37
+ # cache or by actually making the request
38
+ def get_response(req, options, request_performer)
39
+ cached_resp = cache_lookup(req)
40
+ return cached_resp if cached_resp && !cached_resp.stale?
41
+
42
+ # cache miss
43
+ logger.debug { "Cache miss for <#{req.uri}>, making request" }
44
+ actual_req = if cached_resp
45
+ req.conditional_on_changes_to(cached_resp)
46
+ else
47
+ req
48
+ end
49
+ actual_resp = make_request(actual_req, options, request_performer)
50
+
51
+ handle_response(cached_resp, actual_resp, req)
52
+ end
53
+
54
+ # @returns [Response] the most useful of the responses after
55
+ # updating the cache as appropriate
56
+ def handle_response(cached_resp, actual_resp, req)
57
+ if actual_resp.status.not_modified? && cached_resp
58
+ logger.debug { "<#{req.uri}> not modified, using cached version." }
59
+ cached_resp.validated!(actual_resp)
60
+ store_in_cache(req, cached_resp)
61
+ return cached_resp
62
+
63
+ elsif req.cacheable? && actual_resp.cacheable?
64
+ store_in_cache(req, actual_resp)
65
+ return actual_resp
66
+
67
+ else
68
+ return actual_resp
69
+ end
70
+ end
71
+
72
+ # @return [HTTP::Response::Caching] the actual response returned
73
+ # by request_performer
74
+ def make_request(req, options, request_performer)
75
+ req.sent_at = Time.now
76
+
77
+ request_performer.call(req, options).caching.tap do |res|
78
+ res.received_at = Time.now
79
+ res.requested_at = req.sent_at
80
+ end
81
+ end
82
+
83
+ # @return [HTTP::Response::Caching, nil] the cached response for the request
84
+ def cache_lookup(request)
85
+ return nil if request.skips_cache?
86
+
87
+ rack_resp = metastore.lookup(request, entitystore)
88
+ return if rack_resp.nil?
89
+
90
+ HTTP::Response.new(
91
+ rack_resp.status, "1.1", rack_resp.headers, stringify(rack_resp.body)
92
+ ).caching
93
+ end
94
+
95
+ # Store response in cache
96
+ #
97
+ # @return [nil]
98
+ #
99
+ # ---
100
+ #
101
+ # We have to convert the response body in to a string body so
102
+ # that the cache store reading the body will not prevent the
103
+ # original requester from doing so.
104
+ def store_in_cache(request, response)
105
+ response.body = response.body.to_s
106
+ metastore.store(request, response, entitystore)
107
+ nil
108
+ end
109
+
110
+ # Invalidate all response from the requested resource
111
+ #
112
+ # @return [nil]
113
+ def invalidate_cache(request)
114
+ metastore.invalidate(request, entitystore)
115
+ end
116
+
117
+ # Inits a new instance
118
+ #
119
+ # @option opts [String] :metastore URL to the metastore location
120
+ # @option opts [String] :entitystore URL to the entitystore location
121
+ # @option opts [Logger] :logger logger to use
122
+ def initialize(opts)
123
+ @metastore = storage.resolve_metastore_uri(opts.fetch(:metastore))
124
+ @entitystore = storage.resolve_entitystore_uri(opts.fetch(:entitystore))
125
+ @logger = opts.fetch(:logger) { NullLogger.new }
126
+ end
127
+
128
+ attr_reader :metastore, :entitystore, :logger
129
+
130
+ def storage
131
+ @@storage ||= Rack::Cache::Storage.new # rubocop:disable Style/ClassVars
132
+ end
133
+
134
+ def stringify(body)
135
+ if body.respond_to?(:each)
136
+ "".tap do |buf|
137
+ body.each do |part|
138
+ buf << part
139
+ end
140
+ end
141
+ else
142
+ body.to_s
143
+ end
144
+ end
145
+ end
146
+ end