Пример #1
0
strdict	*sd_new(int hint)
{
   strdict *sd = WOMALLOC(sizeof(strdict));
   sd->capacity = (hint != 0) ? hint : 8;
   sd->head = WOMALLOC(sizeof(strdictel) * sd->capacity);
   sd->count = 0;
   return sd;
}
Пример #2
0
XMLCTokenizer *xmlcTokenizerInit()
{
    XMLCTokenizer *s = (XMLCTokenizer*)WOMALLOC(sizeof(XMLCTokenizer));

#if usePropertyTable
    XMLCUInt i;

    /* create character property table */
    /* FIXME: creating property table not thread safe */
    for (i=0; i<0x100; ++i) {
        XMLCUInt properties = 0;
        if (isLetterTest(i))
            properties = properties | PROPERTY_isLetter;
        if (isNameStartCharTest(i))
            properties = properties | PROPERTY_isNameStartChar;
        if (isDigitTest(i))
            properties = properties | PROPERTY_isDigit;
        if (isNameCharTest(i))
            properties = properties | PROPERTY_isNameChar;
        if (isEOLTest(i))
            properties = properties | PROPERTY_isEOL;
        if (isWhiteSpaceTest(i))
            properties = properties | PROPERTY_isWhiteSpace;
        characterPropertiesTable[i] = properties;
    }
#endif
    xmlcTokenizerReset(s);
    return s;
}
Пример #3
0
strtbl	*st_new(int hint)
{
    strtbl *st = WOMALLOC(sizeof(strtbl));
    if (st)
    {
        memset(st, 0, sizeof(strtbl));
        st_setCapacity(st, hint);
    }
    return st;
}
Пример #4
0
/*
 *	The entry point for the parser.
 *      Returns nonzero if there was an error during parsing.
 */
static int xml_parseConfiguration(char *buf, int len)
{
   XMLCDocumentHandler handler;
   WOXMLEdits config;
   XMLCParser *parser;
   int error = 0, i;

   /* initialize the config struct */
   config.current_element = NULL;
   config.new_apps = wolist_new(16);
   config.current_app = NULL;
   config.current_app_instances = NULL;
   config.current_instance = NULL;
   config.new_app_instances =  wolist_new(16);
   config.error = 0;
   config.errorLocation = buf;
   
   if (len == 0)
      return 1; 		/* no content is considered an error */
   
   /* Set up a new document handler struct for the parser */
   memcpy(&handler, &_document, sizeof(XMLCDocumentHandler));
   handler.document = (XMLCDocument *)(&config);

   /* set up and invoke the xml parser */
   parser = xmlcParserInit();
   xmlcTokenizerSetBuffer(parser->tokenizer, buf, len);
   xmlcParserSetPreserveWhiteSpace(parser, 0);
   error = (int)xmlcParserParse(parser, &handler);

   if (error != 0) {
      /* config error */
      WOLog(WO_ERR,"Error parsing configuration: %s", xmlcParserErrorDescription(error));
      if ((intptr_t)config.errorLocation < (intptr_t)buf + len)
      {
         char *badconfig = WOMALLOC((len+1)*sizeof(char));
         strncpy(badconfig, buf, len);
         badconfig[len] = '\0';
         WOLog(WO_ERR,"Error near:\n%s", config.errorLocation);
         WOFREE(badconfig);
      }
   } else {
      /*
       *	load the new settings...
       */
      if (config.new_apps)
         for (i=0; i<wolist_count(config.new_apps); i++)
            ac_updateApplication((strtbl *)wolist_elementAt(config.new_apps, i), (list *)wolist_elementAt(config.new_app_instances, i));
   }

   /* clean up and return */
   freeWOXMLEdits(&config);
   xmlcParserDealloc(parser);
   return error;
}
Пример #5
0
static void copyHeaderForServerVariable(char *var, EXTENSION_CONTROL_BLOCK *p, HTTPRequest *req) {
    char *buf, *value, stackBuf[2048];
    DWORD bufsz = sizeof(stackBuf), pos;

    WOLog(WO_DBG, "reading buffer for server variable %s", var);
    if (p->GetServerVariable(p->ConnID, var, stackBuf, &bufsz) == TRUE) {
        buf = stackBuf;
    } else {
        if(GetLastError() == 122) // ERROR_INSUFFICIENT_BUFFER
        {
            WOLog(WO_DBG, "buffer too small; need %d", bufsz);
            buf = WOMALLOC(bufsz);
            if (p->GetServerVariable(p->ConnID, var, buf, &bufsz) != TRUE)
            {
                WOFREE(buf);
                WOLog(WO_ERR, "Could not get header.");
                return;
            }
        } else
            return; // header not set
    }

    if (buf) {
        //WOLog(WO_DBG, "got raw buffer: %s", buf);
        pos = 0;
        while (pos < bufsz) {
            while (pos < bufsz && buf[pos] < 33)
                pos++;
            if (pos < bufsz)  {
                /* got start of new value */
                value = &buf[pos];
                do {
                    while (pos < bufsz && buf[pos] != '\r')
                        pos++;
                    if (pos + 2 < bufsz && buf[pos+1] == '\n' && (buf[pos+2] == ' ' || buf[pos+2] == '\t')) {
                        /* got a multiline header; change CRLF to whitespace and keep parsing */
                        buf[pos] = ' ';
                        buf[pos+1] = ' ';
                    } else {
                        buf[pos] = 0;
                    }
                } while (pos < bufsz && buf[pos] != 0);
                WOLog(WO_DBG, "found value=\"%s\"", value ? value : "(NULL)");
                if (value)
                    req_addHeader(req, var, value, STR_COPYKEY|STR_COPYVALUE);
                else
                    req_addHeader(req, var, "", STR_COPYKEY);
            }
        }
        if (buf != stackBuf)
            WOFREE(buf);
    }

   return;
}
Пример #6
0
int req_sendRequest(HTTPRequest *req, net_fd socket)
{
   struct iovec *buffers, *bufferIterator;
   int bufferCount, result;

   buffers = WOMALLOC((st_count(req->headers) * 4 + 3) * sizeof(struct iovec));
   buffers[0].iov_base = req->request_str;
   buffers[0].iov_len = strlen(req->request_str);
   bufferIterator = &buffers[1];
   st_perform(req->headers, (st_perform_callback)setupIOVec, &bufferIterator);
   bufferIterator->iov_base = "\r\n";
   bufferIterator->iov_len = 2;
   bufferCount = st_count(req->headers) * 4 + 2;
   if (req->content_length > 0)
   {
      bufferCount++;
      bufferIterator++;
      bufferIterator->iov_base = req->content;
      bufferIterator->iov_len = req->content_buffer_size;
   }
   result = transport->sendBuffers(socket, buffers, bufferCount);

   /* If we are streaming the content data, continue until we have sent everything. */
   /* Note that we reuse buffers, and the existing content-data buffer. */
   if (req->content_length > req->content_buffer_size)
   {
      long total_sent = req->content_buffer_size;
      long len_read, amount_to_read;
      req->haveReadStreamedData = 1;
      while (total_sent < req->content_length && result == 0)
      {
         amount_to_read = req->content_length - total_sent;
         if (amount_to_read > req->content_buffer_size)
            amount_to_read = req->content_buffer_size;
         len_read = req->getMoreContent(req, req->content, amount_to_read, 0);
         if (len_read > 0)
         {
            buffers[0].iov_base = req->content;
            buffers[0].iov_len = len_read;
            result = transport->sendBuffers(socket, buffers, 1);
            total_sent += len_read;
         } else if (len_read < 0) {
            WOLog(WO_ERR, "Failed to read streamed content.");
            result = -1;
         }
      }
   }
   WOFREE(buffers);
   if (result == 0)
      result = transport->flush_connection(socket);
   else
      WOLog(WO_ERR, "error sending request");

   return result;
}
Пример #7
0
void req_allocateContent(HTTPRequest *req, unsigned content_length, int allowStreaming)
{
   if (req) {
      req->content_buffer_size = content_length;
      if (allowStreaming && req->content_buffer_size > REQUEST_STREAMED_THRESHOLD)
      {
         req->content_buffer_size = REQUEST_STREAMED_THRESHOLD;
         WOLog(WO_DBG, "req_allocateContent(): content will be streamed. content length = %d", content_length);
      }
      req->content = WOMALLOC(req->content_buffer_size);
      if (!req->content)
         req->content_buffer_size = 0;
   }
}
Пример #8
0
void sd_setCapacity(strdict *sd, unsigned newsize)
{
   strdictel *newElements;
   if (sd->head != NULL)
      newElements = WOREALLOC(sd->head, newsize * sizeof(strdictel));
   else
      newElements = WOMALLOC(newsize * sizeof(strdictel));
   if (newElements)
   {
      sd->head = newElements;
      sd->capacity = newsize;
   }
   return;
}
Пример #9
0
/*
 *      Called from the xml parser.
 *	Here is where we begin parsing <application>... or <instance>...
 *	or <adaptor>...
 */
static void createElement(XMLCDocument *document, const XMLCCharacter *name, const unsigned int length)
{
   WOXMLEdits *config = (WOXMLEdits *)document;

   if (config->error != 0)		/* would be nice to tell parser to stop */
      return;

   config->errorLocation = name;
   
   if (length == 7 && strncasecmp(name, "adaptor", length) == 0)
   {
      /* do nothing; don't generate a warning */
   } else if (length == 11 && strncasecmp(name, "application", length) == 0) {
      /* begin <application> */
      if (config->current_element != NULL) {
         WOLog(WO_ERR,"Error parsing config: found unexpected <application> tag");
         config->error = 1;
         return;
      }
      /* create new app settings dictionary, instance list, and set current_element to the app dictionary*/
      config->current_app = st_new(8);
      wolist_add(config->new_apps, config->current_app);
      config->current_app_instances = wolist_new(8);
      wolist_add(config->new_app_instances, config->current_app_instances);
      config->current_element = config->current_app;

   } else if (length == 8 && strncasecmp(name, "instance", length) == 0) {
      /* begin <instance> */
      if (config->current_element != config->current_app || config->current_app == NULL) {
         WOLog(WO_ERR,"Error parsing config: found unexpected <instance> tag");
         config->error = 1;
         return;
      }
      /* create new instance settings dictionary and set current_element to point to it */
      config->current_instance = st_new(8);
      wolist_add(config->current_app_instances, config->current_instance);
      config->current_element = config->current_instance;

   } else {
      /* Got something unexpected. Ignore the tag. */
      char *buffer = WOMALLOC(length+1);
      strncpy(buffer,name,length);
      buffer[length] = '\0';
      WOLog(WO_WARN,"Unknown tag in XML: \"%s\"",buffer);
      config->current_element = NULL;
      WOFREE(buffer);
   }
   return;
}
Пример #10
0
WA_recursiveLock WA_createLock(const char *name)
{
   WinRecursiveLock *lock;

   lock = WOMALLOC(sizeof(WinRecursiveLock));
   if (lock)
   {
      lock->lock = CreateMutex(NULL, FALSE, NULL);
      if (name)
         lock->name = name;
      else
         lock->name = unnamedLock;
   } else
      WOLog(WO_ERR, "WA_createLock(): could not malloc");
   return (WA_recursiveLock)lock;
}
Пример #11
0
/*
 * Attempt to expand the capacity of the string table.
 * If the allocation fails, the string table is unchanged.
 */
static void st_setCapacity(strtbl *st, unsigned newsize)
{
    strtblelem *newHead;
    if (newsize < MIN_CAPACITY)
        newsize = MIN_CAPACITY;
    if (st->head != NULL)
        newHead = WOREALLOC(st->head, newsize * sizeof(strtblelem));
    else
        newHead = WOMALLOC(newsize * sizeof(strtblelem));
    if (newHead)
    {
        st->head = newHead;
        st->capacity = newsize;
    } else
        WOLog(WO_ERR, "st_setCapacity(): failed to expand capacity (%d)", newsize);
    return;
}
Пример #12
0
/* You're responsible for freeing the header returned ! */
static char *getHeader(EXTENSION_CONTROL_BLOCK *p, const char *key)
{
#define BUFSZ 2048
   char temp_hdr[BUFSZ];
   DWORD	len = BUFSZ;
   char *hdr = NULL;

   if (p->GetServerVariable(p->ConnID, (char *)key,  temp_hdr, &len) == TRUE) {
      if (len!=0) {
         /* len includes the terminating 0 */
         hdr = WOMALLOC((len)*sizeof(char));
         strncpy(hdr, temp_hdr, len);
         hdr[len-1]='\0';
         return hdr;
      }
   }
   return NULL;
}
Пример #13
0
WA_recursiveLock WA_createLock(const char *name)
{
   CThreadRecursiveLock *lock;

   lock = WOMALLOC(sizeof(CThreadRecursiveLock));
   if (lock)
   {
      mutex_init(&lock->m);
      condition_init(&lock->c);
      lock->lockCount = 0;
      lock->lockingThread = NULL;
      if (name)
         lock->name = name;
      else
         lock->name = unnamedLock;
   }
   return lock;
}
Пример #14
0
WA_recursiveLock WA_createLock(const char *name)
{
   PThreadRecursiveLock *lock;

   lock = WOMALLOC(sizeof(PThreadRecursiveLock));
   if (lock)
   {
      pthread_mutex_init(&lock->m, NULL);
      pthread_cond_init(&lock->c, NULL);
      lock->lockCount = 0;
      lock->lockingThread = 0;
      if (name)
         lock->name = name;
      else
         lock->name = unnamedLock;
   }
   return lock;
}
Пример #15
0
WA_recursiveLock WA_createLock(const char *name)
{
   NSAPIThreadRecursiveLock *lock;

   lock = WOMALLOC(sizeof(NSAPIThreadRecursiveLock));
   if (lock)
   {
      lock->crit = crit_init();
      lock->condvar = condvar_init(lock->crit);
      lock->lockCount = 0;
      lock->lockingThread = NULL;
      if (name)
         lock->name = name;
      else
         lock->name = unnamedLock;
   }
   if (!lock)
      WOLog(WO_ERR, "WA_createLock() failed for lock %s", name ? name : unnamedLock);
   return lock;
}
Пример #16
0
/*
 *	reformat URL to conform to our norms.  also has side effect of
 *	setting 'REQUEST_METHOD' header
 */
void req_reformatRequest(HTTPRequest *req, WOAppReq *app, WOURLComponents *wc, const char *http_version)
{
   char *default_http_version = "HTTP/1.1";
   int http_version_length = http_version ? strlen(http_version) : strlen(default_http_version);

   wc->applicationName.start = app->name;
   wc->applicationName.length = strlen(app->name);
   wc->applicationNumber.start = app->instance;		/* note that this is by reference */
   wc->applicationNumber.length = strlen(app->instance);
   wc->applicationHost.start = app->host;
   wc->applicationHost.length = strlen(app->host);

   if (req->request_str)
      WOFREE(req->request_str);

   /* METHOD + SizeURL + SPACE + http_version_length + \r\n + NULL) */
   req->request_str = WOMALLOC(strlen(req->method_str) + 1 + SizeURL(wc) + 1 + http_version_length + 2 + 1); 

   strcpy(req->request_str, req->method_str);
   strcat(req->request_str," ");
   req_addHeader(req, REQUEST_METHOD_HEADER, req->method_str, 0);
   
   ComposeURL(req->request_str + strlen(req->request_str), wc, req->shouldProcessUrl);
   strcat(req->request_str," ");
   if (http_version)
   {
       strcat(req->request_str,http_version);
       if (strcasecmp(http_version,"HTTP/1.1") == 0)
       {
           req_addHeader(req, "Host", app->host, 0);
       }
   } else {
       strcat(req->request_str,default_http_version);
       req_addHeader(req, "Host", app->host, 0);
   }
   strcat(req->request_str,"\r\n");

   WOLog(WO_INFO,"New request is %s",req->request_str);

   return;
}
Пример #17
0
/*
 * Obtain a lock on a chunk of shared memory. The range of memory
 * begins add address addr, and is size bytes in length. If exclusive
 * is zero the lock is a shared lock for read only access to the region.
 * If exclusive is nonzero the lock is an exclusive lock for write
 * access to the region.
 * The return value is a handle which must be supplied to the WOShmem_unlock
 * function when the lock is released. If some error occurrs and
 * a lock could not be obtained, NULL is returned.
 */
void *WOShmem_lock(const void *addr, size_t size, int exclusive)
{
   struct flock *lockInfo;
   ptrdiff_t offset;
   LockInfo *info = NULL;

   if (addr && WOShmem_fd != -1)
   {
      offset = addr_to_offset(addr);
      if (offset >= 0 && offset + size < WOShmem_size)
      {
         /* This gets called a lot, so as an optimization to avoid the malloc() overhead */
         /* we keep a cache of LockInfo's. */
         WA_lock(WOShmem_mutex);
         info = WOShmem_lockInfoCache;
         if (info)
            WOShmem_lockInfoCache = info->cache;
         WA_unlock(WOShmem_mutex);

         /* if there wasn't one in the cache, malloc a new one */
         if (!info)
            info = WOMALLOC(sizeof(LockInfo));
         
         if (info)
         {
            lockInfo = &info->flockInfo;
            if (lock_file_section(WOShmem_fd, offset, size, lockInfo, exclusive))
            {
               /* failed; put the info struct back on the cache */
               WA_lock(WOShmem_mutex);
               info->cache = WOShmem_lockInfoCache;
               WOShmem_lockInfoCache = info;
               WA_unlock(WOShmem_mutex);
               info = NULL;
            }
         }
      }
   }
   return info;
}
Пример #18
0
int resp_getResponseContent(HTTPResponse *resp, int allowStreaming)
{
   int ret = 0;
   if (resp->content_length) {
      int count, amountToRead;

      if (resp->content == NULL)
      {
         resp->content_buffer_size = resp->content_length;
         if (allowStreaming && (resp->content_buffer_size > RESPONSE_STREAMED_SIZE))
            resp->content_buffer_size = RESPONSE_STREAMED_SIZE;
         resp->content = WOMALLOC(resp->content_buffer_size);
      }
      amountToRead = resp->content_length - resp->content_read;
      if (amountToRead > resp->content_buffer_size)
         amountToRead = resp->content_buffer_size;
      count = transport->recvbytes(resp->instanceConnection->fd, resp->content, amountToRead);
      if (count != amountToRead) {
         // 2009/06/09: either the content length was wrong, unset or the
         //             application has died.  Please use the return value
         //             to resolve this situation in the caller method (if
         //             desired): this method returns 0 on success, -1 if no
         //             data was received from the WebObjects application and
         //             > 0 if an incomplete data package was received (the
         //             return value describes the number of received bytes
         //             in such a situation).
         WOLog(WO_WARN, "Received an unexpected number of bytes (expected %d bytes, got %d)",
               amountToRead, count);
         resp->content_valid = 0;
         ret = ((count == 0)? -1 : count);
      } else {
         resp->content_read += amountToRead;
         resp->content_valid = amountToRead;
      }
   }
   if(ret != 0) resp->flags |= RESP_LENGTH_INVALID;

   return ret;
}
Пример #19
0
ShmemArray *sha_alloc(const char *name, void *arrayBase, size_t elementSize, unsigned int elementCount)
{
   ShmemArray *array;
   int i;

   array = WOMALLOC(sizeof(ShmemArray) + sizeof(ShmemArrayElement) * (elementCount-1));
   if (array)
   {
      array->name = WOSTRDUP(name);
      array->elementSize = elementSize;
      array->elementCount = elementCount;
      for (i=0; i<array->elementCount; i++)
      {
         array->elements[i].element = (void *)(arrayBase + elementSize * i);
         array->elements[i].lock = WA_createLock("array element lock");
         array->elements[i].writeLock = WA_createLock("array element write lock");
         array->elements[i].lockCount = 0;
         array->elements[i].lockHandle = NULL;
         array->elements[i].localData = NULL;
         array->elements[i].localDataCleanupCallbacks = NULL;
      }
   }
   return array;
}
Пример #20
0
/*
 *	the thing that gets called...
 */
__declspec(dllexport) DWORD HttpExtensionProc(EXTENSION_CONTROL_BLOCK *p)
{
   HTTPRequest *req;
   HTTPResponse *resp = NULL;
   WOURLComponents wc = WOURLComponents_Initializer;
   const char *reqerr;
   const char *qs;
   char *script_name;
   char *server_protocol;
   char *uri;
   WOURLError urlerr;

   if (!adaptorEnabled)
   {
      WOLog(WO_ERR, "WebObjects adaptor disabled.");
      return HSE_STATUS_ERROR;
   }
   
   /*
    *	extract WebObjects request components from URI
    */
   script_name = getHeader(p, CGI_SCRIPT_NAME);
   uri = WOMALLOC(strlen(p->lpszPathInfo) + strlen(script_name) + 1);
   strcpy(uri, script_name);
   strcat(uri, p->lpszPathInfo);
   WOLog(WO_INFO,"<WebObjects ISAPI> new request: %s", uri);
   WOFREE(script_name);

   urlerr = WOParseApplicationName(&wc, uri);

   if (urlerr != WOURLOK) {
      const char *_urlerr;
      _urlerr = WOURLstrerror(urlerr);
      WOLog(WO_INFO,"URL Parsing Error: %s", _urlerr);
      if (urlerr == WOURLInvalidApplicationName) {
          if (ac_authorizeAppListing(&wc)) {
              resp = WOAdaptorInfo(NULL, &wc);
              WOFREE(uri); /* this has to be freed before a return in this function */
              return die_resp(p, resp);
          } else {
              WOFREE(uri); /* this has to be freed before a return in this function */
              return die(p, _urlerr, HTTP_NOT_FOUND);
          }
      }
      WOFREE(uri); /* this has to be freed before a return in this function */
      return die(p, _urlerr, HTTP_BAD_REQUEST);
   }

   /*
    *	build the request...
    */
   req = req_new(p->lpszMethod, NULL);

   /*
    *	validate the method
    */
   reqerr = req_validateMethod(req);
   if (reqerr) {
      req_free(req);
      WOFREE(uri); /* this has to be freed before a return in this function */
      return die(p,reqerr, HTTP_BAD_REQUEST);
   }

   /*
    *	get the headers....
    */
   copyHeaders(p, req);

   /*
    *	get form data if any
    *   assume that POSTs with content length will be reformatted to GETs later
    */
   req->content_length = p->cbTotalBytes;
   if (req->content_length > 0)
   {
      char *buffer = WOMALLOC(req->content_length);

      if (p->cbAvailable > 0)
         memcpy(buffer, p->lpbData, p->cbAvailable);

      /*
       * IIS has a weird (or is it convenient?) data queuing mechanism...
       */
      if (req->content_length > p->cbAvailable) {
          DWORD len;
          DWORD totalLength, fetchedLength;

          len = req->content_length - p->cbAvailable;
          totalLength = len;
          fetchedLength = 0;

          while (fetchedLength < totalLength) {
              len = totalLength - fetchedLength;

              if (p->ReadClient (p->ConnID,buffer + p->cbAvailable + fetchedLength, &len) != TRUE) {
                  WOFREE(buffer);
                  req_free(req);
                  return die(p, INV_FORM_DATA, HTTP_BAD_REQUEST);
              }

              fetchedLength += len;
          }
      }
      req->content = buffer;
      if (req_HeaderForKey(req, CONTENT_LENGTH) == NULL) {
         char *length;
         length = (char *)WOMALLOC(32);
         if (length)
         {
            sprintf(length,"%d",req->content_length);
            req_addHeader(req, CONTENT_LENGTH, length, STR_FREEVALUE);
         }
         if (p->lpszContentType != NULL)
            req_addHeader(req, CONTENT_TYPE, p->lpszContentType, 0);
      }
   }

   /* Always get the query string */
   qs = p->lpszQueryString;
   wc.queryString.start = qs;
   wc.queryString.length = qs ? strlen(qs) : 0;

   /*
    *	message the application & collect the response
    *
    *	note that handleRequest free()'s the 'req' for us
    */
   if (resp == NULL) {
      /* if no error so far... */
      req->api_handle = p;			/* stash this... */
      server_protocol = getHeader(p, CGI_SERVER_PROTOCOL);
      resp = tr_handleRequest(req, uri, &wc, server_protocol, NULL);
      WOFREE(server_protocol);
   }

   if (resp != NULL) {
      sendResponse(p, resp);
      resp_free(resp);
   }

   WOFREE(uri); /* this has to be freed before a return in this function */
   req_free(req);
#if defined(FINDLEAKS)
      showleaks();
#endif
   return HSE_STATUS_SUCCESS;
}
Пример #21
0
/*
 *	Copy Headers into the request.
 *
 *	This is kind of like an easter egg hunt, CGI equivilant headers are
 *	stashed all over in different pblocks.  Do the best we can without
 *	missing any...
 */
static void copyHeaders(pblock *pb, Session *sn, Request *rq, HTTPRequest *req)
{
   int i;
   const char *hdrval;
   char *portstr;
   const char *server;


   /*
    *	the following line will generate a compiler warning. uncomment if
    *	Netscape ever implements it. request_loadheaders(sn,rq);
    */

   /*
    *	first, blindly copy the request headers
    */
   for (i=0; i < rq->headers->hsize; i++) {
      struct pb_entry *entry = rq->headers->ht[i];
      while (entry != NULL) {
         pb_param *hdr = entry->param;
         if (hdr != NULL)
            req_addHeader(req, hdr->name, hdr->value, 0);
         	   entry = entry->next;
      }
   }

   for (i=0; i < rq->vars->hsize; i++) {
      struct pb_entry *entry = rq->vars->ht[i];
      while (entry != NULL) {
         pb_param *hdr = entry->param;
          if (hdr != NULL) {
              /*
               * BEGIN Support for getting the client's certificate as one liner.
               */
              if (strcmp((const char *)hdr->name, "auth-cert") == 0 && hdr->value != NULL) {
                  const char *val = (const char *)make_cert_one_line((char *)hdr->value);
                  if(val != NULL){
                      req_addHeader(req, "SSL_CLIENT_CERT", val, 0);
                      //WOLog(WO_DBG, "Adding server variable %s", hdr->name);
                      //WOLog(WO_DBG, "With value %s", hdr->value);
                  }
                  /*
                   * END Support for getting the client's certificate.
                   */
                  else {
                      req_addHeader(req, hdr->name, hdr->value, 0);
                      //WOLog(WO_DBG, "Adding server variable %s", hdr->name);
                      //WOLog(WO_DBG, "With value %s", hdr->value);
                  }
              }
         }
         entry = entry->next;
      }
   }

   if (req->method == HTTP_POST_METHOD)
      req_addHeader(req,"REQUEST_METHOD","POST", 0);
   else if (req->method == HTTP_HEAD_METHOD)
      req_addHeader(req,"REQUEST_METHOD","HEAD", 0);
   else
      req_addHeader(req,"REQUEST_METHOD","GET", 0);

   /*
    *	collect up the server specific headers
    */
   cpyhdr("ip", sn->client, req, "REMOTE_ADDR");
   cpyhdr("query", rq->reqpb, req, "QUERY_STRING");
   cpyhdr("protocol", rq->reqpb, req, "SERVER_PROTOCOL");

   hdrval = session_maxdns(sn);
   if (!hdrval)	hdrval = session_dns(sn);
   if (hdrval)
      req_addHeader(req, "REMOTE_HOST", hdrval, 0);
   req_addHeader(req, "SERVER_SOFTWARE", system_version(), 0);
   portstr = (char *)WOMALLOC(32);
   if (portstr)
   {
      util_itoa(server_portnum, portstr);
      req_addHeader(req, "SERVER_PORT", portstr, STR_FREEVALUE);
   }

   /*
    *	Netscape claims to have fixed this in 3, if it causes a problem
    *	comment it out
    */
   server = server_hostname;
   if (server != NULL)
      req_addHeader(req, "SERVER_NAME", server, 0);


   return;
}
Пример #22
0
int req_sendRequest(HTTPRequest *req, net_fd socket) 
{
   struct iovec *buffers;
   int bufferCount, appStatus;
   int browserStatus = 0;
   String *headersString;

   buffers = WOMALLOC(3 * sizeof(struct iovec));

   headersString = str_create(req->request_str, 0);
   if (headersString) 
   {
      st_perform(req->headers, (st_perform_callback)req_appendHeader, headersString);
   }
   buffers[0].iov_base = headersString->text;
   buffers[0].iov_len = headersString->length;
   buffers[1].iov_base = "\r\n";
   buffers[1].iov_len = 2;
   bufferCount = 2;
   if (req->content_length > 0) 
   {
      bufferCount++;
      buffers[2].iov_base = req->content;
      buffers[2].iov_len = req->content_buffer_size;
   }
   appStatus = transport->sendBuffers(socket, buffers, bufferCount);
   str_free(headersString);

   /* If we are streaming the content data, continue until we have sent everything. */
   /* Note that we reuse buffers, and the existing content-data buffer. */
   if (req->content_length > req->content_buffer_size)
   {
      long total_sent = req->content_buffer_size;
      long len_read, amount_to_read;
      req->haveReadStreamedData = 1;
      while (total_sent < req->content_length)
      {
         amount_to_read = req->content_length - total_sent;
         if (amount_to_read > req->content_buffer_size)
            amount_to_read = req->content_buffer_size;
         len_read = req->getMoreContent(req, req->content, amount_to_read, 0);
         if (len_read > 0)
         {
            if(appStatus == 0)
            {
               buffers[0].iov_base = req->content;
               buffers[0].iov_len = len_read;
               appStatus = transport->sendBuffers(socket, buffers, 1);
               // 2009/04/28: in case of a transport error, carry on with reading
               //             incoming input stream (= browser data).  That way,
               //             the browser (hopefully) switch to the receive mode
               //             after sending the complete request and receives/shows
               //             the adaptor error message (old behaviour: endless
               //             sending/uploading view).
               if(appStatus != 0)
               {
                  WOLog(WO_ERR, "Failed to send streamed content.");
               }
            }
            total_sent += len_read;
         } else if (len_read < 0) {
            WOLog(WO_ERR, "Failed to read streamed content.");
            browserStatus = -1;
            break;
         }
      }
   }
   WOFREE(buffers);
   if(browserStatus != 0) WOLog(WO_ERR, "error receiving request");
   if (appStatus == 0)
   {
      // 2009/04/30: as long as we haven't received any error message from
      //             the instance, flush the socket to complete the data
      //             transfer!
      appStatus = transport->flush_connection(socket);
   }
   else
      WOLog(WO_ERR, "error sending request");

   return
       ((appStatus != 0)
          ? appStatus
          : browserStatus);
}
Пример #23
0
/*
 *	the thing that gets called...
 */
__declspec(dllexport) DWORD __stdcall HttpExtensionProc(EXTENSION_CONTROL_BLOCK *p)
{
   HTTPRequest *req;
   HTTPResponse *resp = NULL;
   WOURLComponents wc = WOURLComponents_Initializer;
   const char *reqerr;
   const char *qs;
   char *script_name;
   char *server_protocol;
   char *uri;
   WOURLError urlerr;

   if (!adaptorEnabled)
   {
      WOLog(WO_ERR, "WebObjects adaptor disabled.");
      return HSE_STATUS_ERROR;
   }
   
   // Deactivate IIS 7.x stream buffering
   //   IIS 7.x (and above?) behaves differently from IIS 6 by introducing 
   //   output buffering ISAPI Extension output
   //   This could cause interrupted and hence incomplete streaming output
   //   This change does deactivate the output buffering in IIS 7.x
   //    (see http://support.microsoft.com/kb/946086) and does not harm
   //    when called within IIS 6
   //
   p->ServerSupportFunction (p->ConnID,
      HSE_REQ_SET_FLUSH_FLAG,
      (LPVOID) TRUE,
      NULL,
      NULL
      );

   /*
    *	extract WebObjects request components from URI
    */
   script_name = getHeader(p, CGI_SCRIPT_NAME);
   uri = WOMALLOC(strlen(p->lpszPathInfo) + strlen(script_name) + 1);
   strcpy(uri, script_name);
   strcat(uri, p->lpszPathInfo);
   WOLog(WO_INFO,"<WebObjects ISAPI> new request: %s", uri);
   WOFREE(script_name);

   urlerr = WOParseApplicationName(&wc, uri);

   if (urlerr != WOURLOK) {
      const char *_urlerr;
      _urlerr = WOURLstrerror(urlerr);
      WOLog(WO_INFO,"URL Parsing Error: %s", _urlerr);
      if (urlerr == WOURLInvalidApplicationName) {
          if (ac_authorizeAppListing(&wc)) {
              resp = WOAdaptorInfo(NULL, &wc);
              WOFREE(uri); /* this has to be freed before a return in this function */
              return die_resp(p, resp);
          } else {
              WOFREE(uri); /* this has to be freed before a return in this function */
              return die(p, _urlerr, HTTP_NOT_FOUND);
          }
      }
      WOFREE(uri); /* this has to be freed before a return in this function */
      return die(p, _urlerr, HTTP_BAD_REQUEST);
   }

   /*
    *	build the request...
    */
   req = req_new(p->lpszMethod, NULL);
   req->api_handle = p;

   /*
    *	get the headers....
    */
   copyHeaders(p, req);

   /*
    *	validate the method
    */
   reqerr = req_validateMethod(req);
   if (reqerr) {
      req_free(req);
      WOFREE(uri); /* this has to be freed before a return in this function */
      return die(p,reqerr, HTTP_BAD_REQUEST);
   }

   /*
    *	get form data if any
    *   assume that POSTs with content length will be reformatted to GETs later
    */
   req->content_length = p->cbTotalBytes;
   if (req->content_length > 0)
   {
      req_allocateContent(req, req->content_length, 1);
      req->getMoreContent = (req_getMoreContentCallback)readContentData;
      req->total_len_read = 0;

      if (req->content_buffer_size == 0)
      {
          WOFREE(uri); /* this has to be freed before a return in this function */
          req_free(req);
          return die(p, ALLOCATION_FAILURE, HTTP_SERVER_ERROR);
      }
      if (readContentData(req, req->content, req->content_buffer_size, 1) == -1) {
         WOFREE(uri); /* this has to be freed before a return in this function */
         req_free(req);
         return die(p, WOURLstrerror(WOURLInvalidPostData), HTTP_BAD_REQUEST);
      }
   }

   /* Always get the query string */
   qs = p->lpszQueryString;
   wc.queryString.start = qs;
   wc.queryString.length = qs ? strlen(qs) : 0;

   /*
    *	message the application & collect the response
    *
    *	note that handleRequest free()'s the 'req' for us
    */
   if (resp == NULL) {
      /* if no error so far... */
      server_protocol = getHeader(p, CGI_SERVER_PROTOCOL);
      resp = tr_handleRequest(req, uri, &wc, server_protocol, NULL);
      WOFREE(server_protocol);
   }

   if (resp != NULL) {
      sendResponse(p, resp);
      resp_free(resp);
   }

   WOFREE(uri); /* this has to be freed before a return in this function */
   req_free(req);
#if defined(FINDLEAKS)
      showleaks();
#endif
      return HSE_STATUS_SUCCESS;
}
Пример #24
0
static int readContentData(HTTPRequest *req, void *dataBuffer, int dataSize, int mustFill)
{
    EXTENSION_CONTROL_BLOCK *p = (EXTENSION_CONTROL_BLOCK *)req->api_handle;
    DWORD len_remaining = dataSize;
    DWORD total_len_read = 0;
    char *buffer = (char *)dataBuffer;
    MS_BOOL readStatus;
    unsigned int lenZeroCounter = 0;

    DWORD len;
    if(p->cbAvailable > req->total_len_read)
    {
        len = p->cbAvailable - req->total_len_read;
        if(len > dataSize) len = dataSize;
        memcpy(buffer, p->lpbData + req->total_len_read, len);
        
        total_len_read += len;
        len_remaining -= len;
    }

    /*
     * IIS has a weird (or is it convenient?) data queuing mechanism...
     */
    while(len_remaining > 0 &&
          (mustFill || total_len_read == 0))
    {
        len = len_remaining;
        readStatus = p->ReadClient (p->ConnID,buffer + total_len_read, &len);
        if(readStatus == TRUE)
        {
           // 2009/04/29: avoid endless loops, because the ReadClient function
           //             will return TRUE but with zero bytes read if the
           //             socket on which the server is listening to the client
           //             is closed!!!
           lenZeroCounter =
              ((len == 0)? (lenZeroCounter + 1) : 0);
           if(lenZeroCounter > MAGIC_LEN_ZERO_LIMIT)
           {
               readStatus = FALSE;
           }
        }

        if(readStatus != TRUE)
        {
           if(lenZeroCounter > MAGIC_LEN_ZERO_LIMIT)
           {
              WOLog(WO_ERR,"ReadClient failed (client socket closed?).");
           }
           else
           {
              WOLog(WO_ERR,"ReadClient failed");
           }
           die(p, INV_FORM_DATA, HTTP_BAD_REQUEST);
           return -1;
        }

        total_len_read += len;
        len_remaining -= len;
    }

    // still required? - BEGIN
    if (req_HeaderForKey(req, CONTENT_LENGTH) == NULL) {
       char *length;
       length = (char *)WOMALLOC(32);
       if (length)
       {
          sprintf(length,"%lu",req->content_length);
          req_addHeader(req, CONTENT_LENGTH, length, STR_FREEVALUE);
       }
       if (p->lpszContentType != NULL)
          req_addHeader(req, CONTENT_TYPE, p->lpszContentType, 0);
    }
    // still required? - END

    req->total_len_read += total_len_read;
    return total_len_read;
}
Пример #25
0
static void copyHeadersAllRaw(EXTENSION_CONTROL_BLOCK *p, HTTPRequest *req) {
    char *buf, *key, *value, stackBuf[2048];
    DWORD bufsz = sizeof(stackBuf), pos;

    /** client certificate support 
    BYTE* CertificateBuf = (BYTE*)calloc(MAX_CERT_SIZE, sizeof(BYTE));
    CERT_CONTEXT_EX ccex;
    ccex.cbAllocated = MAX_CERT_SIZE;
    ccex.CertContext.pbCertEncoded = CertificateBuf;
    end client certificate support **/

    if (p->GetServerVariable(p->ConnID, "ALL_RAW", stackBuf, &bufsz) == TRUE) {
        buf = stackBuf;
    } else {
        WOLog(WO_DBG, "buffer too small; need %d", bufsz);
        buf = WOMALLOC(bufsz);
        if (p->GetServerVariable(p->ConnID, "ALL_RAW", buf, &bufsz) != TRUE) {
            WOFREE(buf);
            WOLog(WO_ERR, "Could not get headers.");
            return;
        }
    }

    if (buf) {
        //WOLog(WO_DBG, "got raw buffer: %s", buf);
        pos = 0;
        while (pos < bufsz) {
            while (pos < bufsz && buf[pos] < 31)
                pos++;
            if (pos < bufsz)  {
                /* got start of new header */
                key = &buf[pos];
                value = NULL;
                /* search for ':' */
                while (pos < bufsz && buf[pos] != ':')
                    pos++;
                /* change ':' to 0 to terminate key */
                buf[pos] = 0;
                pos++;
                /* look for start of value */
                while (pos < bufsz && (buf[pos] == ' ' || buf[pos] == '\t'))
                    pos++;
                if (pos < bufsz && buf[pos] > 31) {
                    /* got start of value */
                    value = &buf[pos];
                    do {
                        while (pos < bufsz && buf[pos] != '\r')
                            pos++;
                        if (pos + 2 < bufsz && buf[pos+1] == '\n' && (buf[pos+2] == ' ' || buf[pos+2] == '\t')) {
                            /* got a multiline header; change CRLF to whitespace and keep parsing */
                            buf[pos] = ' ';
                            buf[pos+1] = ' ';
                        } else {
                            buf[pos] = 0;
                        }
                    } while (pos < bufsz && buf[pos] != 0);
                }

                // do not pass connection setting from client to WO app as this interferes
                //  with our own connection pooling
                if (strcasecmp(key, CONNECTION) == 0)
                    continue;
                
                WOLog(WO_DBG, "found key=\"%s\", value=\"%s\"", key, value ? value : "(NULL)");
                if (value)
                    req_addHeader(req, key, value, STR_COPYKEY|STR_COPYVALUE);
                else
                    req_addHeader(req, key, "", STR_COPYKEY);
            }
        }
        if (buf != stackBuf)
            WOFREE(buf);
    }

    /** client certificate support

    if (p->ServerSupportFunction(p->ConnID, HSE_REQ_GET_CERT_INFO_EX, (LPVOID)&ccex, 0, 0) == FALSE) {
        WOLog(WO_DBG, "Didn't get a certificate, oh well.");
    } else {
        // ccex now contains valid client certificate information.
        DWORD clen = ccex.CertContext.cbCertEncoded;
        char* cstr = make_cert_one_line((BYTE*)CertificateBuf, clen);
        //Don't bother copying the key or value
        req_addHeader(req, "SSL_CLIENT_CERT", cstr, 0);
        free(CertificateBuf);
        free(cstr);
    }
    end client certificate support **/

    return;
}
Пример #26
0
/*
 *	the request handler...
 */
NSAPI_PUBLIC
int WebObjectsRequest(pblock *pb, Session *sn, Request *rq)
{
   HTTPRequest *req;
   HTTPResponse *resp = NULL;
   WOURLComponents wc = WOURLComponents_Initializer;
   const char *reqerr;
   const char *qs;
   int retval;
   char *uri;
   WOURLError urlerr;

   if (!adaptorEnabled)
      return REQ_NOACTION;

   /* spew debug info */
   dump_pb(sn->client,"service.sn->client");
   dump_pb(pb,"service.pb");
   dump_pb(rq->vars,"service.rq->vars");
   dump_pb(rq->reqpb,"service.rq->reqpb");
   dump_pb(rq->headers,"service.rq->headers");
   dump_pb(rq->srvhdrs,"service.rq->srvhdrs");

   uri = pblock_findval("uri", rq->reqpb);
   WOLog(WO_INFO,"<WebObjects NSAPI> new request: %s", uri);

   urlerr = WOParseApplicationName(&wc, uri);
   if (urlerr != WOURLOK) {
      const char *_urlerr;
      _urlerr = WOURLstrerror(urlerr);
      WOLog(WO_INFO,"URL Parsing Error: %s", _urlerr);
      if (urlerr == WOURLInvalidApplicationName) {
          if (ac_authorizeAppListing(&wc)) {
              resp = WOAdaptorInfo(NULL, &wc);
              die_resp(sn, rq, resp);
          } else {
              die(sn, rq, _urlerr, HTTP_NOT_FOUND);
          }
      }
          die(sn, rq, _urlerr, HTTP_BAD_REQUEST);
   }

   /*
    *	build the request ....
    */
   req = req_new( pblock_findval("method", rq->reqpb), NULL);

   /*
    *	validate the method
    */
   reqerr = req_validateMethod(req);
   if (reqerr) {
      req_free(req);
       return die(sn,rq,reqerr, HTTP_BAD_REQUEST);
   }

   /*
    *	copy the headers..
    */
   copyHeaders(pb, sn, rq, req);

   /*
    *	get form data if any
    *   assume that POSTs with content length will be reformatted to GETs later
    */
   if (req->content_length > 0)
   {
      int len_remaining = req->content_length;
      char *buffer = WOMALLOC(req->content_length);
      char *data = buffer;
      int c;

      while (len_remaining-- > 0) {
         if ((c = netbuf_getc(sn->inbuf)) == IO_ERROR) {
            log_error(0,"WebObjects",sn,rq,"Error reading form data");
            WOFREE(buffer);
            req_free(req);
            return die(sn,rq,INV_FORM_DATA, HTTP_BAD_REQUEST);
         }
         *data++ = c;
      }
      req->content = buffer;
   }

   /* Always get the query string */
   qs = pblock_findval("query", rq->reqpb);
   wc.queryString.start = qs;
   wc.queryString.length = qs ? strlen(qs) : 0;


   /*
    *	message the application & collect the response
    *
    *	note that handleRequest free()'s the 'req' for us
    */
   if (resp == NULL) {
      /* if no error so far... */
      req->api_handle = rq;				/* stash this in case it's needed */
      resp = tr_handleRequest(req, uri, &wc, pblock_findval("protocol",rq->reqpb), NULL);
   }

   if (resp != NULL) {
      retval = sendResponse(sn, rq, resp);
      resp_free(resp);
   } else {
      retval = REQ_EXIT;		/* no response from app - bail */
   }
   req_free(req);
#if defined(FINDLEAKS)
   showleaks();
#endif

   return retval;
}
Пример #27
0
static net_fd openapp(const char *hostName, int port, unsigned short cto, unsigned short sto, unsigned short rto, int sbufsiz, int rbufsiz)
{
   int s = 0;
   struct in_addr;
   net_fd appfd;
   struct hostent *host;

   host = hl_find(hostName);
   if (host == NULL)
   {
      WOLog(WO_ERR, "openapp(): host lookup failed for %s", hostName);
      return NULL_FD;
   }
   
   WOLog(WO_INFO, "attempting to connect to %s on port %d",host->h_name,port);

   s = socket(AF_INET, SOCK_STREAM, 0);
   if (s < 0) {
      char *errMsg = WA_errorDescription(WA_error());
      WOLog(WO_ERR,"couldn't create socket to %s (%d): %s", host->h_name, port, errMsg);
      WA_freeErrorDescription(errMsg);
      return NULL_FD;
   }

   /* set send buffer size */
   if (sbufsiz != 0) {
      if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *)&sbufsiz, sizeof(sbufsiz)) < 0) {
         char *errMsg = WA_errorDescription(WA_error());
         WOLog(WO_WARN, "openapp(): error setting send buffer size to %d: %s", sbufsiz, errMsg);
         WA_freeErrorDescription(errMsg);
      }
   }

   /* set receive buffer size */
   if (rbufsiz != 0) {
      if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void *)&rbufsiz, sizeof(rbufsiz)) < 0) {
         char *errMsg = WA_errorDescription(WA_error());
         WOLog(WO_WARN, "openapp(): error setting receive buffer size to %d: %s", rbufsiz, errMsg);
         WA_freeErrorDescription(errMsg);
      }
   }

   /* Set the socket to be non-blocking. */
   if (setBlockingState(s, 1) == -1) {
      char *errMsg = WA_errorDescription(WA_error());
      WOLog(WO_ERR,"openapp(): couldn't set socket to nonblocking");
      WA_freeErrorDescription(errMsg);
      closeSocket(s);
      return NULL_FD;
   }

   /* attempt to connect */
   if (nonBlockingConnectHostent(s, cto, host, port) < 0) {
      char *errMsg = WA_errorDescription(WA_error());
      WOLog(WO_ERR,"couldn't connect to %s (%d): %s", host->h_name, port, errMsg);
      WA_freeErrorDescription(errMsg);
      closeSocket(s);
      return NULL_FD;
   }

   /* set up the buffer */
   appfd = WOMALLOC(sizeof(netfd));
   appfd->s = s;
   appfd->status = TR_OK;
   appfd->pos = 0;
   appfd->send_to = sto;
   appfd->recv_to = rto;
   appfd->count = 0;
   return appfd;
}
Пример #28
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;
}