Dan Janowski
12/21/2004 5:35:00 PM
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