Пример #1
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;
}
Пример #2
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;
}
Пример #3
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 */
}
Пример #4
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;
}