Journal Articles

CVu Journal Vol 10, #6 - Sep 1998 + Internet Topics
Browse in : All > Journals > CVu > 106 (12)
All > Topics > Internet (35)
Any of these categories - All of these categories

Note: when you create a new publication type, the articles module will automatically use the templates user-display-[publicationtype].xt and user-summary-[publicationtype].xt. If those templates do not exist when you try to preview or display a new article, you'll get this warning :-) Please place your own templates in themes/yourtheme/modules/articles . The templates will get the extension .xt there.

Title: Common Gateway Interface Program Testing

Author: Administrator

Date: 03 September 1998 13:15:27 +01:00 or Thu, 03 September 1998 13:15:27 +01:00

Summary: 

Body: 

In the last few months I've found myself writing a lot of CGI programs for a corporate intranet. For a number of reasons that aren't germane to this article, I have to work on a DOS/Windows development system, with the final implementation being on an NT machine. The CGI programs are in C. If I actually get to finish the work on time I may have more to say about the delights of this undertaking.

In order to check my CGI programs before moving them onto the server I wanted to simulate the GET transfer protocol. As anyone with some DOS experience will attest, the command interpreter and environment string handling is, well, basic. One of the things you cannot do is incorporate '=' in an environ-ment string, which is necessary for a GET transfer.

A half-remembered item in the compiler manual sent me hunting, and I finally spied the spawn() function family, with the option to pass a custom environ-ment to the child process. Not, I agree, a portable function, but then this isn't a universal problem!

The upshot was the program RunGET2 (yes, there was a '1'...RIP), which takes a file containing the desired environment key-text pairs and the name of the program to test as arguments. The resulting output to stdout may be captured and inspected or viewed in a web browser.

It's a cheap and cheerful solution to a common problem, and, I expect, the most re-invented of the CGI 'wheels'. The source and an example environment file are available.

/* module title  : RunGET2.c
 * problems      : spawnlpe() may not be available on all systems.
 *                 It doesn't do POST transfers. But a good CGI library should handle either transaparently.
 * description   : Provides a simulated 'GET' environment for a World Wide
 *                 Web Common Gateway Interface program.
 *                 Primarily for systems such as DOS/Windows where environment support is inflexible.
 *                 Requires a definition file containing the environment to be used.   */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <process.h>  /* for spawn function */
/* These values may need to be tuned. Buffersize should reflect the web  server CGI limit.  */
enum {Envsize = 200, Buffersize = 1024};
static char *envp[Envsize];             /* Why static? For something as small */
static int envcount = 0;                /* as this, why not?                  */
int load_env(const char *filename) {
  FILE *fp;
  char buffer[Buffersize];
  int result = 0;
  fp = fopen(filename, "rt");
  if(NULL != fp) {
    int i;
    fgets(buffer, Buffersize - 1, fp);
    *strrchr(buffer, '\n') = '\0';
    while(!feof(fp) && envcount < Envsize - 3)  {
      envp[envcount] = strdup(buffer);
      envcount++;
      fgets(buffer, Buffersize - 1, fp);
      *strrchr(buffer, '\n') = '\0';
    }
/*  the program calculates the length of the query. Like a true web server the length is limited. */
    for(i = 0; i < envcount; i++) {
      if(strncmp(envp[i], "QUERYSTRING=", 12) == 0)  {
        char *ptr = strchr(envp[i], '=') + 1;
        int l;
        l = strlen(ptr);
        sprintf(buffer, "CONTENT_LENGTH=%d", l);
        envp[envcount++] = strdup(buffer);
        break;
      }
    }
    envp[envcount] = NULL;
    fclose(fp);
    result = 1;
  }
  else result = 0;
  return(result);
}
int main(int argc, char **argv) {
  int return_status = 0;
  if(argc == 3)  {
    if(!load_env(*(argv + 1))) {
      fprintf(stderr, "Fault loading environment data from %s\n", *(argv + 1));
      return_status = 1;
    }
    else {
      int result;
      char *program = *(argv + 2);
      char *path_info;
      fprintf(stderr, "Executing CGI program '%s'in GET environment\n", *(argv + 2));
/* Hook to handle extra 'path' information. Need to split it from the program name and put into environment. Easier to put it into the environment definition file!                                  */
      if(NULL != (path_info = strchr(*(argv + 2), '/'))) {
        fprintf(stderr, "PATH_INFO=%s\n", path_info);
      }
/* Run our CGI program with the custom  environment. If you use an interpreted CGI program you will need an argument added to the list. */
      result = spawnlpe(P_WAIT, program, program, NULL, envp);
      if(-1 == result) {
        fprintf(stderr, "Unable to execute\n");
      }
      else fprintf(stderr, "CGI program completed\n");
      while(--envcount >= 0) {
        if(NULL != envp[envcount]) free(envp[envcount]);
      }
    }
  }
  else {
    fprintf(stderr, "RunGET2\nProgram to simulate a CGI GET environment\n");
    fprintf(stderr, "Graham patterson 6th August 1998\n");
    fprintf(stderr, "RunGET2 <environment> <cgi program>\n");
    return_status = 1;
  }
  return return_status;
} 

Graham's code is on the disk. I made a few layout changes to get it to fit. Francis

Notes: 

More fields may be available via dynamicdata ..