rack 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

Files changed (48) hide show
  1. data/AUTHORS +2 -0
  2. data/RDOX +46 -1
  3. data/README +19 -4
  4. data/Rakefile +9 -8
  5. data/bin/rackup +2 -0
  6. data/example/protectedlobster.rb +14 -0
  7. data/lib/rack.rb +19 -0
  8. data/lib/rack/adapter/camping.rb +6 -0
  9. data/lib/rack/auth/abstract/handler.rb +28 -0
  10. data/lib/rack/auth/abstract/request.rb +39 -0
  11. data/lib/rack/auth/basic.rb +58 -0
  12. data/lib/rack/auth/digest/md5.rb +124 -0
  13. data/lib/rack/auth/digest/nonce.rb +52 -0
  14. data/lib/rack/auth/digest/params.rb +55 -0
  15. data/lib/rack/auth/digest/request.rb +40 -0
  16. data/lib/rack/commonlogger.rb +1 -1
  17. data/lib/rack/file.rb +1 -1
  18. data/lib/rack/handler/cgi.rb +7 -7
  19. data/lib/rack/handler/fastcgi.rb +1 -1
  20. data/lib/rack/handler/mongrel.rb +8 -7
  21. data/lib/rack/handler/webrick.rb +7 -6
  22. data/lib/rack/lint.rb +3 -3
  23. data/lib/rack/lobster.rb +4 -4
  24. data/lib/rack/mock.rb +9 -33
  25. data/lib/rack/recursive.rb +1 -1
  26. data/lib/rack/reloader.rb +1 -1
  27. data/lib/rack/request.rb +32 -9
  28. data/lib/rack/response.rb +54 -8
  29. data/lib/rack/session/cookie.rb +73 -0
  30. data/lib/rack/showexceptions.rb +2 -2
  31. data/lib/rack/showstatus.rb +103 -0
  32. data/lib/rack/static.rb +38 -0
  33. data/lib/rack/urlmap.rb +1 -1
  34. data/lib/rack/utils.rb +45 -3
  35. data/test/spec_rack_auth_basic.rb +68 -0
  36. data/test/spec_rack_auth_digest.rb +167 -0
  37. data/test/spec_rack_camping.rb +3 -0
  38. data/test/spec_rack_mock.rb +2 -0
  39. data/test/spec_rack_mongrel.rb +12 -0
  40. data/test/spec_rack_request.rb +60 -0
  41. data/test/spec_rack_response.rb +50 -1
  42. data/test/spec_rack_session_cookie.rb +49 -0
  43. data/test/spec_rack_showstatus.rb +71 -0
  44. data/test/spec_rack_static.rb +37 -0
  45. data/test/spec_rack_urlmap.rb +1 -7
  46. data/test/spec_rack_webrick.rb +17 -0
  47. metadata +23 -3
  48. data/lib/rack/adapter/rails.rb +0 -65
@@ -0,0 +1,52 @@
1
+ require 'base64'
2
+ require 'digest/md5'
3
+
4
+ module Rack
5
+ module Auth
6
+ module Digest
7
+ # Rack::Auth::Digest::Nonce is the default nonce generator for the
8
+ # Rack::Auth::Digest::MD5 authentication handler.
9
+ #
10
+ # +private_key+ needs to set to a constant string.
11
+ #
12
+ # +time_limit+ can be optionally set to an integer (number of seconds),
13
+ # to limit the validity of the generated nonces.
14
+
15
+ class Nonce
16
+
17
+ class << self
18
+ attr_accessor :private_key, :time_limit
19
+ end
20
+
21
+ def self.parse(string)
22
+ new(*Base64.decode64(string).split(' ', 2))
23
+ end
24
+
25
+ def initialize(timestamp = Time.now, given_digest = nil)
26
+ @timestamp, @given_digest = timestamp.to_i, given_digest
27
+ end
28
+
29
+ def to_s
30
+ Base64.encode64([ @timestamp, digest ] * ' ').strip
31
+ end
32
+
33
+ def digest
34
+ ::Digest::MD5.hexdigest([ @timestamp, self.class.private_key ] * ':')
35
+ end
36
+
37
+ def valid?
38
+ digest == @given_digest
39
+ end
40
+
41
+ def stale?
42
+ !self.class.time_limit.nil? && (@timestamp - Time.now.to_i) < self.class.time_limit
43
+ end
44
+
45
+ def fresh?
46
+ !stale?
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,55 @@
1
+ module Rack
2
+ module Auth
3
+ module Digest
4
+ class Params < Hash
5
+
6
+ def self.parse(str)
7
+ split_header_value(str).inject(new) do |header, param|
8
+ k, v = param.split('=', 2)
9
+ header[k] = dequote(v)
10
+ header
11
+ end
12
+ end
13
+
14
+ def self.dequote(str) # From WEBrick::HTTPUtils
15
+ ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
16
+ ret.gsub!(/\\(.)/, "\\1")
17
+ ret
18
+ end
19
+
20
+ def self.split_header_value(str) # From WEBrick::HTTPUtils
21
+ str.scan(/((?:"(?:\\.|[^"])+?"|[^",]+)+)(?:,\s*|\Z)/n).collect{ |v| v[0] }
22
+ end
23
+
24
+ def initialize
25
+ super
26
+
27
+ yield self if block_given?
28
+ end
29
+
30
+ def [](k)
31
+ super k.to_s
32
+ end
33
+
34
+ def []=(k, v)
35
+ super k.to_s, v.to_s
36
+ end
37
+
38
+ UNQUOTED = ['qop', 'nc', 'stale']
39
+
40
+ def to_s
41
+ inject([]) do |parts, (k, v)|
42
+ parts << "#{k}=" + (UNQUOTED.include?(k) ? v.to_s : quote(v))
43
+ parts
44
+ end.join(', ')
45
+ end
46
+
47
+ def quote(str) # From WEBrick::HTTPUtils
48
+ '"' << str.gsub(/[\\\"]/o, "\\\1") << '"'
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,40 @@
1
+ require 'rack/auth/abstract/request'
2
+ require 'rack/auth/digest/params'
3
+ require 'rack/auth/digest/nonce'
4
+
5
+ module Rack
6
+ module Auth
7
+ module Digest
8
+ class Request < Auth::AbstractRequest
9
+
10
+ def method
11
+ @env['REQUEST_METHOD']
12
+ end
13
+
14
+ def digest?
15
+ :digest == scheme
16
+ end
17
+
18
+ def correct_uri?
19
+ @env['PATH_INFO'] == uri
20
+ end
21
+
22
+ def nonce
23
+ @nonce ||= Nonce.parse(params['nonce'])
24
+ end
25
+
26
+ def params
27
+ @params ||= Params.parse(parts.last)
28
+ end
29
+
30
+ def method_missing(sym)
31
+ if params.has_key? key = sym.to_s
32
+ return params[key]
33
+ end
34
+ super
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -2,7 +2,7 @@ module Rack
2
2
  # Rack::CommonLogger forwards every request to an +app+ given, and
3
3
  # logs a line in the Apache common log format to the +logger+, or
4
4
  # rack.errors by default.
5
-
5
+
6
6
  class CommonLogger
7
7
  def initialize(app, logger=nil)
8
8
  @app = app
@@ -4,7 +4,7 @@ module Rack
4
4
  #
5
5
  # Handlers can detect if bodies are a Rack::File, and use mechanisms
6
6
  # like sendfile on the +path+.
7
-
7
+
8
8
  class File
9
9
  attr_accessor :root
10
10
  attr_accessor :path
@@ -4,7 +4,7 @@ module Rack
4
4
  def self.run(app, options=nil)
5
5
  serve app
6
6
  end
7
-
7
+
8
8
  def self.serve(app)
9
9
  env = ENV.to_hash
10
10
  env.delete "HTTP_CONTENT_LENGTH"
@@ -14,18 +14,18 @@ module Rack
14
14
  env.update({"rack.version" => [0,1],
15
15
  "rack.input" => STDIN,
16
16
  "rack.errors" => STDERR,
17
-
17
+
18
18
  "rack.multithread" => false,
19
19
  "rack.multiprocess" => true,
20
20
  "rack.run_once" => true,
21
-
21
+
22
22
  "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http"
23
23
  })
24
-
24
+
25
25
  env["QUERY_STRING"] ||= ""
26
26
  env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
27
27
  env["REQUEST_PATH"] ||= "/"
28
-
28
+
29
29
  status, headers, body = app.call(env)
30
30
  begin
31
31
  send_headers status, headers
@@ -34,7 +34,7 @@ module Rack
34
34
  body.close if body.respond_to? :close
35
35
  end
36
36
  end
37
-
37
+
38
38
  def self.send_headers(status, headers)
39
39
  STDOUT.print "Status: #{status}\r\n"
40
40
  headers.each { |k, vs|
@@ -45,7 +45,7 @@ module Rack
45
45
  STDOUT.print "\r\n"
46
46
  STDOUT.flush
47
47
  end
48
-
48
+
49
49
  def self.send_body(body)
50
50
  body.each { |part|
51
51
  STDOUT.print part
@@ -9,7 +9,7 @@ module Rack
9
9
  }
10
10
  end
11
11
 
12
- module ProperStream
12
+ module ProperStream # :nodoc:
13
13
  def each # This is missing by default.
14
14
  while line = gets
15
15
  yield line
@@ -4,37 +4,38 @@ require 'stringio'
4
4
  module Rack
5
5
  module Handler
6
6
  class Mongrel < ::Mongrel::HttpHandler
7
- def self.run(app, options)
7
+ def self.run(app, options={})
8
8
  server = ::Mongrel::HttpServer.new(options[:Host] || '0.0.0.0',
9
9
  options[:Port] || 8080)
10
10
  server.register('/', Rack::Handler::Mongrel.new(app))
11
+ yield server if block_given?
11
12
  server.run.join
12
13
  end
13
-
14
+
14
15
  def initialize(app)
15
16
  @app = app
16
17
  end
17
-
18
+
18
19
  def process(request, response)
19
20
  env = {}.replace(request.params)
20
21
  env.delete "HTTP_CONTENT_TYPE"
21
22
  env.delete "HTTP_CONTENT_LENGTH"
22
23
 
23
24
  env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
24
-
25
+
25
26
  env.update({"rack.version" => [0,1],
26
27
  "rack.input" => request.body || StringIO.new(""),
27
28
  "rack.errors" => STDERR,
28
-
29
+
29
30
  "rack.multithread" => true,
30
31
  "rack.multiprocess" => false, # ???
31
32
  "rack.run_once" => false,
32
-
33
+
33
34
  "rack.url_scheme" => "http",
34
35
  })
35
36
  env["QUERY_STRING"] ||= ""
36
37
  env.delete "PATH_INFO" if env["PATH_INFO"] == ""
37
-
38
+
38
39
  status, headers, body = @app.call(env)
39
40
 
40
41
  begin
@@ -8,29 +8,30 @@ module Rack
8
8
  server = ::WEBrick::HTTPServer.new(options)
9
9
  server.mount "/", Rack::Handler::WEBrick, app
10
10
  trap(:INT) { server.shutdown }
11
+ yield server if block_given?
11
12
  server.start
12
13
  end
13
-
14
+
14
15
  def initialize(server, app)
15
16
  super server
16
17
  @app = app
17
18
  end
18
-
19
+
19
20
  def service(req, res)
20
21
  env = req.meta_vars
21
22
  env.delete_if { |k, v| v.nil? }
22
-
23
+
23
24
  env.update({"rack.version" => [0,1],
24
25
  "rack.input" => StringIO.new(req.body.to_s),
25
26
  "rack.errors" => STDERR,
26
-
27
+
27
28
  "rack.multithread" => true,
28
29
  "rack.multiprocess" => false,
29
30
  "rack.run_once" => false,
30
-
31
+
31
32
  "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http"
32
33
  })
33
-
34
+
34
35
  env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
35
36
  env["QUERY_STRING"] ||= ""
36
37
  env["REQUEST_PATH"] ||= "/"
@@ -1,7 +1,7 @@
1
1
  module Rack
2
2
  # Rack::Lint validates your application and the requests and
3
3
  # responses according to the Rack spec.
4
-
4
+
5
5
  class Lint
6
6
  def initialize(app)
7
7
  @app = app
@@ -47,7 +47,7 @@ module Rack
47
47
  check_content_type status, headers
48
48
  [status, headers, self]
49
49
  end
50
-
50
+
51
51
  ## == The Environment
52
52
  def check_env(env)
53
53
  ## The environment must be an true instance of Hash (no
@@ -210,7 +210,7 @@ module Rack
210
210
  def initialize(input)
211
211
  @input = input
212
212
  end
213
-
213
+
214
214
  ## * +gets+ must be called without arguments and return a string,
215
215
  ## or +nil+ on EOF.
216
216
  def gets(*args)
@@ -21,14 +21,14 @@ module Rack
21
21
  lobster = LobsterString
22
22
  href = "?flip"
23
23
  end
24
-
24
+
25
25
  [200, {"Content-Type" => "text/html"},
26
26
  ["<title>Lobstericious!</title>",
27
27
  "<pre>", lobster, "</pre>",
28
28
  "<a href='#{href}'>flip!</a>"]
29
29
  ]
30
30
  }
31
-
31
+
32
32
  def call(env)
33
33
  req = Request.new(env)
34
34
  if req.GET["flip"] == "left"
@@ -42,7 +42,7 @@ module Rack
42
42
  lobster = LobsterString
43
43
  href = "?flip=left"
44
44
  end
45
-
45
+
46
46
  Response.new.finish do |res|
47
47
  res.write "<title>Lobstericious!</title>"
48
48
  res.write "<pre>"
@@ -61,5 +61,5 @@ if $0 == __FILE__
61
61
  require 'rack/showexceptions'
62
62
  Rack::Handler::WEBrick.run \
63
63
  Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)),
64
- :Port => 9202
64
+ :Port => 9292
65
65
  end
@@ -2,6 +2,7 @@ require 'uri'
2
2
  require 'stringio'
3
3
  require 'rack/lint'
4
4
  require 'rack/utils'
5
+ require 'rack/response'
5
6
 
6
7
  module Rack
7
8
  # Rack::MockRequest helps testing your Rack application without
@@ -16,7 +17,7 @@ module Rack
16
17
  # <tt>:input</tt>:: A String or IO-like to be used as rack.input.
17
18
  # <tt>:fatal</tt>:: Raise a FatalWarning if the app writes to rack.errors.
18
19
  # <tt>:lint</tt>:: If true, wrap the application in a Rack::Lint.
19
-
20
+
20
21
  class MockRequest
21
22
  class FatalWarning < RuntimeError
22
23
  end
@@ -32,6 +33,10 @@ module Rack
32
33
 
33
34
  def flush
34
35
  end
36
+
37
+ def string
38
+ ""
39
+ end
35
40
  end
36
41
 
37
42
  DEFAULT_ENV = {
@@ -125,45 +130,13 @@ module Rack
125
130
  # Status
126
131
  attr_reader :status
127
132
 
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
133
  # Headers
144
134
  attr_reader :headers, :original_headers
145
135
 
146
- def include?(header)
147
- !!headers[header]
148
- end
149
-
150
136
  def [](field)
151
137
  headers[field]
152
138
  end
153
139
 
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
140
 
168
141
  # Body
169
142
  attr_reader :body
@@ -179,5 +152,8 @@ module Rack
179
152
 
180
153
  # Errors
181
154
  attr_accessor :errors
155
+
156
+
157
+ include Response::Helpers
182
158
  end
183
159
  end