pezra-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 +27 -22
- data/README.markdown +11 -2
- data/lib/resourceful.rb +6 -2
- data/lib/resourceful/abstract_form_data.rb +18 -0
- data/lib/resourceful/header.rb +228 -97
- data/lib/resourceful/multipart_form_data.rb +6 -11
- data/lib/resourceful/net_http_adapter.rb +8 -2
- data/lib/resourceful/request.rb +1 -1
- data/lib/resourceful/resource.rb +10 -6
- data/lib/resourceful/response.rb +5 -5
- data/lib/resourceful/urlencoded_form_data.rb +17 -0
- data/resourceful.gemspec +7 -8
- data/spec/acceptance/caching_spec.rb +1 -1
- data/spec/acceptance/resource_spec.rb +3 -3
- data/spec/resourceful/header_spec.rb +8 -0
- data/spec/resourceful/multipart_form_data_spec.rb +0 -2
- data/spec/resourceful/urlencoded_form_data_spec.rb +44 -0
- metadata +43 -37
data/History.txt
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Version 0.6.0
|
2
|
+
=============
|
3
|
+
|
4
|
+
* Improved support for multi-valued header fields. (Peter Williams)
|
5
|
+
* Added convenience mechanisms for making URL encoded and multipart form data requests. (Peter Williams)
|
6
|
+
* Ruby 1.9 support (Peter Williams)
|
7
|
+
|
8
|
+
Compatibility issues
|
9
|
+
--------------------
|
10
|
+
|
11
|
+
* The semantics of the Resourceful::Header API have changed slightly.
|
12
|
+
Previously, any header might return a string or an array. Now
|
13
|
+
fields are either "single-value" and always return a string, or
|
14
|
+
"multi-value" and always return an array. See API doc for more
|
15
|
+
details.
|
16
|
+
|
17
|
+
|
18
|
+
|
data/Manifest
CHANGED
@@ -1,34 +1,39 @@
|
|
1
|
-
lib/resourceful
|
2
|
-
lib/resourceful/cache_manager.rb
|
3
|
-
lib/resourceful/exceptions.rb
|
4
|
-
lib/resourceful/header.rb
|
5
|
-
lib/resourceful/http_accessor.rb
|
6
|
-
lib/resourceful/memcache_cache_manager.rb
|
7
|
-
lib/resourceful/multipart_form_data.rb
|
1
|
+
lib/resourceful.rb
|
8
2
|
lib/resourceful/net_http_adapter.rb
|
9
3
|
lib/resourceful/options_interpretation.rb
|
10
|
-
lib/resourceful/request.rb
|
11
|
-
lib/resourceful/resource.rb
|
12
|
-
lib/resourceful/response.rb
|
13
4
|
lib/resourceful/stubbed_resource_proxy.rb
|
5
|
+
lib/resourceful/urlencoded_form_data.rb
|
6
|
+
lib/resourceful/header.rb
|
7
|
+
lib/resourceful/memcache_cache_manager.rb
|
8
|
+
lib/resourceful/response.rb
|
14
9
|
lib/resourceful/util.rb
|
15
|
-
lib/resourceful.rb
|
16
|
-
|
10
|
+
lib/resourceful/abstract_form_data.rb
|
11
|
+
lib/resourceful/cache_manager.rb
|
12
|
+
lib/resourceful/request.rb
|
13
|
+
lib/resourceful/resource.rb
|
14
|
+
lib/resourceful/exceptions.rb
|
15
|
+
lib/resourceful/multipart_form_data.rb
|
16
|
+
lib/resourceful/http_accessor.rb
|
17
|
+
lib/resourceful/authentication_manager.rb
|
18
|
+
History.txt
|
19
|
+
resourceful.gemspec
|
20
|
+
README.markdown
|
17
21
|
MIT-LICENSE
|
18
22
|
Rakefile
|
19
|
-
|
20
|
-
|
23
|
+
Manifest
|
24
|
+
spec/simple_sinatra_server_spec.rb
|
25
|
+
spec/old_acceptance_specs.rb
|
26
|
+
spec/acceptance_shared_specs.rb
|
27
|
+
spec/spec_helper.rb
|
28
|
+
spec/simple_sinatra_server.rb
|
21
29
|
spec/acceptance/authorization_spec.rb
|
22
|
-
spec/acceptance/caching_spec.rb
|
23
30
|
spec/acceptance/header_spec.rb
|
24
|
-
spec/acceptance/redirecting_spec.rb
|
25
31
|
spec/acceptance/resource_spec.rb
|
26
|
-
spec/
|
27
|
-
spec/
|
28
|
-
spec/old_acceptance_specs.rb
|
32
|
+
spec/acceptance/caching_spec.rb
|
33
|
+
spec/acceptance/redirecting_spec.rb
|
29
34
|
spec/resourceful/multipart_form_data_spec.rb
|
35
|
+
spec/resourceful/header_spec.rb
|
30
36
|
spec/resourceful/resource_spec.rb
|
31
|
-
spec/
|
32
|
-
spec/
|
37
|
+
spec/resourceful/urlencoded_form_data_spec.rb
|
38
|
+
spec/caching_spec.rb
|
33
39
|
spec/spec.opts
|
34
|
-
spec/spec_helper.rb
|
data/README.markdown
CHANGED
@@ -58,8 +58,17 @@ Post a URL encoded form
|
|
58
58
|
|
59
59
|
require 'resourceful'
|
60
60
|
http = Resourceful::HttpAccessor.new
|
61
|
-
resp = http.resource('http://mysite.example/service').
|
62
|
-
post('
|
61
|
+
resp = http.resource('http://mysite.example/service').
|
62
|
+
post(Resourceful::UrlencodedFormData.new(:hostname => 'test', :level => 'super'))
|
63
|
+
|
64
|
+
Post a Mulitpart form with a file
|
65
|
+
-----------------------
|
66
|
+
|
67
|
+
require 'resourceful'
|
68
|
+
http = Resourceful::HttpAccessor.new
|
69
|
+
form_data = Resourceful::MultipartFormData.new(:username => 'me')
|
70
|
+
form_data.add_file('avatar', '/tmp/my_avatar.png', 'image/png')
|
71
|
+
resp = http.resource('http://mysite.example/service').post(form_data)
|
63
72
|
|
64
73
|
Put an XML document
|
65
74
|
-------------------
|
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
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Resourceful
|
2
|
+
class AbstractFormData
|
3
|
+
def initialize(contents = {})
|
4
|
+
@form_data = []
|
5
|
+
|
6
|
+
contents.each do |k,v|
|
7
|
+
add(k, v)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def add(name, value)
|
12
|
+
form_data << [name.to_s, value]
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
attr_reader :form_data
|
17
|
+
end
|
18
|
+
end
|
data/lib/resourceful/header.rb
CHANGED
@@ -1,125 +1,256 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'resourceful/options_interpretation'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
# Represents the header fields of an HTTP message. To access a field
|
5
|
+
# you can use `#[]` and `#[]=`. For example, to get the content type
|
6
|
+
# of a response you can do
|
7
|
+
#
|
8
|
+
# response.header['Content-Type'] # => "application/xml"
|
9
|
+
#
|
10
|
+
# Lookups and modifications done in this way are case insensitive, so
|
11
|
+
# 'Content-Type', 'content-type' and :content_type are all equivalent.
|
12
|
+
#
|
13
|
+
# Multi-valued fields
|
14
|
+
# -------------------
|
15
|
+
#
|
16
|
+
# Multi-value fields (e.g. Accept) are always returned as an Array
|
17
|
+
# regardless of the number of values, if the field is present.
|
18
|
+
# Single-value fields (e.g. Content-Type) are always returned as
|
19
|
+
# strings. The multi/single valueness of a header field is determined
|
20
|
+
# by the way it is defined in the HTTP spec. Unknown fields are
|
21
|
+
# treated as multi-valued.
|
22
|
+
#
|
23
|
+
# (This behavior is new in 0.6 and may be slightly incompatible with
|
24
|
+
# the way previous versions worked in some situations.)
|
25
|
+
#
|
26
|
+
# For example
|
27
|
+
#
|
28
|
+
# h = Resourceful::Header.new
|
29
|
+
# h['Accept'] = "application/xml"
|
30
|
+
# h['Accept'] # => ["application/xml"]
|
31
|
+
#
|
3
32
|
module Resourceful
|
4
|
-
class Header
|
33
|
+
class Header
|
34
|
+
include Enumerable
|
35
|
+
|
5
36
|
def initialize(hash={})
|
37
|
+
@raw_fields = {}
|
6
38
|
hash.each { |k, v| self[k] = v }
|
7
39
|
end
|
8
40
|
|
9
41
|
def to_hash
|
10
|
-
|
42
|
+
@raw_fields.dup
|
11
43
|
end
|
12
44
|
|
13
45
|
def [](k)
|
14
|
-
|
46
|
+
field_def(k).get_from(@raw_fields)
|
15
47
|
end
|
16
48
|
|
17
49
|
def []=(k, v)
|
18
|
-
|
50
|
+
field_def(k).set_to(v, @raw_fields)
|
19
51
|
end
|
20
52
|
|
21
53
|
def has_key?(k)
|
22
|
-
|
54
|
+
field_def(k).exists_in?(@raw_fields)
|
55
|
+
end
|
56
|
+
|
57
|
+
def each(&blk)
|
58
|
+
@raw_fields.each(&blk)
|
59
|
+
end
|
60
|
+
alias each_field each
|
61
|
+
|
62
|
+
def merge!(another)
|
63
|
+
another.each do |k,v|
|
64
|
+
self[k] = v
|
65
|
+
end
|
66
|
+
self
|
23
67
|
end
|
24
68
|
|
25
|
-
def
|
26
|
-
|
69
|
+
def merge(another)
|
70
|
+
self.class.new(self).merge!(another)
|
27
71
|
end
|
28
72
|
|
29
|
-
def
|
30
|
-
|
31
|
-
blk.call capitalize(k), v
|
32
|
-
}
|
73
|
+
def reverse_merge(another)
|
74
|
+
self.class.new(another).merge!(self)
|
33
75
|
end
|
34
76
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
77
|
+
def dup
|
78
|
+
self.class.new(@raw_fields.dup)
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# Class to handle the details of each type of field.
|
83
|
+
class HeaderFieldDef
|
84
|
+
include Comparable
|
85
|
+
include OptionsInterpretation
|
86
|
+
|
87
|
+
##
|
88
|
+
attr_reader :name
|
89
|
+
|
90
|
+
def initialize(name, options = {})
|
91
|
+
@name = name
|
92
|
+
extract_opts(options) do |opts|
|
93
|
+
@repeatable = opts.extract(:repeatable, :default => false)
|
94
|
+
@hop_by_hop = opts.extract(:hop_by_hop, :default => false)
|
95
|
+
@modifiable = opts.extract(:modifiable, :default => true)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def repeatable?
|
100
|
+
@repeatable
|
101
|
+
end
|
102
|
+
|
103
|
+
def hop_by_hop?
|
104
|
+
@hop_by_hop
|
105
|
+
end
|
106
|
+
|
107
|
+
def modifiable?
|
108
|
+
@modifiable
|
109
|
+
end
|
110
|
+
|
111
|
+
def get_from(raw_fields_hash)
|
112
|
+
raw_fields_hash[name]
|
113
|
+
end
|
114
|
+
|
115
|
+
def set_to(value, raw_fields_hash)
|
116
|
+
raw_fields_hash[name] = if repeatable?
|
117
|
+
Array(value)
|
118
|
+
elsif value.kind_of?(Array)
|
119
|
+
raise ArgumentError, "#{name} field may only have one value" if value.size > 1
|
120
|
+
value.first
|
121
|
+
else
|
122
|
+
value
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def exists_in?(raw_fields_hash)
|
127
|
+
raw_fields_hash.has_key?(name)
|
128
|
+
end
|
129
|
+
|
130
|
+
def <=>(another)
|
131
|
+
name <=> another.name
|
132
|
+
end
|
101
133
|
|
134
|
+
def ==(another)
|
135
|
+
name_pattern === another.name
|
136
|
+
end
|
137
|
+
alias eql? ==
|
138
|
+
|
139
|
+
def ===(another)
|
140
|
+
if another.kind_of?(HeaderFieldDef)
|
141
|
+
self == another
|
142
|
+
else
|
143
|
+
name_pattern === another
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def name_pattern
|
148
|
+
Regexp.new('^' + name.gsub('-', '[_-]') + '$', Regexp::IGNORECASE)
|
149
|
+
end
|
150
|
+
|
151
|
+
def methodized_name
|
152
|
+
name.downcase.gsub('-', '_')
|
153
|
+
end
|
154
|
+
|
155
|
+
alias to_s name
|
156
|
+
|
157
|
+
def gen_setter(klass)
|
158
|
+
klass.class_eval <<-RUBY
|
159
|
+
def #{methodized_name}=(val) # def accept=(val)
|
160
|
+
self['#{name}'] = val # self['Accept'] = val
|
161
|
+
end # end
|
162
|
+
RUBY
|
163
|
+
end
|
164
|
+
|
165
|
+
def gen_getter(klass)
|
166
|
+
klass.class_eval <<-RUBY
|
167
|
+
def #{methodized_name} # def accept
|
168
|
+
self['#{name}'] # self['Accept']
|
169
|
+
end # end
|
170
|
+
RUBY
|
171
|
+
end
|
172
|
+
|
173
|
+
def gen_canonical_name_const(klass)
|
174
|
+
const_name = name.upcase.gsub('-', '_')
|
175
|
+
|
176
|
+
klass.const_set(const_name, name)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
@@header_field_defs = Set.new
|
181
|
+
|
182
|
+
def self.header_field(name, options = {})
|
183
|
+
hfd = HeaderFieldDef.new(name, options)
|
184
|
+
|
185
|
+
@@header_field_defs << hfd
|
186
|
+
|
187
|
+
hfd.gen_getter(self)
|
188
|
+
hfd.gen_setter(self)
|
189
|
+
hfd.gen_canonical_name_const(self)
|
190
|
+
end
|
191
|
+
|
192
|
+
def self.hop_by_hop_headers
|
193
|
+
@@header_field_defs.select{|hfd| hfd.hop_by_hop?}
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.non_modifiable_headers
|
197
|
+
@@header_field_defs.reject{|hfd| hfd.repeatable?}
|
198
|
+
end
|
199
|
+
|
200
|
+
def field_def(name)
|
201
|
+
@@header_field_defs.find{|hfd| hfd === name} ||
|
202
|
+
HeaderFieldDef.new(name.to_s.downcase.gsub(/^.|[-_\s]./) { |x| x.upcase }.gsub('_', '-'), :repeatable => true)
|
102
203
|
end
|
103
204
|
|
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
205
|
|
206
|
+
header_field('Accept', :repeatable => true)
|
207
|
+
header_field('Accept-Charset', :repeatable => true)
|
208
|
+
header_field('Accept-Encoding', :repeatable => true)
|
209
|
+
header_field('Accept-Language', :repeatable => true)
|
210
|
+
header_field('Accept-Ranges', :repeatable => true)
|
211
|
+
header_field('Age')
|
212
|
+
header_field('Allow', :repeatable => true)
|
213
|
+
header_field('Authorization', :repeatable => true)
|
214
|
+
header_field('Cache-Control', :repeatable => true)
|
215
|
+
header_field('Connection', :hop_by_hop => true)
|
216
|
+
header_field('Content-Encoding', :repeatable => true)
|
217
|
+
header_field('Content-Language', :repeatable => true)
|
218
|
+
header_field('Content-Length')
|
219
|
+
header_field('Content-Location', :modifiable => false)
|
220
|
+
header_field('Content-MD5', :modifiable => false)
|
221
|
+
header_field('Content-Range')
|
222
|
+
header_field('Content-Type')
|
223
|
+
header_field('Date')
|
224
|
+
header_field('ETag', :modifiable => false)
|
225
|
+
header_field('Expect', :repeatable => true)
|
226
|
+
header_field('Expires', :modifiable => false)
|
227
|
+
header_field('From')
|
228
|
+
header_field('Host')
|
229
|
+
header_field('If-Match', :repeatable => true)
|
230
|
+
header_field('If-Modified-Since')
|
231
|
+
header_field('If-None-Match', :repeatable => true)
|
232
|
+
header_field('If-Range')
|
233
|
+
header_field('If-Unmodified-Since')
|
234
|
+
header_field('Keep-Alive', :hop_by_hop => true)
|
235
|
+
header_field('Last-Modified', :modifiable => false)
|
236
|
+
header_field('Location')
|
237
|
+
header_field('Max-Forwards')
|
238
|
+
header_field('Pragma', :repeatable => true)
|
239
|
+
header_field('Proxy-Authenticate', :hop_by_hop => true)
|
240
|
+
header_field('Proxy-Authorization', :hop_by_hop => true)
|
241
|
+
header_field('Range')
|
242
|
+
header_field('Referer')
|
243
|
+
header_field('Retry-After')
|
244
|
+
header_field('Server')
|
245
|
+
header_field('TE', :repeatable => true, :hop_by_hop => true)
|
246
|
+
header_field('Trailer', :repeatable => true, :hop_by_hop => true)
|
247
|
+
header_field('Transfer-Encoding', :repeatable => true, :hop_by_hop => true)
|
248
|
+
header_field('Upgrade', :repeatable => true, :hop_by_hop => true)
|
249
|
+
header_field('User-Agent')
|
250
|
+
header_field('Vary', :repeatable => true)
|
251
|
+
header_field('Via', :repeatable => true)
|
252
|
+
header_field('Warning', :repeatable => true)
|
253
|
+
header_field('WWW-Authenticate', :repeatable => true)
|
123
254
|
end
|
124
255
|
end
|
125
256
|
|
@@ -1,16 +1,9 @@
|
|
1
|
+
require 'resourceful/abstract_form_data'
|
1
2
|
|
2
3
|
module Resourceful
|
3
|
-
class MultipartFormData
|
4
|
+
class MultipartFormData < AbstractFormData
|
4
5
|
FileParamValue = Struct.new(:content, :file_name, :content_type)
|
5
6
|
|
6
|
-
def initialize()
|
7
|
-
@form_data = []
|
8
|
-
end
|
9
|
-
|
10
|
-
def add(name, value)
|
11
|
-
form_data << [name, value]
|
12
|
-
end
|
13
|
-
|
14
7
|
def add_file(name, file_name, content_type="application/octet-stream")
|
15
8
|
add(name, FileParamValue.new(File.new(file_name, 'r'), File.basename(file_name), content_type))
|
16
9
|
end
|
@@ -21,8 +14,10 @@ module Resourceful
|
|
21
14
|
|
22
15
|
def read
|
23
16
|
StringIO.new.tap do |out|
|
17
|
+
first = true
|
24
18
|
form_data.each do |key, val|
|
25
|
-
out << "\r\n
|
19
|
+
out << "\r\n" unless first
|
20
|
+
out << "--" << boundary
|
26
21
|
out << "\r\nContent-Disposition: form-data; name=\"#{key}\""
|
27
22
|
if val.kind_of?(FileParamValue)
|
28
23
|
out << "; filename=\"#{val.file_name}\""
|
@@ -34,13 +29,13 @@ module Resourceful
|
|
34
29
|
else
|
35
30
|
out << val.to_s
|
36
31
|
end
|
32
|
+
first = false
|
37
33
|
end
|
38
34
|
out << "\r\n--#{boundary}--"
|
39
35
|
end.string
|
40
36
|
end
|
41
37
|
|
42
38
|
protected
|
43
|
-
attr_reader :form_data
|
44
39
|
|
45
40
|
def boundary
|
46
41
|
@boundary ||= (0..30).map{BOUNDARY_CHARS[rand(BOUNDARY_CHARS.length)]}.join
|
@@ -30,15 +30,21 @@ module Resourceful
|
|
30
30
|
def make_request(method, uri, body = nil, header = nil)
|
31
31
|
uri = uri.is_a?(Addressable::URI) ? uri : Addressable::URI.parse(uri)
|
32
32
|
|
33
|
+
if [:put, :post].include? method
|
34
|
+
body = body ? body.read : ""
|
35
|
+
header[:content_length] = body.size
|
36
|
+
end
|
37
|
+
|
33
38
|
req = net_http_request_class(method).new(uri.absolute_path)
|
34
39
|
header.each_field { |k,v| req[k] = v } if header
|
35
40
|
https = ("https" == uri.scheme)
|
36
|
-
|
41
|
+
conn_class = proxy_details ? Net::HTTP.Proxy(*proxy_details) : Net::HTTP
|
42
|
+
conn = conn_class.new(uri.host, uri.port || (https ? 443 : 80))
|
37
43
|
conn.use_ssl = https
|
38
44
|
begin
|
39
45
|
conn.start
|
40
46
|
res = if body
|
41
|
-
conn.request(req, body
|
47
|
+
conn.request(req, body)
|
42
48
|
else
|
43
49
|
conn.request(req)
|
44
50
|
end
|
data/lib/resourceful/request.rb
CHANGED
@@ -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
|
data/lib/resourceful/resource.rb
CHANGED
@@ -30,7 +30,7 @@ module Resourceful
|
|
30
30
|
alias uri effective_uri
|
31
31
|
|
32
32
|
def default_header(temp_defaults = {})
|
33
|
-
|
33
|
+
@default_header.merge(temp_defaults)
|
34
34
|
end
|
35
35
|
|
36
36
|
# Returns the host for this Resource's current uri
|
@@ -139,14 +139,14 @@ module Resourceful
|
|
139
139
|
|
140
140
|
# Ensures that the request has a content type header
|
141
141
|
def ensure_content_type(body, header)
|
142
|
-
return if header.has_key?(
|
142
|
+
return if header.has_key?('Content-Type')
|
143
143
|
|
144
144
|
if body.respond_to?(:content_type)
|
145
|
-
header[
|
145
|
+
header['Content-Type'] = body.content_type
|
146
146
|
return
|
147
147
|
end
|
148
148
|
|
149
|
-
return if default_header.has_key?(
|
149
|
+
return if default_header.has_key?('Content-Type')
|
150
150
|
|
151
151
|
# could not figure it out
|
152
152
|
raise MissingContentType
|
@@ -154,12 +154,16 @@ module Resourceful
|
|
154
154
|
|
155
155
|
# Actually make the request
|
156
156
|
def request(method, data, header)
|
157
|
+
header = default_header.merge(header)
|
157
158
|
ensure_content_type(data, header) if data
|
158
159
|
|
159
160
|
data = StringIO.new(data) if data.kind_of?(String)
|
160
161
|
|
161
|
-
|
162
|
-
|
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)
|
163
167
|
request.fetch_response
|
164
168
|
end
|
165
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/resourceful.gemspec
CHANGED
@@ -2,26 +2,25 @@
|
|
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-08-
|
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/
|
13
|
-
s.files = ["lib/resourceful/
|
14
|
-
s.has_rdoc = true
|
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"]
|
15
14
|
s.homepage = %q{http://github.com/paul/resourceful}
|
16
15
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Resourceful", "--main", "README.markdown"]
|
17
|
-
s.require_paths = ["lib"
|
16
|
+
s.require_paths = ["lib"]
|
18
17
|
s.rubyforge_project = %q{resourceful}
|
19
|
-
s.rubygems_version = %q{1.3.
|
18
|
+
s.rubygems_version = %q{1.3.5}
|
20
19
|
s.summary = %q{An HTTP library for Ruby that takes advantage of everything HTTP has to offer.}
|
21
20
|
|
22
21
|
if s.respond_to? :specification_version then
|
23
22
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
-
s.specification_version =
|
23
|
+
s.specification_version = 3
|
25
24
|
|
26
25
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
26
|
s.add_runtime_dependency(%q<addressable>, [">= 2.1.0"])
|
@@ -104,7 +104,7 @@ describe Resourceful do
|
|
104
104
|
|
105
105
|
it 'should revalidate the cached response if the response is expired' do
|
106
106
|
in_the_past = (Time.now - 60).httpdate
|
107
|
-
resource = @http.resource(uri_for_code(200, "
|
107
|
+
resource = @http.resource(uri_for_code(200, "Expires" => in_the_past))
|
108
108
|
|
109
109
|
resp = resource.get
|
110
110
|
resp.should be_expired
|
@@ -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
|
@@ -29,7 +29,6 @@ describe Resourceful::MultipartFormData do
|
|
29
29
|
|
30
30
|
boundary = /boundary=(\w+)/.match(@form_data.content_type)[1]
|
31
31
|
@form_data.read.should eql(<<MPFD[0..-2])
|
32
|
-
\r
|
33
32
|
--#{boundary}\r
|
34
33
|
Content-Disposition: form-data; name="foo"\r
|
35
34
|
\r
|
@@ -62,7 +61,6 @@ MPFD
|
|
62
61
|
|
63
62
|
boundary = /boundary=(\w+)/.match(@form_data.content_type)[1]
|
64
63
|
@form_data.read.should eql(<<MPFD[0..-2])
|
65
|
-
\r
|
66
64
|
--#{boundary}\r
|
67
65
|
Content-Disposition: form-data; name="foo"; filename="#{File.basename(file_to_upload.path)}"\r
|
68
66
|
Content-Type: application/octet-stream\r
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../spec_helper"
|
2
|
+
require 'tempfile'
|
3
|
+
require "resourceful/urlencoded_form_data.rb"
|
4
|
+
|
5
|
+
describe Resourceful::UrlencodedFormData do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@form_data = Resourceful::UrlencodedFormData.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should know its content-type" do
|
12
|
+
@form_data.content_type.should match(/^application\/x-www-form-urlencoded$/i)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "instantiation" do
|
16
|
+
it "should be creatable with hash" do
|
17
|
+
Resourceful::UrlencodedFormData.new(:foo => 'testing').read.should eql("foo=testing")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "with simple parameters" do
|
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
|
+
@form_data.read.should eql("foo=bar&baz=this")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should escape character in values that are unsafe" do
|
34
|
+
@form_data.add('foo', 'this & that')
|
35
|
+
|
36
|
+
@form_data.read.should eql("foo=this+%26+that")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should escape character in names that are unsafe" do
|
40
|
+
@form_data.add('foo=bar', 'this')
|
41
|
+
@form_data.read.should eql("foo%3Dbar=this")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pezra-resourceful
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Sadauskas
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-08-
|
12
|
+
date: 2009-08-14 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -79,58 +79,65 @@ executables: []
|
|
79
79
|
extensions: []
|
80
80
|
|
81
81
|
extra_rdoc_files:
|
82
|
-
- lib/resourceful
|
83
|
-
- lib/resourceful/cache_manager.rb
|
84
|
-
- lib/resourceful/exceptions.rb
|
85
|
-
- lib/resourceful/header.rb
|
86
|
-
- lib/resourceful/http_accessor.rb
|
87
|
-
- lib/resourceful/memcache_cache_manager.rb
|
88
|
-
- lib/resourceful/multipart_form_data.rb
|
82
|
+
- lib/resourceful.rb
|
89
83
|
- lib/resourceful/net_http_adapter.rb
|
90
84
|
- lib/resourceful/options_interpretation.rb
|
91
|
-
- lib/resourceful/request.rb
|
92
|
-
- lib/resourceful/resource.rb
|
93
|
-
- lib/resourceful/response.rb
|
94
85
|
- lib/resourceful/stubbed_resource_proxy.rb
|
86
|
+
- lib/resourceful/urlencoded_form_data.rb
|
87
|
+
- lib/resourceful/header.rb
|
88
|
+
- lib/resourceful/memcache_cache_manager.rb
|
89
|
+
- lib/resourceful/response.rb
|
95
90
|
- lib/resourceful/util.rb
|
96
|
-
- lib/resourceful.rb
|
97
|
-
- README.markdown
|
98
|
-
files:
|
99
|
-
- lib/resourceful/authentication_manager.rb
|
91
|
+
- lib/resourceful/abstract_form_data.rb
|
100
92
|
- lib/resourceful/cache_manager.rb
|
93
|
+
- lib/resourceful/request.rb
|
94
|
+
- lib/resourceful/resource.rb
|
101
95
|
- lib/resourceful/exceptions.rb
|
102
|
-
- lib/resourceful/header.rb
|
103
|
-
- lib/resourceful/http_accessor.rb
|
104
|
-
- lib/resourceful/memcache_cache_manager.rb
|
105
96
|
- lib/resourceful/multipart_form_data.rb
|
97
|
+
- lib/resourceful/http_accessor.rb
|
98
|
+
- lib/resourceful/authentication_manager.rb
|
99
|
+
- README.markdown
|
100
|
+
files:
|
101
|
+
- lib/resourceful.rb
|
106
102
|
- lib/resourceful/net_http_adapter.rb
|
107
103
|
- lib/resourceful/options_interpretation.rb
|
108
|
-
- lib/resourceful/request.rb
|
109
|
-
- lib/resourceful/resource.rb
|
110
|
-
- lib/resourceful/response.rb
|
111
104
|
- lib/resourceful/stubbed_resource_proxy.rb
|
105
|
+
- lib/resourceful/urlencoded_form_data.rb
|
106
|
+
- lib/resourceful/header.rb
|
107
|
+
- lib/resourceful/memcache_cache_manager.rb
|
108
|
+
- lib/resourceful/response.rb
|
112
109
|
- lib/resourceful/util.rb
|
113
|
-
- lib/resourceful.rb
|
114
|
-
-
|
110
|
+
- lib/resourceful/abstract_form_data.rb
|
111
|
+
- lib/resourceful/cache_manager.rb
|
112
|
+
- lib/resourceful/request.rb
|
113
|
+
- lib/resourceful/resource.rb
|
114
|
+
- lib/resourceful/exceptions.rb
|
115
|
+
- lib/resourceful/multipart_form_data.rb
|
116
|
+
- lib/resourceful/http_accessor.rb
|
117
|
+
- lib/resourceful/authentication_manager.rb
|
118
|
+
- History.txt
|
119
|
+
- resourceful.gemspec
|
120
|
+
- README.markdown
|
115
121
|
- MIT-LICENSE
|
116
122
|
- Rakefile
|
117
|
-
-
|
118
|
-
-
|
123
|
+
- Manifest
|
124
|
+
- spec/simple_sinatra_server_spec.rb
|
125
|
+
- spec/old_acceptance_specs.rb
|
126
|
+
- spec/acceptance_shared_specs.rb
|
127
|
+
- spec/spec_helper.rb
|
128
|
+
- spec/simple_sinatra_server.rb
|
119
129
|
- spec/acceptance/authorization_spec.rb
|
120
|
-
- spec/acceptance/caching_spec.rb
|
121
130
|
- spec/acceptance/header_spec.rb
|
122
|
-
- spec/acceptance/redirecting_spec.rb
|
123
131
|
- spec/acceptance/resource_spec.rb
|
124
|
-
- spec/
|
125
|
-
- spec/
|
126
|
-
- spec/old_acceptance_specs.rb
|
132
|
+
- spec/acceptance/caching_spec.rb
|
133
|
+
- spec/acceptance/redirecting_spec.rb
|
127
134
|
- spec/resourceful/multipart_form_data_spec.rb
|
135
|
+
- spec/resourceful/header_spec.rb
|
128
136
|
- spec/resourceful/resource_spec.rb
|
129
|
-
- spec/
|
130
|
-
- spec/
|
137
|
+
- spec/resourceful/urlencoded_form_data_spec.rb
|
138
|
+
- spec/caching_spec.rb
|
131
139
|
- spec/spec.opts
|
132
|
-
|
133
|
-
has_rdoc: true
|
140
|
+
has_rdoc: false
|
134
141
|
homepage: http://github.com/paul/resourceful
|
135
142
|
licenses:
|
136
143
|
post_install_message:
|
@@ -143,7 +150,6 @@ rdoc_options:
|
|
143
150
|
- README.markdown
|
144
151
|
require_paths:
|
145
152
|
- lib
|
146
|
-
- ext
|
147
153
|
required_ruby_version: !ruby/object:Gem::Requirement
|
148
154
|
requirements:
|
149
155
|
- - ">="
|
@@ -161,7 +167,7 @@ requirements: []
|
|
161
167
|
rubyforge_project: resourceful
|
162
168
|
rubygems_version: 1.3.5
|
163
169
|
signing_key:
|
164
|
-
specification_version:
|
170
|
+
specification_version: 3
|
165
171
|
summary: An HTTP library for Ruby that takes advantage of everything HTTP has to offer.
|
166
172
|
test_files: []
|
167
173
|
|