Exemplo n.º 1
0
static HTTPResponse *_errorResponse(WOAppReq *app, WOURLComponents *wc, HTTPRequest *req)
{
   HTTPResponse *resp;
   const char *redirect_url = &app->redirect_url[0];

   WOLog(WO_ERR,"Request handling error: %s",_errors[app->error]);

   if (app->redirect_url[0] == 0)
      redirect_url = adaptor_valueForKey(WOERRREDIR);

   /*
    *	try to do the right thing...
    */
   if (redirect_url != NULL) {
      resp = resp_redirectedResponse(redirect_url);
   } else if (app->error == err_notFound) {
      if (ac_authorizeAppListing(wc))
         resp = WOAdaptorInfo(NULL, wc);
      else {
         resp = resp_errorResponse(NOT_FOUND_APP, HTTP_NOT_FOUND);
         if (resp->statusMsg)	WOFREE(resp->statusMsg);
         resp->statusMsg = WOSTRDUP("File Not Found");
      }
   } else
       resp = resp_errorResponse(_errors[app->error], HTTP_SERVER_ERROR);

   if (resp)
   {
      st_add(resp->headers, "Cache-Control", "no-cache, private, no-store, must-revalidate, max-age=0", 0);
      st_add(resp->headers, "Expires", "Thu, 01 Jan 1970 00:00:00 GMT", 0);
      st_add(resp->headers, "date", "Thu, 01 Jan 1970 00:00:00 GMT", 0);
      st_add(resp->headers, "pragma", "no-cache", 0);
   }
   return resp;
}
Exemplo n.º 2
0
/*
 * Make a new combine_diff_path from path/mode/sha1
 * and append it to paths list tail.
 *
 * Memory for created elements could be reused:
 *
 *	- if last->next == NULL, the memory is allocated;
 *
 *	- if last->next != NULL, it is assumed that p=last->next was returned
 *	  earlier by this function, and p->next was *not* modified.
 *	  The memory is then reused from p.
 *
 * so for clients,
 *
 * - if you do need to keep the element
 *
 *	p = path_appendnew(p, ...);
 *	process(p);
 *	p->next = NULL;
 *
 * - if you don't need to keep the element after processing
 *
 *	pprev = p;
 *	p = path_appendnew(p, ...);
 *	process(p);
 *	p = pprev;
 *	; don't forget to free tail->next in the end
 *
 * p->parent[] remains uninitialized.
 */
static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,
	int nparent, const struct strbuf *base, const char *path, int pathlen,
	unsigned mode, const struct object_id *oid)
{
	struct combine_diff_path *p;
	size_t len = st_add(base->len, pathlen);
	size_t alloclen = combine_diff_path_size(nparent, len);

	/* if last->next is !NULL - it is a pre-allocated memory, we can reuse */
	p = last->next;
	if (p && (alloclen > (intptr_t)p->next)) {
		FREE_AND_NULL(p);
	}

	if (!p) {
		p = xmalloc(alloclen);

		/*
		 * until we go to it next round, .next holds how many bytes we
		 * allocated (for faster realloc - we don't need copying old data).
		 */
		p->next = (struct combine_diff_path *)(intptr_t)alloclen;
	}

	last->next = p;

	p->path = (char *)&(p->parent[nparent]);
	memcpy(p->path, base->buf, base->len);
	memcpy(p->path + base->len, path, pathlen);
	p->path[len] = 0;
	p->mode = mode;
	oidcpy(&p->oid, oid ? oid : &null_oid);

	return p;
}
Exemplo n.º 3
0
/*
 * Called during server init -
 *
 *	the following keys can be specified in an Init line in the
 *	obj.conf, like this:
 *
 *	Init fn="WebObjects_init" config="path-to-config" \
 *			root="WebObjects-Doc-Root-Path"
 *
 *	pb contains the "name=value" pairs from the Init line
 *	sn = rq = NULL
 *
 */
NSAPI_PUBLIC
int WebObjects_init(pblock *pb, Session *sn, Request *rq)
{
   strtbl *dict;
   int i;

   WOLog_init(NULL, NULL, WOLogLevel[WO_DBG]);
   dump_pb(pb,"init.pb");

   dict = st_new(10);
   /*
    *	copy all the key/value pairs into our init table
    */
   for (i=0; i < pb->hsize; i++) {
      struct pb_entry *entry = pb->ht[i];
      while (entry != NULL) {
         pb_param *kvpair = entry->param;
         if (kvpair != NULL) {
            st_add(dict, kvpair->name, kvpair->value, STR_COPYKEY|STR_COPYVALUE);
         }
         entry = entry->next;
      }
   }

   adaptorEnabled = init_adaptor(dict)==0;
   if (adaptorEnabled)
      log_error(1,"WebObjects",NULL,NULL,"initialized");
   return REQ_PROCEED;
}
Exemplo n.º 4
0
strtbl *st_newWithString(const char *s)
{
    strtbl *st = NULL;
    char key[MAXSTR], value[MAXSTR];

    if ((s == NULL) || (*s != LEFTCURLY))
        return NULL;
    /*
     *	repeat over key = value pairs
     */
    s++;
    while (*s != RIGHTCURLY) {
        s = _getstr(s, key);
        while (*s && isspace((int)*s))	s++;
        if (*s == EQUAL)
            s = _getstr(s+1, value);

        if (*key && *value) {
            if (st == NULL)
                st = st_new(0);
            st_add(st, key, value, STR_COPYKEY|STR_COPYVALUE);
        }
        while (*s && (isspace((int)*s) || (*s == SEMI)))	s++;
    }

    return st;
}
Exemplo n.º 5
0
/*
 *	return a redirect response to 'path'
 */
HTTPResponse *resp_redirectedResponse(const char *path)
{
   HTTPResponse *resp;

   resp = WOCALLOC(1,sizeof(HTTPResponse));
   resp->status = 302; /* redirected */
   resp->statusMsg = WOSTRDUP("OK Apple");
   resp->headers = st_new(2);
   st_add(resp->headers, LOCATION, path, STR_COPYVALUE|STR_FREEVALUE);
   return resp;
}
Exemplo n.º 6
0
static const char *add_slash(const char *path)
{
	size_t len = strlen(path);
	if (path[len - 1] != '/') {
		char *with_slash = xmalloc(st_add(len, 2));
		memcpy(with_slash, path, len);
		with_slash[len++] = '/';
		with_slash[len] = 0;
		return with_slash;
	}
	return path;
}
Exemplo n.º 7
0
void resp_addHeader(HTTPResponse *resp, String *rawhdr)
{
   char *key, *value;

   /* keep track of the String */
   resp_addStringToResponse(resp, rawhdr);
   
   /*
    *	break into key/value, make key lowercase
    *   Note that this walks over the String's buffer, but
    *   at this point the response owns the String so that's ok.
    *   The String buffer will get reclaimed when responseStrings
    *   is freed, in resp_free().
    */
   for (key = rawhdr->text, value = key; *value != ':'; value++) {
      if(*value == '\0') // mstoll 13.10.2005 check added
      {
         WOLog(WO_ERR,"Header without ':': %s", rawhdr->text);
         break;
      }
      if (isupper((int)*value))
         *value = tolower((int)*value);				/* ... and change to lowercase. */
   }
   if (*value == ':') {
      *value++ = '\0';			/* terminate key string */
      while (*value && isspace((int)*value))	value++;
   } else {
      return;			/* Zounds ! something wrong with header... */
   }

   st_add(resp->headers, key, value, 0);
   
   /*
    *	scan inline for content-length
    */
   if ((resp->content_length == 0) && ((strcasecmp(CONTENT_LENGTH,key) == 0) || strcasecmp("content_length", key) == 0))
   {
      // 2009/06/10: an explicit content-length value is available.
      //             Update response flag information:
      resp->flags |= RESP_LENGTH_EXPLICIT;
      resp->content_length = atoi(value);
      WOLog(WO_INFO,"content-length was set expl.: %d", resp->content_length);
   }

   if (((strcasecmp(CONTENT_TYPE,key) == 0) || strcasecmp("content_type", key) == 0))
   {
      // 2011/11/16: an explicit content-type value is available.
      //             Update response flag information:
      resp->flags |= RESP_CONTENT_TYPE_SET;
   }

   return;
}
Exemplo n.º 8
0
static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t block_alloc)
{
	struct mp_block *p;

	mem_pool->pool_alloc += sizeof(struct mp_block) + block_alloc;
	p = xmalloc(st_add(sizeof(struct mp_block), block_alloc));
	p->next_block = mem_pool->mp_block;
	p->next_free = (char *)p->space;
	p->end = p->next_free + block_alloc;
	mem_pool->mp_block = p;

	return p;
}
Exemplo n.º 9
0
static strtbl *read_registry_config()
{
   const regthing *info;
   strtbl *config;
   char value[MAX_VAL_LENGTH];

   config = st_new(12);
   for (info=options; info->regKey != NULL; info++) {
      if (WOReadKeyFromConfiguration(info->regKey, value, MAX_VAL_LENGTH))
         st_add(config,info->myKey,value,STR_COPYVALUE|STR_FREEVALUE);
   }
   return config;
}
Exemplo n.º 10
0
HTTPResponse *resp_errorResponse(const char *msg, int status)
{
   HTTPResponse *resp;
   char buf[12];
   String *html_msg;

   resp = WOCALLOC(1,sizeof(HTTPResponse));
   resp->status = status;
   resp->statusMsg = WOSTRDUP("Error WebObjects");
   resp->headers = st_new(2);
   st_add(resp->headers, CONTENT_TYPE, DEFAULT_CONTENT, 0);
   html_msg = str_create(errorRespTextBegin, sizeof(errorRespTextBegin) + sizeof(errorRespTextEnd) + strlen(msg));
   str_append(html_msg, msg);
   str_append(html_msg, errorRespTextEnd);
   resp->content_length = resp->content_valid = resp->content_read = html_msg->length;
   resp->content = html_msg->text;
   resp_addStringToResponse(resp, html_msg);
   resp->flags |= RESP_DONT_FREE_CONTENT;
   sprintf(buf,"%d",resp->content_length);
   st_add(resp->headers, CONTENT_LENGTH, buf, STR_COPYVALUE|STR_FREEVALUE);
   return resp;
}
Exemplo n.º 11
0
static void queue_directory(const unsigned char *sha1,
		struct strbuf *base, const char *filename,
		unsigned mode, int stage, struct archiver_context *c)
{
	struct directory *d;
	size_t len = st_add4(base->len, 1, strlen(filename), 1);
	d = xmalloc(st_add(sizeof(*d), len));
	d->up	   = c->bottom;
	d->baselen = base->len;
	d->mode	   = mode;
	d->stage   = stage;
	c->bottom  = d;
	d->len = xsnprintf(d->path, len, "%.*s%s/", (int)base->len, base->buf, filename);
	hashcpy(d->oid.hash, sha1);
}
Exemplo n.º 12
0
static int add_submodule_odb(const char *path)
{
	struct strbuf objects_directory = STRBUF_INIT;
	struct alternate_object_database *alt_odb;
	int ret = 0;
	size_t alloc;

	strbuf_git_path_submodule(&objects_directory, path, "objects/");
	if (!is_directory(objects_directory.buf)) {
		ret = -1;
		goto done;
	}
	/* avoid adding it twice */
	prepare_alt_odb();
	for (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next)
		if (alt_odb->name - alt_odb->base == objects_directory.len &&
				!strncmp(alt_odb->base, objects_directory.buf,
					objects_directory.len))
			goto done;

	alloc = st_add(objects_directory.len, 42); /* for "12/345..." sha1 */
	alt_odb = xmalloc(st_add(sizeof(*alt_odb), alloc));
	alt_odb->next = alt_odb_list;
	xsnprintf(alt_odb->base, alloc, "%s", objects_directory.buf);
	alt_odb->name = alt_odb->base + objects_directory.len;
	alt_odb->name[2] = '/';
	alt_odb->name[40] = '\0';
	alt_odb->name[41] = '\0';
	alt_odb_list = alt_odb;

	/* add possible alternates from the submodule */
	read_info_alternates(objects_directory.buf, 0);
done:
	strbuf_release(&objects_directory);
	return ret;
}
Exemplo n.º 13
0
void req_addHeader(HTTPRequest *req,const char *key, const char *value, int flags)
{
   const char *hdrkey;

   hdrkey = req_AddHeader_common(req, key, value);

   /*
    *	we know that all interfaces (CGI, NSAPI,...) use statically allocated
    *	header keys, always.  *Most* of the time, the value is static too,
    *	but there are cases where it might not be e.g. derived value, like
    *	"server-port", or are always malloc'd.  
    */
   st_add((strtbl *)req->headers, hdrkey, value, flags);

   return;
}
Exemplo n.º 14
0
/*
 * Called from the xml parser to process a tag attribute. Just adds the key/value pair to the
 * current_element dictionary.
 */
static void createAttribute(XMLCDocument *document, const XMLCCharacter *name, const unsigned int nameLength, const XMLCCharacter *value, const unsigned int valueLength)
{
   WOXMLEdits *config = (WOXMLEdits *)document;

   if (config->error != 0)		/* would be nice to tell parser to stop */
      return;
   config->errorLocation = &value[valueLength+1];
   if (config->current_element)
   {
      /* Insert null terminators into the xml buffer. */
      /* This is so we don't have to copy all the string values. They are stored by reference */
      /* until the parse completes, then they are copied into the "live" configuration. The */
      /* buffer containing the xml is not freed until after this completes. */
      ((char *)name)[nameLength] = 0;
      ((char *)value)[valueLength] = 0;
      st_add(config->current_element, name, value, 0);
   } else
      WOLog(WO_WARN, "createAttribute() called with NULL current_element.");
   return;
}
Exemplo n.º 15
0
Arquivo: merge.c Projeto: 1tgr/git
/*
 * Pretend as if the user told us to merge with the remote-tracking
 * branch we have for the upstream of the current branch
 */
static int setup_with_upstream(const char ***argv)
{
	struct branch *branch = branch_get(NULL);
	int i;
	const char **args;

	if (!branch)
		die(_("No current branch."));
	if (!branch->remote_name)
		die(_("No remote for the current branch."));
	if (!branch->merge_nr)
		die(_("No default upstream defined for the current branch."));

	args = xcalloc(st_add(branch->merge_nr, 1), sizeof(char *));
	for (i = 0; i < branch->merge_nr; i++) {
		if (!branch->merge[i]->dst)
			die(_("No remote-tracking branch for %s from %s"),
			    branch->merge[i]->src, branch->remote_name);
		args[i] = branch->merge[i]->dst;
	}
	args[i] = NULL;
	*argv = args;
	return i;
}
Exemplo n.º 16
0
void st_setValueForKey(strtbl *st, const char *key, const char *value, int flags)
{
    int index;
    strtblelem *el;

    index = st_findKey(st, key);
    if (index == -1)
    {
        st_add(st, key, value, flags);
    } else {
        el = &st->head[index];
        if (el->flags & STR_FREEVALUE)
            WOFREE((void *)el->value);
        /* keep the old key flags, but take the new value flags */
        el->flags = (el->flags & (STR_COPYKEY|STR_FREEKEY)) | (flags & (STR_COPYVALUE | STR_FREEVALUE));
        if (flags & STR_COPYVALUE)
        {
            el->value = WOSTRDUP(value);
            el->flags |= STR_FREEVALUE;
        } else
            el->value = value;
    }
    return;
}
Exemplo n.º 17
0
Arquivo: proc.c Projeto: aaronb/CS637
// Per-CPU process scheduler.
// Each CPU calls scheduler() after setting itself up.
// Scheduler never returns.  It loops, doing:
//  - choose a process to run
//  - swtch to start running that process
//  - eventually that process transfers control
//      via swtch back to the scheduler.
void
scheduler(void)
{
  struct proc *p;
  struct cpu *c;
  int i;

#ifdef STRACE
st_init();
#endif

  c = &cpus[cpu()];
  for(;;){
    // Enable interrupts on this processor.
    sti();

    acquire(&proc_table_lock);

    //hold lottery
#ifdef LOTTERY
    if (tickets == 0) {
       release(&proc_table_lock);
       continue;
    }
    //cprintf("tickets: %d\n", tickets); 
    int winner = rand() / (32767 / tickets + 1);
    int sum = 0;
    //cprintf("winner: %d\n", winner);
#endif

    // Loop over process table looking for process to run.
    for(i = 0; i < NPROC; i++){
      p = &proc[i];
      if(p->state != RUNNABLE)
        continue;

#ifdef LOTTERY
      sum += p->tickets;
      if (sum <= winner)
         continue;
#endif

      // Switch to chosen process.  It is the process's job
      // to release proc_table_lock and then reacquire it
      // before jumping back to us.
      c->curproc = p;
      setupsegs(p);
      setstate(p, RUNNING);

#ifdef STRACE
	   st_add(p);
#endif
		
      swtch(&c->context, &p->context);

      // Process is done running for now.
      // It should have changed its p->state before coming back.
      c->curproc = 0;
      setupsegs(0);

#ifdef LOTTERY
      break;
#endif
    }
    release(&proc_table_lock);

  }
}
Exemplo n.º 18
0
Arquivo: refs.c Projeto: chidveer/git
char *shorten_unambiguous_ref(const char *refname, int strict)
{
	int i;
	static char **scanf_fmts;
	static int nr_rules;
	char *short_name;

	if (!nr_rules) {
		/*
		 * Pre-generate scanf formats from ref_rev_parse_rules[].
		 * Generate a format suitable for scanf from a
		 * ref_rev_parse_rules rule by interpolating "%s" at the
		 * location of the "%.*s".
		 */
		size_t total_len = 0;
		size_t offset = 0;

		/* the rule list is NULL terminated, count them first */
		for (nr_rules = 0; ref_rev_parse_rules[nr_rules]; nr_rules++)
			/* -2 for strlen("%.*s") - strlen("%s"); +1 for NUL */
			total_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;

		scanf_fmts = xmalloc(st_add(st_mult(sizeof(char *), nr_rules), total_len));

		offset = 0;
		for (i = 0; i < nr_rules; i++) {
			assert(offset < total_len);
			scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset;
			offset += snprintf(scanf_fmts[i], total_len - offset,
					   ref_rev_parse_rules[i], 2, "%s") + 1;
		}
	}

	/* bail out if there are no rules */
	if (!nr_rules)
		return xstrdup(refname);

	/* buffer for scanf result, at most refname must fit */
	short_name = xstrdup(refname);

	/* skip first rule, it will always match */
	for (i = nr_rules - 1; i > 0 ; --i) {
		int j;
		int rules_to_fail = i;
		int short_name_len;

		if (1 != sscanf(refname, scanf_fmts[i], short_name))
			continue;

		short_name_len = strlen(short_name);

		/*
		 * in strict mode, all (except the matched one) rules
		 * must fail to resolve to a valid non-ambiguous ref
		 */
		if (strict)
			rules_to_fail = nr_rules;

		/*
		 * check if the short name resolves to a valid ref,
		 * but use only rules prior to the matched one
		 */
		for (j = 0; j < rules_to_fail; j++) {
			const char *rule = ref_rev_parse_rules[j];
			char refname[PATH_MAX];

			/* skip matched rule */
			if (i == j)
				continue;

			/*
			 * the short name is ambiguous, if it resolves
			 * (with this previous rule) to a valid ref
			 * read_ref() returns 0 on success
			 */
			mksnpath(refname, sizeof(refname),
				 rule, short_name_len, short_name);
			if (ref_exists(refname))
				break;
		}

		/*
		 * short name is non-ambiguous if all previous rules
		 * haven't resolved to a valid ref
		 */
		if (j == rules_to_fail)
			return short_name;
	}

	free(short_name);
	return xstrdup(refname);
}
Exemplo n.º 19
0
int main() {

#ifdef	PROFILE
    int i;
#endif
    const char *config_url, *username, *password, *config_options;
    strtbl *options = NULL;
    int exit_status = 0;

    // install SIGUSR1, SIGPIPE, SIGTERM handler
    signal(SIGTERM, sig_handler);
    signal(SIGUSR1, sig_handler);
    signal(SIGPIPE, sig_handler);

      /* Provide a hook via an environment variable to define the config URL */
      config_url = getenv(WO_CONFIG_URL);
      if (!config_url) {
         /* Flat file URL */
         /* config_url = "file:///Local/Library/WebObjects/Configuration/WOConfig.xml"; */
         /* Local wotaskd */
         /* config_url = "http://localhost:1085"; */
         /* Multicast URL */
         config_url = CONFIG_URL; /* Actually "webobjects://239.128.14.2:1085"; */
      }
      WOLog(WO_INFO,"<FastCGI> config url is %s", config_url);
      options = st_new(8);
      st_add(options, WOCONFIG, config_url, 0);

      /*
         * If your webserver is configured to pass these environment variables, we use them to
       * protect WOAdaptorInfo output.
       */
      username = getenv(WO_ADAPTOR_INFO_USERNAME);
      if (username && strlen(username) != 0) {
         st_add(options, WOUSERNAME, username, 0);
         password = getenv(WO_ADAPTOR_INFO_PASSWORD);
         if(password && strlen(password) != 0) {
            st_add(options, WOPASSWORD, password, 0);
         }
      }

      config_options = getenv(WO_CONFIG_OPTIONS);
      if (config_options)
         st_add(options, WOOPTIONS, config_options, 0);
      /*
       * SECURITY ALERT
       *
       * To disable WOAdaptorInfo, uncomment the next line.
       * st_add(options, WOUSERNAME, "disabled", 0);
       *
       * To specify an WOAdaptorInfo username and password, uncomment the next two lines.
       * st_add(options, WOUSERNAME, "joe", 0);
       * st_add(options, WOPASSWORD, "secret", 0);
       *
       */

      if (init_adaptor(options)) {
          WOLog( WO_ERR, "<FastCGI> Adaptor initialization failed.");
    	    exit(-1);
      }

    WOLog( WO_INFO,"<FastCGI> process started" );
   
    while (!should_terminate) {

      HTTPRequest *req;
      HTTPResponse *resp = NULL;
      WOURLComponents wc = WOURLComponents_Initializer;
      const char *qs;
      unsigned int qs_len;
      char *url;
      const char *script_name, *path_info;
      const char *reqerr;
      WOURLError urlerr;
      FCGX_ParamArray hdrp_org;
     
      exit_status = FCGX_Accept(&in, &out, &err, &hdrp );
      if ( exit_status < 0 ) {
	    break;
      }

#ifdef	PROFILE
    for (i=0; i < 50000; i++) {
#endif

      WOLog( WO_INFO,"<FastCGI> request accepted" );

#ifdef WIN32
      _setmode(_fileno(stdout), _O_BINARY);
      _setmode(_fileno(stdin), _O_BINAR1Y);
#endif

      script_name = FCGX_GetParam( CGI_SCRIPT_NAME, hdrp);
      path_info = FCGX_GetParam( CGI_PATH_INFO, hdrp);

      WOLog( WO_INFO,"<FastCGI> CGI_SCRIPT_NAME = %s", script_name );
      WOLog( WO_INFO,"<FastCGI> CGI_PATH_INFO = %s", path_info );

      if (script_name == NULL) {
         prepareAndSendErrorResponse(INV_SCRIPT, HTTP_NOT_FOUND);
         break;
      } else if (path_info == NULL) {
         path_info = "/";
      }

      /*
       *	extract WebObjects application name from URI
       */

      url = WOMALLOC(strlen(path_info) + strlen(script_name) + 1);
      strcpy(url, script_name);
      strcat(url, path_info);
      WOLog(WO_INFO,"<FastCGI> new request: %s",url);
      
      urlerr = WOParseApplicationName(&wc, url);
      if (urlerr != WOURLOK) {
         const char *_urlerr;
         _urlerr = WOURLstrerror(urlerr);
         WOLog(WO_INFO,"<FastCGI> URL Parsing Error: %s", _urlerr);

         if (urlerr == WOURLInvalidApplicationName) {
             if (ac_authorizeAppListing(&wc)) {
                 resp = WOAdaptorInfo(NULL, &wc);
                 sendErrorResponse(resp);
             } else {
                 prepareAndSendErrorResponse(_urlerr, HTTP_NOT_FOUND);
             }
             WOFREE(url);
             break;
         }

         prepareAndSendErrorResponse(_urlerr, HTTP_BAD_REQUEST);
         WOFREE(url);
         break;
      }


      /*
       *	build the request...
       */
      req = req_new( FCGX_GetParam("REQUEST_METHOD", hdrp), NULL);


      /*
       *	validate the method
       */
      reqerr = req_validateMethod(req);
      if (reqerr) {
          prepareAndSendErrorResponse(reqerr, HTTP_BAD_REQUEST);
          WOFREE(url);
          break;
      }

      /*
       *	copy the headers.  This looks wierd... all we're doing is copying
       *	*every* environment variable into our headers.  It may be beyond
       *	the spec, but more information probably won't hurt.
       */
      hdrp_org=hdrp;
      while (hdrp && *hdrp) {
         char *key, *value;
         /* copy env. line. */
         key = WOSTRDUP(*hdrp);

         for (value = key; *value && !isspace((int)*value) && (*value != '='); value++) {}
         if (*value) {
            *value++ = '\0';	/* null terminate 'key' */
         }
         while (*value && (isspace((int)*value) || (*value == '='))) {
            value++;
         }
         /* BEGIN Support for getting the client's certificate. */
         if (strcmp((const char *)key, "SSL_CLIENT_CERTIFICATE") == 0 || strcmp((const char *)key, "SSL_SERVER_CERTIFICATE") == 0 ) {
             value = 0;
             WOLog(WO_INFO,"<FastCGI> DROPPING ENV VAR (DUPLICATE) = %s", key);
         }
         if (strcmp((const char *)key, "SSL_CLIENT_CERT") == 0 || strcmp((const char *)key, "SSL_SERVER_CERT") == 0) {
             value = make_cert_one_line(value);
             //WOLog(WO_INFO,"<FastCGI> PASSING %s = %s", key, value);
         }
         /*  END Support for getting the client's certificate  */

         if (key && *key && value && *value) {
            /* must specify copy key and value because key translation might replace this key, and value lives in the same buffer */
            req_addHeader(req, key, value, STR_COPYKEY|STR_COPYVALUE);
         }

         /*  BEGIN Support for getting the client's certificate  */
         if (freeValueNeeded ) {
             free(value);
             freeValueNeeded=0;
         }
         /*  END Support for getting the client's certificate  */

         WOFREE(key);
         hdrp++;			/* next env variable */
      }
      hdrp=hdrp_org;

      /*
       *	get form data if any
       *	assume that POSTs with content length will be reformatted to GETs later
       */
	
      WOLog ( WO_INFO, "Getting request data, length: %d",req->content_length );
      if (req->content_length > 0) {
         req_allocateContent(req, req->content_length, 1);
         req->getMoreContent = (req_getMoreContentCallback)readContentData;
         WOLog ( WO_INFO, "content_buffer_size: %d",req->content_buffer_size );
         if (req->content_buffer_size == 0) {
            prepareAndSendErrorResponse(ALLOCATION_FAILURE, HTTP_SERVER_ERROR);
            WOFREE(url);
            break;
         }
         if (readContentData(req, req->content, req->content_buffer_size, 1) == -1) {
            prepareAndSendErrorResponse(WOURLstrerror(WOURLInvalidPostData), HTTP_BAD_REQUEST);
            WOFREE(url);
            break;
         }
      }

      /* Always get the query string */
      qs = FCGX_GetParam("QUERY_STRING", hdrp);
      if (qs) {
         qs_len = strlen(qs);
      } else {
         qs_len = 0;
      }

      if (qs_len > 0) {
         wc.queryString.start = qs;
         wc.queryString.length = qs_len;
         WOLog(WO_INFO,"<FastCGI> new request with Query String: %s", qs);
      }

      /*
       *	message the application & collect the response
       */
      resp = tr_handleRequest(req, url, &wc, FCGX_GetParam(CGI_SERVER_PROTOCOL, hdrp), documentRoot());

      if (resp != NULL) {
         sendResponse(resp);
         resp_free(resp);		/* dump the response */
      }

      WOFREE(url);
      req_free(req);

#if defined(FINDLEAKS)
      showleaks();
#endif
    }

#ifdef	PROFILE
    }
#endif


    st_free(options);
    WOLog( WO_INFO,"<FastCGI> process exiting" );

    return exit_status;
}