From: domingo@... (Domingo Alvarez Duarte) Date: 2001-08-14T07:27:24+09:00 Subject: [ruby-talk:19664] No more temp files for each non_empty_file_field in multipart/form-dad forms I'm working with ruby recently and want adopt it as my favority development language and using the cgi module I've noted that when it process a "multipart/form-data" it creates a tmp file for each of the form fields and in my system (suse linux 7.1 apache 1.3.20 mod_ruby) the temp files remain after template processing, and in "cgi/session" the files used for the session aren't unlocked and I've got some headaches with that (frozen browser requests), I did some work on that modules and create a patch against it. with this modifications only if a file is sent it stores a tmp file object in the cgi.params if not it stores a string, so no more need to use cgi['some_non_empty_file_field'][0].read. cut here ---------------------- Index: lib/cgi.rb =================================================================== RCS file: /src/ruby/lib/cgi.rb,v retrieving revision 1.29 diff -u -r1.29 cgi.rb --- lib/cgi.rb 2001/04/17 19:43:27 1.29 +++ lib/cgi.rb 2001/08/13 21:54:58 @@ -189,7 +189,7 @@ RELEASE_DATE = '2001-04-18' VERSION_CODE = 214 RELEASE_CODE = 20010418 - REVISION = '$Id: cgi.rb,v 1.29 2001/04/17 19:43:27 wakou Exp $' + REVISION = '$Id: cgi.rb,v 1.23.2.5 2001/04/17 19:41:49 wakou Exp $' NEEDS_BINMODE = true if /WIN/ni.match(RUBY_PLATFORM) PATH_SEPARATOR = {'UNIX'=>'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'} @@ -241,9 +241,10 @@ url_encoded_string = CGI::escape("string") =end def CGI::escape(string) - string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do - '%' + $1.unpack('H2' * $1.size).join('%').upcase - end.tr(' ', '+') + string.gsub(/[^a-zA-Z0-9_\-.]/n){ sprintf("%%%02X", $&.unpack("C")[0]) } +# string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do +# '%' + $1.unpack('H2' * $1.size).join('%').upcase +# end.tr(' ', '+') end @@ -252,9 +253,10 @@ string = CGI::unescape("url encoded string") =end def CGI::unescape(string) - string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do - [$1.delete('%')].pack('H*') - end + string.gsub(/\+/, ' ').gsub(/%([0-9a-fA-F]{2})/){ [$1.hex].pack("c") } +# string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do +# [$1.delete('%')].pack('H*') +# end end @@ -803,8 +805,8 @@ until -1 == content_length head = nil - body = Tempfile.new("CGI") - body.binmode + bodyvar = '' + isFile = false until head and /#{boundary}(?:#{EOL}|--)/n.match(buf) @@ -817,7 +819,7 @@ end if head and ( (EOL + boundary + EOL).size < buf.size ) - body.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)] + bodyvar += buf[0 ... (buf.size - (EOL + boundary + EOL).size)] buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = "" end @@ -832,51 +834,59 @@ end buf = buf.sub(/\A((?:.|\n)*?)(?:#{EOL})?#{boundary}(#{EOL}|--)/n) do - body.print $1 + bodyvar += $1 if "--" == $2 content_length = -1 end "" end - body.rewind - - eval <<-END - def body.local_path - #{body.path.dump} - end - END /Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head) - eval <<-END - def body.original_filename - #{ - filename = ($1 or "").dup - if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and - /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and - (not /MSIE/ni.match(env_table['HTTP_USER_AGENT'])) - CGI::unescape(filename) - else - filename - end.dump.untaint - }.taint - end - END - - /Content-Type: (.*)/ni.match(head) - eval <<-END - def body.content_type - #{($1 or "").dump.untaint}.taint - end - END + if $1 && (bodyvar.size > 0) # Only create a temp file if necessary + isFile = true + body = Tempfile.new("CGI") + body.binmode + body.print bodyvar + + body.rewind + + eval <<-END + def body.local_path + #{body.path.dump} + end + END + + eval <<-END + def body.original_filename + #{ + filename = ($1 or "").dup + if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and + /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and + (not /MSIE/ni.match(env_table['HTTP_USER_AGENT'])) + CGI::unescape(filename) + else + filename + end.dump.untaint + }.taint + end + END + + /Content-Type: (.*)/ni.match(head) + eval <<-END + def body.content_type + #{($1 or "").dump.untaint}.taint + end + END + end - /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head) + /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head) name = $1.dup if paramscvs server: Diffing lib/cgi ..has_key?(name) - params[name].push(body) + isFile ? params[name].push(body) : params[name].push(bodyvar) else - params[name] = [body] + isFile ? params[name] = [body] : params[name] = [bodyvar] end end Index: lib/cgi/session.rb =================================================================== RCS file: /src/ruby/lib/cgi/session.rb,v retrieving revision 1.13 diff -u -r1.13 session.rb --- lib/cgi/session.rb 2001/08/06 03:05:21 1.13 +++ lib/cgi/session.rb 2001/08/13 21:54:58 @@ -147,11 +147,13 @@ def close return if @f.closed? update + @f.flock File::LOCK_UN @f.close end def delete path = @f.path + @f.flock File::LOCK_UN @f.close File::unlink path end