developer.com
developerdirect.com
htmlgoodies.com
javagoodies.com
jars.com
intranetjournal.com
javascripts.com
|
All Categories :
CGI & PERL
Appendix E
cgihtml Reference Guide
CONTENTS
The cgihtml library is a collection of routines written in C for
parsing Common Gateway Interface input and for outputting HyperText
Markup Language. These tasks, which normally require several lines
of C, can be reduced to just a few lines. Using cgihtml enables
you to focus on the main algorithms of your code rather than on
laborious parsing and output routines.
The cgihtml routines were written for UNIX machines. The library
has been successfully ported to Windows NT and Windows 3.1, and
probably could be ported to other operating systems fairly easily.
The cgihtml library includes the following files:
README | A file you should read first
|
CHANGES | Version revision information
|
TODO | Things or changes I want to implement eventually
|
docs/ | Documentation directory
|
debug-cgi.sh | Shell script to help debug CGI code
|
Makefile | A makefile to compile and install cgihtml
|
cgi-lib.c | Source code |
html-lib.c | Source code |
llist.c | Source code |
string-lib.c | Source code |
cgi-lib.h | Header file for routines
|
html-lib.h | Header file for routines
|
llist.h | Header file for routines
|
string-lib.h | Header file for routines
|
query-results.c | Example program
|
mail.cgi.c | Example program
|
ignore.cgi.c | Example program
|
index-sample.cgi.c | Example program
|
test.cgi.c | Example program
|
The latest version of cgihtml is always available at
<URL:ftp://hcs.harvard.edu/pub/web/tools/cgihtml.tar.gz>
The cgihtml home page, which contains links to documentation and
other cgihtml resources, is available at
<URL:http://hcs.harvard.edu/~eekim/web/cgihtml/>
You can subscribe to the cgihtml mailing list for the latest cgihtml
information and announcements. To subscribe, send e-mail to majordomo@hcs.harvard.edu
with the following body:
subscribe cgihtml
The cgihtml archive comes in one of three different compressed
formats: gzip (.gz), compress (.Z), and pkzip (.zip). To unpack
the gzipped or UNIX-compressed archive, try the following commands:
% gzip -c cgihtml.tar.gz | tar xvof -
or
% zcat cgihtml.tar.Z | tar xvof -
To unpack the pkzipped archive, use the following command:
C:\> pkunzip -a cgihtml.zip
After you unpack the distribution, you need to compile it. First,
look over the makefile, which by default looks like this:
# Makefile for cgihtml.a
# $Id: Makefile,v 1.4 1996/02/21 13:42:21 eekim Exp
eekim $
CC= gcc
RANLIB = ranlib
CFLAGS= -g -Wall -DUNIX
CGI-BIN= /home/eekim/Web/cgi-bin
all: cgihtml.a query-results mail.cgi index-sample.cgi ignore.cgi
test.cgi
cgihtml.a: cgi-lib.o llist.o html-lib.o string-lib.o
ar cr cgihtml.a cgi-lib.o llist.o html-lib.o
string-lib.o
$(RANLIB) cgihtml.a
query-results: query-results.o cgihtml.a
$(CC) query-results.o cgihtml.a -o query-results
mail.cgi: mail.cgi.o cgihtml.a
$(CC) mail.cgi.o cgihtml.a -o mail.cgi
index-sample.cgi: index-sample.cgi.o cgihtml.a
$(CC) index-sample.cgi.o cgihtml.a -o index-sample.cgi
ignore.cgi: ignore.cgi.o cgihtml.a
$(CC) ignore.cgi.o cgihtml.a -o ignore.cgi
test.cgi: test.cgi.o cgihtml.a
$(CC) test.cgi.o cgihtml.a -o test.cgi
install: all
chmod a+x query-results mail.cgi index-sample.cgi
ignore.cgi test.cgi
strip query-results mail.cgi index-sample.cgi
gnore.cgi test.cgi
mv -f query-results mail.cgi index-sample.cgi
ignore.cgi test.cgi $(CGI-BIN)
clean:
rm -f *.o cgihtml.a
rm -f query-results
mail.cgi index-sample.cgi ignore.cgi test.cgi
You might want to change a few options. If you are compiling this
package on any non-UNIX platform, especially Windows NT, comment
out the -DUNIX reference,
as follows:
CFLAGS= -g -Wall #-DUNIX
You can also change -g to
-O2 if you don't want debugging
information compiled into the library. If you do not have the
Gnu C Compiler, change the CC
variable to the name of your C compiler. It must be ANSI-compliant.
Finally, change the value of CGI-BIN
to the value of your cgi-bin
directory.
To compile the library, type the following:
% make cgihtml.a
This command builds the library cgihtml.a. To compile the library
as well as all the example programs, type the following:
% make all
While you compile the libraries on various UNIX machines, you
might have trouble with the ranlib
command. If your system doesn't seem to have this command, you
most likely don't need it. Set the RANLIB
variable in the makefile to True.
After you successfully build cgihtml.a, copy it and all the header
files to your CGI source code directory.
When you use cgihtml, consider what header files you must include
and what variables you need to initialize. The possible header
files are
cgi-lib.h
html-lib.h
llist.h
string-lib.h
You do not have to include llist.h if you include cgi-lib.h because
cgi-lib.h implicitly includes llist.h.
If you are parsing CGI input, you must take the following steps:
- Declare a linked list.
- Parse the data into the linked list.
- Manipulate the data.
- Clear the linked list.
The best way to understand how to use cgihtml properly is by example.
The following is a basic template for all CGI applications:
/* template using cgihtml.a library */
#include <stdio.h> /*
standard io functions */
#include "cgi-lib.h" /* CGI-related routines
*/
#include "html-lib.h" /* HTML-related routines */
int main()
{
llist entries; /* define a linked list;
this is where the entries */
/*
are stored. */
read_cgi_input(&entries); /* parse
the form data and add it to the list */
/* The data is now in a very usable form. To search
the list entries
by name, call the function:
cgi_val(entries,
"nameofentry")
which returns a pointer to the value
associated with "nameofentry". */
html_header(); /*
print HTML MIME header */
html_begin("Output"); /*
send appropriate HTML headers with title */
/*
Output */
/* display whatever data you wish, probably with printf()
*/
html_end(); /*
send appropriate HTML end footers ( ) */
list_clear(&entries); /* free
up the pointers in the linked list */
return 0; send
exit code of 0 -- successful */
}
Most of the C code throughout this book uses cgihtml, so look
through the other chapters for more examples.
To compile your program with the library, include the file cgihtml.a
when you link your object files. For example, if your main object
file is program.cgi.o, the following should work successfully:
% gcc -o program.cgi program.cgi.o cgihtml.a
This section contains listings and explanations for the routines
contained in the cgihtml library.
Variables
cgi-lib.h defines constants for the standard CGI environment variables.
The value of the environment variable QUERY_STRING,
for example, is stored in the constant QUERY_STRING
in cgi-lib.h. Here is a list of the constants:
SERVER_SOFTWARE
SERVER_NAME
GATEWAY_INTERFACE
SERVER_PROTOCOL
SERVER_PORT
REQUEST_METHOD
PATH_INFO
PATH_TRANSLATED
SCRIPT_NAME
QUERY_STRING
REMOTE_HOST
REMOTE_ADDR
AUTH_TYPE
REMOTE_USER
REMOTE_IDENT
CONTENT_TYPE
CONTENT_LENGTH
Functions
The following is a listing of the functions. The following sections
are the global definitions needed by the functions.
void die();
short accept_image()
void unescape_url()
int read_cgi_input(llist *entries);
char* cgi_val(llist l, char *name);
char **cgi_val_multi(llist l, char *name);
void print_cgi_env();
void print_entries(llist l);
char* escape_input(char *str);
short is_form_empty(llist l);
void die();
You should use die() in conjunction
with UNIX's signal handling libraries. To prevent runaway processes,
you should send an alarm signal after a certain amount of time
and call die() upon receiving
this signal.
At this stage, die() is somewhat
primitive. It displays a simple error message and kills the program
gracefully.
If you are not using UNIX, then die()
is unavailable.
short accept_image();
The function accept_image()
determines whether the browser accepts pictures. It does so by
checking the HTTP_ACCEPT
environment variable for an image MIME type. It returns a 1
if the browser accepts graphics, a 0
otherwise.
void unescape_url();
The function unescape_url()
converts escaped URI values into their character form. read_cgi_input()
calls this function. You rarely, if ever, need to access this
function directly, but it is made available in case you do.
int read_cgi_input(llist *entries);
This routine parses the raw CGI data passed from the browser to
the server and adds each associated name and value to the linked
list entries. It parses information transmitted using both the
GET and POST
method. If it receives no information, it returns a 0;
otherwise, it returns a 1.
Remember that receiving no information is not the same as receiving
an empty form. An empty form means that the values are empty,
but read_cgi_input() still
reads the names of each field.
char* cgi_val(llist l, char *name);
The routine cgi_val() searches
the linked list for the value of the entry named name
and returns the value if it finds it. If it cannot find an entry
with name name, it returns
a null string.
char** cgi_val_multi(llist l, char
*name);
This routine is the same as cgi_val()
except that it returns multiple values with the same name to an
array of strings. It returns a null string if it cannot find an
entry with name name.
void print_cgi_env();
This routine prints the environment variables defined in cgi-lib.h.
It prints (null) if the variables
are empty.
void print_entries(llist l);
This generic routine iterates through the linked list and prints
each name and associated value in HTML form. It uses the <dl>
list format to display the list.
char* escape_input(char *str);
The routine escape_input()
"escapes" shell metacharacters in the string. Because
I could not find any authoritative documentation on what characters
are considered metacharacters, escape_input()
escapes all nonalphanumeric characters.
C routines including system()
and popen() open up a Bourne
shell process before running. If you do not escape shell metacharacters
in the input (prefix metacharacters with a backslash), then malicious
users might be able to take advantage of your system.
short is_form_empty(llist l);
This routine returns a 1
if an empty form is submitted; it returns 0
otherwise.
The following explains the contents of the html-lib.h header file.
Functions
The following are listings the functions. The following sections
are the global definitions needed by the functions.
void html_header();
void mime_header(char *mime);
void nph_header(char *status);
void show_html_page(char *loc)
void status(char *status);
void pragma(char *msg);
void html_begin(char *title);
void html_end();
void h1(char *str); ... void h6(char *str);
void hidden(char *name, char *value);
void html_header();
The routine html_header()
prints a MIME-compliant header that should precede the output
of any HTML document from a CGI script. It simply prints the following
line and a blank line to stdout:
Content-Type: text/html
void mime_header(char *mime);
This routine enables you to print any MIME header. If you are
about to send a GIF image to the standard output from your C CGI
program, for example, precede your program with the following:
mime_header("image/gif");
/* now you can send your GIF file to stdout */
The mime_header() routine
simply prints Content-Type:
followed by your specified MIME header and a blank line.
void nph_header(char *status);
This routine sends a standard HTTP header for direct communication
with the client using no parse header. status
is the status code followed by the status message. To send a No
Content header, for example, you can use the following:
nph_header("204 No Content");
html_header();
These lines send the following:
HTTP/1.0 204 No Content
Server: CGI using cgihtml
Content-Type: text/html
The nph_header() function
does not send a blank line after printing the headers, so you
must follow it with either another header or a blank line. Also,
scripts using this function must have nph-
preceding their filenames.
void show_html_page(char *loc);
This routine sends a Location:
header. loc is the location
of the HTML file you want sent to the browser. If you want to
send the root index file from the CGI program, for example, use
the following line:
show_html_page("/index.html");
void status(char *status);
This routine sends an HTTP Status
header. status is a status
code followed by a status message. To send a status code of 302
(temporary redirection) followed by a location header, for example,
use the following:
status("302 Temporarily Moved");
show_html_page("http://hcs.harvard.edu/");
The status() function does
not print a blank line following the header, so you must follow
it with either another function that does output a blank line
or an explicit printf("\r\n");.
void pragma(char *msg);
This routine sends an HTTP pragma
header. It is most commonly used to tell the browser not to cache
the document. Here's an example:
pragma("No-cache");
html_header();
As with status(), pragma()
does not print a blank line following the header.
void html_begin(char *title);
The html_begin() function
sends somewhat standard HTML tags that should generally be at
the top of every HTML file. It sends the following:
<html> <head>
<title>title</title>
</head>
<body>
void html_end();
The html_end() function is
the complement to html_begin(),
sending the following HTML:
</body> </html>
Note that neither html_begin()
nor html_end() are necessary
for your CGI scripts to output HTML, but they are good style,
and I encourage use of these routines.
void h1(char *str);
This routine surrounds str
with the headline 1 tags: <h1>.
Routines h2(), h3(),
h4(), h5(),
and h6() also do the same.
void hidden(char *name, char *value);
This routine prints an <input type=hidden>
tag with name *name and value
*value. It is useful for
maintaining state.
For most scripts, you will most likely never have to use any of
the link list routines available, with the exception of list_clear(),
because cgi-lib.h handles most common linked list manipulation
almost transparently. You might sometimes want to manipulate the
information directly, however, or perform special functions on
each entry, in which case these routines can be useful.
Variables
The following are listings of the functions. The following sections
are the global definitions needed by the functions.
typedef struct {
char *name;
char *value;
} entrytype;
typedef struct _node {
entrytype entry;
struct _node* next;
} node;
typedef struct {
node* head;
} llist;
Functions
The following are listings of the functions. The following sections
are the global definitions needed by the functions.
void list_create(llist *l);
node* list_next(node* w);
short on_list(llist *l, node* w);
short on_list_debug(llist *l, node* w);
void list_traverse(llist *l, void (*visit)(entrytype item));
node* list_insafter(llist* l, node* w, entrytype item);
void list_clear(llist* l);
void list_create(llist *l);
The routine list_create()
creates and initializes the list, and it should be called at the
beginning of every CGI script using this library to parse input.
node* list_next(node* w);
The routine list_next() returns
the next node on the list.
short on_list(llist *l, node* w);
The routine on_list() returns
a 1 if the node
w is on the linked list l; otherwise, it returns a
0.
short on_list_debug(llist *l, node*
w);
The previous routine makes the assumption that your linked list
routines are bug-free, a possibly bad assumption. If you are
using linked list routines and on_list()
doesn't return the correct value, try using on_list_debug(),
which makes no assumptions, is almost definitely reliable, but
is a little slower than the other routine.
void list_traverse(llist *l,void
(*visit)(entrytype item));
The routine list_traverse()
lets you pass a pointer to a function that manipulates each entry
on the list.
To use this routine, you must create a function that takes as
its argument a variable of type entrytype.
If you want to write your own print_entries()
function, for example, you could do the following:
void print_element(entrytype item);
{
printf("%s = %s\n",item.name,item.value);
}
void print_entries(llist entries);
{
list_traverse(&stuff, print_element);
}
node* list_insafter(llist* l, node*
w, entrytype item);
The routine list_insafter()
adds the entry item after the node w
and returns the pointer to the newly created node. I didn't write
a function to insert before a node because my CGI functions don't
need one.
void list_clear(llist* l);
This routine frees up the memory used by the linked list after
you are finished with it. It is imperative that you call this
function at the end of every program that calls read_cgi_input().
This section lists and describes the contents of string-lib.h.
Functions
The following are listings of the functions. The following sections
are the global definitions needed by the functions.
char* newstr(char *str);
char *substr(char *str, int offset, int len);
char *replace_ltgt(char *str);
char* newstr(char *str);
The function newstr() allocates
memory and returns a copy of str.
Use this function to allocate memory correctly and copy strings.
char *substr(char *str, int offset,
int len);
This routine is equivalent to the Perl function with the same
name. It returns a substring of str
of length len starting from
offset away from either the
beginning or end of the string (if it's positive or negative,
respectively).
char *replace_ltgt(char *str);
This routine replaces less-than (<)
and greater-than (>) signs
with their HTML-escaped equivalents (<
and >, respectively).
Listings E.1 through E.8 provide the complete source code for
cgihtml.
Listing E.1. llist.h.
/* llist.h - Header file for llist.c
Eugene Kim, eekim@fas.harvard.edu
$Id: llist.h,v 1.2 1995/08/13 21:30:53 eekim
Exp $
Copyright (C) 1995 Eugene Eric Kim
All Rights Reserved
*/
typedef struct {
char *name;
char *value;
} entrytype;
typedef struct _node {
entrytype entry;
struct _node* next;
} node;
typedef struct {
node* head;
} llist;
void list_create(llist *l);
node* list_next(node* w);
short on_list(llist *l, node* w);
short on_list_debug(llist *l, node* w);
void list_traverse(llist *l, void (*visit)(entrytype item));
node* list_insafter(llist* l, node* w, entrytype item);
void list_clear(llist* l);
Listing E.2. llist.c.
/* llist.c - Minimal linked list library
for revised CGI C library
Eugene Kim, eekim@fas.harvard.edu
$Id: llist.c,v 1.2 1995/08/13 21:30:53 eekim
Exp $
Copyright (C) 1995 Eugene Eric Kim
All Rights Reserved
*/
#include <stdlib.h>
#include <string.h>
#include "llist.h"
#include "string-lib.h"
void list_create(llist *l)
{
(*l).head = 0;
}
node* list_next(node* w)
{
return (*w).next;
}
short on_list(llist *l, node* w)
{
return (w != 0);
}
short on_list_debug(llist *l, node* w)
{
node* current;
if (w == 0)
return 0;
else {
current = (*l).head;
while ( (current != w) && (current
!= 0) )
current = (*current).next;
if (current == w)
return 1;
else
return 0;
}
}
void list_traverse(llist *l, void (*visit)(entrytype item))
{
node* current;
current = (*l).head;
while (current != 0) {
(*visit)((*current).entry);
current = (*current).next;
}
}
node* list_insafter(llist* l, node* w, entrytype item)
{
node* newnode = malloc(sizeof(node));
(*newnode).entry.name = newstr(item.name);
(*newnode).entry.value = newstr(item.value);
if ( (*l).head == 0) {
(*newnode).next = 0;
(*l).head = newnode;
}
else if (!on_list(l,w))
/* ERROR: can't insert item after w since
w is not on l */
exit(1);
else {
/* insert node after */
if (newnode == 0) /* can assume that w
!= NULL */
/* ERROR: nothing to insert
after */
exit(1);
else {
(*newnode).next = (*w).next;
(*w).next = newnode;
}
}
return newnode;
}
void list_clear(llist* l)
{
node* lastnode;
node* nexttolast;
node* current;
while ((*l).head != 0) {
current = (*l).head;
if ((*current).next == 0) {
free(current);
current = 0;
(*l).head = current;
}
else {
while ( (*current).next !=
0 ) {
nexttolast = current;
lastnode = (*current).next;
current = lastnode;
}
free(lastnode);
(*nexttolast).next = 0;
}
}
}
Listing E.3. string-lib.h.
/* string-lib.h - headers for string-lib.c
$Id: string-lib.h,v 1.1 1995/08/13
21:30:53 eekim Exp $
*/
char *newstr(char *str);
char *substr(char *str, int offset, int len);
char *replace_ltgt(char *str);
Listing E.4. string-lib.c.
/* string-lib.c - generic string processing
routines
$Id: string-lib.c,v 1.2 1996/02/18
22:33:27 eekim Exp eekim $
Copyright © 1996 Eugene Eric Kim
All Rights Reserved.
*/
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include "string-lib.h"
char *newstr(char *str)
{
return strcpy((char *)malloc(sizeof(char) * strlen(str)+1),str);
}
char *substr(char *str, int offset, int len)
{
int slen, start, i;
char *nstr;
if (str == NULL)
return NULL;
else
slen = strlen(str);
nstr = malloc(sizeof(char) * slen + 1);
if (offset >= 0)
start = offset;
else
start = slen + offset - 1;
if ( (start < 0) || (start > slen) ) /* invalid
offset */
return NULL;
for (i = start; i < slen; i++)
nstr[i - start] = str[i];
nstr[slen] = '\0';
return nstr;
}
char *replace_ltgt(char *str)
{
int i,j = 0;
char *new = malloc(sizeof(char) * (strlen(str) * 4
+ 1));
for (i = 0; i < strlen(str); i++) {
if (str[i] == '<') {
new[j] = '&';
new[j+1] = 'l';
new[j+2] = 't';
new[j+3] = ';';
j += 3;
}
else if (str[i] == '>') {
new[j] = '&';
new[j+1] = 'g';
new[j+2] = 't';
new[j+3] = ';';
j += 3;
}
else
new[j] = str[i];
j++;
}
new[j] = '\0';
return new;
}
Listing E.5. cgi-lib.h.
/* cgi-lib.h - header file for cgi-lib.c
Eugene Kim, eekim@fas.harvard.edu
$Id: cgi-lib.h,v 1.4 1996/02/21 13:40:41 eekim
Exp eekim $
Copyright (C) 1996 Eugene Eric Kim
All Rights Reserved
*/
#include <stdlib.h>
#include "llist.h"
/* CGI Environment Variables */
#define SERVER_SOFTWARE getenv("SERVER_SOFTWARE")
#define SERVER_NAME getenv("SERVER_NAME")
#define GATEWAY_INTERFACE getenv("GATEWAY_INTERFACE")
#define SERVER_PROTOCOL getenv("SERVER_PROTOCOL")
#define SERVER_PORT getenv("SERVER_PORT")
#define REQUEST_METHOD getenv("REQUEST_METHOD")
#define PATH_INFO getenv("PATH_INFO")
#define PATH_TRANSLATED getenv("PATH_TRANSLATED")
#define SCRIPT_NAME getenv("SCRIPT_NAME")
#define QUERY_STRING getenv("QUERY_STRING")
#define REMOTE_HOST getenv("REMOTE_HOST")
#define REMOTE_ADDR getenv("REMOTE_ADDR")
#define AUTH_TYPE getenv("AUTH_TYPE")
#define REMOTE_USER getenv("REMOTE_USER")
#define REMOTE_IDENT getenv("REMOTE_IDENT")
#define CONTENT_TYPE getenv("CONTENT_TYPE")
#define CONTENT_LENGTH getenv("CONTENT_LENGTH")
#ifdef UNIX
void die();
#endif
short accept_image();
/* form processing routines */
void unescape_url(char *url);
int read_cgi_input(llist* entries);
char *cgi_val(llist l,char *name);
char **cgi_val_multi(llist l, char *name);
/* miscellaneous CGI routines */
void print_cgi_env();
void print_entries(llist l);
char *escape_input(char *str);
short is_form_empty(llist l);
Listing E.6. cgi-lib.c.
/* cgi-lib.c - C routines that make writing
CGI scripts in C a breeze
Eugene Kim, <eekim@fas.harvard.edu>
$Id: cgi-lib.c,v 1.7 1996/02/21 13:40:27 eekim
Exp eekim $
Motivation: Perl is a much more convenient language
to use when
writing CGI scripts. Unfortunately,
it is also a larger drain on
the system. Hopefully, these routines
will make writing CGI
scripts just as easy in C.
Copyright (C) 1996 Eugene Eric Kim
All Rights Reserved
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "cgi-lib.h"
#include "html-lib.h"
#include "string-lib.h"
#ifdef UNIX
void die()
{
/* this routine needs some beefing up. I hope to eventually add:
o more detailed information
o error logging
o perhaps sending a header which
signifies an internal error
*/
html_header();
html_begin("CGI Error");
printf("<h1>CGI Error</h1>\r\n");
printf("An internal error has occurred. Please
contact your web\r\n");
printf("administrator. Thanks.\r\n");
html_end();
exit(1);
}
#endif
short accept_image()
{
char *httpaccept = getenv("HTTP_ACCEPT");
if (strstr(httpaccept,"image") == NULL)
return 0;
else
return 1;
}
/* x2c() and unescape_url() stolen from NCSA code */
char x2c(char *what)
{
register char digit;
digit = (what[0] >= 'A' ? ((what[0] & 0xdf)
- 'A')+10 : (what[0] - '0'));
digit *= 16;
digit += (what[1] >= 'A' ? ((what[1] & 0xdf)
- 'A')+10 : (what[1] - '0'));
return(digit);
}
void unescape_url(char *url)
{
register int x,y;
for (x=0,y=0; url[y]; ++x,++y) {
if((url[x] = url[y]) == '%') {
url[x] = x2c(&url[y+1]);
y+=2;
}
}
url[x] = '\0';
}
int read_cgi_input(llist* entries)
{
int i,j,content_length;
short NM = 1;
char *input;
entrytype entry;
node* window;
list_create(entries);
window = (*entries).head;
/* get the input */
if (REQUEST_METHOD == NULL) {
/* perhaps add an HTML error message here
for robustness sake;
don't know whether CGI
is running from command line or from
web server. In fact,
maybe a general CGI error routine might
be nice, sort of a generalization
of die(). */
fprintf(stderr,"caught by cgihtml:
REQUEST_METHOD is null\n");
exit(1);
}
if (!strcmp(REQUEST_METHOD,"POST")) {
if (CONTENT_LENGTH != NULL) {
content_length = atoi(CONTENT_LENGTH);
input = malloc(sizeof(char)
* content_length + 1);
if (fread(input,sizeof(char),content_length,stdin)
!= content_length) {
/* consistency error. */
fprintf(stderr,"caught by cgihtml:
input length < CONTENT_LENGTH\n");
exit(1);
}
}
else { /* null content length */
/* again, perhaps more detailed,
robust error message here */
fprintf(stderr,"caught
by cgihtml: CONTENT_LENGTH is null\n");
exit(1);
}
}
else if (!strcmp(REQUEST_METHOD,"GET"))
{
if (QUERY_STRING == NULL) {
fprintf(stderr,"caught
by cgihtml: QUERY_STRING is null\n");
exit(1);
}
input = newstr(QUERY_STRING);
content_length = strlen(input);
}
else { /* error: invalid request method */
fprintf(stderr,"caught by cgihtml:
REQUEST_METHOD invalid\n");
exit(1);
}
/* parsing starts here */
if (content_length == 0)
return 0;
else {
j = 0;
entry.name = malloc(sizeof(char) * content_length
+ 1);
entry.value = malloc(sizeof(char) * content_length
+ 1);
for (i = 0; i < content_length; i++)
{
if (input[i] == '=') {
entry.name[j] = '\0';
unescape_url(entry.name);
if (i == content_length - 1) {
strcpy(entry.value,"");
window = list_insafter(entries,window,entry);
}
j = 0;
NM = 0;
}
else if ( (input[i] == '&')
|| (i == content_length - 1) ) {
if (i == content_length - 1) {
entry.value[j] = input[i];
j++;
}
entry.value[j] = '\0';
unescape_url(entry.value);
window = list_insafter(entries,window,entry);
j = 0;
NM = 1;
}
else if (NM) {
if (input[i] == '+')
entry.name[j] = ' ';
else
entry.name[j] = input[i];
j++;
}
else if (!NM) {
if (input[i] == '+')
entry.value[j] = ' ';
else
entry.value[j] = input[i];
j++;
}
}
return 1;
}
}
char *cgi_val(llist l, char *name)
{
short FOUND = 0;
node* window;
window = l.head;
while ( (window != 0) && (!FOUND) )
if (!strcmp((*window).entry.name,name))
FOUND = 1;
else
window = (*window).next;
if (FOUND)
return (*window).entry.value;
else
return NULL;
}
/* cgi_val_multi - contributed by Mitch Garnaat <garnaat@wrc.xerox.com>;
modified by me */
char **cgi_val_multi(llist l, char *name)
{
short FOUND = 0;
node* window;
char **ret_val = 0;
int num_vals = 0, i;
window = l.head;
while (window != 0) {
if (!strcmp((*window).entry.name,name))
{
FOUND = 1;
num_vals++;
}
window = (*window).next;
}
if (FOUND) {
/* copy the value pointers into the returned
array */
ret_val = (char**) malloc(sizeof(char*)
* (num_vals + 1));
window = l.head;
i = 0;
while (window != NULL) {
if (!strcmp((*window).entry.name,name))
{
ret_val[i] = (*window).entry.value;
i++;
}
window = (*window).next;
}
/* NULL terminate the array */
ret_val[i] = 0;
return ret_val;
}
else
return NULL;
}
/* miscellaneous useful CGI routines */
void print_cgi_env()
{
printf("<p>SERVER_SOFTWARE = %s<br>\n",SERVER_SOFTWARE);
printf("SERVER_NAME = %s<br>\n",SERVER_NAME);
printf("GATEWAY_INTERFACE = %s<br>\n",GATEWAY_INTERFACE);
printf("SERVER_PROTOCOL = %s<br>\n",SERVER_PROTOCOL);
printf("SERVER_PORT = %s<br>\n",SERVER_PORT);
printf("REQUEST_METHOD = %s<br>\n",REQUEST_METHOD);
printf("PATH_INFO = %s<br>\n",PATH_INFO);
printf("PATH_TRANSLATED = %s<br>\n",PATH_TRANSLATED);
printf("SCRIPT_NAME = %s<br>\n",SCRIPT_NAME);
printf("QUERY_STRING = %s<br>\n",QUERY_STRING);
printf("REMOTE_HOST = %s<br>\n",REMOTE_HOST);
printf("REMOTE_ADDR = %s<br>\n",REMOTE_ADDR);
printf("AUTH_TYPE = %s<br>\n",AUTH_TYPE);
printf("REMOTE_USER = %s<br>\n",REMOTE_USER);
printf("REMOTE_IDENT = %s<br>\n",REMOTE_IDENT);
printf("CONTENT_TYPE = %s<br>\n",CONTENT_TYPE);
printf("CONTENT_LENGTH = %s<br></p>\n",CONTENT_LENGTH);
}
void print_entries(llist l)
{
node* window;
window = l.head;
printf("<dl>\r\n");
while (window != NULL) {
printf(" <dt> <b>%s</b>\r\n",(*window).entry.name);
printf(" <dd> %s\r\n",replace_ltgt((*window).entry.value));
window = (*window).next;
}
printf("</dl>\r\n");
}
char *escape_input(char *str)
/* takes string and escapes all metacharacters. should be used
before
including string in system() or similar call.
*/
{
int i,j = 0;
char *new = malloc(sizeof(char) * (strlen(str) * 2
+ 1));
for (i = 0; i < strlen(str); i++) {
if (!( ((str[i] >= 'A') &&
(str[i] <= 'Z')) ||
((str[i] >= 'a')
&& (str[i] <= 'z')) ||
((str[i] >= '0')
&& (str[i] <= '9')) )) {
new[j] = '\\';
j++;
}
new[j] = str[i];
j++;
}
new[j] = '\0';
return new;
}
short is_form_empty(llist l)
{
node* window;
short EMPTY = 1;
window = l.head;
while ( (window != NULL) && (EMPTY == 1) )
{
if (strcmp((*window).entry.value,""))
EMPTY = 0;
window = (*window).next;
}
return EMPTY;
}
Listing E.7. html-lib.h.
/* html-lib.h - header file for html-lib.c
Eugene Kim, eekim@fas.harvard.edu
$Id: html-lib.h,v 1.3 1996/02/18 22:33:27 eekim
Exp eekim $
Copyright (C) 1996 Eugene Eric Kim
All Rights Reserved
*/
void html_header();
void mime_header(char *mime);
void nph_header(char *status);
void show_html_page(char *loc);
void status(char *status);
void pragma(char *msg);
void html_begin(char *title);
void html_end();
/* better to do printf inside of function, or return string? */
void h1(char *str);
void h2(char *str);
void h3(char *str);
void h4(char *str);
void h5(char *str);
void h6(char *str);
void hidden(char *name, char *value);
Listing E.8. html-lib.c.
/* html-lib.c - C routines that output
various HTML constructs
Eugene Kim, eekim@fas.harvard.edu
$Id: html-lib.c,v 1.3 1996/02/18 22:33:27 eekim
Exp eekim $
Copyright (C) 1996 Eugene Eric Kim
All Rights Reserved
*/
#include <stdio.h>
#include "html-lib.h"
/* HTTP headers */
void html_header()
{
printf("Content-type: text/html\r\n\r\n");
}
void mime_header(char *mime)
/* char *mime = valid mime type */
{
printf("Content-type: %s\r\n\r\n",mime);
}
void nph_header(char *status)
{
printf("HTTP/1.0 %s\r\n",status);
printf("Server: CGI using cgihtml\r\n");
}
void show_html_page(char *loc)
{
printf("Location: %s\r\n\r\n",loc);
}
void status(char *status)
{
printf("Status: %s\r\n",status);
}
void pragma(char *msg)
{
printf("Pragma: %s\r\n",msg);
}
/* HTML shortcuts */
void html_begin(char *title)
{
printf("<html> <head>\n");
printf("<title>%s</title>\n",title);
printf("</head>\n\n");
printf("<body>\n");
}
void html_end()
{
printf("</body> </html>\n");
}
void h1(char *str)
{
printf("<h1>%s</h1>\n",str);
}
void h2(char *str)
{
printf("<h2>%s</h2>\n",str);
}
void h3(char *str)
{
printf("<h3>%s</h3>\n",str);
}
void h4(char *str)
{
printf("<h4>%s</h4>\n",str);
}
void h5(char *str)
{
printf("<h5>%s</h5>\n",str);
}
void h6(char *str)
{
printf("<h6>%s</h6>\n",str);
}
void hidden(char *name, char *value)
{
printf("<input type=hidden name=\"%s\"
value=\"%s\">\n",name,value);
}

Contact
reference@developer.com with questions or comments.
Copyright 1998
EarthWeb Inc., All rights reserved.
PLEASE READ THE ACCEPTABLE USAGE STATEMENT.
Copyright 1998 Macmillan Computer Publishing. All rights reserved.
|
|