Pacific-Design.com

    
Home Index

1. Cpp 11

2. cgi-echo

Cpp 11 / cgi-echo /

Handle a CGI request by returning what was received.

/* cgi-echo.c
   Handle a CGI request by returning what was received.
   gcc cgi-echo.c -o cgi-echo.cgi  
*/

#include <stdio.h>
#ifndef NO_STDLIB_H
#include <stdlib.h>
#else
char *getenv();
#endif

typedef struct {
    char *name;
    char *val;
} entry;

   // Globals
int max_entries = 20;
int n_entries = 0;
entry *entries ;

char *filefield(FILE *f, char stop, int *nmax);
void store_field(char *field);
void decode_hex(char *str);
char x2c(char *what);
void print_safely( char *str );

/**********************************************************************/
main(int argc, char *argv[])
{
    entries = (entry*) malloc(max_entries*sizeof(entry));
    register int i=0;
    int count;

    printf("Content-type: text/html\r\n\r\n");
    printf("<html><head><title>CGI Echo Response</title></head><body>\n");
    printf("<h1>CGI Echo Response</h1>\n");

    if (strcmp(getenv("REQUEST_METHOD"),"POST") == 0)
    {
        printf("Method: POST<br>\n");
        printf("Content_length: %s<p>\n", getenv("CONTENT_LENGTH"));
        printf("Content_type: %s<p>\n", getenv("CONTENT_TYPE"));
        printf("<table border='1' cellpadding='3'>\n");
        count = atoi( getenv("CONTENT_LENGTH") );
        if ( strcmp(getenv("CONTENT_TYPE"),
                    "application/x-www-form-urlencoded") == 0)
        {
           while (count != 0 && !feof(stdin))
           {
              char *field = filefield( stdin, '&', &count);
              store_field( field );
           }
        }
        else  // Other content-type
        {
            char ch[2] = "0";
            printf("<tr><td>");
            while ((i = getchar()) >= 0)
            {
               ch[0] = i;
               print_safely( ch );
            }
            printf("</td></tr>");
        }
        printf("</table>\n");
    }
    else if (strcmp(getenv("REQUEST_METHOD"),"GET") == 0)
    {
        printf("Method: GET<br>\n");
        printf("<table border='1' cellpadding='3'>\n");
        char *query = getenv("QUERY_STRING");
        if (query == NULL)
           printf("<tr><td>No query information to decode.</td></tr>\n");
        else
        {
           char *ptr = query;
           while (*ptr != '\0')
           {
              char *field = ptr;
              for (i=ptr-query; query[i] != '\0'; ++i,++ptr)
              {
                 if (query[i] == '&')
                 {
                    query[i] = '\0';
                    ptr = &query[i+1];
                    break;
                 }
              }
              store_field( field );
           }
        }
        printf("</table>\n");
    }
    else
    {
        char * ptr = getenv("REQUEST_METHOD");
        if (ptr != NULL) printf("Method: %s<br>\n",ptr);
        ptr =getenv("CONTENT_TYPE");
        if (ptr != NULL) printf("Content_type: %s<p>\n", ptr);
        ptr =getenv("QUERY_STRING");
        if (ptr != NULL) printf("Query_string: %s<p>\n", ptr);
        ptr =getenv("CONTENT_LENGTH");
        if (ptr != NULL) printf("Content_length: %s<p>\n", ptr);
    }

    printf("</body></html>\n");
}


/*********************************************************************/
/* Dynamically allocate a character array large enough to contain a field
   from the file "f", where a field is defined as groups of characters 
   separated by 'stop' characters.  Do not include the 'stop' character 
   in the returned text string.  Do not read beyond the counter 'nmax' 
   characters.  Update 'nmax' to reflect the number of characters still 
   not processed from the file. */
char *filefield(FILE *f, char stop, int *nmax)
{
    int wsize = 64;
    char *word;
    int pos = 0;

    word = (char *) malloc(sizeof(char) * (wsize + 1));

    while (1)
    {
        word[pos] = (char)fgetc(f);
        if (pos == wsize)
        {
            word[pos+1] = '\0';
            wsize += 64;
            word = (char *)realloc( word, sizeof(char)*(wsize+1));
        }
        --(*nmax);
        if (word[pos] == stop || feof(f) || *nmax == 0)
        {
            if(word[pos] != stop) ++pos;
            word[pos] = '\0';
            return word;
        }
        ++pos;
    }
}


/*********************************************************************/
/* Store the field in the global 'entries' table, and dump the contents as 
   HTML to output. */
void store_field(char *field)
{
    register int i=0;
    printf("<tr><td>%s</td>\n",field);

       // Replace '+' with ' '
    for( i=0; field[i]; ++i) if (field[i] == '+') field[i] = ' ';

       // Find '=' and split there
    for ( i=0; field[i] != '\0' && field[i] != '='; ++i) ;
    if (field[i] == '\0')  // no '='
    {
       decode_hex( field );
       printf(" <td>", field);
       print_safely(field);
       printf("</td></tr>\n");
    }
    else   // split at '='
    {
       int eqpos = i;
       field[eqpos] = '\0';
       decode_hex( field );
       decode_hex( &field[eqpos+1] );
       printf(" <td>\"");
       print_safely(field);
       printf("\" = \"");
       print_safely(&field[eqpos+1]);
       printf("\"</td></tr>\n");
       if (n_entries == max_entries)
       {
          max_entries += 10;
          entries = (entry*) realloc( entries, sizeof(entry)*max_entries);
       }
       entries[n_entries].name = field;
       entries[n_entries].val = &field[eqpos+1];
       ++n_entries;
    }
}

/*********************************************************************/
/* Search for any '%' character and, interpreting the next two characters 
   as a hexadecimal character code, replace the three characters with the 
   encoded character. */
void decode_hex( char *str )
{
    register int x, y;

    for ( x=0,y=0; str[y]; ++x,++y)
    {
        if ((str[x] = str[y]) == '%')
        {
            str[x] = x2c(&str[y+1]);
            y+=2;
        }
    }
    str[x] = '\0';
}

/*********************************************************************/
/* Convert 2 hexadecimal digits to an ASCII character, without checking. */
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);
}


/*********************************************************************/
/* Print the string to standard output, converting any '<', '>', and '&' to 
   entities so that they will display properly in HTML. */
void print_safely( char *str )
{
   register int i;
   for (i=0; str[i] != '\0'; ++i)
   {
      if      (str[i] == '<') printf("&lt;");
      else if (str[i] == '>') printf("&gt;");
      else if (str[i] == '&') printf("&amp;");
      else if (str[i] == '\n') printf("<br>\n");
      else if (str[i] == ' ') printf("&nbsp;");
      else if (str[i] < ' ') printf("\\%x%c",str[i],str[i]);
      else putchar( str[i] );
   }
}