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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2