ruby picture

RCR 67: unify cgi handling of normal and multipart forms

Submitted by patsplat (Thu Mar 14 22:03:54 UTC 2002)

Abstract

This is a legacy RCR from Ruby Garden, submitted by patsplat. Matz has declared these RCRs obsolete, and asked that their authors resubmit them in the new format.

Instead of making all multipart params Tempfiles, I prefer that only params with unusual content-types be affected. Everything else would remain Strings.

I don't mind using a different interface on the param where I expect a file. It's frustrating, though, to see the entire application unravel b/c an upload was added to one form.

A wrapper for cgi which does this is at:

> rb

If this is approved, I will write a patch for cgi.rb which provides this behavior.

Problem

(RCR imported from old format)

Proposal

Analysis

(RCR imported from old format)

Implementation

(RCR imported from old format)
ruby picture
Comments Current voting

Multi-Part and Files (, 2002-03-16 13:41:28)

The Ruby CGI library as it stands creates a lot of files for multi-part forms.
Creating temporary files for all the parts of a multi-part encoded form is pure silliness.

If there is some reason "it must be done" then at least you could only do it only for "large" objects.

Oh and they are "Tempfile" not "File" leading to issues when passed to libraries such as Ruby/GD.

cure for silliness and the blues.... (patsplat, 2002-03-16 23:14:16)

I agree that it's pretty silly to have tempfile objects for every parameter. It makes sense for uploaded files to be made into Tempfiles, but not much else. I got bothered the most, though, by the interface change.

My patch to don't create a temp file for each cgi parameter (, 2002-05-10 03:26:11)

Bellow is a patch against ruby 1.6.7 cgi.rb that doesn't create a temp file for each parameter on multi/part form data.

I contains a modification to escape_url as well because I got some strange results with the original one.

It as well disable SimpleDelegator from Cookie Class because it slow down the cookie processing specially when using session.

The session diff against ruby 1.6.7 cgi/session as well follows it try to modify session to don't rely on SimpleDelegator.

In fact I don't know exact if there is unwanted side efects for session what I know is that it was working for me and a lot faster tha before.
Before open a session was consuming 40ms and now around 5ms.

Any question send to me at domingo@dad-it.com

cgi.diff start




---
6a7,8
> Version 2.1.4
>
170,172c172,174
   CGI.new("html4")    # html4.0 (Strict)<br />
> CGI.new("html4Tr") # html4.0 Transitional
> CGI.new("html4Fr") # html4.0 Frameset
186c188,192
   VERSION = '2.1.4'<br />
> RELEASE_DATE = '2001-04-18'
> VERSION_CODE = 214
> RELEASE_CODE = 20010418
> REVISION = '$Id: cgi.rb.dad,v 1.1 2001/09/04 10:35:56 mingo Exp $'
238,240c244,247
     string.gsub(/[^a-zA-Z0-9_-.]/n){ sprintf("%%%02X", $&amp;.unpack("C")[0]) }<br />
> # string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
> # '%' + $1.unpack('H2' * $1.size).join('%').upcase
> # end.tr(' ', '+')
249,251c256,259
     string.gsub(/+/, ' ').gsub(/%([0-9a-fA-F]{2})/){ [$1.hex].pack("c") }<br />
> # string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do
> # [$1.delete('%')].pack('H*')
> # end
408,409c416
     if options.kind_of?(String)<br />
411,412d417
       options["type"].concat( "; charset=" )<br />
> options["type"].concat( options.delete("charset") )
425,428c431,439
       buf.concat( (env_table["SERVER_PROTOCOL"] or "HTTP/1.0")  + " " )<br />
> buf.concat( (HTTP_STATUS[options["status"]] or
> options["status"] or
> "200 OK"
> ) + EOL
> )
> buf.concat(
> "Date: " + CGI::rfc1123_date(Time.now) + EOL
> )
442,443c453,454
       status = (HTTP_STATUS[options["status"]] or options["status"])<br />
> buf.concat("Status: " + status + EOL)
448c459
       buf.concat("Server: " + options.delete("server") + EOL)<br />
452c463
       buf.concat("Connection: " + options.delete("connection") + EOL)<br />
455c466
     buf.concat("Content-Type: " + options.delete("type") + EOL)<br />
458c469
       buf.concat("Content-Length: " + options.delete("length").to_s + EOL)<br />
462c473
       buf.concat("Content-Language: " + options.delete("language") + EOL)<br />
466c477
       buf.concat("Expires: " + CGI::rfc1123_date( options.delete("expires") ) + EOL)<br />
472c483
         buf.concat("Set-Cookie: " + options.delete("cookie").to_s + EOL)<br />
475c486
           buf.concat("Set-Cookie: " + cookie.to_s + EOL)<br />
479c490
           buf.concat("Set-Cookie: " + cookie.to_s + EOL)<br />
485c496
         buf.concat("Set-Cookie: " + cookie.to_s + EOL)<br />
490c501
       buf.concat(key + ": " + value + EOL)<br />
502d512
   class Cookie #       #super(@value)<br />
661c668
       buf.concat(@name + '=')<br />
664c671
         buf.concat CGI::escape(@value)<br />
666c673
         buf.concat(@value.collect{|v| CGI::escape(v) }.join("&amp;"))<br />
670c677
         buf.concat('; domain=' + @domain)<br />
674c681
         buf.concat('; path=' + @path)<br />
678c685
         buf.concat('; expires=' + CGI::rfc1123_date(@expires))<br />
682c689
         buf.concat('; secure')<br />
705c712,714
       if cookies.has_key?(name)<br />
> cookies[name].value.push(*values)
> else
737a747
> eval_methods = ''
739c749
       eval_methods        eval_methods      eval(eval_methods)<br />
>
799,800c811,812
   bodyvar = ''<br />
> isFile = false
813c825
       bodyvar += buf[0 ... (buf.size - (EOL + boundary + EOL).size)]<br />
822c834
           buf.concat c<br />
828c840
     bodyvar += $1<br />
835,841d846
   if $1 &amp;&amp; (bodyvar.size&amp;gt; 0) # Only create a temp file if necessary<br />
> isFile = true
> body = Tempfile.new("CGI")
> body.binmode
> body.print bodyvar
>
> body.rewind
>
> eval def body.local_path
> #{body.path.dump}
> 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 def body.content_type
> #{($1 or "").dump.untaint}.taint
> end
> END
> end
866c883
   /Content-Disposition:.* name="?([^";]*)"?/ni.match(head)<br />
870c887
           isFile ? params[name].push(body) : params[name].push(bodyvar)<br />
872c889
           isFile ? params[name] = [body] : params[name] = [bodyvar]<br />
1270c1287
         body.concat hidden<br />
1344c1361
           buf.concat( attributes.delete("DOCTYPE") )<br />
1349c1366
         buf.concat( doctype )<br />
1353c1370
         buf.concat( super(attributes){ yield } )<br />
1355c1372
         buf.concat( super(attributes) )<br />
1734c1751
         methods.concat(          methods.concat(          methods.concat(          methods.concat(          methods.concat(          methods.concat(          methods.concat(          methods.concat(          methods.concat(        extend TagMaker<br />
> extend Html4Tr
> element_init()
1870c1890
         methods.concat(          methods.concat(        eval "CGI_PARAMS  = @params.nil?  ? nil : @params.dup<br />
> CGI_COOKIES = @cookies.nil? ? nil : @cookies.dup"
1918,1919d1937
       md5.hexdigest[0,32]<br />
40c40,45
     #id, = request.cookies[session_key]<br />
> begin
> id = request.cookies[session_key].value[0]
> rescue Exception
> id = nil
> end
session.diff end




---

Re: unify cgi handling of normal and multipart forms (patsplat, 2002-09-12 17:39:30)

so now I've rolled this change, and others into:

>


Strongly opposed 0
Opposed 0
Neutral 0
In favor 0
Strongly advocate 0
ruby picture
If you have registered at RCRchive, you may now sign in below. If you have not registered, you may sign up for a username and password. Registering enables you to submit new RCRs, and vote and leave comments on existing RCRs.
Your username:
Your password:

ruby picture

Powered by .