Skip to content

Commit

Permalink
specs added, comments, readme updated
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Mendler committed Mar 4, 2009
1 parent b8e7f9a commit 088813e
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 8 deletions.
5 changes: 4 additions & 1 deletion README.rdoc
Expand Up @@ -35,12 +35,15 @@ interface:
CSS for cross-site AJAX-style data loading
* Rack::Deflect - Helps protect against DoS attacks.
* Rack::ResponseCache - Caches responses to requests without query strings
to Disk or a user provider Ruby object. Similar to Rails' page caching.
to Disk or a user provider Ruby object. Similar to Rails' page caching. (Better use Rack::Cache by rtomayko)
* Rack::RelativeRedirect - Transforms relative paths in redirects to
absolute URLs.
* Rack::Backstage - Returns content of specified file if it exists, which makes
it convenient for putting up maintenance pages.
* Rack::Format - Adds a format extension at the end of the URI when there is none, corresponding to the mime-type given in the Accept HTTP header.
* Rack::Tidy - Validate and cleanup XML output with xmllint or tidy
* Rack::Rewrite - Rewrite url bases. If you have an application which wants to be installed in / you can installed it e.g.
in /~user/app by using this middleware's base rewriting.

=== Use

Expand Down
14 changes: 11 additions & 3 deletions lib/rack/contrib/rewrite.rb
@@ -1,21 +1,29 @@
require 'cgi'

module Rack
# Rack::Rewrite rewrites absolute paths to another base.
# If you have an application for / which you want to install under /~user/app
# then you can use this middleware.
# You have to specify the base as option.

class Rewrite

def initialize(app, options={})
raise ArgumentError, 'Base option is missing' if !options[:base]
@app = app
@base = options[:base]
@base.gsub!(%r{^/+|/+$}, '')
end

def call(env)
if env['PATH_INFO'] =~ %r{^/#{@base}$|^/#{@base}/}
env['PATH_INFO'] = env['PATH_INFO'].sub(%r{^/#{@base}/?}, '/')
env['REQUEST_URI'] = env['REQUEST_URI'].sub(%r{^/#{@base}/?}, '/')
env['PATH_INFO'] = env['PATH_INFO'].to_s.sub(%r{^/#{@base}/?}, '/')
env['REQUEST_URI'] = env['REQUEST_URI'].to_s.sub(%r{^/#{@base}/?}, '/')

status, header, body = @app.call(env)

if [301, 302, 303, 307].include?(status)
header['Location'] = '/' + @base + header['Location']
header['Location'] = '/' + @base + header['Location'] if header['Location'][0..0] == '/'
elsif ![204, 304].include?(status) && html?(header)
tmp = ''
body.each {|data| tmp << data}
Expand Down
13 changes: 9 additions & 4 deletions lib/rack/contrib/tidy.rb
@@ -1,14 +1,19 @@
require 'open3'

module Rack
# Rack::Tidy cleans markup and validates it.
# It adds a comment with the errors at the end.
#
# You can specify tidy/xmllint via the mode options.

class Tidy
TIDY_CMD = 'tidy -i -xml -access 3 -quiet'
XMLLINT_CMD = 'xmllint --format --valid -'

def initialize(app, options={})
@app = app
mode = options[:mode] || :tidy
@cmd = mode == :tidy ? TIDY_CMD : XMLLINT_CMD
mode = options[:mode] || 'tidy'
@cmd = mode.to_s == 'tidy' ? TIDY_CMD : XMLLINT_CMD
end

def call(env)
Expand All @@ -19,7 +24,7 @@ def call(env)
stdin.close
body = stdout.read
errors = stderr.read.strip
body += "<!--\n#{errors}\n-->\n" if !errors.blank?
body += "<!--\n#{errors}\n-->\n" if !errors.empty?
}
header['Content-Length'] = body.length.to_s
[status, header, body]
Expand All @@ -28,7 +33,7 @@ def call(env)
private

def html?(header)
%w(application/xhtml+xml text/html).any? do |type|
%w(application/xhtml+xml text/html text/xml).any? do |type|
header['Content-Type'].to_s.include?(type)
end
end
Expand Down
7 changes: 7 additions & 0 deletions test/invalid-output.html
@@ -0,0 +1,7 @@
<!--
line 6 column 14 - Error: unexpected </div> in <p>
line 7 column 3 - Error: unexpected </body> in <p>
line 8 column 1 - Error: unexpected </html> in <p>
line 1 column 1 - Access: [3.2.1.1]: <doctype> missing.
line 1 column 1 - Access: [3.3.1.1]: use style sheets to control presentation.
-->
8 changes: 8 additions & 0 deletions test/invalid.html
@@ -0,0 +1,8 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Titel</title>
</head>
<body>
Blabla<p></div>
</body>
</html>
35 changes: 35 additions & 0 deletions test/spec_rack_rewrite.rb
@@ -0,0 +1,35 @@
require 'test/spec'
require 'rack/mock'
require 'rack/contrib/rewrite'

context "Rack::Rewrite" do

def action(id, expect)
response = Rack::MockRequest.new(@app).get("/~user/app/action#{id}")
response.body.should.equal(expect)
response.status.should.equal(200)
end

specify "should rewrite absolute paths" do
@app = Rack::Builder.new do
use Rack::Lint
use Rack::Rewrite, :base => '/~user/app'
run Rack::URLMap.new({
'/action1' => lambda { [200, {"Content-Type" => "text/html"}, ['<a href="/action">']] },
'/action2' => lambda { [200, {"Content-Type" => "text/html"}, ['<a href=\'/action\'>']] },
'/action3' => lambda { [200, {"Content-Type" => "text/html"}, ['<a href="http://xy">']] },
'/action4' => lambda { [200, {"Content-Type" => "text/html"}, ['<a href="relative">']] },
'/action5' => lambda { [200, {"Content-Type" => "text/html"}, ['<img title="image" src="/img"/>']] },
'/action6' => lambda { [200, {"Content-Type" => "text/html"}, ['<link rel="stylesheet" href="/style.css" type="text/css">']] },
})
end

action(1, '<a href="/~user/app/action">')
action(2, '<a href=\'/~user/app/action\'>')
action(3, '<a href="http://xy">')
action(4, '<a href="relative">')
action(5, '<img title="image" src="/~user/app/img"/>')
action(6, '<link rel="stylesheet" href="/~user/app/style.css" type="text/css">')
end

end
38 changes: 38 additions & 0 deletions test/spec_rack_tidy.rb
@@ -0,0 +1,38 @@
require 'test/spec'
require 'rack/mock'
require 'rack/contrib/tidy'

context "Rack::Tidy" do

specify "should run tidy on xml" do
app = Rack::Builder.new do
use Rack::Lint
use Rack::Tidy
run Rack::URLMap.new({
"/valid" => lambda { [200, {"Content-Type" => "text/html"}, File.open('test/valid.html')] },
"/invalid" => lambda { [200, {"Content-Type" => "text/html"}, File.open('test/invalid.html')] },
})
end
response = Rack::MockRequest.new(app).get('/valid')
response.status.should.equal(200)
response.body.should.equal(File.read('test/valid.html'))

response = Rack::MockRequest.new(app).get('/invalid')
response.status.should.equal(200)
response.body.should.equal(File.read('test/invalid-output.html'))
end

specify "should not run tidy on non-xml" do
app = Rack::Builder.new do
use Rack::Lint
use Rack::Tidy
run Rack::URLMap.new({
"/image" => lambda { [200, {"Content-Type" => "image/png", "Content-Length" => "9"}, ['>no html<']] },
})
end
response = Rack::MockRequest.new(app).get('/image')
response.status.should.equal(200)
response.body.should.equal('>no html<')
end

end
11 changes: 11 additions & 0 deletions test/valid.html
@@ -0,0 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Titel</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div>Content</div>
</body>
</html>

0 comments on commit 088813e

Please sign in to comment.