rackful 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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