rack 0.9.1 → 1.0.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 (79) hide show
  1. data/COPYING +1 -1
  2. data/RDOX +115 -16
  3. data/README +54 -7
  4. data/Rakefile +61 -85
  5. data/SPEC +50 -17
  6. data/bin/rackup +9 -5
  7. data/example/protectedlobster.ru +1 -1
  8. data/lib/rack.rb +7 -3
  9. data/lib/rack/auth/abstract/handler.rb +13 -4
  10. data/lib/rack/auth/digest/md5.rb +1 -1
  11. data/lib/rack/auth/digest/request.rb +2 -2
  12. data/lib/rack/auth/openid.rb +344 -302
  13. data/lib/rack/builder.rb +1 -5
  14. data/lib/rack/chunked.rb +49 -0
  15. data/lib/rack/conditionalget.rb +4 -0
  16. data/lib/rack/content_length.rb +7 -3
  17. data/lib/rack/content_type.rb +23 -0
  18. data/lib/rack/deflater.rb +83 -74
  19. data/lib/rack/directory.rb +5 -2
  20. data/lib/rack/file.rb +4 -1
  21. data/lib/rack/handler.rb +22 -1
  22. data/lib/rack/handler/cgi.rb +7 -3
  23. data/lib/rack/handler/fastcgi.rb +26 -24
  24. data/lib/rack/handler/lsws.rb +7 -4
  25. data/lib/rack/handler/mongrel.rb +5 -3
  26. data/lib/rack/handler/scgi.rb +5 -3
  27. data/lib/rack/handler/thin.rb +3 -0
  28. data/lib/rack/handler/webrick.rb +11 -5
  29. data/lib/rack/lint.rb +138 -66
  30. data/lib/rack/lock.rb +16 -0
  31. data/lib/rack/mime.rb +4 -4
  32. data/lib/rack/mock.rb +3 -3
  33. data/lib/rack/reloader.rb +88 -46
  34. data/lib/rack/request.rb +46 -10
  35. data/lib/rack/response.rb +15 -3
  36. data/lib/rack/rewindable_input.rb +98 -0
  37. data/lib/rack/session/abstract/id.rb +71 -82
  38. data/lib/rack/session/cookie.rb +2 -0
  39. data/lib/rack/session/memcache.rb +59 -47
  40. data/lib/rack/session/pool.rb +56 -29
  41. data/lib/rack/showexceptions.rb +2 -1
  42. data/lib/rack/showstatus.rb +1 -1
  43. data/lib/rack/urlmap.rb +12 -5
  44. data/lib/rack/utils.rb +115 -65
  45. data/rack.gemspec +54 -0
  46. data/test/multipart/binary +0 -0
  47. data/test/multipart/empty +10 -0
  48. data/test/multipart/ie +6 -0
  49. data/test/multipart/nested +10 -0
  50. data/test/multipart/none +9 -0
  51. data/test/multipart/text +10 -0
  52. data/test/spec_rack_auth_basic.rb +5 -1
  53. data/test/spec_rack_auth_digest.rb +93 -36
  54. data/test/spec_rack_auth_openid.rb +47 -100
  55. data/test/spec_rack_builder.rb +2 -2
  56. data/test/spec_rack_chunked.rb +62 -0
  57. data/test/spec_rack_conditionalget.rb +7 -7
  58. data/test/spec_rack_content_type.rb +30 -0
  59. data/test/spec_rack_deflater.rb +36 -14
  60. data/test/spec_rack_directory.rb +1 -1
  61. data/test/spec_rack_file.rb +11 -0
  62. data/test/spec_rack_handler.rb +21 -2
  63. data/test/spec_rack_lint.rb +163 -44
  64. data/test/spec_rack_lock.rb +38 -0
  65. data/test/spec_rack_mock.rb +6 -1
  66. data/test/spec_rack_request.rb +81 -12
  67. data/test/spec_rack_response.rb +46 -2
  68. data/test/spec_rack_rewindable_input.rb +118 -0
  69. data/test/spec_rack_session_memcache.rb +170 -62
  70. data/test/spec_rack_session_pool.rb +129 -41
  71. data/test/spec_rack_static.rb +2 -2
  72. data/test/spec_rack_thin.rb +3 -2
  73. data/test/spec_rack_urlmap.rb +10 -0
  74. data/test/spec_rack_utils.rb +214 -49
  75. data/test/spec_rack_webrick.rb +7 -0
  76. data/test/unregistered_handler/rack/handler/unregistered.rb +7 -0
  77. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +7 -0
  78. metadata +95 -6
  79. data/AUTHORS +0 -8
@@ -1,6 +1,7 @@
1
1
  require 'ostruct'
2
2
  require 'erb'
3
3
  require 'rack/request'
4
+ require 'rack/utils'
4
5
 
5
6
  module Rack
6
7
  # Rack::ShowExceptions catches all exceptions raised from the app it
@@ -335,7 +336,7 @@ TEMPLATE = <<'HTML'
335
336
 
336
337
  <div id="explanation">
337
338
  <p>
338
- You're seeing this error because you use <code>Rack::ShowException</code>.
339
+ You're seeing this error because you use <code>Rack::ShowExceptions</code>.
339
340
  </p>
340
341
  </div>
341
342
 
@@ -27,7 +27,7 @@ module Rack
27
27
  message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s
28
28
  detail = env["rack.showstatus.detail"] || message
29
29
  body = @template.result(binding)
30
- size = body.respond_to?(:bytesize) ? body.bytesize : body.size
30
+ size = Rack::Utils.bytesize(body)
31
31
  [status, headers.merge("Content-Type" => "text/html", "Content-Length" => size.to_s), [body]]
32
32
  else
33
33
  [status, headers, body]
@@ -12,7 +12,11 @@ module Rack
12
12
  # first, since they are most specific.
13
13
 
14
14
  class URLMap
15
- def initialize(map)
15
+ def initialize(map = {})
16
+ remap(map)
17
+ end
18
+
19
+ def remap(map)
16
20
  @mapping = map.map { |location, app|
17
21
  if location =~ %r{\Ahttps?://(.*?)(/.*)}
18
22
  host, location = $1, $2
@@ -26,20 +30,23 @@ module Rack
26
30
  location = location.chomp('/')
27
31
 
28
32
  [host, location, app]
29
- }.sort_by { |(h, l, a)| [-l.size, h.to_s.size] } # Longest path first
33
+ }.sort_by { |(h, l, a)| [h ? -h.size : (-1.0 / 0.0), -l.size] } # Longest path first
30
34
  end
31
35
 
32
36
  def call(env)
33
37
  path = env["PATH_INFO"].to_s.squeeze("/")
38
+ script_name = env['SCRIPT_NAME']
34
39
  hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT')
35
40
  @mapping.each { |host, location, app|
36
41
  next unless (hHost == host || sName == host \
37
42
  || (host.nil? && (hHost == sName || hHost == sName+':'+sPort)))
38
43
  next unless location == path[0, location.size]
39
44
  next unless path[location.size] == nil || path[location.size] == ?/
40
- env["SCRIPT_NAME"] += location
41
- env["PATH_INFO"] = path[location.size..-1]
42
- return app.call(env)
45
+
46
+ return app.call(
47
+ env.merge(
48
+ 'SCRIPT_NAME' => (script_name + location),
49
+ 'PATH_INFO' => path[location.size..-1]))
43
50
  }
44
51
  [404, {"Content-Type" => "text/plain"}, ["Not Found: #{path}"]]
45
52
  end
@@ -29,7 +29,6 @@ module Rack
29
29
  # and ';' characters. You can also use this to parse
30
30
  # cookies by changing the characters used in the second
31
31
  # parameter (which defaults to '&;').
32
-
33
32
  def parse_query(qs, d = '&;')
34
33
  params = {}
35
34
 
@@ -51,6 +50,50 @@ module Rack
51
50
  end
52
51
  module_function :parse_query
53
52
 
53
+ def parse_nested_query(qs, d = '&;')
54
+ params = {}
55
+
56
+ (qs || '').split(/[#{d}] */n).each do |p|
57
+ k, v = unescape(p).split('=', 2)
58
+ normalize_params(params, k, v)
59
+ end
60
+
61
+ return params
62
+ end
63
+ module_function :parse_nested_query
64
+
65
+ def normalize_params(params, name, v = nil)
66
+ name =~ %r([\[\]]*([^\[\]]+)\]*)
67
+ k = $1 || ''
68
+ after = $' || ''
69
+
70
+ return if k.empty?
71
+
72
+ if after == ""
73
+ params[k] = v
74
+ elsif after == "[]"
75
+ params[k] ||= []
76
+ raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
77
+ params[k] << v
78
+ elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
79
+ child_key = $1
80
+ params[k] ||= []
81
+ raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
82
+ if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key)
83
+ normalize_params(params[k].last, child_key, v)
84
+ else
85
+ params[k] << normalize_params({}, child_key, v)
86
+ end
87
+ else
88
+ params[k] ||= {}
89
+ raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash)
90
+ params[k] = normalize_params(params[k], after, v)
91
+ end
92
+
93
+ return params
94
+ end
95
+ module_function :normalize_params
96
+
54
97
  def build_query(params)
55
98
  params.map { |k, v|
56
99
  if v.class == Array
@@ -102,57 +145,42 @@ module Rack
102
145
  end
103
146
  module_function :select_best_encoding
104
147
 
105
- # The recommended manner in which to implement a contexting application
106
- # is to define a method #context in which a new Context is instantiated.
107
- #
108
- # As a Context is a glorified block, it is highly recommended that you
109
- # define the contextual block within the application's operational scope.
110
- # This would typically the application as you're place into Rack's stack.
111
- #
112
- # class MyObject
113
- # ...
114
- # def context app
115
- # Rack::Utils::Context.new app do |env|
116
- # do_stuff
117
- # response = app.call(env)
118
- # do_more_stuff
119
- # end
120
- # end
121
- # ...
122
- # end
123
- #
124
- # mobj = MyObject.new
125
- # app = mobj.context other_app
126
- # Rack::Handler::Mongrel.new app
127
- class Context < Proc
128
- alias_method :old_inspect, :inspect
148
+ # Return the bytesize of String; uses String#length under Ruby 1.8 and
149
+ # String#bytesize under 1.9.
150
+ if ''.respond_to?(:bytesize)
151
+ def bytesize(string)
152
+ string.bytesize
153
+ end
154
+ else
155
+ def bytesize(string)
156
+ string.size
157
+ end
158
+ end
159
+ module_function :bytesize
160
+
161
+ # Context allows the use of a compatible middleware at different points
162
+ # in a request handling stack. A compatible middleware must define
163
+ # #context which should take the arguments env and app. The first of which
164
+ # would be the request environment. The second of which would be the rack
165
+ # application that the request would be forwarded to.
166
+ class Context
129
167
  attr_reader :for, :app
130
- def initialize app_f, app_r
131
- raise 'running context not provided' unless app_f
168
+
169
+ def initialize(app_f, app_r)
132
170
  raise 'running context does not respond to #context' unless app_f.respond_to? :context
133
- raise 'application context not provided' unless app_r
134
- raise 'application context does not respond to #call' unless app_r.respond_to? :call
135
- @for = app_f
136
- @app = app_r
171
+ @for, @app = app_f, app_r
137
172
  end
138
- def inspect
139
- "#{old_inspect} ==> #{@for.inspect} ==> #{@app.inspect}"
173
+
174
+ def call(env)
175
+ @for.context(env, @app)
140
176
  end
141
- def context app_r
142
- raise 'new application context not provided' unless app_r
143
- raise 'new application context does not respond to #call' unless app_r.respond_to? :call
144
- @for.context app_r
177
+
178
+ def recontext(app)
179
+ self.class.new(@for, app)
145
180
  end
146
- def pretty_print pp
147
- pp.text old_inspect
148
- pp.nest 1 do
149
- pp.breakable
150
- pp.text '=for> '
151
- pp.pp @for
152
- pp.breakable
153
- pp.text '=app> '
154
- pp.pp @app
155
- end
181
+
182
+ def context(env, app=@app)
183
+ recontext(app).call(env)
156
184
  end
157
185
  end
158
186
 
@@ -165,7 +193,14 @@ module Rack
165
193
  end
166
194
 
167
195
  def to_hash
168
- {}.replace(self)
196
+ inject({}) do |hash, (k,v)|
197
+ if v.respond_to? :to_ary
198
+ hash[k] = v.to_ary.join("\n")
199
+ else
200
+ hash[k] = v
201
+ end
202
+ hash
203
+ end
169
204
  end
170
205
 
171
206
  def [](k)
@@ -258,7 +293,7 @@ module Rack
258
293
 
259
294
  def self.parse_multipart(env)
260
295
  unless env['CONTENT_TYPE'] =~
261
- %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n
296
+ %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n
262
297
  nil
263
298
  else
264
299
  boundary = "--#{$1}"
@@ -267,16 +302,19 @@ module Rack
267
302
  buf = ""
268
303
  content_length = env['CONTENT_LENGTH'].to_i
269
304
  input = env['rack.input']
305
+ input.rewind
270
306
 
271
307
  boundary_size = boundary.size + EOL.size
272
308
  bufsize = 16384
273
309
 
274
310
  content_length -= boundary_size
275
311
 
276
- status = input.read(boundary_size)
312
+ read_buffer = ''
313
+
314
+ status = input.read(boundary_size, read_buffer)
277
315
  raise EOFError, "bad content body" unless status == boundary + EOL
278
316
 
279
- rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/
317
+ rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n
280
318
 
281
319
  loop {
282
320
  head = nil
@@ -284,15 +322,15 @@ module Rack
284
322
  filename = content_type = name = nil
285
323
 
286
324
  until head && buf =~ rx
287
- if !head && i = buf.index("\r\n\r\n")
325
+ if !head && i = buf.index(EOL+EOL)
288
326
  head = buf.slice!(0, i+2) # First \r\n
289
327
  buf.slice!(0, 2) # Second \r\n
290
328
 
291
329
  filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1]
292
- content_type = head[/Content-Type: (.*)\r\n/ni, 1]
293
- name = head[/Content-Disposition:.* name="?([^\";]*)"?/ni, 1]
330
+ content_type = head[/Content-Type: (.*)#{EOL}/ni, 1]
331
+ name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1]
294
332
 
295
- if filename
333
+ if content_type || filename
296
334
  body = Tempfile.new("RackMultipart")
297
335
  body.binmode if body.respond_to?(:binmode)
298
336
  end
@@ -305,7 +343,7 @@ module Rack
305
343
  body << buf.slice!(0, buf.size - (boundary_size+4))
306
344
  end
307
345
 
308
- c = input.read(bufsize < content_length ? bufsize : content_length)
346
+ c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer)
309
347
  raise EOFError, "bad content body" if c.nil? || c.empty?
310
348
  buf << c
311
349
  content_length -= c.size
@@ -319,26 +357,38 @@ module Rack
319
357
  content_length = -1 if $1 == "--"
320
358
  end
321
359
 
322
- if filename
360
+ if filename == ""
361
+ # filename is blank which means no file has been selected
362
+ data = nil
363
+ elsif filename
323
364
  body.rewind
365
+
366
+ # Take the basename of the upload's original filename.
367
+ # This handles the full Windows paths given by Internet Explorer
368
+ # (and perhaps other broken user agents) without affecting
369
+ # those which give the lone filename.
370
+ filename =~ /^(?:.*[:\\\/])?(.*)/m
371
+ filename = $1
372
+
324
373
  data = {:filename => filename, :type => content_type,
325
374
  :name => name, :tempfile => body, :head => head}
375
+ elsif !filename && content_type
376
+ body.rewind
377
+
378
+ # Generic multipart cases, not coming from a form
379
+ data = {:type => content_type,
380
+ :name => name, :tempfile => body, :head => head}
326
381
  else
327
382
  data = body
328
383
  end
329
384
 
330
- if name
331
- if name =~ /\[\]\z/
332
- params[name] ||= []
333
- params[name] << data
334
- else
335
- params[name] = data
336
- end
337
- end
385
+ Utils.normalize_params(params, name, data) unless data.nil?
338
386
 
339
387
  break if buf.empty? || content_length == -1
340
388
  }
341
389
 
390
+ input.rewind
391
+
342
392
  params
343
393
  end
344
394
  end
@@ -0,0 +1,54 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{rack}
5
+ s.version = "1.0.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Christian Neukirchen"]
9
+ s.date = %q{2009-04-25}
10
+ s.default_executable = %q{rackup}
11
+ s.description = %q{Rack provides minimal, modular and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call. Also see http://rack.rubyforge.org.}
12
+ s.email = %q{chneukirchen@gmail.com}
13
+ s.executables = ["rackup"]
14
+ s.extra_rdoc_files = ["README", "SPEC", "RDOX", "KNOWN-ISSUES"]
15
+ s.files = ["COPYING", "KNOWN-ISSUES", "README", "Rakefile", "bin/rackup", "contrib/rack_logo.svg", "example/lobster.ru", "example/protectedlobster.rb", "example/protectedlobster.ru", "lib/rack.rb", "lib/rack/adapter/camping.rb", "lib/rack/auth/abstract/handler.rb", "lib/rack/auth/abstract/request.rb", "lib/rack/auth/basic.rb", "lib/rack/auth/digest/md5.rb", "lib/rack/auth/digest/nonce.rb", "lib/rack/auth/digest/params.rb", "lib/rack/auth/digest/request.rb", "lib/rack/auth/openid.rb", "lib/rack/builder.rb", "lib/rack/cascade.rb", "lib/rack/chunked.rb", "lib/rack/commonlogger.rb", "lib/rack/conditionalget.rb", "lib/rack/content_length.rb", "lib/rack/content_type.rb", "lib/rack/deflater.rb", "lib/rack/directory.rb", "lib/rack/file.rb", "lib/rack/handler.rb", "lib/rack/handler/cgi.rb", "lib/rack/handler/evented_mongrel.rb", "lib/rack/handler/fastcgi.rb", "lib/rack/handler/lsws.rb", "lib/rack/handler/mongrel.rb", "lib/rack/handler/scgi.rb", "lib/rack/handler/swiftiplied_mongrel.rb", "lib/rack/handler/thin.rb", "lib/rack/handler/webrick.rb", "lib/rack/head.rb", "lib/rack/lint.rb", "lib/rack/lobster.rb", "lib/rack/lock.rb", "lib/rack/methodoverride.rb", "lib/rack/mime.rb", "lib/rack/mock.rb", "lib/rack/recursive.rb", "lib/rack/reloader.rb", "lib/rack/request.rb", "lib/rack/response.rb", "lib/rack/rewindable_input.rb", "lib/rack/session/abstract/id.rb", "lib/rack/session/cookie.rb", "lib/rack/session/memcache.rb", "lib/rack/session/pool.rb", "lib/rack/showexceptions.rb", "lib/rack/showstatus.rb", "lib/rack/static.rb", "lib/rack/urlmap.rb", "lib/rack/utils.rb", "test/cgi/lighttpd.conf", "test/cgi/test", "test/cgi/test.fcgi", "test/cgi/test.ru", "test/multipart/binary", "test/multipart/empty", "test/multipart/ie", "test/multipart/nested", "test/multipart/none", "test/multipart/text", "test/spec_rack_auth_basic.rb", "test/spec_rack_auth_digest.rb", "test/spec_rack_auth_openid.rb", "test/spec_rack_builder.rb", "test/spec_rack_camping.rb", "test/spec_rack_cascade.rb", "test/spec_rack_cgi.rb", "test/spec_rack_chunked.rb", "test/spec_rack_commonlogger.rb", "test/spec_rack_conditionalget.rb", "test/spec_rack_content_length.rb", "test/spec_rack_content_type.rb", "test/spec_rack_deflater.rb", "test/spec_rack_directory.rb", "test/spec_rack_fastcgi.rb", "test/spec_rack_file.rb", "test/spec_rack_handler.rb", "test/spec_rack_head.rb", "test/spec_rack_lint.rb", "test/spec_rack_lobster.rb", "test/spec_rack_lock.rb", "test/spec_rack_methodoverride.rb", "test/spec_rack_mock.rb", "test/spec_rack_mongrel.rb", "test/spec_rack_recursive.rb", "test/spec_rack_request.rb", "test/spec_rack_response.rb", "test/spec_rack_rewindable_input.rb", "test/spec_rack_session_cookie.rb", "test/spec_rack_session_memcache.rb", "test/spec_rack_session_pool.rb", "test/spec_rack_showexceptions.rb", "test/spec_rack_showstatus.rb", "test/spec_rack_static.rb", "test/spec_rack_thin.rb", "test/spec_rack_urlmap.rb", "test/spec_rack_utils.rb", "test/spec_rack_webrick.rb", "test/testrequest.rb", "test/unregistered_handler/rack/handler/unregistered.rb", "test/unregistered_handler/rack/handler/unregistered_long_one.rb", "SPEC", "RDOX", "rack.gemspec"]
16
+ s.has_rdoc = true
17
+ s.homepage = %q{http://rack.rubyforge.org}
18
+ s.require_paths = ["lib"]
19
+ s.rubyforge_project = %q{rack}
20
+ s.rubygems_version = %q{1.3.1}
21
+ s.summary = %q{a modular Ruby webserver interface}
22
+ s.test_files = ["test/spec_rack_auth_basic.rb", "test/spec_rack_auth_digest.rb", "test/spec_rack_auth_openid.rb", "test/spec_rack_builder.rb", "test/spec_rack_camping.rb", "test/spec_rack_cascade.rb", "test/spec_rack_cgi.rb", "test/spec_rack_chunked.rb", "test/spec_rack_commonlogger.rb", "test/spec_rack_conditionalget.rb", "test/spec_rack_content_length.rb", "test/spec_rack_content_type.rb", "test/spec_rack_deflater.rb", "test/spec_rack_directory.rb", "test/spec_rack_fastcgi.rb", "test/spec_rack_file.rb", "test/spec_rack_handler.rb", "test/spec_rack_head.rb", "test/spec_rack_lint.rb", "test/spec_rack_lobster.rb", "test/spec_rack_lock.rb", "test/spec_rack_methodoverride.rb", "test/spec_rack_mock.rb", "test/spec_rack_mongrel.rb", "test/spec_rack_recursive.rb", "test/spec_rack_request.rb", "test/spec_rack_response.rb", "test/spec_rack_rewindable_input.rb", "test/spec_rack_session_cookie.rb", "test/spec_rack_session_memcache.rb", "test/spec_rack_session_pool.rb", "test/spec_rack_showexceptions.rb", "test/spec_rack_showstatus.rb", "test/spec_rack_static.rb", "test/spec_rack_thin.rb", "test/spec_rack_urlmap.rb", "test/spec_rack_utils.rb", "test/spec_rack_webrick.rb"]
23
+
24
+ if s.respond_to? :specification_version then
25
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
26
+ s.specification_version = 2
27
+
28
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
29
+ s.add_development_dependency(%q<test-spec>, [">= 0"])
30
+ s.add_development_dependency(%q<camping>, [">= 0"])
31
+ s.add_development_dependency(%q<fcgi>, [">= 0"])
32
+ s.add_development_dependency(%q<memcache-client>, [">= 0"])
33
+ s.add_development_dependency(%q<mongrel>, [">= 0"])
34
+ s.add_development_dependency(%q<ruby-openid>, ["~> 2.0.0"])
35
+ s.add_development_dependency(%q<thin>, [">= 0"])
36
+ else
37
+ s.add_dependency(%q<test-spec>, [">= 0"])
38
+ s.add_dependency(%q<camping>, [">= 0"])
39
+ s.add_dependency(%q<fcgi>, [">= 0"])
40
+ s.add_dependency(%q<memcache-client>, [">= 0"])
41
+ s.add_dependency(%q<mongrel>, [">= 0"])
42
+ s.add_dependency(%q<ruby-openid>, ["~> 2.0.0"])
43
+ s.add_dependency(%q<thin>, [">= 0"])
44
+ end
45
+ else
46
+ s.add_dependency(%q<test-spec>, [">= 0"])
47
+ s.add_dependency(%q<camping>, [">= 0"])
48
+ s.add_dependency(%q<fcgi>, [">= 0"])
49
+ s.add_dependency(%q<memcache-client>, [">= 0"])
50
+ s.add_dependency(%q<mongrel>, [">= 0"])
51
+ s.add_dependency(%q<ruby-openid>, ["~> 2.0.0"])
52
+ s.add_dependency(%q<thin>, [">= 0"])
53
+ end
54
+ end
Binary file
@@ -0,0 +1,10 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="submit-name"
3
+
4
+ Larry
5
+ --AaB03x
6
+ Content-Disposition: form-data; name="files"; filename="file1.txt"
7
+ Content-Type: text/plain
8
+
9
+
10
+ --AaB03x--
@@ -0,0 +1,6 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="files"; filename="C:\Documents and Settings\Administrator\Desktop\file1.txt"
3
+ Content-Type: text/plain
4
+
5
+ contents
6
+ --AaB03x--
@@ -0,0 +1,10 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="foo[submit-name]"
3
+
4
+ Larry
5
+ --AaB03x
6
+ Content-Disposition: form-data; name="foo[files]"; filename="file1.txt"
7
+ Content-Type: text/plain
8
+
9
+ contents
10
+ --AaB03x--
@@ -0,0 +1,9 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="submit-name"
3
+
4
+ Larry
5
+ --AaB03x
6
+ Content-Disposition: form-data; name="files"; filename=""
7
+
8
+
9
+ --AaB03x--
@@ -0,0 +1,10 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="submit-name"
3
+
4
+ Larry
5
+ --AaB03x
6
+ Content-Disposition: form-data; name="files"; filename="file1.txt"
7
+ Content-Type: text/plain
8
+
9
+ contents
10
+ --AaB03x--
@@ -35,7 +35,7 @@ context 'Rack::Auth::Basic' do
35
35
  response.should.be.a.client_error
36
36
  response.status.should.equal 401
37
37
  response.should.include 'WWW-Authenticate'
38
- response.headers['WWW-Authenticate'].should =~ /Basic realm="/
38
+ response.headers['WWW-Authenticate'].should =~ /Basic realm="#{Regexp.escape(realm)}"/
39
39
  response.body.should.be.empty
40
40
  end
41
41
 
@@ -66,4 +66,8 @@ context 'Rack::Auth::Basic' do
66
66
  end
67
67
  end
68
68
 
69
+ specify 'realm as optional constructor arg' do
70
+ app = Rack::Auth::Basic.new(unprotected_app, realm) { true }
71
+ assert_equal realm, app.realm
72
+ end
69
73
  end