rack 0.1.0
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.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- data/AUTHORS +3 -0
- data/COPYING +18 -0
- data/KNOWN-ISSUES +18 -0
- data/RDOX +144 -0
- data/README +154 -0
- data/Rakefile +174 -0
- data/SPEC +132 -0
- data/bin/rackup +148 -0
- data/contrib/rack_logo.svg +111 -0
- data/example/lobster.ru +4 -0
- data/lib/rack.rb +67 -0
- data/lib/rack/adapter/camping.rb +16 -0
- data/lib/rack/adapter/rails.rb +65 -0
- data/lib/rack/builder.rb +52 -0
- data/lib/rack/cascade.rb +26 -0
- data/lib/rack/commonlogger.rb +56 -0
- data/lib/rack/file.rb +108 -0
- data/lib/rack/handler/cgi.rb +57 -0
- data/lib/rack/handler/fastcgi.rb +81 -0
- data/lib/rack/handler/mongrel.rb +57 -0
- data/lib/rack/handler/webrick.rb +56 -0
- data/lib/rack/lint.rb +394 -0
- data/lib/rack/lobster.rb +65 -0
- data/lib/rack/mock.rb +183 -0
- data/lib/rack/recursive.rb +57 -0
- data/lib/rack/reloader.rb +64 -0
- data/lib/rack/request.rb +112 -0
- data/lib/rack/response.rb +114 -0
- data/lib/rack/showexceptions.rb +344 -0
- data/lib/rack/urlmap.rb +50 -0
- data/lib/rack/utils.rb +176 -0
- data/test/cgi/lighttpd.conf +20 -0
- data/test/cgi/test +9 -0
- data/test/cgi/test.fcgi +9 -0
- data/test/cgi/test.ru +7 -0
- data/test/spec_rack_camping.rb +44 -0
- data/test/spec_rack_cascade.rb +35 -0
- data/test/spec_rack_cgi.rb +82 -0
- data/test/spec_rack_commonlogger.rb +32 -0
- data/test/spec_rack_fastcgi.rb +82 -0
- data/test/spec_rack_file.rb +32 -0
- data/test/spec_rack_lint.rb +317 -0
- data/test/spec_rack_lobster.rb +45 -0
- data/test/spec_rack_mock.rb +150 -0
- data/test/spec_rack_mongrel.rb +87 -0
- data/test/spec_rack_recursive.rb +77 -0
- data/test/spec_rack_request.rb +219 -0
- data/test/spec_rack_response.rb +110 -0
- data/test/spec_rack_showexceptions.rb +21 -0
- data/test/spec_rack_urlmap.rb +140 -0
- data/test/spec_rack_utils.rb +57 -0
- data/test/spec_rack_webrick.rb +89 -0
- data/test/testrequest.rb +43 -0
- metadata +117 -0
    
        data/lib/rack/lobster.rb
    ADDED
    
    | @@ -0,0 +1,65 @@ | |
| 1 | 
            +
            require 'zlib'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'rack/request'
         | 
| 4 | 
            +
            require 'rack/response'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Rack
         | 
| 7 | 
            +
              # Paste has a Pony, Rack has a Lobster!
         | 
| 8 | 
            +
              class Lobster
         | 
| 9 | 
            +
                LobsterString = Zlib::Inflate.inflate("eJx9kEEOwyAMBO99xd7MAcytUhPlJyj2
         | 
| 10 | 
            +
                P6jy9i4k9EQyGAnBarEXeCBqSkntNXsi/ZCvC48zGQoZKikGrFMZvgS5ZHd+aGWVuWwhVF0
         | 
| 11 | 
            +
                t1drVmiR42HcWNz5w3QanT+2gIvTVCiE1lm1Y0eU4JGmIIbaKwextKn8rvW+p5PIwFl8ZWJ
         | 
| 12 | 
            +
                I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0])
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                LambdaLobster = lambda { |env|
         | 
| 15 | 
            +
                  if env["QUERY_STRING"].include?("flip")
         | 
| 16 | 
            +
                    lobster = LobsterString.split("\n").
         | 
| 17 | 
            +
                      map { |line| line.ljust(42).reverse }.
         | 
| 18 | 
            +
                      join("\n")
         | 
| 19 | 
            +
                    href = "?"
         | 
| 20 | 
            +
                  else
         | 
| 21 | 
            +
                    lobster = LobsterString
         | 
| 22 | 
            +
                    href = "?flip"
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                  
         | 
| 25 | 
            +
                  [200, {"Content-Type" => "text/html"},
         | 
| 26 | 
            +
                   ["<title>Lobstericious!</title>",
         | 
| 27 | 
            +
                    "<pre>", lobster, "</pre>",
         | 
| 28 | 
            +
                    "<a href='#{href}'>flip!</a>"]
         | 
| 29 | 
            +
                  ]
         | 
| 30 | 
            +
                }
         | 
| 31 | 
            +
                
         | 
| 32 | 
            +
                def call(env)
         | 
| 33 | 
            +
                  req = Request.new(env)
         | 
| 34 | 
            +
                  if req.GET["flip"] == "left"
         | 
| 35 | 
            +
                    lobster = LobsterString.split("\n").
         | 
| 36 | 
            +
                      map { |line| line.ljust(42).reverse }.
         | 
| 37 | 
            +
                      join("\n")
         | 
| 38 | 
            +
                    href = "?flip=right"
         | 
| 39 | 
            +
                  elsif req.GET["flip"] == "crash"
         | 
| 40 | 
            +
                    raise "Lobster crashed"
         | 
| 41 | 
            +
                  else
         | 
| 42 | 
            +
                    lobster = LobsterString
         | 
| 43 | 
            +
                    href = "?flip=left"
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                  
         | 
| 46 | 
            +
                  Response.new.finish do |res|
         | 
| 47 | 
            +
                    res.write "<title>Lobstericious!</title>"
         | 
| 48 | 
            +
                    res.write "<pre>"
         | 
| 49 | 
            +
                    res.write lobster
         | 
| 50 | 
            +
                    res.write "</pre>"
         | 
| 51 | 
            +
                    res.write "<p><a href='#{href}'>flip!</a></p>"
         | 
| 52 | 
            +
                    res.write "<p><a href='?flip=crash'>crash!</a></p>"
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            if $0 == __FILE__
         | 
| 60 | 
            +
              require 'rack'
         | 
| 61 | 
            +
              require 'rack/showexceptions'
         | 
| 62 | 
            +
              Rack::Handler::WEBrick.run \
         | 
| 63 | 
            +
                Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)),
         | 
| 64 | 
            +
                :Port => 9202
         | 
| 65 | 
            +
            end
         | 
    
        data/lib/rack/mock.rb
    ADDED
    
    | @@ -0,0 +1,183 @@ | |
| 1 | 
            +
            require 'uri'
         | 
| 2 | 
            +
            require 'stringio'
         | 
| 3 | 
            +
            require 'rack/lint'
         | 
| 4 | 
            +
            require 'rack/utils'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Rack
         | 
| 7 | 
            +
              # Rack::MockRequest helps testing your Rack application without
         | 
| 8 | 
            +
              # actually using HTTP.
         | 
| 9 | 
            +
              #
         | 
| 10 | 
            +
              # After performing a request on a URL with get/post/put/delete, it
         | 
| 11 | 
            +
              # returns a MockResponse with useful helper methods for effective
         | 
| 12 | 
            +
              # testing.
         | 
| 13 | 
            +
              #
         | 
| 14 | 
            +
              # You can pass a hash with additional configuration to the
         | 
| 15 | 
            +
              # get/post/put/delete.
         | 
| 16 | 
            +
              # <tt>:input</tt>:: A String or IO-like to be used as rack.input.
         | 
| 17 | 
            +
              # <tt>:fatal</tt>:: Raise a FatalWarning if the app writes to rack.errors.
         | 
| 18 | 
            +
              # <tt>:lint</tt>:: If true, wrap the application in a Rack::Lint.
         | 
| 19 | 
            +
              
         | 
| 20 | 
            +
              class MockRequest
         | 
| 21 | 
            +
                class FatalWarning < RuntimeError
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                class FatalWarner
         | 
| 25 | 
            +
                  def puts(warning)
         | 
| 26 | 
            +
                    raise FatalWarning, warning
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  def write(warning)
         | 
| 30 | 
            +
                    raise FatalWarning, warning
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def flush
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                DEFAULT_ENV = {
         | 
| 38 | 
            +
                  "rack.version" => [0,1],
         | 
| 39 | 
            +
                  "rack.input" => StringIO.new,
         | 
| 40 | 
            +
                  "rack.errors" => StringIO.new,
         | 
| 41 | 
            +
                  "rack.multithread" => true,
         | 
| 42 | 
            +
                  "rack.multiprocess" => true,
         | 
| 43 | 
            +
                  "rack.run_once" => false,
         | 
| 44 | 
            +
                }
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def initialize(app)
         | 
| 47 | 
            +
                  @app = app
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def get(uri, opts={})    request("GET", uri, opts)    end
         | 
| 51 | 
            +
                def post(uri, opts={})   request("POST", uri, opts)   end
         | 
| 52 | 
            +
                def put(uri, opts={})    request("PUT", uri, opts)    end
         | 
| 53 | 
            +
                def delete(uri, opts={}) request("DELETE", uri, opts) end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                def request(method="GET", uri="", opts={})
         | 
| 56 | 
            +
                  env = self.class.env_for(uri, opts.merge(:method => method))
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  if opts[:lint]
         | 
| 59 | 
            +
                    app = Rack::Lint.new(@app)
         | 
| 60 | 
            +
                  else
         | 
| 61 | 
            +
                    app = @app
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  errors = env["rack.errors"]
         | 
| 65 | 
            +
                  MockResponse.new(*(app.call(env) + [errors]))
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                # Return the Rack environment used for a request to +uri+.
         | 
| 69 | 
            +
                def self.env_for(uri="", opts={})
         | 
| 70 | 
            +
                  uri = URI(uri)
         | 
| 71 | 
            +
                  env = DEFAULT_ENV.dup
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  env["REQUEST_METHOD"] = opts[:method] || "GET"
         | 
| 74 | 
            +
                  env["SERVER_NAME"] = uri.host || "example.org"
         | 
| 75 | 
            +
                  env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80"
         | 
| 76 | 
            +
                  env["QUERY_STRING"] = uri.query.to_s
         | 
| 77 | 
            +
                  env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path
         | 
| 78 | 
            +
                  env["rack.url_scheme"] = uri.scheme || "http"
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  env["SCRIPT_NAME"] = opts[:script_name] || ""
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  if opts[:fatal]
         | 
| 83 | 
            +
                    env["rack.errors"] = FatalWarner.new
         | 
| 84 | 
            +
                  else
         | 
| 85 | 
            +
                    env["rack.errors"] = StringIO.new
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  opts[:input] ||= ""
         | 
| 89 | 
            +
                  if String === opts[:input]
         | 
| 90 | 
            +
                    env["rack.input"] = StringIO.new(opts[:input])
         | 
| 91 | 
            +
                  else
         | 
| 92 | 
            +
                    env["rack.input"] = opts[:input]
         | 
| 93 | 
            +
                  end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                  opts.each { |field, value|
         | 
| 96 | 
            +
                    env[field] = value  if String === field
         | 
| 97 | 
            +
                  }
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  env
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
              # Rack::MockResponse provides useful helpers for testing your apps.
         | 
| 104 | 
            +
              # Usually, you don't create the MockResponse on your own, but use
         | 
| 105 | 
            +
              # MockRequest.
         | 
| 106 | 
            +
             | 
| 107 | 
            +
              class MockResponse
         | 
| 108 | 
            +
                def initialize(status, headers, body, errors=StringIO.new(""))
         | 
| 109 | 
            +
                  @status = status.to_i
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  @original_headers = headers
         | 
| 112 | 
            +
                  @headers = Rack::Utils::HeaderHash.new
         | 
| 113 | 
            +
                  headers.each { |field, values|
         | 
| 114 | 
            +
                    values.each { |value|
         | 
| 115 | 
            +
                      @headers[field] = value
         | 
| 116 | 
            +
                    }
         | 
| 117 | 
            +
                  }
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  @body = ""
         | 
| 120 | 
            +
                  body.each { |part| @body << part }
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                  @errors = errors.string
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                # Status
         | 
| 126 | 
            +
                attr_reader :status
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                def invalid?;       @status < 100 || @status >= 600;       end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                def informational?; @status >= 100 && @status < 200;       end
         | 
| 131 | 
            +
                def successful?;    @status >= 200 && @status < 300;       end
         | 
| 132 | 
            +
                def redirection?;   @status >= 300 && @status < 400;       end
         | 
| 133 | 
            +
                def client_error?;  @status >= 400 && @status < 500;       end
         | 
| 134 | 
            +
                def server_error?;  @status >= 500 && @status < 600;       end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                def ok?;            @status == 200;                        end
         | 
| 137 | 
            +
                def forbidden?;     @status == 403;                        end
         | 
| 138 | 
            +
                def not_found?;     @status == 404;                        end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                def redirect?;      [301, 302, 303, 307].include? @status; end
         | 
| 141 | 
            +
                def empty?;         [201, 204, 304].include?      @status; end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                # Headers
         | 
| 144 | 
            +
                attr_reader :headers, :original_headers
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                def include?(header)
         | 
| 147 | 
            +
                  !!headers[header]
         | 
| 148 | 
            +
                end
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                def [](field)
         | 
| 151 | 
            +
                  headers[field]
         | 
| 152 | 
            +
                end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                def content_type
         | 
| 155 | 
            +
                  headers["Content-Type"]
         | 
| 156 | 
            +
                end
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                def content_length
         | 
| 159 | 
            +
                  cl = headers["Content-Length"]
         | 
| 160 | 
            +
                  cl ? cl.to_i : cl
         | 
| 161 | 
            +
                end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                def location
         | 
| 164 | 
            +
                  headers["Location"]
         | 
| 165 | 
            +
                end
         | 
| 166 | 
            +
             | 
| 167 | 
            +
             | 
| 168 | 
            +
                # Body
         | 
| 169 | 
            +
                attr_reader :body
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                def =~(other)
         | 
| 172 | 
            +
                  @body =~ other
         | 
| 173 | 
            +
                end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                def match(other)
         | 
| 176 | 
            +
                  @body.match other
         | 
| 177 | 
            +
                end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
             | 
| 180 | 
            +
                # Errors
         | 
| 181 | 
            +
                attr_accessor :errors
         | 
| 182 | 
            +
              end
         | 
| 183 | 
            +
            end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            require 'uri'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Rack
         | 
| 4 | 
            +
              # Rack::ForwardRequest gets caught by Rack::Recursive and redirects
         | 
| 5 | 
            +
              # the current request to the app at +url+.
         | 
| 6 | 
            +
              #
         | 
| 7 | 
            +
              #   raise ForwardRequest.new("/not-found")
         | 
| 8 | 
            +
              #
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              class ForwardRequest < Exception
         | 
| 11 | 
            +
                attr_reader :url, :env
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def initialize(url, env={})
         | 
| 14 | 
            +
                  @url = URI(url)
         | 
| 15 | 
            +
                  @env = env
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  @env["PATH_INFO"] =       @url.path
         | 
| 18 | 
            +
                  @env["QUERY_STRING"] =    @url.query  if @url.query
         | 
| 19 | 
            +
                  @env["HTTP_HOST"] =       @url.host   if @url.host
         | 
| 20 | 
            +
                  @env["HTTP_PORT"] =       @url.port   if @url.port
         | 
| 21 | 
            +
                  @env["rack.url_scheme"] = @url.scheme if @url.scheme
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  super "forwarding to #{url}"
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              # Rack::Recursive allows applications called down the chain to
         | 
| 28 | 
            +
              # include data from other applications (by using
         | 
| 29 | 
            +
              # <tt>rack['rack.recursive.include'][...]</tt> or raise a
         | 
| 30 | 
            +
              # ForwardRequest to redirect internally.
         | 
| 31 | 
            +
              
         | 
| 32 | 
            +
              class Recursive
         | 
| 33 | 
            +
                def initialize(app)
         | 
| 34 | 
            +
                  @app = app
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def call(env)
         | 
| 38 | 
            +
                  @script_name = env["SCRIPT_NAME"]
         | 
| 39 | 
            +
                  @app.call(env.merge('rack.recursive.include' => method(:include)))
         | 
| 40 | 
            +
                rescue ForwardRequest => req
         | 
| 41 | 
            +
                  call(env.merge(req.env))
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def include(env, path)
         | 
| 45 | 
            +
                  unless path.index(@script_name) == 0 && (path[@script_name.size] == ?/ ||
         | 
| 46 | 
            +
                                                           path[@script_name.size].nil?)
         | 
| 47 | 
            +
                    raise ArgumentError, "can only include below #{@script_name}, not #{path}"
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  env = env.merge("PATH_INFO" => path, "SCRIPT_NAME" => @script_name,
         | 
| 51 | 
            +
                                  "REQUEST_METHOD" => "GET",
         | 
| 52 | 
            +
                                  "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "",
         | 
| 53 | 
            +
                                  "rack.input" => StringIO.new(""))
         | 
| 54 | 
            +
                  @app.call(env)
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,64 @@ | |
| 1 | 
            +
            require 'thread'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Rack
         | 
| 4 | 
            +
              # Rack::Reloader checks on every request, but at most every +secs+
         | 
| 5 | 
            +
              # seconds, if a file loaded changed, and reloads it, logging to
         | 
| 6 | 
            +
              # rack.errors.
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              # It is recommended you use ShowExceptions to catch SyntaxErrors etc.
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
              class Reloader
         | 
| 11 | 
            +
                def initialize(app, secs=10)
         | 
| 12 | 
            +
                  @app = app
         | 
| 13 | 
            +
                  @secs = secs              # reload every @secs seconds max
         | 
| 14 | 
            +
                  @last = Time.now
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def call(env)
         | 
| 18 | 
            +
                  if Time.now > @last + @secs
         | 
| 19 | 
            +
                    Thread.exclusive {
         | 
| 20 | 
            +
                      reload!(env['rack.errors'])
         | 
| 21 | 
            +
                      @last = Time.now
         | 
| 22 | 
            +
                    }
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  @app.call(env)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def reload!(stderr=STDERR)
         | 
| 29 | 
            +
                  need_reload = $LOADED_FEATURES.find_all { |loaded|
         | 
| 30 | 
            +
                    begin
         | 
| 31 | 
            +
                      if loaded =~ /\A[.\/]/  # absolute filename or 1.9
         | 
| 32 | 
            +
                        abs = loaded
         | 
| 33 | 
            +
                      else
         | 
| 34 | 
            +
                        abs = $LOAD_PATH.map { |path| ::File.join(path, loaded) }.
         | 
| 35 | 
            +
                                         find { |file| ::File.exist? file }
         | 
| 36 | 
            +
                      end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                      if abs
         | 
| 39 | 
            +
                        ::File.mtime(abs) > @last - @secs  rescue false
         | 
| 40 | 
            +
                      else
         | 
| 41 | 
            +
                        false
         | 
| 42 | 
            +
                      end
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                  }
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  need_reload.each { |l|
         | 
| 47 | 
            +
                    $LOADED_FEATURES.delete l
         | 
| 48 | 
            +
                  }
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  need_reload.each { |to_load|
         | 
| 51 | 
            +
                    begin
         | 
| 52 | 
            +
                      if require to_load
         | 
| 53 | 
            +
                        stderr.puts "#{self.class}: reloaded `#{to_load}'"
         | 
| 54 | 
            +
                      end
         | 
| 55 | 
            +
                    rescue LoadError, SyntaxError => e
         | 
| 56 | 
            +
                      raise e                 # Possibly ShowExceptions
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
                  }
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  stderr.flush
         | 
| 61 | 
            +
                  need_reload
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
            end
         | 
    
        data/lib/rack/request.rb
    ADDED
    
    | @@ -0,0 +1,112 @@ | |
| 1 | 
            +
            require 'rack/utils'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Rack
         | 
| 4 | 
            +
              # Rack::Request provides a convenient interface to a Rack
         | 
| 5 | 
            +
              # environment.  It is stateless, the environment +env+ passed to the
         | 
| 6 | 
            +
              # constructor will be directly modified.
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              #   req = Rack::Request.new(env)
         | 
| 9 | 
            +
              #   req.post?
         | 
| 10 | 
            +
              #   req.params["data"]
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
              class Request
         | 
| 13 | 
            +
                # The environment of the request.
         | 
| 14 | 
            +
                attr_reader :env
         | 
| 15 | 
            +
                
         | 
| 16 | 
            +
                def initialize(env)
         | 
| 17 | 
            +
                  @env = env
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def body;            @env["rack.input"]                       end
         | 
| 21 | 
            +
                def scheme;          @env["rack.url_scheme"]                  end
         | 
| 22 | 
            +
                def script_name;     @env["SCRIPT_NAME"].to_s                 end
         | 
| 23 | 
            +
                def path_info;       @env["PATH_INFO"].to_s                   end
         | 
| 24 | 
            +
                def port;            @env["SERVER_PORT"].to_i                 end
         | 
| 25 | 
            +
                def request_method;  @env["REQUEST_METHOD"]                   end
         | 
| 26 | 
            +
                def query_string;    @env["QUERY_STRING"].to_s                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def host
         | 
| 29 | 
            +
                  # Remove port number.
         | 
| 30 | 
            +
                  (@env["HTTP_HOST"] || @env["SERVER_NAME"]).gsub(/:\d+\z/, '')
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def script_name=(s); @env["SCRIPT_NAME"] = s.to_s             end
         | 
| 34 | 
            +
                def path_info=(s);   @env["PATH_INFO"] = s.to_s               end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def get?;            request_method == "GET"                  end
         | 
| 37 | 
            +
                def post?;           request_method == "POST"                 end
         | 
| 38 | 
            +
                def put?;            request_method == "PUT"                  end
         | 
| 39 | 
            +
                def delete?;         request_method == "DELETE"               end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                # Returns the data recieved in the query string.
         | 
| 42 | 
            +
                def GET
         | 
| 43 | 
            +
                  if @env["rack.request.query_string"] == query_string
         | 
| 44 | 
            +
                    @env["rack.request.query_hash"]
         | 
| 45 | 
            +
                  else
         | 
| 46 | 
            +
                    @env["rack.request.query_string"] = query_string
         | 
| 47 | 
            +
                    @env["rack.request.query_hash"]   =
         | 
| 48 | 
            +
                      Utils.parse_query(query_string)
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                # Returns the data recieved in the request body.
         | 
| 53 | 
            +
                #
         | 
| 54 | 
            +
                # This method support both application/x-www-form-urlencoded and
         | 
| 55 | 
            +
                # multipart/form-data.
         | 
| 56 | 
            +
                def POST
         | 
| 57 | 
            +
                  if @env["rack.request.form_input"] == @env["rack.input"]
         | 
| 58 | 
            +
                    @env["rack.request.form_hash"]
         | 
| 59 | 
            +
                  else
         | 
| 60 | 
            +
                    @env["rack.request.form_input"] = @env["rack.input"]
         | 
| 61 | 
            +
                    unless @env["rack.request.form_hash"] =
         | 
| 62 | 
            +
                        Utils::Multipart.parse_multipart(env) 
         | 
| 63 | 
            +
                      @env["rack.request.form_vars"] = @env["rack.input"].read
         | 
| 64 | 
            +
                      @env["rack.request.form_hash"] = Utils.parse_query(@env["rack.request.form_vars"])
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                    @env["rack.request.form_hash"]
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                # The union of GET and POST data.
         | 
| 71 | 
            +
                def params
         | 
| 72 | 
            +
                  self.GET.update(self.POST)
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                def cookies
         | 
| 76 | 
            +
                  return {}  unless @env["HTTP_COOKIE"]
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  if @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"]
         | 
| 79 | 
            +
                    @env["rack.request.cookie_hash"]
         | 
| 80 | 
            +
                  else
         | 
| 81 | 
            +
                    @env["rack.request.cookie_string"] = @env["HTTP_COOKIE"]
         | 
| 82 | 
            +
                    # XXX sure?
         | 
| 83 | 
            +
                    @env["rack.request.cookie_hash"] =
         | 
| 84 | 
            +
                      Utils.parse_query(@env["rack.request.cookie_string"], ';,')
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                def xhr?
         | 
| 89 | 
            +
                  @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest"
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                # Tries to return a remake of the original request URL as a string.
         | 
| 93 | 
            +
                def url
         | 
| 94 | 
            +
                  url = scheme + "://"
         | 
| 95 | 
            +
                  url << host
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  if scheme == "https" && port != 443 ||
         | 
| 98 | 
            +
                      scheme == "http" && port != 80
         | 
| 99 | 
            +
                    url << ":#{port}"
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  url << script_name
         | 
| 103 | 
            +
                  url << path_info
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  unless query_string.empty?
         | 
| 106 | 
            +
                    url << "?" << query_string
         | 
| 107 | 
            +
                  end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  url
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
              end
         | 
| 112 | 
            +
            end
         |