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
/*
 *	Handle the meat of the request:
 *	   - check for a load balanced instance
 *	   - (or) autostart an (or find an autostarted) instance
 *	   - open a socket to the application
 *	   - message the application with the request using HTTP
 *	   - wait for and receive the response
 *	   - free the request
 *	   - return the response
 *
 *	If we can't message the application, retry the request up to
 *	RETRIES times (see config.h).
 *
 */
HTTPResponse *tr_handleRequest(HTTPRequest *req, const char *url, WOURLComponents *wc, const char *server_protocol, const char *docroot)
{
   WOAppReq app;
   int connectionAttempts = 0, searchAttempts = 0;
   HTTPResponse *resp = NULL;
   WOAppHandle appHandle = AC_INVALID_HANDLE;
   _WOApp *woapp = NULL;
   WOInstanceHandle instHandle = AC_INVALID_HANDLE, retryInstHandle;
   _WOInstance *inst;
   int urlVersion, retries = RETRIES;

   memset(&app, 0, sizeof(WOAppReq));
   app.urlVersion = CURRENT_WOF_VERSION_MAJOR;
   app.docroot = docroot;
   app.request = req;				/* valid for request forwarding phase */

   /*
    * copy the application name
    */
   if (wc->applicationName.length != 0 && wc->applicationName.length < WA_MAX_APP_NAME_LENGTH) {
      strncpy(app.name, wc->applicationName.start, wc->applicationName.length);
      app.name[wc->applicationName.length] = '\0';
   }

   /*
    *	find the application
    */
   for (searchAttempts = 0; searchAttempts < 2 && instHandle == AC_INVALID_HANDLE; searchAttempts++)
   {
      /* If the find app succeeds, have to be very careful about the possibility */
      /* that someone else can delete it out from under us. */
      appHandle = ac_findApplication(app.name);
      if (appHandle != AC_INVALID_HANDLE)
      {
         /* cache some info so we don't have to keep the app locked */
         woapp = ac_lockedApp(appHandle);
         urlVersion = woapp->urlVersion;
         app.scheduler = lb_schedulerByName(woapp->loadbalance);
         strncpy(app.redirect_url, woapp->redirect_url, WA_MAX_URL_LENGTH);
         retries = woapp->retries;
         /* extract the request & application information from the URI */
         resp = _collectRequestInformation(&app, wc, url, urlVersion, req);
         if (resp != NULL) {
            ac_unlockApp(appHandle);
            return resp;		/* some kind of error in URI */
         }

         /* note: if we found the app, it is still locked at this point */

         /*
          *	select an app, the request may be requesting a specific instance
          *	or it may be indifferent.  an instance neutral request may be a new
          *	request or a returning one for which the state is not stored in the
          *	app.
          * 	if specified instance does not respond, we'll failover to another
          * 	instance
          */
         if (app.instance[0] == 0) {
            instHandle = tr_selectInstance(&app, woapp);
            if (instHandle != AC_INVALID_HANDLE)
            {
               WOLog(WO_INFO,"Selected new app instance at index %d", instHandle);
               tr_prepareToUseInstance(&app, instHandle);
               ac_unlockInstance(instHandle);
            }
         } else {
            WOLog(WO_INFO,"Selecting specific app instance %s.", app.instance);
            instHandle = ac_findInstance(woapp, app.instance);
            if (instHandle == AC_INVALID_HANDLE)
            {
               WOLog(WO_WARN, "Unable to find instance %s. Attempting to select another.", app.instance);
               instHandle = tr_selectInstance(&app, woapp);
            }
            if (instHandle != AC_INVALID_HANDLE)
            {
               tr_prepareToUseInstance(&app, instHandle);
               ac_unlockInstance(instHandle);
            }
         }

         /* At this point, pendingResponses has been incremented in the instance. */
         /* An instance will not be deleted with a nonzero pendingResponses coung, and */
         /* an app will not be deleted if it has any instances. Now it is ok to unlock the app. */
         ac_unlockApp(appHandle);
      }
      /* If we didn't find the app or if we didn't find a specific requested instance, reload the config */
      if (searchAttempts == 0 && (appHandle == AC_INVALID_HANDLE || (instHandle == AC_INVALID_HANDLE && app.instance[0] == '-')))
      {
         if (app.instance[0] != 0)
            WOLog(WO_INFO, "Requested application '%s' not found. Reloading config.", app.name);
         else
            WOLog(WO_INFO, "Specific instance %s:%s not found. Reloading config.", app.name, app.instance);
         ac_resetConfigTimers();
         ac_readConfiguration();
      } else {
         /* didn't reload the config, so no point in retrying */
         break;
      }
   }

   /*
    *	run the request...
    */
   resp = NULL;
   if (instHandle != AC_INVALID_HANDLE) {
      /* Attempt to send request and read response */
      do {
         /* Fix up URL so app knows it's being load balanced ...  */
         /* We need to do this in the loop to get correct instance number into the request URL */
         req_reformatRequest(req, &app, wc, server_protocol);
         WOLog(WO_INFO,"Sending request to instance number %s, port %d", app.instance, app.port);
         resp = _runRequest(&app, appHandle, instHandle, req);

         /* Cannot retry if we have read some streamed content data because we cannot unwind the byte stream. */
         if (req->haveReadStreamedData)
            retries = 0;
         
         if (resp) {
            if (resp->status == 302) /* redirected */
            {
               if (!req->haveReadStreamedData && st_valueFor(resp->headers, "x-webobjects-refusing-redirection"))
               {
                  /* redirected because instance is refusing new sessions */
                  resp_free(resp);
                  resp = NULL;
                  WOLog(WO_INFO, "Request redirected because instance refusing new sessions.");
               }
            }
         } else {
            if (app.error != err_read)
            {
               connectionAttempts++;
               /* Mark this instance as unresponsive */
               WOLog(WO_INFO,"Marking instance %s dead", app.instance);
               if (app.scheduler->instanceDidNotRespond)
               {
                  inst = ac_lockInstance(instHandle);
                  if (inst)
                  {
                     app.scheduler->instanceDidNotRespond(inst);
                     ac_unlockInstance(instHandle);
                  }
               }
               WOLog(WO_DBG, "connectionAttempts = %d, retries = %d", connectionAttempts, retries);
               ac_readConfiguration();
            }
         }
         if (resp == NULL && connectionAttempts <= retries) {
            /* appHandle is still valid because we have not decremented pendingResponses on the instance */
            woapp = ac_lockApp(appHandle);
            if (woapp)
            {
               retryInstHandle = tr_selectInstance(&app, woapp);
               if (retryInstHandle != AC_INVALID_HANDLE)
               {
                  tr_prepareToUseInstance(&app, retryInstHandle);
                  ac_unlockInstance(retryInstHandle);
               }
               ac_unlockApp(appHandle);
            } else
               retryInstHandle = AC_INVALID_HANDLE;
            /* Decrement pendingResponses on the original instance. It is safe to do now. */
            /* The retry instance has had pendingResponses incremented, which will prevent the */
            /* app from being removed. (Or, there was not other instance to retry, and we are done.) */
            inst = ac_lockInstance(instHandle);
            if (inst)
            {
               if (inst->pendingResponses > 0)
                  inst->pendingResponses--;
               ac_unlockInstance(instHandle);
               instHandle = retryInstHandle;
            }
            if (retryInstHandle != AC_INVALID_HANDLE) {
               WOLog(WO_INFO,"Attempting failover to new instance at index %d", retryInstHandle);
            } else {
               WOLog(WO_INFO,"No new instance located for failover");
            }
            instHandle = retryInstHandle;
         }
      } while (resp == NULL && instHandle != AC_INVALID_HANDLE && connectionAttempts < retries);
      if (instHandle != AC_INVALID_HANDLE)
      {
         /* still have to decrement pendingResponses */
         inst = ac_lockInstance(instHandle);
         if (inst)
         {
            if (inst->pendingResponses > 0)
               inst->pendingResponses--;
            ac_unlockInstance(instHandle);
            /* At this point, the app could be removed from the config at any time. */
            instHandle = retryInstHandle;
         }
      }
   } else {
      if (ac_authorizeAppListing(wc))
         resp = WOAdaptorInfo(req, wc);
      else
         app.error = err_notFound;
   }

   /*
    *	how'd we do?
    */
   if (resp == NULL) {
      /*
       *	we may be able to send a palatable response...
       */
      resp = _errorResponse(&app, wc, req);
   }
   return resp;
}
Exemplo n.º 3
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.º 4
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.º 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;
}