[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Newb CGI Question

Michael Buffington

4/20/2005 7:54:00 PM

So I thought I had CGI in Ruby figured out, but I'm stumped on the following:

I want use Ruby to dynamically serve an image. The image tag would
look like <img src="file.rb?id=200">, where 200 is the id for an
image.

So here's what I have (I'm trading embarrassment for guidance):

require "cgi"
cgi = CGI.new("html4")
cgi.out('image/png')
File.read('200.png')

Now, I'm pretty sure I'm not reading the file right, but what I seem
to be stuck on first is getting my MIME type right. When hitting the
CGI, I can't get Content-Type to come back as 'image/png'. It's always
'text/html'.

Any tips?



10 Answers

Joost Diepenmaat

4/20/2005 8:06:00 PM

0

On Thu, Apr 21, 2005 at 04:54:24AM +0900, Michael Buffington wrote:
> So I thought I had CGI in Ruby figured out, but I'm stumped on the following:
>
> I want use Ruby to dynamically serve an image. The image tag would
> look like <img src="file.rb?id=200">, where 200 is the id for an
> image.
>
> So here's what I have (I'm trading embarrassment for guidance):
>
> require "cgi"
> cgi = CGI.new("html4")
> cgi.out('image/png')
> File.read('200.png')

Shouldn't that be

cgi.header("image/png") {
File.read('200.png');
}

Or something similar?

J.


Ryan Leavengood

4/20/2005 8:13:00 PM

0

> So I thought I had CGI in Ruby figured out, but I'm stumped on the
> following:
>
> I want use Ruby to dynamically serve an image. The image tag would
> look like <img src="file.rb?id=200">, where 200 is the id for an
> image.
>
> So here's what I have (I'm trading embarrassment for guidance):
>
> require "cgi"
> cgi = CGI.new("html4")
> cgi.out('image/png')
> File.read('200.png')
>
> Now, I'm pretty sure I'm not reading the file right, but what I seem
> to be stuck on first is getting my MIME type right. When hitting the
> CGI, I can't get Content-Type to come back as 'image/png'. It's always
> 'text/html'.
>
> Any tips?

Try the following:

require "cgi"
cgi = CGI.new("html4")
cgi.out('image/png') do
File.read("#{cgi['id']}.png")
end

You have to supply the content in a block passed to out. I also added the
necessary code to read the id and open that file.

Ryan Leavengood


Michael Buffington

4/20/2005 8:28:00 PM

0

> require "cgi"
> cgi = CGI.new("html4")
> cgi.out('image/png') do
> File.read("#{cgi['id']}.png")
> end

Still doesn't seem to nail it. Firefox reports the page as
'text/plain'. Hitting the URL directly doesn't pull the image, using
<img src=".."> produces a broken link. In Safari, it downloads
endlessly.

I'm not sure what CGI is doing behind the scenes with cgi.out. From
what I read in the docs, it seems like cgi.out is supposed to write
the header for you, but the header I'm getting is very sparse:

HTTP/1.x 200 OK
Connection: close
Date: Wed, 20 Apr 2005 19:20:41 GMT
Server: lighttpd/1.3.13

I should at least see Content-Type: image/png in the header.

I also haven't ruled out lighttpd in this case, but it's much more
likely I'm doing something wrong, not lighttpd.



Paul Battley

4/20/2005 10:35:00 PM

0

I have found that you need to write the header manually, despite what
the docs say.

This snippet will save you a lot of hassle whilst developing under
CGI. It should trap errors and give a backtrace in the browser, as
well as indicate if you didn't send the header properly:

---- cgicroak.rb ----

require 'cgi'

class CGI
def self.croak(*args)
cgi = CGI.new(args)
old_stdout = $stdout
buffer = ''
def buffer.write(s)
self << s
end
$stdout = buffer
begin
yield(cgi)
unless (buffer =~ /^Content-type:.*?\r?\n\r?\n/i)
raise RuntimeError, "No header sent"
end
rescue Exception => e
buffer.replace('')
print(cgi.header('type' => 'text/plain'))
puts("Error\n\n")
puts("#{e.class.to_s}: #{e.to_s}\n\n")
puts(e.backtrace.join("\n"))
end
$stdout = old_stdout
$stdout.write(buffer)
end
end

---- index.cgi ----

#!/path/to/your/ruby

require 'croakcgi'

CGI.croak('html4') do |cgi|

# Your requires go here

print(cgi.header)

# Your code

end

--- EOF ---

Paul.



Paul Battley

4/20/2005 10:42:00 PM

0

Oops - I referred to the file as both 'croakcgi' and 'cgicroak'.
Choose one or the other!



Michael Buffington

4/20/2005 11:40:00 PM

0

This is really great - seeing Ruby errors definitely makes things more clear.

So, to test this all out, here's what my "index.cgi" looks like:
#! /usr/bin/ruby
require 'cgicroak'

CGI.croak('html4') do |cgi|
cgi.out("type" => "text/html") {"shizzle"}
end

This works as expected. The word shizzle makes it to the browser.

However, when I execute this:
#! /usr/bin/ruby
require 'cgicroak'

CGI.croak('html4') do |cgi|
cgi.out("type" => "image/gif") {File.open("image.gif")}
end

I get:
Error NameError: undefined method `length'

I get the same thing with:
#! /usr/bin/ruby
require 'cgicroak'

CGI.croak('html4') do |cgi|
cgi.out("type" => "image/gif", "length" => File.size("image.gif"))
{File.open("image.gif")}
end

In either cases, if I use cgi.header instead of cgi.out, I get an error saying:
"No header sent"

Any ideas about what's going on?

On 4/20/05, Paul Battley <pbattley@gmail.com> wrote:
> I have found that you need to write the header manually, despite what
> the docs say.
>
> This snippet will save you a lot of hassle whilst developing under
> CGI. It should trap errors and give a backtrace in the browser, as
> well as indicate if you didn't send the header properly:
>
> ---- cgicroak.rb ----
>
> require 'cgi'
>
> class CGI
> def self.croak(*args)
> cgi = CGI.new(args)
> old_stdout = $stdout
> buffer = ''
> def buffer.write(s)
> self << s
> end
> $stdout = buffer
> begin
> yield(cgi)
> unless (buffer =~ /^Content-type:.*?\r?\n\r?\n/i)
> raise RuntimeError, "No header sent"
> end
> rescue Exception => e
> buffer.replace('')
> print(cgi.header('type' => 'text/plain'))
> puts("Error\n\n")
> puts("#{e.class.to_s}: #{e.to_s}\n\n")
> puts(e.backtrace.join("\n"))
> end
> $stdout = old_stdout
> $stdout.write(buffer)
> end
> end
>
> ---- index.cgi ----
>
> #!/path/to/your/ruby
>
> require 'croakcgi'
>
> CGI.croak('html4') do |cgi|
>
> # Your requires go here
>
> print(cgi.header)
>
> # Your code
>
> end
>
> --- EOF ---
>
> Paul.
>
>



Michael Buffington

4/20/2005 11:50:00 PM

0

Looks I've figure most of it. This sort of works:

#! /usr/bin/ruby

require 'cgicroak'

CGI.croak('html4') do |cgi|
print(cgi.header("type" => "image/gif", "length" =>
File.size("image.gif"), "status" => "304"))
File.read("agent.gif")
end

Problem is, the server reports that it can't display the image due to
errors. Any ideas what I'm doing wrong when I actually read the image
file in?


On 4/20/05, Michael Buffington <michael.buffington@gmail.com> wrote:
> This is really great - seeing Ruby errors definitely makes things more clear.
>
> So, to test this all out, here's what my "index.cgi" looks like:
> #! /usr/bin/ruby
> require 'cgicroak'
>
> CGI.croak('html4') do |cgi|
> cgi.out("type" => "text/html") {"shizzle"}
> end
>
> This works as expected. The word shizzle makes it to the browser.
>
> However, when I execute this:
> #! /usr/bin/ruby
> require 'cgicroak'
>
> CGI.croak('html4') do |cgi|
> cgi.out("type" => "image/gif") {File.open("image.gif")}
> end
>
> I get:
> Error NameError: undefined method `length'
>
> I get the same thing with:
> #! /usr/bin/ruby
> require 'cgicroak'
>
> CGI.croak('html4') do |cgi|
> cgi.out("type" => "image/gif", "length" => File.size("image.gif"))
> {File.open("image.gif")}
> end
>
> In either cases, if I use cgi.header instead of cgi.out, I get an error saying:
> "No header sent"
>
> Any ideas about what's going on?
>
> On 4/20/05, Paul Battley <pbattley@gmail.com> wrote:
> > I have found that you need to write the header manually, despite what
> > the docs say.
> >
> > This snippet will save you a lot of hassle whilst developing under
> > CGI. It should trap errors and give a backtrace in the browser, as
> > well as indicate if you didn't send the header properly:
> >
> > ---- cgicroak.rb ----
> >
> > require 'cgi'
> >
> > class CGI
> > def self.croak(*args)
> > cgi = CGI.new(args)
> > old_stdout = $stdout
> > buffer = ''
> > def buffer.write(s)
> > self << s
> > end
> > $stdout = buffer
> > begin
> > yield(cgi)
> > unless (buffer =~ /^Content-type:.*?\r?\n\r?\n/i)
> > raise RuntimeError, "No header sent"
> > end
> > rescue Exception => e
> > buffer.replace('')
> > print(cgi.header('type' => 'text/plain'))
> > puts("Error\n\n")
> > puts("#{e.class.to_s}: #{e.to_s}\n\n")
> > puts(e.backtrace.join("\n"))
> > end
> > $stdout = old_stdout
> > $stdout.write(buffer)
> > end
> > end
> >
> > ---- index.cgi ----
> >
> > #!/path/to/your/ruby
> >
> > require 'croakcgi'
> >
> > CGI.croak('html4') do |cgi|
> >
> > # Your requires go here
> >
> > print(cgi.header)
> >
> > # Your code
> >
> > end
> >
> > --- EOF ---
> >
> > Paul.
> >
> >
>



Paul Battley

4/21/2005 12:16:00 AM

0

You are reading the data, but not actually sending it to the client.

- File.read("agent.gif")
+ print(File.read("agent.gif"))

I think that's the problem. You can also get rid of the 304 status;
it's not appropriate:
http://www.w3.org/Protocols/rfc2616/rfc2616-...

Finally, you are sending the length of a different file in the code
sample you gave.



Michael Buffington

4/21/2005 12:27:00 AM

0

On 4/20/05, Paul Battley <pbattley@gmail.com> wrote:
> You are reading the data, but not actually sending it to the client.
>
> - File.read("agent.gif")
> + print(File.read("agent.gif"))
>

Adding print produces the same result - can't display the image due to errors.

> I think that's the problem. You can also get rid of the 304 status;
> it's not appropriate:
> http://www.w3.org/Protocols/rfc2616/rfc2616-...

Fair enough - I added because when accessing the image directly, the
returned status was 304.

Interestingly, when I remove the 304, I get a broken image rather than
an error message.

>
> Finally, you are sending the length of a different file in the code
> sample you gave.

Woops. Email editing faux pas. The code is correct.

>



Paul Battley

4/21/2005 12:36:00 AM

0

I just ran up a similar example using a jpeg I had to hand (yes, it
really was called 'foo.jpeg'!).

require 'cgicroak'

CGI.croak do |cgi|
print(cgi.header('type' => 'image/jpeg'))
print(File.read('foo.jpeg'))
end

It works, and displays the image, so the code seems all right. Do
check things like file permissions, though - it could be that it is
failing to read the image from disk. And, of course, check the image
itself.