almodovar 0.1.0 → 0.1.2
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.
- data/vendor/resourceful-0.5.3-patched/MIT-LICENSE +21 -0
- data/vendor/resourceful-0.5.3-patched/Manifest +29 -0
- data/vendor/resourceful-0.5.3-patched/README.markdown +84 -0
- data/vendor/resourceful-0.5.3-patched/Rakefile +71 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful.rb +18 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/authentication_manager.rb +108 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/cache_manager.rb +240 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/exceptions.rb +34 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/header.rb +126 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/http_accessor.rb +98 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/memcache_cache_manager.rb +75 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/net_http_adapter.rb +70 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/options_interpreter.rb +78 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/request.rb +230 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/resource.rb +163 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/response.rb +221 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/stubbed_resource_proxy.rb +47 -0
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/util.rb +6 -0
- data/vendor/resourceful-0.5.3-patched/resourceful.gemspec +48 -0
- data/vendor/resourceful-0.5.3-patched/spec/acceptance/authorization_spec.rb +16 -0
- data/vendor/resourceful-0.5.3-patched/spec/acceptance/caching_spec.rb +192 -0
- data/vendor/resourceful-0.5.3-patched/spec/acceptance/header_spec.rb +24 -0
- data/vendor/resourceful-0.5.3-patched/spec/acceptance/redirecting_spec.rb +12 -0
- data/vendor/resourceful-0.5.3-patched/spec/acceptance/resource_spec.rb +84 -0
- data/vendor/resourceful-0.5.3-patched/spec/acceptance_shared_specs.rb +44 -0
- data/vendor/resourceful-0.5.3-patched/spec/old_acceptance_specs.rb +378 -0
- data/vendor/resourceful-0.5.3-patched/spec/simple_sinatra_server.rb +74 -0
- data/vendor/resourceful-0.5.3-patched/spec/simple_sinatra_server_spec.rb +98 -0
- data/vendor/resourceful-0.5.3-patched/spec/spec.opts +3 -0
- data/vendor/resourceful-0.5.3-patched/spec/spec_helper.rb +28 -0
- metadata +32 -2
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2008 Absolute-Performance, Inc
|
2
|
+
Copyright (c) 2008 Peter Williams
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,29 @@
|
|
1
|
+
lib/resourceful.rb
|
2
|
+
lib/resourceful/net_http_adapter.rb
|
3
|
+
lib/resourceful/stubbed_resource_proxy.rb
|
4
|
+
lib/resourceful/header.rb
|
5
|
+
lib/resourceful/memcache_cache_manager.rb
|
6
|
+
lib/resourceful/response.rb
|
7
|
+
lib/resourceful/util.rb
|
8
|
+
lib/resourceful/options_interpreter.rb
|
9
|
+
lib/resourceful/cache_manager.rb
|
10
|
+
lib/resourceful/request.rb
|
11
|
+
lib/resourceful/resource.rb
|
12
|
+
lib/resourceful/exceptions.rb
|
13
|
+
lib/resourceful/http_accessor.rb
|
14
|
+
lib/resourceful/authentication_manager.rb
|
15
|
+
README.markdown
|
16
|
+
MIT-LICENSE
|
17
|
+
Rakefile
|
18
|
+
Manifest
|
19
|
+
spec/simple_sinatra_server_spec.rb
|
20
|
+
spec/old_acceptance_specs.rb
|
21
|
+
spec/acceptance_shared_specs.rb
|
22
|
+
spec/spec_helper.rb
|
23
|
+
spec/simple_sinatra_server.rb
|
24
|
+
spec/acceptance/authorization_spec.rb
|
25
|
+
spec/acceptance/header_spec.rb
|
26
|
+
spec/acceptance/resource_spec.rb
|
27
|
+
spec/acceptance/caching_spec.rb
|
28
|
+
spec/acceptance/redirecting_spec.rb
|
29
|
+
spec/spec.opts
|
@@ -0,0 +1,84 @@
|
|
1
|
+
Resourceful
|
2
|
+
===========
|
3
|
+
|
4
|
+
Resourceful provides a convenient Ruby API for making HTTP requests.
|
5
|
+
|
6
|
+
Features:
|
7
|
+
|
8
|
+
* GET, PUT, POST and DELETE HTTP requests
|
9
|
+
* HTTP Basic and Digest authentication
|
10
|
+
* HTTP Caching with pluggable backends
|
11
|
+
* Follow redirects based on the results of a callback
|
12
|
+
|
13
|
+
More Info
|
14
|
+
=========
|
15
|
+
|
16
|
+
* Source: [Github](http://github.com/paul/resourceful/tree/master)
|
17
|
+
* Bug Tracking: [Lighthouse](http://resourceful.lighthouseapp.com)
|
18
|
+
* Project Page: [Rubyforge](http://rubyforge.org/projects/resourceful/)
|
19
|
+
* Documentation: [API Docs](http://resourceful.rubyforge.org)
|
20
|
+
|
21
|
+
Examples
|
22
|
+
========
|
23
|
+
|
24
|
+
Getting started
|
25
|
+
---------------
|
26
|
+
|
27
|
+
gem install resourceful
|
28
|
+
|
29
|
+
Simplest example
|
30
|
+
---------------
|
31
|
+
|
32
|
+
require 'resourceful'
|
33
|
+
http = Resourceful::HttpAccessor.new
|
34
|
+
resp = http.resource('http://rubyforge.org').get
|
35
|
+
puts resp.body
|
36
|
+
|
37
|
+
Get a page requiring HTTP Authentication
|
38
|
+
----------------------------------------
|
39
|
+
|
40
|
+
my_realm_authenticator = Resourceful::BasicAuthenticator.new('My Realm', 'admin', 'secret')
|
41
|
+
http = Resourceful::HttpAccessor.new(:authenticator => my_realm_authenticator)
|
42
|
+
resp = http.resource('http://example.com/').get
|
43
|
+
puts resp.body
|
44
|
+
|
45
|
+
Redirection based on callback results
|
46
|
+
-------------------------------------
|
47
|
+
|
48
|
+
Resourceful will by default follow redirects on read requests (GET and HEAD), but not for
|
49
|
+
POST, etc. If you want to follow a redirect after a post, you will need to set the resource#on_redirect
|
50
|
+
callback. If the callback evaluates to true, it will follow the redirect.
|
51
|
+
|
52
|
+
resource = http.resource('http://example.com/redirect_me')
|
53
|
+
resource.on_redirect { |req, resp| resp.header['Location'] =~ /example.com/ }
|
54
|
+
resource.get # Will only follow the redirect if the new location is example.com
|
55
|
+
|
56
|
+
Post a URL encoded form
|
57
|
+
-----------------------
|
58
|
+
|
59
|
+
require 'resourceful'
|
60
|
+
http = Resourceful::HttpAccessor.new
|
61
|
+
resp = http.resource('http://mysite.example/service').
|
62
|
+
post('hostname=test&level=super', :content_type => 'application/x-www-form-urlencoded')
|
63
|
+
|
64
|
+
Put an XML document
|
65
|
+
-------------------
|
66
|
+
|
67
|
+
require 'resourceful'
|
68
|
+
http = Resourceful::HttpAccessor.new
|
69
|
+
resp = http.resource('http://mysite.example/service').
|
70
|
+
put('<?xml version="1.0"?><test/>', :content_type => 'application/xml')
|
71
|
+
|
72
|
+
Delete a resource
|
73
|
+
-----------------
|
74
|
+
|
75
|
+
require 'resourceful'
|
76
|
+
http = Resourceful::HttpAccessor.new
|
77
|
+
resp = http.resource('http://mysite.example/service').delete
|
78
|
+
|
79
|
+
|
80
|
+
Copyright
|
81
|
+
---------
|
82
|
+
|
83
|
+
Copyright (c) 2008 Absolute Performance, Inc, Peter Williams. Released under the MIT License.
|
84
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'lib/resourceful'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'echoe'
|
7
|
+
|
8
|
+
Echoe.new('resourceful', Resourceful::VERSION) do |p|
|
9
|
+
p.description = "An HTTP library for Ruby that takes advantage of everything HTTP has to offer."
|
10
|
+
p.url = "http://github.com/paul/resourceful"
|
11
|
+
p.author = "Paul Sadauskas"
|
12
|
+
p.email = "psadauskas@gmail.com"
|
13
|
+
|
14
|
+
p.ignore_pattern = ["pkg/*", "tmp/*"]
|
15
|
+
p.dependencies = ['addressable', 'httpauth']
|
16
|
+
p.development_dependencies = ['thin', 'yard', 'sinatra', 'rspec']
|
17
|
+
end
|
18
|
+
rescue LoadError => e
|
19
|
+
puts "install 'echoe' gem to be able to build the gem"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'spec/rake/spectask'
|
23
|
+
|
24
|
+
desc 'Run all specs'
|
25
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
26
|
+
t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
|
27
|
+
t.libs << 'lib'
|
28
|
+
t.spec_files = FileList['spec/acceptance/*_spec.rb']
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Run the specs for the server'
|
32
|
+
Spec::Rake::SpecTask.new('spec:server') do |t|
|
33
|
+
t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
|
34
|
+
t.libs << 'lib'
|
35
|
+
t.spec_files = FileList['spec/simple_sinatra_server_spec.rb']
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
require 'spec/simple_sinatra_server'
|
40
|
+
desc "Run the sinatra echo server, with loggin"
|
41
|
+
task :server do
|
42
|
+
Sinatra::Default.set(
|
43
|
+
:run => true,
|
44
|
+
:logging => true
|
45
|
+
)
|
46
|
+
end
|
47
|
+
rescue LoadError => e
|
48
|
+
puts "Install 'sinatra' gem to run the server"
|
49
|
+
end
|
50
|
+
|
51
|
+
desc 'Default: Run Specs'
|
52
|
+
task :default => :spec
|
53
|
+
|
54
|
+
desc 'Run all tests'
|
55
|
+
task :test => :spec
|
56
|
+
|
57
|
+
begin
|
58
|
+
require 'yard'
|
59
|
+
|
60
|
+
desc "Generate Yardoc"
|
61
|
+
YARD::Rake::YardocTask.new do |t|
|
62
|
+
t.files = ['lib/**/*.rb', 'README.markdown']
|
63
|
+
end
|
64
|
+
rescue LoadError => e
|
65
|
+
puts "Install 'yard' gem to generate docs"
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "Update rubyforge documentation"
|
69
|
+
task :update_docs => :yardoc do
|
70
|
+
puts %x{rsync -aPz doc/* psadauskas@resourceful.rubyforge.org:/var/www/gforge-projects/resourceful/}
|
71
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
__DIR__ = File.dirname(__FILE__)
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift __DIR__ unless
|
5
|
+
$LOAD_PATH.include?(__DIR__) ||
|
6
|
+
$LOAD_PATH.include?(File.expand_path(__DIR__))
|
7
|
+
|
8
|
+
require 'resourceful/util'
|
9
|
+
|
10
|
+
require 'resourceful/header'
|
11
|
+
require 'resourceful/http_accessor'
|
12
|
+
|
13
|
+
# Resourceful is a library that provides a high level HTTP interface.
|
14
|
+
module Resourceful
|
15
|
+
VERSION = "0.5.3"
|
16
|
+
RESOURCEFUL_USER_AGENT_TOKEN = "Resourceful/#{VERSION}(Ruby/#{RUBY_VERSION})"
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
#require 'rubygems'
|
2
|
+
require 'httpauth'
|
3
|
+
require 'addressable/uri'
|
4
|
+
|
5
|
+
module Resourceful
|
6
|
+
|
7
|
+
class AuthenticationManager
|
8
|
+
def initialize
|
9
|
+
@authenticators = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_auth_handler(authenticator)
|
13
|
+
@authenticators << authenticator
|
14
|
+
end
|
15
|
+
|
16
|
+
def associate_auth_info(challenge)
|
17
|
+
@authenticators.each do |authenticator|
|
18
|
+
authenticator.update_credentials(challenge) if authenticator.valid_for?(challenge)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_credentials(request)
|
23
|
+
@authenticators.each do |authenticator|
|
24
|
+
authenticator.add_credentials_to(request) if authenticator.can_handle?(request)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
class BasicAuthenticator
|
31
|
+
|
32
|
+
def initialize(realm, username, password)
|
33
|
+
@realm, @username, @password = realm, username, password
|
34
|
+
@domain = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def valid_for?(challenge_response)
|
38
|
+
return false unless challenge_response.header['WWW-Authenticate']
|
39
|
+
|
40
|
+
!challenge_response.header['WWW-Authenticate'].grep(/^\s*basic/i).find do |a_challenge|
|
41
|
+
@realm.downcase == /realm="([^"]+)"/i.match(a_challenge)[1].downcase
|
42
|
+
end.nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_credentials(challenge)
|
46
|
+
@domain = Addressable::URI.parse(challenge.uri).host
|
47
|
+
end
|
48
|
+
|
49
|
+
def can_handle?(request)
|
50
|
+
Addressable::URI.parse(request.uri).host == @domain
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_credentials_to(request)
|
54
|
+
request.header['Authorization'] = credentials
|
55
|
+
end
|
56
|
+
|
57
|
+
def credentials
|
58
|
+
HTTPAuth::Basic.pack_authorization(@username, @password)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
class DigestAuthenticator
|
64
|
+
|
65
|
+
attr_reader :username, :password, :realm, :domain, :challenge
|
66
|
+
|
67
|
+
def initialize(realm, username, password)
|
68
|
+
@realm = realm
|
69
|
+
@username, @password = username, password
|
70
|
+
@domain = nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def update_credentials(challenge_response)
|
74
|
+
@domain = Addressable::URI.parse(challenge_response.uri).host
|
75
|
+
@challenge = HTTPAuth::Digest::Challenge.from_header(challenge_response.header['WWW-Authenticate'].first)
|
76
|
+
end
|
77
|
+
|
78
|
+
def valid_for?(challenge_response)
|
79
|
+
return false unless challenge_header = challenge_response.header['WWW-Authenticate']
|
80
|
+
begin
|
81
|
+
challenge = HTTPAuth::Digest::Challenge.from_header(challenge_header.first)
|
82
|
+
rescue HTTPAuth::UnwellformedHeader
|
83
|
+
return false
|
84
|
+
end
|
85
|
+
challenge.realm == @realm
|
86
|
+
end
|
87
|
+
|
88
|
+
def can_handle?(request)
|
89
|
+
Addressable::URI.parse(request.uri).host == @domain
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_credentials_to(request)
|
93
|
+
request.header['Authorization'] = credentials_for(request)
|
94
|
+
end
|
95
|
+
|
96
|
+
def credentials_for(request)
|
97
|
+
HTTPAuth::Digest::Credentials.from_challenge(@challenge,
|
98
|
+
:username => @username,
|
99
|
+
:password => @password,
|
100
|
+
:method => request.method.to_s.upcase,
|
101
|
+
:uri => ::URI.parse(request.uri).request_uri).to_header
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
end
|
108
|
+
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'resourceful/header'
|
2
|
+
require 'digest/md5'
|
3
|
+
|
4
|
+
module Resourceful
|
5
|
+
|
6
|
+
class AbstractCacheManager
|
7
|
+
def initialize
|
8
|
+
raise NotImplementedError,
|
9
|
+
"Use one of CacheManager's child classes instead. Try NullCacheManager if you don't want any caching at all."
|
10
|
+
end
|
11
|
+
|
12
|
+
# Finds a previously cached response to the provided request. The
|
13
|
+
# response returned may be stale.
|
14
|
+
#
|
15
|
+
# @param [Resourceful::Request] request
|
16
|
+
# The request for which we are looking for a response.
|
17
|
+
#
|
18
|
+
# @return [Resourceful::Response]
|
19
|
+
# A (possibly stale) response for the request provided.
|
20
|
+
def lookup(request); end
|
21
|
+
|
22
|
+
# Store a response in the cache.
|
23
|
+
#
|
24
|
+
# This method is smart enough to not store responses that cannot be
|
25
|
+
# cached (Vary: * or Cache-Control: no-cache, private, ...)
|
26
|
+
#
|
27
|
+
# @param request<Resourceful::Request>
|
28
|
+
# The request used to obtain the response. This is needed so the
|
29
|
+
# values from the response's Vary header can be stored.
|
30
|
+
# @param response<Resourceful::Response>
|
31
|
+
# The response to be stored.
|
32
|
+
def store(request, response); end
|
33
|
+
|
34
|
+
# Invalidates a all cached entries for a uri.
|
35
|
+
#
|
36
|
+
# This is used, for example, to invalidate the cache for a resource
|
37
|
+
# that gets POSTed to.
|
38
|
+
#
|
39
|
+
# @param uri<String>
|
40
|
+
# The uri of the resource to be invalidated
|
41
|
+
def invalidate(uri); end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
# Returns an alphanumeric hash of a URI
|
46
|
+
def uri_hash(uri)
|
47
|
+
Digest::MD5.hexdigest(uri)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# This is the default cache, and does not do any caching. All lookups
|
52
|
+
# result in nil, and all attempts to store a response are a no-op.
|
53
|
+
class NullCacheManager < AbstractCacheManager
|
54
|
+
def initialize; end
|
55
|
+
|
56
|
+
def lookup(request)
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def store(request, response); end
|
61
|
+
end
|
62
|
+
|
63
|
+
# This is a nieve implementation of caching. Unused entries are never
|
64
|
+
# removed, and this may eventually eat up all your memory and cause your
|
65
|
+
# machine to explode.
|
66
|
+
class InMemoryCacheManager < AbstractCacheManager
|
67
|
+
|
68
|
+
def initialize
|
69
|
+
@collection = Hash.new{ |h,k| h[k] = CacheEntryCollection.new}
|
70
|
+
end
|
71
|
+
|
72
|
+
def lookup(request)
|
73
|
+
response = @collection[request.uri.to_s][request]
|
74
|
+
response.authoritative = false if response
|
75
|
+
response
|
76
|
+
end
|
77
|
+
|
78
|
+
def store(request, response)
|
79
|
+
return unless response.cacheable?
|
80
|
+
|
81
|
+
@collection[request.uri.to_s][request] = response
|
82
|
+
end
|
83
|
+
|
84
|
+
def invalidate(uri)
|
85
|
+
@collection.delete(uri)
|
86
|
+
end
|
87
|
+
end # class InMemoryCacheManager
|
88
|
+
|
89
|
+
# Stores cache entries in a directory on the filesystem. Similarly to the
|
90
|
+
# InMemoryCacheManager there are no limits on storage, so this will eventually
|
91
|
+
# eat up all your disk!
|
92
|
+
class FileCacheManager < AbstractCacheManager
|
93
|
+
# Create a new FileCacheManager
|
94
|
+
#
|
95
|
+
# @param [String] location
|
96
|
+
# A directory on the filesystem to store cache entries. This directory
|
97
|
+
# will be created if it doesn't exist
|
98
|
+
def initialize(location="/tmp/resourceful")
|
99
|
+
require 'fileutils'
|
100
|
+
require 'yaml'
|
101
|
+
@dir = FileUtils.mkdir_p(location)
|
102
|
+
end
|
103
|
+
|
104
|
+
def lookup(request)
|
105
|
+
response = cache_entries_for(request)[request]
|
106
|
+
response.authoritative = false if response
|
107
|
+
response
|
108
|
+
end
|
109
|
+
|
110
|
+
def store(request, response)
|
111
|
+
return unless response.cacheable?
|
112
|
+
|
113
|
+
entries = cache_entries_for(request)
|
114
|
+
entries[request] = response
|
115
|
+
File.open(cache_file(request.uri), "w") {|fh| fh.write( YAML.dump(entries) ) }
|
116
|
+
end
|
117
|
+
|
118
|
+
def invalidate(uri);
|
119
|
+
File.unlink(cache_file(uri));
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
def cache_entries_for(request)
|
125
|
+
if File.readable?( cache_file(request.uri) )
|
126
|
+
YAML.load_file( cache_file(request.uri) )
|
127
|
+
else
|
128
|
+
Resourceful::CacheEntryCollection.new
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def cache_file(uri)
|
133
|
+
"#{@dir}/#{uri_hash(uri)}"
|
134
|
+
end
|
135
|
+
end # class FileCacheManager
|
136
|
+
|
137
|
+
|
138
|
+
# The collection of cached entries. Nominally all the entry in a
|
139
|
+
# collection of this sort will be for the same resource but that is
|
140
|
+
# not required to be true.
|
141
|
+
class CacheEntryCollection
|
142
|
+
include Enumerable
|
143
|
+
|
144
|
+
def initialize
|
145
|
+
@entries = []
|
146
|
+
end
|
147
|
+
|
148
|
+
# Iterates over the entries. Needed for Enumerable
|
149
|
+
def each(&block)
|
150
|
+
@entries.each(&block)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Looks of a Entry that could fullfil the request. Returns nil if none
|
154
|
+
# was found.
|
155
|
+
#
|
156
|
+
# @param [Resourceful::Request] request
|
157
|
+
# The request to use for the lookup.
|
158
|
+
#
|
159
|
+
# @return [Resourceful::Response]
|
160
|
+
# The cached response for the specified request if one is available.
|
161
|
+
def [](request)
|
162
|
+
entry = find { |entry| entry.valid_for?(request) }
|
163
|
+
entry.response if entry
|
164
|
+
end
|
165
|
+
|
166
|
+
# Saves an entry into the collection. Replaces any existing ones that could
|
167
|
+
# be used with the updated response.
|
168
|
+
#
|
169
|
+
# @param [Resourceful::Request] request
|
170
|
+
# The request that was used to obtain the response
|
171
|
+
# @param [Resourceful::Response] response
|
172
|
+
# The cache_entry generated from response that was obtained.
|
173
|
+
def []=(request, response)
|
174
|
+
@entries.delete_if { |e| e.valid_for?(request) }
|
175
|
+
@entries << CacheEntry.new(request, response)
|
176
|
+
|
177
|
+
response
|
178
|
+
end
|
179
|
+
end # class CacheEntryCollection
|
180
|
+
|
181
|
+
# Represents a previous request and cached response with enough
|
182
|
+
# detail to determine construct a cached response to a matching
|
183
|
+
# request in the future. It also understands what a matching
|
184
|
+
# request means.
|
185
|
+
class CacheEntry
|
186
|
+
# request_vary_headers is a HttpHeader with keys from the Vary
|
187
|
+
# header of the response, plus the values from the matching fields
|
188
|
+
# in the request
|
189
|
+
attr_reader :request_vary_headers
|
190
|
+
|
191
|
+
# The time at which the client believes the request was made.
|
192
|
+
attr_reader :request_time
|
193
|
+
|
194
|
+
# The URI of the request
|
195
|
+
attr_reader :request_uri
|
196
|
+
|
197
|
+
# The response to that we are caching
|
198
|
+
attr_reader :response
|
199
|
+
|
200
|
+
# @param [Resourceful::Request] request
|
201
|
+
# The request whose response we are storing in the cache.
|
202
|
+
# @param response<Resourceful::Response>
|
203
|
+
# The Response obhect to be stored.
|
204
|
+
def initialize(request, response)
|
205
|
+
@request_uri = request.uri
|
206
|
+
@request_time = request.request_time
|
207
|
+
@request_vary_headers = select_request_headers(request, response)
|
208
|
+
@response = response
|
209
|
+
end
|
210
|
+
|
211
|
+
# Returns true if this entry may be used to fullfil the given request,
|
212
|
+
# according to the vary headers.
|
213
|
+
#
|
214
|
+
# @param request<Resourceful::Request>
|
215
|
+
# The request to do the lookup on.
|
216
|
+
def valid_for?(request)
|
217
|
+
request.uri == @request_uri and
|
218
|
+
@request_vary_headers.all? {|key, value| request.header[key] == value}
|
219
|
+
end
|
220
|
+
|
221
|
+
# Selects the headers from the request named by the response's Vary header
|
222
|
+
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.6
|
223
|
+
#
|
224
|
+
# @param [Resourceful::Request] request
|
225
|
+
# The request used to obtain the response.
|
226
|
+
# @param [Resourceful::Response] response
|
227
|
+
# The response obtained from the request.
|
228
|
+
def select_request_headers(request, response)
|
229
|
+
header = Resourceful::Header.new
|
230
|
+
|
231
|
+
response.header['Vary'].each do |name|
|
232
|
+
header[name] = request.header[name]
|
233
|
+
end if response.header['Vary']
|
234
|
+
|
235
|
+
header
|
236
|
+
end
|
237
|
+
|
238
|
+
end # class CacheEntry
|
239
|
+
|
240
|
+
end
|