recursive.rb 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. require 'uri'
  2. module Rack
  3. # Rack::ForwardRequest gets caught by Rack::Recursive and redirects
  4. # the current request to the app at +url+.
  5. #
  6. # raise ForwardRequest.new("/not-found")
  7. #
  8. class ForwardRequest < Exception
  9. attr_reader :url, :env
  10. def initialize(url, env={})
  11. @url = URI(url)
  12. @env = env
  13. @env["PATH_INFO"] = @url.path
  14. @env["QUERY_STRING"] = @url.query if @url.query
  15. @env["HTTP_HOST"] = @url.host if @url.host
  16. @env["HTTP_PORT"] = @url.port if @url.port
  17. @env["rack.url_scheme"] = @url.scheme if @url.scheme
  18. super "forwarding to #{url}"
  19. end
  20. end
  21. # Rack::Recursive allows applications called down the chain to
  22. # include data from other applications (by using
  23. # <tt>rack['rack.recursive.include'][...]</tt> or raise a
  24. # ForwardRequest to redirect internally.
  25. class Recursive
  26. def initialize(app)
  27. @app = app
  28. end
  29. def call(env)
  30. dup._call(env)
  31. end
  32. def _call(env)
  33. @script_name = env["SCRIPT_NAME"]
  34. @app.call(env.merge('rack.recursive.include' => method(:include)))
  35. rescue ForwardRequest => req
  36. call(env.merge(req.env))
  37. end
  38. def include(env, path)
  39. unless path.index(@script_name) == 0 && (path[@script_name.size] == ?/ ||
  40. path[@script_name.size].nil?)
  41. raise ArgumentError, "can only include below #{@script_name}, not #{path}"
  42. end
  43. env = env.merge("PATH_INFO" => path, "SCRIPT_NAME" => @script_name,
  44. "REQUEST_METHOD" => "GET",
  45. "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "",
  46. "rack.input" => StringIO.new(""))
  47. @app.call(env)
  48. end
  49. end
  50. end