http 0.7.4 → 0.8.0.pre

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