paul-resourceful 0.5.4 → 0.6.0
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/History.txt +18 -0
- data/Manifest +11 -1
- data/README.markdown +11 -2
- data/Rakefile +38 -18
- data/lib/resourceful/abstract_form_data.rb +18 -0
- data/lib/resourceful/header.rb +228 -97
- data/lib/resourceful/http_accessor.rb +32 -26
- data/lib/resourceful/multipart_form_data.rb +46 -0
- data/lib/resourceful/net_http_adapter.rb +19 -5
- data/lib/resourceful/options_interpretation.rb +72 -0
- data/lib/resourceful/request.rb +6 -2
- data/lib/resourceful/resource.rb +25 -9
- data/lib/resourceful/response.rb +5 -5
- data/lib/resourceful/urlencoded_form_data.rb +17 -0
- data/lib/resourceful.rb +6 -2
- data/resourceful.gemspec +8 -8
- data/spec/acceptance/caching_spec.rb +6 -8
- data/spec/acceptance/header_spec.rb +1 -1
- data/spec/acceptance/resource_spec.rb +3 -3
- data/spec/caching_spec.rb +89 -0
- data/spec/resourceful/header_spec.rb +8 -0
- data/spec/resourceful/multipart_form_data_spec.rb +77 -0
- data/spec/resourceful/resource_spec.rb +20 -0
- data/spec/resourceful/urlencoded_form_data_spec.rb +44 -0
- data/spec/simple_sinatra_server.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- metadata +18 -6
- data/lib/resourceful/options_interpreter.rb +0 -78
@@ -23,17 +23,31 @@ module Resourceful
|
|
23
23
|
# Make an HTTP request using the standard library net/http.
|
24
24
|
#
|
25
25
|
# Will use a proxy defined in the http_proxy environment variable, if set.
|
26
|
-
|
26
|
+
#
|
27
|
+
# @param [#read] body
|
28
|
+
# An IO-ish thing containing the body of the request
|
29
|
+
#
|
30
|
+
def make_request(method, uri, body = nil, header = nil)
|
27
31
|
uri = uri.is_a?(Addressable::URI) ? uri : Addressable::URI.parse(uri)
|
28
32
|
|
33
|
+
if [:put, :post].include? method
|
34
|
+
body = body ? body.read : ""
|
35
|
+
header[:content_length] = body.size
|
36
|
+
end
|
37
|
+
|
29
38
|
req = net_http_request_class(method).new(uri.absolute_path)
|
30
39
|
header.each_field { |k,v| req[k] = v } if header
|
31
40
|
https = ("https" == uri.scheme)
|
32
|
-
|
41
|
+
conn_class = proxy_details ? Net::HTTP.Proxy(*proxy_details) : Net::HTTP
|
42
|
+
conn = conn_class.new(uri.host, uri.port || (https ? 443 : 80))
|
33
43
|
conn.use_ssl = https
|
34
44
|
begin
|
35
45
|
conn.start
|
36
|
-
res =
|
46
|
+
res = if body
|
47
|
+
conn.request(req, body)
|
48
|
+
else
|
49
|
+
conn.request(req)
|
50
|
+
end
|
37
51
|
ensure
|
38
52
|
conn.finish if conn.started?
|
39
53
|
end
|
@@ -49,12 +63,12 @@ module Resourceful
|
|
49
63
|
private
|
50
64
|
|
51
65
|
# Parse proxy details from http_proxy environment variable
|
52
|
-
def
|
66
|
+
def proxy_details
|
53
67
|
proxy = Addressable::URI.parse(ENV["http_proxy"])
|
54
68
|
[proxy.host, proxy.port, proxy.user, proxy.password] if proxy
|
55
69
|
end
|
56
70
|
|
57
|
-
def
|
71
|
+
def net_http_request_class(method)
|
58
72
|
case method
|
59
73
|
when :get then Net::HTTP::Get
|
60
74
|
when :head then Net::HTTP::Head
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Resourceful
|
2
|
+
# Declarative way of interpreting options hashes
|
3
|
+
#
|
4
|
+
# include OptionsInterpretion
|
5
|
+
# def my_method(opts = {})
|
6
|
+
# extract_opts(opts) do |opts|
|
7
|
+
# host = opts.extract(:host)
|
8
|
+
# port = opts.extract(:port, :default => 80) {|p| Integer(p)}
|
9
|
+
# end
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
module OptionsInterpretation
|
13
|
+
# Interpret an options hash
|
14
|
+
#
|
15
|
+
# @param [Hash] opts
|
16
|
+
# The options to interpret.
|
17
|
+
#
|
18
|
+
# @yield block that used to interpreter options hash
|
19
|
+
#
|
20
|
+
# @yieldparam [Resourceful::OptionsInterpretion::OptionsInterpreter] interpeter
|
21
|
+
# An interpreter that can be used to extract option information from the options hash.
|
22
|
+
def extract_opts(opts, &blk)
|
23
|
+
opts = opts.clone
|
24
|
+
yield OptionsInterpreter.new(opts)
|
25
|
+
|
26
|
+
unless opts.empty?
|
27
|
+
raise ArgumentError, "Unrecognized options: #{opts.keys.join(", ")}"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class OptionsInterpreter
|
33
|
+
def initialize(options_hash)
|
34
|
+
@options_hash = options_hash
|
35
|
+
end
|
36
|
+
|
37
|
+
# Extract a particular option.
|
38
|
+
#
|
39
|
+
# @param [String] name
|
40
|
+
# Name of option to extract
|
41
|
+
# @param [Hash] interpreter_opts
|
42
|
+
# ':default'
|
43
|
+
# :: The default value, or an object that responds to #call
|
44
|
+
# with the default value.
|
45
|
+
# ':required'
|
46
|
+
# :: Boolean indicating if this option is required. Default:
|
47
|
+
# false if a default is provided; otherwise true.
|
48
|
+
def extract(name, interpreter_opts = {}, &blk)
|
49
|
+
option_required = !interpreter_opts.has_key?(:default)
|
50
|
+
option_required = interpreter_opts[:required] if interpreter_opts.has_key?(:required)
|
51
|
+
|
52
|
+
raise ArgumentError, "Required option #{name} not provided" if option_required && !@options_hash.has_key?(name)
|
53
|
+
# We have the option we need
|
54
|
+
|
55
|
+
orig_val = @options_hash.delete(name)
|
56
|
+
|
57
|
+
if block_given?
|
58
|
+
yield orig_val
|
59
|
+
|
60
|
+
elsif orig_val
|
61
|
+
orig_val
|
62
|
+
|
63
|
+
elsif interpreter_opts[:default] && interpreter_opts[:default].respond_to?(:call)
|
64
|
+
interpreter_opts[:default].call()
|
65
|
+
|
66
|
+
elsif interpreter_opts[:default]
|
67
|
+
interpreter_opts[:default]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/resourceful/request.rb
CHANGED
@@ -163,7 +163,7 @@ module Resourceful
|
|
163
163
|
def perform!
|
164
164
|
@request_time = Time.now
|
165
165
|
|
166
|
-
http_resp =
|
166
|
+
http_resp = adapter.make_request(@method, @resource.uri, @body, @header)
|
167
167
|
@response = Resourceful::Response.new(uri, *http_resp)
|
168
168
|
@response.request_time = @request_time
|
169
169
|
@response.authoritative = true
|
@@ -205,7 +205,7 @@ module Resourceful
|
|
205
205
|
|
206
206
|
# Does this request force us to revalidate the cache?
|
207
207
|
def forces_revalidation?
|
208
|
-
if max_age == 0 ||
|
208
|
+
if max_age == 0 || skip_cache?
|
209
209
|
logger.info(" Client forced revalidation")
|
210
210
|
true
|
211
211
|
else
|
@@ -225,6 +225,10 @@ module Resourceful
|
|
225
225
|
def logger
|
226
226
|
resource.logger
|
227
227
|
end
|
228
|
+
|
229
|
+
def adapter
|
230
|
+
accessor.http_adapter
|
231
|
+
end
|
228
232
|
end
|
229
233
|
|
230
234
|
end
|
data/lib/resourceful/resource.rb
CHANGED
@@ -5,7 +5,6 @@ module Resourceful
|
|
5
5
|
|
6
6
|
class Resource
|
7
7
|
attr_reader :accessor
|
8
|
-
attr_accessor :default_header
|
9
8
|
|
10
9
|
# Build a new resource for a uri
|
11
10
|
#
|
@@ -30,6 +29,10 @@ module Resourceful
|
|
30
29
|
end
|
31
30
|
alias uri effective_uri
|
32
31
|
|
32
|
+
def default_header(temp_defaults = {})
|
33
|
+
@default_header.merge(temp_defaults)
|
34
|
+
end
|
35
|
+
|
33
36
|
# Returns the host for this Resource's current uri
|
34
37
|
def host
|
35
38
|
Addressable::URI.parse(uri).host
|
@@ -95,7 +98,6 @@ module Resourceful
|
|
95
98
|
# @raise [UnsuccessfulHttpRequestError] unless the request is a
|
96
99
|
# success, ie the final request returned a 2xx response code
|
97
100
|
def post(data = nil, header = {})
|
98
|
-
check_content_type_exists(data, header)
|
99
101
|
request(:post, data, header)
|
100
102
|
end
|
101
103
|
|
@@ -116,7 +118,6 @@ module Resourceful
|
|
116
118
|
# @raise [UnsuccessfulHttpRequestError] unless the request is a
|
117
119
|
# success, ie the final request returned a 2xx response code
|
118
120
|
def put(data, header = {})
|
119
|
-
check_content_type_exists(data, header)
|
120
121
|
request(:put, data, header)
|
121
122
|
end
|
122
123
|
|
@@ -137,17 +138,32 @@ module Resourceful
|
|
137
138
|
private
|
138
139
|
|
139
140
|
# Ensures that the request has a content type header
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
141
|
+
def ensure_content_type(body, header)
|
142
|
+
return if header.has_key?('Content-Type')
|
143
|
+
|
144
|
+
if body.respond_to?(:content_type)
|
145
|
+
header['Content-Type'] = body.content_type
|
146
|
+
return
|
144
147
|
end
|
148
|
+
|
149
|
+
return if default_header.has_key?('Content-Type')
|
150
|
+
|
151
|
+
# could not figure it out
|
152
|
+
raise MissingContentType
|
145
153
|
end
|
146
154
|
|
147
155
|
# Actually make the request
|
148
156
|
def request(method, data, header)
|
149
|
-
|
150
|
-
|
157
|
+
header = default_header.merge(header)
|
158
|
+
ensure_content_type(data, header) if data
|
159
|
+
|
160
|
+
data = StringIO.new(data) if data.kind_of?(String)
|
161
|
+
|
162
|
+
logger.debug { header.map {|k,v| "#{k}: #{v}"}.join("\n\t\t") }
|
163
|
+
logger.debug { data = StringIO.new(data.read); data.string } if data
|
164
|
+
|
165
|
+
log_request_with_time "#{method.to_s.upcase} [#{uri}]" do
|
166
|
+
request = Request.new(method, self, data, header)
|
151
167
|
request.fetch_response
|
152
168
|
end
|
153
169
|
end
|
data/lib/resourceful/response.rb
CHANGED
@@ -26,8 +26,8 @@ module Resourceful
|
|
26
26
|
if header['Cache-Control'] and header['Cache-Control'].first.include?('max-age')
|
27
27
|
max_age = header['Cache-Control'].first.split(',').grep(/max-age/).first.split('=').last.to_i
|
28
28
|
return true if current_age > max_age
|
29
|
-
elsif header['
|
30
|
-
return true if Time.httpdate(header['
|
29
|
+
elsif header['Expires']
|
30
|
+
return true if Time.httpdate(header['Expires']) < Time.now
|
31
31
|
end
|
32
32
|
|
33
33
|
false
|
@@ -75,8 +75,8 @@ module Resourceful
|
|
75
75
|
|
76
76
|
# Algorithm taken from RCF2616#13.2.3
|
77
77
|
def current_age
|
78
|
-
age_value = header['Age']
|
79
|
-
date_value = Time.httpdate(header['Date']
|
78
|
+
age_value = header['Age'] || 0
|
79
|
+
date_value = Time.httpdate(header['Date'])
|
80
80
|
now = Time.now
|
81
81
|
|
82
82
|
apparent_age = [0, response_time - date_value].max
|
@@ -85,7 +85,7 @@ module Resourceful
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def body
|
88
|
-
encoding = header['Content-Encoding']
|
88
|
+
encoding = header['Content-Encoding']
|
89
89
|
case encoding
|
90
90
|
when nil
|
91
91
|
# body is identity encoded; just return it
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'resourceful/abstract_form_data'
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
module Resourceful
|
5
|
+
class UrlencodedFormData < AbstractFormData
|
6
|
+
|
7
|
+
def content_type
|
8
|
+
"application/x-www-form-urlencoded"
|
9
|
+
end
|
10
|
+
|
11
|
+
def read
|
12
|
+
@form_data.map do |k,v|
|
13
|
+
CGI.escape(k) + '=' + CGI.escape(v)
|
14
|
+
end.join('&')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/resourceful.rb
CHANGED
@@ -10,9 +10,13 @@ require 'resourceful/util'
|
|
10
10
|
require 'resourceful/header'
|
11
11
|
require 'resourceful/http_accessor'
|
12
12
|
|
13
|
+
module Resourceful
|
14
|
+
autoload :MultipartFormData, 'resourceful/multipart_form_data'
|
15
|
+
autoload :UrlencodedFormData, 'resourceful/urlencoded_form_data'
|
16
|
+
end
|
17
|
+
|
13
18
|
# Resourceful is a library that provides a high level HTTP interface.
|
14
19
|
module Resourceful
|
15
|
-
VERSION = "0.
|
20
|
+
VERSION = "0.6.0"
|
16
21
|
RESOURCEFUL_USER_AGENT_TOKEN = "Resourceful/#{VERSION}(Ruby/#{RUBY_VERSION})"
|
17
|
-
|
18
22
|
end
|
data/resourceful.gemspec
CHANGED
@@ -2,20 +2,20 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{resourceful}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.6.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Paul Sadauskas"]
|
9
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-08-14}
|
10
10
|
s.description = %q{An HTTP library for Ruby that takes advantage of everything HTTP has to offer.}
|
11
11
|
s.email = %q{psadauskas@gmail.com}
|
12
|
-
s.extra_rdoc_files = ["lib/resourceful.rb", "lib/resourceful/net_http_adapter.rb", "lib/resourceful/stubbed_resource_proxy.rb", "lib/resourceful/header.rb", "lib/resourceful/memcache_cache_manager.rb", "lib/resourceful/response.rb", "lib/resourceful/util.rb", "lib/resourceful/
|
13
|
-
s.files = ["lib/resourceful.rb", "lib/resourceful/net_http_adapter.rb", "lib/resourceful/stubbed_resource_proxy.rb", "lib/resourceful/header.rb", "lib/resourceful/memcache_cache_manager.rb", "lib/resourceful/response.rb", "lib/resourceful/util.rb", "lib/resourceful/
|
12
|
+
s.extra_rdoc_files = ["lib/resourceful.rb", "lib/resourceful/net_http_adapter.rb", "lib/resourceful/options_interpretation.rb", "lib/resourceful/stubbed_resource_proxy.rb", "lib/resourceful/urlencoded_form_data.rb", "lib/resourceful/header.rb", "lib/resourceful/memcache_cache_manager.rb", "lib/resourceful/response.rb", "lib/resourceful/util.rb", "lib/resourceful/abstract_form_data.rb", "lib/resourceful/cache_manager.rb", "lib/resourceful/request.rb", "lib/resourceful/resource.rb", "lib/resourceful/exceptions.rb", "lib/resourceful/multipart_form_data.rb", "lib/resourceful/http_accessor.rb", "lib/resourceful/authentication_manager.rb", "README.markdown"]
|
13
|
+
s.files = ["lib/resourceful.rb", "lib/resourceful/net_http_adapter.rb", "lib/resourceful/options_interpretation.rb", "lib/resourceful/stubbed_resource_proxy.rb", "lib/resourceful/urlencoded_form_data.rb", "lib/resourceful/header.rb", "lib/resourceful/memcache_cache_manager.rb", "lib/resourceful/response.rb", "lib/resourceful/util.rb", "lib/resourceful/abstract_form_data.rb", "lib/resourceful/cache_manager.rb", "lib/resourceful/request.rb", "lib/resourceful/resource.rb", "lib/resourceful/exceptions.rb", "lib/resourceful/multipart_form_data.rb", "lib/resourceful/http_accessor.rb", "lib/resourceful/authentication_manager.rb", "History.txt", "resourceful.gemspec", "README.markdown", "MIT-LICENSE", "Rakefile", "Manifest", "spec/simple_sinatra_server_spec.rb", "spec/old_acceptance_specs.rb", "spec/acceptance_shared_specs.rb", "spec/spec_helper.rb", "spec/simple_sinatra_server.rb", "spec/acceptance/authorization_spec.rb", "spec/acceptance/header_spec.rb", "spec/acceptance/resource_spec.rb", "spec/acceptance/caching_spec.rb", "spec/acceptance/redirecting_spec.rb", "spec/resourceful/multipart_form_data_spec.rb", "spec/resourceful/header_spec.rb", "spec/resourceful/resource_spec.rb", "spec/resourceful/urlencoded_form_data_spec.rb", "spec/caching_spec.rb", "spec/spec.opts"]
|
14
14
|
s.homepage = %q{http://github.com/paul/resourceful}
|
15
15
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Resourceful", "--main", "README.markdown"]
|
16
16
|
s.require_paths = ["lib"]
|
17
17
|
s.rubyforge_project = %q{resourceful}
|
18
|
-
s.rubygems_version = %q{1.3.
|
18
|
+
s.rubygems_version = %q{1.3.5}
|
19
19
|
s.summary = %q{An HTTP library for Ruby that takes advantage of everything HTTP has to offer.}
|
20
20
|
|
21
21
|
if s.respond_to? :specification_version then
|
@@ -23,14 +23,14 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.specification_version = 3
|
24
24
|
|
25
25
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
|
-
s.add_runtime_dependency(%q<addressable>, [">= 0"])
|
26
|
+
s.add_runtime_dependency(%q<addressable>, [">= 2.1.0"])
|
27
27
|
s.add_runtime_dependency(%q<httpauth>, [">= 0"])
|
28
28
|
s.add_development_dependency(%q<thin>, [">= 0"])
|
29
29
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
30
30
|
s.add_development_dependency(%q<sinatra>, [">= 0"])
|
31
31
|
s.add_development_dependency(%q<rspec>, [">= 0"])
|
32
32
|
else
|
33
|
-
s.add_dependency(%q<addressable>, [">= 0"])
|
33
|
+
s.add_dependency(%q<addressable>, [">= 2.1.0"])
|
34
34
|
s.add_dependency(%q<httpauth>, [">= 0"])
|
35
35
|
s.add_dependency(%q<thin>, [">= 0"])
|
36
36
|
s.add_dependency(%q<yard>, [">= 0"])
|
@@ -38,7 +38,7 @@ Gem::Specification.new do |s|
|
|
38
38
|
s.add_dependency(%q<rspec>, [">= 0"])
|
39
39
|
end
|
40
40
|
else
|
41
|
-
s.add_dependency(%q<addressable>, [">= 0"])
|
41
|
+
s.add_dependency(%q<addressable>, [">= 2.1.0"])
|
42
42
|
s.add_dependency(%q<httpauth>, [">= 0"])
|
43
43
|
s.add_dependency(%q<thin>, [">= 0"])
|
44
44
|
s.add_dependency(%q<yard>, [">= 0"])
|
@@ -30,9 +30,7 @@ describe Resourceful do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def uri_for_code(code, params = {})
|
33
|
-
|
34
|
-
uri = template.expand("code" => code.to_s)
|
35
|
-
|
33
|
+
uri = Addressable::Template.new("http://localhost:42682/code/{code}").expand("code" => code.to_s)
|
36
34
|
uri_plus_params(uri, params)
|
37
35
|
end
|
38
36
|
|
@@ -106,7 +104,7 @@ describe Resourceful do
|
|
106
104
|
|
107
105
|
it 'should revalidate the cached response if the response is expired' do
|
108
106
|
in_the_past = (Time.now - 60).httpdate
|
109
|
-
resource = @http.resource(uri_for_code(200, "
|
107
|
+
resource = @http.resource(uri_for_code(200, "Expires" => in_the_past))
|
110
108
|
|
111
109
|
resp = resource.get
|
112
110
|
resp.should be_expired
|
@@ -121,7 +119,7 @@ describe Resourceful do
|
|
121
119
|
|
122
120
|
it "should be authoritative if the response is directly from the server" do
|
123
121
|
resource = @http.resource(
|
124
|
-
uri_plus_params('http://localhost:
|
122
|
+
uri_plus_params('http://localhost:42682/', "Cache-Control" => 'max-age=10')
|
125
123
|
)
|
126
124
|
|
127
125
|
response = resource.get
|
@@ -131,7 +129,7 @@ describe Resourceful do
|
|
131
129
|
it "should be authoritative if a cached response was revalidated with the server" do
|
132
130
|
now = Time.now.httpdate
|
133
131
|
resource = @http.resource(
|
134
|
-
uri_plus_params('http://localhost:
|
132
|
+
uri_plus_params('http://localhost:42682/cached',
|
135
133
|
"modified" => now,
|
136
134
|
"Cache-Control" => 'max-age=0')
|
137
135
|
)
|
@@ -144,7 +142,7 @@ describe Resourceful do
|
|
144
142
|
it "should not be authoritative if the cached response was not revalidated" do
|
145
143
|
now = Time.now.httpdate
|
146
144
|
resource = @http.resource(
|
147
|
-
uri_plus_params('http://localhost:
|
145
|
+
uri_plus_params('http://localhost:42682/cached',
|
148
146
|
"modified" => now,
|
149
147
|
"Cache-Control" => 'max-age=10')
|
150
148
|
)
|
@@ -162,7 +160,7 @@ describe Resourceful do
|
|
162
160
|
now = Time.now.httpdate
|
163
161
|
|
164
162
|
resource = @http.resource(
|
165
|
-
uri_plus_params('http://localhost:
|
163
|
+
uri_plus_params('http://localhost:42682/cached',
|
166
164
|
"modified" => now,
|
167
165
|
"Cache-Control" => 'max-age=0')
|
168
166
|
)
|
@@ -6,7 +6,7 @@ describe Resourceful do
|
|
6
6
|
describe 'setting headers' do
|
7
7
|
before do
|
8
8
|
@http = Resourceful::HttpAccessor.new
|
9
|
-
@resource = @http.resource("http://localhost:
|
9
|
+
@resource = @http.resource("http://localhost:42682/header")
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'should handle "Content-Type"' do
|
@@ -7,12 +7,12 @@ describe Resourceful do
|
|
7
7
|
describe "working with a resource" do
|
8
8
|
before do
|
9
9
|
@http = Resourceful::HttpAccessor.new
|
10
|
-
@resource = @http.resource('http://localhost:
|
10
|
+
@resource = @http.resource('http://localhost:42682/')
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'should make the original uri available' do
|
14
|
-
@resource.effective_uri.should == 'http://localhost:
|
15
|
-
@resource.uri.should == 'http://localhost:
|
14
|
+
@resource.effective_uri.should == 'http://localhost:42682/'
|
15
|
+
@resource.uri.should == 'http://localhost:42682/'
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'should set the user agent string on the default header' do
|
@@ -0,0 +1,89 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'fakeweb'
|
4
|
+
|
5
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "..", "lib")
|
6
|
+
require 'resourceful'
|
7
|
+
|
8
|
+
describe "Caching" do
|
9
|
+
|
10
|
+
before do
|
11
|
+
FakeWeb.allow_net_connect = false
|
12
|
+
FakeWeb.clean_registry
|
13
|
+
|
14
|
+
@http = Resourceful::HttpAccessor.new(:cache_manager => Resourceful::InMemoryCacheManager.new)
|
15
|
+
if ENV['SPEC_LOGGING']
|
16
|
+
@http.logger = Resourceful::StdOutLogger.new
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "should cache" do
|
21
|
+
|
22
|
+
before do
|
23
|
+
FakeWeb.register_uri(:get, "http://example.com/cache",
|
24
|
+
[{:body => "Original response", :cache_control => "private,max-age=15"},
|
25
|
+
{:body => "Overrode cached response"}]
|
26
|
+
)
|
27
|
+
|
28
|
+
@resource = @http.resource("http://example.com/cache")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should cache the response" do
|
32
|
+
resp = @resource.get
|
33
|
+
resp.body.should == "Original response"
|
34
|
+
|
35
|
+
resp = @resource.get
|
36
|
+
resp.body.should == "Original response"
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "updating headers" do
|
42
|
+
before do
|
43
|
+
FakeWeb.register_uri(:get, "http://example.com/override",
|
44
|
+
[{:body => "Original response", :cache_control => "private,max-age=0", :x_updateme => "foo"},
|
45
|
+
{:body => "Overrode cached response", :status => 304, :x_updateme => "bar"} ]
|
46
|
+
)
|
47
|
+
|
48
|
+
@resource = @http.resource("http://example.com/override")
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should update headers from the 304" do
|
52
|
+
resp = @resource.get
|
53
|
+
resp.headers['X-Updateme'].should == ["foo"]
|
54
|
+
|
55
|
+
resp = @resource.get
|
56
|
+
resp.headers['X-Updateme'].should == ["bar"]
|
57
|
+
resp.headers['Cache-Control'].should == ["private,max-age=0"]
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "updating expiration" do
|
63
|
+
before do
|
64
|
+
FakeWeb.register_uri(:get, "http://example.com/timeout",
|
65
|
+
[{:body => "Original response", :cache_control => "private,max-age=1"},
|
66
|
+
{:body => "cached response", :cache_control => "private,max-age=1"}]
|
67
|
+
)
|
68
|
+
|
69
|
+
@resource = @http.resource("http://example.com/timeout")
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should refresh the expiration timer" do
|
73
|
+
resp = @resource.get
|
74
|
+
resp.should_not be_stale
|
75
|
+
|
76
|
+
sleep 2
|
77
|
+
|
78
|
+
resp.should be_stale
|
79
|
+
|
80
|
+
resp = @resource.get
|
81
|
+
resp.should_not be_stale
|
82
|
+
|
83
|
+
resp = @resource.get
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../spec_helper"
|
2
|
+
require 'tempfile'
|
3
|
+
require "resourceful/multipart_form_data.rb"
|
4
|
+
|
5
|
+
describe Resourceful::MultipartFormData do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@form_data = Resourceful::MultipartFormData.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should know its content-type" do
|
12
|
+
@form_data.content_type.should match(/^multipart\/form-data/i)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should know its boundary string" do
|
16
|
+
@form_data.content_type.should match(/; boundary=[0-9A-Za-z]{10,}/i)
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
describe "with simple parameters" do
|
21
|
+
|
22
|
+
it "should all simple parameters to be added" do
|
23
|
+
@form_data.add(:foo, "testing")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should render a multipart form-data document when #read is called" do
|
27
|
+
@form_data.add('foo', 'bar')
|
28
|
+
@form_data.add('baz', 'this')
|
29
|
+
|
30
|
+
boundary = /boundary=(\w+)/.match(@form_data.content_type)[1]
|
31
|
+
@form_data.read.should eql(<<MPFD[0..-2])
|
32
|
+
--#{boundary}\r
|
33
|
+
Content-Disposition: form-data; name="foo"\r
|
34
|
+
\r
|
35
|
+
bar\r
|
36
|
+
--#{boundary}\r
|
37
|
+
Content-Disposition: form-data; name="baz"\r
|
38
|
+
\r
|
39
|
+
this\r
|
40
|
+
--#{boundary}--
|
41
|
+
MPFD
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "with file parameter" do
|
46
|
+
it "should add file parameters to be added" do
|
47
|
+
Tempfile.open('resourceful-post-file-tests') do |file_to_upload|
|
48
|
+
file_to_upload << "This is a test"
|
49
|
+
file_to_upload.flush
|
50
|
+
|
51
|
+
@form_data.add_file(:foo, file_to_upload.path)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should render a multipart form-data document when #read is called" do
|
56
|
+
Tempfile.open('resourceful-post-file-tests') do |file_to_upload|
|
57
|
+
file_to_upload << "This is a test"
|
58
|
+
file_to_upload.flush
|
59
|
+
|
60
|
+
@form_data.add_file(:foo, file_to_upload.path)
|
61
|
+
|
62
|
+
boundary = /boundary=(\w+)/.match(@form_data.content_type)[1]
|
63
|
+
@form_data.read.should eql(<<MPFD[0..-2])
|
64
|
+
--#{boundary}\r
|
65
|
+
Content-Disposition: form-data; name="foo"; filename="#{File.basename(file_to_upload.path)}"\r
|
66
|
+
Content-Type: application/octet-stream\r
|
67
|
+
\r
|
68
|
+
This is a test\r
|
69
|
+
--#{boundary}--
|
70
|
+
MPFD
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../spec_helper"
|
2
|
+
|
3
|
+
module Resourceful
|
4
|
+
describe Resource do
|
5
|
+
before do
|
6
|
+
@http_adapter = stub(:http_adapter)
|
7
|
+
http = Resourceful::HttpAccessor.new(:http_adapter => @http_adapter)
|
8
|
+
@resource = http.resource('http://foo.example')
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "POSTing" do
|
12
|
+
it "should use bodies content type as the request content-type if it is known" do
|
13
|
+
@http_adapter.should_receive(:make_request).with(anything, anything, anything, hash_including('Content-Type' => 'application/x-special-type')).and_return([200, {}, ""])
|
14
|
+
body = stub(:body, :content_type => 'application/x-special-type', :read => "hello there")
|
15
|
+
@resource.post(body)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|