Forum: Ruby CGI help

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Jeff L. (Guest)
on 2009-05-09 02:04
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<") }
James B. (Guest)
on 2009-05-09 02:29
(Received via mailing list)
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 L. (Guest)
on 2009-05-09 04:13
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
>
> http://www.ruby-doc.org/docs/ProgrammingRuby/html/web.html
>

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]$
7stud -. (Guest)
on 2009-05-09 09:58
Jeff Leggett wrote:
> output = cgi.html do
>    cgi.head { cgi.title { TITLE } } +
>    cgi.body { cgi.h1 { TITLE } } +
How about getting rid of.........^ ?
Jeff L. (Guest)
on 2009-05-09 20:35
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]$
Douglas S. (Guest)
on 2009-05-09 20:52
(Received via mailing list)
>
>              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
Jeff L. (Guest)
on 2009-05-09 21:06
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 :(  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. (Guest)
on 2009-05-09 21:31
(Received via mailing list)
>
>
> *SIGH* Sure enough that fixed the syntax errors... Darn thing still
> doesn't work though :(  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
Jeff L. (Guest)
on 2009-05-09 21:42
Douglas S. wrote:
>>
>>
>> *SIGH* Sure enough that fixed the syntax errors... Darn thing still
>> doesn't work though :(  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:in `each_line'
        from ./vuln.rb:16
        from /usr/lib/ruby/1.8/cgi.rb:1557:in `form'
        from ./vuln.rb:13
        from (eval):1022:in `body'
        from ./vuln.rb:12
        from /usr/lib/ruby/1.8/cgi.rb:1657:in `html'
        from (eval):1006:in `html'
        from /usr/lib/ruby/1.8/cgi.rb:1657:in `html'
        from ./vuln.rb:10
[jleggett@binford cgi-bin]$
7stud -. (Guest)
on 2009-05-09 21:47
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.
7stud -. (Guest)
on 2009-05-09 22:07
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
7stud -. (Guest)
on 2009-05-09 22:09
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. (Guest)
on 2009-05-09 22:15
(Received via mailing list)
> 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.

2) 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.

3) 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.

4) 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. (Guest)
on 2009-05-09 22:18
(Received via mailing list)
>
> >         cgi.textarea() +
>

You have a trailing + and have not provided the second argument in all
the
examples that fail.
7stud -. (Guest)
on 2009-05-09 23:48
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.
Jeff L. (Guest)
on 2009-05-10 00:05
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.
Douglas S. (Guest)
on 2009-05-10 02:46
(Received via mailing list)
>
> 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
7stud -. (Guest)
on 2009-05-10 03:27
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
Brian C. (Guest)
on 2009-05-11 17:19
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.
This topic is locked and can not be replied to.