LevSelector.com |
HTTP, CGI and Cookies
On this page: | Other pages: | |
*
http
protocol
* books * simple cgi_examples * security - tainting * debugging CGI scripts * CGI.pm * CGI.pm freq.used elements * CGI.pm propagates values * CGI::Carp |
*
libs
of cgi scripts
* cookies * cgi in C * cgi in shell |
*
CGI::Application
module
|
HTTP | home - top of the page - |
HTTP protocol (mostly ver. 1.0, or 1.1) is the protocol carring
most of web messages.
It is the protocol used when you enter http address in your browser.
It is a simple protocol.
Every time browser wants something from a web server - it sends a request.
Request consists of a header,
followed by an empty line
followed by an optional body.
Header starts with a command.
Most common commands - GET or POST (others are HEAD, PUT, DELETE,
etc.).
Here is an example of a successful GET request to retrieve a file.
The client (browser) sends:
GET /index.html HTTP/1.0
Connection: Keep-Alive User-Agent: Mozilla/3.0Gold (WinNT; I) Host: www.vedanco.com Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* |
The server responds with:
HTTP/1.1 200 OK
Date: Fri, 13 Oct 2000 00:29:37 GMT Server: Apache/1.3.9 (Unix) (Red Hat/Linux) Last-Modified: Sun, 17 Sep 2000 17:47:28 GMT Content-Length: 7871 Content-Type: text/html <html>
|
As you see, web server responds sending header followed by HTML page or an image - they will be in the body of the message. The Content-type of this data (for example "text/html") and the length of the data will be indicated in the header of the server response.
When the browser receives the HTML page - it may find that this page
needs some images. Then it may send more requests to the server, like this
one:
GET /images/logo.gif HTTP/1.0
Connection: Keep-Alive User-Agent: Mozilla/3.0Gold (WinNT; I) Host: www.vedanco.com Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* |
Server will send responses like this one:
HTTP/1.1 200 OK
Date: Fri, 13 Oct 2000 00:29:37 GMT Server: Apache/1.3.9 (Unix) (Red Hat/Linux) Content-Type: image/gif Content-Length: 10381 Last-Modified: Sun, 17 Sep 2000 17:47:28 GMT (data of GIF file here) |
To pretend that you are a browser, try to send this one line header followed by an empty line from a unix prompt:
telnet www.somesite.com
80 <ENTER>
GET / HTTP/1.0<ENTER>
<ENTER>
To send data from the form in the browser, you usually use either GET
or POST.
When using GET, the data is passed in one long QUERY STRING appended via question mark, for example: GET /work.cgi?first=John&last=Smith HTTP/1.0 When you use POST - the same data is passed in the body of the HTTP request |
BOOKS | home - top of the page - |
*
CGI Programming 101 by Jacqueline
D. Hamilton - This is probably the best book about Perl/CGI for a beginner.
All examples for this book are here: *www.cgi101.com/class/
, www.cgi101.com/class/indices.html
-
* CGI Programming with Perl (O'Reilly, 2nd Edition) by Scott Guelich, Linda Mui, Gunther Birznieks, Shishir Gundavaram * Web Client Programming With Perl by Clinton Wong - excellent intro into HTTP protocol. Learn how to write your own web spiders. it is out of print, but is available for free online: www.oreilly.com/openbook/webclient/index.html * Perl Debugged (2001) by Peter J. Scott, Ed Wright - excellent chapter #13 "Debugging CGI Programs" *
How to Set Up
and Maintain a Web Site - Lincoln D. Stein
|
simple CGI examples | home - top of the page - |
The logic of the typical script is:
- get request (parameters)
- do something
- print http header and html page back to the browser
Here is a very simple Perl/CGI script:
#!/usr/local/bin/perl -wT
$|++; # unbuffer STDOUT (because with default buffer ~8kb the output may be delayed) print "Content-type: text/html\n\n"; # print http header and an empty line separator # do something interesting here print "<html>test</html>\n"; # print output |
Here is a CGI script showing ENV variables:
#!/usr/local/bin/perl -wT
$|++; print "Content-type: text/html\n\n"; print "<html><head><title>ENV</title></head><body>\n"; print "<h3>Table on ENV variables and their values</h3>\n<table>\n"; for my $key (keys %ENV) { print "<tr><td>$key</td><td>$ENV{$key}</td></tr>\n"; } print "</table></body></html>\n"; |
Here is a simple function parse_request
to get access to form parameters: $in{$name} = $value;
#*******************************-
# die_www() #*******************************- sub die_www { my $message = shift; print "Content-Type: text/html\n\n"; print "<html><head><title>die-message</title></head> <body><br><br>$message<br><br></body></html>\n"; exit(0); } #*******************************-
#*******************************-
#*******************************-
foreach my $pair (@pairs) {
|
Security - tainting | home - top of the page - |
Classical example of a security problem:
Let's say you have a form which asks to enter email address.
One day a bad-bad user enters a command ' ; rm * ' in this field. Your script saves this into a variable $email and tries to send an email: open MAIL,"|$SENDMAIL $email" the 'rm *' command may be triggered at this point - and delete all files in the directory (on your server !!). |
The solution - use -T option (taint mode):
#!/usr/bin/perl -T
In taint mode any external data ($email in this case) is tainted by
a special flag. Any attempt to to use tainted data for some outside action
results in an error. The only way to remove taint from data is to use regular
expression to select something from this data into $1,$2, etc. - and use
them instead.
Debugging CGI scripts | home - top of the page - |
check that the script
- has proper extension (usually "cgi")
- is in proper directory (usually "cgi-bin")
- made executable (chmod 755 test.cgi) - and subdirectory also
executable
- has no syntax errors or warnings
- can be run from prompt, shebang line is correct (points on
the right version of perl)
Look in the access and error log of the web server on the unix prompt.
Or you can use separate cgi script for that:
#!/usr/local/bin/perl
# err.cgi use strict; $|++; print"Content-type:text/plain\n\n"; print"access_log:\n"; my @tail = qx(tail -10 /etc/httpd/logs/access_log); print " @tail\n"; print"error_log:\n"; @tail = qx(tail -10 /etc/httpd/logs/error_log); print " @tail\n"; |
You can show errors on the browser, for example using this:
use CGI qw(:standard);
use CGI::Carp qw(fatalsToBrowser); |
Another good module - CGI::Debug
Only report errors:
use CGI::Debug( report => 'errors' ); Do not bother about warnings:
Allways show complete debugging info:
Send debug data as mail to file owner:
|
Here is how to email info about errors (without using CGI::Debug):
use lib "/home/merlyn/lib";
use FatalsToEmail qw(Address merlyn@stonehenge.comm);
# Randal Schwartz - www.stonehenge.com/merlyn/LinuxMag/col14.html
package FatalsToEmail;
use strict; my %config = (
# ------------------------------------------------
$SIG{__DIE__} = \&trapper; # ------------------------------------------------
my $prefix = localtime;
print STDOUT <<END;
send_mail($message);
# ------------------------------------------------
eval { require Net::SMTP; 1 } or die "no Net::SMTP";
|
CGI.pm module | home - top of the page - |
CGI.pm module:
CGI.pm module (written by Lincoln D. Stein) comes standard with Perl.
I recommend to always use it.
- http://stein.cshl.org/WWW/CGI/examples/
- examles by Lincoln D. Stein himself
This module is a base of many other good packages, for example ( CGI::Application
module ).
Below is a summary from the book "CGI programming
with Perl" 2nd ed. by O'Reilly - I will refer to it as "CGI
programming book".
Here is a simple example using CGI.pm:
Object-oriented style:
#!/usr/local/bin/perl -wT
use strict; use CGI; my $q = new CGI; my $name = $q->param("name"); print $q->header("text/html"),
|
Standard syntax:
#!/usr/local/bin/perl -wT
use strict; use CGI qw(:standard); my $name = param("name"); print header("text/html"),
|
You have access to environment information via %ENV hash, for example:
my $qstr = $ENV{QUERY_STRING};
CGI.pm also gives you more than 30 method calls with
names similar to keys of the hash.
Some methods:
query_string method:
my $qstr = $q->qwery_string; Accept method:
|
Accessing parameters:
#!/usr/local/bin/perl -wT
use strict; use CGI; my $q = new CGI; print $q->header("text/plain"); my ($name, $value); for $name ($q->param) { print "$name:\n"; for $value ($q->param($name) ) { print "$value:\n"; } } |
You can access parameters from both POST (STDIN) and GET (QUERY_STRING) - you will need to uncomment a line of code in CGI.pm (page 95 in the CGI programming book).
There are 4 ways to use param() function:
$scalar = $q->param('name'); #
returns the value
@array = $q->param('name'); # returns array of values for this name $scalar = $q->param( ); # returns the number of all named form elements @array = $q->param( ); # returns an array of names of all form elements |
Changing / deleting parameters:
$q->param(title => "Some Title");
$q->param(account => "Acc1", "Acc2"); $q->param(account => "Acc1", "Acc2"); $q->delete("age"); $q->delete_all; |
To include parameters into strings, you can:
-- create intermediate variables:
my $user = q->param('user'); print "Hi, $user!"; -- use @{[...]} syntax: print "Hi, @{[q->param('user')]}!"; -- import names of parameters into a separate namepace: $q->import_names( "Q"); print "Hi, $Q::user!"; |
File uploads:
HTML:
<form action="/cgi/upload.cgi" method="POST" enctype="multipart/form-data"> <p>Please choose a file to upload: <input type="FILE" name="file"> <input type="SUBMIT"></form> CGI: my $fname = $q->param("file"); # this can cause problems on some problems - read workarounds - pp.97,98 in the CGI programming book). my $fh = $q->upload("$fname"); # this is file handler to get the file contents - see full example pp.99-101. |
Generating output:
#!/usr/local/bin/perl -wT
use strict; use CGI; my $q = new CGI; my $time1 = localtime; print $q->header("text/plain"), $q->start_html ( -title => "The Time", -bgcolor => "#ffffff" ), $q->h2( "Current Time" ), $q->hr, $q->p( "The current time is:", $q->b( $time1 ) ), $q->end_html; |
Output - Excel file:
#!/usr/local/bin/perl -wT |
Some other elements:
print $q->start_html(
-title=>'SomeTitle', -xbase e=>$SomeBaseURL, -script=>$SomeJavaScript, # or -script=>{ -language => 'JavaScript', -src=>'/javascript/somefile.js'}, # or -script=>{ -language => 'JavaScript', -code=>$SomeJavaScript}, -style=>{ -code => $someStyleCode, -src=>$src_file },
print $q->p( $paragraph_text );
|
Note confilcts:
The <tr> tag conflicts with the perl translate function tr///. Use
TR() or Tr() instead.
The <param> tag (applets) conflicts with CGI's own param() method. Use PARAM() instead. The <select> tag in select-lists conflicts with perl's select() function. Use Select() instead. |
Table:
print $q->table(
{ -border => 1, -width => "100%" }, $q->Tr( [ $q->th( { -bgcolor => "#cccccc" }, ["Name", "Age" ] ), $q->td(["Mary", 29]), # row $q->td(["Bill", 27]), # row $q->td(["Sue", 26]), # row ] ) # end of rows ); # end of table |
Form:
#!/usr/local/bin/perl
use CGI qw(:standard); print header; print start_html('A Simple Example'), h1('A Simple Example'), start_form, "What's your name? ",textfield('name'), p, "What's the combination?", p, checkbox_group(-name=>'words', -values=>['eenie','meenie','minie','moe'], -defaults=>['eenie','minie']), p, "What's your favorite color? ", popup_menu(-name=>'color', -values=>['red','green','blue','chartreuse']), # this is equivalent of <select> list p, submit, end_form, hr; if (param()) {
|
All form elements:
start_form, end_form,
textfield, password_field, filefield, button, submit, reset, checkbox, checkbox_group, radio_group, popup_menu, # <select size="1"> scrolling_list, # <select size="n"> where n>1 textarea, hidden Examples:
|
cookie method:
To retrieve cookie - use cookie method without value parameter
use CGI; $query = new CGI; %answers = $query->cookie(-name=>'answers'); # $query->cookie('answers') will work too! To set cookie:
Store many values (hash) into a cookie:
Store 2 or more cookies:
|
CGI.pm script with most freq.used elements | home - top of the page - |
Real working script with most frequently used elements:
#!/usr/local/bin/perl
# file cgi_all.cgi use strict;
print $q->header("text/html"),
function a(mes){
), # end of javascript definition -style=>{ -src=>'style0.css' },
print $q->h4( "Current Time" ),nn,
print $q->table(
# --------------------------------------
print $q->start_form(-name=>'form1', -method=>'POST', -action=>'cgi_all.cgi'),
$q->textarea(-name=>"Comments", -rows=>'3', -columns=>'60',
# filefield $q->br,nn,
# --------------------------------------
print $q->end_html;
|
Note that some functions in Perl capitalized to avoid conflicts with html-tag names:
Select
Tr Link Delete Accept Sub |
CGI.pm propagates values | home - top of the page - |
CGI.pm, by default, propagates existing values of form fields. This is normally A Good Thing, as it allows you to easily have data move from screen to screen. This mechanism allows you to set a value (which acts like a default), which is overridden by an existing value stored in the CGI query object. When a user submits "name=Terry" on a form, the next screen will automagically have "name=Terry" without necessitating that the programmer explicitally copy it from the query to the new screen.
E.g.:
$output .= $q->hidden(-name=>'name'); # Nice and
simple
Instead of:
$output .= $q->hidden(-name=>'name', -value=>$q->param('name'));
# Ugh!
However, there are some cases where you do not want the value of a particular form variable to persist. Case in point: Your run-mode form parameter. In this case, you always want your new value to override any pre-existing form value. CGI.pm provides an "override" attribute which provides this function:
my $q = $self->query();
$output .= $q->hidden(-name=>'rm', -value=>$which_one,
-override=>1);
This will cause the form parameter "rm" to always be set to $which_one regardless of any pre-existing value submitted for "rm".
CGI::Carp module | home - top of the page - |
CGI::Carp is also written by Lincoln Stein, distributed with CGI.pm
- writes to error log
- creates an error (html) page
Example: creating your own Error.pm module:
#!/usr/local/bin/perl -wT
package CGIBook::Error; use Exporter;
use strict;
BEGIN {
sub error {
1; |
Example using this module in your cgi script:
#!/usr/local/bin/perl -wT
use strict;
do_something
|
CGI libs | home - top of the page - |
Many-many CGI scripts:
*
www.worldwidemart.com/scripts/
- Matt's Script Archives
*
www.cgi-resources.com/
-
*
www.scriptsearch.com/pages/l4.shtml
- Script Search - The world's largest CGI library
Cookies | home - top of the page - |
A cookie is information that a Web site puts on your hard disk so that
it can remember something about you at a later time.
*www.LevSelector.com/cookie.html
- short Perl/Javascript/Java examples
*
do search for cookielib
on search engines ( http://www.google.com/search?q=cookielib
) - Matt's Script Archive: HTTP Cookie Library.
*
www.zdnet.com/devhead/resources/scriptlibrary/javascript/cookies.html
-
*
www.hidaho.com/cookies/cookie.txt
-
*
www.cookiecentral.com/-
*
www.worldwidemart.com/scripts/cookielib.shtml
-
*
home.netscape.com/newsref/std/cookie_spec.html
-
*
www.netscapeworld.com/netscapeworld/nw-07-1996/nw-07-cookies.html
-
CGI in C | home - top of the page - |
Click here to see an example of a C program
processing a CGI input.
In this example some other process took the QUERY string for GET or
STDIN for POST and passed it to this CGI program via STDIN
(length is in CONTENT_LENGTH variable). Note how long is the code in
comparison to Perl version.
CGI in a unix shell (ksh) | home - top of the page - |
Form processing example.