rackful 0.0.2 → 0.1.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/README.md CHANGED
@@ -1,2 +1,14 @@
1
- All documentation is available
2
- [here, as GitHub pages](http://pieterb.github.com/Rackful/).
1
+ Rackful
2
+ =======
3
+
4
+ Library for creating Rackful web services
5
+
6
+ The latest documentation is always available
7
+ [here, as GitHub pages](http://pieterb.github.com/Rackful/).
8
+
9
+ Licensing
10
+ ---------
11
+ Copyright ©2011-2012 Pieter van Beek <pieterb@sara.nl>
12
+
13
+ Licensed under the Apache License 2.0. You should have received a copy of the
14
+ license as part of this distribution.
data/example/config.ru CHANGED
@@ -1,26 +1,28 @@
1
- require File.dirname(__FILE__) + '/../lib/rackful.rb'
1
+ require 'rackful'
2
+ require 'rackful/header_spoofing'
3
+ require 'rackful/method_spoofing'
4
+ require 'rackful/relative_location'
2
5
  require 'digest/md5'
3
6
 
4
7
  # The class of the object we're going to serve:
5
8
  class Root
6
9
  include Rackful::Resource
7
- def initialize *args
8
- super
9
- @content = 'Hello world!'
10
- end
11
- def do_GET request, response
12
- response['Content-Type'] = 'text/plain'
13
- response.write @content
10
+ attr_reader :to_rackful
11
+ def initialize
12
+ self.path = '/'
13
+ @to_rackful = 'Hello world!'
14
14
  end
15
15
  def do_PUT request, response
16
- @content = request.body.read
17
- response.status = status_code :no_content
16
+ @to_rackful = request.body.read.encode( Encoding::UTF_8 )
18
17
  end
19
- def etag
20
- '"' + Digest::MD5.new.update(@content).to_s + '"'
18
+ def get_etag
19
+ '"' + Digest::MD5.new.update(to_rackful).to_s + '"'
21
20
  end
21
+ add_serializer Rackful::XHTML, 1.0
22
+ add_serializer Rackful::JSON, 1.0
23
+ add_media_type 'text/plain'
22
24
  end
23
- $root_resource = Root.new '/'
25
+ $root_resource = Root.new
24
26
 
25
27
  # Rackful::Server needs a resource factory which can map URIs to resource objects:
26
28
  class ResourceFactory
@@ -32,4 +34,8 @@ class ResourceFactory
32
34
  end
33
35
  end
34
36
 
37
+ use Rackful::MethodSpoofing
38
+ use Rackful::HeaderSpoofing
39
+ use Rackful::RelativeLocation
40
+
35
41
  run Rackful::Server.new ResourceFactory.new
@@ -0,0 +1,41 @@
1
+ require 'rack'
2
+ require 'rackful/header_spoofing'
3
+ require 'rackful/method_spoofing'
4
+ require 'rackful/relative_location'
5
+
6
+ # The class of the object we're going to serve:
7
+ class Root
8
+ include Rackful::Resource
9
+ def initialize *args
10
+ super
11
+ @content = 'Hello world!'
12
+ end
13
+ def do_GET request, response
14
+ response['Content-Type'] = 'text/plain'
15
+ response.write @content
16
+ end
17
+ def do_PUT request, response
18
+ @content = request.body.read
19
+ response.status = status_code :no_content
20
+ end
21
+ def etag
22
+ '"' + Digest::MD5.new.update(@content).to_s + '"'
23
+ end
24
+ end
25
+ $root_resource = Root.new '/'
26
+
27
+ # Rackful::Server needs a resource factory which can map URIs to resource objects:
28
+ class ResourceFactory
29
+ def [] uri
30
+ case uri
31
+ when '/'; $root_resource
32
+ else; nil
33
+ end
34
+ end
35
+ end
36
+
37
+ use Rackful::MethodSpoofing
38
+ use Rackful::HeaderSpoofing
39
+ use Rackful::RelativeLocation
40
+
41
+ run Rackful::Server.new ResourceFactory.new
@@ -12,9 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- module Rackful
15
+ require 'rackful'
16
16
 
17
- =begin
17
+ =begin markdown
18
18
  Rack middleware that provides header spoofing.
19
19
 
20
20
  If you use this middleware, then clients are allowed to spoof an HTTP header
@@ -26,41 +26,48 @@ This can be useful if you want to specify certain request headers from within
26
26
  a normal web browser.
27
27
  @example Using this middleware
28
28
  use Rackful::HeaderSpoofing
29
+ @since 0.0.1
29
30
  =end
30
- class HeaderSpoofing
31
+ class Rackful::HeaderSpoofing
31
32
 
32
- def initialize app
33
- @app = app
34
- end
33
+ def initialize app
34
+ @app = app
35
+ end
35
36
 
36
- def call env
37
- before_call env
38
- @app.call env
39
- # after_call env
40
- end
37
+ def call env
38
+ before_call env
39
+ r = @app.call env
40
+ after_call env
41
+ r
42
+ end
41
43
 
42
- def before_call env
43
- original_query_string = env['QUERY_STRING']
44
- env['QUERY_STRING'] = original_query_string.
45
- split('&', -1).
46
- collect { |s| s.split('=', -1) }.
47
- select {
48
- |p|
49
- if /\A_http_([a-z]+(?:[\-_][a-z]+)*)\z/i === p[0]
50
- header_name = p.shift.gsub('-', '_').upcase
51
- env[header_name] = p.join('=')
52
- false
53
- else
54
- true
55
- end
56
- }.
57
- collect { |p| p.join('=') }.
58
- join('&')
59
- if original_query_string != env['QUERY_STRING']
60
- env['rackful.header_spoofing.query_string'] ||= original_query_string
44
+ def before_call env
45
+ original_query_string = env['QUERY_STRING']
46
+ env['QUERY_STRING'] = original_query_string.
47
+ split('&', -1).
48
+ collect { |s| s.split('=', -1) }.
49
+ select {
50
+ |p|
51
+ if /\A_http_([a-z]+(?:[\-_][a-z]+)*)\z/i === p[0]
52
+ header_name = p.shift.gsub('-', '_').upcase[1..-1]
53
+ env[header_name] = p.join('=')
54
+ false
55
+ else
56
+ true
61
57
  end
62
- end
58
+ }.
59
+ collect { |p| p.join('=') }.
60
+ join('&')
61
+ if original_query_string != env['QUERY_STRING']
62
+ env['rackful.header_spoofing.query_string'] ||= original_query_string
63
+ end
64
+ end
63
65
 
66
+ def after_call env
67
+ if original_query_string = env['rackful.header_spoofing.query_string']
68
+ env['rackful.header_spoofing.query_string'] = env['QUERY_STRING']
69
+ env['QUERY_STRING'] = original_query_string
64
70
  end
71
+ end
65
72
 
66
- end
73
+ end # Rackful::HeaderSpoofing
@@ -14,9 +14,7 @@
14
14
 
15
15
  require 'rackful'
16
16
 
17
- module Rackful
18
-
19
- =begin
17
+ =begin markdown
20
18
  Rack middleware that provides method spoofing.
21
19
 
22
20
  If you use this middleware, then clients are allowed to spoof an HTTP method
@@ -37,68 +35,68 @@ In that case, you can put the parameters in a `POST` body, like this:
37
35
  param_1=hello&param_2=world&param_3=...
38
36
  @example Using this middleware
39
37
  use Rackful::MethodSpoofing
38
+ @since 0.0.1
40
39
  =end
41
- class MethodSpoofing
40
+ class Rackful::MethodSpoofing
42
41
 
43
- def initialize app
44
- @app = app
45
- end
42
+ def initialize app
43
+ @app = app
44
+ end
46
45
 
47
- def call env
48
- before_call env
49
- @app.call env
50
- after_call env
51
- end
46
+ def call env
47
+ before_call env
48
+ r = @app.call env
49
+ after_call env
50
+ r
51
+ end
52
52
 
53
- def before_call env
54
- return unless ['GET', 'POST'].include? env['REQUEST_METHOD']
55
- original_query_string = env['QUERY_STRING']
56
- new_method = nil
57
- env['QUERY_STRING'] = original_query_string.
58
- split('&', -1).
59
- collect { |s| s.split('=', -1) }.
60
- select {
61
- |p|
62
- if /_method/i === p[0] &&
63
- /\A[A-Z]+\z/ === ( method = p[1..-1].join('=').upcase ) &&
64
- ! new_method
65
- new_method = method
66
- false
67
- else
68
- true
69
- end
70
- }.
71
- collect { |p| p.join('=') }.
72
- join('&')
73
- if new_method
74
- if 'GET' == new_method &&
75
- 'POST' == env['REQUEST_METHOD'] &&
76
- 'application/x-www-form-urlencoded' == env['CONTENT_TYPE']
77
- unless env['QUERY_STRING'].empty
78
- env['QUERY_STRING'] = env['QUERY_STRING'] + '&'
79
- end
80
- begin
81
- env['QUERY_STRING'] = env['QUERY_STRING'] + env['rack.input'].read
82
- env['rack.input'].rewind
83
- end
84
- env['rackful.method_spoofing.input'] = env['rack.input']
85
- env.delete 'rack.input'
86
- env.delete 'CONTENT_TYPE'
87
- env.delete 'CONTENT_LENGTH' if env.key? 'CONTENT_LENGTH'
88
- end
89
- env['rackful.method_spoofing.QUERY_STRING'] ||= original_query_string
90
- env['rackful.method_spoofing.REQUEST_METHOD'] = env['REQUEST_METHOD']
91
- env['REQUEST_METHOD'] = new_method
53
+ def before_call env
54
+ return unless ['GET', 'POST'].include? env['REQUEST_METHOD']
55
+ original_query_string = env['QUERY_STRING']
56
+ new_method = nil
57
+ env['QUERY_STRING'] = original_query_string.
58
+ split('&', -1).
59
+ collect { |s| s.split('=', -1) }.
60
+ select {
61
+ |p|
62
+ if /_method/i === p[0] &&
63
+ /\A[A-Z]+\z/ === ( method = p[1..-1].join('=').upcase ) &&
64
+ ! new_method
65
+ new_method = method
66
+ false
67
+ else
68
+ true
92
69
  end
93
- end
94
-
95
- def after_call env
96
- if env.key? 'rackful.method_spoofing.input'
97
- env['rack.input'] = env['rackful.method_spoofing.input']
98
- env.delete 'rackful.input'
70
+ }.
71
+ collect { |p| p.join('=') }.
72
+ join('&')
73
+ if new_method
74
+ if 'GET' == new_method &&
75
+ 'POST' == env['REQUEST_METHOD'] &&
76
+ 'application/x-www-form-urlencoded' == env['CONTENT_TYPE']
77
+ unless env['QUERY_STRING'].empty
78
+ env['QUERY_STRING'] = env['QUERY_STRING'] + '&'
79
+ end
80
+ begin
81
+ env['QUERY_STRING'] = env['QUERY_STRING'] + env['rack.input'].read
82
+ env['rack.input'].rewind
99
83
  end
84
+ env['rackful.method_spoofing.input'] = env['rack.input']
85
+ env.delete 'rack.input'
86
+ env.delete 'CONTENT_TYPE'
87
+ env.delete 'CONTENT_LENGTH' if env.key? 'CONTENT_LENGTH'
100
88
  end
101
-
89
+ env['rackful.method_spoofing.QUERY_STRING'] ||= original_query_string
90
+ env['rackful.method_spoofing.REQUEST_METHOD'] = env['REQUEST_METHOD']
91
+ env['REQUEST_METHOD'] = new_method
102
92
  end
93
+ end
103
94
 
95
+ def after_call env
96
+ if env.key? 'rackful.method_spoofing.input'
97
+ env['rack.input'] = env['rackful.method_spoofing.input']
98
+ env.delete 'rackful.method_spoofing.input'
99
+ end
104
100
  end
101
+
102
+ end # Rackful::MethodSpoofing
@@ -12,11 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
-
15
+ require 'rackful'
16
16
  require 'rack/request'
17
17
 
18
- module Rackful
19
-
20
18
  =begin markdown
21
19
  Rack middleware, inspired by {Rack::RelativeRedirect}.
22
20
 
@@ -31,28 +29,44 @@ Differences with {Rack::RelativeRedirect}:
31
29
  - uses Rack::Request::base_url for creating absolute URIs.
32
30
  - the `Location:` header, if present, is always rectified, independent of the
33
31
  HTTP status code.
32
+ @since 0.0.1
34
33
  =end
35
- class RelativeLocation
34
+ class Rackful::RelativeLocation
36
35
 
37
- def initialize(app)
38
- @app = app
39
- end
36
+ def initialize(app)
37
+ @app = app
38
+ end
40
39
 
41
- def call(env)
42
- res = @app.call(env)
43
- if ( location = res[1]['Location'] ) and
44
- ! %r{\A[a-z]+://}.match(location)
45
- request = Rack::Request.new env
46
- unless '/' == location[0, 1]
47
- path = request.path.dup
48
- path[ %r{[^/]*\z} ] = ''
49
- location = File.expand_path( location, path )
50
- end
51
- res[1]['Location'] = request.base_url + location
40
+ def call_old(env)
41
+ res = @app.call(env)
42
+ if ( location = res[1]['Location'] ) and
43
+ ! %r{\A[a-z]+://}.match(location)
44
+ request = Rack::Request.new env
45
+ unless '/' == location[0, 1]
46
+ path = ( res[1]['Content-Location'] || request.path ).dup
47
+ path[ %r{[^/]*\z} ] = ''
48
+ location = File.expand_path( location, path )
52
49
  end
53
- res
50
+ if '/' == location[0, 1]
51
+ location = request.base_url + location
52
+ end
53
+ res[1]['Location'] = location
54
54
  end
55
+ res
56
+ end
55
57
 
56
- end # RelativeLocation
58
+ def call(env)
59
+ res = @app.call(env)
60
+ request = nil
61
+ ['Location', 'Content-Location'].each do
62
+ |header|
63
+ if ( location = res[1][header] ) and
64
+ '/' == location[0,1]
65
+ request ||= Rack::Request.new env
66
+ res[1][header] = request.base_url + location
67
+ end
68
+ end
69
+ res
70
+ end
57
71
 
58
- end # Rackful
72
+ end # Rackful::RelativeLocation