L'utilisation d'un Regex dans l'URI d'un gestionnaire Mongrel
Question
J'utilise actuellement Mongrel pour développer un projet d'application web personnalisé.
Je voudrais Mongrel d'utiliser un gestionnaire Http défini sur la base d'une expression régulière. Par exemple, chaque fois que quelqu'un appelle une URL comme http: //test/bla1.js ou http:. //test/bla2.js le même gestionnaire Http est appelé à gérer la demande
Mon code si loin ressemble un comme ça:
http_server = Mongrel::Configurator.new :host => config.get("http_host") do
listener :port => config.get("http_port") do
uri Regexp.escape("/[a-z0-9]+.js"), :handler => BLAH::CustomHandler.new
uri '/ui/public', :handler => Mongrel::DirHandler.new("#{$d}/public/")
uri '/favicon', :handler => Mongrel::Error404Handler.new('')
trap("INT") { stop }
run
end
end
Comme vous pouvez le voir, je suis en train d'utiliser une expression régulière au lieu d'une chaîne ici:
uri Regexp.escape("/[a-z0-9]+.js"), :handler => BLAH::CustomHandler.new
mais cela ne fonctionne pas. Toute solution?
Merci pour cela.
La solution
Vous devez injecter un nouveau code dans une partie de la URIClassifier
de Mongrel, qui est par ailleurs parfaitement au courant des URIs d'expression régulière.
Voici une façon de faire cela:
#
# Must do the following BEFORE Mongrel::Configurator.new
# Augment some of the key methods in Mongrel::URIClassifier
# See lib/ruby/gems/XXX/gems/mongrel-1.1.5/lib/mongrel/uri_classifier.rb
#
Mongrel::URIClassifier.class_eval <<-EOS, __FILE__, __LINE__
# Save original methods
alias_method :register_without_regexp, :register
alias_method :unregister_without_regexp, :unregister
alias_method :resolve_without_regexp, :resolve
def register(uri, handler)
if uri.is_a?(Regexp)
unless (@regexp_handlers ||= []).any? { |(re,h)| re==uri ? h.concat(handler) : false }
@regexp_handlers << [ uri, handler ]
end
else
# Original behaviour
register_without_regexp(uri, handler)
end
end
def unregister(uri)
if uri.is_a?(Regexp)
raise Mongrel::URIClassifier::RegistrationError, "\#{uri.inspect} was not registered" unless (@regexp_handlers ||= []).reject! { |(re,h)| re==uri }
else
# Original behaviour
unregister_without_regexp(uri)
end
end
def resolve(request_uri)
# Try original behaviour FIRST
result = resolve_without_regexp(request_uri)
# If a match is not found with non-regexp URIs, try regexp
if result[0].blank?
(@regexp_handlers ||= []).any? { |(re,h)| (m = re.match(request_uri)) ? (result = [ m.pre_match + m.to_s, (m.to_s == Mongrel::Const::SLASH ? request_uri : m.post_match), h ]) : false }
end
result
end
EOS
http_server = Mongrel::Configurator.new :host => config.get("http_host") do
listener :port => config.get("http_port") do
# Can pass a regular expression as URI
# (URI must be of type Regexp, no escaping please!)
# Regular expression can match any part of an URL, start with "^/..." to
# anchor match at URI beginning.
# The way this is implemented, regexp matches are only evaluated AFTER
# all non-regexp matches have failed (mostly for performance reasons.)
# Also, for regexp URIs, the :in_front is ignored; adding multiple handlers
# to the same URI regexp behaves as if :in_front => false
uri /^[a-z0-9]+.js/, :handler => BLAH::CustomHandler.new
uri '/ui/public', :handler => Mongrel::DirHandler.new("#{$d}/public/")
uri '/favicon', :handler => Mongrel::Error404Handler.new('')
trap("INT") { stop }
run
end
end
Semble fonctionner très bien avec Mongrel 1.1.5.
Autres conseils
Vous devriez envisager de créer un application rack à la place. Rack est:
- standard pour les applications Web Ruby
- utilisé en interne par tous les cadres web Ruby populaires ( Rails , Merb , Sinatra , Camping , Ramaze , ...)
- beaucoup plus facile d'étendre
- prêt à être exécuté sur tout serveur d'applications (Mongrel, Webrick, mince, passager, ...)
rack a un DSL mappage d'URL, rack :: Builder, qui vous permet de cartographier les différentes applications de rack à préfixes d'URL particuliers. Vous enregistrez généralement comme config.ru
, et l'exécuter avec rackup
.
Malheureusement, il ne permet pas non plus d'expressions régulières. Mais à cause de la simplicité du rack, il est vraiment facile d'écrire une « application » (un lambda
, en fait) qui appelle l'application appropriée si l'URL correspond à un certain regex.
Selon votre exemple, votre config.ru
peut ressembler à ceci:
require "my_custom_rack_app" # Whatever provides your MyCustomRackApp.
js_handler = MyCustomRackApp.new
default_handlers = Rack::Builder.new do
map "/public" do
run Rack::Directory.new("my_dir/public")
end
# Uncomment this to replace Rack::Builder's 404 handler with your own:
# map "/" do
# run lambda { |env|
# [404, {"Content-Type" => "text/plain"}, ["My 404 response"]]
# }
# end
end
run lambda { |env|
if env["PATH_INFO"] =~ %r{/[a-z0-9]+\.js}
js_handler.call(env)
else
default_handlers.call(env)
end
}
Ensuite, exécutez votre application Rack sur la ligne de commande:
% rackup
Si vous avez installé bâtarde, il sera lancé sur le port 9292. Fait!