nitro 0.23.0 → 0.24.0

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 (76) hide show
  1. data/CHANGELOG +350 -0
  2. data/INSTALL +2 -2
  3. data/ProjectInfo +61 -0
  4. data/README +5 -4
  5. data/Rakefile +5 -4
  6. data/bin/nitrogen +3 -1
  7. data/doc/AUTHORS +27 -3
  8. data/doc/RELEASES +193 -0
  9. data/doc/lhttpd.txt +4 -0
  10. data/lib/nitro.rb +1 -1
  11. data/lib/nitro/adapter/cgi.rb +6 -321
  12. data/lib/nitro/adapter/fastcgi.rb +2 -14
  13. data/lib/nitro/adapter/scgi.rb +237 -71
  14. data/lib/nitro/adapter/webrick.rb +25 -7
  15. data/lib/nitro/caching.rb +1 -0
  16. data/lib/nitro/cgi.rb +296 -0
  17. data/lib/nitro/{cookie.rb → cgi/cookie.rb} +0 -0
  18. data/lib/nitro/cgi/http.rb +62 -0
  19. data/lib/nitro/{request.rb → cgi/request.rb} +4 -1
  20. data/lib/nitro/{response.rb → cgi/response.rb} +0 -0
  21. data/lib/nitro/cgi/stream.rb +43 -0
  22. data/lib/nitro/cgi/utils.rb +38 -0
  23. data/lib/nitro/compiler.rb +23 -11
  24. data/lib/nitro/compiler/css.rb +8 -0
  25. data/lib/nitro/compiler/morphing.rb +66 -0
  26. data/lib/nitro/context.rb +21 -30
  27. data/lib/nitro/controller.rb +23 -100
  28. data/lib/nitro/dispatcher.rb +18 -8
  29. data/lib/nitro/element.rb +6 -2
  30. data/lib/nitro/flash.rb +2 -2
  31. data/lib/nitro/mixin/buffer.rb +2 -2
  32. data/lib/nitro/mixin/form.rb +204 -93
  33. data/lib/nitro/mixin/javascript.rb +170 -11
  34. data/lib/nitro/mixin/markup.rb +1 -0
  35. data/lib/nitro/mixin/pager.rb +7 -4
  36. data/lib/nitro/mixin/rss.rb +2 -0
  37. data/lib/nitro/mixin/table.rb +23 -6
  38. data/lib/nitro/mixin/xhtml.rb +2 -2
  39. data/lib/nitro/render.rb +19 -5
  40. data/lib/nitro/scaffold.rb +12 -6
  41. data/lib/nitro/server.rb +4 -6
  42. data/lib/nitro/server/runner.rb +2 -2
  43. data/lib/nitro/session.rb +8 -1
  44. data/lib/nitro/session/file.rb +40 -0
  45. data/lib/part/admin.rb +2 -0
  46. data/lib/part/admin/controller.rb +7 -3
  47. data/lib/part/admin/skin.rb +8 -1
  48. data/lib/part/admin/template/index.xhtml +39 -1
  49. data/proto/public/error.xhtml +5 -3
  50. data/proto/public/js/behaviour.js +254 -254
  51. data/proto/public/js/controls.js +427 -165
  52. data/proto/public/js/dragdrop.js +255 -276
  53. data/proto/public/js/effects.js +476 -277
  54. data/proto/public/js/prototype.js +561 -127
  55. data/proto/public/js/scaffold.js +74 -0
  56. data/proto/public/js/scriptaculous.js +44 -0
  57. data/proto/public/js/util.js +548 -0
  58. data/proto/public/scaffold/list.xhtml +4 -1
  59. data/proto/scgi.rb +333 -0
  60. data/script/scgi_ctl +221 -0
  61. data/script/scgi_service +120 -0
  62. data/test/nitro/adapter/raw_post1.bin +0 -0
  63. data/test/nitro/{tc_cookie.rb → cgi/tc_cookie.rb} +1 -1
  64. data/test/nitro/{tc_request.rb → cgi/tc_request.rb} +1 -1
  65. data/test/nitro/mixin/tc_xhtml.rb +1 -1
  66. data/test/nitro/{adapter/tc_cgi.rb → tc_cgi.rb} +12 -12
  67. data/test/nitro/tc_controller.rb +9 -5
  68. metadata +159 -169
  69. data/benchmark/bench.rb +0 -5
  70. data/benchmark/simple-webrick-n-200.txt +0 -44
  71. data/benchmark/static-webrick-n-200.txt +0 -43
  72. data/benchmark/tiny-lhttpd-n-200-c-5.txt +0 -43
  73. data/benchmark/tiny-webrick-n-200-c-5.txt +0 -44
  74. data/benchmark/tiny-webrick-n-200.txt +0 -44
  75. data/benchmark/tiny2-webrick-n-200.txt +0 -44
  76. data/examples/README +0 -7
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ Name = Release[/\D+/].sub(/\-+$/, '') || 'unknown'
10
10
  Version = Release[/[\d.]+/] || 'unknown'
11
11
 
12
12
  AuthorName, AuthorMail = 'George Moschovitis', 'gm@navel.gr'
13
- RubyVersion = '1.8.2'
13
+ RubyVersion = '1.8.3'
14
14
 
15
15
  # Description = (readme[/README\s+(.+?)\n\n/m, 1] || "unknown").gsub(/\s+/, " ")
16
16
  # Summary = Description[/^.+?>/] || "unknown"
@@ -62,10 +62,11 @@ spec = Gem::Specification.new do |s|
62
62
 
63
63
  s.add_dependency 'glue', "= #{s.version}"
64
64
  s.add_dependency 'og', "= #{s.version}"
65
- s.add_dependency 'ruby-breakpoint', '>= 0.5'
66
- s.add_dependency 'RedCloth', '>= 3.0.3'
65
+ s.add_dependency 'gen', "= #{s.version}"
66
+ s.add_dependency 'ruby-breakpoint', '= 0.5'
67
+ s.add_dependency 'RedCloth', '= 3.0.3'
67
68
 
68
- s.required_ruby_version = '>= 1.8.2'
69
+ s.required_ruby_version = '= 1.8.3'
69
70
 
70
71
  s.files = FileList[
71
72
  '[A-Z]*', 'install.rb', '{bin,benchmark,examples,doc,proto,lib,test,vendor}/**/*'
data/bin/nitrogen CHANGED
@@ -1,9 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ $NITRO_NO_ENVIRONMENT = true
4
+
3
5
  require 'nitro'
4
6
  require 'ftools'
5
7
 
6
- require 'nano/dir/recurse'
8
+ require 'nano/dir/%3A%3Arecurse'
7
9
 
8
10
  PROTO_DIR = File.join(Nitro::LibPath, '..', 'proto')
9
11
 
data/doc/AUTHORS CHANGED
@@ -3,7 +3,8 @@ MAIN DEVELOPER:
3
3
  * George Moschovitis <gm@navel.gr>
4
4
  Project leader, architecture and design, main coder,
5
5
  documentation, maintainer.
6
-
6
+
7
+
7
8
  IDEAS, ADDITIONAL CODING, SUPPORT:
8
9
 
9
10
  * Guillaume Pierronnet <guillaume.pierronnet@laposte.net>
@@ -15,22 +16,45 @@ IDEAS, ADDITIONAL CODING, SUPPORT:
15
16
  * Dan Yoder <dan@zeraweb.com>
16
17
  Original 'Elements' implementation, bug reports.
17
18
 
18
- * Anastasios Koutoumanos <ak@navel.gr>
19
- Design.
19
+ * Aleksi Niemela <Aleksi.Niemela@cs.helsinki.fi>
20
+ Bug fixes, patches, documentation.
20
21
 
22
+ * Chris Farmiloe <chris.farmiloe@farmiloe.com>
23
+ Bug fixes, Scaffolding improvements, patches.
24
+
25
+ * Rob Pitt <rob@motionpath.co.uk>
26
+ Bug fixes, Scaffolding improvements, patches.
27
+
28
+ * Zed A. Shaw <zedshaw@zedshaw.com>
29
+ SCGI adapter.
30
+
31
+ * Anastasios Koutoumanos <ak@navel.gr>
32
+ Design, bug reports.
33
+
34
+ * TRANS <transfire@gmail.com>
35
+ Small bug fixes.
36
+
21
37
  * Kostas Nasis <kostas@nasis.com>
22
38
  Ideas and bug reports.
23
39
 
40
+
24
41
  INTEGRATED LIBRARIES:
25
42
 
26
43
  Nitro integrates several open source libraries:
27
44
 
45
+ * Facets (Nano/Mega): The best collection of
46
+ Ruby extensions/utilities.
47
+ Tomas Sawyer, http://nano.rubyforge.org, http://mega.rubyforge.org
48
+
28
49
  * Prototype: Object Oriented Javascript library
29
50
  Sam Stepherson, http://www.conio.net
30
51
 
31
52
  * Script.aculo.us: Special FX Javascript library
32
53
  Thomas Fuchs, http://script.aculo.us
33
54
 
55
+ * Breakpointer
56
+
57
+
34
58
  CODE FROM OTHER PROJECTS:
35
59
 
36
60
  Occasionaly, Nitro may include code from other open source
data/doc/RELEASES CHANGED
@@ -1,3 +1,196 @@
1
+ == Version 0.24.0
2
+
3
+ A snapshot of the latest developments. This version features
4
+ tons of big and small features and bug fixes that were
5
+ implemented during the last month. Special thanks fly to
6
+ Tom, Chris, Guill, Rob, Aleksi, and all others that sent
7
+ patches and code.
8
+
9
+ Most notable additions:
10
+
11
+
12
+ * Totaly recoded annotation / property system. The property
13
+ system is now based on Facet annotations and inheritors.
14
+ You can now annotate every object, attribute or method
15
+ in Nitro. For example you can annotate your actions with
16
+ routing rules or sitemap strings etc, etc. One unified
17
+ system for annotations and metadata is used throughout
18
+ the whole Framework.
19
+
20
+ Here is an example:
21
+
22
+ class A
23
+ attr_accessor :val
24
+ ann :val, :klass => String
25
+ ann :self, :doc => 'Self annotation'
26
+ end
27
+
28
+ A.ann.val.class => String
29
+ A.ann.self.doc =>
30
+
31
+ if A.ann.val[:class]
32
+
33
+ etc, etc...
34
+
35
+ * Implemented one of the most requested features. An Og
36
+ frontend for KirbyBase. The KirbyBase store does not yet
37
+ support all features, but is really useful. For example
38
+ it can power the Spark wiki example. Switching between
39
+ KirbyBase, Mysql, Postgres, Sqlite, etc by changing
40
+ one line of code is really cool ;-)
41
+
42
+ * Better Seperation of Concerns for Og managed classes. Og
43
+ can now annotate and handle classes from other libraries.
44
+ Lets say you have the following class:
45
+
46
+ class User
47
+ attr_accessor :name
48
+ attr_accessor :body
49
+ end
50
+
51
+ Using Ruby's open classes and Nitro's advanced annotation
52
+ system you can easily prepare this class for Og management
53
+
54
+ class User
55
+ ann :user, :klass => String
56
+ ann :body, :klass => String
57
+ end
58
+
59
+ or even better:
60
+
61
+ class User
62
+ property :user, String
63
+ property :body, String
64
+ end
65
+
66
+ This style promotes SOC: You define your classes in one
67
+ place and annotate them for Og in another place.
68
+
69
+ * Introduced a simple code generation framework. Two example
70
+ generators are included:
71
+
72
+ * app: generates the directory structure for a new
73
+ nitro application.
74
+
75
+ * form: generates an xhtml form for a Ruby class.
76
+ This generator leverages the annotations of the
77
+ object class.
78
+
79
+ * Improved scaffolding code and django style auto
80
+ administration system. The new scaffolder supports all
81
+ Og relation types and provides an intuitive DHTML
82
+ interface for editing.
83
+
84
+ * SCGI (http://python.ca/nas/scgi/protocol.txt) support.
85
+ Thanks to a refactoring of Nitro's cgi code this
86
+ version integrates with Zed Shaw's SCGI adapter. This
87
+ provides FastCGI's performance with an easy
88
+ installation.
89
+
90
+ * Experimental HTTP streaming support. Here is a
91
+ simple example:
92
+
93
+ def index
94
+ response.content_type = "text/plain"
95
+ stream do
96
+ 5.times do |i|
97
+ print "#{i}"*10000 + "\n"
98
+ sleep 1
99
+ end
100
+ end
101
+ end
102
+
103
+ * Simple Og automatic evolution system. Lets say you have a class Article
104
+
105
+ class Article
106
+ property :title, String
107
+ property :nbody, String
108
+ property :dumy, Fixnum
109
+ end
110
+
111
+ lets you want to change your
112
+ class to this one:
113
+
114
+ class NewArticle
115
+ property :ntitle, String
116
+ property :nbody, String
117
+ property :new, Float
118
+ end
119
+
120
+ First you export the database:
121
+
122
+ og.export
123
+
124
+ Then you import the database. Some rules
125
+ are needed when renaming classes or properties.
126
+ New properties or deleted properties are handled
127
+ automatically.
128
+
129
+ rules = {
130
+ :Article => {
131
+ :self => :NewArticle, # rename the class
132
+ :title => :ntitle,
133
+ :body => :nbody
134
+ }
135
+ }
136
+ og.import :evolution => rules
137
+
138
+ Thats all. In a future version this will be integrated into
139
+ the default runner scripts.
140
+
141
+ * Og helpers to create simple rdbms management scripts. Here
142
+ is an example:
143
+
144
+ mysql "-u root -p", <<-END
145
+ drop database if exists weblog_development;
146
+ create database weblog_development;
147
+ grant all on weblog_development.* to #{`id -un`.strip}@localhost;
148
+ END
149
+
150
+ At the moment this is only available for Mysql.
151
+
152
+ * Added support for dynamic CSS using Nitro's advanced templating
153
+ system. Create the dynamic CSS file with an .csst extension in
154
+ your template root.
155
+
156
+ <?r
157
+ green = '#79b500'
158
+ background = '#fff'
159
+ ?>
160
+
161
+ .page {
162
+ background: #{green}
163
+
164
+ <?r 10.times do ?>
165
+ padding: 5px;
166
+ <?r end ?>
167
+
168
+ // or even
169
+
170
+ <% 3.times do %>
171
+ margin: 5px;
172
+ <% end %>
173
+ }
174
+ ..
175
+
176
+ then, add this line in run.rb:
177
+
178
+ Compiler.precompile 'style.css'
179
+
180
+ The CSS file will be regenerated automatically whenever the
181
+ template changes...
182
+
183
+ * Updated to support latest Prototype, Scriptaculous etc.
184
+
185
+ * Cleaned up Og implementation.
186
+
187
+ * Fixed minor Ruby 1.8.3 compatibility issues.
188
+
189
+ * Even better integration with Ruby Facets.
190
+
191
+ * Tons of bug fixes and small but useful features.
192
+
193
+
1
194
  == Version 0.23.0
2
195
 
3
196
  The summer vacations are over and there is a brand new Nitro
data/doc/lhttpd.txt ADDED
@@ -0,0 +1,4 @@
1
+
2
+ = Installation
3
+
4
+ ./configure --enable-rewrite
data/lib/nitro.rb CHANGED
@@ -16,7 +16,7 @@ module Nitro
16
16
 
17
17
  # The version.
18
18
 
19
- Version = '0.23.0'
19
+ Version = '0.24.0'
20
20
 
21
21
  # Library path.
22
22
 
@@ -2,30 +2,21 @@ require 'cgi'
2
2
  require 'stringio'
3
3
  require 'tempfile'
4
4
 
5
- require 'glue/attribute'
6
-
7
5
  # Speeds things up, more comaptible with OSX.
8
6
 
9
7
  Socket.do_not_reverse_lookup = true
10
8
 
11
9
  module Nitro
12
10
 
13
- class Cgi
14
- # Maximum content length allowed in requests.
15
-
16
- cattr_accessor :max_content_length, (2 * 1024 * 1024)
17
-
18
- # Multipart parsing buffer size.
19
-
20
- cattr_accessor :buffer_size, (10 * 1024)
21
-
11
+ class CgiAdapter
22
12
  #--
23
13
  # No need for connection pooling, CGI uses process.
24
14
  #++
25
15
 
26
16
  def self.start(server)
27
17
  cgi = CGI.new
28
-
18
+ CgiUtils.process(server, cgi, cgi, cgi)
19
+ =begin
29
20
  context = Context.new(server)
30
21
  context.headers = ENV
31
22
 
@@ -36,319 +27,13 @@ class Cgi
36
27
 
37
28
  cgi.print(CgiUtils.response_headers(context))
38
29
  cgi.print(context.out)
30
+ =end
39
31
  end
40
- end
41
-
42
- # CGI utility methods.
43
-
44
- class CgiUtils
45
-
46
- # HTTP protocol EOL constants
47
-
48
- CR = "\x0d"
49
- LF = "\x0a"
50
- CRLF = "\x0d\x0a"
51
- EOL = CRLF
52
-
53
- # Constants for readable code
54
-
55
- STATUS_OK = 200
56
- STATUS_PARTIAL_CONTENT = 206
57
- STATUS_MOVED = 301
58
- STATUS_REDIRECT = 302
59
- STATUS_SEE_OTHER = 303 # gmosx: VERIFY THIS
60
- STATUS_SEE_OTHER_307 = 307 # gmosx: VERIFY THIS
61
- STATUS_NOT_MODIFIED = 304
62
- STATUS_BAD_REQUEST = 400
63
- STATUS_AUTH_REQUIRED = 401
64
- STATUS_FORBIDDEN = 403
65
- STATUS_NOT_FOUND = 404
66
- STATUS_METHOD_NOT_ALLOWED = 405
67
- STATUS_NOT_ACCEPTABLE = 406
68
- STATUS_LENGTH_REQUIRED = 411
69
- STATUS_PRECONDITION_FAILED = 412
70
- STATUS_SERVER_ERROR = 500
71
- STATUS_NOT_IMPLEMENTED = 501
72
- STATUS_BAD_GATEWAY = 502
73
- STATUS_VARIANT_ALSO_VARIES = 506
74
-
75
- # Hash to allow id to description maping.
76
-
77
- STATUS_STRINGS = {
78
- 200 => "OK",
79
- 206 => "Partial Content",
80
- 300 => "Multiple Choices",
81
- 301 => "Moved Permanently",
82
- 302 => "Found",
83
- 303 => "See other", # gmosx: VERIFY THIS
84
- 304 => "Not Modified",
85
- 307 => "See other 07", # gmosx: VERIFY THIS
86
- 400 => "Bad Request",
87
- 401 => "Authorization Required",
88
- 403 => "Forbidden",
89
- 404 => "Not Found",
90
- 405 => "Method Not Allowed",
91
- 406 => "Not Acceptable",
92
- 411 => "Length Required",
93
- 412 => "Precondition Failed",
94
- 500 => "Internal Server Error",
95
- 501 => "Method Not Implemented",
96
- 502 => "Bad Gateway",
97
- 506 => "Variant Also Negotiates"
98
- }
99
-
100
- # Returns a hash with the pairs from the query
101
- # string. The implicit hash construction that is done
102
- # in parse_request_params is not done here.
103
- #
104
- # Parameters in the form xxx[] are converted
105
- # to arrays.
106
- #
107
- # Use the field.attr or field[attr] notation to pass
108
- # compound objects.
109
-
110
- def self.parse_query_string(query_string)
111
- params = {}
112
-
113
- # gmosx, THINK: better return nil here?
114
- return params if (query_string.nil? or query_string.empty?)
115
-
116
- query_string.split(/[&;]/).each do |p|
117
- key, val = p.split('=')
118
-
119
- key = CGI.unescape(key) unless key.nil?
120
- val = CGI.unescape(val) unless val.nil?
121
-
122
- if key =~ /(.*)\[\]$/
123
- # Multiple values, for example a checkbox collection.
124
- # Stored as an array.
125
- if params.has_key?($1)
126
- params[$1] << val
127
- else
128
- params[$1] = [val]
129
- end
130
- elsif key =~ /(.*)\[(.*)\]$/ or key =~ /(.*)\.(.*)$/
131
- # A compound object with attributes.
132
- # Stored as a Hash.
133
- params[$1] ||= {}
134
- params[$1][$2] = val
135
- else
136
- # Standard single valued parameter.
137
- params[key] = val.nil? ? nil : val
138
- end
139
- end
140
-
141
- return params
142
- end
143
-
144
- # Parse the HTTP_COOKIE header and returns the
145
- # cookies as a key->value hash. For efficiency no
146
- # cookie objects are created.
147
- #
148
- # [+context+]
149
- # The context
150
-
151
- def self.parse_cookies(context)
152
- env = context.env
153
-
154
- # FIXME: dont precreate?
155
- context.cookies = {}
156
-
157
- if env.has_key?('HTTP_COOKIE') or env.has_key?('COOKIE')
158
- (env['HTTP_COOKIE'] or env['COOKIE']).split(/; /).each do |c|
159
- key, val = c.split(/=/, 2)
160
-
161
- key = CGI.unescape(key)
162
- val = val.split(/&/).collect{|v| CGI::unescape(v)}.join("\0")
163
-
164
- if context.cookies.include?(key)
165
- context.cookies[key] += "\0" + val
166
- else
167
- context.cookies[key] = val
168
- end
169
- end
170
- end
171
- end
172
-
173
- # Build the response headers for the context.
174
- #
175
- # [+context+]
176
- # The context of the response.
177
- #
178
- # [+proto+]
179
- # If true emmit the protocol line. Useful for MOD_RUBY.
180
- #--
181
- # FIXME: return the correct protocol from env.
182
- # TODO: Perhaps I can optimize status calc.
183
- #++
184
-
185
- def self.response_headers(context, proto = false)
186
- reason = STATUS_STRINGS[context.status]
187
-
188
- if proto
189
- buf = "HTTP/1.1 #{context.status} #{reason}#{EOL}Date: #{CGI::rfc1123_date(Time.now)}#{EOL}"
190
- else
191
- buf = "Status: #{context.status} #{reason}#{EOL}"
192
- end
193
-
194
- context.response_headers.each do |key, value|
195
- tmp = key.gsub(/\bwww|^te$|\b\w/) { |s| s.upcase }
196
- buf << "#{tmp}: #{value}" << EOL
197
- end
198
32
 
199
- context.response_cookies.each do |cookie|
200
- buf << "Set-Cookie: " << cookie.to_s << EOL
201
- end if context.response_cookies
202
-
203
- buf << EOL
204
-
205
- return buf
206
- end
207
-
208
- # Initialize the request params.
209
- # Handles multipart forms (in particular, forms that involve
210
- # file uploads). Reads query parameters in the @params field,
211
- # and cookies into @cookies.
212
-
213
- def self.parse_params(context)
214
- method = context.method
215
- if (:post == method) and
216
- %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(context.headers['CONTENT_TYPE'])
217
- boundary = $1.dup
218
- context.params = parse_multipart(context, boundary)
219
-
220
- # Also include the URL parameters.
221
- context.params.update(CgiUtils.parse_query_string(context.query_string))
222
- else
223
- case method
224
- when :get, :head
225
- context.params = CgiUtils.parse_query_string(context.query_string)
226
- when :post
227
- context.in.binmode # if defined?(context.in.binmode)
228
- context.params = CgiUtils.parse_query_string(context.in.read(context.content_length) || '')
229
- end
230
- end
231
- end
232
-
233
- # Parse a multipart request.
234
- # Adapted from Ruby's cgi.rb
235
- #--
236
- # TODO: optimize and rationalize this.
237
- #++
238
-
239
- def self.parse_multipart(context, boundary)
240
- input = context.in
241
- content_length = context.content_length
242
- env_table = context.env
243
-
244
- params = Hash.new([])
245
- boundary = "--" + boundary
246
- buf = ""
247
-
248
- input.binmode if defined? input.binmode
249
- boundary_size = boundary.size + EOL.size
250
- content_length -= boundary_size
251
- status = input.read(boundary_size)
252
-
253
- if nil == status
254
- raise EOFError, "no content body"
255
- elsif boundary + EOL != status
256
- raise EOFError, "bad content body"
257
- end
258
-
259
- loop do
260
- head = nil
261
-
262
- if 10240 < content_length
263
- body = Tempfile.new("CGI")
264
- else
265
- begin
266
- body = StringIO.new
267
- rescue LoadError
268
- body = Tempfile.new("CGI")
269
- end
270
- end
271
- body.binmode if defined? body.binmode
272
-
273
- until head and /#{boundary}(?:#{EOL}|--)/n.match(buf)
274
-
275
- if (not head) and /#{EOL}#{EOL}/n.match(buf)
276
- buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
277
- head = $1.dup
278
- ""
279
- end
280
- next
281
- end
282
-
283
- if head and ( (EOL + boundary + EOL).size < buf.size )
284
- body.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)]
285
- buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
286
- end
287
-
288
- c = if Cgi.buffer_size < content_length
289
- input.read(Cgi.buffer_size)
290
- else
291
- input.read(content_length)
292
- end
293
- if c.nil?
294
- raise EOFError, "bad content body"
295
- end
296
- buf.concat(c)
297
- content_length -= c.size
298
- end
299
-
300
- buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{boundary}([\r\n]{1,2}|--)/n) do
301
- body.print $1
302
- if "--" == $2
303
- content_length = -1
304
- end
305
- ""
306
- end
307
-
308
- body.rewind
309
-
310
- /Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head)
311
-
312
- filename = ($1 or "")
313
-
314
- if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and
315
- /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and
316
- (not /MSIE/ni.match(env_table['HTTP_USER_AGENT']))
317
- filename = CGI::unescape(filename)
318
- end
319
-
320
- /Content-Type: (.*)/ni.match(head)
321
- content_type = ($1 or "")
322
-
323
- (class << body; self; end).class_eval do
324
- alias local_path path
325
- define_method(:original_filename) { filename.dup.taint }
326
- define_method(:content_type) { content_type.dup.taint }
327
-
328
- # gmosx: this hides the performance hit!!
329
- define_method(:to_s) { read }
330
- end
331
-
332
- /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head)
333
- name = $1.dup
334
-
335
- if params.has_key?(name)
336
- params[name] = [params[name]] << body
337
- else
338
- params[name] = body
339
- end
340
-
341
- break if buf.size == 0
342
- break if content_length === -1
343
- end
344
-
345
- return params
346
- end
347
-
348
33
  end
349
34
 
350
35
  end
351
36
 
352
- # * George Moschovitis <gm@navel.gr>
353
37
  # * James Britt <james_b@neurogami.com>
354
- # * Michael Neumann <mneumann@ntecs.de>
38
+ # * George Moschovitis <gm@navel.gr>
39
+