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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2