qoobaa-rack 1.0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/COPYING +18 -0
  2. data/KNOWN-ISSUES +18 -0
  3. data/RDOX +0 -0
  4. data/README +353 -0
  5. data/Rakefile +164 -0
  6. data/SPEC +164 -0
  7. data/bin/rackup +176 -0
  8. data/contrib/rack_logo.svg +111 -0
  9. data/example/lobster.ru +4 -0
  10. data/example/protectedlobster.rb +14 -0
  11. data/example/protectedlobster.ru +8 -0
  12. data/lib/rack/adapter/camping.rb +22 -0
  13. data/lib/rack/auth/abstract/handler.rb +37 -0
  14. data/lib/rack/auth/abstract/request.rb +37 -0
  15. data/lib/rack/auth/basic.rb +58 -0
  16. data/lib/rack/auth/digest/md5.rb +124 -0
  17. data/lib/rack/auth/digest/nonce.rb +51 -0
  18. data/lib/rack/auth/digest/params.rb +55 -0
  19. data/lib/rack/auth/digest/request.rb +40 -0
  20. data/lib/rack/auth/openid.rb +487 -0
  21. data/lib/rack/builder.rb +63 -0
  22. data/lib/rack/cascade.rb +41 -0
  23. data/lib/rack/chunked.rb +49 -0
  24. data/lib/rack/commonlogger.rb +52 -0
  25. data/lib/rack/conditionalget.rb +47 -0
  26. data/lib/rack/content_length.rb +29 -0
  27. data/lib/rack/content_type.rb +23 -0
  28. data/lib/rack/deflater.rb +96 -0
  29. data/lib/rack/directory.rb +153 -0
  30. data/lib/rack/file.rb +88 -0
  31. data/lib/rack/handler/cgi.rb +61 -0
  32. data/lib/rack/handler/evented_mongrel.rb +8 -0
  33. data/lib/rack/handler/fastcgi.rb +88 -0
  34. data/lib/rack/handler/lsws.rb +60 -0
  35. data/lib/rack/handler/mongrel.rb +87 -0
  36. data/lib/rack/handler/scgi.rb +62 -0
  37. data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
  38. data/lib/rack/handler/thin.rb +18 -0
  39. data/lib/rack/handler/webrick.rb +71 -0
  40. data/lib/rack/handler.rb +69 -0
  41. data/lib/rack/head.rb +19 -0
  42. data/lib/rack/lint.rb +546 -0
  43. data/lib/rack/lobster.rb +65 -0
  44. data/lib/rack/lock.rb +16 -0
  45. data/lib/rack/methodoverride.rb +27 -0
  46. data/lib/rack/mime.rb +204 -0
  47. data/lib/rack/mock.rb +187 -0
  48. data/lib/rack/recursive.rb +57 -0
  49. data/lib/rack/reloader.rb +107 -0
  50. data/lib/rack/request.rb +248 -0
  51. data/lib/rack/response.rb +183 -0
  52. data/lib/rack/rewindable_input.rb +100 -0
  53. data/lib/rack/session/abstract/id.rb +142 -0
  54. data/lib/rack/session/cookie.rb +91 -0
  55. data/lib/rack/session/memcache.rb +109 -0
  56. data/lib/rack/session/pool.rb +100 -0
  57. data/lib/rack/showexceptions.rb +349 -0
  58. data/lib/rack/showstatus.rb +106 -0
  59. data/lib/rack/static.rb +38 -0
  60. data/lib/rack/urlmap.rb +55 -0
  61. data/lib/rack/utils.rb +528 -0
  62. data/lib/rack.rb +90 -0
  63. data/rack.gemspec +60 -0
  64. data/test/cgi/lighttpd.conf +20 -0
  65. data/test/cgi/test +9 -0
  66. data/test/cgi/test.fcgi +8 -0
  67. data/test/cgi/test.ru +7 -0
  68. data/test/multipart/binary +0 -0
  69. data/test/multipart/empty +10 -0
  70. data/test/multipart/file1.txt +1 -0
  71. data/test/multipart/ie +6 -0
  72. data/test/multipart/nested +10 -0
  73. data/test/multipart/none +9 -0
  74. data/test/multipart/text +10 -0
  75. data/test/spec_rack_auth_basic.rb +73 -0
  76. data/test/spec_rack_auth_digest.rb +226 -0
  77. data/test/spec_rack_auth_openid.rb +84 -0
  78. data/test/spec_rack_builder.rb +84 -0
  79. data/test/spec_rack_camping.rb +51 -0
  80. data/test/spec_rack_cascade.rb +48 -0
  81. data/test/spec_rack_cgi.rb +89 -0
  82. data/test/spec_rack_chunked.rb +62 -0
  83. data/test/spec_rack_commonlogger.rb +61 -0
  84. data/test/spec_rack_conditionalget.rb +41 -0
  85. data/test/spec_rack_content_length.rb +43 -0
  86. data/test/spec_rack_content_type.rb +30 -0
  87. data/test/spec_rack_deflater.rb +127 -0
  88. data/test/spec_rack_directory.rb +61 -0
  89. data/test/spec_rack_fastcgi.rb +89 -0
  90. data/test/spec_rack_file.rb +75 -0
  91. data/test/spec_rack_handler.rb +43 -0
  92. data/test/spec_rack_head.rb +30 -0
  93. data/test/spec_rack_lint.rb +521 -0
  94. data/test/spec_rack_lobster.rb +45 -0
  95. data/test/spec_rack_lock.rb +38 -0
  96. data/test/spec_rack_methodoverride.rb +60 -0
  97. data/test/spec_rack_mock.rb +243 -0
  98. data/test/spec_rack_mongrel.rb +189 -0
  99. data/test/spec_rack_recursive.rb +77 -0
  100. data/test/spec_rack_request.rb +504 -0
  101. data/test/spec_rack_response.rb +218 -0
  102. data/test/spec_rack_rewindable_input.rb +118 -0
  103. data/test/spec_rack_session_cookie.rb +82 -0
  104. data/test/spec_rack_session_memcache.rb +250 -0
  105. data/test/spec_rack_session_pool.rb +172 -0
  106. data/test/spec_rack_showexceptions.rb +21 -0
  107. data/test/spec_rack_showstatus.rb +72 -0
  108. data/test/spec_rack_static.rb +37 -0
  109. data/test/spec_rack_thin.rb +91 -0
  110. data/test/spec_rack_urlmap.rb +185 -0
  111. data/test/spec_rack_utils.rb +467 -0
  112. data/test/spec_rack_webrick.rb +130 -0
  113. data/test/testrequest.rb +57 -0
  114. data/test/unregistered_handler/rack/handler/unregistered.rb +7 -0
  115. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +7 -0
  116. metadata +276 -0
data/lib/rack/utils.rb ADDED
@@ -0,0 +1,528 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ require 'set'
4
+ require 'tempfile'
5
+
6
+ module Rack
7
+ # Rack::Utils contains a grab-bag of useful methods for writing web
8
+ # applications adopted from all kinds of Ruby libraries.
9
+
10
+ module Utils
11
+ # Performs URI escaping so that you can construct proper
12
+ # query strings faster. Use this rather than the cgi.rb
13
+ # version since it's faster. (Stolen from Camping).
14
+ def escape(s)
15
+ s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
16
+ '%'+$1.unpack('H2'*$1.bytesize).join('%').upcase
17
+ }.tr(' ', '+')
18
+ end
19
+ module_function :escape
20
+
21
+ # Unescapes a URI escaped string. (Stolen from Camping).
22
+ def unescape(s)
23
+ s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
24
+ [$1.delete('%')].pack('H*')
25
+ }
26
+ end
27
+ module_function :unescape
28
+
29
+ DEFAULT_SEP = /[&;] */n
30
+
31
+ # Stolen from Mongrel, with some small modifications:
32
+ # Parses a query string by breaking it up at the '&'
33
+ # and ';' characters. You can also use this to parse
34
+ # cookies by changing the characters used in the second
35
+ # parameter (which defaults to '&;').
36
+ def parse_query(qs, d = nil)
37
+ params = {}
38
+
39
+ (qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
40
+ k, v = p.split('=', 2).map { |x| unescape(x) }
41
+
42
+ if cur = params[k]
43
+ if cur.class == Array
44
+ params[k] << v
45
+ else
46
+ params[k] = [cur, v]
47
+ end
48
+ else
49
+ params[k] = v
50
+ end
51
+ end
52
+
53
+ return params
54
+ end
55
+ module_function :parse_query
56
+
57
+ def parse_nested_query(qs, d = nil)
58
+ params = {}
59
+
60
+ (qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
61
+ k, v = unescape(p).split('=', 2)
62
+ normalize_params(params, k, v)
63
+ end
64
+
65
+ return params
66
+ end
67
+ module_function :parse_nested_query
68
+
69
+ def normalize_params(params, name, v = nil)
70
+ name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
71
+ k = $1 || ''
72
+ after = $' || ''
73
+
74
+ return if k.empty?
75
+
76
+ if after == ""
77
+ params[k] = v
78
+ elsif after == "[]"
79
+ params[k] ||= []
80
+ raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
81
+ params[k] << v
82
+ elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
83
+ child_key = $1
84
+ params[k] ||= []
85
+ raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
86
+ if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key)
87
+ normalize_params(params[k].last, child_key, v)
88
+ else
89
+ params[k] << normalize_params({}, child_key, v)
90
+ end
91
+ else
92
+ params[k] ||= {}
93
+ raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash)
94
+ params[k] = normalize_params(params[k], after, v)
95
+ end
96
+
97
+ return params
98
+ end
99
+ module_function :normalize_params
100
+
101
+ def build_query(params)
102
+ params.map { |k, v|
103
+ if v.class == Array
104
+ build_query(v.map { |x| [k, x] })
105
+ else
106
+ "#{escape(k)}=#{escape(v)}"
107
+ end
108
+ }.join("&")
109
+ end
110
+ module_function :build_query
111
+
112
+ def build_nested_query(value, prefix = nil)
113
+ case value
114
+ when Array
115
+ value.map { |v|
116
+ build_nested_query(v, "#{prefix}[]")
117
+ }.join("&")
118
+ when Hash
119
+ value.map { |k, v|
120
+ build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
121
+ }.join("&")
122
+ when String
123
+ raise ArgumentError, "value must be a Hash" if prefix.nil?
124
+ "#{prefix}=#{escape(value)}"
125
+ else
126
+ prefix
127
+ end
128
+ end
129
+ module_function :build_nested_query
130
+
131
+ # Escape ampersands, brackets and quotes to their HTML/XML entities.
132
+ def escape_html(string)
133
+ string.to_s.gsub("&", "&amp;").
134
+ gsub("<", "&lt;").
135
+ gsub(">", "&gt;").
136
+ gsub("'", "&#39;").
137
+ gsub('"', "&quot;")
138
+ end
139
+ module_function :escape_html
140
+
141
+ def select_best_encoding(available_encodings, accept_encoding)
142
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
143
+
144
+ expanded_accept_encoding =
145
+ accept_encoding.map { |m, q|
146
+ if m == "*"
147
+ (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] }
148
+ else
149
+ [[m, q]]
150
+ end
151
+ }.inject([]) { |mem, list|
152
+ mem + list
153
+ }
154
+
155
+ encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m }
156
+
157
+ unless encoding_candidates.include?("identity")
158
+ encoding_candidates.push("identity")
159
+ end
160
+
161
+ expanded_accept_encoding.find_all { |m, q|
162
+ q == 0.0
163
+ }.each { |m, _|
164
+ encoding_candidates.delete(m)
165
+ }
166
+
167
+ return (encoding_candidates & available_encodings)[0]
168
+ end
169
+ module_function :select_best_encoding
170
+
171
+ # Return the bytesize of String; uses String#length under Ruby 1.8 and
172
+ # String#bytesize under 1.9.
173
+ if ''.respond_to?(:bytesize)
174
+ def bytesize(string)
175
+ string.bytesize
176
+ end
177
+ else
178
+ def bytesize(string)
179
+ string.bytesize
180
+ end
181
+ end
182
+ module_function :bytesize
183
+
184
+ # Context allows the use of a compatible middleware at different points
185
+ # in a request handling stack. A compatible middleware must define
186
+ # #context which should take the arguments env and app. The first of which
187
+ # would be the request environment. The second of which would be the rack
188
+ # application that the request would be forwarded to.
189
+ class Context
190
+ attr_reader :for, :app
191
+
192
+ def initialize(app_f, app_r)
193
+ raise 'running context does not respond to #context' unless app_f.respond_to? :context
194
+ @for, @app = app_f, app_r
195
+ end
196
+
197
+ def call(env)
198
+ @for.context(env, @app)
199
+ end
200
+
201
+ def recontext(app)
202
+ self.class.new(@for, app)
203
+ end
204
+
205
+ def context(env, app=@app)
206
+ recontext(app).call(env)
207
+ end
208
+ end
209
+
210
+ # A case-insensitive Hash that preserves the original case of a
211
+ # header when set.
212
+ class HeaderHash < Hash
213
+ def initialize(hash={})
214
+ super()
215
+ @names = {}
216
+ hash.each { |k, v| self[k] = v }
217
+ end
218
+
219
+ def to_hash
220
+ inject({}) do |hash, (k,v)|
221
+ if v.respond_to? :to_ary
222
+ hash[k] = v.to_ary.join("\n")
223
+ else
224
+ hash[k] = v
225
+ end
226
+ hash
227
+ end
228
+ end
229
+
230
+ def [](k)
231
+ super(@names[k] ||= @names[k.downcase])
232
+ end
233
+
234
+ def []=(k, v)
235
+ delete k
236
+ @names[k] = @names[k.downcase] = k
237
+ super k, v
238
+ end
239
+
240
+ def delete(k)
241
+ canonical = k.downcase
242
+ result = super @names.delete(canonical)
243
+ @names.delete_if { |name,| name.downcase == canonical }
244
+ result
245
+ end
246
+
247
+ def include?(k)
248
+ @names.include?(k) || @names.include?(k.downcase)
249
+ end
250
+
251
+ alias_method :has_key?, :include?
252
+ alias_method :member?, :include?
253
+ alias_method :key?, :include?
254
+
255
+ def merge!(other)
256
+ other.each { |k, v| self[k] = v }
257
+ self
258
+ end
259
+
260
+ def merge(other)
261
+ hash = dup
262
+ hash.merge! other
263
+ end
264
+
265
+ def replace(other)
266
+ clear
267
+ other.each { |k, v| self[k] = v }
268
+ self
269
+ end
270
+ end
271
+
272
+ # Every standard HTTP code mapped to the appropriate message.
273
+ # Stolen from Mongrel.
274
+ HTTP_STATUS_CODES = {
275
+ 100 => 'Continue',
276
+ 101 => 'Switching Protocols',
277
+ 200 => 'OK',
278
+ 201 => 'Created',
279
+ 202 => 'Accepted',
280
+ 203 => 'Non-Authoritative Information',
281
+ 204 => 'No Content',
282
+ 205 => 'Reset Content',
283
+ 206 => 'Partial Content',
284
+ 300 => 'Multiple Choices',
285
+ 301 => 'Moved Permanently',
286
+ 302 => 'Found',
287
+ 303 => 'See Other',
288
+ 304 => 'Not Modified',
289
+ 305 => 'Use Proxy',
290
+ 307 => 'Temporary Redirect',
291
+ 400 => 'Bad Request',
292
+ 401 => 'Unauthorized',
293
+ 402 => 'Payment Required',
294
+ 403 => 'Forbidden',
295
+ 404 => 'Not Found',
296
+ 405 => 'Method Not Allowed',
297
+ 406 => 'Not Acceptable',
298
+ 407 => 'Proxy Authentication Required',
299
+ 408 => 'Request Timeout',
300
+ 409 => 'Conflict',
301
+ 410 => 'Gone',
302
+ 411 => 'Length Required',
303
+ 412 => 'Precondition Failed',
304
+ 413 => 'Request Entity Too Large',
305
+ 414 => 'Request-URI Too Large',
306
+ 415 => 'Unsupported Media Type',
307
+ 416 => 'Requested Range Not Satisfiable',
308
+ 417 => 'Expectation Failed',
309
+ 500 => 'Internal Server Error',
310
+ 501 => 'Not Implemented',
311
+ 502 => 'Bad Gateway',
312
+ 503 => 'Service Unavailable',
313
+ 504 => 'Gateway Timeout',
314
+ 505 => 'HTTP Version Not Supported'
315
+ }
316
+
317
+ # Responses with HTTP status codes that should not have an entity body
318
+ STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 304)
319
+
320
+ # A multipart form data parser, adapted from IOWA.
321
+ #
322
+ # Usually, Rack::Request#POST takes care of calling this.
323
+
324
+ module Multipart
325
+ class UploadedFile
326
+ # The filename, *not* including the path, of the "uploaded" file
327
+ attr_reader :original_filename
328
+
329
+ # The content type of the "uploaded" file
330
+ attr_accessor :content_type
331
+
332
+ def initialize(path, content_type = "text/plain", binary = false)
333
+ raise "#{path} file does not exist" unless ::File.exist?(path)
334
+ @content_type = content_type
335
+ @original_filename = ::File.basename(path)
336
+ @tempfile = Tempfile.new(@original_filename)
337
+ @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
338
+ @tempfile.binmode if binary
339
+ FileUtils.copy_file(path, @tempfile.path)
340
+ end
341
+
342
+ def path
343
+ @tempfile.path
344
+ end
345
+ alias_method :local_path, :path
346
+
347
+ def method_missing(method_name, *args, &block) #:nodoc:
348
+ @tempfile.__send__(method_name, *args, &block)
349
+ end
350
+ end
351
+
352
+ EOL = "\r\n"
353
+ MULTIPART_BOUNDARY = "AaB03x"
354
+
355
+ def self.parse_multipart(env)
356
+ unless env['CONTENT_TYPE'] =~
357
+ %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n
358
+ nil
359
+ else
360
+ boundary = "--#{$1}"
361
+
362
+ params = {}
363
+ buf = ""
364
+ content_length = env['CONTENT_LENGTH'].to_i
365
+ input = env['rack.input']
366
+ input.rewind
367
+
368
+ boundary_size = Utils.bytesize(boundary) + EOL.bytesize
369
+ bufsize = 16384
370
+
371
+ content_length -= boundary_size
372
+
373
+ read_buffer = ''
374
+
375
+ status = input.read(boundary_size, read_buffer)
376
+ raise EOFError, "bad content body" unless status == boundary + EOL
377
+
378
+ rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n
379
+
380
+ loop {
381
+ head = nil
382
+ body = ''
383
+ filename = content_type = name = nil
384
+
385
+ until head && buf =~ rx
386
+ if !head && i = buf.index(EOL+EOL)
387
+ head = buf.slice!(0, i+2) # First \r\n
388
+ buf.slice!(0, 2) # Second \r\n
389
+
390
+ filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1]
391
+ content_type = head[/Content-Type: (.*)#{EOL}/ni, 1]
392
+ name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1]
393
+
394
+ if content_type || filename
395
+ body = Tempfile.new("RackMultipart")
396
+ body.binmode if body.respond_to?(:binmode)
397
+ end
398
+
399
+ next
400
+ end
401
+
402
+ # Save the read body part.
403
+ if head && (boundary_size+4 < buf.bytesize)
404
+ body << buf.slice!(0, buf.bytesize - (boundary_size+4))
405
+ end
406
+
407
+ c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer)
408
+ raise EOFError, "bad content body" if c.nil? || c.empty?
409
+ buf << c
410
+ content_length -= c.bytesize
411
+ end
412
+
413
+ # Save the rest.
414
+ if i = buf.index(rx)
415
+ body << buf.slice!(0, i)
416
+ buf.slice!(0, boundary_size+2)
417
+
418
+ content_length = -1 if $1 == "--"
419
+ end
420
+
421
+ if filename == ""
422
+ # filename is blank which means no file has been selected
423
+ data = nil
424
+ elsif filename
425
+ body.rewind
426
+
427
+ # Take the basename of the upload's original filename.
428
+ # This handles the full Windows paths given by Internet Explorer
429
+ # (and perhaps other broken user agents) without affecting
430
+ # those which give the lone filename.
431
+ filename =~ /^(?:.*[:\\\/])?(.*)/m
432
+ filename = $1
433
+
434
+ data = {:filename => filename, :type => content_type,
435
+ :name => name, :tempfile => body, :head => head}
436
+ elsif !filename && content_type
437
+ body.rewind
438
+
439
+ # Generic multipart cases, not coming from a form
440
+ data = {:type => content_type,
441
+ :name => name, :tempfile => body, :head => head}
442
+ else
443
+ data = body
444
+ end
445
+
446
+ Utils.normalize_params(params, name, data) unless data.nil?
447
+
448
+ break if buf.empty? || content_length == -1
449
+ }
450
+
451
+ input.rewind
452
+
453
+ params
454
+ end
455
+ end
456
+
457
+ def self.build_multipart(params, first = true)
458
+ if first
459
+ unless params.is_a?(Hash)
460
+ raise ArgumentError, "value must be a Hash"
461
+ end
462
+
463
+ multipart = false
464
+ query = lambda { |value|
465
+ case value
466
+ when Array
467
+ value.each(&query)
468
+ when Hash
469
+ value.values.each(&query)
470
+ when UploadedFile
471
+ multipart = true
472
+ end
473
+ }
474
+ params.values.each(&query)
475
+ return nil unless multipart
476
+ end
477
+
478
+ flattened_params = Hash.new
479
+
480
+ params.each do |key, value|
481
+ k = first ? key.to_s : "[#{key}]"
482
+
483
+ case value
484
+ when Array
485
+ value.map { |v|
486
+ build_multipart(v, false).each { |subkey, subvalue|
487
+ flattened_params["#{k}[]#{subkey}"] = subvalue
488
+ }
489
+ }
490
+ when Hash
491
+ build_multipart(value, false).each { |subkey, subvalue|
492
+ flattened_params[k + subkey] = subvalue
493
+ }
494
+ else
495
+ flattened_params[k] = value
496
+ end
497
+ end
498
+
499
+ if first
500
+ flattened_params.map { |name, file|
501
+ if file.respond_to?(:original_filename)
502
+ ::File.open(file.path, "rb") do |f|
503
+ f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding)
504
+ <<-EOF
505
+ --#{MULTIPART_BOUNDARY}\r
506
+ Content-Disposition: form-data; name="#{name}"; filename="#{Utils.escape(file.original_filename)}"\r
507
+ Content-Type: #{file.content_type}\r
508
+ Content-Length: #{::File.stat(file.path).size}\r
509
+ \r
510
+ #{f.read}\r
511
+ EOF
512
+ end
513
+ else
514
+ <<-EOF
515
+ --#{MULTIPART_BOUNDARY}\r
516
+ Content-Disposition: form-data; name="#{name}"\r
517
+ \r
518
+ #{file}\r
519
+ EOF
520
+ end
521
+ }.join + "--#{MULTIPART_BOUNDARY}--\r"
522
+ else
523
+ flattened_params
524
+ end
525
+ end
526
+ end
527
+ end
528
+ end
data/lib/rack.rb ADDED
@@ -0,0 +1,90 @@
1
+ # Copyright (C) 2007, 2008, 2009 Christian Neukirchen <purl.org/net/chneukirchen>
2
+ #
3
+ # Rack is freely distributable under the terms of an MIT-style license.
4
+ # See COPYING or http://www.opensource.org/licenses/mit-license.php.
5
+
6
+ path = File.expand_path(File.dirname(__FILE__))
7
+ $:.unshift(path) unless $:.include?(path)
8
+
9
+
10
+ # The Rack main module, serving as a namespace for all core Rack
11
+ # modules and classes.
12
+ #
13
+ # All modules meant for use in your application are <tt>autoload</tt>ed here,
14
+ # so it should be enough just to <tt>require rack.rb</tt> in your code.
15
+
16
+ module Rack
17
+ # The Rack protocol version number implemented.
18
+ VERSION = [1,0]
19
+
20
+ # Return the Rack protocol version as a dotted string.
21
+ def self.version
22
+ VERSION.join(".")
23
+ end
24
+
25
+ # Return the Rack release as a dotted string.
26
+ def self.release
27
+ "1.0"
28
+ end
29
+
30
+ autoload :Builder, "rack/builder"
31
+ autoload :Cascade, "rack/cascade"
32
+ autoload :Chunked, "rack/chunked"
33
+ autoload :CommonLogger, "rack/commonlogger"
34
+ autoload :ConditionalGet, "rack/conditionalget"
35
+ autoload :ContentLength, "rack/content_length"
36
+ autoload :ContentType, "rack/content_type"
37
+ autoload :File, "rack/file"
38
+ autoload :Deflater, "rack/deflater"
39
+ autoload :Directory, "rack/directory"
40
+ autoload :ForwardRequest, "rack/recursive"
41
+ autoload :Handler, "rack/handler"
42
+ autoload :Head, "rack/head"
43
+ autoload :Lint, "rack/lint"
44
+ autoload :Lock, "rack/lock"
45
+ autoload :MethodOverride, "rack/methodoverride"
46
+ autoload :Mime, "rack/mime"
47
+ autoload :Recursive, "rack/recursive"
48
+ autoload :Reloader, "rack/reloader"
49
+ autoload :ShowExceptions, "rack/showexceptions"
50
+ autoload :ShowStatus, "rack/showstatus"
51
+ autoload :Static, "rack/static"
52
+ autoload :URLMap, "rack/urlmap"
53
+ autoload :Utils, "rack/utils"
54
+
55
+ autoload :MockRequest, "rack/mock"
56
+ autoload :MockResponse, "rack/mock"
57
+
58
+ autoload :Request, "rack/request"
59
+ autoload :Response, "rack/response"
60
+
61
+ module Auth
62
+ autoload :Basic, "rack/auth/basic"
63
+ autoload :AbstractRequest, "rack/auth/abstract/request"
64
+ autoload :AbstractHandler, "rack/auth/abstract/handler"
65
+ autoload :OpenID, "rack/auth/openid"
66
+ module Digest
67
+ autoload :MD5, "rack/auth/digest/md5"
68
+ autoload :Nonce, "rack/auth/digest/nonce"
69
+ autoload :Params, "rack/auth/digest/params"
70
+ autoload :Request, "rack/auth/digest/request"
71
+ end
72
+ end
73
+
74
+ module Session
75
+ autoload :Cookie, "rack/session/cookie"
76
+ autoload :Pool, "rack/session/pool"
77
+ autoload :Memcache, "rack/session/memcache"
78
+ end
79
+
80
+ # *Adapters* connect Rack with third party web frameworks.
81
+ #
82
+ # Rack includes an adapter for Camping, see README for other
83
+ # frameworks supporting Rack in their code bases.
84
+ #
85
+ # Refer to the submodules for framework-specific calling details.
86
+
87
+ module Adapter
88
+ autoload :Camping, "rack/adapter/camping"
89
+ end
90
+ end
data/rack.gemspec ADDED
@@ -0,0 +1,60 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{rack}
5
+ s.version = "1.0.0.1"
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-07-21}
10
+ s.default_executable = %q{rackup}
11
+ s.description = %q{Rack provides minimal, modular and adaptable interface for developing
12
+ web applications in Ruby. By wrapping HTTP requests and responses in
13
+ the simplest way possible, it unifies and distills the API for web
14
+ servers, web frameworks, and software in between (the so-called
15
+ middleware) into a single method call.
16
+
17
+ Also see http://rack.rubyforge.org.
18
+ }
19
+ s.email = %q{chneukirchen@gmail.com}
20
+ s.executables = ["rackup"]
21
+ s.extra_rdoc_files = ["README", "SPEC", "RDOX", "KNOWN-ISSUES"]
22
+ 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/file1.txt", "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"]
23
+ s.homepage = %q{http://rack.rubyforge.org}
24
+ s.require_paths = ["lib"]
25
+ s.rubyforge_project = %q{rack}
26
+ s.rubygems_version = %q{1.3.4}
27
+ s.summary = %q{a modular Ruby webserver interface}
28
+ s.test_files = ["test/spec_rack_auth_openid.rb", "test/spec_rack_session_cookie.rb", "test/spec_rack_commonlogger.rb", "test/spec_rack_session_memcache.rb", "test/spec_rack_mock.rb", "test/spec_rack_deflater.rb", "test/spec_rack_directory.rb", "test/spec_rack_conditionalget.rb", "test/spec_rack_cascade.rb", "test/spec_rack_urlmap.rb", "test/spec_rack_mongrel.rb", "test/spec_rack_head.rb", "test/spec_rack_static.rb", "test/spec_rack_lint.rb", "test/spec_rack_handler.rb", "test/spec_rack_auth_basic.rb", "test/spec_rack_rewindable_input.rb", "test/spec_rack_showexceptions.rb", "test/spec_rack_thin.rb", "test/spec_rack_lock.rb", "test/spec_rack_camping.rb", "test/spec_rack_file.rb", "test/spec_rack_utils.rb", "test/spec_rack_auth_digest.rb", "test/spec_rack_webrick.rb", "test/spec_rack_chunked.rb", "test/spec_rack_fastcgi.rb", "test/spec_rack_lobster.rb", "test/spec_rack_cgi.rb", "test/spec_rack_showstatus.rb", "test/spec_rack_response.rb", "test/spec_rack_methodoverride.rb", "test/spec_rack_content_length.rb", "test/spec_rack_recursive.rb", "test/spec_rack_request.rb", "test/spec_rack_session_pool.rb", "test/spec_rack_content_type.rb", "test/spec_rack_builder.rb"]
29
+
30
+ if s.respond_to? :specification_version then
31
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
32
+ s.specification_version = 3
33
+
34
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
35
+ s.add_development_dependency(%q<test-spec>, [">= 0"])
36
+ s.add_development_dependency(%q<camping>, [">= 0"])
37
+ s.add_development_dependency(%q<fcgi>, [">= 0"])
38
+ s.add_development_dependency(%q<memcache-client>, [">= 0"])
39
+ s.add_development_dependency(%q<mongrel>, [">= 0"])
40
+ s.add_development_dependency(%q<ruby-openid>, ["~> 2.0.0"])
41
+ s.add_development_dependency(%q<thin>, [">= 0"])
42
+ else
43
+ s.add_dependency(%q<test-spec>, [">= 0"])
44
+ s.add_dependency(%q<camping>, [">= 0"])
45
+ s.add_dependency(%q<fcgi>, [">= 0"])
46
+ s.add_dependency(%q<memcache-client>, [">= 0"])
47
+ s.add_dependency(%q<mongrel>, [">= 0"])
48
+ s.add_dependency(%q<ruby-openid>, ["~> 2.0.0"])
49
+ s.add_dependency(%q<thin>, [">= 0"])
50
+ end
51
+ else
52
+ s.add_dependency(%q<test-spec>, [">= 0"])
53
+ s.add_dependency(%q<camping>, [">= 0"])
54
+ s.add_dependency(%q<fcgi>, [">= 0"])
55
+ s.add_dependency(%q<memcache-client>, [">= 0"])
56
+ s.add_dependency(%q<mongrel>, [">= 0"])
57
+ s.add_dependency(%q<ruby-openid>, ["~> 2.0.0"])
58
+ s.add_dependency(%q<thin>, [">= 0"])
59
+ end
60
+ end