apache-config-generator/lib/apache/rewrites.rb

300 lines
6.8 KiB
Ruby
Raw Normal View History

2010-05-05 16:25:07 +00:00
module Apache
2010-05-10 19:57:34 +00:00
# Handle the creation of RewriteRules, RewriteConds, Redirects, and RedirectMatches
2010-05-05 16:25:07 +00:00
module Rewrites
2010-05-10 19:57:34 +00:00
# Enable the rewrite engine, optionally setting the logging level
#
# enable_rewrite_engine :log_level => 1 #=>
# RewriteEngine on
# RewriteLogLevel 1
2010-05-10 21:43:34 +00:00
def enable_rewrite_engine(options = {})
2010-05-06 14:40:45 +00:00
self << ''
2010-05-05 16:25:07 +00:00
rewrite_engine! :on
options.each do |option, value|
case option
when :log_level
rewrite_log_level! value
end
end
2010-05-06 14:40:45 +00:00
self << ''
2010-05-05 16:25:07 +00:00
end
2010-05-10 19:57:34 +00:00
# Pass the block to RewriteManager.build
2010-05-05 16:25:07 +00:00
def rewrites(&block)
self + indent(RewriteManager.build(&block))
2010-05-06 14:40:45 +00:00
self << ''
2010-05-05 16:25:07 +00:00
end
2010-05-10 19:57:34 +00:00
# Create a permanent Redirect
#
# r301 '/here', '/there' #=> Redirect permanent "/here" "/there"
def r301(*opt)
self << "Redirect permanent #{quoteize(*opt) * " "}"
end
2010-05-05 16:25:07 +00:00
end
2010-05-10 19:57:34 +00:00
# Handle the creation of Rewritable things
2010-05-05 16:25:07 +00:00
class RewriteManager
class << self
attr_accessor :rewrites
2010-05-10 19:57:34 +00:00
# Reset the current list of rewrites
2010-05-07 20:04:06 +00:00
def reset!
2010-05-05 16:25:07 +00:00
@rewrites = []
2010-05-07 20:04:06 +00:00
end
2010-05-10 19:57:34 +00:00
# Build rewritable things from the provided block
2010-05-07 20:04:06 +00:00
def build(&block)
reset!
2010-05-05 16:25:07 +00:00
self.instance_eval(&block)
2010-05-07 02:26:12 +00:00
@rewrites.collect(&:to_a).flatten
end
2010-05-10 19:57:34 +00:00
# Commit the latest rewritable thing to the list of rewrites
2010-05-07 02:26:12 +00:00
def commit!
@rewrites << @rewrite
@rewrite = nil
end
2010-05-10 19:57:34 +00:00
# Ensure that there's a RewriteRule to be worked with
2010-05-07 02:26:12 +00:00
def ensure_rewrite!
@rewrite = RewriteRule.new if !@rewrite
2010-05-05 16:25:07 +00:00
end
2010-05-10 19:57:34 +00:00
# Create a RewriteRule with the given options
#
# rewrite %r{/here(.*)}, '/there$1', :last => true #=>
# RewriteRule "/here(.*)" "/there$1" [L]
2010-05-05 16:25:07 +00:00
def rewrite(*opts)
2010-05-07 02:26:12 +00:00
ensure_rewrite!
2010-05-05 16:25:07 +00:00
@rewrite.rule(*opts)
2010-05-07 02:26:12 +00:00
commit!
end
2010-05-05 16:25:07 +00:00
2010-05-07 20:04:06 +00:00
alias :rule :rewrite
2010-05-10 19:57:34 +00:00
# Create a RewriteCond with the given options
#
# cond "%{REQUEST_FILENAME}", "^/here" #=>
# RewriteCond "%{REQUEST_FILENAME}", "^/here"
2010-05-07 02:26:12 +00:00
def cond(*opts)
ensure_rewrite!
@rewrite.cond(*opts)
2010-05-05 16:25:07 +00:00
end
2010-05-10 19:57:34 +00:00
# Create a permanent RedirectMatch
#
# r301 %r{/here(.*)}, "/there$1" #=>
# RedirectMatch permanent "/here(.*)" "/there$1"
def r301(*opts)
redirect = RedirectMatchPermanent.new
redirect.rule(*opts)
@rewrites << redirect
end
2010-05-10 19:57:34 +00:00
# Test the rewritable things defined in this block
2010-05-05 16:25:07 +00:00
def rewrite_test(from, to, opts = {})
orig_from = from.dup
@rewrites.each do |r|
from = r.test(from, opts)
end
if from != to
puts "[warn] #{orig_from} >> #{to} failed!"
puts "[warn] Result: #{from}"
end
end
end
end
2010-05-10 19:57:34 +00:00
# Common methods for testing rewritable things that use regular expressions
2010-05-07 20:04:06 +00:00
module RegularExpressionMatcher
2010-05-10 19:57:34 +00:00
# Test this rewritable thing
2010-05-07 20:04:06 +00:00
def test(from, opts = {})
from = from.gsub(@from, @to.gsub(/\$([0-9])/) { |m| '\\' + $1 })
replace_placeholders(from, opts)
end
2010-05-10 19:57:34 +00:00
# Replace the placeholders in this rewritable thing
def replace_placeholders(s, opts)
2010-05-07 20:04:06 +00:00
opts.each do |opt, value|
case value
when String
s = s.gsub('%{' + opt.to_s.upcase + '}', value)
end
2010-05-07 20:04:06 +00:00
end
s
2010-05-07 20:04:06 +00:00
end
end
2010-05-10 19:57:34 +00:00
# A matchable thing to be extended
class MatchableThing
2010-05-07 02:26:12 +00:00
include Apache::Quoteize
2010-05-10 19:57:34 +00:00
# The Apache directive tag for this thing
def tag; raise 'Override this method'; end
2010-05-05 16:25:07 +00:00
def initialize
@from = nil
@to = nil
end
2010-05-07 20:04:06 +00:00
def rule(from, to)
2010-05-05 16:25:07 +00:00
@from = from
@to = to
2010-05-07 02:26:12 +00:00
end
2010-05-07 20:04:06 +00:00
def to_s
"#{tag} #{[quoteize(@from), quoteize(@to)].compact.flatten * " "}"
end
2010-05-07 02:26:12 +00:00
2010-05-07 20:04:06 +00:00
def to_a
[ to_s ]
2010-05-05 16:25:07 +00:00
end
2010-05-07 20:04:06 +00:00
end
2010-05-05 16:25:07 +00:00
2010-05-10 19:57:34 +00:00
# A RewriteRule definition
2010-05-07 20:04:06 +00:00
class RewriteRule < MatchableThing
include RegularExpressionMatcher
def tag; 'RewriteRule'; end
def initialize
super
@conditions = []
@options = nil
2010-05-05 16:25:07 +00:00
end
2010-05-10 19:57:34 +00:00
# Define the rule, passing in additional options
#
# rule %r{^/here}, '/there', { :last => true, :preserve_query_string => true }
2010-05-07 20:04:06 +00:00
def rule(from, to,options = {})
super(from, to)
raise "from must be a Regexp" if !from.kind_of?(Regexp)
2010-05-05 16:25:07 +00:00
2010-05-07 20:04:06 +00:00
options = options.collect do |key, value|
2010-05-07 02:26:12 +00:00
case key
when :last
'L'
2010-05-10 21:43:34 +00:00
when :pass_through
'PT'
2010-05-07 02:26:12 +00:00
when :preserve_query_string
'QSA'
end
2010-05-10 15:27:56 +00:00
end.sort
2010-05-05 16:25:07 +00:00
2010-05-07 20:04:06 +00:00
@options = !options.empty? ? "[#{options * ','}]" : nil
end
2010-05-05 16:25:07 +00:00
2010-05-10 19:57:34 +00:00
# Add a RewriteCondition to this RewriteRule
2010-05-07 20:04:06 +00:00
def cond(from, to, *opts)
rewrite_cond = RewriteCondition.new
rewrite_cond.cond(from, to, *opts)
2010-05-05 16:25:07 +00:00
2010-05-07 20:04:06 +00:00
@conditions << rewrite_cond
2010-05-05 16:25:07 +00:00
end
2010-05-07 20:04:06 +00:00
def to_s
"#{tag} #{[quoteize(@from.source), quoteize(@to), @options].compact.flatten * " "}"
end
def to_a
2010-05-10 19:57:34 +00:00
[ @conditions.collect(&:to_s), super ].flatten
2010-05-07 20:04:06 +00:00
end
2010-05-10 19:57:34 +00:00
# Test this RewriteRule, ensuring the RewriteConds also match
def test(from, opts = {})
ok = true
@conditions.each do |c|
ok = false if !c.test(from, opts)
end
if ok
super(from, opts)
else
replace_placeholders(from, opts)
end
end
end
2010-05-10 19:57:34 +00:00
# A permanent RedirectMatch
class RedirectMatchPermanent < MatchableThing
2010-05-07 20:04:06 +00:00
include RegularExpressionMatcher
def tag; 'RedirectMatch permanent'; end
2010-05-07 20:04:06 +00:00
2010-05-10 19:57:34 +00:00
def rule(from, to)
super(from, to)
raise "from must be a Regexp" if !from.kind_of?(Regexp)
end
2010-05-07 20:04:06 +00:00
def to_s
"#{tag} #{[quoteize(@from.source), quoteize(@to)].compact.flatten * " "}"
end
2010-05-05 16:25:07 +00:00
end
2010-05-07 02:26:12 +00:00
2010-05-10 19:57:34 +00:00
# A RewriteCond
2010-05-07 02:26:12 +00:00
class RewriteCondition < MatchableThing
include RegularExpressionMatcher
2010-05-07 02:26:12 +00:00
def tag; 'RewriteCond'; end
2010-05-07 20:04:06 +00:00
2010-05-10 19:57:34 +00:00
# Define a RewriteCond
#
# rule "%{REQUEST_FILENAME}", "^/here", :case_insensitive #=>
# RewriteCond "%{REQUEST_FILENAME}" "^/here" [NC]
2010-05-07 20:04:06 +00:00
def rule(from, to, *opts)
super(from, to)
options = opts.collect do |opt|
case opt
when :or
'OR'
when :case_insensitive
'NC'
when :no_vary
'NV'
end
end
@options = (!options.empty?) ? "[#{options * ','}]" : nil
end
2010-05-07 02:26:12 +00:00
alias :cond :rule
2010-05-07 20:04:06 +00:00
def initialize
super
@options = nil
end
2010-05-07 02:26:12 +00:00
def to_s
2010-05-07 20:04:06 +00:00
"#{tag} #{[quoteize(@from), quoteize(@to), @options].compact.flatten * " "}"
2010-05-07 02:26:12 +00:00
end
2010-05-10 19:57:34 +00:00
# Test this RewriteCond
def test(from, opts = {})
super(from, opts)
source = replace_placeholders(@from, opts)
result = false
case @to[0..0]
when '!'
result = !source[Regexp.new(@to[1..-1])]
when '-'
case @to
when '-f'
result = opts[:files].include? source if opts[:files]
end
else
result = source[Regexp.new(@to)]
end
result
end
2010-05-07 02:26:12 +00:00
end
2010-05-05 16:25:07 +00:00
end