Entirely obsolete and probably horrible, I wrote this in the 90s to make it easier to put together CGI scripts. It got some traction within my university, but nowhere else, particularly. I include it here because I'm all nostalgic.
Beej's CGI library (BCGI) is a library of C functions to handle WWW forms and the Common Gateway Interface [1]. This library will allow a C program to handle both GET and POST methods of form information transmission , ISINDEX, and click maps with the ISMAP tag. Some primitive functions are included for region detection within a clickable map, as well.
Using the library to handle form information is somewhat simple. When you
compile a program, you want to compile in the BCGI library, and link it to the
math library (-lm
on Unix, usually) because BGCI makes a call to sqrt()
for
the distance()
function.
Let's go by example, and construct a simple form that handles POST method data.
Here is a HTML document that handles the form. Construction of form info is available on the Web [2] along with sample CGI source [3], and is beyond the scope of this document.
<form METHOD=POST ACTION="monsearch.cgi">
Enter the monster's character <input NAME="mchar" SIZE=2><br>
Enter your player's level <input NAME="plev" SIZE=3><br>
<input TYPE=submit value="Gimme the info"> or <input TYPE=reset>
</form>
This simple HTML page will call up a script called monsearch.cgi. This is simply the executable from a C program that uses BCGI. Here is the C program source:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "bcgi.h"
#define MAXCOMMANDLINE 255
main()
{
char *p, *buf, commandline[MAXCOMMANDLINE], mchar;
char tmp[200];
int plev,i=0;
char *arg[12];
printf("Content-Type: text/html\n\n");
if (strcmp(get_request_method(), "POST")) {
printf("monsearch: REQUEST_METHOD must be POST!\n");
exit(1);
}
printf("<html><head><title>Monster memory search results</title>");
printf("<head>\n");
printf("<body><h1>Monster memory search results</h1>\n<hr>\n<pre>\n");
if ((buf=malloc(get_content_length()+1)) == NULL) {
printf("Error: cannot allocate space for buffer<p></body></html>");
exit(1);
}
strcpy(commandline, "/user/s2/beej/public_html/moria/mon -len 64");
get_pdata(buf, get_content_length()+1);
p = getvar(buf, "mchar");
if (p != NULL && *p != '\0') {
strcpy(tmp,p);
escape(tmp);
sprintf(commandline+strlen(commandline), " -mchar %s",tmp);
}
p = getvar(buf, "plev");
if (p != NULL && *p != '\0') {
strcpy(tmp,p);
escape(tmp);
sprintf(commandline+strlen(commandline), " -plev %s", p);
}
fflush(stdout);
system(commandline);
fflush(stdout);
printf("</pre><hr></body></html>");
}
As with the POST method, the first output is that of the header (in this case
only Content-Type:
) followed by the requested document information.
The first step this program takes is to make sure that the REQUEST_METHOD
environment variable is set to POST
. It accomplishes this by calling the
function get_request_method(). The purpose behind this step is for "CGI
compliance" [4]. Leave it out if you're lazy. ;-)
Next, a buffer is allocated to hold all of the POST data that is passed through
stdin. The POST data is read into the buffer with a call to get_pdata()
.
Note that the buffer must be large enough to accommodate all of the POST data,
followed by a terminating null character. In the initial call to malloc
, the
size of the post data is obtained through a call to get_content_length()
.
Next, we search the buffer for the variable mchar
. (Remember this is the name
of the variable that we used in the NAME=
field in the HTML form document.)
The value returned is a pointer to that null terminated data. (The maximum
length of this data is defined in the library header file. Note that if you
change this value, you must recompile the library.)
A call is then made to escape()
. This function prepends a backslash \
character to any characters that may have special meaning to a shell. Since we
are using user entered options to construct a command line for system()
, there
could be a security risk involved if we do not call escape()
. See Security
Considerations below.
The process is then repeated with plev
. Note that getvar()
will return
NULL
if the variable is not found, but will return a pointer to an empty
string if the user didn't enter any data there.
Finally, the actual call to system()
is padded with fflush()
calls to sync
the output.
For method GET
and ISINDEX
, the process is similar, except no call to
get_pdata()
is made (obviously). The data can be retrieved with
get_query_string()
, or through the command line options (if you so desire.)
You can then call getvar()
with the results of get_query_string()
to
retrieve actual variable information.
If you're using using the ISMAP
tag option, the mouse coordinates of the click
can be retrieved from the command line, or from get_query_string()
. The
coordinates will be in the form X,Y
.
There is a document on the Web that deals security considerations [5] and this
should be read before exposing your form handler to the web. If you are
careless, it might be possible for people to execute commands on your local
machine. The escape()
function is one of those included for your protection.
An ounce of prevention...
int distance(int x1, int y1, int x2, int y2)
Returns the distance between two points (x1,y1) and (x2,y2). Useful for calculating distance between a click point and another point.
char *escape(char *s)
Inserts a leading \
before any characters that might be useful to the shell.
This is included to help cover possible security risks when building a command
line with user's input. The string s must have enough room to hold the
additional backslashes. Finally, escape returns a pointer to the escaped string.
char *getvar(char *buf, char *var)
Searches a buffer created with get_pdata()
for a variable with the name
pointed to by var. getvar()
returns a pointer to a null terminated string
containing the data. The maximum length of this string is defined in the BCGI
header file. Subsequent calls to getvar()
with the var parameter set to NULL
cause the buffer to be searched for additional occurances of the variable
initially specified.
int get_content_length(void)
Returns as in integer the value of the CONTENT_LENGTH
environment variable.
Useful in determining the size of buffer needed for a get_pdata()
call. This
function returns NULL
on error.
char *get_content_type(void)
Returns a pointer to the environment variable CONTENT_TYPE
. This function
returns NULL
on error.
char *get_gateway_interface(void)
Returns a pointer to the environment variable GATEWAY_INTERFACE
. This function
returns NULL
on error.
char *get_http_user_agent(void)
Returns a pointer to the environment variable HTTP_USER_AGENT
. This function
returns NULL
on error.
char *get_http_accept(void)
Returns a pointer to the environment variable HTTP_ACCEPT
. This function
returns NULL
on error.
void get_pdata(char *buf, int maxsize)
Fills a buffer of size maxsize
with POST method data read from stdin
. If
the buffer is not large enough to hold the data AND a null terminating
character, the input data is cut short, and a null character is placed at the
end of the string.
char *get_query_string(void)
Returns a pointer to the environment variable QUERY_STRING. This value can be used for method GET, or the tag ISINDEX, or the tag option ISMAP. This function returns NULL on error.
char *get_remote_addr(void)
Returns a pointer to the environment variable REMOTE_ADDR
. This is the IP
address of the client that is accessing your document. This function returns
NULL
on error.
char *get_remote_host(void)
Returns a pointer to the environment variable REMOTE_HOST
. This is the host
name of the client that is accessing your document. This function returns NULL
on error.
char *get_request_method(void)
Returns a pointer to the environment variable REQUEST_METHOD
. This function
returns NULL
on error.
char *get_script_name(void)
Returns a pointer to the environment variable SCRIPT_NAME
. This function
returns NULL
on error.
char *get_server_name(void)
Returns a pointer to the environment variable SERVER_NAME
. This function
returns NULL
on error.
unsigned short get_server_port(void)
Returns the port that your server is listining on or 0
if an error occurs.
char *get_server_protocol(void)
Returns a pointer to the environment variable SERVER_PROTOCOL
. This function
returns NULL
on error.
char *get_server_software(void)
Returns a pointer to the environment variable SERVER_SOFTWARE
. This function
returns NULL
on error.
int nearest(int x, int y, int point[], int numpoints)
Returns the index of the coordinate pair in the point array, with the number of
points in the array defined by numpoints, that is nearest to the point
(x
,y
). This function returns -1
if numpoints is 0
or any other error
occurs. If there is a tie in distance, the first point in the point array will
be matched.
void un_url(char *s)
Collapses a string that is encoded in URL form into a normal string.
int xyinrect(int x, int y, int x1, int y1, int x2, int y2)
Returns true if the point (x
,y
) is inside the rectangle with upper left
coordinate (x1
,y1
) and lower right coordinate (x2
,y2
), inclusive.
int xyincircle(int x, int y, int cx, int cy, int r);
Returns true if the point (x
,y
) is inside or on the circle with center
(cx
,cy
) and radius r
.
-
The Common Gateway Interface http://hoohoo.ncsa.uiuc.edu/cgi/overview.html
-
FORM information http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/fill-out-forms/overview.html
-
CGI sample source ftp://ftp.ncsa.uiuc.edu/Web/httpd/Unix/ncsa_httpd/cgi/
-
CGI compliance http://hoohoo.ncsa.uiuc.edu/cgi/from-htbin.html
-
Security considerations http://hoohoo.ncsa.uiuc.edu/cgi/security.html