rackful 0.0.2 → 0.1.0

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