actionpack 2.3.2 → 2.3.3

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

Potentially problematic release.


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

Files changed (117) hide show
  1. data/CHANGELOG +5 -0
  2. data/Rakefile +10 -9
  3. data/lib/action_controller.rb +2 -7
  4. data/lib/action_controller/assertions/response_assertions.rb +11 -3
  5. data/lib/action_controller/base.rb +7 -2
  6. data/lib/action_controller/caching.rb +1 -1
  7. data/lib/action_controller/caching/actions.rb +9 -1
  8. data/lib/action_controller/caching/sweeper.rb +45 -0
  9. data/lib/action_controller/caching/sweeping.rb +0 -42
  10. data/lib/action_controller/failsafe.rb +40 -6
  11. data/lib/action_controller/flash.rb +11 -3
  12. data/lib/action_controller/http_authentication.rb +5 -2
  13. data/lib/action_controller/integration.rb +5 -12
  14. data/lib/action_controller/middlewares.rb +0 -1
  15. data/lib/action_controller/reloader.rb +34 -3
  16. data/lib/action_controller/request.rb +6 -2
  17. data/lib/action_controller/response.rb +2 -2
  18. data/lib/action_controller/routing/route_set.rb +2 -1
  19. data/lib/action_controller/streaming.rb +1 -1
  20. data/lib/action_controller/test_process.rb +9 -1
  21. data/lib/action_pack/version.rb +1 -1
  22. data/lib/action_view/helpers.rb +1 -1
  23. data/lib/action_view/helpers/asset_tag_helper.rb +21 -9
  24. data/lib/action_view/helpers/date_helper.rb +2 -2
  25. data/lib/action_view/helpers/form_helper.rb +25 -12
  26. data/lib/action_view/helpers/form_options_helper.rb +2 -0
  27. data/lib/action_view/helpers/form_tag_helper.rb +10 -4
  28. data/lib/action_view/helpers/number_helper.rb +1 -1
  29. data/lib/action_view/helpers/prototype_helper.rb +7 -7
  30. data/lib/action_view/helpers/scriptaculous_helper.rb +5 -5
  31. data/lib/action_view/helpers/text_helper.rb +3 -3
  32. data/lib/action_view/helpers/url_helper.rb +1 -1
  33. data/lib/action_view/paths.rb +1 -1
  34. data/lib/action_view/template.rb +22 -33
  35. data/test/abstract_unit.rb +1 -1
  36. data/test/activerecord/active_record_store_test.rb +3 -3
  37. data/test/controller/action_pack_assertions_test.rb +27 -0
  38. data/test/controller/caching_test.rb +39 -0
  39. data/test/controller/cookie_test.rb +10 -0
  40. data/test/controller/dispatcher_test.rb +9 -7
  41. data/test/controller/failsafe_test.rb +60 -0
  42. data/test/controller/filter_params_test.rb +2 -1
  43. data/test/controller/flash_test.rb +6 -1
  44. data/test/controller/http_digest_authentication_test.rb +34 -3
  45. data/test/controller/integration_test.rb +31 -3
  46. data/test/controller/redirect_test.rb +4 -1
  47. data/test/controller/reloader_test.rb +97 -0
  48. data/test/controller/render_test.rb +19 -9
  49. data/test/controller/request/multipart_params_parsing_test.rb +1 -62
  50. data/test/controller/request/test_request_test.rb +35 -0
  51. data/test/controller/request/url_encoded_params_parsing_test.rb +0 -38
  52. data/test/controller/request_test.rb +218 -230
  53. data/test/controller/resources_test.rb +8 -0
  54. data/test/controller/routing_test.rb +21 -0
  55. data/test/controller/send_file_test.rb +1 -1
  56. data/test/controller/session/cookie_store_test.rb +9 -32
  57. data/test/controller/test_test.rb +8 -0
  58. data/test/fixtures/failsafe/500.html +1 -0
  59. data/test/template/active_record_helper_test.rb +1 -1
  60. data/test/template/asset_tag_helper_test.rb +46 -0
  61. data/test/template/form_helper_test.rb +117 -6
  62. data/test/template/form_options_helper_test.rb +22 -0
  63. data/test/template/form_tag_helper_test.rb +23 -6
  64. data/test/template/prototype_helper_test.rb +11 -11
  65. data/test/template/template_test.rb +32 -0
  66. metadata +20 -63
  67. data/lib/action_controller/rewindable_input.rb +0 -28
  68. data/lib/action_controller/vendor/rack-1.0/rack.rb +0 -89
  69. data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +0 -22
  70. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +0 -37
  71. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +0 -37
  72. data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +0 -58
  73. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +0 -124
  74. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +0 -51
  75. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +0 -55
  76. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +0 -40
  77. data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +0 -480
  78. data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +0 -63
  79. data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +0 -36
  80. data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +0 -49
  81. data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +0 -61
  82. data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +0 -45
  83. data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +0 -29
  84. data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +0 -23
  85. data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +0 -85
  86. data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +0 -153
  87. data/lib/action_controller/vendor/rack-1.0/rack/file.rb +0 -88
  88. data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +0 -48
  89. data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +0 -61
  90. data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +0 -8
  91. data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +0 -89
  92. data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +0 -55
  93. data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +0 -84
  94. data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +0 -59
  95. data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +0 -8
  96. data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +0 -18
  97. data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +0 -67
  98. data/lib/action_controller/vendor/rack-1.0/rack/head.rb +0 -19
  99. data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +0 -462
  100. data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +0 -65
  101. data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +0 -16
  102. data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +0 -27
  103. data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +0 -204
  104. data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +0 -160
  105. data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +0 -57
  106. data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +0 -64
  107. data/lib/action_controller/vendor/rack-1.0/rack/request.rb +0 -241
  108. data/lib/action_controller/vendor/rack-1.0/rack/response.rb +0 -179
  109. data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +0 -142
  110. data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +0 -91
  111. data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +0 -109
  112. data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +0 -100
  113. data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +0 -349
  114. data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +0 -106
  115. data/lib/action_controller/vendor/rack-1.0/rack/static.rb +0 -38
  116. data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +0 -55
  117. data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +0 -392
@@ -1,106 +0,0 @@
1
- require 'erb'
2
- require 'rack/request'
3
- require 'rack/utils'
4
-
5
- module Rack
6
- # Rack::ShowStatus catches all empty responses the app it wraps and
7
- # replaces them with a site explaining the error.
8
- #
9
- # Additional details can be put into <tt>rack.showstatus.detail</tt>
10
- # and will be shown as HTML. If such details exist, the error page
11
- # is always rendered, even if the reply was not empty.
12
-
13
- class ShowStatus
14
- def initialize(app)
15
- @app = app
16
- @template = ERB.new(TEMPLATE)
17
- end
18
-
19
- def call(env)
20
- status, headers, body = @app.call(env)
21
- headers = Utils::HeaderHash.new(headers)
22
- empty = headers['Content-Length'].to_i <= 0
23
-
24
- # client or server error, or explicit message
25
- if (status.to_i >= 400 && empty) || env["rack.showstatus.detail"]
26
- req = Rack::Request.new(env)
27
- message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s
28
- detail = env["rack.showstatus.detail"] || message
29
- body = @template.result(binding)
30
- size = Rack::Utils.bytesize(body)
31
- [status, headers.merge("Content-Type" => "text/html", "Content-Length" => size.to_s), [body]]
32
- else
33
- [status, headers, body]
34
- end
35
- end
36
-
37
- def h(obj) # :nodoc:
38
- case obj
39
- when String
40
- Utils.escape_html(obj)
41
- else
42
- Utils.escape_html(obj.inspect)
43
- end
44
- end
45
-
46
- # :stopdoc:
47
-
48
- # adapted from Django <djangoproject.com>
49
- # Copyright (c) 2005, the Lawrence Journal-World
50
- # Used under the modified BSD license:
51
- # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
52
- TEMPLATE = <<'HTML'
53
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
54
- <html lang="en">
55
- <head>
56
- <meta http-equiv="content-type" content="text/html; charset=utf-8" />
57
- <title><%=h message %> at <%=h req.script_name + req.path_info %></title>
58
- <meta name="robots" content="NONE,NOARCHIVE" />
59
- <style type="text/css">
60
- html * { padding:0; margin:0; }
61
- body * { padding:10px 20px; }
62
- body * * { padding:0; }
63
- body { font:small sans-serif; background:#eee; }
64
- body>div { border-bottom:1px solid #ddd; }
65
- h1 { font-weight:normal; margin-bottom:.4em; }
66
- h1 span { font-size:60%; color:#666; font-weight:normal; }
67
- table { border:none; border-collapse: collapse; width:100%; }
68
- td, th { vertical-align:top; padding:2px 3px; }
69
- th { width:12em; text-align:right; color:#666; padding-right:.5em; }
70
- #info { background:#f6f6f6; }
71
- #info ol { margin: 0.5em 4em; }
72
- #info ol li { font-family: monospace; }
73
- #summary { background: #ffc; }
74
- #explanation { background:#eee; border-bottom: 0px none; }
75
- </style>
76
- </head>
77
- <body>
78
- <div id="summary">
79
- <h1><%=h message %> <span>(<%= status.to_i %>)</span></h1>
80
- <table class="meta">
81
- <tr>
82
- <th>Request Method:</th>
83
- <td><%=h req.request_method %></td>
84
- </tr>
85
- <tr>
86
- <th>Request URL:</th>
87
- <td><%=h req.url %></td>
88
- </tr>
89
- </table>
90
- </div>
91
- <div id="info">
92
- <p><%= detail %></p>
93
- </div>
94
-
95
- <div id="explanation">
96
- <p>
97
- You're seeing this error because you use <code>Rack::ShowStatus</code>.
98
- </p>
99
- </div>
100
- </body>
101
- </html>
102
- HTML
103
-
104
- # :startdoc:
105
- end
106
- end
@@ -1,38 +0,0 @@
1
- module Rack
2
-
3
- # The Rack::Static middleware intercepts requests for static files
4
- # (javascript files, images, stylesheets, etc) based on the url prefixes
5
- # passed in the options, and serves them using a Rack::File object. This
6
- # allows a Rack stack to serve both static and dynamic content.
7
- #
8
- # Examples:
9
- # use Rack::Static, :urls => ["/media"]
10
- # will serve all requests beginning with /media from the "media" folder
11
- # located in the current directory (ie media/*).
12
- #
13
- # use Rack::Static, :urls => ["/css", "/images"], :root => "public"
14
- # will serve all requests beginning with /css or /images from the folder
15
- # "public" in the current directory (ie public/css/* and public/images/*)
16
-
17
- class Static
18
-
19
- def initialize(app, options={})
20
- @app = app
21
- @urls = options[:urls] || ["/favicon.ico"]
22
- root = options[:root] || Dir.pwd
23
- @file_server = Rack::File.new(root)
24
- end
25
-
26
- def call(env)
27
- path = env["PATH_INFO"]
28
- can_serve = @urls.any? { |url| path.index(url) == 0 }
29
-
30
- if can_serve
31
- @file_server.call(env)
32
- else
33
- @app.call(env)
34
- end
35
- end
36
-
37
- end
38
- end
@@ -1,55 +0,0 @@
1
- module Rack
2
- # Rack::URLMap takes a hash mapping urls or paths to apps, and
3
- # dispatches accordingly. Support for HTTP/1.1 host names exists if
4
- # the URLs start with <tt>http://</tt> or <tt>https://</tt>.
5
- #
6
- # URLMap modifies the SCRIPT_NAME and PATH_INFO such that the part
7
- # relevant for dispatch is in the SCRIPT_NAME, and the rest in the
8
- # PATH_INFO. This should be taken care of when you need to
9
- # reconstruct the URL in order to create links.
10
- #
11
- # URLMap dispatches in such a way that the longest paths are tried
12
- # first, since they are most specific.
13
-
14
- class URLMap
15
- def initialize(map = {})
16
- remap(map)
17
- end
18
-
19
- def remap(map)
20
- @mapping = map.map { |location, app|
21
- if location =~ %r{\Ahttps?://(.*?)(/.*)}
22
- host, location = $1, $2
23
- else
24
- host = nil
25
- end
26
-
27
- unless location[0] == ?/
28
- raise ArgumentError, "paths need to start with /"
29
- end
30
- location = location.chomp('/')
31
-
32
- [host, location, app]
33
- }.sort_by { |(h, l, a)| [-l.size, h.to_s.size] } # Longest path first
34
- end
35
-
36
- def call(env)
37
- path = env["PATH_INFO"].to_s.squeeze("/")
38
- script_name = env['SCRIPT_NAME']
39
- hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT')
40
- @mapping.each { |host, location, app|
41
- next unless (hHost == host || sName == host \
42
- || (host.nil? && (hHost == sName || hHost == sName+':'+sPort)))
43
- next unless location == path[0, location.size]
44
- next unless path[location.size] == nil || path[location.size] == ?/
45
-
46
- return app.call(
47
- env.merge(
48
- 'SCRIPT_NAME' => (script_name + location),
49
- 'PATH_INFO' => path[location.size..-1]))
50
- }
51
- [404, {"Content-Type" => "text/plain"}, ["Not Found: #{path}"]]
52
- end
53
- end
54
- end
55
-
@@ -1,392 +0,0 @@
1
- require 'set'
2
- require 'tempfile'
3
-
4
- module Rack
5
- # Rack::Utils contains a grab-bag of useful methods for writing web
6
- # applications adopted from all kinds of Ruby libraries.
7
-
8
- module Utils
9
- # Performs URI escaping so that you can construct proper
10
- # query strings faster. Use this rather than the cgi.rb
11
- # version since it's faster. (Stolen from Camping).
12
- def escape(s)
13
- s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
14
- '%'+$1.unpack('H2'*$1.size).join('%').upcase
15
- }.tr(' ', '+')
16
- end
17
- module_function :escape
18
-
19
- # Unescapes a URI escaped string. (Stolen from Camping).
20
- def unescape(s)
21
- s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
22
- [$1.delete('%')].pack('H*')
23
- }
24
- end
25
- module_function :unescape
26
-
27
- # Stolen from Mongrel, with some small modifications:
28
- # Parses a query string by breaking it up at the '&'
29
- # and ';' characters. You can also use this to parse
30
- # cookies by changing the characters used in the second
31
- # parameter (which defaults to '&;').
32
- def parse_query(qs, d = '&;')
33
- params = {}
34
-
35
- (qs || '').split(/[#{d}] */n).each do |p|
36
- k, v = unescape(p).split('=', 2)
37
-
38
- if cur = params[k]
39
- if cur.class == Array
40
- params[k] << v
41
- else
42
- params[k] = [cur, v]
43
- end
44
- else
45
- params[k] = v
46
- end
47
- end
48
-
49
- return params
50
- end
51
- module_function :parse_query
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 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 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
- params[k] = normalize_params(params[k], after, v)
90
- end
91
-
92
- return params
93
- end
94
- module_function :normalize_params
95
-
96
- def build_query(params)
97
- params.map { |k, v|
98
- if v.class == Array
99
- build_query(v.map { |x| [k, x] })
100
- else
101
- escape(k) + "=" + escape(v)
102
- end
103
- }.join("&")
104
- end
105
- module_function :build_query
106
-
107
- # Escape ampersands, brackets and quotes to their HTML/XML entities.
108
- def escape_html(string)
109
- string.to_s.gsub("&", "&amp;").
110
- gsub("<", "&lt;").
111
- gsub(">", "&gt;").
112
- gsub("'", "&#39;").
113
- gsub('"', "&quot;")
114
- end
115
- module_function :escape_html
116
-
117
- def select_best_encoding(available_encodings, accept_encoding)
118
- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
119
-
120
- expanded_accept_encoding =
121
- accept_encoding.map { |m, q|
122
- if m == "*"
123
- (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] }
124
- else
125
- [[m, q]]
126
- end
127
- }.inject([]) { |mem, list|
128
- mem + list
129
- }
130
-
131
- encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m }
132
-
133
- unless encoding_candidates.include?("identity")
134
- encoding_candidates.push("identity")
135
- end
136
-
137
- expanded_accept_encoding.find_all { |m, q|
138
- q == 0.0
139
- }.each { |m, _|
140
- encoding_candidates.delete(m)
141
- }
142
-
143
- return (encoding_candidates & available_encodings)[0]
144
- end
145
- module_function :select_best_encoding
146
-
147
- # Return the bytesize of String; uses String#length under Ruby 1.8 and
148
- # String#bytesize under 1.9.
149
- if ''.respond_to?(:bytesize)
150
- def bytesize(string)
151
- string.bytesize
152
- end
153
- else
154
- def bytesize(string)
155
- string.size
156
- end
157
- end
158
- module_function :bytesize
159
-
160
- # Context allows the use of a compatible middleware at different points
161
- # in a request handling stack. A compatible middleware must define
162
- # #context which should take the arguments env and app. The first of which
163
- # would be the request environment. The second of which would be the rack
164
- # application that the request would be forwarded to.
165
- class Context
166
- attr_reader :for, :app
167
-
168
- def initialize(app_f, app_r)
169
- raise 'running context does not respond to #context' unless app_f.respond_to? :context
170
- @for, @app = app_f, app_r
171
- end
172
-
173
- def call(env)
174
- @for.context(env, @app)
175
- end
176
-
177
- def recontext(app)
178
- self.class.new(@for, app)
179
- end
180
-
181
- def context(env, app=@app)
182
- recontext(app).call(env)
183
- end
184
- end
185
-
186
- # A case-insensitive Hash that preserves the original case of a
187
- # header when set.
188
- class HeaderHash < Hash
189
- def initialize(hash={})
190
- @names = {}
191
- hash.each { |k, v| self[k] = v }
192
- end
193
-
194
- def to_hash
195
- inject({}) do |hash, (k,v)|
196
- if v.respond_to? :to_ary
197
- hash[k] = v.to_ary.join("\n")
198
- else
199
- hash[k] = v
200
- end
201
- hash
202
- end
203
- end
204
-
205
- def [](k)
206
- super @names[k.downcase]
207
- end
208
-
209
- def []=(k, v)
210
- delete k
211
- @names[k.downcase] = k
212
- super k, v
213
- end
214
-
215
- def delete(k)
216
- super @names.delete(k.downcase)
217
- end
218
-
219
- def include?(k)
220
- @names.has_key? k.downcase
221
- end
222
-
223
- alias_method :has_key?, :include?
224
- alias_method :member?, :include?
225
- alias_method :key?, :include?
226
-
227
- def merge!(other)
228
- other.each { |k, v| self[k] = v }
229
- self
230
- end
231
-
232
- def merge(other)
233
- hash = dup
234
- hash.merge! other
235
- end
236
- end
237
-
238
- # Every standard HTTP code mapped to the appropriate message.
239
- # Stolen from Mongrel.
240
- HTTP_STATUS_CODES = {
241
- 100 => 'Continue',
242
- 101 => 'Switching Protocols',
243
- 200 => 'OK',
244
- 201 => 'Created',
245
- 202 => 'Accepted',
246
- 203 => 'Non-Authoritative Information',
247
- 204 => 'No Content',
248
- 205 => 'Reset Content',
249
- 206 => 'Partial Content',
250
- 300 => 'Multiple Choices',
251
- 301 => 'Moved Permanently',
252
- 302 => 'Found',
253
- 303 => 'See Other',
254
- 304 => 'Not Modified',
255
- 305 => 'Use Proxy',
256
- 307 => 'Temporary Redirect',
257
- 400 => 'Bad Request',
258
- 401 => 'Unauthorized',
259
- 402 => 'Payment Required',
260
- 403 => 'Forbidden',
261
- 404 => 'Not Found',
262
- 405 => 'Method Not Allowed',
263
- 406 => 'Not Acceptable',
264
- 407 => 'Proxy Authentication Required',
265
- 408 => 'Request Timeout',
266
- 409 => 'Conflict',
267
- 410 => 'Gone',
268
- 411 => 'Length Required',
269
- 412 => 'Precondition Failed',
270
- 413 => 'Request Entity Too Large',
271
- 414 => 'Request-URI Too Large',
272
- 415 => 'Unsupported Media Type',
273
- 416 => 'Requested Range Not Satisfiable',
274
- 417 => 'Expectation Failed',
275
- 500 => 'Internal Server Error',
276
- 501 => 'Not Implemented',
277
- 502 => 'Bad Gateway',
278
- 503 => 'Service Unavailable',
279
- 504 => 'Gateway Timeout',
280
- 505 => 'HTTP Version Not Supported'
281
- }
282
-
283
- # Responses with HTTP status codes that should not have an entity body
284
- STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 304)
285
-
286
- # A multipart form data parser, adapted from IOWA.
287
- #
288
- # Usually, Rack::Request#POST takes care of calling this.
289
-
290
- module Multipart
291
- EOL = "\r\n"
292
-
293
- def self.parse_multipart(env)
294
- unless env['CONTENT_TYPE'] =~
295
- %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n
296
- nil
297
- else
298
- boundary = "--#{$1}"
299
-
300
- params = {}
301
- buf = ""
302
- content_length = env['CONTENT_LENGTH'].to_i
303
- input = env['rack.input']
304
-
305
- boundary_size = boundary.size + EOL.size
306
- bufsize = 16384
307
-
308
- content_length -= boundary_size
309
-
310
- status = input.read(boundary_size)
311
- raise EOFError, "bad content body" unless status == boundary + EOL
312
-
313
- rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n
314
-
315
- loop {
316
- head = nil
317
- body = ''
318
- filename = content_type = name = nil
319
-
320
- until head && buf =~ rx
321
- if !head && i = buf.index("\r\n\r\n")
322
- head = buf.slice!(0, i+2) # First \r\n
323
- buf.slice!(0, 2) # Second \r\n
324
-
325
- filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1]
326
- content_type = head[/Content-Type: (.*)\r\n/ni, 1]
327
- name = head[/Content-Disposition:.* name="?([^\";]*)"?/ni, 1]
328
-
329
- if filename
330
- body = Tempfile.new("RackMultipart")
331
- body.binmode if body.respond_to?(:binmode)
332
- end
333
-
334
- next
335
- end
336
-
337
- # Save the read body part.
338
- if head && (boundary_size+4 < buf.size)
339
- body << buf.slice!(0, buf.size - (boundary_size+4))
340
- end
341
-
342
- c = input.read(bufsize < content_length ? bufsize : content_length)
343
- raise EOFError, "bad content body" if c.nil? || c.empty?
344
- buf << c
345
- content_length -= c.size
346
- end
347
-
348
- # Save the rest.
349
- if i = buf.index(rx)
350
- body << buf.slice!(0, i)
351
- buf.slice!(0, boundary_size+2)
352
-
353
- content_length = -1 if $1 == "--"
354
- end
355
-
356
- if filename == ""
357
- # filename is blank which means no file has been selected
358
- data = nil
359
- elsif filename
360
- body.rewind
361
-
362
- # Take the basename of the upload's original filename.
363
- # This handles the full Windows paths given by Internet Explorer
364
- # (and perhaps other broken user agents) without affecting
365
- # those which give the lone filename.
366
- filename =~ /^(?:.*[:\\\/])?(.*)/m
367
- filename = $1
368
-
369
- data = {:filename => filename, :type => content_type,
370
- :name => name, :tempfile => body, :head => head}
371
- else
372
- data = body
373
- end
374
-
375
- Utils.normalize_params(params, name, data) unless data.nil?
376
-
377
- break if buf.empty? || content_length == -1
378
- }
379
-
380
- begin
381
- input.rewind if input.respond_to?(:rewind)
382
- rescue Errno::ESPIPE
383
- # Handles exceptions raised by input streams that cannot be rewound
384
- # such as when using plain CGI under Apache
385
- end
386
-
387
- params
388
- end
389
- end
390
- end
391
- end
392
- end