CGI help

So, I am trying ot read the contents of a file and format the contents
there into a CGI form. At 6PM on A friday hough, I am just not seeing
my errors - appreciate another srt of eyes!

require “cgi”

Filename = ‘classification.txt’

EMPTY_STRING = ‘’
TITLE = ‘Vulnerability Classification’
cgi = CGI.new(‘html4’)
output = cgi.html do
cgi.head { cgi.title { TITLE } } +
cgi.body { cgi.h1 { TITLE } } +
cgi.form(‘post’) do
if File.readable?(Filename) then
f = File.open(Filename,“r”)
f.each_line { |l| l.chomp
inputs = l.split(’,’)
puts inputs[0].to_s + “: "
opts = “”” + inputs[1].to_s + “”"
2.times { inputs.delete_at(0) }
until inputs.empty? do
opts = opts + “[”" + inputs[1].to_s + “”,"" +
inputs[0].to_s + “”]"
2.times { inputs.delete_at(0) }
end
cgi.popup_menu(opts) +
cgi.br +
}
f.close
end
cgi.submit
end
end
cgi.out { output.gsub(’><’, “>\n<”) }

Jeff Leggett wrote:

So, I am trying ot read the contents of a file and format the contents
there into a CGI form. At 6PM on A friday hough, I am just not seeing
my errors - appreciate another srt of eyes!

Your file may need to start with a shebang line:

#!/usr/local/bin/ruby

or whatever the path to ruby on your system is.

Also, print out the correct headers

http://www.ruby-doc.org/docs/ProgrammingRuby/html/web.html

It helps to get the simplest possible CGI script running first, then
adding details, since debugging CGI is a painful.


James B.

www.jamesbritt.com - Playing with Better Toys
www.ruby-doc.org - Ruby Help & Documentation
www.rubystuff.com - The Ruby Store for Ruby Stuff
www.neurogami.com - Smart application development

Jeff Leggett wrote:

output = cgi.html do
cgi.head { cgi.title { TITLE } } +
cgi.body { cgi.h1 { TITLE } } +
How about getting rid of…^ ?

James B. wrote:

Your file may need to start with a shebang line:

#!/usr/local/bin/ruby

Yes, it does - I just left that out of the C&P.

Also, print out the correct headers

Programming Ruby: The Pragmatic Programmer's Guide

The CGI does all that for you… My problem is if I take out the inner
loop (starting with “if File.readable?(Filename) then” it works fine. I
just can’t for the life of me see the syntax errors.

[jleggett@binford cgi-bin]$ ./vuln.rb
./vuln.rb:27: syntax error
./vuln.rb:29: syntax error
end
^
./vuln.rb:31: syntax error
end
^
./vuln.rb:37: syntax error
[jleggett@binford cgi-bin]$

         cgi.popup_menu(opts) +
         cgi.br +

You have an extraneous ‘+’ at the end of that last line. Remove it and
your
script should start working.

Cheers,
Doug Seifert

7stud – wrote:

Jeff Leggett wrote:

output = cgi.html do
cgi.head { cgi.title { TITLE } } +
cgi.body { cgi.h1 { TITLE } } +
How about getting rid of…^ ?

I changed it like that, EXACT same errors. I have matched up the ‘ends’
and bracket more times than I can count now, even slept on it, thinking
my tired brain would see it right off this morning, but no… Thanks for
your help though guys…

#!/usr/bin/ruby

require “cgi”

Filename = ‘classification.txt’

EMPTY_STRING = ‘’
TITLE = ‘Vulnerability Classification’
cgi = CGI.new(‘html4’)
output = cgi.html do
cgi.head { cgi.title { TITLE } } +
cgi.body { cgi.h1 { TITLE } +
cgi.form(‘post’) do
if File.readable?(Filename) then
f = File.open(Filename,“r”)
f.each_line { |l| l.chomp
inputs = l.split(’,’)
puts inputs[0].to_s + “: "
opts = “”” + inputs[1].to_s + “”"
2.times { inputs.delete_at(0) }
until inputs.empty? do
opts = opts + “[”" + inputs[1].to_s + “”,"" +
inputs[0].to_s + “”]"
2.times { inputs.delete_at(0) }
end
cgi.popup_menu(opts) +
cgi.br +
}
f.close
end
cgi.submit
end
}
end
cgi.out { output.gsub(’><’, “>\n<”) }

[jleggett@binford cgi-bin]$ ./vuln.rb
./vuln.rb:27: syntax error
./vuln.rb:29: syntax error
end
^
./vuln.rb:31: syntax error
end
^
./vuln.rb:38: syntax error
[jleggett@binford cgi-bin]$

SIGH Sure enough that fixed the syntax errors… Darn thing still
doesn’t work though :frowning: Writes the h1 TITLE, and the submit, nothing in
between…

Can you post the contents of classification.txt? Some sample data would
help. Is the file readable by the web server process? Are you sure
that
the working directory when the cgi is run is such that opening
classification.txt with no other path info will work ( puts Dir.pwd )
…?

-Doug Seifert

Douglas S. wrote:

         cgi.popup_menu(opts) +
         cgi.br +

You have an extraneous ‘+’ at the end of that last line. Remove it and
your
script should start working.

Cheers,
Doug Seifert

SIGH Sure enough that fixed the syntax errors… Darn thing still
doesn’t work though :frowning: Writes the h1 TITLE, and the submit, nothing in
between…

My own fault trying to learn a new language - done it in perl I’d been
done yesterday at lunch LOL

Thanks for helping the n00b guys.

Douglas S. wrote:

SIGH Sure enough that fixed the syntax errors… Darn thing still
doesn’t work though :frowning: Writes the h1 TITLE, and the submit, nothing in
between…

Can you post the contents of classification.txt? Some sample data would
help. Is the file readable by the web server process? Are you sure
that
the working directory when the cgi is run is such that opening
classification.txt with no other path info will work ( puts Dir.pwd )
…?

-Doug Seifert

[jleggett@binford cgi-bin]$ cat classification.txt
Access Control,access,High,0,Medium,5,Low,10
Authentication,auth,High,0,Medium,5,Low,10
Confidentiality Impact,confi,High,10,Medium,5,Low,0
Confidentiality modifier,confm,Employee Data,30,Customer
Data,20,System/network Data,10,application metadata,5,N/A,0
integrity impact,integi,High,10,Medium,5,Low,0
integrity modifier,integm,System/Application,30,Customer
Information,20,Employee Info,30,Individual Info,10,N/A,0
Availability Impact,avail,High,10,medium,5,Low,0
[jleggett@binford cgi-bin]$

Yeah I added an else to the File.readable link to make sure it’s
there… it’s there… the problem seems to be now it’s not building the
CGI all up… I get errors again.

1 #!/usr/bin/ruby

 2  require "cgi"

 3  Filename = 'classification.txt'

 4  EMPTY_STRING = ''
 5  TITLE = 'Vulnerability Classification'
 6  cgi = CGI.new('html4')
 7  output = cgi.html do
 8     cgi.head { cgi.title { TITLE } } +
 9     cgi.body { cgi.h1 { TITLE }  +
10     cgi.form('post', 'http://binford.x.com/cgi-bin/vulnclass.rb') 

do
11 if File.readable?(Filename) then
12 f = File.open(Filename,“r”)
13 f.each_line { |l| l.chomp
14 inputs = l.split(’,’)
15 cgi.p { inputs[0].to_s + “: " } +
16 #opts = “”” + inputs[1].to_s + “”"
17 2.times { inputs.delete_at(0) }
18 until inputs.empty? do
19 opts = opts + “[”" + inputs[1].to_s + “”,""

  • inputs[0].to_s + “”]"
    20 2.times { inputs.delete_at(0) }
    21 end
    22 # puts opts
    23 cgi.popup_menu(opts) +
    24 cgi.br
    25 }
    26 f.close
    27 else
    28 puts “File not read-able!\n”
    29 end
    30 cgi.submit
    31 end
    32 }
    33 end
    34 cgi.out { output.gsub(’><’, “>\n<”) }

Produces:

[jleggett@binford cgi-bin]$ ./vuln.rb
(offline mode: enter name=value pairs on standard input)
./vuln.rb:20:in +': can't convert Fixnum into String (TypeError) from ./vuln.rb:20 from ./vuln.rb:16:ineach_line’
from ./vuln.rb:16
from /usr/lib/ruby/1.8/cgi.rb:1557:in form' from ./vuln.rb:13 from (eval):1022:inbody’
from ./vuln.rb:12
from /usr/lib/ruby/1.8/cgi.rb:1657:in html' from (eval):1006:inhtml’
from /usr/lib/ruby/1.8/cgi.rb:1657:in `html’
from ./vuln.rb:10
[jleggett@binford cgi-bin]$

7stud – wrote:

I have no idea why that is the case.

Here is a simplification of the issue if anyone wants to offer some
advice. The following code produces no errors:

#!/usr/bin/ruby

require “cgi”

cgi = CGI.new(‘html4’)
output = cgi.html {
cgi.head { cgi.title { “Test” } } +
cgi.body {
cgi.form(‘post’) {
cgi.textarea() +
cgi.submit
} #form
} #cgi.body
} #cgi.html

This code produces kEND errors:

#!/usr/bin/ruby

require “cgi”

cgi = CGI.new(‘html4’)
output = cgi.html {
cgi.head { cgi.title { “Test” } } +
cgi.body {
cgi.form(‘post’) {
if true
cgi.textarea() +
end
cgi.submit
} #form
} #cgi.body
} #cgi.html

Jeff Leggett wrote:

7stud – wrote:

Jeff Leggett wrote:

output = cgi.html do
cgi.head { cgi.title { TITLE } } +
cgi.body { cgi.h1 { TITLE } } +
How about getting rid of…^ ?

I changed it like that, EXACT same errors. I have matched up the ‘ends’
and bracket more times than I can count now, even slept on it, thinking
my tired brain would see it right off this morning, but no… Thanks for
your help though guys…

#!/usr/bin/ruby

require “cgi”

Filename = ‘classification.txt’

EMPTY_STRING = ‘’
TITLE = ‘Vulnerability Classification’
cgi = CGI.new(‘html4’)
output = cgi.html do
cgi.head { cgi.title { TITLE } } +
cgi.body { cgi.h1 { TITLE } +
cgi.form(‘post’) do
if File.readable?(Filename) then
f = File.open(Filename,“r”)
f.each_line { |l| l.chomp
inputs = l.split(’,’)
puts inputs[0].to_s + “: "
opts = “”” + inputs[1].to_s + “”"
2.times { inputs.delete_at(0) }
until inputs.empty? do
opts = opts + “[”" + inputs[1].to_s + “”,"" +
inputs[0].to_s + “”]"
2.times { inputs.delete_at(0) }
end
cgi.popup_menu(opts) +
cgi.br +
}
f.close
end
cgi.submit
end
}
end
cgi.out { output.gsub(’><’, “>\n<”) }

[jleggett@binford cgi-bin]$ ./vuln.rb
./vuln.rb:27: syntax error
./vuln.rb:29: syntax error
end
^
./vuln.rb:31: syntax error
end
^
./vuln.rb:38: syntax error
[jleggett@binford cgi-bin]$

Putting these lines:

cgi.popup_menu(opts) +
cgi.br +

inside the if statement doesn’t work for me: I get a bunch of kEND
errors. If I move those lines outside the if statement, then no errors:

cgi = CGI.new(‘html4’)
output = cgi.html {
cgi.head { cgi.title { TITLE } } +
cgi.body { cgi.h1 { TITLE } +
cgi.form(‘post’) {
if File.readable?(Filename)
f = File.open(Filename,“r”)
opts = “”

    f.each_line do |l|
      l.chomp #does nothing
      inputs = l.split(',')
      puts inputs[0].to_s + ": "
      opts << "\"" + inputs[1].to_s + "\""
      2.times { inputs.delete_at(0) }
      until inputs.empty?
        opts << "[\"" + inputs[1].to_s + "\",\"" + inputs[0].to_s + 

“”]"
2.times { inputs.delete_at(0) }
end
end #each_line

    f.close
  end #if

  cgi.popup_menu(opts) +
  cgi.br +
  cgi.submit
} #form

} #cgi.body
} #cgi.html

cgi.out { output.gsub(’><’, “>\n<”) }

I have no idea why that is the case.

Availability Impact,avail,High,10,medium,5,Low,0
[jleggett@binford cgi-bin]$

OK, after figuring out how CGI works in ruby … there are some problems
with your original code:

  1. cgi.body { cgi.h1 { TITLE } }

The above will generate a body tag with a h1 tag and then close the
body. I
think you wanted to defer that closing brace until after the form was
generated.

  1. The block passed to the form method must evaluate to a string which
    will
    be the form’s contents. Your block will evaluate to the return value of
    File.close (because this is the last statement executed by the block).
    close
    returns nil, which when coerced to a string would be “” (the empty
    string).
    Thus, your form will have no content.

  2. popup_menu takes a String as the first argument which is the name of
    the
    select tag and then an arbitrary number of arguments representing the
    options. I think you want to use Arrays as the arguments because you
    want
    to specify an option value and option name. The code you wrote does not
    do
    that. It just passes a big string to popup_menu as a single argument.

  3. You are mixing puts with generating strings inside the CGI tag method
    blocks. You need to make sure you don’t use puts as it will corrupt the
    HTML generated by the script by outputting stuff you don’t want output.

I took a stab at correcting all these problems, and changed some minor
things, but didn’t really try to rubyfy the code:

require “cgi”

Filename = ‘classification.txt’

EMPTY_STRING = ‘’
TITLE = ‘Vulnerability Classification’
cgi = CGI.new(‘html4’)
output = cgi.html do
cgi.head { cgi.title { TITLE } } +
cgi.body do
cgi.h1 { TITLE } +
cgi.form(‘post’) do
form_contents = “”
if File.readable?(Filename) then
# Use the version of File#open that takes a block. That
# way you don’t have to worry about closing the file after
# you are done with it – it will happen automatically when
# the block is done executing
File.open(Filename,“r”) do |f|
f.each_line do |l|
# Need to use chomp! instead of plain chomp to
# ensure l is actually changed. Otherwise, we just
# create and throw away a new string
l.chomp!
inputs = l.split(’,’)
form_contents << inputs[0] + ": "
select_name = inputs[1]
select_opts = []
2.times { inputs.delete_at(0) }
until inputs.empty? do
select_opts << [inputs[1], inputs[0]]
2.times { inputs.delete_at(0) }
end
form_contents << cgi.popup_menu(select_name, *select_opts) +
cgi.br
end
end
end
form_contents + cgi.submit
end
end
end

Douglas S. wrote:

    cgi.textarea() +

You have a trailing + and have not provided the second argument in all
the
examples that fail.

The second argument to +? What about cgi.submit? This works:

cgi.form(‘post’) {
cgi.textarea() +
cgi.submit
}

This produces kEND errors:

cgi.form(‘post’) {
if true
cgi.textarea() +
else
cgi.textarea() +

  cgi.submit
}

You can’t do this in plain ruby:

str = “hello” +
" goodbye"

But the cgi syntax allows you to add things together like that.

7stud – wrote:

This code produces kEND errors:

#!/usr/bin/ruby

require “cgi”

cgi = CGI.new(‘html4’)
output = cgi.html {
cgi.head { cgi.title { “Test” } } +
cgi.body {
cgi.form(‘post’) {
if true
cgi.textarea() +
end
cgi.submit
} #form
} #cgi.body
} #cgi.html

So does this:

#!/usr/bin/ruby

require “cgi”

cgi = CGI.new(‘html4’)
output = cgi.html {
cgi.head { cgi.title { “Test” } } +
cgi.body {
cgi.form(‘post’) {
if true
cgi.textarea() +
else
cgi.textarea() +
end

  cgi.submit
} #form

} #cgi.body
} #cgi.html

Douglas S. wrote:

OK, after figuring out how CGI works in ruby … there are some problems
with your original code:

WOW, thanks Doug! That was it totally… I had read use of the
destructive method (!) but didn’t grok till I saw it… And the rest of
the way now makes prefect sense.

I appreciate all of yours help. I decided my perl only skills were
getting long in the tooth and decided I needed to pick up a truly OO
language, and learn it… but seems a lot harder than when learning new
languages did 20+ years ago.

cgi.form(‘post’) {
cgi.textarea() +
cgi.submit
}

The above works because the interpreter finds something on the next line
to
add to the result of cgi.textarea().

  cgi.submit

}

The interpreter sees that + at the end of the line in the first branch
of
the if statement and gets confused looking for something to add it to.
It
would be nice if it could figure out that you wanted to add it to the
result
of the statement that comes after the if statement, but that is not how
it
works. You would need to do something like like this to get it to work:

(condition ? cgi.textarea() : cgi.textarea()) +
cgi.submit

You can’t do this in plain ruby:

str = “hello” +
" goodbye"

The above works just fine. You end up with str being a reference to
“hello
goodby”.

But the cgi syntax allows you to add things together like that.

There is nothing magical about the cgi syntax. All that is happening is
that String objects are getting added together. To get it to work, you
have
to ensure that the blocks passed to the various cgi methods end up
evaluating to the string you want the tag created by the block’s method
to
contain. You do that by making the last statement evaluated in the
block be
the string you want as content.

-Doug Seifert

Douglas S. wrote:

You can’t do this in plain ruby:

str = “hello” +
" goodbye"

The above works just fine. You end up with str being a reference to
“hello
goodby”.

Hmmm…I must have done something wrong when I was testing that–because
now it works. In that case. the op’s problem makes perfect sense. His
code was trying to do this:

str = "form element1 " +

if true
"form element2 " +
end

“submit button”

which gives the kEND errors the op was seeing:

r1test.rb:5: syntax error, unexpected kEND
r1test.rb:10: syntax error, unexpected $end, expecting kEND

    cgi.textarea() +

You have a trailing + and have not provided the second argument in all
the
examples that fail.

Douglas S. wrote:

The interpreter sees that + at the end of the line in the first branch
of
the if statement and gets confused looking for something to add it to.
It
would be nice if it could figure out that you wanted to add it to the
result
of the statement that comes after the if statement, but that is not how
it
works. You would need to do something like like this to get it to work:

(condition ? cgi.textarea() : cgi.textarea()) +
cgi.submit

You can just use ‘if’ that way too, as it returns a value, although its
low precedence means you’ll need brackets:

(
if condition
foo
else
bar
end
) +
baz

Personally I wouldn’t try to write it this way; it’s too error-prone as
has been demonstrated already. I think it would be clearer to append to
a target string in stages:

str = “”
if condition
str << foo
else
str << baz
end
str << baz

Here, each line stands by itself.

But for any complex output it’s probably better to forget about using
CGI methods to generate HTML, and use some sort of template (e.g. ERB or
HAML).

Admittedly, in a one-shot CGI environment, there’s a bigger startup
overhead both in reading the template library and parsing the template,
for every request. But if performance is a concern, then you shouldn’t
be using CGI anyway.

If you write your app using a simple framework like Sinatra, then you
can run it both as CGI and in a number of other environments, without
changing the app.