Exemplo n.º 1
0
//-----------------------------------------------------------------------------
// This callback function is used when a complete message is received to
// consume.  We basically need to create a request to handle it, add it to the
// list.  If a reply is sent during the processing, then it will close out the
// request automatically, otherwise it will be up to something else to close it
// out.
static void message_handler(rq_message_t *msg, void *arg)
{
	int processed;
	rq_http_t *http;
	rq_http_req_t *req;

	assert(msg);
	assert(arg);
	
	http = (rq_http_t *) arg;
	assert(http);

	// We dont know what the use of this object will be, so we need to create it
	// and put it in a list (to keep track of it) until something gets rid of it.
	req = req_new(http, http->arg);
	req->msg = msg;

	assert(req->reply);
	assert(BUF_LENGTH(req->reply) == 0);

	assert(msg->data);
	assert(http->risp);
	processed = risp_process(http->risp, req, BUF_LENGTH(msg->data), BUF_DATA(msg->data));
	assert(processed == BUF_LENGTH(msg->data));

	// if we still have the msg pointer as part of the request, then the message
	// hasn't been replied yet, so we need to add the request to the list and
	// let it finish elsewhere. 
	if (req->msg) {
		assert(req->inprocess == 0);
		req->inprocess++;

		// then we need to add this request to the list.
		assert(http->req_list);
		ll_push_head(http->req_list, req);
		req = NULL;
	}
	else {
		// We have already replied to the request, so we dont need it anymore.
		req_free(req);
		req = NULL;
	}
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
static int
mtp_function_bind(struct usb_configuration *c, struct usb_function *f)
{
	int n, rc, id;
	struct usb_ep *ep;
	struct usb_request *req;
	struct proc_dir_entry *mtp_proc = NULL;

	spin_lock_init(&g_usb_mtp_context.lock);
	g_usb_mtp_context.cdev = c->cdev;
	/* allocate interface ID(s) */
	id = usb_interface_id(c, f);
	if (id < 0)
		return id;
	intf_desc.bInterfaceNumber = id;

	/* Find all the endpoints we will use */
	ep = usb_ep_autoconfig(g_usb_mtp_context.cdev->gadget,
						&fs_bulk_in_desc);
	if (!ep) {
		mtp_err("auto-configure hs_bulk_in_desc error\n");
		goto autoconf_fail;
	}
	ep->driver_data = &g_usb_mtp_context;
	g_usb_mtp_context.bulk_in = ep;

	ep = usb_ep_autoconfig(g_usb_mtp_context.cdev->gadget,
						&fs_bulk_out_desc);
	if (!ep) {
		mtp_err("auto-configure hs_bulk_out_desc error\n");
		goto autoconf_fail;
	}
	ep->driver_data = &g_usb_mtp_context;
	g_usb_mtp_context.bulk_out = ep;

	ep = usb_ep_autoconfig(g_usb_mtp_context.cdev->gadget,
						&fs_intr_in_desc);
	if (!ep) {
		mtp_err("auto-configure hs_intr_in_desc error\n");
		goto autoconf_fail;
	}
	ep->driver_data = &g_usb_mtp_context;
	g_usb_mtp_context.intr_in = ep;

	if (gadget_is_dualspeed(g_usb_mtp_context.cdev->gadget)) {
		/* Assume endpoint addresses are the same for both speeds */
		hs_bulk_in_desc.bEndpointAddress =
		    fs_bulk_in_desc.bEndpointAddress;
		hs_bulk_out_desc.bEndpointAddress =
		    fs_bulk_out_desc.bEndpointAddress;
		hs_intr_in_desc.bEndpointAddress =
		    fs_intr_in_desc.bEndpointAddress;
	}

	rc = -ENOMEM;

	for (n = 0; n < MAX_BULK_RX_REQ_NUM; n++) {
		req = req_new(g_usb_mtp_context.bulk_out, BULK_BUFFER_SIZE);
		if (!req)
			goto autoconf_fail;

		pending_reqs[n] = req;

		req->complete = mtp_out_complete;
		req_put(&g_usb_mtp_context.rx_reqs, req);
	}
	for (n = 0; n < MAX_BULK_TX_REQ_NUM; n++) {
		req = req_new(g_usb_mtp_context.bulk_in, BULK_BUFFER_SIZE);
		if (!req)
			goto autoconf_fail;

		req->complete = mtp_in_complete;
		req_put(&g_usb_mtp_context.tx_reqs, req);
	}

	for (n = 0; n < MAX_CTL_RX_REQ_NUM; n++)
		ctl_req_put(&g_usb_mtp_context.ctl_rx_reqs, &ctl_reqs[n]);

	g_usb_mtp_context.int_tx_req =
		req_new(g_usb_mtp_context.intr_in, BULK_BUFFER_SIZE);
	if (!g_usb_mtp_context.int_tx_req)
		goto autoconf_fail;
	g_usb_mtp_context.intr_in_busy = 0;
	g_usb_mtp_context.int_tx_req->complete = mtp_int_complete;

	g_usb_mtp_context.ctl_tx_req =
		req_new(g_usb_mtp_context.cdev->gadget->ep0, 512);
	if (!g_usb_mtp_context.ctl_tx_req)
		goto autoconf_fail;

	misc_register(&mtp_device);

	mtp_proc = create_proc_entry("mtpctl", 0666, 0);
	if (!mtp_proc) {
		mtp_err("creating /proc/mtpctl failed\n");
		goto autoconf_fail;
    }
    mtp_proc->proc_fops = &mtp_ctl_fops;

	return 0;

autoconf_fail:
	rc = -ENOTSUPP;
	mtp_function_unbind(c, f);
	return rc;
}
Exemplo n.º 5
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;
}
Exemplo n.º 6
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;
}