[RFC] Form Processing

Please comment if you think this is useful, good, bad (or ugly). It is all written and partially tested, but I am interested in some feedback before I release it or if I should.

I wanted a bit more intelligence in CGI form processing. This is an effort to that end. I called it Forms, derived from the HTML entity and that it allows the representation of a Form within Ruby.

Forms is a CGI parser, value manager and validator that works with cgi-bin, mod_ruby and WEBrick (in the most efficient block handling even though the body is available is completely conflicting ways). It performs only request processing and does nothing related to response generation or handling.

Values are uniformly mapped to reduce the multi-value problems in other implementations. Each value is tagged with its source, :GET, :POST, :COOKIE. Values from all sources are combined and accessed the same way.

Validation is done by creating a form template before parsing. There are a few Input types which correspond to HTML form types and they do basic validation. Additional parsing/validation can be hooked in.

multiparts are handled in a slightly different way than other libraries, if the input is a file, then it is always put to a Tempfile, otherwise it is kept in as a regular String. There is no use of StringIO. I think this keeps expectations in line with what is being asked for in the HTML Form. File input handling only keeps a trailing block of data in memory while looking for the boundary, everything else written to the temp file.

Some other features:
a. allow_generics=true enables capture of non-predefined values, otherwise they are dropped. Generic inputs do not get input validation since there is no basis.

b. default values

c. is_set? (only true if the value came from the client)

···

------------------------------------------------
Here is a simple example for a cgi-bin:

f=Forms.new
f.allow_generics=true
p=f.input_template(Forms::Text.new('hipmo'))
p.parser=proc {|input,vsp|
   throw(:invalid) if vsp.value.empty?
   vsp.value.capitalize!
}

p=f.input_template(Forms::File.new('upfile'))
p.parser= proc {|input,vsp|
   throw(:invalid) unless vsp.respond_to?(:filename) and vsp.filename =~ /\.zip$/
}

f.parse $stdin

...
<form method=POST enctype=multipart/form-data>
<input type=text name=hipmo>
<input type=file name=upfile>
<input type=submit>
</form>

...

if f['upfile'].valid?
   puts "<pre>"+f['upfile'].content_type+"</pre>"
   puts "<pre>"+f['upfile'].filename+"</pre>"
   puts "<pre>"+f['upfile'].length.to_s+"</pre>"

   zipfile=Zip::ZipInputStream.open(f['upfile'].path)
   while (ze=zipfile.get_next_entry)
     puts "<pre>"+ze.name+"</pre>"
   end
end

Hello,

this library seems interesting. I would like to have a look at the
actual implementation.

regards,
George

I have been looking for something in Ruby that would allow me to have a web user agent (a programmatic browser if you prefer) that can drive a series of Web page mostly for the purpose of doing testing of a Web based application.

it looks like what you have done can help in this respect by allowing me to receive froms from the server and manipulate them as form objects then post the reply to the server.

Am I correct?

Laurent