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,34 @@
|
|
1
|
+
|
2
|
+
module Resourceful
|
3
|
+
|
4
|
+
# This exception used to indicate that the request did not succeed.
|
5
|
+
# The HTTP response is included so that the appropriate actions can
|
6
|
+
# be taken based on the details of that response
|
7
|
+
class UnsuccessfulHttpRequestError < Exception
|
8
|
+
attr_reader :http_response, :http_request
|
9
|
+
|
10
|
+
# Initialize new error from the HTTP request and response attributes.
|
11
|
+
def initialize(http_request, http_response)
|
12
|
+
super("#{http_request.method} request to <#{http_request.uri}> failed with code #{http_response.code}")
|
13
|
+
@http_request = http_request
|
14
|
+
@http_response = http_response
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class MalformedServerResponse < UnsuccessfulHttpRequestError
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
# Exception indicating that the server used a content coding scheme
|
23
|
+
# that Resourceful is unable to handle.
|
24
|
+
class UnsupportedContentCoding < Exception
|
25
|
+
end
|
26
|
+
|
27
|
+
# Raised when a body is supplied, but not a content-type header
|
28
|
+
class MissingContentType < ArgumentError
|
29
|
+
def initialize
|
30
|
+
super("A Content-Type must be specified when an entity-body is supplied.")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# A case-normalizing Hash, adjusting on [] and []=.
|
2
|
+
# Shamelessly swiped from Rack
|
3
|
+
module Resourceful
|
4
|
+
class Header < Hash
|
5
|
+
def initialize(hash={})
|
6
|
+
hash.each { |k, v| self[k] = v }
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_hash
|
10
|
+
{}.replace(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](k)
|
14
|
+
super capitalize(k)
|
15
|
+
end
|
16
|
+
|
17
|
+
def []=(k, v)
|
18
|
+
super capitalize(k), v
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_key?(k)
|
22
|
+
super capitalize(k)
|
23
|
+
end
|
24
|
+
|
25
|
+
def capitalize(k)
|
26
|
+
k.to_s.downcase.gsub(/^.|[-_\s]./) { |x| x.upcase }.gsub('_', '-')
|
27
|
+
end
|
28
|
+
|
29
|
+
def each_field(&blk)
|
30
|
+
to_hash.each { |k,v|
|
31
|
+
blk.call capitalize(k), v
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
HEADERS = %w[
|
36
|
+
Accept
|
37
|
+
Accept-Charset
|
38
|
+
Accept-Encoding
|
39
|
+
Accept-Language
|
40
|
+
Accept-Ranges
|
41
|
+
Age
|
42
|
+
Allow
|
43
|
+
Authorization
|
44
|
+
Cache-Control
|
45
|
+
Connection
|
46
|
+
Content-Encoding
|
47
|
+
Content-Language
|
48
|
+
Content-Length
|
49
|
+
Content-Location
|
50
|
+
Content-MD5
|
51
|
+
Content-Range
|
52
|
+
Content-Type
|
53
|
+
Date
|
54
|
+
ETag
|
55
|
+
Expect
|
56
|
+
Expires
|
57
|
+
From
|
58
|
+
Host
|
59
|
+
If-Match
|
60
|
+
If-Modified-Since
|
61
|
+
If-None-Match
|
62
|
+
If-Range
|
63
|
+
If-Unmodified-Since
|
64
|
+
Keep-Alive
|
65
|
+
Last-Modified
|
66
|
+
Location
|
67
|
+
Max-Forwards
|
68
|
+
Pragma
|
69
|
+
Proxy-Authenticate
|
70
|
+
Proxy-Authorization
|
71
|
+
Range
|
72
|
+
Referer
|
73
|
+
Retry-After
|
74
|
+
Server
|
75
|
+
TE
|
76
|
+
Trailer
|
77
|
+
Transfer-Encoding
|
78
|
+
Upgrade
|
79
|
+
User-Agent
|
80
|
+
Vary
|
81
|
+
Via
|
82
|
+
Warning
|
83
|
+
WWW-Authenticate
|
84
|
+
]
|
85
|
+
|
86
|
+
HEADERS.each do |header|
|
87
|
+
const = header.upcase.gsub('-', '_')
|
88
|
+
meth = header.downcase.gsub('-', '_')
|
89
|
+
|
90
|
+
class_eval <<-RUBY, __FILE__, __LINE__
|
91
|
+
#{const} = "#{header}".freeze # ACCEPT = "accept".freeze
|
92
|
+
|
93
|
+
def #{meth} # def accept
|
94
|
+
self[#{const}] # self[ACCEPT]
|
95
|
+
end # end
|
96
|
+
|
97
|
+
def #{meth}=(str) # def accept=(str)
|
98
|
+
self[#{const}] = str # self[ACCEPT] = str
|
99
|
+
end # end
|
100
|
+
RUBY
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
HOP_BY_HOP_HEADERS = [
|
105
|
+
CONNECTION,
|
106
|
+
KEEP_ALIVE,
|
107
|
+
PROXY_AUTHENTICATE,
|
108
|
+
PROXY_AUTHORIZATION,
|
109
|
+
TE,
|
110
|
+
TRAILER,
|
111
|
+
TRANSFER_ENCODING,
|
112
|
+
UPGRADE
|
113
|
+
].freeze
|
114
|
+
|
115
|
+
NON_MODIFIABLE_HEADERS = [
|
116
|
+
CONTENT_LOCATION,
|
117
|
+
CONTENT_MD5,
|
118
|
+
ETAG,
|
119
|
+
LAST_MODIFIED,
|
120
|
+
EXPIRES
|
121
|
+
].freeze
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
require 'resourceful/options_interpreter'
|
4
|
+
require 'resourceful/authentication_manager'
|
5
|
+
require 'resourceful/cache_manager'
|
6
|
+
require 'resourceful/resource'
|
7
|
+
require 'resourceful/stubbed_resource_proxy'
|
8
|
+
|
9
|
+
module Resourceful
|
10
|
+
# This is an imitation Logger used when no real logger is
|
11
|
+
# registered. This allows most of the code to assume that there
|
12
|
+
# is always a logger available, which significantly improved the
|
13
|
+
# readability of the logging related code.
|
14
|
+
class BitBucketLogger
|
15
|
+
def warn(*args); end
|
16
|
+
def info(*args); end
|
17
|
+
def debug(*args); end
|
18
|
+
end
|
19
|
+
|
20
|
+
# This is the simplest logger. It just writes everything to STDOUT.
|
21
|
+
class StdOutLogger
|
22
|
+
def warn(*args); puts args; end
|
23
|
+
def info(*args); puts args; end
|
24
|
+
def debug(*args); puts args; end
|
25
|
+
end
|
26
|
+
|
27
|
+
# This class provides a simple interface to the functionality
|
28
|
+
# provided by the Resourceful library. Conceptually this object
|
29
|
+
# acts a collection of all the resources available via HTTP.
|
30
|
+
class HttpAccessor
|
31
|
+
|
32
|
+
# A logger object to which messages about the activities of this
|
33
|
+
# object will be written. This should be an object that responds
|
34
|
+
# to +#info(message)+ and +#debug(message)+.
|
35
|
+
#
|
36
|
+
# Errors will not be logged. Instead an exception will be raised
|
37
|
+
# and the application code should log it if appropriate.
|
38
|
+
attr_accessor :logger, :cache_manager
|
39
|
+
|
40
|
+
attr_reader :auth_manager
|
41
|
+
attr_reader :user_agent_tokens
|
42
|
+
|
43
|
+
INIT_OPTIONS = OptionsInterpreter.new do
|
44
|
+
option(:logger, :default => Resourceful::BitBucketLogger.new)
|
45
|
+
option(:user_agent, :default => []) {|ua| [ua].flatten}
|
46
|
+
option(:cache_manager, :default => NullCacheManager.new)
|
47
|
+
option(:authenticator)
|
48
|
+
option(:authenticators, :default => [])
|
49
|
+
end
|
50
|
+
|
51
|
+
# Initializes a new HttpAccessor. Valid options:
|
52
|
+
#
|
53
|
+
# +:logger+:: A Logger object that the new HTTP accessor should
|
54
|
+
# send log messages
|
55
|
+
#
|
56
|
+
# +:user_agent+:: One or more additional user agent tokens to
|
57
|
+
# added to the user agent string.
|
58
|
+
#
|
59
|
+
# +:cache_manager+:: The cache manager this accessor should use.
|
60
|
+
#
|
61
|
+
# +:authenticator+:: Add a single authenticator for this accessor.
|
62
|
+
#
|
63
|
+
# +:authenticators+:: Enumerable of the authenticators for this
|
64
|
+
# accessor.
|
65
|
+
def initialize(options = {})
|
66
|
+
@user_agent_tokens = [RESOURCEFUL_USER_AGENT_TOKEN]
|
67
|
+
|
68
|
+
INIT_OPTIONS.interpret(options) do |opts|
|
69
|
+
@user_agent_tokens.push(*opts[:user_agent].reverse)
|
70
|
+
self.logger = opts[:logger]
|
71
|
+
@auth_manager = AuthenticationManager.new()
|
72
|
+
@cache_manager = opts[:cache_manager]
|
73
|
+
|
74
|
+
add_authenticator(opts[:authenticator]) if opts[:authenticator]
|
75
|
+
opts[:authenticators].each { |a| add_authenticator(a) }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns the string that identifies this HTTP accessor. If you
|
80
|
+
# want to add a token to the user agent string simply add the new
|
81
|
+
# token to the end of +#user_agent_tokens+.
|
82
|
+
def user_agent_string
|
83
|
+
user_agent_tokens.reverse.join(' ')
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns a resource object representing the resource indicated
|
87
|
+
# by the specified URI. A resource object will be created if necessary.
|
88
|
+
def resource(uri, opts = {})
|
89
|
+
resource = Resource.new(self, uri, opts)
|
90
|
+
end
|
91
|
+
alias [] resource
|
92
|
+
|
93
|
+
# Adds an Authenticator to the set used by the accessor.
|
94
|
+
def add_authenticator(an_authenticator)
|
95
|
+
auth_manager.add_auth_handler(an_authenticator)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "resourceful/cache_manager"
|
2
|
+
|
3
|
+
require 'memcache'
|
4
|
+
|
5
|
+
module Resourceful
|
6
|
+
class MemcacheCacheManager < AbstractCacheManager
|
7
|
+
|
8
|
+
# Create a new Memcached backed cache manager
|
9
|
+
#
|
10
|
+
# @param [*String] memcache_servers
|
11
|
+
# list of all Memcached servers this cache manager should use.
|
12
|
+
def initialize(*memcache_servers)
|
13
|
+
@memcache = MemCache.new(memcache_servers, :multithread => true)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Finds a previously cached response to the provided request. The
|
17
|
+
# response returned may be stale.
|
18
|
+
#
|
19
|
+
# @param [Resourceful::Request] request
|
20
|
+
# The request for which we are looking for a response.
|
21
|
+
#
|
22
|
+
# @return [Resourceful::Response, nil]
|
23
|
+
# A (possibly stale) response for the request provided or nil if
|
24
|
+
# no matching response is found.
|
25
|
+
def lookup(request)
|
26
|
+
resp = cache_entries_for(request)[request]
|
27
|
+
return if resp.nil?
|
28
|
+
|
29
|
+
resp.authoritative = false
|
30
|
+
|
31
|
+
resp
|
32
|
+
end
|
33
|
+
|
34
|
+
# Store a response in the cache.
|
35
|
+
#
|
36
|
+
# This method is smart enough to not store responses that cannot be
|
37
|
+
# cached (Vary: * or Cache-Control: no-cache, private, ...)
|
38
|
+
#
|
39
|
+
# @param [Resourceful::Request] request
|
40
|
+
# The request used to obtain the response. This is needed so the
|
41
|
+
# values from the response's Vary header can be stored.
|
42
|
+
# @param [Resourceful::Response] response
|
43
|
+
# The response to be stored.
|
44
|
+
def store(request, response)
|
45
|
+
return unless response.cachable?
|
46
|
+
|
47
|
+
entries = cache_entries_for(request)
|
48
|
+
entries[request] = response
|
49
|
+
|
50
|
+
@memcache[request.to_mc_key] = entries
|
51
|
+
end
|
52
|
+
|
53
|
+
# Invalidates a all cached entries for a uri.
|
54
|
+
#
|
55
|
+
# This is used, for example, to invalidate the cache for a resource
|
56
|
+
# that gets POSTed to.
|
57
|
+
#
|
58
|
+
# @param [String] uri
|
59
|
+
# The uri of the resource to be invalidated
|
60
|
+
def invalidate(uri)
|
61
|
+
@memcache.delete(uri_hash(uri))
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
##
|
68
|
+
# The memcache proxy.
|
69
|
+
attr_reader :memcache
|
70
|
+
|
71
|
+
def cache_entries_for(a_request)
|
72
|
+
@memcache.get(uri_hash(a_request.uri)) || Resourceful::CacheEntryCollection.new
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'addressable/uri'
|
4
|
+
|
5
|
+
require 'pathname'
|
6
|
+
require 'resourceful/header'
|
7
|
+
|
8
|
+
module Addressable
|
9
|
+
class URI
|
10
|
+
def absolute_path
|
11
|
+
absolute_path = ""
|
12
|
+
absolute_path << self.path.to_s
|
13
|
+
absolute_path << "?#{self.query}" if self.query != nil
|
14
|
+
absolute_path << "##{self.fragment}" if self.fragment != nil
|
15
|
+
return absolute_path
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Resourceful
|
21
|
+
|
22
|
+
class NetHttpAdapter
|
23
|
+
# Make an HTTP request using the standard library net/http.
|
24
|
+
#
|
25
|
+
# Will use a proxy defined in the http_proxy environment variable, if set.
|
26
|
+
def self.make_request(method, uri, body = nil, header = nil)
|
27
|
+
uri = uri.is_a?(Addressable::URI) ? uri : Addressable::URI.parse(uri)
|
28
|
+
|
29
|
+
req = net_http_request_class(method).new(uri.absolute_path)
|
30
|
+
header.each_field { |k,v| req[k] = v } if header
|
31
|
+
https = ("https" == uri.scheme)
|
32
|
+
conn = Net::HTTP.Proxy(*proxy_details).new(uri.host, uri.port || (https ? 443 : 80))
|
33
|
+
conn.use_ssl = https
|
34
|
+
begin
|
35
|
+
conn.start
|
36
|
+
res = conn.request(req, body)
|
37
|
+
ensure
|
38
|
+
conn.finish if conn.started?
|
39
|
+
end
|
40
|
+
|
41
|
+
[ Integer(res.code),
|
42
|
+
Resourceful::Header.new(res.header.to_hash),
|
43
|
+
res.body
|
44
|
+
]
|
45
|
+
ensure
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# Parse proxy details from http_proxy environment variable
|
52
|
+
def self.proxy_details
|
53
|
+
proxy = Addressable::URI.parse(ENV["http_proxy"])
|
54
|
+
[proxy.host, proxy.port, proxy.user, proxy.password] if proxy
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.net_http_request_class(method)
|
58
|
+
case method
|
59
|
+
when :get then Net::HTTP::Get
|
60
|
+
when :head then Net::HTTP::Head
|
61
|
+
when :post then Net::HTTP::Post
|
62
|
+
when :put then Net::HTTP::Put
|
63
|
+
when :delete then Net::HTTP::Delete
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Resourceful
|
4
|
+
# Class that supports a declarative way to pick apart an options
|
5
|
+
# hash.
|
6
|
+
#
|
7
|
+
# OptionsInterpreter.new do
|
8
|
+
# option(:accept) { |accept| [accept].flatten.map{|m| m.to_str} }
|
9
|
+
# option(:http_header_fields, :default => {})
|
10
|
+
# end.interpret(:accept => 'this/that')
|
11
|
+
# # => {:accept => ['this/that'], :http_header_fields => { } }
|
12
|
+
#
|
13
|
+
# The returned hash contains :accept with the pass accept option
|
14
|
+
# value transformed into an array and :http_header_fields with its
|
15
|
+
# default value.
|
16
|
+
#
|
17
|
+
# OptionsInterpreter.new do
|
18
|
+
# option(:max_redirects)
|
19
|
+
# end.interpret(:foo => 1, :bar => 2)
|
20
|
+
# # Raises ArgumentError: Unrecognized options: foo, bar
|
21
|
+
#
|
22
|
+
# If options are passed that are not defined an exception is raised.
|
23
|
+
#
|
24
|
+
class OptionsInterpreter
|
25
|
+
def self.interpret(options_hash, &block)
|
26
|
+
interpreter = self.new(options_hash)
|
27
|
+
interpreter.instance_eval(&block)
|
28
|
+
|
29
|
+
interpreter.interpret
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(&block)
|
33
|
+
@handlers = Hash.new
|
34
|
+
|
35
|
+
instance_eval(&block) if block_given?
|
36
|
+
end
|
37
|
+
|
38
|
+
def interpret(options_hash, &block)
|
39
|
+
unless (unrecognized_options = (options_hash.keys - supported_options)).empty?
|
40
|
+
raise ArgumentError, "Unrecognized options: #{unrecognized_options.join(", ")}"
|
41
|
+
end
|
42
|
+
|
43
|
+
options = Hash.new
|
44
|
+
handlers.each do |opt_name, a_handler|
|
45
|
+
opt_val = a_handler.call(options_hash)
|
46
|
+
options[opt_name] = opt_val if opt_val
|
47
|
+
end
|
48
|
+
|
49
|
+
yield(options) if block_given?
|
50
|
+
|
51
|
+
options
|
52
|
+
end
|
53
|
+
|
54
|
+
def option(name, opts = {}, &block)
|
55
|
+
|
56
|
+
passed_value_fetcher = if opts[:default]
|
57
|
+
default_value = opts[:default]
|
58
|
+
lambda{|options_hash| options_hash[name] || default_value}
|
59
|
+
else
|
60
|
+
lambda{|options_hash| options_hash[name]}
|
61
|
+
end
|
62
|
+
|
63
|
+
handlers[name] = if block_given?
|
64
|
+
lambda{|options_hash| (val = passed_value_fetcher.call(options_hash)) ? block.call(val) : nil}
|
65
|
+
else
|
66
|
+
passed_value_fetcher
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def supported_options
|
71
|
+
handlers.keys
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
attr_reader :handlers
|
77
|
+
end
|
78
|
+
end
|