joshbuddy-rack-rewrite 0.0.2
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.rdoc +41 -0
- data/VERSION.yml +4 -0
- data/lib/rack_rewrite/actions.rb +142 -0
- data/lib/rack_rewrite.rb +108 -0
- data/spec/conditions_spec.rb +22 -0
- data/spec/rewrite_spec.rb +24 -0
- data/spec/spec_helper.rb +11 -0
- metadata +61 -0
data/README.rdoc
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
= rack-rewrite
|
2
|
+
|
3
|
+
Rack middleware for request rewriting.
|
4
|
+
|
5
|
+
== Example
|
6
|
+
|
7
|
+
use Rack::Rewrite do
|
8
|
+
|
9
|
+
on :method => 'get' do
|
10
|
+
|
11
|
+
# When it sees /api or /test, it calls whatever is in the act block
|
12
|
+
#
|
13
|
+
on :uri => %r{/(api|test)} do
|
14
|
+
act { puts "hey way to go!" }
|
15
|
+
pass
|
16
|
+
end
|
17
|
+
|
18
|
+
# When it sees /google, it makes a redirect to google with the value of the query string as the search
|
19
|
+
#
|
20
|
+
on :uri => %r{/google.*} do
|
21
|
+
redirect { "http://google.com/search?q=#{CGI.escape(query_string)}" }
|
22
|
+
end
|
23
|
+
|
24
|
+
# If a URI starts with /valid_place, it strips it off and keeps on truckin'
|
25
|
+
#
|
26
|
+
on :uri => %r{/valid_place/.*} do
|
27
|
+
set(:uri) { uri[%r{/valid_place(/.*)}, 1] }
|
28
|
+
pass
|
29
|
+
end
|
30
|
+
|
31
|
+
# If a URI starts with /hello_kitty, add a kitty header equal to your query string
|
32
|
+
#
|
33
|
+
on :uri => %r{/hello_kitty/.*} do
|
34
|
+
act { header['kitty'] = query_string }
|
35
|
+
pass
|
36
|
+
end
|
37
|
+
|
38
|
+
fail
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/VERSION.yml
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
module Rack
|
2
|
+
class Rewrite
|
3
|
+
class Action
|
4
|
+
|
5
|
+
def uri
|
6
|
+
@env['PATH_INFO']
|
7
|
+
end
|
8
|
+
|
9
|
+
def uri=(uri)
|
10
|
+
@env['PATH_INFO'] = uri
|
11
|
+
update_uri_qs
|
12
|
+
end
|
13
|
+
|
14
|
+
def query_string
|
15
|
+
@env['QUERY_STRING']
|
16
|
+
end
|
17
|
+
|
18
|
+
def query_string=(query_string)
|
19
|
+
@env['QUERY_STRING'] = query_string
|
20
|
+
update_uri_qs
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_uri_qs
|
24
|
+
@env['REQUEST_PATH'] = uri
|
25
|
+
@env['REQUEST_URI'] = query_string.empty? ? uri : "#{uri}?#{query_string}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def method
|
29
|
+
@env['REQUEST_METHOD']
|
30
|
+
end
|
31
|
+
|
32
|
+
def method=(method)
|
33
|
+
@env['REQUEST_METHOD'] = method.to_s.upcase
|
34
|
+
end
|
35
|
+
|
36
|
+
def host
|
37
|
+
@env['HTTP_HOST']
|
38
|
+
end
|
39
|
+
|
40
|
+
def host=(host)
|
41
|
+
@env['HTTP_HOST'] = host
|
42
|
+
end
|
43
|
+
|
44
|
+
def port
|
45
|
+
@env['SERVER_PORT']
|
46
|
+
end
|
47
|
+
|
48
|
+
def port=(port)
|
49
|
+
@env['SERVER_PORT'] = port.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
def scheme
|
53
|
+
@env['rack.url_scheme']
|
54
|
+
end
|
55
|
+
|
56
|
+
def scheme=(scheme)
|
57
|
+
@env['rack.url_scheme'] = scheme
|
58
|
+
end
|
59
|
+
|
60
|
+
def setup(env)
|
61
|
+
@env = env
|
62
|
+
end
|
63
|
+
|
64
|
+
class Pass < Action
|
65
|
+
def call(env)
|
66
|
+
throw :pass
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class Fail < Action
|
71
|
+
def call(env)
|
72
|
+
raise
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Set < Action
|
77
|
+
|
78
|
+
def initialize(variable, action)
|
79
|
+
@variable = variable
|
80
|
+
@action = action
|
81
|
+
end
|
82
|
+
|
83
|
+
def call(env)
|
84
|
+
setup(env)
|
85
|
+
self.send :"#{@variable}=", case @action
|
86
|
+
when Proc
|
87
|
+
instance_eval(&@action)
|
88
|
+
else
|
89
|
+
instance_eval(@action)
|
90
|
+
end
|
91
|
+
env
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
class Do < Action
|
97
|
+
def initialize(caller, action)
|
98
|
+
@caller = caller
|
99
|
+
@action = action
|
100
|
+
end
|
101
|
+
|
102
|
+
def method_missing(method, *args, &block)
|
103
|
+
@caller.send(method, *args, &block)
|
104
|
+
end
|
105
|
+
|
106
|
+
def call(env)
|
107
|
+
setup(env)
|
108
|
+
case @action
|
109
|
+
when Proc
|
110
|
+
instance_eval(&@action)
|
111
|
+
else
|
112
|
+
instance_eval(@action)
|
113
|
+
end
|
114
|
+
env
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
class Redirect < Action
|
120
|
+
def initialize(caller, action)
|
121
|
+
@caller = caller
|
122
|
+
@action = action
|
123
|
+
end
|
124
|
+
|
125
|
+
def call(env)
|
126
|
+
setup(env)
|
127
|
+
@caller.redirect = [ 302, {'Location'=> case @action
|
128
|
+
when Proc
|
129
|
+
instance_eval(&@action)
|
130
|
+
else
|
131
|
+
instance_eval(@action)
|
132
|
+
end}, []]
|
133
|
+
throw :pass
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
|
data/lib/rack_rewrite.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__))
|
2
|
+
require 'rack_rewrite/actions'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
class Rewrite
|
6
|
+
|
7
|
+
attr_accessor :path, :redirect, :headers
|
8
|
+
|
9
|
+
class ConditionSet
|
10
|
+
|
11
|
+
attr_reader :parent_set, :actions, :conditions
|
12
|
+
|
13
|
+
def initialize(parent_set, conditions = nil)
|
14
|
+
@parent_set = parent_set
|
15
|
+
@conditions = conditions
|
16
|
+
@actions = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def satisfied?(env)
|
20
|
+
if conditions
|
21
|
+
|
22
|
+
uri_ok = conditions.key?(:uri) ? conditions[:uri] === env['PATH_INFO'] : true
|
23
|
+
method_ok = conditions.key?(:method) ? conditions[:method] === env['REQUEST_METHOD'].downcase : true
|
24
|
+
host_ok = conditions.key?(:host) ? conditions[:host] === env['HTTP_HOST'] : true
|
25
|
+
port_ok = conditions.key?(:port) ? conditions[:port] === env['SERVER_PORT'].to_i : true
|
26
|
+
scheme_ok = conditions.key?(:scheme) ? conditions[:scheme] === env['rack.url_scheme'] : true
|
27
|
+
|
28
|
+
#puts "uri_ok: #{uri_ok} method_ok #{method_ok} host_ok #{host_ok} port_ok #{port_ok} scheme_ok #{scheme_ok} for conditions #{conditions.inspect}"
|
29
|
+
|
30
|
+
uri_ok && method_ok && host_ok && port_ok && scheme_ok
|
31
|
+
else
|
32
|
+
true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect
|
37
|
+
"#{id} .. conditions=#{conditions.inspect}\nactions=#{actions.inspect}"
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(app, options = {}, &block)
|
43
|
+
@app = app
|
44
|
+
@options = []
|
45
|
+
@current_condition_set = @root = ConditionSet.new(nil)
|
46
|
+
instance_eval(&block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def on(conditions = {}, &block)
|
50
|
+
@current_condition_set.actions << ConditionSet.new(@current_condition_set, conditions)
|
51
|
+
@current_condition_set = @current_condition_set.actions.last
|
52
|
+
instance_eval(&block)
|
53
|
+
@current_condition_set = @current_condition_set.parent_set
|
54
|
+
end
|
55
|
+
|
56
|
+
def set(variable, pattern = nil, &block)
|
57
|
+
@current_condition_set.actions << Action::Set.new(variable, pattern || block)
|
58
|
+
end
|
59
|
+
|
60
|
+
def act(&block)
|
61
|
+
@current_condition_set.actions << Action::Do.new(self, block)
|
62
|
+
end
|
63
|
+
|
64
|
+
def pass
|
65
|
+
@current_condition_set.actions << Action::Pass.new
|
66
|
+
end
|
67
|
+
|
68
|
+
def fail
|
69
|
+
@current_condition_set.actions << Action::Fail.new
|
70
|
+
end
|
71
|
+
|
72
|
+
def redirect(pattern = nil, &block)
|
73
|
+
@current_condition_set.actions << Action::Redirect.new(self, pattern || block)
|
74
|
+
end
|
75
|
+
|
76
|
+
def call(env)
|
77
|
+
@headers = {}
|
78
|
+
catch(:pass) {
|
79
|
+
env = call_conditions(env, @root)
|
80
|
+
raise
|
81
|
+
}
|
82
|
+
if @redirect
|
83
|
+
redirect = @redirect
|
84
|
+
@redirect = nil
|
85
|
+
redirect
|
86
|
+
else
|
87
|
+
(status, headers, body) = @app.call(env)
|
88
|
+
[status, headers.merge(@headers), body]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def call_conditions(env, conditions_set)
|
93
|
+
if conditions_set.satisfied?(env)
|
94
|
+
conditions_set.actions.each_with_index do |act, index|
|
95
|
+
break if @done
|
96
|
+
case act
|
97
|
+
when ConditionSet
|
98
|
+
call_conditions(env, act)
|
99
|
+
else
|
100
|
+
env = act.call(env)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Rack::Rewrite Conditions" do
|
4
|
+
|
5
|
+
['get', 'post', 'put', 'delete'].each do |method|
|
6
|
+
|
7
|
+
it "should detect method #{method}" do
|
8
|
+
env = Rack::MockRequest.env_for('/test', :method => method)
|
9
|
+
app = mock('app')
|
10
|
+
app.should_receive(:call).with(env).and_return([200, {}, ["body"]])
|
11
|
+
Rack::Rewrite.new(app) { on(:method => method) { pass } }.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should detect a simple uri" do
|
16
|
+
env = Rack::MockRequest.env_for('/test', :method => 'get')
|
17
|
+
app = mock('app')
|
18
|
+
app.should_receive(:call).with(env).and_return([200, {}, ["body"]])
|
19
|
+
Rack::Rewrite.new(app) { on(:uri => '/test') { pass } }.call(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Rack::Rewrite Rewriting" do
|
4
|
+
|
5
|
+
it "should rewrite a uri" do
|
6
|
+
env = Rack::MockRequest.env_for('/test', :method => 'get')
|
7
|
+
app = mock('app')
|
8
|
+
app.should_receive(:call) { |resp|
|
9
|
+
resp['PATH_INFO'].should == '/test/test'
|
10
|
+
[200, {}, ["body"]]
|
11
|
+
}
|
12
|
+
|
13
|
+
Rack::Rewrite.new(app) { on(:uri => '/test') { set(:uri) { "/test#{uri}" }; pass } }.call(env)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should arbitrarily add a new header" do
|
17
|
+
env = Rack::MockRequest.env_for('/test?Happy-Land', :method => 'get')
|
18
|
+
app = mock('app')
|
19
|
+
app.should_receive(:call).and_return([200, {'Content-type' => 'text/html'}, ['mybody']])
|
20
|
+
response = Rack::Rewrite.new(app) { on(:uri => '/test') { act{ headers['My-special-header'] = query_string }; pass } }.call(env)
|
21
|
+
response[1]['My-special-header'].should == 'Happy-Land'
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: joshbuddy-rack-rewrite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joshua Hull
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-04 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: joshbuddy@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- README.rdoc
|
26
|
+
- VERSION.yml
|
27
|
+
- lib/rack_rewrite
|
28
|
+
- lib/rack_rewrite/actions.rb
|
29
|
+
- lib/rack_rewrite.rb
|
30
|
+
- spec/conditions_spec.rb
|
31
|
+
- spec/rewrite_spec.rb
|
32
|
+
- spec/spec_helper.rb
|
33
|
+
has_rdoc: true
|
34
|
+
homepage: http://github.com/joshbuddy/rack-rewrite
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options:
|
37
|
+
- --inline-source
|
38
|
+
- --charset=UTF-8
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.2.0
|
57
|
+
signing_key:
|
58
|
+
specification_version: 2
|
59
|
+
summary: TODO
|
60
|
+
test_files: []
|
61
|
+
|