Пример #1
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;
}
Пример #2
0
inline
static void cpyhdr(const char *key,pblock *pb,HTTPRequest *req,const char *wokey)
{
    const char *value = pblock_findval((char *)key, pb);
    if (value != NULL)
       req_addHeader(req, (wokey) ? wokey : key, value, 0);
}
Пример #3
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;
}
Пример #4
0
/*
 *	run the request
 */
static HTTPResponse *_runRequest(WOAppReq *app, WOAppHandle woappHandle, WOInstanceHandle instHandle, HTTPRequest *req) {
   WOConnection *c;
   HTTPResponse *resp = NULL;
   int send_status, keepConnection, retryRequest = 0;
   const char *idString = NULL;

   WOLog(WO_INFO,"Trying to contact %s:%s on %s(%d)", app->name,app->instance,app->host,app->port);

   /* Tag the request with a unique identifier (if it hasn't been already) */
   /* (It might already have been tagged if we are retrying the request due to refusing new sessions, for example) */
   idString = req_HeaderForKey(req, REQUEST_ID_HEADER);
   if (idString == NULL)
   {
      String *requestID = tr_uniqueID();
      if (requestID)
      {
         req_addHeader(req, REQUEST_ID_HEADER, requestID->text, STR_COPYVALUE);
         idString = req_HeaderForKey(req, REQUEST_ID_HEADER);
         str_free(requestID);
      }
   }
   
   do {
      c = tr_open(instHandle);				/* connect */

      if (c == NULL) {
         WOLog(WO_INFO,"%s:%s NOT LISTENING on %s(%d)", app->name,app->instance,app->host,app->port);
         app->error = err_connect;
         return NULL;
      }

      /*
       *	app found and is listening on port
       */
      if (app->scheduler->beginTransaction)
         app->scheduler->beginTransaction(app, instHandle);

      /* Make sure that we're the only connection header, and we're explicit about the setting */
      req_removeHeader(req,CONNECTION);
      if (c->isPooled) {
         req_addHeader(req,CONNECTION,HTTP_KEEP_ALIVE,0);
      } else {
	 req_addHeader(req,CONNECTION,HTTP_CLOSE,0);
      }

      WOLog(WO_INFO,"%s:%s on %s(%d) connected [pooled: %s]", app->name, app->instance, app->host, app->port, c->isPooled ? "Yes" : "No");

      /*
       *	send the request....
       */
      send_status = req_sendRequest(req, c->fd);
      if (send_status != 0) {
         if ((send_status == TR_RESET) && (retryRequest == 0) && !req->haveReadStreamedData)  {
              /* If we get here the connection was reset. This means the instance has either quit or crashed. */
              /* Bump the generation number so all pooled connections to this instance will be invalidated. */
              /* Then retry the request with a new connection. If the instance is not running the retry will */
              /* fail with a different error and the instance will be marked dead. */
              _WOInstance *inst = ac_lockInstance(instHandle);
              /* note: if we get here, keepConnection == 0 --> this connection will be closed */
              if (inst)
              {
                  ac_cycleInstance(inst, c->generation);
                  ac_unlockInstance(instHandle);
              }
              retryRequest++;
              WOLog(WO_INFO, "retrying request due to connection reset");

              /* Must close connection before continuing */
              tr_close(c, instHandle, 0);
              continue;
          } else {
              WOLog(WO_ERR,"Failed to send request");
              tr_close(c, instHandle, 0);          /* close app connection */
              if (send_status == -1)
                 app->error = err_read;
              else
                 app->error = err_send;
              return NULL;
          }
      }

      /* Note that we have a request queued */
      WOLog(WO_INFO,"Request %s sent, awaiting response", req->request_str);

      /* While the app is processing the request, take the opportunity to check/update the config. */
      ac_readConfiguration();

      /*
       *	now wait for the response...
       */
      resp = resp_getResponseHeaders(c, instHandle);
      /* go ahead and read the first chunk of response data */
      if (resp && req->method != HTTP_HEAD_METHOD)
      {
         if (resp_getResponseContent(resp, 1) == -1)
         {
            resp_free(resp);
            resp = NULL;
         }
      }

      /* Validate the ID */
      if (idString && resp)
      {
         const char *respID = st_valueFor(resp->headers, REQUEST_ID_HEADER);
         if (respID != NULL)
         {
            if (strcmp(respID, idString) != 0)
            {
               WOLog(WO_ERR, "Got response with wrong ID! Dumping response. request ID = %s, response ID = %s", idString, respID);
               /* note this will cause the connection to be closed below */
               resp_free(resp);
               resp = NULL;
            } else
               st_removeKey(resp->headers, REQUEST_ID_HEADER);
         } else
            WOLog(WO_WARN, "Got response with no ID.");
      }
               
      app->response = resp;

      /*
       *	check if this connection can be kept open
       */
      keepConnection = 0;

#ifndef CGI /* doesn't make sense to keep the connection for CGI */
      if (resp && resp->headers)
      {
         const char *keepAlive;
         keepAlive = st_valueFor(resp->headers, CONNECTION);
         if (keepAlive)
         {
            /* if the keep alive header is set, honor the value */
            if (strcasecmp(keepAlive, HTTP_KEEP_ALIVE) == 0)
               keepConnection = 1;
         } else {
            /* no keep alive header - keep alive by default for HTTP/1.1 only */
            if (resp->flags & RESP_HTTP11)
               keepConnection = 1;
         }
      }
#endif

      if (resp != NULL) {
         if (app->scheduler->finalizeTransaction)
            if (app->scheduler->finalizeTransaction(app, instHandle))
               keepConnection = 0;

         st_removeKey(resp->headers, REFUSING_SESSIONS_HEADER);
         st_removeKey(resp->headers, LOAD_AVERAGE_HEADER);
         st_removeKey(resp->headers, CONNECTION);

         WOLog(WO_INFO,"received ->%d %s",resp->status,resp->statusMsg);
         retryRequest = 0;
      } else {
         if (c != NULL && tr_connectionWasReset(c))
         {
            /* If we get here the connection was reset. This means the instance has either quit or crashed. */
            /* Bump the generation number so all pooled connections to this instance will be invalidated. */
            /* Then retry the request with a new connection. If the instance is not running the retry will */
            /* fail with a different error and the instance will be marked dead. */
            /* Note that only one retry due to a connection reset error is allowed. This is to prevent an */
            /* infinite loop if the instance dies while processing the request and restarts quickly enough */
            /* to process the retry. */
            _WOInstance *inst = ac_lockInstance(instHandle);
            /* note: if we get here, keepConnection == 0 --> this connection will be closed */
            if (inst)
            {
               ac_cycleInstance(inst, c->generation);
               ac_unlockInstance(instHandle);
            }
            retryRequest++;
            if (retryRequest == 1)
               WOLog(WO_INFO, "retrying request due to connection reset");
         } else
         app->error = err_response;
      }
      if (resp && resp->content_read < resp->content_length)
      {
         resp->keepConnection = keepConnection;
         resp->instHandle = instHandle;
         resp->flags |= RESP_CLOSE_CONNECTION;
      } else {
         tr_close(c, instHandle, keepConnection);
      }
   } while (retryRequest == 1);

   return resp;
}
Пример #5
0
/*
 *	finish the job that the api stubs started..
 */
static HTTPResponse *_collectRequestInformation(WOAppReq *app, WOURLComponents *wc, const char *url, int urlVersion, HTTPRequest *req)
{
   const char *urlerr;
   /*
    *	we need to complete the URL parsing...
    */
   if ((urlVersion == 4) || (urlVersion == 3)) {
      urlerr = WOParseAndCheckURL(wc, url, urlVersion, req->shouldProcessUrl);
   } else {
      urlerr = "Unsupported URL version";
      WOLog(WO_WARN, "Unsupported URL version (%d) on %s", urlVersion, app->name);
   }

   if (urlerr != NULL)
      return resp_errorResponse(urlerr, HTTP_BAD_REQUEST);

   /*
    *	pick up the app name & host (if any) & instance
    */
   if (wc->applicationName.length == 0)
       return resp_errorResponse(NO_APPNAME, HTTP_BAD_REQUEST);

   strncpy(app->name, wc->applicationName.start, wc->applicationName.length);
   app->name[wc->applicationName.length] = '\0';
   if (app->name[wc->applicationName.length - 1] == '/')	/* garbage? */
       app->name[wc->applicationName.length - 1] = '\0';

       if (wc->applicationHost.length > 0) {
          strncpy(app->host, wc->applicationHost.start, wc->applicationHost.length);
          app->host[wc->applicationHost.length] = '\0';
       } else
       app->host[0] = '\0';

       /*
        *	is the session/application information in the URL?
        *	if not, look in the cookies for the application instance number
        *	in the cookies.
        */
       app->instance[0] = 0; /* default to any instance */
       if (wc->applicationNumber.length > 0) {
          if (wc->applicationNumber.length < WA_MAX_INSTANCE_NUMBER_LENGTH)
          {
             memcpy(app->instance, wc->applicationNumber.start, wc->applicationNumber.length);
             app->instance[wc->applicationNumber.length] = 0;
          }
       } else {
          const char *cookie, *woinst;

          cookie = req_HeaderForKey(req, COOKIE);
          if (cookie && ((woinst = strstr(cookie, INST_COOKIE)) != NULL)) {
             const char *instid = &woinst[sizeof(INST_COOKIE)-1];
             int len = 0;
             while (len < WA_MAX_INSTANCE_NUMBER_LENGTH && instid[len] != ';' && instid[len])
                len++;
             if (len < WA_MAX_INSTANCE_NUMBER_LENGTH)
             {
                memcpy(app->instance, instid, len);
                app->instance[len] = 0;
             }

			 // remove any quotes from the instance number
#ifdef _MSC_VER // SWK Start VC can't define attributes here using '{' fixed it
			 {
#endif
			 char *before, *after;
			 before = after = app->instance;
			 while(*before){
			 	if((*before == '\'') || (*before == '"')){
					before++;
				}
				*after++ = *before++;
			 }
			 *after = 0;
#ifdef _MSC_VER // SWK End
			 }
#endif
             WOLog(WO_INFO,"Cookie instance %s from %s",app->instance,cookie);
          }
       }

       app->urlVersion = (wc->webObjectsVersion.start) ?
       atoi(wc->webObjectsVersion.start) : CURRENT_WOF_VERSION_MAJOR;

       /*
        *	Add the adaptor identifier header.
        *  WOFramework checks for the presence of this header, so the name should not change.
        *  (The value of the header is ignored by WOFramework.)
        */
       req_addHeader(req, "x-webobjects-adaptor-version", WA_adaptorName, 0);

       return NULL;  /* no errors */
}
Пример #6
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;
}
Пример #7
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;
}
Пример #8
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;
}
Пример #9
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;
}
Пример #10
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;
}