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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2