The website for current versions of AdaCGI is http://www.dwheeler.com/adacgi.
This Ada package provides two data access approaches for CGI-related data:
The main access routines support both Ada 95 types String and Unbounded_String.
The AdaCGI package is available in various formats, including zip, tarball (tar.gz), and RPM foramts. Again, go to the AdaCGI website to get the latest version in a variety of formats.
This documentation assumes that you are already familiar with HTML. To use this package you'll need to learn a little about Ada 95; the Lovelace Ada 95 tutorial provides one good way to do so. It would help if you understood the Common Gateway Interface (CGI), though hopefully for straightforward web applications you won't need to.
Below are the following sections; the ``license'' and ``advantages'' sections will hopefully help you determine if this library is right for you, the ``installation'' and ``trying out'' sections will help you get started, and the rest (including the example) will hopefully give you enough information to be able to use it effectively:
AdaCGI License
AdaCGI is copyright (C) 1995-2000 David A. Wheeler
(dwheeler@dwheeler.com, or
alternatively dwheeler@ida.org and wheeler@ida.org).
AdaCGI is an open source library; the actual library
is released using the LGPL license as modified by a
special exception and a clarification
(see the CGI specification for the actual license).
You can use this library in proprietary programs but
any changes to the library must stay as open source.
No payment is required, but please provide credit if you use this package.
The demonstration programs and this documentation are covered by the GPL.
The special exception made to the LGPL in the AdaCGI library license is the same as that used by many Ada libraries, including the GNAT (gcc-based) Ada compiler library and GtkAda. This exception eliminates the requirement to create special object files to permit re-linking new libraries. While this requirement is desirable, it's onerous to do using today's heavily optimizing compilers and hard to do with generics, so this exception is common in Ada open source programs.
The clarification states that any user who uses the server remotely still has the right to acquire the source of this library as used by the serving program. The clarification was added because, as an interface to the web, the issue of "who is executing this program" could be a source of confusion. If you allow users to run your program, then you can't make the library proprietary from them.
Installing AdaCGI
If you use an RPM-based Linux system (e.g., Red Hat Linux),
just get and install the RPM file as usual.
For example, on a Linux i386-derived system (including Pentiums), you can
get the precompiled file and just run:
rpm -Uvh adacgi-*.i386.rpm
The RPM installs the source files in the directory /usr/lib/ada/adainclude, the compiled files in /usr/lib/ada/adalib, top-level documentation in /usr/doc/adacgi-*, and the sample programs in /usr/doc/adacgi-*/sample (this is different than older RPMs, which for example used ``gnat'' instead of ``ada''). Detailed HTML format documentation is integrated into the standard Ada documentation tree; the curious might want to know that this tree begins at /usr/share/ada/html/adacgi. The precompiled library depends on the Ada GNAT runtime library; you can get you can get these and other files from the Ada for Linux website. Note that a renaming of the GNAT RPMs has taken place, starting at GNAT version 3.12p release 9; this AdaCGI RPM requires at least this version.
At the time of this writing I don't have a Debian (.deb) format for Debian-based systems (such as Debian and Corel), sorry. You can use the Unix-like instructions (below) to install it. It's been reported to me that ``alien'' translates adacgi into a Debian package fairly well by doing:
alien --to-deb adacgi-*.i386.rpmThis isn't perfect, for example, /usr/share/doc is now used instead of /usr/doc. However, it's been reported to work. Even better, please provide me with such a packaging!
Warning: If you've installed older versions of AdaCGI in 'zip' or 'tar.gz' format, please note that the packaging conventions have changed slightly. This version of AdaCGI automatically unpacks itself into a subdirectory with the name of the version as part of the directory name, following standard distribution-making conventions. Older versions of AdaCGI unpacked themselves into the current directory, which while convenient for some was inconvenient for others and was not what most distributions do.
On a Unix-like system where you're not using the RPM format, get the tarball, create and move into a new directory, and install as usual. If you use the GNU tools (e.g., essentially any Linux system):
tar xvfz adacgi-*.tarOtherwise, if you're using a Unix-like system, the commands should work fine (you may need to install a version of ``gunzip'' first):
gunzip adacgi-*.tar.gz tar xvf adacgi-*.tarOn a Microsoft-based platform, get the zip file, create and move into a new directory, and install as usual, using a command like this (you might have ``unzip'' instead of ``pkunzip''):
pkunzip adacgi-*.zip
If you want to use the demonstration programs, then you need to compile them. If you're using the RPM version, first copy the demonstration programs to some other directory:
mkdir adacgisample cp /usr/doc/adacgi*/sample/* adacgisample cd adacgisampleFor other formats, just move into the directory with adacgi. Then, for any format, type "make" to build the programs. This assumes that you have a suitable Ada compiler installed, of course; the files use the GNAT naming convention and assume that the compiler can be invoked using ``gnatmake''; adjust for your local situation.
The files cgi.ads and cgi.adb are the actual library; the other files are documentation and example programs. At this time only the RPM files automatically install themselves in a library directory; on other systems you'll need to compile the library into a shared area or simply include the library as part of your server's source code directory. The last "make" only compiles the sample programs.
If during compilations you get messages like
"getenv not found", you probably need to add the C library to the
list of searched libraries. On most systems, that's automatic, but
it isn't for ObjectAda.
Anthony A. Lowe
Impatient to do something? Well, compile the demonstration
programs as described above, and then run the "minimal" program by
typing:
The output will look like this:
Notice that no web server is required here; we can just invoke the
program directly. That's really handy in debugging, because sometimes
when you're interacting with a buggy server program it's hard to
determing why things are failing unless you can see EXACTLY what
is being sent back.
So, how can we send data to this script?
The answer is by setting the REQUEST_METHOD and QUERY_STRING
environment variables.
Setting the REQUEST_METHOD variable to GET causes the library to
get its data from the QUERY_STRING variable.
This QUERY_STRING
environment variable is of the form "fieldname=value"; if there's
more than one field, the entries should be separated by ampersands (&).
If you want the values "=", "&", " ", or "%" in the value, write them
as "%3D", "%26", "%20", and "%25" respectively using the standard URL escaping
mechanism (i.e., characters are replaced with % followed by 2 hexadecimal
digits).
On Unix-compatible systems running an sh-compatible shell
(including Linux running bash), just do the following:
Now, when you re-run ./minimal, you'll see that the program instead
simply lists all of the fields that you've sent and their data.
So, how could you get this running through a web server?
Well, you'll need to copy this program into an area that the web server
accepts for executables.
By implication, that means that your web server will have to be
configured to run programs in certain directories
and that you have permission to write to such a directory.
On a typical Linux system running the Apache web server, such a
directory is probably called "/home/httpd/cgi-bin", and is writable
by root, so on such a
configuration you'd do this to make the server "minimal" available to all:
Assuming that your web server will run programs and you've installed your
server in an appropriate place, now you need to try it out.
Start up a web browser and open up:
You can also see the screenshot showing
the demo.adb program in action.
You can also try out the more useful "search.adb" sample program, which
lets the user specify a file to search and a string;
the search program then lists every line in that file containing
the string.
Search requires a list of files that can be searched, called the
"srchlist"; copy the demo file 'srchlist' to some useful location
(I suggest /home/httpd/srchlist) and edit the srchlist file to be useful
to you.
The srchlist format is:
If you aren't going to place "srchlist" at /home/httpd/srchlist, then
edit the program "search.adb" to change Search_List_Filename to some
other value.
Then compile "search.adb" (with GNAT, a "gnatmake search" will do nicely).
Copy the resuling "search" executable to where the web server can use it
(usually that would be /home/httpd/cgi-bin).
Now send your browser to
http://localhost/cgi-bin/search, and you should see a form that
lets you search.
To use package CGI, "with CGI" in your Ada program.
Package CGI will automatically load the CGI information when your Ada
program begins executing.
CGI handles both "GET" and "POST" forms of CGI data automatically.
The form information from a GET or POST form is loaded into a sequence of
variables; each variable has a Key and a Value.
Package CGI transforms "Isindex" queries into a form with a single key
(named "isindex"), and the key's value is the query value.
Once the main Ada program starts, it can make various calls to the CGI
subprograms to get information or to send information back out.
A typical program using package CGI would first call "CGI.Put_CGI_Header",
which tells the calling HTTP server what kind of information will be returned.
Usually the CGI header is a reply saying "I will reply a generated
HTML document", so that is the default of Put_CGI_Header, but you could
reply something else (for example, a Location: header to automatically
redirect someone to a different URL; see the CGI specification for
information about references which allow you to redirect browsers
elsewhere).
Most CGI programs handle various types of forms, and most should automatically
reply with a blank form if the user hasn't provided a filled-in form.
Thus, your program will probably call CGI.Input_Received, which returns
True if input has been received (and otherwise it returns False).
You should reply with a blank form if CGI.Input_Received is False.
You can then use various routines to query what data values were sent.
You can query either by the name of a variable (what is the value of 'name'?)
or by position (what was the first variable's key name and value sent?):
There are also a number of useful output functions:
Function Get_Environment simply calls the underlying operating system
and requests the value of the given operating system variable; this may
be useful for acquiring less-often-used CGI values.
If the variable does not exist, function Get_Environment replies with
a null string ("").
To set a cookie's value in a remote browser,
call Set_Cookie with the appropriate parameters.
Note that Set_Cookie must be called before Put_CGI_Header.
The expires attribute specifies when the cookie will no longer be stored;
the domain attribute determines which host names will cause the cookie to
be sent (at least two domain levels); the path attribute specifies the
subset of URLs in a domain where the cookie will be returned; and if the
cookie is marked secure, the cookie will only be sent over encrypted
channels (e.g., SSL, using https://).
Cookie values are automatically loaded by this package on initialization.
You can retrieve their values by calling Cookie_Value.
You can retrieve cookies by their key value or by simple index.
Just like CGI form fields, a key can occur multiple times.
Information other than the key and value
(such as expiration time, domain, path, and secure setting) is not available
through AdaCGI, because this information is not sent in the underlying
protocol from the user to the web server.
You can send cookie values to your program without using a web server
by setting the environment variable HTTP_COOKIE.
This has the format "key=value", separated by a semicolon,
using URL escapes.
The distribution includes a sample program, cookie_test,
that prints the "first" cookie and the first value of the cookie
named "problem".
Here's how to try it out on a Unix-like machine using an
sh-like command shell (e.g., a typical Linux system):
Many CGI applications display a number of forms, data, and so on.
For larger applications, I suggest drawing a sort of
``state diagram'' showing the different displays as the nodes
and showing the expected transitions between displayes.
For each display, identify what information is needed for it;
make sure that all the ways to reach that display will provide that
information.
In many cases I find it useful to have some CGI variable indicate the
form desired (say ``command'').
Remember that HTTP is essentially stateless; if you need some data later,
you'll need to send it back to the user to store, or at least store some
sort of identifier so that you can determine which user's data to use.
Also, users can hop directly into any point by bookmarking things or
just writing their own URLs, so
don't depend on users only going through an ``expected path.''
Note: all of the text files are stored in Unix text file format.
MS-DOS users will need to convert them to MS-DOS text file format
(some MS-DOS text editors will do this automatically).
This package has the following known limitations:
As with all CGI programs, there are security ramifications.
In general, ALWAYS check any values sent to you, and be conservative:
identify the list of acceptable values, and reject anything that
doesn't meet that list.
Thus for strings, identify the legal characters and maximum length
you'll accept, and reject anything that doesn't meet those requirements.
Don't do the reverse and identify ``characters you'll prohibit,''
because you'll probably forget an important case.
You may need to escape shell characters.
For numbers, identify minimum and maximum values.
Be very cautious about filenames; beware of filenames with ".." or
"/" in them (it's best not to accept them at all, if you can).
Since the user may not be the actual source for some variables and/or data,
when generating HTML
always send variable data through HTML_Encode first.
That way, the presence of the special reserved characters "&", "<",
">", or """ won't cause problems for the user's browser.
It's worth noting that Ada (and AdaCGI) can easily handle the "NIL"
character (ASCII 0, represented as %00 in URLs).
However, many system functions called by an Ada program assume that
NIL is the end of a string, so calling system functions with such
values may cause surprises.
This isn't really unique to Ada; Perl can also handle NIL and has the
same issues.
If you don't already know them, examine the extant literature on the
subject of CGI security.
Useful resources about CGI security include
Gundavaram's Perl CGI FAQ (particularly the security information),
Kim's CGI book,
Phillips'
safe CGI material,
Stein's WWW Security FAQ,
and
Webber's web
security tips.
You might find my document
"Secure Programming
for Linux HOWTO" useful; I include a number of CGI-relevant tips.
You could also search altavista for "CGI" and "security":
http://www.altavista.com/cgi-bin/query?q=%2BCGI+%2Bsecurity.
CGI is the standard interface between a web server and a web application,
in the same way that HTTP is the standard interface between a web client
(browser) and a web server.
When using CGI there are 3 active components: the web client,
the web server, and the web application (you're writing the web application).
The client sends a request to the web server, the web server
starts up the web application, the web server sends the request data to the
web application using the CGI interface,
the web application replies with data using the CGI interface,
and the web server sends that data on to the web client.
The web application then exits; the next client request will start a
separate copy of the web application.
If there are simultaneously clients making requests, then the web application
will be executed more than once simultaneously (each web application
serves exactly one request).
First, let's cover alternatives to CGI for interfacing to the web,
listing their advantages and disadvantages compared to CGI:
For lots of people, CGI is the way to go to implement web applications.
So, assuming that you've evaluated your options and decided to use CGI,
let's move on.
The next question is, why use Ada?
Well, here are some advantages of using Ada for web applications:
Sounds like you should always use Ada, right?
Nonsense - no engineering decision is ever that simple.
Here are some weaknesses of Ada for building web applications:
At one time, Ada compilers were extremely costly ($20,000 or more), which
was a serious disadvantage. Nowadays, there's an open-source no-cost
high-quality implementation (GNAT) and several other inexpensive
implementations, so that's no longer a relevant disadvantage.
As always, base your decision based on the engineering trade-off.
Finally, even if you're using CGI and Ada, you needn't use this library.
See the resource section for un-CGI and WebAda CGI.
However, neither of those support cookies.
For specific weaknesses, WebAda CGI has buggy encoders,
and un-CGI is both slower than AdaCGI
and introduces data ambiguity when handling data with multiple keys.
In short, I believe that if you're using Ada and CGI, AdaCGI is the
library you want to use.
If it isn't, please let me know why so that it can be that way again :-).
-- Alex Gertsen (AlexGertsen@libertybay.com)
This is version 1.6.
For version 1.5:
Version 1.4 was released 21-Oct-1999.
I changed the library license to the LGPL with minor additions
as described in cgi.ads.
I don't mind proprietary products using this library, but if they
make improvements to this component and "release" its use to users
I want EVERY user to be able to get the improvements.
I also changed the documentation license to be a straight GPL license.
All the demo programs are (C) 1995-1999 David A. Wheeler, licensed under
the GPL license.
The name of the packaged collection of files was changed to "AdaCGI", to
clearly differentiate it from non-Ada CGI interfaces (the actual Ada package
is still named "CGI", for backwards compatibility; after all, there's
no ambiguity when calling from Ada :-) ).
The program "minimal.adb" was changed to be more aesthetically pleasing
(in particular, the submit button comes AFTER the data request).
This version includes a patch by Juergen Pfeifer
(Juergen.Pfeifer@t-online.de) that fixed an ambiguity in search.adb;
it also makes use of his RPM packaging.
I also added a patch by Bob Holcomb (bob_holcomb@hotmail.com)
to directly support cookies, and modified his patch to eliminate
a bug involving semicolons in cookie values.
I added a major documentation section on how to start using the program
(the "trying out" section).
Version 1.3 fixes a nasty bug in the low-level "getenv" routine,
which kept this program from working on OS/2 and some other systems.
Version 1.2 added routines which get a Value and then get a Line or
Line_Count all at once, developed by Clyde Roby (roby@ida.org).
The Ustrings package (used by the search demo) has had two minor changes:
Put_Line to a designated file now works correctly (instead of putting to
the current output), and Get_Line
can read in a line up to the maximum length of an Unbounded_String.
Major additions in version 1.1 are:
Version 1.0 was released June 1995.
This documentation is (C) 1995-1999 David A. Wheeler.
This documentation is free; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This documentation is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Basically the key to making this work in ObjectAda is to
add the Win32 library to the search path (in Project-Settings-Search).
Once it is there, it links fine.
Trying out a sample program
To actually use this library, you need to write a program
(this is, after all, only a library!), test the program, and then
install it so it will be invoked by your web server.
Included are some sample programs so you can try things out
and see how the library works.
./minimal
Content-type: text/html
<HTML><HEAD><TITLE>Minimal Form Demonstration</TITLE>
</HEAD><BODY>
<FORM METHOD=POST>What's your Name?<INPUT NAME="username">
<INPUT TYPE="submit"></FORM>
</BODY></HTML>
The first line means that the program is returning an HTML file
(the common case).
The second (blank) line means that there is no more meta-information
about the data to be returned to the user (such as cookies to be set).
The rest of the lines are a tiny HTML file, which in this case
presents a trivial form.
REQUEST_METHOD="GET"
export REQUEST_METHOD
QUERY_STRING="name=David%20Wheeler&email=dwheeler@dwheeler.com"
export QUERY_STRING
su
cp minimal /home/httpd/cgi-bin
http://localhost/cgi-bin/minimal
replacing "localhost" with the name of the machine the web server is at
if it's not your local machine.
You should see a request to enter your name, a text box for entry,
and a submit button.
You can provide preset values to it by opening the URL using a format like:
http://localhost/cgi-bin/minimal?name=David%20Wheeler&email=dwheeler@dwheeler.com
<FILENAME>,<EXTERNAL NAME>
where <FILENAME> is the local filename, and <EXTERNAL NAME> is the
name that the user will see. The comma is the separator; that means that
filenames can't have commas in them, sorry.
Note that this is both a convenience and a security measure; users only
see an easy-to-read external name, and only files that are specifically
listed as searchable can be searched.
You'll then need to set up reasonable files to search;
I've included /usr/dict/words as a sample entry because many systems
have such a file.
Details on Ada 95 Binding to CGI
Now, let's talk about how to write your own programs using this library.
Minimal Example
Here is a minimal example. Procedure "Minimal" always replies with an
HTML document. If input is received, the document is simply a list
of the variable values. If no input is received, procedure Minimal
replies with a simple fill-in form:
with CGI, Text_IO; use CGI, Text_IO;
procedure Minimal is
-- Demonstrate CGI interface.
-- To run this program directly (without an HTTP server), set the
-- environment variable REQUEST_METHOD to "GET" and the variable
-- QUERY_STRING to either "" or "x=a&y=b".
begin
-- First, declare that we'll regurn a generated HTML document:
Put_CGI_Header;
-- Now send the top of a typical HTML document, which is
-- <HTML><HEAD><TITLE>title</TITLE></HEAD><BODY>
Put_HTML_Head("Minimal Form Demonstration");
if CGI.Input_Received then -- Check if input was received.
Put_Variables; -- Input received; show all variable values.
else
-- No input received; reply with a simple HTML form.
Put_Line("<FORM METHOD=POST>What's your Name?<INPUT NAME=""name"">" &
"<INPUT TYPE=""submit""></FORM>");
end if;
Put_HTML_Tail; -- End the HTML document, sending </BODY></HTML>
end Minimal;
Procedure Minimal is stored in file minimal.adb.
More sophisticated sample programs are demo.adb and search.adb.
Cookies
Cookies are supported by this package.
A "cookie" is simply a value sent by a web server to a web browser; from
then on, the web browser will respond with that value when reconnecting
with that server.
You should be aware that cookies can be used to
reduce user anonymity, so some users intentionally disable cookies
(see the references below for more about cookie controversies).
Also, cookie data is intended to be small; a web user might not store
more than 20 cookies per server, cookies larger than 4K, or 300 cookies total.
If you need more, just store an ID with the cookie and store the rest
of the data on the server.
HTTP_COOKIE="first_cookie=first_value;problem=my%20problem"
export HTTP_COOKIE
./test_cookie
Contents of AdaCGI Distribution
File adacgi.zip is
the distribution collection of AdaCGI.
It contains the following files:
cgi.html - Documentation for AdaCGI.
cgi-doc.htm - A duplicate of cgi.html (see README for an explanation).
cgi.ads - The Ada 95 package specification for the AdaCGI library.
cgi.adb - The Ada 95 package body for the AdaCGI library.
minimal.adb - A minimal demonstration of how to use the library.
demo.adb - A larger demonstration of how to use the library.
search.adb - A larger demo that searches a set of files.
test_cookie - A demo for getting cookie values.
test_send.adb - A demo for setting cookie values.
makefile - The makefile to compile demo and minimal using GNAT.
README - A short list of the files.
Advantages and Disadvantages: CGI, Ada, AdaCGI
No tool is perfect, or appropriate for all circumstances.
Here are some advantages and disadvantages of CGI and Ada for web applications;
look at these and other information to determine if they're a good
match for your application.
Another advantage of FastCGI is that
inter-application locking is potentially eliminated.
I can't thank you enough for your great creation! I have been extensively
using the CGI package (version 1.5) in the last couple of weeks and have
totally fallen in love with it! It is simple and does everything one could
ask for! So thank you, I don't know how I could put together my project
without it!