rack_ssi 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/.gitignore +17 -0
- data/Gemfile +9 -0
- data/LICENSE +22 -0
- data/README.md +39 -0
- data/Rakefile +7 -0
- data/lib/rack_ssi.rb +41 -0
- data/lib/ssi_processor.rb +69 -0
- data/rack-ssi.gemspec +20 -0
- data/spec/rack_ssi_spec.rb +68 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/ssi_processor_spec.rb +197 -0
- metadata +91 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Thibaut Sacreste
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Rack::SSI
|
2
|
+
|
3
|
+
Rack middleware for processing SSI based on the [nginx HttpSsiModule](http://wiki.nginx.org/HttpSsiModule).
|
4
|
+
Directives currently supported: `block` and `include`
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'rack_ssi', :git => "git@github.com:forward/rack-ssi.git"
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install rack_ssi
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
require 'rack_ssi'
|
23
|
+
|
24
|
+
### Sinatra
|
25
|
+
|
26
|
+
configure do
|
27
|
+
use Rack::SSI, {
|
28
|
+
:logging => :on,
|
29
|
+
:when => lambda {|env| not env['SOME_CUSTOM_HEADER'] == 'ON'},
|
30
|
+
:locations => {
|
31
|
+
%r{^/includes} => "http://includes.mydomain.com"
|
32
|
+
}
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
### Rails
|
37
|
+
|
38
|
+
config.middleware.use Rack::SSI, { ... }
|
39
|
+
|
data/Rakefile
ADDED
data/lib/rack_ssi.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path('../ssi_processor', __FILE__)
|
2
|
+
require 'rest_client'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module Rack
|
6
|
+
class SSI
|
7
|
+
|
8
|
+
def initialize(app, options = {})
|
9
|
+
@app = app
|
10
|
+
@logging = options[:logging] == :on
|
11
|
+
@locations = options[:locations] || {}
|
12
|
+
@predicate = options[:when] || lambda {|_| true}
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
status, headers, body = @app.call(env)
|
17
|
+
unprocessed = [status, headers, body]
|
18
|
+
|
19
|
+
return unprocessed unless @predicate.call(env)
|
20
|
+
return unprocessed unless headers["Content-Type"] && headers["Content-Type"].include?("text/html")
|
21
|
+
return unprocessed unless status == 200
|
22
|
+
|
23
|
+
ssi = Rack::SSIProcessor.new
|
24
|
+
ssi.locations = @locations
|
25
|
+
ssi.logger = logger(env) if @logging
|
26
|
+
new_body = ssi.process(body)
|
27
|
+
headers["Content-Length"] = (new_body.reduce(0) {|sum, part| sum + part.bytesize}).to_s
|
28
|
+
|
29
|
+
[status, headers, new_body]
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def logger(env)
|
34
|
+
if defined?(Rails)
|
35
|
+
return Rails.logger
|
36
|
+
end
|
37
|
+
env['rack.logger']
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Rack
|
2
|
+
class SSIProcessor
|
3
|
+
|
4
|
+
attr_accessor :logger, :locations
|
5
|
+
|
6
|
+
def process(body)
|
7
|
+
# see http://wiki.nginx.org/HttpSsiModule
|
8
|
+
# currently only supporting 'block' and 'include' directives
|
9
|
+
blocks = {}
|
10
|
+
output = []
|
11
|
+
body.each do |part|
|
12
|
+
new_part = process_block(part) {|name, content| blocks[name] = content}
|
13
|
+
output << process_include(new_part, blocks)
|
14
|
+
end
|
15
|
+
output
|
16
|
+
end
|
17
|
+
|
18
|
+
def process_block(part)
|
19
|
+
part.gsub(/<!--#\s+block\s+name="(\w+)"\s+-->(.*?)<!--#\s+endblock\s+-->/) do
|
20
|
+
name, content = $1, $2
|
21
|
+
_info "processing block directive with name=#{name}"
|
22
|
+
yield [name, content]
|
23
|
+
""
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def process_include(part, blocks)
|
28
|
+
part.gsub(/<!--#\s+include\s+(?:virtual|file)="([^"]+)"(?:\s+stub="(\w+)")?\s+-->/) do
|
29
|
+
location, stub = $1, $2
|
30
|
+
_info "processing include directive with location=#{location}"
|
31
|
+
status, _, body = fetch location
|
32
|
+
if stub && (status != 200 || body.nil? || body == "")
|
33
|
+
blocks[stub]
|
34
|
+
else
|
35
|
+
body
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def fetch(location)
|
41
|
+
locations.select{|k,v| k.is_a?(String)}.each do |pattern, host|
|
42
|
+
return _get("#{host}#{location}") if location == pattern
|
43
|
+
end
|
44
|
+
locations.select{|k,v| k.is_a?(Regexp)}.each do |pattern, host|
|
45
|
+
return _get("#{host}#{location}") if location =~ pattern
|
46
|
+
end
|
47
|
+
_error "no match found for location=#{location}"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def _get(url)
|
53
|
+
_info "fetching #{url}"
|
54
|
+
RestClient.get(url) do |response, request, result|
|
55
|
+
_error "error fetching #{url}: #{response.code} response" if response.code != 200
|
56
|
+
[response.code, response.headers, response.body]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def _info(message)
|
61
|
+
logger.info "Rack::SSI #{message}" if logger
|
62
|
+
end
|
63
|
+
|
64
|
+
def _error(message)
|
65
|
+
logger.info "Rack::SSI #{message}" if logger
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
data/rack-ssi.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.authors = ["Thibaut Sacreste"]
|
5
|
+
gem.email = ["thibaut.sacreste@gmail.com"]
|
6
|
+
gem.description = <<-EOS
|
7
|
+
Rack middleware for processing SSI based on the nginx HttpSsiModule.
|
8
|
+
Directives currently supported: 'block' and 'include'
|
9
|
+
EOS
|
10
|
+
gem.summary = "Rack middleware for processing SSI based on the nginx HttpSsiModule."
|
11
|
+
gem.homepage = "https://github.com/forward/rack-ssi"
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split($\)
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
|
+
gem.name = "rack_ssi"
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
gem.version = "0.0.2"
|
19
|
+
gem.add_dependency "rest-client"
|
20
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Rack::SSI do
|
4
|
+
describe "#call" do
|
5
|
+
|
6
|
+
it "should not process response if the when predicate returns false" do
|
7
|
+
app = double
|
8
|
+
body = ["I am a response"]
|
9
|
+
app.stub(:call).and_return([200, {"Content-Type" => ["text/html"]}, body])
|
10
|
+
rack_ssi = Rack::SSI.new(app, :when => lambda {|env| false })
|
11
|
+
|
12
|
+
Rack::SSIProcessor.any_instance.should_not_receive(:process).and_return([""])
|
13
|
+
|
14
|
+
rack_ssi.call({})
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should process response if the when predicate returns true" do
|
18
|
+
app = double
|
19
|
+
body = ["I am a response"]
|
20
|
+
app.stub(:call).and_return([200, {"Content-Type" => ["text/html"]}, body])
|
21
|
+
rack_ssi = Rack::SSI.new(app, :when => lambda {|env| true })
|
22
|
+
|
23
|
+
Rack::SSIProcessor.any_instance.should_receive(:process).with(body).once.and_return([""])
|
24
|
+
|
25
|
+
rack_ssi.call({})
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should process html responses only" do
|
29
|
+
app = double
|
30
|
+
body = ["I am a response"]
|
31
|
+
app.stub(:call).and_return(
|
32
|
+
[200, {"Content-Type" => ["text/html"]}, body],
|
33
|
+
[200, {"Content-Type" => ["text/css"]}, []])
|
34
|
+
rack_ssi = Rack::SSI.new(app)
|
35
|
+
|
36
|
+
Rack::SSIProcessor.any_instance.should_receive(:process).with(body).once.and_return([""])
|
37
|
+
|
38
|
+
rack_ssi.call({})
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should process 200 responses only" do
|
42
|
+
app = double
|
43
|
+
body = ["I am a response"]
|
44
|
+
app.stub(:call).and_return(
|
45
|
+
[200, {"Content-Type" => ["text/html"]}, body],
|
46
|
+
[500, {"Content-Type" => ["text/html"]}, []])
|
47
|
+
rack_ssi = Rack::SSI.new(app)
|
48
|
+
|
49
|
+
Rack::SSIProcessor.any_instance.should_receive(:process).with(body).once.and_return([""])
|
50
|
+
|
51
|
+
rack_ssi.call({})
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should return the processed response and update the Content-Length header" do
|
55
|
+
body = ["I am a response"]
|
56
|
+
app = double(:call => [200, {"Content-Type" => ["text/html"], "Content-Length" => "15"}, body])
|
57
|
+
rack_ssi = Rack::SSI.new(app)
|
58
|
+
Rack::SSIProcessor.any_instance.stub(:process => ["I am a bigger response"])
|
59
|
+
|
60
|
+
_, headers, new_body = rack_ssi.call({})
|
61
|
+
|
62
|
+
new_body.should == ["I am a bigger response"]
|
63
|
+
headers["Content-Length"].should == "22"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path('../../lib/rack_ssi', __FILE__)
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Rack::SSIProcessor do
|
4
|
+
|
5
|
+
describe "#process_block" do
|
6
|
+
it "should yield block directives and strip them out of the html" do
|
7
|
+
html = <<-eos
|
8
|
+
<html>
|
9
|
+
<body>
|
10
|
+
<!--# block name="shush" --><!--# endblock -->
|
11
|
+
<p>some content</p>
|
12
|
+
<!--# block name="shouty" --><h1>ERROR!</h1><!--# endblock -->
|
13
|
+
</body>
|
14
|
+
</html>
|
15
|
+
eos
|
16
|
+
|
17
|
+
expected = <<-eos.gsub /\s+/, ""
|
18
|
+
<html>
|
19
|
+
<body>
|
20
|
+
<p>some content</p>
|
21
|
+
</body>
|
22
|
+
</html>
|
23
|
+
eos
|
24
|
+
|
25
|
+
ssi = Rack::SSIProcessor.new
|
26
|
+
blocks = []
|
27
|
+
|
28
|
+
processed = ssi.process_block(html) {|block| blocks << block}
|
29
|
+
|
30
|
+
processed.gsub(/\s+/, "").should == expected
|
31
|
+
blocks.should == [["shush", ""], ["shouty", "<h1>ERROR!</h1>"]]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#process_include" do
|
36
|
+
context "the SSI include request returns a valid response" do
|
37
|
+
it "should replace include directives with appropriate content" do
|
38
|
+
html = <<-eos
|
39
|
+
<html>
|
40
|
+
<body>
|
41
|
+
<!--# include virtual="/some/location" -->
|
42
|
+
<!--# include virtual="/some/other/location" -->
|
43
|
+
</body>
|
44
|
+
</html>
|
45
|
+
eos
|
46
|
+
|
47
|
+
expected = <<-eos.gsub /\s+/, ""
|
48
|
+
<html>
|
49
|
+
<body>
|
50
|
+
<p>some content</p>
|
51
|
+
<p>some more content</p>
|
52
|
+
</body>
|
53
|
+
</html>
|
54
|
+
eos
|
55
|
+
|
56
|
+
ssi = Rack::SSIProcessor.new
|
57
|
+
ssi.stub(:fetch).with("/some/location").and_return([200, {}, "<p>some content</p>"])
|
58
|
+
ssi.stub(:fetch).with("/some/other/location").and_return([200, {}, "<p>some more content</p>"])
|
59
|
+
|
60
|
+
processed = ssi.process_include(html, {})
|
61
|
+
|
62
|
+
processed.gsub(/\s+/, "").should == expected
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "the SSI include request returns an empty response" do
|
67
|
+
it "should replace include directives with the content of the block specified by the 'stub' parameter" do
|
68
|
+
html = <<-eos
|
69
|
+
<html>
|
70
|
+
<body>
|
71
|
+
<!--# include virtual="/some/broken/location" stub="oops" -->
|
72
|
+
</body>
|
73
|
+
</html>
|
74
|
+
eos
|
75
|
+
|
76
|
+
expected = <<-eos.gsub /\s+/, ""
|
77
|
+
<html>
|
78
|
+
<body>
|
79
|
+
<p>oops, something went wrong!</p>
|
80
|
+
</body>
|
81
|
+
</html>
|
82
|
+
eos
|
83
|
+
|
84
|
+
ssi = Rack::SSIProcessor.new
|
85
|
+
ssi.stub(:fetch).with("/some/broken/location").and_return([200, {}, ""])
|
86
|
+
|
87
|
+
processed = ssi.process_include(html, {"oops" => "<p>oops, something went wrong!</p>"})
|
88
|
+
|
89
|
+
processed.gsub(/\s+/, "").should == expected
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should replace include directives with the empty response if no 'stub' parameter" do
|
93
|
+
html = <<-eos
|
94
|
+
<html>
|
95
|
+
<body>
|
96
|
+
<!--# include virtual="/some/broken/location" -->
|
97
|
+
</body>
|
98
|
+
</html>
|
99
|
+
eos
|
100
|
+
|
101
|
+
ssi = Rack::SSIProcessor.new
|
102
|
+
ssi.stub(:fetch).with("/some/broken/location").and_return([200, {}, ""])
|
103
|
+
|
104
|
+
processed = ssi.process_include(html, {})
|
105
|
+
|
106
|
+
processed.gsub(/\s+/, "").should == "<html><body></body></html>"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "the SSI include request returns an error response" do
|
111
|
+
it "should replace include directives with the content of the block specified by the 'stub' parameter" do
|
112
|
+
html = <<-eos
|
113
|
+
<html>
|
114
|
+
<body>
|
115
|
+
<!--# include virtual="/some/broken/location" stub="oops" -->
|
116
|
+
</body>
|
117
|
+
</html>
|
118
|
+
eos
|
119
|
+
|
120
|
+
expected = <<-eos.gsub /\s+/, ""
|
121
|
+
<html>
|
122
|
+
<body>
|
123
|
+
<p>oops, something went wrong!</p>
|
124
|
+
</body>
|
125
|
+
</html>
|
126
|
+
eos
|
127
|
+
|
128
|
+
ssi = Rack::SSIProcessor.new
|
129
|
+
ssi.stub(:fetch).with("/some/broken/location").and_return([500, {}, "<crap>"])
|
130
|
+
|
131
|
+
processed = ssi.process_include(html, {"oops" => "<p>oops, something went wrong!</p>"})
|
132
|
+
|
133
|
+
processed.gsub(/\s+/, "").should == expected
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should replace include directives with the error response if no 'stub' parameter" do
|
137
|
+
html = <<-eos
|
138
|
+
<html>
|
139
|
+
<body>
|
140
|
+
<!--# include virtual="/some/broken/location" -->
|
141
|
+
</body>
|
142
|
+
</html>
|
143
|
+
eos
|
144
|
+
|
145
|
+
ssi = Rack::SSIProcessor.new
|
146
|
+
ssi.stub(:fetch).with("/some/broken/location").and_return([500, {}, "<bang>"])
|
147
|
+
|
148
|
+
processed = ssi.process_include(html, {})
|
149
|
+
|
150
|
+
processed.gsub(/\s+/, "").should == "<html><body><bang></body></html>"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "#fetch" do
|
157
|
+
it "should resolve locations by exact match first" do
|
158
|
+
ssi = Rack::SSIProcessor.new
|
159
|
+
ssi.locations = {
|
160
|
+
/\/pants/ => "http://host1",
|
161
|
+
"/pants" => "http://host2"
|
162
|
+
}
|
163
|
+
|
164
|
+
RestClient.should_receive(:get).with("http://host2/pants")
|
165
|
+
ssi.fetch("/pants")
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should resolve locations by regex if no exact match" do
|
169
|
+
ssi = Rack::SSIProcessor.new
|
170
|
+
ssi.locations = {
|
171
|
+
/^\/pants\/.*/ => "http://host1",
|
172
|
+
"/pants" => "http://host2"
|
173
|
+
}
|
174
|
+
|
175
|
+
RestClient.should_receive(:get).with("http://host1/pants/on/fire")
|
176
|
+
ssi.fetch("/pants/on/fire")
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe "#process" do
|
181
|
+
it "should do it all!" do
|
182
|
+
body = [
|
183
|
+
'<html><body>',
|
184
|
+
'<!--# block name="shouty" --><p>ERROR!</p><!--# endblock -->',
|
185
|
+
'<!--# include virtual="/includes/broken" stub="shouty" -->',
|
186
|
+
'<!--# include virtual="/includes/header" -->',
|
187
|
+
'</body></html>'
|
188
|
+
]
|
189
|
+
ssi = Rack::SSIProcessor.new
|
190
|
+
ssi.stub(:fetch).with("/includes/broken").and_return([500, {}, "<p>pants!</p>"])
|
191
|
+
ssi.stub(:fetch).with("/includes/header").and_return([200, {}, "<h1>Hello</h1>"])
|
192
|
+
|
193
|
+
ssi.process(body).join.should == "<html><body><p>ERROR!</p><h1>Hello</h1></body></html>"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack_ssi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Thibaut Sacreste
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-08-20 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rest-client
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: " Rack middleware for processing SSI based on the nginx HttpSsiModule.\n Directives currently supported: 'block' and 'include'\n"
|
35
|
+
email:
|
36
|
+
- thibaut.sacreste@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- .gitignore
|
45
|
+
- Gemfile
|
46
|
+
- LICENSE
|
47
|
+
- README.md
|
48
|
+
- Rakefile
|
49
|
+
- lib/rack_ssi.rb
|
50
|
+
- lib/ssi_processor.rb
|
51
|
+
- rack-ssi.gemspec
|
52
|
+
- spec/rack_ssi_spec.rb
|
53
|
+
- spec/spec_helper.rb
|
54
|
+
- spec/ssi_processor_spec.rb
|
55
|
+
homepage: https://github.com/forward/rack-ssi
|
56
|
+
licenses: []
|
57
|
+
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
hash: 3
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
version: "0"
|
81
|
+
requirements: []
|
82
|
+
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 1.8.24
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: Rack middleware for processing SSI based on the nginx HttpSsiModule.
|
88
|
+
test_files:
|
89
|
+
- spec/rack_ssi_spec.rb
|
90
|
+
- spec/spec_helper.rb
|
91
|
+
- spec/ssi_processor_spec.rb
|