qoobaa-rack 1.0.0.1

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.
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