(file) Return to HTTPConnection.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

   1 karl  1.107 //%2006////////////////////////////////////////////////////////////////////////
   2 mike  1.2   //
   3 karl  1.79  // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
   4             // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
   5             // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
   6 karl  1.59  // IBM Corp.; EMC Corporation, The Open Group.
   7 karl  1.79  // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
   8             // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
   9 karl  1.91  // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
  10             // EMC Corporation; VERITAS Software Corporation; The Open Group.
  11 karl  1.107 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
  12             // EMC Corporation; Symantec Corporation; The Open Group.
  13 mike  1.2   //
  14             // Permission is hereby granted, free of charge, to any person obtaining a copy
  15 kumpf 1.27  // of this software and associated documentation files (the "Software"), to
  16             // deal in the Software without restriction, including without limitation the
  17             // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  18 mike  1.2   // sell copies of the Software, and to permit persons to whom the Software is
  19             // furnished to do so, subject to the following conditions:
  20 karl  1.107 // 
  21 kumpf 1.27  // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
  22 mike  1.2   // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
  23             // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
  24 kumpf 1.27  // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  25             // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  26             // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  27 mike  1.2   // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28             // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29             //
  30 kumpf 1.120 //==============================================================================
  31             //
  32 mike  1.2   //%/////////////////////////////////////////////////////////////////////////////
  33             
  34             #include <Pegasus/Common/Config.h>
  35 kumpf 1.16  #include <Pegasus/Common/Constants.h>
  36 mike  1.2   
  37 mike  1.112 #include "Network.h"
  38 mike  1.2   #include <iostream>
  39             #include <cctype>
  40             #include <cstdlib>
  41 mike  1.116 #include "Signal.h"
  42 mike  1.2   #include "Socket.h"
  43             #include "TLS.h"
  44             #include "HTTPConnection.h"
  45             #include "MessageQueue.h"
  46             #include "Monitor.h"
  47             #include "HTTPMessage.h"
  48 kumpf 1.3   #include "Tracer.h"
  49 mike  1.104 #include "Buffer.h"
  50 kumpf 1.105 #include "LanguageParser.h"
  51 mike  1.2   
  52 gerarda 1.44  #ifdef PEGASUS_KERBEROS_AUTHENTICATION
  53 gerarda 1.46  #include <Pegasus/Common/CIMKerberosSecurityAssociation.h>
  54 gerarda 1.44  #endif
  55 kumpf   1.63  #include <Pegasus/Common/XmlWriter.h>
  56 gerarda 1.44  
  57 mike    1.2   PEGASUS_USING_STD;
  58               
  59               PEGASUS_NAMESPACE_BEGIN
  60               
  61               // initialize the request count
  62               
  63 mike    1.103 AtomicInt HTTPConnection::_requestCount(0);
  64 mike    1.2   
  65               ////////////////////////////////////////////////////////////////////////////////
  66               //
  67               // Local routines:
  68               //
  69               ////////////////////////////////////////////////////////////////////////////////
  70               
  71 brian.campbell 1.72  /*
  72                       * string and number constants for HTTP sending/receiving
  73                       */
  74                      
  75                      // buffer size for sending receiving
  76                      static const Uint32 httpTcpBufferSize = 8192;
  77                      
  78 david.dillard  1.93  // string constants for HTTP header. "Name" represents strings on the left
  79                      // side of headerNameTerminator and "Value" represents strings on the right
  80 brian.campbell 1.72  // side of headerNameTerminator
  81                      
  82                      #define headerNameTrailer "Trailer"
  83                      #undef CRLF
  84                      #define CRLF "\r\n"
  85                      
  86                      static const char headerNameTransferTE[] = "TE";
  87                      static const char headerNameTransferEncoding[] = "transfer-encoding";
  88                      static const char headerNameContentLength[] = "content-length";
  89                      static const char headerValueTransferEncodingChunked[] = "chunked";
  90                      static const char headerValueTransferEncodingIdentity[] = "identity";
  91                      static const char headerValueTEchunked[] = "chunked";
  92                      static const char headerValueTEtrailers[] = "trailers";
  93                      static const char headerNameError[] = "CIMError";
  94                      static const char headerNameCode[] = "CIMStatusCode";
  95                      static const char headerNameDescription[] = "CIMStatusCodeDescription";
  96                      static const char headerNameOperation[] = "CIMOperation";
  97 brian.campbell 1.85  static const char headerNameContentLanguage[] = "Content-Language";
  98 brian.campbell 1.72  
  99                      // the names comes from the HTTP specification on chunked transfer encoding
 100                      
 101                      static const char headerNameTerminator[] = ": ";
 102                      static const char headerValueSeparator[] = ", ";
 103                      static const char headerLineTerminator[] = CRLF;
 104                      static const char headerTerminator[] = CRLF CRLF;
 105 david.dillard  1.88  static const char chunkLineTerminator[] = CRLF;
 106                      static const char chunkTerminator[] = CRLF;
 107                      static const char chunkBodyTerminator[] = CRLF;
 108                      static const char trailerTerminator[] = CRLF;
 109                      static const char chunkExtensionTerminator[] = ";";
 110 brian.campbell 1.72  
 111                      // string sizes
 112                      
 113 kumpf          1.122 static const Uint32 headerNameContentLengthLength =
 114                          sizeof(headerNameContentLength) - 1;
 115                      static const Uint32 headerValueTransferEncodingChunkedLength =
 116                          sizeof(headerValueTransferEncodingChunked) - 1;
 117                      static const Uint32 headerNameTransferEncodingLength =
 118                          sizeof(headerNameTransferEncoding) - 1;
 119 brian.campbell 1.72  static const Uint32 headerNameTerminatorLength =sizeof(headerNameTerminator)-1;
 120                      static const Uint32 headerLineTerminatorLength =sizeof(headerLineTerminator)-1;
 121                      static const Uint32 chunkLineTerminatorLength = sizeof(chunkLineTerminator)-1;
 122                      static const Uint32 chunkTerminatorLength = sizeof(chunkTerminator)-1;
 123                      static const Uint32 chunkBodyTerminatorLength = sizeof(chunkBodyTerminator)-1;
 124                      static const Uint32 trailerTerminatorLength = sizeof(trailerTerminator)-1;
 125 kumpf          1.122 static const Uint32 chunkExtensionTerminatorLength =
 126                          sizeof(chunkExtensionTerminator) - 1;
 127 brian.campbell 1.72  
 128                      // the number of bytes it takes to place a Uint32 into a string (minus null)
 129                      static const Uint32 numberAsStringLength = 10;
 130                      
 131                      /*
 132                       * given an HTTP status code, return the description. not all codes are listed
 133                       * here. Unmapped codes result in the internal error string.
 134                       * Add any required future codes here.
 135                       */
 136                      
 137                      static const String httpDetailDelimiter = headerValueSeparator;
 138                      static const String httpStatusInternal = HTTP_STATUS_INTERNALSERVERERROR;
 139                      
 140                      /*
 141                       * throw given http code with detail, file, line
 142                       * This is shared client/server code. The caller will decide what to do
 143                       * with the thrown message
 144                       */
 145                      
 146                      static void _throwEventFailure(const String &status, const String &detail,
 147 kumpf          1.98      const char *func,
 148                          const char *file , Uint32 line)
 149 david.dillard  1.93  {
 150 kumpf          1.98      String message = status + httpDetailDelimiter + detail;
 151 marek          1.131     PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, message);
 152 kumpf          1.98      if (status == httpStatusInternal)
 153                              throw AssertionFailureException(file, line, message);
 154                          else throw Exception(message);
 155 brian.campbell 1.72  }
 156                      
 157                      // throw a http exception. This is used for both client and server common code.
 158                      // The macro allows is used for file, line inclusion for debugging
 159                      
 160                      #define _throwEventFailure(status, detail) \
 161                        _throwEventFailure(status, String(detail), func, __FILE__, __LINE__)
 162                      
 163 kumpf          1.113 #define _socketWriteError()                                                   \
 164                          do                                                                        \
 165                          {                                                                         \
 166 marek          1.131         PEG_TRACE((__FILE__, __LINE__, TRC_DISCARDED_DATA, Tracer::LEVEL2,     \
 167 kumpf          1.113             "Socket write failed with error %d; could not write response "    \
 168                                      "to client.  (Client may have timed out.)",                   \
 169 marek          1.131             getSocketError()));                                                \
 170 kumpf          1.113         throw Exception("socket write error");                                \
 171                          }                                                                         \
 172                          while (0)
 173                      
 174 david.dillard  1.93  static inline Uint32 _Min(Uint32 x, Uint32 y)
 175 mike           1.2   {
 176 david.dillard  1.93      return x < y ? x : y;
 177 mike           1.2   }
 178                      
 179 kumpf          1.42  // Used to test signal handling
 180                      void * sigabrt_generator(void * parm)
 181                      {
 182                          abort();
 183                          return 0;
 184                      }
 185                      
 186                      
 187 mike           1.2   ////////////////////////////////////////////////////////////////////////////////
 188                      //
 189                      // HTTPConnection
 190                      //
 191                      ////////////////////////////////////////////////////////////////////////////////
 192                      
 193                      HTTPConnection::HTTPConnection(
 194                          Monitor* monitor,
 195 kumpf          1.137     SharedPtr<MP_Socket>& socket,
 196 kumpf          1.120     const String& ipAddress,
 197 mday           1.19      MessageQueue* ownerMessageQueue,
 198 sushma.fernandes 1.119     MessageQueue* outputMessageQueue)
 199 david.dillard    1.93      :
 200 kumpf            1.98      Base(PEGASUS_QUEUENAME_HTTPCONNECTION),
 201                            _monitor(monitor),
 202                            _socket(socket),
 203 kumpf            1.120     _ipAddress(ipAddress),
 204 kumpf            1.98      _ownerMessageQueue(ownerMessageQueue),
 205                            _outputMessageQueue(outputMessageQueue),
 206                            _contentOffset(-1),
 207                            _contentLength(-1),
 208 kumpf            1.102     _connectionClosePending(false),
 209                            _acceptPending(false)
 210 kumpf            1.98  {
 211                            PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::HTTPConnection");
 212                        
 213                            _socket->disableBlocking();
 214                            _authInfo.reset(new AuthenticationInfo(true));
 215 kumpf            1.7   
 216 kumpf            1.98      // Add SSL verification information to the authentication information
 217                            if (_socket->isSecure())
 218                            {
 219 thilo.boehm      1.117 #ifndef PEGASUS_PLATFORM_ZOS_ZSERIES_IBM
 220 kumpf            1.122         if (_socket->isPeerVerificationEnabled() &&
 221                                    _socket->isCertificateVerified())
 222 kumpf            1.98          {
 223 sushma.fernandes 1.132             _authInfo->setConnectionAuthenticated(true);
 224 kumpf            1.98              _authInfo->setAuthType(AuthenticationInfoRep::AUTH_TYPE_SSL);
 225 kumpf            1.122             _authInfo->setClientCertificateChain(
 226                                        _socket->getPeerCertificateChain());
 227 kumpf            1.98          }
 228 thilo.boehm      1.117 #else
 229 kumpf            1.123         if (_socket->isClientAuthenticated())
 230 thilo.boehm      1.117         {
 231 sushma.fernandes 1.132             _authInfo->setConnectionAuthenticated(true);
 232 thilo.boehm      1.117             _authInfo->setAuthenticatedUser(_socket->getAuthenticatedUser());
 233                                }
 234                        #endif
 235                        
 236 kumpf            1.98      }
 237                        
 238                            _responsePending = false;
 239                            _connectionRequestCount = 0;
 240                            _transferEncodingChunkOffset = 0;
 241                        
 242 kumpf            1.120     PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
 243                                "Connection IP address = " + _ipAddress);
 244                        
 245 sushma.fernandes 1.121     _authInfo->setIpAddress(_ipAddress);
 246                        
 247 kumpf            1.98      PEG_METHOD_EXIT();
 248 mike             1.2   }
 249                        
 250                        HTTPConnection::~HTTPConnection()
 251                        {
 252 kumpf            1.98      PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::~HTTPConnection");
 253 kumpf            1.7   
 254 kumpf            1.98       _socket->close();
 255 kumpf            1.7   
 256 kumpf            1.98      PEG_METHOD_EXIT();
 257 mike             1.2   }
 258                        
 259 kumpf            1.118 void HTTPConnection::enqueue(Message *message)
 260                        {
 261                            handleEnqueue(message);
 262                        }
 263                        
 264 mday             1.5   void HTTPConnection::handleEnqueue(Message *message)
 265 mike             1.2   {
 266 kumpf            1.98      PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::handleEnqueue");
 267                        
 268 kumpf            1.123     if (! message)
 269 kumpf            1.98      {
 270                                PEG_METHOD_EXIT();
 271                                return;
 272                            }
 273                        
 274 mike             1.116     AutoMutex connectionLock(_connection_mut);
 275 kumpf            1.7   
 276 kumpf            1.98      switch (message->getType())
 277                            {
 278                                case SOCKET_MESSAGE:
 279                                {
 280 marek            1.131             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL4,
 281 kumpf            1.98                  "HTTPConnection::handleEnqueue - SOCKET_MESSAGE");
 282                                    SocketMessage* socketMessage = (SocketMessage*)message;
 283                                    if (socketMessage->events & SocketMessage::READ)
 284                                        _handleReadEvent();
 285                                    break;
 286                                }
 287                        
 288                                case HTTP_MESSAGE:
 289                                {
 290 marek            1.131             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL4,
 291 kumpf            1.98                  "HTTPConnection::handleEnqueue - HTTP_MESSAGE");
 292                        
 293                                    _handleWriteEvent(*message);
 294                                    break;
 295                                }
 296                        
 297                                default:
 298                                    // ATTN: need unexpected message error!
 299                                    break;
 300 kumpf            1.122     } // switch
 301 david.dillard    1.93  
 302 kumpf            1.122     delete message;
 303 david.dillard    1.93  
 304 kumpf            1.122     PEG_METHOD_EXIT();
 305 brian.campbell   1.72  }
 306 mike             1.2   
 307 brian.campbell   1.72  /*
 308 david.dillard    1.93   * handle the message coming down from the above. This is shared client and
 309                         * server code. If the message is coming in chunks, then validate the chunk
 310 brian.campbell   1.72   * sequence number. If the message is being processed on the server side,
 311                         * make sure the client has requested transfer encodings and/or trailers before
 312                         * sending them. If not, the message must be queued up until a complete flag
 313                         * has arrived.
 314                         */
 315                        
 316                        Boolean HTTPConnection::_handleWriteEvent(Message &message)
 317                        {
 318 kumpf            1.98      static const char func[] = "HTTPConnection::_handleWriteEvent";
 319                            String httpStatus;
 320                            HTTPMessage& httpMessage = *(HTTPMessage*)&message;
 321 mike             1.104     Buffer& buffer = httpMessage.message;
 322 kumpf            1.98      Boolean isFirst = message.isFirst();
 323                            Boolean isLast = message.isComplete();
 324                            Sint32 totalBytesWritten = 0;
 325 kumpf            1.128     Uint32 messageLength = buffer.size();
 326 mike             1.2   
 327 kumpf            1.98      try
 328                            {
 329 chuck            1.95          // delivery behavior:
 330 kumpf            1.98          // 1 handler.processing() : header + optional body?
 331                                // 2 handler.deliver()    : 1+ fully XML encoded object(s)
 332                                // 3 handler.complete()   : deliver() + isLast = true
 333                        
 334                                Uint32 bytesRemaining = messageLength;
 335                                char *messageStart = (char *) buffer.getData();
 336                                Uint32 bytesToWrite = httpTcpBufferSize;
 337                                Uint32 messageIndex = message.getIndex();
 338                                Boolean isChunkResponse = false;
 339                                Boolean isChunkRequest = false;
 340                                Boolean isFirstException = false;
 341                        
 342                                if (_isClient() == false)
 343                                {
 344                                    // for null termination
 345                                    buffer.reserveCapacity(messageLength + 1);
 346                                    messageStart = (char *) buffer.getData();
 347 david.dillard    1.89              messageStart[messageLength] = 0;
 348 marek            1.131             PEG_TRACE((TRC_XML_IO, Tracer::LEVEL2,
 349 kumpf            1.130                 "<!-- Response: queue id: %u -->\n%s",
 350 dave.sudlik      1.125                 getQueueId(),
 351 marek            1.131                 buffer.getData()));
 352 kumpf            1.98              if (isFirst == true)
 353                                    {
 354                                        _incomingBuffer.clear();
 355                                        // tracks the message coming from above
 356                                        _transferEncodingChunkOffset = 0;
 357                                        _mpostPrefix.clear();
 358                                        cimException = CIMException();
 359                                    }
 360                                    else
 361                                    {
 362                                        // this is coming from our own internal code, therefore it is an
 363                                        // internal error. somehow the chunks came out of order.
 364                                        if (_transferEncodingChunkOffset+1 != messageIndex)
 365 kumpf            1.122                     _throwEventFailure(
 366                                                httpStatusInternal, "chunk sequence mismatch");
 367 kumpf            1.98                  _transferEncodingChunkOffset++;
 368                                    }
 369                        
 370                                    // save the first error
 371                                    if (httpMessage.cimException.getCode() != CIM_ERR_SUCCESS)
 372                                    {
 373                                        httpStatus = httpMessage.cimException.getMessage();
 374                                        if (cimException.getCode() == CIM_ERR_SUCCESS)
 375                                        {
 376                                            cimException = httpMessage.cimException;
 377 kumpf            1.122                     // set language to first error language (overriding
 378                                            // anything there)
 379 kumpf            1.98                      contentLanguages = cimException.getContentLanguages();
 380                                            isFirstException = true;
 381                                        }
 382                                    }
 383                                    else if (cimException.getCode() == CIM_ERR_SUCCESS)
 384                                    {
 385                                        if (isFirst == true)
 386                                            contentLanguages = httpMessage.contentLanguages;
 387                                        else if (httpMessage.contentLanguages != contentLanguages)
 388 kumpf            1.105                     contentLanguages.clear();
 389 kumpf            1.98                  else contentLanguages = httpMessage.contentLanguages;
 390                                    }
 391 kumpf            1.122             // check to see if the client requested chunking OR trailers.
 392                                    // trailers are tightly integrated with chunking, so it can also
 393                                    // be used.
 394 kumpf            1.98  
 395                                    if (isChunkRequested() == true)
 396                                    {
 397                                        isChunkRequest = true;
 398                                    }
 399                                    else
 400                                    {
 401 kumpf            1.122                 // we are not sending chunks because the client did not
 402                                        // request it
 403 kumpf            1.98  
 404 kumpf            1.122                 // save the entire FIRST error response for non-chunked error
 405                                        // responses this will be used as the error message
 406 kumpf            1.98  
 407                                        if (isFirstException == true)
 408                                        {
 409                                            // this shouldnt happen, but this is defensive ...
 410                                            if (messageLength == 0)
 411                                            {
 412                                                CIMStatusCode code = httpMessage.cimException.getCode();
 413                                                String httpDetail(cimStatusCodeToString(code));
 414                                                char s[21];
 415                                                sprintf(s, "%u", code);
 416                                                String httpStatus(s);
 417 mike             1.104                         Buffer message = XmlWriter::formatHttpErrorRspMessage
 418 kumpf            1.98                              (httpStatus, String(), httpDetail);
 419 kumpf            1.128                         messageLength = message.size();
 420 kumpf            1.98                          message.reserveCapacity(messageLength+1);
 421                                                messageStart = (char *) message.getData();
 422                                                messageStart[messageLength] = 0;
 423                                            }
 424                                            cimException = CIMException(cimException.getCode(),
 425                                                String(messageStart, messageLength));
 426                                        }
 427                        
 428                                        if (isFirst == false)
 429                                        {
 430                                            // subsequent chunks from the server, just append
 431                        
 432 kumpf            1.128                     messageLength += _incomingBuffer.size();
 433 kumpf            1.98                      _incomingBuffer.reserveCapacity(messageLength+1);
 434 mike             1.104                     _incomingBuffer.append(buffer.getData(), buffer.size());
 435 kumpf            1.98                      buffer.clear();
 436                                            // null terminate
 437                                            messageStart = (char *) _incomingBuffer.getData();
 438                                            messageStart[messageLength] = 0;
 439 kumpf            1.122                     // put back in buffer, so the httpMessage parser can work
 440                                            // below
 441 kumpf            1.98                      _incomingBuffer.swap(buffer);
 442                                        }
 443                        
 444                                        if (isLast == false)
 445                                        {
 446 kumpf            1.122                     // this tells the send loop below to do nothing until we
 447                                            // are at the last response
 448 kumpf            1.98                      bytesRemaining = 0;
 449                                        }
 450                                        else
 451                                        {
 452                                            if (cimException.getCode() != CIM_ERR_SUCCESS)
 453                                            {
 454                                                buffer.clear();
 455                                                // discard all data collected to this point
 456                                                _incomingBuffer.clear();
 457                                                String messageS = cimException.getMessage();
 458                                                CString messageC = messageS.getCString();
 459                                                messageStart = (char *) (const char *) messageC;
 460 a.dunfey         1.126                         messageLength = (Uint32)strlen(messageStart);
 461 kumpf            1.98                          buffer.reserveCapacity(messageLength+1);
 462                                                buffer.append(messageStart, messageLength);
 463                                                // null terminate
 464                                                messageStart = (char *) buffer.getData();
 465                                                messageStart[messageLength] = 0;
 466                                            }
 467                                            bytesRemaining = messageLength;
 468                                        }
 469                        
 470                                    } // if not sending chunks
 471                        
 472                                    // We now need to adjust the contentLength line.
 473 kumpf            1.122             // If chunking was requested and this is the first chunk, then
 474                                    // we need to enter this block so we can adjust the header and
 475                                    // send to the client the first set of bytes right away.
 476                                    // If chunking was NOT requested, we have to wait for the last
 477                                    // chunk of the message to get (and set) the size of the content
 478                                    // because we are going to send it the traditional (i.e
 479                                    // non-chunked) way
 480 kumpf            1.98  
 481                                    if (isChunkRequest == true && isFirst == true ||
 482                                            isChunkRequest == false && isLast == true)
 483                                    {
 484                                        // need to find the end of the header
 485                                        String startLine;
 486                                        Array<HTTPHeader> headers;
 487                                        Uint32 contentLength = 0;
 488                        
 489 kumpf            1.122                 // Note: this gets the content length from subtracting the
 490                                        // header length from the messageLength, not by parsing the
 491                                        // content length header field
 492 kumpf            1.98  
 493                                        httpMessage.parse(startLine, headers, contentLength);
 494                                        Uint32 httpStatusCode = 0;
 495                                        String httpVersion;
 496                                        String reasonPhrase;
 497 kumpf            1.122                 Boolean isValid = httpMessage.parseStatusLine(
 498                                            startLine, httpVersion, httpStatusCode, reasonPhrase);
 499 kumpf            1.98                  Uint32 headerLength = messageLength - contentLength;
 500                                        char save = messageStart[headerLength];
 501                                        messageStart[headerLength] = 0;
 502                        
 503                                        char *contentLengthStart =
 504                                            strstr(messageStart, headerNameContentLength);
 505                        
 506                                        char* contentLengthEnd = contentLengthStart ?
 507                                            strstr(contentLengthStart, headerLineTerminator) : 0;
 508                        
 509                                        messageStart[headerLength] = save;
 510                        
 511                                        // the message may or may not have the content length specified
 512                                        // depending on the type of request it is
 513                        
 514                                        if (contentLengthStart)
 515                                        {
 516                                            // the message has the content length specified.
 517 kumpf            1.122                     // If we are NOT sending a chunked response, then we need
 518                                            // to overlay the contentLength number to reflect the
 519                                            // actual byte count of the content (i.e message body).
 520                                            // If we ARE sending a chunked response, then we will
 521                                            // overlay the transferEncoding keyword name and value
 522 kumpf            1.98                      // on top of the contentLength keyword and value.
 523                        
 524                                            // Important note:
 525 kumpf            1.122                     // for performance reasons, the contentLength and/or
 526                                            // transferEncoding strings are being overlayed
 527                                            // DIRECTLY inside the message buffer WITHOUT changing
 528                                            // the actual length in bytes of the message.
 529                                            // The XmlWriter has been modified to pad out the
 530                                            // maximum number in zeros to accomodate any number.
 531                                            // The maximum contentLength name and value is identical
 532                                            // to the transferEncoding name and value and can
 533                                            // be easily interchanged. By doing this, we do not have
 534                                            // to piece together the header (and more importantly,
 535                                            // the lengthy body) all over again!
 536 kumpf            1.98                      // This is why the http line lengths are validated below
 537                        
 538                                            Uint32 transferEncodingLineLengthExpected =
 539                                                headerNameTransferEncodingLength +
 540                                                headerNameTerminatorLength +
 541                                                headerValueTransferEncodingChunkedLength;
 542                        
 543                                            Uint32 contentLengthLineLengthExpected =
 544                                                headerNameContentLengthLength +
 545                                                headerNameTerminatorLength + numberAsStringLength;
 546                        
 547                                            Uint32 contentLengthLineLengthFound =
 548 a.dunfey         1.126                         (Uint32)(contentLengthEnd - contentLengthStart);
 549 kumpf            1.98  
 550                                            if (isValid == false || ! contentLengthEnd ||
 551                                                    contentLengthLineLengthFound !=
 552                                                    transferEncodingLineLengthExpected ||
 553                                                    transferEncodingLineLengthExpected !=
 554                                                    contentLengthLineLengthExpected)
 555                                            {
 556 kumpf            1.122                         // these should match up since this is coming
 557                                                // directly from our code in XmlWriter! If not,
 558                                                // some code changes have got out of sync
 559 kumpf            1.98  
 560                                                _throwEventFailure(httpStatusInternal,
 561                                                    "content length was incorrectly formatted");
 562                                            }
 563                        
 564                                            // we will be sending a chunk response if:
 565                                            // 1. chunking has been requested AND
 566                                            // 2. contentLength has been set
 567                                            //    (meaning a non-bodyless message has come in) OR
 568                                            // 3. this is not the last message
 569 kumpf            1.122                     //    (meaning the data is coming in pieces and we should
 570                                            //    send chunked)
 571 kumpf            1.98  
 572 kumpf            1.122                     if (isChunkRequest == true &&
 573                                                (contentLength > 0 || isLast == false))
 574                                            {
 575 kumpf            1.98                          isChunkResponse = true;
 576 kumpf            1.122                     }
 577 kumpf            1.98  
 578                                            save = contentLengthStart[contentLengthLineLengthExpected];
 579                                            contentLengthStart[contentLengthLineLengthExpected] = 0;
 580                        
 581                                            // overlay the contentLength value
 582                                            if (isChunkResponse == false)
 583                                            {
 584 kumpf            1.122                         // overwrite the content length number with the actual
 585                                                // byte count
 586 kumpf            1.98                          char *contentLengthNumberStart = contentLengthStart +
 587 kumpf            1.122                             headerNameContentLengthLength +
 588                                                    headerNameTerminatorLength;
 589 kumpf            1.98                          char format[6];
 590                                                sprintf (format, "%%.%uu", numberAsStringLength);
 591 kumpf            1.122                         // overwrite the bytes in buffer with the content
 592                                                //encoding length
 593                                                sprintf(contentLengthNumberStart,
 594                                                    format, contentLength);
 595                                                contentLengthStart[contentLengthLineLengthExpected] =
 596                                                    save;
 597 kumpf            1.98                      }
 598                                            else
 599                                            {
 600                                                // overlay the contentLength name and value with the
 601                                                // transferEncoding name and value
 602                        
 603 kumpf            1.122                         sprintf(contentLengthStart, "%s%s%s",
 604                                                    headerNameTransferEncoding,
 605                                                    headerNameTerminator,
 606                                                    headerValueTransferEncodingChunked);
 607 kumpf            1.98                          bytesToWrite = messageLength - contentLength;
 608                        
 609 kumpf            1.122                         contentLengthStart[contentLengthLineLengthExpected] =
 610                                                    save;
 611 kumpf            1.98                          String operationName = headerNameOperation;
 612                                                // look for 2-digit prefix (if mpost was use)
 613                                                HTTPMessage::lookupHeaderPrefix(headers, operationName,
 614                                                    _mpostPrefix);
 615                                            } // else chunk response is true
 616                        
 617                                        } // if content length was found
 618                        
 619                                        if (isChunkRequest == false)
 620                                        {
 621                                            if (isLast == true)
 622                                            {
 623 kumpf            1.105                         if (contentLanguages.size() != 0)
 624 kumpf            1.98                          {
 625 kumpf            1.122                             // we must insert the content-language into the
 626                                                    // header
 627 mike             1.104                             Buffer contentLanguagesString;
 628 kumpf            1.98  
 629 kumpf            1.122                             // this is the keyword:value(s) + header line
 630                                                    // terminator
 631                                                    contentLanguagesString <<
 632                                                        headerNameContentLanguage <<
 633 kumpf            1.98                                  headerNameTerminator <<
 634 kumpf            1.105                                 LanguageParser::buildContentLanguageHeader(
 635                                                            contentLanguages).getCString() <<
 636 kumpf            1.98                                  headerLineTerminator;
 637                        
 638 kumpf            1.122                             Uint32 insertOffset =
 639                                                        headerLength - headerLineTerminatorLength;
 640                                                    messageLength =
 641 kumpf            1.128                                 contentLanguagesString.size() + buffer.size();
 642 kumpf            1.98                              buffer.reserveCapacity(messageLength+1);
 643 kumpf            1.128                             messageLength = contentLanguagesString.size();
 644 kumpf            1.122                             messageStart =
 645                                                        (char *)contentLanguagesString.getData();
 646                                                    // insert the content language line before end
 647                                                    // of header
 648 kumpf            1.98                              // note: this can be expensive on large payloads
 649 kumpf            1.122                             buffer.insert(
 650                                                        insertOffset, messageStart, messageLength);
 651 kumpf            1.128                             messageLength = buffer.size();
 652 kumpf            1.98                              // null terminate
 653                                                    messageStart = (char *) buffer.getData();
 654                                                    messageStart[messageLength] = 0;
 655                                                    bytesRemaining = messageLength;
 656                                                } // if there were any content languages
 657 chuck            1.95  
 658                        #ifdef PEGASUS_KERBEROS_AUTHENTICATION
 659 kumpf            1.122                         // The following is processing to wrap (encrypt) the
 660                                                // response from the server when using kerberos
 661                                                // authentications.
 662                                                // If the security association does not exist then
 663                                                // kerberos authentication is not being used.
 664                                                CIMKerberosSecurityAssociation *sa =
 665                                                    _authInfo->getSecurityAssociation();
 666 chuck            1.95  
 667 chuck            1.96                          if (sa)
 668                                                {
 669 kumpf            1.122                             // The message needs to be parsed in order to
 670                                                    // distinguish between the headers and content.
 671                                                    // When parsing, the code breaks out of the loop
 672                                                    // as soon as it finds the double separator that
 673                                                    // terminates the headers so the headers and
 674                                                    // content can be easily separated.
 675 chuck            1.95  
 676 chuck            1.96                              Boolean authrecExists = false;
 677 kumpf            1.136                             String authorization;
 678 kumpf            1.122                             if (HTTPMessage::lookupHeader(
 679                                                            headers, "WWW-Authenticate",
 680                                                            authorization, false))
 681 chuck            1.96                              {
 682                                                        authrecExists = true;
 683 kumpf            1.98                              }
 684                        
 685 kumpf            1.122                             // The following is processing to wrap (encrypt)
 686                                                    // the response from the server when using
 687                                                    // kerberos authentications.
 688                                                    sa->wrapResponseMessage(
 689                                                        buffer, contentLength, authrecExists);
 690 chuck            1.96                              messageLength = buffer.size();
 691                        
 692                                                    // null terminate
 693                                                    messageStart = (char *) buffer.getData();
 694                                                    messageStart[messageLength] = 0;
 695                                                    bytesRemaining = messageLength;
 696                                                }  // endif kerberos security assoc exists
 697 chuck            1.95  #endif
 698 kumpf            1.98                      } // if this is the last chunk
 699                                            else bytesRemaining = 0;
 700                                        } // if chunk request is false
 701                                    } // if this is the first chunk containing the header
 702                                    else
 703                                    {
 704                                        // if chunking was requested, then subsequent messages that are
 705                                        // received need to turn response chunking on
 706                        
 707                                        if (isChunkRequest == true && messageIndex > 0)
 708                                        {
 709                                            isChunkResponse = true;
 710                                            bytesToWrite = messageLength;
 711                                        }
 712                                    }
 713                        
 714                                    // the data is sitting in buffer, but we want to cache it in
 715                                    // _incomingBuffer because there may be more chunks to append
 716                                    if (isChunkRequest == false)
 717                                        _incomingBuffer.swap(buffer);
 718                        
 719 kumpf            1.98          } // if not a client
 720                        
 721 marek            1.131         PEG_TRACE_CSTRING(TRC_HTTP,Tracer::LEVEL4, 
 722 thilo.boehm      1.129                 "HTTPConnection::_handleWriteEvent: Server write event.");
 723                        
 724 kumpf            1.98          SignalHandler::ignore(PEGASUS_SIGPIPE);
 725                        
 726                                // use the next four lines to test the SIGABRT handler
 727                                //getSigHandle()->registerHandler(PEGASUS_SIGABRT, sig_act);
 728                                //getSigHandle()->activate(PEGASUS_SIGABRT);
 729                                //Thread t(sigabrt_generator, NULL, false);
 730                                //t.run();
 731                        
 732                                char *sendStart = messageStart;
 733                                Sint32 bytesWritten = 0;
 734                        
 735                                if (isFirst == true && isChunkResponse == true && bytesToWrite > 0)
 736                                {
 737                                    // send the header first for chunked reponses.
 738                        
 739                                    // dont include header terminator yet
 740                                    Uint32 headerLength = bytesToWrite;
 741                                    bytesToWrite -= headerLineTerminatorLength;
 742 marek            1.131             PEG_TRACE_CSTRING(TRC_HTTP,Tracer::LEVEL4, 
 743 thilo.boehm      1.129               "HTTPConnection::_handleWriteEvent: "
 744                                      "Sending header for chunked reponses.");
 745 kumpf            1.98  
 746                                    bytesWritten = _socket->write(sendStart, bytesToWrite);
 747                                    if (bytesWritten < 0)
 748 kumpf            1.113                 _socketWriteError();
 749 kumpf            1.98              totalBytesWritten += bytesWritten;
 750                                    bytesRemaining -= bytesWritten;
 751                        
 752                                    // put in trailer header.
 753 mike             1.104             Buffer trailer;
 754 kumpf            1.98              trailer << headerNameTrailer << headerNameTerminator <<
 755                                        _mpostPrefix << headerNameCode <<    headerValueSeparator <<
 756                                        _mpostPrefix << headerNameDescription << headerValueSeparator <<
 757                                        headerNameContentLanguage << headerLineTerminator;
 758                                    sendStart = (char *) trailer.getData();
 759 kumpf            1.128             bytesToWrite = trailer.size();
 760 thilo.boehm      1.129 
 761 marek            1.131             PEG_TRACE_CSTRING(TRC_HTTP,Tracer::LEVEL4, 
 762 thilo.boehm      1.129                     "HTTPConnection::_handleWriteEvent: "
 763                                            "Sending trailer header for chunked responses.");
 764                        
 765 kumpf            1.98              bytesWritten = _socket->write(sendStart, bytesToWrite);
 766                        
 767                                    if (bytesWritten < 0)
 768 kumpf            1.113                 _socketWriteError();
 769 kumpf            1.98              totalBytesWritten += bytesWritten;
 770                                    // the trailer is outside the header buffer, so dont include in
 771                                    // tracking variables
 772                        
 773                                    // now send header terminator
 774                                    bytesToWrite = headerLineTerminatorLength;
 775                                    sendStart = messageStart + headerLength - bytesToWrite;
 776 thilo.boehm      1.129 
 777 marek            1.131             PEG_TRACE_CSTRING(TRC_HTTP,Tracer::LEVEL4, 
 778 thilo.boehm      1.129                     "HTTPConnection::_handleWriteEvent: "
 779                                            "Sending header terminator for chunked responses.");
 780                        
 781 kumpf            1.98              bytesWritten = _socket->write(sendStart, bytesToWrite);
 782                                    if (bytesWritten < 0)
 783 kumpf            1.113                 _socketWriteError();
 784 kumpf            1.98              totalBytesWritten += bytesWritten;
 785                                    bytesRemaining -= bytesWritten;
 786                        
 787                                    messageStart += headerLength;
 788                                    messageLength -= headerLength;
 789                                    sendStart = messageStart;
 790                                    bytesWritten = 0;
 791                                    bytesToWrite = bytesRemaining;
 792                                } // if first chunk of chunked response
 793                        
 794                                // room enough for hex string representing chunk length and terminator
 795                                char chunkLine[sizeof(Uint32)*2 + chunkLineTerminatorLength+1];
 796                        
 797                                for (; bytesRemaining > 0; )
 798                                {
 799                                    if (isChunkResponse == true)
 800                                    {
 801 kumpf            1.122                 // send chunk line containing hex string and chunk line
 802                                        // terminator
 803 kumpf            1.98                  sprintf(chunkLine, "%x%s", bytesToWrite, chunkLineTerminator);
 804                                        sendStart = chunkLine;
 805 a.dunfey         1.126                 Sint32 chunkBytesToWrite = (Sint32)strlen(sendStart);
 806 thilo.boehm      1.129 
 807 marek            1.131                 PEG_TRACE_CSTRING(TRC_HTTP,Tracer::LEVEL4, 
 808 thilo.boehm      1.129                         "HTTPConnection::_handleWriteEvent: "
 809                                                "Sending chunk with chunk line terminator.");
 810                        
 811 kumpf            1.98                  bytesWritten = _socket->write(sendStart, chunkBytesToWrite);
 812                                        if (bytesWritten < 0)
 813 kumpf            1.113                     _socketWriteError();
 814 kumpf            1.98                  totalBytesWritten += bytesWritten;
 815                                    }
 816                        
 817                                    // for chunking, we will send the entire chunk data in one send, but
 818                                    // for non-chunking, we will send incrementally
 819                                    else bytesToWrite = _Min(bytesRemaining, bytesToWrite);
 820                        
 821                                    // send non-chunked data
 822 kumpf            1.122             //
 823 gs.keenan        1.114             // Socket writes larger than 64K cause some platforms to return
 824                                    //  errors. When the socket write can't send the full buffer at
 825                                    //  one time, subtract the bytes sent and loop until the whole
 826                                    //  buffer has gone.  Use httpTcpBufferSize for maximum send size.
 827 kumpf            1.122             //
 828 gs.keenan        1.114             for (; bytesRemaining > 0; )
 829                                    {
 830                                      sendStart = messageStart + messageLength - bytesRemaining;
 831                                      bytesToWrite = _Min(httpTcpBufferSize, bytesRemaining);
 832 thilo.boehm      1.129 
 833 marek            1.131               PEG_TRACE_CSTRING(TRC_HTTP,Tracer::LEVEL4, 
 834 thilo.boehm      1.129                       "HTTPConnection::_handleWriteEvent: "
 835                                              "Sending non-chunked data.");
 836                        
 837 gs.keenan        1.114               bytesWritten = _socket->write(sendStart, bytesToWrite);
 838                                      if (bytesWritten < 0)
 839                                          _socketWriteError();
 840                                      totalBytesWritten += bytesWritten;
 841                                      bytesRemaining -= bytesWritten;
 842                                    }
 843 kumpf            1.98  
 844                                    if (isChunkResponse == true)
 845                                    {
 846 kumpf            1.122                 // send chunk terminator, on the last chunk, it is the chunk
 847                                        // body terminator
 848 mike             1.104                 Buffer trailer;
 849 dave.sudlik      1.125                 Boolean traceTrailer = false;
 850 kumpf            1.98                  trailer << chunkLineTerminator;
 851                        
 852 kumpf            1.122                 // on the last chunk, attach the last chunk termination
 853                                        // sequence: 0 + last chunk terminator + optional trailer +
 854                                        // chunkBodyTerminator
 855 kumpf            1.98  
 856                                        if (isLast == true)
 857                                        {
 858                                            if (bytesRemaining > 0)
 859                                                _throwEventFailure(httpStatusInternal,
 860                                                    "more bytes after indicated last chunk");
 861                                            trailer << "0" << chunkLineTerminator;
 862                                            Uint32 httpStatus = cimException.getCode();
 863                        
 864                                            if (httpStatus != 0)
 865                                            {
 866                                                char httpStatusP[11];
 867                                                sprintf(httpStatusP, "%u",httpStatus);
 868                        
 869 dave.sudlik      1.125                         traceTrailer = true;
 870 kumpf            1.122                         trailer << _mpostPrefix << headerNameCode <<
 871                                                    headerNameTerminator << httpStatusP <<
 872                                                    headerLineTerminator;
 873                                                const String& httpDescription =
 874                                                    cimException.getMessage();
 875 kumpf            1.98                          if (httpDescription.size() != 0)
 876                                                    trailer << _mpostPrefix << headerNameDescription <<
 877 kumpf            1.122                                 headerNameTerminator << httpDescription <<
 878                                                        headerLineTerminator;
 879 kumpf            1.98                      }
 880                        
 881                                            // Add Content-Language to the trailer if requested
 882 kumpf            1.105                     if (contentLanguages.size() != 0)
 883 kumpf            1.98                      {
 884 dave.sudlik      1.125                         traceTrailer = true;
 885 kumpf            1.98                          trailer << _mpostPrefix
 886                                                    << headerNameContentLanguage << headerNameTerminator
 887 kumpf            1.105                             << LanguageParser::buildContentLanguageHeader(
 888                                                           contentLanguages)
 889 kumpf            1.98                              << headerLineTerminator;
 890                                            }
 891                        
 892                                            // now add chunkBodyTerminator
 893                                            trailer << chunkBodyTerminator;
 894                                        } // if isLast
 895                        
 896 dave.sudlik      1.125                 if (traceTrailer)
 897                                        {
 898 marek            1.131                     PEG_TRACE((TRC_XML_IO, Tracer::LEVEL2,
 899 kumpf            1.130                         "<!-- Trailer: queue id: %u -->\n%s",
 900 dave.sudlik      1.125                         getQueueId(),
 901 marek            1.131                         trailer.getData()));
 902 dave.sudlik      1.125                 }
 903 kumpf            1.98                  sendStart = (char *) trailer.getData();
 904                                        Sint32 chunkBytesToWrite = (Sint32) trailer.size();
 905 thilo.boehm      1.129 
 906 marek            1.131                 PEG_TRACE_CSTRING(TRC_HTTP,Tracer::LEVEL4, 
 907 thilo.boehm      1.129                         "HTTPConnection::_handleWriteEvent: "
 908                                                "Sending the last chunk with chunk body terminator ");
 909                        
 910 kumpf            1.98                  bytesWritten = _socket->write(sendStart, chunkBytesToWrite);
 911                                        if (bytesWritten < 0)
 912 kumpf            1.113                     _socketWriteError();
 913 kumpf            1.98                  totalBytesWritten += bytesWritten;
 914                                    } // isChunkResponse == true
 915                        
 916                                } // for all bytes in message
 917                        
 918                            } // try
 919                        
 920                            catch (Exception &e)
 921                            {
 922                                httpStatus = e.getMessage();
 923                            }
 924                            catch (...)
 925                            {
 926                                httpStatus = HTTP_STATUS_INTERNALSERVERERROR;
 927 marek            1.134         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2, "Unknown internal error");
 928 kumpf            1.98      }
 929                        
 930                            if (isLast == true)
 931                            {
 932                                _incomingBuffer.clear();
 933                                _transferEncodingTEValues.clear();
 934                        
 935 a.dunfey         1.127         // Reset the transfer encoding chunk offset. If it is not reset here,
 936                                // then a request sent with chunked encoding may not be properly read
 937                                // off of a connection in which a chunked response has been sent.
 938                                _transferEncodingChunkOffset = 0;
 939                        
 940 kumpf            1.98          //
 941                                // decrement request count
 942                                //
 943                        
 944                                _requestCount--;
 945 kumpf            1.133         _responsePending = false;
 946 kumpf            1.98  
 947                                if (httpStatus.size() == 0)
 948                                {
 949                                    static const char msg[] =
 950                                        "A response has been sent (%d of %d bytes have been written).\n"
 951                                        "There are %d requests pending within the CIM Server.\n"
 952 kumpf            1.122                 "A total of %d requests have been processed on this "
 953                                            "connection.";
 954 kumpf            1.98  
 955 marek            1.131             PEG_TRACE((TRC_HTTP, Tracer::LEVEL4, msg, totalBytesWritten,
 956                                        messageLength, _requestCount.get(), _connectionRequestCount));
 957 kumpf            1.98          }
 958                        
 959                                //
 960                                // Since we are done writing, update the status of entry to IDLE
 961                                // and notify the Monitor.
 962                                //
 963                                if (_isClient() == false)
 964                                {
 965 j.alex           1.99              // Check for message to close
 966 kumpf            1.123             if (message.getCloseConnect()== true)
 967 j.alex           1.99              {
 968 marek            1.131                 PEG_TRACE((
 969 j.alex           1.99                      TRC_HTTP,
 970                                            Tracer::LEVEL3,
 971 kumpf            1.122                     "HTTPConnection::_handleWriteEvent - Connection: Close "
 972 kumpf            1.135                         "in client message."));
 973                                        _closeConnection();
 974 kumpf            1.122             }
 975                                    else
 976                                    {
 977 marek            1.131                 PEG_TRACE((TRC_HTTP, Tracer::LEVEL2,
 978                                            "Now setting state to %d", _MonitorEntry::IDLE));
 979 j.alex           1.99                  _monitor->setState (_entry_index, _MonitorEntry::IDLE);
 980                                        _monitor->tickle();
 981                                    }
 982 kumpf            1.98              cimException = CIMException();
 983                                }
 984                            }
 985 sushma.fernandes 1.78  
 986 kumpf            1.98      return httpStatus.size() == 0 ? false : true;
 987 mday             1.5   
 988                        }
 989                        
 990                        void HTTPConnection::handleEnqueue()
 991                        {
 992                           Message* message = dequeue();
 993                        
 994                            if (!message)
 995                                return;
 996                            handleEnqueue(message);
 997 mike             1.2   }
 998                        
 999                        Boolean _IsBodylessMessage(const char* line)
1000                        {
1001                            //ATTN: Make sure this is the right place to check for HTTP/1.1 and
1002                            //      HTTP/1.0 that is part of the authentication challenge header.
1003 kumpf            1.9       // ATTN-RK-P2-20020305: How do we make sure we have the complete list?
1004 h.sterling       1.75  
1005                            // List of request methods which do not have message bodies
1006                            const char* METHOD_NAMES[] =
1007                            {
1008                                "GET",
1009                                "HEAD"
1010                            };
1011                        
1012 kumpf            1.122     // List of response codes which the client accepts and which should not
1013                            // (normally) have message bodies.  The RFC is vague regarding which
1014                            // response codes support or require bodies.  These are being reported by
1015                            // class (4xx, 5xx, etc) because the CIM client should be able to handle
1016                            // any status code, including those not explicitly defined in RFC 2616.
1017                            // Therefore, listing codes individually will not work because the client
1018                            // socket will hang on a code not in this list if no content length is
1019                            // specified.
1020 h.sterling       1.75      // See bugzilla 1586
1021                            const char* RESPONSE_CODES[] =
1022                            {
1023 kumpf            1.98          "HTTP/1.1 3XX",
1024                                "HTTP/1.0 3XX",
1025 h.sterling       1.75          "HTTP/1.1 4XX",
1026                                "HTTP/1.0 4XX",
1027                                "HTTP/1.1 5XX",
1028                                "HTTP/1.0 5XX"
1029                            };
1030                        
1031 david.dillard    1.93      // Check for bodyless HTTP request method
1032 h.sterling       1.75      const Uint32 METHOD_NAMES_SIZE = sizeof(METHOD_NAMES) / sizeof(char*);
1033                        
1034                            for (Uint32 i = 0; i < METHOD_NAMES_SIZE; i++)
1035                            {
1036 a.dunfey         1.126         Uint32 n = (Uint32)strlen(METHOD_NAMES[i]);
1037 h.sterling       1.75  
1038 kumpf            1.98          if (strncmp(line, METHOD_NAMES[i], n) == 0 && isspace(line[n]))
1039                                    return true;
1040 h.sterling       1.75      }
1041                        
1042                            // Check for bodyless HTTP status code
1043                            const Uint32 RESPONSE_CODES_SIZE = sizeof(RESPONSE_CODES) / sizeof(char*);
1044                        
1045                            for (Uint32 i = 0; i < RESPONSE_CODES_SIZE; i++)
1046                            {
1047 a.dunfey         1.126         Uint32 n = (Uint32)strlen(RESPONSE_CODES[i]);
1048 h.sterling       1.75  
1049 kumpf            1.98          if (strncmp(line, RESPONSE_CODES[i], n - 2) == 0 && isspace(line[n]))
1050 h.sterling       1.75                  return true;
1051                                    }
1052                        
1053                            return false;
1054                        }
1055                        
1056                        /*
1057                        Boolean _IsBodylessMessage(const char* line)
1058                        {
1059                            //ATTN: Make sure this is the right place to check for HTTP/1.1 and
1060                            //      HTTP/1.0 that is part of the authentication challenge header.
1061                            // ATTN-RK-P2-20020305: How do we make sure we have the complete list?
1062 mike             1.2       const char* METHOD_NAMES[] =
1063                            {
1064                                "GET",
1065 kumpf            1.9           "HTTP/1.1 400",
1066                                "HTTP/1.0 400",
1067 mike             1.2           "HTTP/1.1 401",
1068 kumpf            1.10          "HTTP/1.0 401",
1069 kumpf            1.63          "HTTP/1.1 413",
1070                                "HTTP/1.0 413",
1071 kumpf            1.60          "HTTP/1.1 500",
1072                                "HTTP/1.0 500",
1073 kumpf            1.10          "HTTP/1.1 501",
1074 kumpf            1.60          "HTTP/1.0 501",
1075                                "HTTP/1.1 503",
1076                                "HTTP/1.0 503"
1077 mike             1.2       };
1078                        
1079                            const Uint32 METHOD_NAMES_SIZE = sizeof(METHOD_NAMES) / sizeof(char*);
1080                        
1081                            for (Uint32 i = 0; i < METHOD_NAMES_SIZE; i++)
1082                            {
1083 kumpf            1.98          Uint32 n = strlen(METHOD_NAMES[i]);
1084 mike             1.2   
1085 kumpf            1.98          if (strncmp(line, METHOD_NAMES[i], n) == 0 && isspace(line[n]))
1086                                    return true;
1087 mike             1.2       }
1088                        
1089                            return false;
1090 h.sterling       1.75  }*/
1091 mike             1.2   
1092 david.dillard    1.93  void HTTPConnection::_getContentLengthAndContentOffset()
1093 mike             1.2   {
1094 kumpf            1.98      static const char func[] =
1095 brian.campbell   1.72      "HTTPConnection::_getContentLengthAndContentOffset";
1096 kumpf            1.128     Uint32 size = _incomingBuffer.size();
1097 kumpf            1.98      if (size == 0)
1098                                return;
1099 mike             1.2       char* data = (char*)_incomingBuffer.getData();
1100                            char* line = (char*)data;
1101                            char* sep;
1102                            Uint32 lineNum = 0;
1103                            Boolean bodylessMessage = false;
1104 kumpf            1.109     Boolean gotContentLength = false;
1105                            Boolean gotTransferEncoding = false;
1106                            Boolean gotContentLanguage = false;
1107                            Boolean gotTransferTE = false;
1108 mike             1.2   
1109 sushma.fernandes 1.138     while ((sep = 
1110                                HTTPMessage::findSeparator(line, (Uint32)(size - (line - data)))))
1111 mike             1.2       {
1112 kumpf            1.98          char save = *sep;
1113                                *sep = '\0';
1114                        
1115                                // Did we find the double separator which terminates the headers?
1116                        
1117                                if (line == sep)
1118                                {
1119                                    *sep = save;
1120                                    line = sep + ((save == '\r') ? 2 : 1);
1121 a.dunfey         1.126             _contentOffset = (Sint32)(line - _incomingBuffer.getData());
1122 kumpf            1.98  
1123                                    // reserve space for entire non-chunked message
1124                                    if (_contentLength > 0)
1125                                    {
1126 dave.sudlik      1.110                 try
1127                                        {
1128 kumpf            1.122                     Uint32 capacity = (Uint32)(_contentLength +
1129 dave.sudlik      1.110                         _contentOffset + 1);
1130                                            _incomingBuffer.reserveCapacity(capacity);
1131                                            data = (char *)_incomingBuffer.getData();
1132                                            data[capacity-1] = 0;
1133                                        }
1134 kumpf            1.123                 catch (const PEGASUS_STD(bad_alloc)&)
1135 dave.sudlik      1.110                 {
1136                                            _throwEventFailure(HTTP_STATUS_REQUEST_TOO_LARGE,
1137                                                "Error reserving space for non-chunked message");
1138                                        }
1139 kumpf            1.123                 catch (...)
1140 dave.sudlik      1.110                 {
1141 kumpf            1.122                     _throwEventFailure(
1142                                                httpStatusInternal, "unexpected exception");
1143 dave.sudlik      1.110                 }
1144 kumpf            1.98              }
1145                        
1146                                    break;
1147                                }
1148 mike             1.2   
1149 kumpf            1.98          // If this is one of the bodyless methods, then we can assume the
1150                                // message is complete when the "\r\n\r\n" is encountered.
1151 mike             1.2   
1152 kumpf            1.98          if (lineNum == 0 && _IsBodylessMessage(line))
1153                                    bodylessMessage = true;
1154                        
1155                                // Look for the content-length if not already found:
1156                        
1157                                char* colon = strchr(line, ':');
1158                        
1159                                if (colon)
1160                                {
1161                                    *colon  = '\0';
1162                        
1163                                    // remove whitespace after colon before value
1164                                    char *valueStart = colon + 1;
1165 kumpf            1.123             while (*valueStart == ' ' || *valueStart == '\t')
1166 kumpf            1.98                  valueStart++;
1167                        
1168                                    // we found some non-whitespace token
1169                                    if (valueStart != sep)
1170                                    {
1171                                        char *valueEnd = sep - 1;
1172                        
1173 kumpf            1.122                 // now remove whitespace from end of line back to last byte
1174                                        // of value
1175 kumpf            1.123                 while (*valueEnd == ' ' || *valueEnd == '\t')
1176 kumpf            1.98                      valueEnd--;
1177                        
1178                                        char valueSave = *(valueEnd+1);
1179                        
1180                                        if (System::strcasecmp(line, headerNameContentLength) == 0)
1181                                        {
1182 kumpf            1.109                     if (gotContentLength)
1183                                            {
1184                                                _throwEventFailure(HTTP_STATUS_BADREQUEST,
1185                                                    "Duplicate Content-Length header detected");
1186                                            }
1187                                            gotContentLength = true;
1188                        
1189 kumpf            1.98                      if (_transferEncodingValues.size() == 0)
1190 kumpf            1.109                     {
1191                                                // Use a dummy character conversion to catch an
1192                                                // invalid character in the value.
1193                                                char dummy;
1194                                                if (sscanf(valueStart, "%d%c",
1195                                                        &_contentLength, &dummy) != 1)
1196                                                {
1197                                                    _throwEventFailure(HTTP_STATUS_BADREQUEST,
1198                                                        "Invalid Content-Length header detected");
1199                                                }
1200                                            }
1201                                            else
1202                                            {
1203                                                _contentLength = -1;
1204                                            }
1205 kumpf            1.98                  }
1206 kumpf            1.122                 else if (System::strcasecmp(
1207                                                     line, headerNameTransferEncoding) == 0)
1208 kumpf            1.98                  {
1209 kumpf            1.109                     if (gotTransferEncoding)
1210                                            {
1211                                                _throwEventFailure(HTTP_STATUS_BADREQUEST,
1212                                                    "Duplicate Transfer-Encoding header detected");
1213                                            }
1214                                            gotTransferEncoding = true;
1215                        
1216 kumpf            1.98                      _transferEncodingValues.clear();
1217                        
1218 kumpf            1.122                     if (strcmp(valueStart,
1219                                                    headerValueTransferEncodingChunked) == 0)
1220                                                _transferEncodingValues.append(
1221                                                    headerValueTransferEncodingChunked);
1222                                            else if (strcmp(valueStart,
1223                                                         headerValueTransferEncodingIdentity) == 0)
1224 kumpf            1.98                          ; // do nothing
1225                                            else _throwEventFailure(HTTP_STATUS_NOTIMPLEMENTED,
1226 kumpf            1.122                              "unimplemented transfer-encoding value");
1227 kumpf            1.98                      _contentLength = -1;
1228                                        }
1229 kumpf            1.122                 else if (System::strcasecmp(
1230                                                     line, headerNameContentLanguage) == 0)
1231 kumpf            1.98                  {
1232 kumpf            1.122                     // note: if this is a chunked header, then this will be
1233                                            // ignored later
1234                                            String contentLanguagesString(
1235 a.dunfey         1.126                         valueStart, (Uint32)(valueEnd - valueStart + 1));
1236 kumpf            1.98                      try
1237                                            {
1238 kumpf            1.109                         ContentLanguageList contentLanguagesValue =
1239 kumpf            1.105                             LanguageParser::parseContentLanguageHeader(
1240                                                        contentLanguagesString);
1241 kumpf            1.109 
1242                                                if (gotContentLanguage)
1243                                                {
1244                                                    // Append these content languages to the existing
1245                                                    // list.
1246                                                    for (Uint32 i = 0;
1247                                                         i < contentLanguagesValue.size(); i++)
1248                                                    {
1249                                                        contentLanguages.append(
1250                                                            contentLanguagesValue.getLanguageTag(i));
1251                                                    }
1252                                                }
1253                                                else
1254                                                {
1255                                                    contentLanguages = contentLanguagesValue;
1256                                                    gotContentLanguage = true;
1257                                                }
1258 kumpf            1.98                      }
1259 kumpf            1.123                     catch (...)
1260 kumpf            1.98                      {
1261 marek            1.131                         PEG_TRACE((TRC_HTTP, Tracer::LEVEL2,
1262 kumpf            1.122                             "HTTPConnection: ERROR: contentLanguages had "
1263                                                        "parsing failure. clearing languages. error "
1264                                                        "data=%s",
1265 marek            1.131                             (const char *)contentLanguagesString.getCString()));
1266 kumpf            1.105                         contentLanguages.clear();
1267 kumpf            1.98                      }
1268                                        }
1269                                        else if (System::strcasecmp(line, headerNameTransferTE) == 0)
1270                                        {
1271 kumpf            1.109                     if (gotTransferTE)
1272                                            {
1273                                                _throwEventFailure(HTTP_STATUS_BADREQUEST,
1274                                                    "Duplicate TE header detected");
1275                                            }
1276                                            gotTransferTE = true;
1277                        
1278 kumpf            1.98                      _transferEncodingTEValues.clear();
1279                                            static const char valueDelimiter = ',';
1280                                            char *valuesStart = valueStart;
1281                        
1282                                            // now tokenize the values
1283                                            while (*valuesStart)
1284                                            {
1285                                                // strip off whitepsace from the front
1286 kumpf            1.123                         while (*valuesStart == ' ' || *valuesStart == '\t')
1287 kumpf            1.98                              valuesStart++;
1288                        
1289                                                if (valuesStart == valueEnd)
1290                                                    break;
1291                        
1292                                                char *v = strchr(valuesStart, valueDelimiter);
1293                                                if (v)
1294                                                {
1295                                                    if (v == valuesStart)
1296                                                    {
1297                                                        valuesStart++;
1298                                                        continue;
1299                                                    }
1300                                                    v--;
1301                                                    // strip off whitespace from the end
1302 kumpf            1.123                             while (*v == ' ' || *v == '\t')
1303 kumpf            1.98                                  v--;
1304                                                    v++;
1305                                                    *v = 0;
1306                                                }
1307                        
1308                                                _transferEncodingTEValues.append(valuesStart);
1309                        
1310                                                if (v)
1311                                                {
1312                                                    *v = valueDelimiter;
1313                                                    valuesStart = v+1;
1314                                                }
1315                                                else break;
1316                                            }
1317                                        }
1318                        
1319                                        *(valueEnd+1) = valueSave;
1320                                    } // if some value tokens
1321                        
1322                                    *colon = ':';
1323                                }
1324 kumpf            1.98  
1325                                *sep = save;
1326                                line = sep + ((save == '\r') ? 2 : 1);
1327                                lineNum++;
1328 mike             1.2       }
1329                        
1330                            if (_contentOffset != -1 && bodylessMessage)
1331 kumpf            1.98          _contentLength = 0;
1332 mike             1.2   }
1333                        
1334                        void HTTPConnection::_clearIncoming()
1335                        {
1336                            _contentOffset = -1;
1337                            _contentLength = -1;
1338                            _incomingBuffer.clear();
1339 kumpf            1.98      _mpostPrefix.clear();
1340                            contentLanguages.clear();
1341 mike             1.2   }
1342                        
1343                        void HTTPConnection::_closeConnection()
1344                        {
1345 kumpf            1.98      // return - don't send the close connection message.
1346                            // let the monitor dispatch function do the cleanup.
1347                            PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::_closeConnection");
1348                            _connectionClosePending = true;
1349                        
1350                            // NOTE: if there is a response pending while a close connection request
1351                            // occurs, then this indicates potential activity on this connection apart
1352                            // from this thread of execution (although this code here is locked, other
1353                            // threads may be waiting on this one.)
1354                            // The caller MUST check this value before attempting a delete of this
1355                            // connnection, otherwise the delete may occur while other chunked responses
1356                            // are waiting to be delivered through this connection.
1357                            // This condition may happen on a client error/timeout/interrupt/disconnect
1358                        
1359                            if (_isClient() == false)
1360                            {
1361                                if (_responsePending == true)
1362                                {
1363 marek            1.131             PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL2,
1364 kumpf            1.122                 "HTTPConnection::_closeConnection - Close connection "
1365                                            "requested while responses are still expected on this "
1366                                            "connection. connection=0x%p, socket=%d\n",
1367 marek            1.131                 (void*)this, getSocket()));
1368 kumpf            1.61  
1369 kumpf            1.98          }
1370                        
1371                                // still set to DYING
1372 marek            1.131         PEG_TRACE((TRC_HTTP, Tracer::LEVEL2,
1373                                    "Now setting state to %d", _MonitorEntry::DYING));
1374 kumpf            1.98          _monitor->setState (_entry_index, _MonitorEntry::DYING);
1375                                _monitor->tickle();
1376                            }
1377                        
1378                            if (_connectionRequestCount == 0)
1379                            {
1380 marek            1.131         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL4,
1381 kumpf            1.122             "HTTPConnection::_closeConnection - Connection being closed "
1382                                        "without receiving any requests.");
1383 kumpf            1.98      }
1384                        
1385                            PEG_METHOD_EXIT();
1386 kumpf            1.3   
1387 kumpf            1.98  //    Message* message= new CloseConnectionMessage(_socket->getSocket));
1388                        //    message->dest = _ownerMessageQueue->getQueueId();
1389 mday             1.6   //    SendForget(message);
1390 mday             1.19  //    _ownerMessageQueue->enqueue(message);
1391 mike             1.2   }
1392                        
1393 brian.campbell   1.81  Boolean HTTPConnection::isChunkRequested()
1394                        {
1395 kumpf            1.98      Boolean answer = false;
1396                            if (_transferEncodingTEValues.size() > 0 &&
1397                                (Contains(_transferEncodingTEValues, String(headerValueTEchunked)) ||
1398                                 Contains(_transferEncodingTEValues, String(headerValueTEtrailers))))
1399                                answer = true;
1400 chuck            1.95  
1401                        #ifdef PEGASUS_KERBEROS_AUTHENTICATION
1402 kumpf            1.98      CIMKerberosSecurityAssociation *sa = _authInfo->getSecurityAssociation();
1403 chuck            1.95  
1404 kumpf            1.98      if (sa)
1405                            {
1406                                answer = false;
1407                            }
1408 chuck            1.95  #endif
1409                        
1410 kumpf            1.98      return answer;
1411 brian.campbell   1.81  }
1412                        
1413 marek            1.115 void HTTPConnection::setSocketWriteTimeout(Uint32 socketWriteTimeout)
1414                        {
1415                                _socket->setSocketWriteTimeout(socketWriteTimeout);
1416                        }
1417                        
1418                        
1419 brian.campbell   1.72  // determine if the current code being executed is on the client side
1420                        
1421                        Boolean HTTPConnection::_isClient()
1422                        {
1423 kumpf            1.98      return strcmp(get_owner().getQueueName(),
1424                                PEGASUS_QUEUENAME_HTTPCONNECTOR) == 0 ? true : false;
1425 brian.campbell   1.72  }
1426                        
1427                        /*
1428                         * determine if the data read in should be treated as transfer encoded data.
1429                         * If so, proceed to strip out the transfer encoded meta data within the body
1430 david.dillard    1.93   * but the headers relating to transfer encoding will remain unchanged.
1431                         * One should refer to the transfer encoding section of the HTTP protocol
1432 brian.campbell   1.72   * specification to understand the parsing semantics below.
1433                         * NOTE: this function is coded as a syncronous read! The entire message will
1434                         * be read in before the message leaves this class and is passed up to the
1435                         * client application.
1436                         */
1437                        
1438 david.dillard    1.94  void HTTPConnection::_handleReadEventTransferEncoding()
1439 brian.campbell   1.72  {
1440 kumpf            1.122     static const char func[] =
1441                                "HTTPConnection::_handleReadEventTransferEncoding";
1442 kumpf            1.98      PEG_METHOD_ENTER(TRC_HTTP, func);
1443 kumpf            1.122 
1444 kumpf            1.128     Uint32 messageLength = _incomingBuffer.size();
1445 kumpf            1.98      Uint32 headerLength = (Uint32) _contentOffset;
1446                        
1447                            // return immediately under these conditions:
1448                        
1449                            // - Header terminator has not been reached yet (_contentOffset < 0)
1450                            // - This is a non-transfer encoded message because the content length
1451                            //   has been set from the given header value (_contentLength > 0)
1452                            //   (_contentLength == 0 means bodyless, so return too - section 4.3)
1453                            // - The message read in so far is <= to the header length
1454                            // - No transfer encoding has been declared in the header.
1455                        
1456                            if (_contentOffset < 0 || _contentLength >= 0 ||
1457                                messageLength <= headerLength || _transferEncodingValues.size() == 0)
1458                            {
1459                                PEG_METHOD_EXIT();
1460                                return;
1461                            }
1462                        
1463                            // on the first chunk in the message, set the encoding offset to the content
1464                            // offset
1465                        
1466 kumpf            1.98      if (_transferEncodingChunkOffset == 0)
1467                                _transferEncodingChunkOffset = (Uint32) _contentOffset;
1468 brian.campbell   1.72  
1469 kumpf            1.98      char *headerStart = (char *) _incomingBuffer.getData();
1470                            char *messageStart = headerStart;
1471 brian.campbell   1.72  
1472 kumpf            1.98      // loop thru the received data (so far) and strip out all chunked meta data.
1473                            // this logic assumes that the data read in may be only partial at any point
1474                            // during the parsing. the variable _transferEncodingChunkOffset represents
1475                            // the byte offset (from the start of the message) of the last NON completed
1476                            // chunk parsed within the message. Remember that the tcp reader has padded
1477                            // the buffer with a terminating null for easy string parsing.
1478 brian.campbell   1.72  
1479 kumpf            1.98      for (;;)
1480                            {
1481                                // we have parsed the length, but not all bytes of chunk have been read
1482                                // in yet
1483                                if (_transferEncodingChunkOffset >= messageLength)
1484                                    break;
1485                        
1486                                // this is the length from _transferEncodingChunkOffset to the end
1487                                // of the message (so far). It represents the bytes that have not been
1488                                // processed yet
1489                        
1490                                Uint32 remainderLength = messageLength - _transferEncodingChunkOffset;
1491                        
1492                                // the start of the first fully non-parsed chunk of this interation
1493                                char *chunkLineStart = messageStart + _transferEncodingChunkOffset;
1494                                char *chunkLineEnd = chunkLineStart;
1495                        
1496 kumpf            1.122         // Find the end of the hex string representing the data portion
1497                                // length of the current chunk. Note that we must hit at least one
1498                                // non-hexdigit (except null) to know we have read in the complete
1499                                // number
1500 kumpf            1.98  
1501                                while (isxdigit(*chunkLineEnd))
1502                                    chunkLineEnd++;
1503                        
1504                                if (! *chunkLineEnd)
1505                                    break;
1506                        
1507                                // This is the parsed chunk length in hex. From here on, this many bytes
1508                                // plus the chunk terminator (AFTER this chunk line is done) must be
1509                                // read in to constitute a complete chunk in which
1510                                // _transferEncodingChunkOffset can be incremented to the next chunk
1511                        
1512                                Uint32 chunkLengthParsed =
1513                                    (Uint32) strtoul((const char *)chunkLineStart, 0, 16);
1514                        
1515                                // this also covers strings stated even larger
1516                                if (chunkLengthParsed == PEG_NOT_FOUND)
1517                                    _throwEventFailure(HTTP_STATUS_REQUEST_TOO_LARGE,
1518                                        "stated chunk length too large");
1519                        
1520                                char *chunkExtensionStart = chunkLineEnd;
1521 kumpf            1.98          chunkLineEnd = strstr(chunkLineEnd, chunkLineTerminator);
1522                        
1523 kumpf            1.122         // If we have not received the chunk line terminator yet, then
1524                                // return and wait for the next iteration. This is done because the
1525                                // hex length given only represents the non-meta data, not the chunk
1526                                // line itself.
1527 kumpf            1.98  
1528                                if (!chunkLineEnd)
1529                                    break;
1530                        
1531 kumpf            1.122         // the token after the hex digit must be either the chunk line
1532                                // terminator or the chunk extension terminator. If not, the sender
1533                                // has sent an illegal chunked encoding syntax.
1534 kumpf            1.98  
1535                                if (strncmp(chunkExtensionStart, chunkExtensionTerminator,
1536                                        chunkExtensionTerminatorLength) != 0 &&
1537                                    strncmp(chunkExtensionStart, chunkLineTerminator,
1538                                        chunkLineTerminatorLength) != 0)
1539 kumpf            1.122         {
1540                                    _throwEventFailure(
1541                                        HTTP_STATUS_BADREQUEST, "missing chunk extension");
1542                                }
1543 kumpf            1.98  
1544                                chunkLineEnd += chunkLineTerminatorLength;
1545 a.dunfey         1.126         Uint32 chunkLineLength = (Uint32)(chunkLineEnd - chunkLineStart);
1546 kumpf            1.98          Uint32 chunkMetaLength = chunkLineLength;
1547                                if (chunkLengthParsed > 0)
1548                                    chunkMetaLength += chunkTerminatorLength;
1549                                Uint32 chunkTerminatorOffset = _transferEncodingChunkOffset +
1550                                    chunkLineLength + chunkLengthParsed;
1551                        
1552                                // The parsed length represents the non-meta data bytes which starts
1553                                // after the chunk line terminator has been received.
1554 kumpf            1.122         // If we dont have enough remainder bytes to process from the length
1555                                // parsed then return and wait for the next iteration.
1556 kumpf            1.98  
1557 jim.wunderlich   1.108         //
1558                                // Also, if this is the last chunk, then we have to know if there
1559 kumpf            1.122         // is enough data in here to be able to verify that meta crlf for
1560 jim.wunderlich   1.108         // the end of the whole chunked message is present.
1561 kumpf            1.122         // If chunkLengthParsed + chunkMetaLenght == reminderLength, it
1562 jim.wunderlich   1.108         // means that there is a space only for meta crlf of the last chunk.
1563 kumpf            1.122         // Therefore go back and re-read socket until you get enough data
1564                                // for at least 2 crlfs.  One for the end of the last chunk or
1565                                // the end of the optional trailer, and one for the end of whole
1566 jim.wunderlich   1.108         // message.
1567                        
1568                                if (chunkLengthParsed + chunkMetaLength >= remainderLength)
1569 kumpf            1.98              break;
1570                        
1571 kumpf            1.122         // at this point we have a complete chunk. proceed and strip out
1572                                // meta-data
1573                                // NOTE: any time "remove" is called on the buffer, many variables
1574                                // must be recomputed to reflect the data removed.
1575 brian.campbell   1.72  
1576 kumpf            1.98          // remove the chunk length line
1577                                _incomingBuffer.remove(_transferEncodingChunkOffset, chunkLineLength);
1578 kumpf            1.128         messageLength = _incomingBuffer.size();
1579 kumpf            1.98          // always keep the byte after the last data byte null for easy string
1580                                // processing.
1581 brian.campbell   1.72          messageStart[messageLength] = 0;
1582                        
1583 kumpf            1.98          // recalculate since we just removed the chunk length line
1584                                chunkTerminatorOffset -= chunkLineLength;
1585                        
1586                                // is this the last chunk ?
1587                                if (chunkLengthParsed == 0)
1588                                {
1589                                    // We are at the last chunk. The only remaining data should be:
1590                                    // 1. optional trailer first
1591 kumpf            1.122             // 2. message terminator (will remain on incoming buffer and
1592                                    //    passed up)
1593 kumpf            1.98  
1594                                    remainderLength -= chunkLineLength;
1595                        
1596                                    CIMStatusCode cimStatusCode = CIM_ERR_SUCCESS;
1597                                    Uint32 httpStatusCode = HTTP_STATUSCODE_OK;
1598                                    String httpStatus;
1599                                    String cimErrorValue;
1600                        
1601                                    // is there an optional trailer ?
1602                                    if (remainderLength > chunkBodyTerminatorLength)
1603                                    {
1604 kumpf            1.122                 Uint32 trailerLength =
1605                                            remainderLength - chunkBodyTerminatorLength;
1606 kumpf            1.98                  Uint32 trailerOffset = _transferEncodingChunkOffset;
1607                                        char *trailerStart = messageStart + trailerOffset;
1608                                        char *trailerTerminatorStart = trailerStart + trailerLength -
1609                                            trailerTerminatorLength;
1610                        
1611                                        // no trailer terminator before end of chunk body ?
1612                                        if (strncmp(trailerTerminatorStart, trailerTerminator,
1613                                                trailerTerminatorLength) != 0)
1614                                            _throwEventFailure(HTTP_STATUS_BADREQUEST,
1615                                                "No chunk trailer terminator received");
1616                        
1617 mike             1.104                 Buffer trailer;
1618 kumpf            1.98                  // add a dummy startLine so that the parser works
1619                                        trailer << " " << headerLineTerminator;
1620                        
1621                                        char save = trailerStart[trailerLength];
1622                                        trailerStart[trailerLength] = 0;
1623                                        trailer << trailerStart;
1624                                        trailerStart[trailerLength] = save;
1625                        
1626                                        _incomingBuffer.remove(trailerOffset, trailerLength);
1627 kumpf            1.128                 messageLength = _incomingBuffer.size();
1628 kumpf            1.98                  messageStart[messageLength] = 0;
1629                                        remainderLength -= trailerLength;
1630                        
1631                                        // parse the trailer looking for the code and description
1632                                        String startLine;
1633                                        Array<HTTPHeader> headers;
1634                                        Uint32 contentLength = 0;
1635                                        HTTPMessage httpTrailer(trailer);
1636                                        httpTrailer.parse(startLine, headers, contentLength);
1637                        
1638                                        String cimErrorName = headerNameError;
1639                                        // first look for cim error. this is an http level error
1640                                        Boolean found = false;
1641                        
1642 kumpf            1.122                 found = httpTrailer.lookupHeader(
1643                                            headers, cimErrorName, cimErrorValue, true);
1644 kumpf            1.98  
1645                                        if (found == true)
1646                                        {
1647 kumpf            1.122                     // we have a cim error. parse the header to get the
1648                                            // original http level error if any, otherwise, we have
1649                                            // to make one up.
1650 kumpf            1.98  
1651 mike             1.104                     Buffer header(messageStart, headerLength);
1652 kumpf            1.98                      String startLine;
1653                                            Array<HTTPHeader> headers;
1654                                            Uint32 contentLength = 0;
1655                                            HTTPMessage httpHeader(header);
1656                                            httpHeader.parse(startLine, headers, contentLength);
1657                                            String httpVersion;
1658 kumpf            1.122                     Boolean isValid = httpHeader.parseStatusLine(
1659                                                startLine, httpVersion, httpStatusCode,httpStatus);
1660 kumpf            1.98                      if (isValid == false || httpStatusCode == 0 ||
1661                                                    httpStatusCode == HTTP_STATUSCODE_OK)
1662                                            {
1663                                                // ATTN: make up our own http code if not given ?
1664                                                httpStatusCode = (Uint32) HTTP_STATUSCODE_BADREQUEST;
1665                                                httpStatus = HTTP_STATUS_BADREQUEST;
1666                                            }
1667                                        }
1668                                        else
1669                                        {
1670                                            String codeName = headerNameCode;
1671                                            String codeValue;
1672 kumpf            1.122                     found = httpTrailer.lookupHeader(
1673                                                headers, codeName, codeValue, true);
1674 kumpf            1.98                      if (found == true && codeValue.size() > 0 &&
1675 kumpf            1.122                         (cimStatusCode = (CIMStatusCode)atoi(
1676                                                     codeValue.getCString())) > 0)
1677 kumpf            1.98                      {
1678 kumpf            1.122                         HTTPMessage::lookupHeaderPrefix(
1679                                                    headers, codeName, _mpostPrefix);
1680                                                httpStatus = _mpostPrefix + codeName +
1681                                                    headerNameTerminator + codeValue +
1682                                                    headerLineTerminator;
1683 kumpf            1.98  
1684                                                // look for cim status description
1685                                                String descriptionName = headerNameDescription;
1686                                                String descriptionValue;
1687 kumpf            1.122                         found = httpTrailer.lookupHeader(
1688                                                    headers, descriptionName, descriptionValue, true);
1689 kumpf            1.98                          if (descriptionValue.size() == 0)
1690 kumpf            1.122                         {
1691                                                    descriptionValue =
1692                                                        cimStatusCodeToString(cimStatusCode);
1693                                                }
1694 kumpf            1.98  
1695 kumpf            1.122                         httpStatus = httpStatus + _mpostPrefix +
1696                                                    descriptionName + headerNameTerminator +
1697                                                    descriptionValue + headerLineTerminator;
1698 kumpf            1.98  
1699                                            } // if found a cim status code
1700                        
1701                                            // Get Content-Language out of the trailer, if it is there
1702                                            String contentLanguagesString;
1703                                            found = httpTrailer.lookupHeader(headers,
1704                                                headerNameContentLanguage,
1705                                                contentLanguagesString,
1706                                                true);
1707                        
1708 kumpf            1.105                     contentLanguages.clear();
1709 kumpf            1.98                      if (found == true && contentLanguagesString.size() > 0)
1710                                            {
1711                                                try
1712                                                {
1713 kumpf            1.105                             contentLanguages =
1714                                                        LanguageParser::parseContentLanguageHeader(
1715                                                            contentLanguagesString);
1716 kumpf            1.98                          }
1717 kumpf            1.123                         catch (...)
1718 kumpf            1.98                          {
1719 marek            1.131                             PEG_TRACE((TRC_HTTP, Tracer::LEVEL2,
1720 kumpf            1.122                                 "HTTPConnection: ERROR: contentLanguages had "
1721                                                            "parsing failure. clearing languages. "
1722                                                            "error data=%s",
1723                                                        (const char *)contentLanguagesString.
1724 marek            1.131                                     getCString()));
1725 kumpf            1.105                             contentLanguages.clear();
1726 kumpf            1.98                          }
1727                                            }
1728                        
1729                                        } // else not a cim error
1730                                    } // if optional trailer present
1731                        
1732                                    char *chunkBodyTerminatorStart =
1733                                        messageStart + _transferEncodingChunkOffset;
1734                        
1735                                    // look for chunk body terminator
1736                                    if (remainderLength != chunkBodyTerminatorLength ||
1737                                        strncmp(chunkBodyTerminatorStart, chunkBodyTerminator,
1738                                            chunkBodyTerminatorLength) != 0)
1739                                        _throwEventFailure(HTTP_STATUS_BADREQUEST,
1740                                            "No chunk body terminator received");
1741                        
1742                                    // else the remainder is just the terminator, which we will leave
1743                                    // on the incoming buffer and pass up
1744                                    // (as if a non-transfer message arrived)
1745 brian.campbell   1.72  
1746 kumpf            1.98              _transferEncodingChunkOffset = 0;
1747                                    _contentLength = messageLength - headerLength;
1748 brian.campbell   1.72  
1749 kumpf            1.98              if (httpStatusCode != HTTP_STATUSCODE_OK)
1750                                    {
1751                                        _handleReadEventFailure(httpStatus, cimErrorValue);
1752                                    }
1753                                    else if (cimStatusCode != CIM_ERR_SUCCESS)
1754                                    {
1755 kumpf            1.122                 // discard the XML payload data (body) according to cim
1756                                        // operations spec and add code and description to the
1757                                        // header so the next layer can interpret the error correctly
1758 kumpf            1.98  
1759                                        _incomingBuffer.remove(headerLength, _contentLength);
1760                                        // remove the header line terminator
1761 kumpf            1.122                 _incomingBuffer.remove(
1762                                            headerLength - headerLineTerminatorLength,
1763 kumpf            1.98                      headerLineTerminatorLength);
1764                                        // append new status
1765 kumpf            1.122                 _incomingBuffer.append(
1766                                            httpStatus.getCString(), httpStatus.size());
1767 kumpf            1.98  
1768 kumpf            1.122                 _incomingBuffer.append(
1769                                            headerLineTerminator, headerLineTerminatorLength);
1770                                        // null terminate - the buffer is at least as long after
1771                                        // removing
1772 kumpf            1.98                  char *data = (char *)_incomingBuffer.getData();
1773                                        data[_incomingBuffer.size()] = 0;
1774                                        _contentLength = 0;
1775                                        _contentOffset = 0;
1776                                    }
1777 brian.campbell   1.72  
1778 kumpf            1.98              break;
1779                                } // if last chunk
1780                        
1781 kumpf            1.122         // we are NOT on the last chunk! validate that the offset where the
1782                                // chunk terminator was found matches what the parsed chunk length
1783                                // claimed.
1784 kumpf            1.98  
1785                                if (strncmp(messageStart + chunkTerminatorOffset, chunkTerminator,
1786 brian.campbell   1.72                  chunkTerminatorLength) != 0)
1787 kumpf            1.98              _throwEventFailure(HTTP_STATUS_BADREQUEST, "Bad chunk terminator");
1788 brian.campbell   1.72  
1789 kumpf            1.98          // now remove the chunk terminator
1790                                _incomingBuffer.remove(chunkTerminatorOffset, chunkTerminatorLength);
1791 kumpf            1.128         messageLength = _incomingBuffer.size();
1792 kumpf            1.98          messageStart[messageLength] = 0;
1793 brian.campbell   1.72  
1794 kumpf            1.122         // jump to the start of the next chunk (which may not have been
1795                                // read yet)
1796 kumpf            1.98          _transferEncodingChunkOffset = chunkTerminatorOffset;
1797                            } // for all remaining bytes containing chunks
1798                        
1799                            PEG_METHOD_EXIT();
1800 brian.campbell   1.72  }
1801                        
1802                        /*
1803 david.dillard    1.93   * Handle a failure on the read or an HTTP error. This is NOT meant for
1804 brian.campbell   1.72   * errors found in the cim response or the trailer.
1805                         * The http status MAY have the detailed message attached to it using the
1806                         * detail delimiter.
1807                         */
1808                        
1809 kumpf            1.109 void HTTPConnection::_handleReadEventFailure(
1810                            const String& httpStatusWithDetail,
1811                            const String& cimError)
1812 brian.campbell   1.72  {
1813 kumpf            1.98      Uint32 delimiterFound = httpStatusWithDetail.find(httpDetailDelimiter);
1814                            String httpDetail;
1815 kumpf            1.109     String httpStatus = httpStatusWithDetail.subString(0, delimiterFound);
1816 brian.campbell   1.72  
1817 kumpf            1.98      if (delimiterFound != PEG_NOT_FOUND)
1818                            {
1819 kumpf            1.109         httpDetail = httpStatusWithDetail.subString(
1820                                    delimiterFound + httpDetailDelimiter.size());
1821 kumpf            1.98      }
1822 brian.campbell   1.72  
1823 marek            1.131     PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
1824 kumpf            1.109         httpStatus + httpDetailDelimiter + httpDetail +
1825                                    httpDetailDelimiter + cimError);
1826 brian.campbell   1.72  
1827 kumpf            1.98      _requestCount++;
1828 mike             1.104     Buffer message;
1829 kumpf            1.98      message = XmlWriter::formatHttpErrorRspMessage(httpStatus, cimError,
1830                                httpDetail);
1831                            HTTPMessage* httpMessage = new HTTPMessage(message);
1832                        
1833                            // this is common error code. If we are the server side, we want to send
1834                            // back the error to the client, but if we are the client side, then we
1835                            // simply want to queue up this error locally so the client app can receive
1836                            // the error. The client side's own message queue name will be the same
1837                            // as the connector name (the server would be acceptor)
1838 brian.campbell   1.72  
1839 kumpf            1.98      if (_isClient() == true)
1840                            {
1841                                httpMessage->dest = _outputMessageQueue->getQueueId();
1842 brian.campbell   1.72  
1843 kumpf            1.98          _outputMessageQueue->enqueue(httpMessage);
1844 brian.campbell   1.72  
1845 kumpf            1.98          _clearIncoming();
1846                            }
1847                            else
1848                            {
1849                                // else server side processing error - send back to client
1850 marek            1.131         PEG_TRACE((TRC_XML_IO, Tracer::LEVEL2,
1851 kumpf            1.130             "<!-- Error response: queue id: %u -->\n%s",
1852                                    getQueueId(),
1853 marek            1.131             httpMessage->message.getData()));
1854 kumpf            1.98          handleEnqueue(httpMessage);
1855                            }
1856                            _closeConnection();
1857 brian.campbell   1.72  }
1858                        
1859 mike             1.2   void HTTPConnection::_handleReadEvent()
1860                        {
1861 brian.campbell   1.72      static const char func[] = "HTTPConnection::_handleReadEvent()";
1862                            PEG_METHOD_ENTER(TRC_HTTP, func);
1863 kumpf            1.7   
1864 kumpf            1.102     if (_acceptPending)
1865                            {
1866                                PEGASUS_ASSERT(!_isClient());
1867                        
1868                                Sint32 socketAcceptStatus = _socket->accept();
1869                        
1870                                if (socketAcceptStatus < 0)
1871                                {
1872 marek            1.131             PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
1873 kumpf            1.102                 "HTTPConnection: SSL_accept() failed");
1874                                    _closeConnection();
1875                                    PEG_METHOD_EXIT();
1876                                    return;
1877                                }
1878                                else if (socketAcceptStatus == 0)
1879                                {
1880                                    // Not enough data yet to complete the SSL handshake
1881 marek            1.131             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
1882 kumpf            1.102                 "HTTPConnection: SSL_accept() pending");
1883                                    PEG_METHOD_EXIT();
1884                                    return;
1885                                }
1886                                else
1887                                {
1888                                    // Add SSL verification information to the authentication info
1889 thilo.boehm      1.117             if (_socket->isSecure())
1890                                    {
1891                        #ifndef PEGASUS_PLATFORM_ZOS_ZSERIES_IBM
1892 kumpf            1.122                 if (_socket->isPeerVerificationEnabled() &&
1893                                            _socket->isCertificateVerified())
1894                                        {
1895 sushma.fernandes 1.132                     _authInfo->setConnectionAuthenticated(true);
1896 kumpf            1.122                     _authInfo->setAuthType(
1897                                                AuthenticationInfoRep::AUTH_TYPE_SSL);
1898                                            _authInfo->setClientCertificateChain(
1899                                                _socket->getPeerCertificateChain());
1900                                        }
1901 thilo.boehm      1.117 #else
1902 kumpf            1.123                 if (_socket->isClientAuthenticated())
1903 thilo.boehm      1.117                 {
1904 sushma.fernandes 1.132                     _authInfo->setConnectionAuthenticated(true);
1905 kumpf            1.122                     _authInfo->setAuthenticatedUser(
1906                                                _socket->getAuthenticatedUser());
1907 thilo.boehm      1.117                 }
1908                        #endif
1909                                    }
1910 kumpf            1.102 
1911                                    // Go back to the select() and wait for data on the connection
1912                                    _acceptPending = false;
1913                                    PEG_METHOD_EXIT();
1914                                    return;
1915                                }
1916                            }
1917                        
1918 mike             1.2       // -- Append all data waiting on socket to incoming buffer:
1919                        
1920                            Sint32 bytesRead = 0;
1921 kumpf            1.38      Boolean incompleteSecureReadOccurred = false;
1922 brian.campbell   1.72  
1923 mike             1.2       for (;;)
1924                            {
1925 kumpf            1.133         char buffer[httpTcpBufferSize];
1926 kumpf            1.98  
1927                                Sint32 n = _socket->read(buffer, sizeof(buffer)-1);
1928                        
1929                                if (n <= 0)
1930                                {
1931 h.sterling       1.101             if (_socket->isSecure())
1932 kumpf            1.98              {
1933                                        // It is possible that SSL_read was not able to
1934                                        // read the entire SSL record.  This could happen
1935                                        // if the record was send in multiple packets
1936                                        // over the network and only some of the packets
1937                                        // are available.  Since SSL requires the entire
1938                                        // record to successfully decrypt, the SSL_read
1939                                        // operation will return "0 bytes" read.
1940                                        // Once all the bytes of the SSL record have been read,
1941                                        // SSL_read will return the entire record.
1942                                        // The following test was added to allow
1943                                        // handleReadEvent to distinguish between a
1944                                        // disconnect and partial read of an SSL record.
1945                                        //
1946 kumpf            1.122                 incompleteSecureReadOccurred =
1947                                            _socket->incompleteReadOccurred(n);
1948 kumpf            1.98              }
1949                                    break;
1950 kumpf            1.63          }
1951 david.dillard    1.93  
1952 kumpf            1.98          try
1953                                {
1954 kumpf            1.133             _incomingBuffer.reserveCapacity(_incomingBuffer.size() + n);
1955 kumpf            1.98              _incomingBuffer.append(buffer, n);
1956                                }
1957 kumpf            1.123         catch (...)
1958 kumpf            1.98          {
1959                                    static const char detailP[] =
1960                                        "Unable to append the request to the input buffer";
1961 kumpf            1.133             String httpStatus =
1962 kumpf            1.98                  HTTP_STATUS_REQUEST_TOO_LARGE + httpDetailDelimiter + detailP;
1963                                    _handleReadEventFailure(httpStatus);
1964                                    PEG_METHOD_EXIT();
1965                                    return;
1966                                }
1967 david.dillard    1.93  
1968 kumpf            1.98          bytesRead += n;
1969 gs.keenan        1.92  #if defined (PEGASUS_OS_VMS)
1970                                if (n < sizeof(buffer))
1971                                {
1972 kumpf            1.98              //
1973                                    // Read is smaller than the buffer size.
1974                                    // No more to read, continue.
1975                                    //
1976                                    break;
1977 gs.keenan        1.92          }
1978                        #endif
1979 mike             1.2       }
1980 mday             1.49  
1981 marek            1.131     PEG_TRACE((TRC_HTTP, Tracer::LEVEL4,
1982 kumpf            1.98          "Total bytesRead = %d; Bytes read this iteration = %d",
1983 marek            1.131         _incomingBuffer.size(), bytesRead));
1984 mike             1.2   
1985 brian.campbell   1.72      try
1986                            {
1987 kumpf            1.98          if (_contentOffset == -1)
1988                                    _getContentLengthAndContentOffset();
1989                                _handleReadEventTransferEncoding();
1990 brian.campbell   1.72      }
1991 kumpf            1.123     catch (Exception& e)
1992 brian.campbell   1.72      {
1993 kumpf            1.133         _handleReadEventFailure(e.getMessage());
1994 kumpf            1.98          PEG_METHOD_EXIT();
1995                                return;
1996 brian.campbell   1.72      }
1997 mike             1.2   
1998 david.dillard    1.93      // -- See if the end of the message was reached (some peers signal end of
1999 mike             1.2       // -- the message by closing the connection; others use the content length
2000                            // -- HTTP header and then there are those messages which have no bodies
2001                            // -- at all).
2002                        
2003 david.dillard    1.93      if ((bytesRead == 0 && !incompleteSecureReadOccurred) ||
2004 h.sterling       1.101         (_contentLength != -1 && _contentOffset != -1 &&
2005                                (Sint32(_incomingBuffer.size()) >= _contentLength + _contentOffset)))
2006 mike             1.2       {
2007 kumpf            1.133         // If no message was received, just close the connection
2008                                if (_incomingBuffer.size() == 0)
2009                                {
2010                                    _clearIncoming();
2011                        
2012                                    PEG_TRACE((TRC_XML_IO, Tracer::LEVEL2,
2013                                        "<!-- No request message received; connection closed: "
2014                                            "queue id: %u -->",
2015                                        getQueueId()));
2016                                    _closeConnection();
2017                        
2018                                    PEG_TRACE((TRC_HTTP, Tracer::LEVEL4,
2019                                        "_requestCount = %d", _requestCount.get()));
2020                        
2021                                    PEG_METHOD_EXIT();
2022                                    return;
2023                                }
2024                        
2025                                // A message was received, so process it.  If the connection was
2026                                // closed, we will handle that in the next iteration.
2027                        
2028 kumpf            1.98          HTTPMessage* message = new HTTPMessage(_incomingBuffer, getQueueId());
2029 a.arora          1.77          message->authInfo = _authInfo.get();
2030 kumpf            1.120         message->ipAddress = _ipAddress;
2031 kumpf            1.98          message->contentLanguages = contentLanguages;
2032 kumpf            1.133         message->dest = _outputMessageQueue->getQueueId();
2033 brian.campbell   1.85  
2034 kumpf            1.130         if (_isClient() == false)
2035                                {
2036 sushma.fernandes 1.138             PEG_TRACE((
2037                                        TRC_XML_IO, 
2038                                        Tracer::LEVEL2,
2039                                        "<!-- Request: queue id: %u -->\n%s", 
2040 kumpf            1.130                 getQueueId(),
2041 sushma.fernandes 1.138                 Tracer::getHTTPRequestMessage(
2042                                            _incomingBuffer).get()));
2043 kumpf            1.130         }
2044                        
2045 mike             1.2           //
2046 david.dillard    1.93          // increment request count
2047 mike             1.2           //
2048 kumpf            1.133         _requestCount++;
2049                                _connectionRequestCount++;
2050                                _responsePending = true;
2051                        
2052 marek            1.131         PEG_TRACE((TRC_HTTP, Tracer::LEVEL4,
2053                                    "_requestCount = %d", _requestCount.get()));
2054 david.dillard    1.93  
2055 sushma.fernandes 1.78          //
2056                                // Set the entry status to BUSY.
2057                                //
2058                                if (_isClient() == false && !_connectionClosePending)
2059                                {
2060 marek            1.131             PEG_TRACE((TRC_HTTP, Tracer::LEVEL2,
2061                                        "Now setting state to %d", _MonitorEntry::BUSY));
2062 sushma.fernandes 1.78              _monitor->setState (_entry_index, _MonitorEntry::BUSY);
2063                                    _monitor->tickle();
2064                                }
2065 kumpf            1.133 
2066 mreddy           1.124         try
2067                                {
2068                                    _outputMessageQueue->enqueue(message);
2069                                }
2070                                catch (Exception& e)
2071                                {
2072                                    String httpStatus =
2073                                        HTTP_STATUS_BADREQUEST + httpDetailDelimiter + e.getMessage();
2074                                    _handleReadEventFailure(httpStatus);
2075                                }   
2076                        
2077 kumpf            1.98          _clearIncoming();
2078 mike             1.2       }
2079 kumpf            1.7       PEG_METHOD_EXIT();
2080 mike             1.2   }
2081                        
2082                        Uint32 HTTPConnection::getRequestCount()
2083                        {
2084 kumpf            1.123     return _requestCount.get();
2085 mike             1.2   }
2086 mday             1.18  
2087 mday             1.19  Boolean HTTPConnection::run(Uint32 milliseconds)
2088                        {
2089 kumpf            1.98      Boolean handled_events = false;
2090                            int events = 0;
2091 kumpf            1.133     fd_set fdread;
2092 kumpf            1.98      struct timeval tv = { 0, 1 };
2093                            FD_ZERO(&fdread);
2094                            FD_SET(getSocket(), &fdread);
2095                            events = select(FD_SETSIZE, &fdread, NULL, NULL, &tv);
2096 mike             1.111 
2097                            if (events == PEGASUS_SOCKET_ERROR)
2098 kumpf            1.98          return false;
2099                        
2100                            if (events)
2101                            {
2102                                events = 0;
2103 kumpf            1.123         if (FD_ISSET(getSocket(), &fdread))
2104 kumpf            1.98          {
2105                                    events |= SocketMessage::READ;
2106                                    Message *msg = new SocketMessage(getSocket(), events);
2107                                    try
2108                                    {
2109                                        handleEnqueue(msg);
2110                                    }
2111 kumpf            1.123             catch (...)
2112 kumpf            1.98              {
2113 marek            1.131                 PEG_TRACE_CSTRING(
2114 mreddy           1.124                     TRC_DISCARDED_DATA, 
2115                                            Tracer::LEVEL2,
2116 kumpf            1.98                      "HTTPConnection::run handleEnqueue(msg) failure");
2117                                        return true;
2118                                    }
2119                                    handled_events = true;
2120                                }
2121                            }
2122 sushma.fernandes 1.78  
2123 kumpf            1.98      return handled_events;
2124 mday             1.19  }
2125 mday             1.54  
2126 mike             1.2   PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2