rackful 0.1.4 → 0.2.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.
@@ -1,285 +0,0 @@
1
- # Required for parsing:
2
- require 'rackful/resource.rb'
3
- require 'rackful/serializer.rb'
4
-
5
- # Required for running
6
- require 'rexml/rexml'
7
-
8
-
9
- module Rackful
10
-
11
- =begin markdown
12
- Exception which represents an HTTP Status response.
13
- @abstract
14
- =end
15
- class HTTPStatus < RuntimeError
16
-
17
-
18
- include Resource
19
-
20
-
21
- attr_reader :status, :headers, :to_rackful
22
-
23
-
24
- =begin markdown
25
- @param [Symbol, Integer] status e.g. `404` or `:not_found`
26
- @param [String] message XHTML
27
- @param [ { Symbol => Object }, { String => String } ] info
28
- * If the Hash is indexed by {Symbol}s, then the values will be returned in
29
- the response body.
30
- * If the Hash is indexed by {String}s, the +key => value+ pairs are returned
31
- as response headers.
32
- =end
33
- def initialize status, message = nil, info = {}
34
- self.path = Request.current.path
35
- @status = status_code status
36
- raise "Wrong status: #{status}" if 0 === @status
37
- message ||= ''
38
- @headers = {}
39
- @to_rackful = {}
40
- info.each do
41
- |k, v|
42
- if k.kind_of? Symbol then @to_rackful[k] = v
43
- else @headers[k] = v end
44
- end
45
- @to_rackful = nil if @to_rackful.empty?
46
- begin
47
- REXML::Document.new \
48
- '<?xml version="1.0" encoding="UTF-8" ?>' +
49
- "<div>#{message}</div>"
50
- rescue
51
- message = Rack::Utils.escape_html(message)
52
- end
53
- super message
54
- if 500 <= @status
55
- errors = Request.current.env['rack.errors']
56
- errors.puts self.inspect
57
- errors.puts "Headers: #{@headers.inspect}"
58
- errors.puts "Info: #{@to_rackful.inspect}"
59
- end
60
- end
61
-
62
-
63
- def title
64
- "#{status} #{HTTP_STATUS_CODES[status]}"
65
- end
66
-
67
-
68
- class XHTML < ::Rackful::XHTML
69
-
70
-
71
- def header
72
- super + <<EOS
73
- <h1>HTTP/1.1 #{Rack::Utils.escape_html(resource.title)}</h1>
74
- <div id="rackful_description">#{resource.message}</div>
75
- EOS
76
- end
77
-
78
-
79
- def headers; self.resource.headers; end
80
-
81
-
82
- end # class HTTPStatus::XHTML
83
-
84
-
85
- #~ class JSON < ::Rackful::JSON
86
- #~
87
- #~
88
- #~ def headers; self.resource.headers; end
89
- #~
90
- #~
91
- #~ def each &block
92
- #~ super( [ self.resource.message, self.resource.to_rackful ], &block )
93
- #~ end
94
- #~
95
- #~
96
- #~ end # class HTTPStatus::XHTML
97
-
98
-
99
- add_serializer XHTML, 1.0
100
-
101
-
102
- end # class Rackful::HTTPStatus
103
-
104
-
105
- =begin markdown
106
- @abstract Base class for HTTP status codes with only a simple text message, or
107
- no message at all.
108
- =end
109
- class HTTPSimpleStatus < HTTPStatus
110
-
111
- def initialize message = nil
112
- /HTTP(\d\d\d)\w+\z/ === self.class.to_s
113
- status = $1.to_i
114
- super( status, message )
115
- end
116
-
117
- end
118
-
119
-
120
- class HTTP201Created < HTTPStatus
121
-
122
- def initialize locations
123
- locations = [ locations ] unless locations.kind_of? Array
124
- locations = locations.collect { |l| l.to_path }
125
- rf = Request.current.resource_factory
126
- if locations.size > 1
127
- locations = locations.collect {
128
- |l|
129
- resource = rf[l]
130
- { :location => l }.merge( resource.default_headers )
131
- rf.uncache l if rf.respond_to? :uncache
132
- }
133
- super(
134
- 201, 'New resources were created:', :locations => locations
135
- )
136
- else
137
- location = locations[0]
138
- resource = rf[location]
139
- super(
140
- 201, 'A new resource was created:', {
141
- :location => location,
142
- 'Location' => location
143
- }.merge( resource.default_headers )
144
- )
145
- end
146
- end
147
-
148
- end # class HTTP201Created
149
-
150
-
151
- class HTTP202Accepted < HTTPStatus
152
-
153
- def initialize location = nil
154
- if location
155
- super(
156
- 202, '', {
157
- :'Job status location:' => Path.new(locations),
158
- 'Location' => locations
159
- }
160
- )
161
- else
162
- super 202
163
- end
164
- end
165
-
166
- end # class HTTP202Accepted
167
-
168
-
169
- class HTTP301MovedPermanently < HTTPStatus
170
-
171
- def initialize location
172
- super(
173
- 301, '', {
174
- :'New location:' => Path.new(location),
175
- 'Location' => location
176
- }
177
- )
178
- end
179
-
180
- end
181
-
182
-
183
- class HTTP303SeeOther < HTTPStatus
184
-
185
- def initialize location
186
- super(
187
- 303, '', {
188
- :'See:' => Path.new(location),
189
- 'Location' => location
190
- }
191
- )
192
- end
193
-
194
- end
195
-
196
-
197
- class HTTP304NotModified < HTTPStatus
198
-
199
- def initialize
200
- super( 304 )
201
- end
202
-
203
- end
204
-
205
-
206
- class HTTP307TemporaryRedirect < HTTPStatus
207
-
208
- def initialize location
209
- super(
210
- 301, '', {
211
- :'Current location:' => Path.new(location),
212
- 'Location' => location
213
- }
214
- )
215
- end
216
-
217
- end
218
-
219
-
220
- class HTTP400BadRequest < HTTPSimpleStatus; end
221
-
222
- class HTTP403Forbidden < HTTPSimpleStatus; end
223
-
224
- class HTTP404NotFound < HTTPSimpleStatus; end
225
-
226
-
227
- class HTTP405MethodNotAllowed < HTTPStatus
228
-
229
- def initialize methods
230
- super 405, '', 'Allow' => methods.join(', '),
231
- :'Allowed methods:' => methods
232
- end
233
-
234
- end
235
-
236
-
237
- class HTTP406NotAcceptable < HTTPStatus
238
-
239
- def initialize content_types
240
- super 406, '',
241
- :'Available content-type(s):' => content_types
242
- end
243
-
244
- end
245
-
246
-
247
- class HTTP409Conflict < HTTPSimpleStatus; end
248
-
249
- class HTTP410Gone < HTTPSimpleStatus; end
250
-
251
- class HTTP411LengthRequired < HTTPSimpleStatus; end
252
-
253
-
254
- class HTTP412PreconditionFailed < HTTPStatus
255
-
256
- def initialize header = nil
257
- info =
258
- if header
259
- { header.to_sym => Request.current.env[ 'HTTP_' + header.gsub('-', '_').upcase ] }
260
- else
261
- {}
262
- end
263
- super 412, 'Failed precondition:', info
264
- end
265
-
266
- end
267
-
268
-
269
- class HTTP415UnsupportedMediaType < HTTPStatus
270
-
271
- def initialize media_types
272
- super 415, '',
273
- :'Supported media-type(s):' => media_types
274
- end
275
-
276
- end
277
-
278
-
279
- class HTTP422UnprocessableEntity < HTTPSimpleStatus; end
280
-
281
- class HTTP501NotImplemented < HTTPSimpleStatus; end
282
-
283
- class HTTP503ServiceUnavailable < HTTPSimpleStatus; end
284
-
285
- end # module Rackful
@@ -1,72 +0,0 @@
1
- # Copyright ©2011-2012 Pieter van Beek <pieterb@sara.nl>
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- require 'rackful'
16
-
17
- =begin markdown
18
- Rack middleware that provides header spoofing.
19
-
20
- If you use this middleware, then clients are allowed to spoof an HTTP header
21
- by specifying a `_http_SOME_HEADER=...` request parameter, for example:
22
-
23
- http://example.com/some_resource?_http_DEPTH=infinity
24
-
25
- This can be useful if you want to specify certain request headers from within
26
- a normal web browser.
27
- @example Using this middleware
28
- use Rackful::HeaderSpoofing
29
- =end
30
- class Rackful::HeaderSpoofing
31
-
32
- def initialize app
33
- @app = app
34
- end
35
-
36
- def call env
37
- before_call env
38
- r = @app.call env
39
- after_call env
40
- r
41
- end
42
-
43
- def before_call env
44
- original_query_string = env['QUERY_STRING']
45
- env['QUERY_STRING'] = original_query_string.
46
- split('&', -1).
47
- collect { |s| s.split('=', -1) }.
48
- select {
49
- |p|
50
- if /\A_http_([a-z]+(?:[\-_][a-z]+)*)\z/i === p[0]
51
- header_name = p.shift.gsub('-', '_').upcase[1..-1]
52
- env[header_name] = p.join('=')
53
- false
54
- else
55
- true
56
- end
57
- }.
58
- collect { |p| p.join('=') }.
59
- join('&')
60
- if original_query_string != env['QUERY_STRING']
61
- env['rackful.header_spoofing.query_string'] ||= original_query_string
62
- end
63
- end
64
-
65
- def after_call env
66
- #if original_query_string = env['rackful.header_spoofing.query_string']
67
- #env['rackful.header_spoofing.query_string'] = env['QUERY_STRING']
68
- #env['QUERY_STRING'] = original_query_string
69
- #end
70
- end
71
-
72
- end # Rackful::HeaderSpoofing
@@ -1,101 +0,0 @@
1
- # Copyright ©2011-2012 Pieter van Beek <pieterb@sara.nl>
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- require 'rackful'
16
-
17
- =begin markdown
18
- Rack middleware that provides method spoofing.
19
-
20
- If you use this middleware, then clients are allowed to spoof an HTTP method
21
- by specifying a `_method=...` request parameter, for example:
22
-
23
- http://example.com/some_resource?_method=DELETE
24
-
25
- This can be useful if you want to perform `PUT` and `DELETE` requests from
26
- within a browser, of when you want to perform a `GET` requests with (too)
27
- many parameters, exceeding the maximum URI length in your client or server.
28
- In that case, you can put the parameters in a `POST` body, like this:
29
-
30
- POST /some_resource HTTP/1.1
31
- Host: example.com
32
- Content-Type: application/x-www-form-urlencoded
33
- Content-Length: 123456789
34
-
35
- param_1=hello&param_2=world&param_3=...
36
- @example Using this middleware
37
- use Rackful::MethodSpoofing
38
- =end
39
- class Rackful::MethodSpoofing
40
-
41
- def initialize app
42
- @app = app
43
- end
44
-
45
- def call env
46
- before_call env
47
- r = @app.call env
48
- after_call env
49
- r
50
- end
51
-
52
- def before_call env
53
- return unless ['GET', 'POST'].include? env['REQUEST_METHOD']
54
- original_query_string = env['QUERY_STRING']
55
- new_method = nil
56
- env['QUERY_STRING'] = original_query_string.
57
- split('&', -1).
58
- collect { |s| s.split('=', -1) }.
59
- select {
60
- |p|
61
- if /_method/i === p[0] &&
62
- /\A[A-Z]+\z/ === ( method = p[1..-1].join('=').upcase ) &&
63
- ! new_method
64
- new_method = method
65
- false
66
- else
67
- true
68
- end
69
- }.
70
- collect { |p| p.join('=') }.
71
- join('&')
72
- if new_method
73
- if 'GET' == new_method &&
74
- 'POST' == env['REQUEST_METHOD'] &&
75
- 'application/x-www-form-urlencoded' == env['CONTENT_TYPE']
76
- unless env['QUERY_STRING'].empty
77
- env['QUERY_STRING'] = env['QUERY_STRING'] + '&'
78
- end
79
- begin
80
- env['QUERY_STRING'] = env['QUERY_STRING'] + env['rack.input'].read
81
- env['rack.input'].rewind
82
- end
83
- env['rackful.method_spoofing.input'] = env['rack.input']
84
- env.delete 'rack.input'
85
- env.delete 'CONTENT_TYPE'
86
- env.delete 'CONTENT_LENGTH' if env.key? 'CONTENT_LENGTH'
87
- end
88
- env['rackful.method_spoofing.QUERY_STRING'] ||= original_query_string
89
- env['rackful.method_spoofing.REQUEST_METHOD'] = env['REQUEST_METHOD']
90
- env['REQUEST_METHOD'] = new_method
91
- end
92
- end
93
-
94
- def after_call env
95
- if env.key? 'rackful.method_spoofing.input'
96
- env['rack.input'] = env['rackful.method_spoofing.input']
97
- env.delete 'rackful.method_spoofing.input'
98
- end
99
- end
100
-
101
- end # Rackful::MethodSpoofing