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

   1 mike  1.2 //%/////////////////////////////////////////////////////////////////////////////
   2           //
   3 kumpf 1.27 // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,
   4 mike  1.2  // The Open Group, Tivoli Systems
   5            //
   6            // Permission is hereby granted, free of charge, to any person obtaining a copy
   7 kumpf 1.27 // of this software and associated documentation files (the "Software"), to
   8            // deal in the Software without restriction, including without limitation the
   9            // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10 mike  1.2  // sell copies of the Software, and to permit persons to whom the Software is
  11            // furnished to do so, subject to the following conditions:
  12            // 
  13 kumpf 1.27 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
  14 mike  1.2  // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
  15            // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
  16 kumpf 1.27 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  17            // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18            // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  19 mike  1.2  // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20            // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21            //
  22            //==============================================================================
  23            //
  24            // Author: Mike Brasher (mbrasher@bmc.com)
  25            //
  26            // Modified By:
  27            //         Nag Boranna, Hewlett-Packard Company(nagaraja_boranna@hp.com)
  28            //         Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com)
  29 david 1.41 //         Dave Rosckes (rosckes@us.ibm.com)
  30 mike  1.2  //
  31            //%/////////////////////////////////////////////////////////////////////////////
  32            
  33            #include <Pegasus/Common/Config.h>
  34 kumpf 1.16 #include <Pegasus/Common/Constants.h>
  35 mike  1.2  
  36            #include <iostream>
  37            #include <cctype>
  38            #include <cstdlib>
  39            #include "Socket.h"
  40            #include "TLS.h"
  41            #include "HTTPConnection.h"
  42            #include "MessageQueue.h"
  43            #include "Monitor.h"
  44            #include "HTTPMessage.h"
  45 kumpf 1.42 #include "Signal.h"
  46 kumpf 1.3  #include "Tracer.h"
  47 mike  1.2  
  48 kumpf 1.15 
  49 gerarda 1.44 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
  50              #include <Pegasus/Common/XmlWriter.h>
  51 gerarda 1.46 #include <Pegasus/Common/CIMKerberosSecurityAssociation.h>
  52 gerarda 1.44 #endif
  53              
  54              
  55 mike    1.2  PEGASUS_USING_STD;
  56              
  57              PEGASUS_NAMESPACE_BEGIN
  58              
  59 gerarda 1.44 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
  60              /**
  61                  Constant representing the Kerberos authentication challenge header.
  62              */
  63              static const String KERBEROS_CHALLENGE_HEADER = "WWW-Authenticate: Negotiate ";
  64              #endif
  65              
  66 mike    1.2  // initialize the request count
  67              
  68              AtomicInt HTTPConnection::_requestCount = 0;
  69              
  70              ////////////////////////////////////////////////////////////////////////////////
  71              //
  72              // Local routines:
  73              //
  74              ////////////////////////////////////////////////////////////////////////////////
  75              
  76              static inline Uint32 _Min(Uint32 x, Uint32 y) 
  77              {
  78                  return x < y ? x : y; 
  79              }
  80              
  81              static char* _FindSeparator(const char* data, Uint32 size)
  82              {
  83                  const char* p = data;
  84                  const char* end = p + size;
  85              
  86                  while (p != end)
  87 mike    1.2      {
  88              	if (*p == '\r')
  89              	{
  90              	    Uint32 n = end - p;
  91              
  92              	    if (n >= 2 && p[1] == '\n')
  93              		return (char*)p;
  94              	}
  95              	else if (*p == '\n')
  96              	    return (char*)p;
  97              
  98              	p++;
  99                  }
 100              
 101                  return 0;
 102              }
 103              
 104 kumpf   1.42 // Used to test signal handling
 105              void * sigabrt_generator(void * parm)
 106              {
 107                  abort();
 108                  return 0;
 109              }
 110              
 111              
 112 mike    1.2  ////////////////////////////////////////////////////////////////////////////////
 113              //
 114              // HTTPConnection
 115              //
 116              ////////////////////////////////////////////////////////////////////////////////
 117              
 118              HTTPConnection::HTTPConnection(
 119                  Monitor* monitor,
 120                  //Sint32 socket, 
 121                  MP_Socket* socket, 
 122 mday    1.19     MessageQueue* ownerMessageQueue,
 123                  MessageQueue* outputMessageQueue)
 124 mike    1.2      : 
 125 kumpf   1.16    Base(PEGASUS_QUEUENAME_HTTPCONNECTION), 
 126 mday    1.4     _monitor(monitor),
 127                 _socket(socket), 
 128                 _ownerMessageQueue(ownerMessageQueue),
 129                 _outputMessageQueue(outputMessageQueue),
 130                 _contentOffset(-1),
 131                 _contentLength(-1)
 132 mike    1.2  {
 133 kumpf   1.7     PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::HTTPConnection");
 134              
 135 mday    1.4     //Socket::disableBlocking(_socket);
 136                 _socket->disableBlocking();
 137 kumpf   1.12    _authInfo = new AuthenticationInfo(true);
 138 kumpf   1.7  
 139                 PEG_METHOD_EXIT();
 140 mike    1.2  }
 141              
 142              HTTPConnection::~HTTPConnection()
 143              {
 144 kumpf   1.7     PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::~HTTPConnection");
 145              
 146 mike    1.2      _socket->close();
 147                  delete _socket;
 148                  delete _authInfo;
 149 kumpf   1.7  
 150                 PEG_METHOD_EXIT();
 151 mike    1.2  }
 152              
 153 mday    1.5  
 154              void HTTPConnection::handleEnqueue(Message *message)
 155 mike    1.2  {
 156 kumpf   1.7     PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::handleEnqueue");
 157              
 158 mday    1.19    if( ! message || _dying.value() > 0 )
 159 kumpf   1.7     {
 160                    PEG_METHOD_EXIT();
 161 mday    1.5        return;
 162 kumpf   1.7     }
 163 mday    1.18 
 164 mday    1.5     
 165 mday    1.24    Boolean LockAcquired = false;
 166 kumpf   1.3  
 167 kumpf   1.40   if (pegasus_thread_self() != _connection_mut.get_owner())
 168 mday    1.24   {
 169 kumpf   1.40      _connection_mut.lock(pegasus_thread_self());  // Use lock_connection() ?
 170 mday    1.24      LockAcquired = true;
 171                }
 172 kumpf   1.3  
 173 mday    1.5     switch (message->getType())
 174                 {
 175                    case SOCKET_MESSAGE:
 176                    {
 177 mday    1.18 
 178 kumpf   1.14          Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
 179 kumpf   1.7              "HTTPConnection::handleEnqueue - SOCKET_MESSAGE");
 180 mday    1.18 	 
 181 mday    1.5  	 SocketMessage* socketMessage = (SocketMessage*)message;
 182 mike    1.2  
 183 mday    1.5  	 if (socketMessage->events & SocketMessage::READ)
 184              	    _handleReadEvent();
 185 mike    1.2  
 186 mday    1.5  	 break;
 187                    }
 188 mike    1.2  
 189 mday    1.5        case HTTP_MESSAGE:
 190                    {
 191 kumpf   1.14          Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
 192 kumpf   1.7              "HTTPConnection::handleEnqueue - HTTP_MESSAGE");
 193 mday    1.18 	 
 194 mday    1.5  	 HTTPMessage* httpMessage = (HTTPMessage*)message;
 195 mike    1.2  
 196 gerarda 1.44 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
 197 gerarda 1.45          // TODO::KERBEROS complete and verify code
 198 gerarda 1.44          CIMKerberosSecurityAssociation *sa = _authInfo->getSecurityAssociation();
 199 gerarda 1.45          // Determine if message came from CIMOperationResponseEncoder and Kerberos is being used.
 200                       if ((int)httpMessage->authInfo == 99 && sa)
 201 gerarda 1.44          {
 202 gerarda 1.45              char* outmessage = NULL;
 203                           Uint64   outlength = 0;
 204                           Array<Sint8> final_buffer;
 205                           final_buffer.clear();
 206                           Array<Sint8> header_buffer;
 207                           header_buffer.clear();
 208                           Array<Sint8> unwrapped_content_buffer;
 209                           unwrapped_content_buffer.clear();
 210                           if (sa->getClientAuthenticated())
 211                           { 
 212                               // TODO::KERBEROS Question - will parse be able to distinguish headers from 
 213                               //     contents when the contents is wrapped??? I am thinking we are okay
 214                               //     because the code breaks out of the loop as soon as it finds the 
 215                               //     double separator that terminates the headers.
 216                               // Parse the HTTP message:
 217                               String startLine;
 218                               Array<HTTPHeader> headers;
 219                               Uint32 contentLength;
 220                               httpMessage->parse(startLine, headers, contentLength);
 221              
 222                               for (Uint64 i = 0; i < (httpMessage->message.size()-contentLength); i++)
 223 gerarda 1.45                  {
 224                                   header_buffer.append(httpMessage->message[i]);
 225                               }
 226              
 227                               for (Uint64 i = (httpMessage->message.size()-contentLength); i < httpMessage->message.size(); i++)
 228                               {
 229                                    unwrapped_content_buffer.append(outmessage[i]);
 230 gerarda 1.44                  }
 231 gerarda 1.45 
 232                               if (sa->wrap_message((const char*)unwrapped_content_buffer.getData(),
 233                                                    (Uint64)unwrapped_content_buffer.size(),
 234                                                     outmessage,
 235                                                     outlength))
 236 gerarda 1.44                  {
 237 gerarda 1.45                          // build a bad request
 238                                       final_buffer = XmlWriter::formatHttpErrorRspMessage(HTTP_STATUS_BADREQUEST);
 239                               }
 240                           }
 241                           //  Note:  wrap_message can result in the client no longer being authenticated so the 
 242                           //  flag needs to be checked.  
 243                           if (!sa->getClientAuthenticated())
 244                           {
 245                                if (final_buffer.size() == 0)
 246                                {
 247 gerarda 1.44                       // set authenticated flag in _authInfo to not authenticated because the
 248                                    // wrap resulted in an expired token or credential.
 249                                    _authInfo->setAuthStatus(AuthenticationInfoRep::CHALLENGE_SENT);
 250                                    // build a 401 response 
 251                                    // do we need to add a token here or just restart the negotiate again???
 252                                    // authResponse.append(sa->getServerToken());
 253 gerarda 1.45                       XmlWriter::appendUnauthorizedResponseHeader(final_buffer, KERBEROS_CHALLENGE_HEADER);
 254                                }
 255                           }
 256                           else
 257                           {
 258                                if (final_buffer.size() == 0 && outlength > 0)
 259                                {
 260                                    Array<Sint8> wrapped_content_buffer;
 261                                    wrapped_content_buffer.clear();
 262                                    for (Uint64 i = 0; i < outlength; i++)
 263                                    {
 264                                        wrapped_content_buffer.append(outmessage[i]);
 265                                    }
 266                                    final_buffer.appendArray(header_buffer);
 267                                    final_buffer.appendArray(wrapped_content_buffer);
 268                                }
 269                           }
 270              
 271                           if (outmessage)
 272                               delete [] outmessage;  // outmessage is no longer needed
 273              
 274 gerarda 1.45              if (final_buffer.size())
 275                           {
 276                               httpMessage->message.clear();
 277                               httpMessage->message = final_buffer;
 278                           }
 279 gerarda 1.44          }
 280              #endif
 281              
 282 mday    1.5  	 // ATTN: convert over to asynchronous write scheme:
 283 mike    1.2  
 284 mday    1.5  	 // Send response message to the client (use synchronous I/O for now:
 285 mike    1.2  
 286 mday    1.49 
 287 mike    1.2  
 288 mday    1.5  	 const Array<Sint8>& buffer = httpMessage->message;
 289 gerarda 1.45  
 290 mday    1.5  	 const Uint32 CHUNK_SIZE = 16 * 1024;
 291 mike    1.2  
 292 kumpf   1.42 	 SignalHandler::ignore(PEGASUS_SIGPIPE);
 293 mike    1.2  
 294 kumpf   1.42 	 // use the next four lines to test the SIGABRT handler
 295              	 //getSigHandle()->registerHandler(PEGASUS_SIGABRT, sig_act);
 296              	 //getSigHandle()->activate(PEGASUS_SIGABRT);
 297              	 //Thread t(sigabrt_generator, NULL, false);
 298 mday    1.5  	 //t.run();
 299 kumpf   1.22 
 300                       Uint32 totalBytesWritten = 0;
 301 mday    1.5  	 for (Uint32 bytesRemaining = buffer.size(); bytesRemaining > 0; )
 302              	 {
 303              	    Uint32 bytesToWrite = _Min(bytesRemaining, CHUNK_SIZE);
 304              
 305              	    Sint32 bytesWritten = _socket->write(
 306              	       buffer.getData() + buffer.size() - bytesRemaining, 
 307              	       bytesToWrite);
 308              
 309              	    if (bytesWritten < 0)
 310              	       break;
 311              	    //throw ConnectionBroken();
 312              
 313 kumpf   1.22             totalBytesWritten += bytesWritten;
 314 mday    1.5  	    bytesRemaining -= bytesWritten;
 315              	 }
 316              	 //
 317              	 // decrement request count
 318              	 //
 319              	 _requestCount--;
 320 kumpf   1.22 	 _socket->disableBlocking();
 321              
 322 kumpf   1.7           Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
 323 kumpf   1.22             "Total bytes written = %d; Buffer Size = %d; _requestCount = %d",
 324                           totalBytesWritten,  buffer.size(), _requestCount.value());
 325 mday    1.5  
 326              	 break;
 327                    }
 328              
 329                    default:
 330              	 // ATTN: need unexpected message error!
 331              	 break;
 332 mday    1.19    }
 333 mike    1.2  
 334 mday    1.5     delete message;
 335 kumpf   1.3  
 336 mday    1.24    if (LockAcquired)
 337                 {
 338 kumpf   1.40       _connection_mut.unlock();  // Use unlock_connection() ?
 339 mday    1.24    }
 340 kumpf   1.7     PEG_METHOD_EXIT();
 341 mday    1.5  }
 342              
 343              
 344              void HTTPConnection::handleEnqueue()
 345              {
 346                 Message* message = dequeue();
 347              
 348                  if (!message)
 349                      return;
 350                  handleEnqueue(message);
 351 mike    1.2  }
 352              
 353              Boolean _IsBodylessMessage(const char* line)
 354              {
 355                  //ATTN: Make sure this is the right place to check for HTTP/1.1 and
 356                  //      HTTP/1.0 that is part of the authentication challenge header.
 357 kumpf   1.9      // ATTN-RK-P2-20020305: How do we make sure we have the complete list?
 358 mike    1.2      const char* METHOD_NAMES[] =
 359                  {
 360                      "GET",
 361 kumpf   1.9          "HTTP/1.1 400",
 362                      "HTTP/1.0 400",
 363 mike    1.2          "HTTP/1.1 401",
 364 kumpf   1.10         "HTTP/1.0 401",
 365                      "HTTP/1.1 501",
 366                      "HTTP/1.0 501"
 367 mike    1.2      };
 368              
 369                  const Uint32 METHOD_NAMES_SIZE = sizeof(METHOD_NAMES) / sizeof(char*);
 370              
 371                  for (Uint32 i = 0; i < METHOD_NAMES_SIZE; i++)
 372                  {
 373              	Uint32 n = strlen(METHOD_NAMES[i]);
 374              
 375              	if (strncmp(line, METHOD_NAMES[i], n) == 0 && isspace(line[n]))
 376              	    return true;
 377                  }
 378              
 379                  return false;
 380              }
 381              
 382              void HTTPConnection::_getContentLengthAndContentOffset()
 383              {
 384                  char* data = (char*)_incomingBuffer.getData();
 385                  Uint32 size = _incomingBuffer.size();
 386                  char* line = (char*)data;
 387                  char* sep;
 388 mike    1.2      Uint32 lineNum = 0;
 389                  Boolean bodylessMessage = false;
 390              
 391                  while ((sep = _FindSeparator(line, size - (line - data))))
 392                  {
 393              	char save = *sep;
 394              	*sep = '\0';
 395              
 396              	// Did we find the double separator which terminates the headers?
 397              
 398              	if (line == sep)
 399              	{
 400              	    *sep = save;
 401              	    line = sep + ((save == '\r') ? 2 : 1);
 402              	    _contentOffset = line - _incomingBuffer.getData();
 403              	    break;
 404              	}
 405              
 406              	// If this is one of the bodyless methods, then we can assume the
 407              	// message is complete when the "\r\n\r\n" is encountered.
 408              
 409 mike    1.2  	if (lineNum == 0 && _IsBodylessMessage(line))
 410              	    bodylessMessage = true;
 411              
 412              	// Look for the content-length if not already found:
 413              
 414              	char* colon = strchr(line, ':');
 415              
 416              	if (colon)
 417              	{
 418              	    *colon  = '\0';
 419              
 420 kumpf   1.37 	    if (System::strcasecmp(line, "content-length") == 0)
 421 mike    1.2  		_contentLength = atoi(colon + 1);
 422              
 423              	    *colon = ':';
 424              	}
 425              
 426              	*sep = save;
 427              	line = sep + ((save == '\r') ? 2 : 1);
 428              	lineNum++;
 429                  }
 430              
 431                  if (_contentOffset != -1 && bodylessMessage)
 432              	_contentLength = 0;
 433              }
 434              
 435              void HTTPConnection::_clearIncoming()
 436              {
 437                  _contentOffset = -1;
 438                  _contentLength = -1;
 439                  _incomingBuffer.clear();
 440              }
 441              
 442 mike    1.2  void HTTPConnection::_closeConnection()
 443              {
 444 mday    1.19    // return - don't send the close connection message. 
 445                 // let the monitor dispatch function do the cleanup. 
 446                 PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::_closeConnection");
 447                 _dying = 1;
 448                 PEG_METHOD_EXIT();
 449 kumpf   1.3  
 450 mday    1.19 //     Message* message= new CloseConnectionMessage(_socket->getSocket());
 451              //     message->dest = _ownerMessageQueue->getQueueId();
 452 mday    1.6  //    SendForget(message);
 453 mday    1.19 //    _ownerMessageQueue->enqueue(message);
 454 mike    1.2  }
 455              
 456              void HTTPConnection::_handleReadEvent()
 457              {
 458 kumpf   1.7      PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::_handleReadEvent");
 459              
 460 mike    1.2      // -- Append all data waiting on socket to incoming buffer:
 461              
 462 kumpf   1.22 #ifdef LOCK_CONNECTION_ENABLED
 463                  lock_connection();
 464              #endif
 465              
 466 mday    1.49 
 467                  
 468 mike    1.2      Sint32 bytesRead = 0;
 469 kumpf   1.38     Boolean incompleteSecureReadOccurred = false;
 470 mike    1.2      for (;;)
 471                  {
 472              	char buffer[4096];
 473                      Sint32 n = _socket->read(buffer, sizeof(buffer));
 474              
 475              	if (n <= 0)
 476 kumpf   1.38 	{
 477              	    if (_socket->isSecure() && bytesRead == 0)
 478                          {
 479              	       // It is possible that SSL_read was not able to 
 480              	       // read the entire SSL record.  This could happen
 481              	       // if the record was send in multiple packets
 482              	       // over the network and only some of the packets
 483              	       // are available.  Since SSL requires the entire
 484              	       // record to successfully decrypt, the SSL_read
 485              	       // operation will return "0 bytes" read.
 486              	       // Once all the bytes of the SSL record have been read,
 487              	       // SSL_read will return the entire record.
 488              	       // The following test was added to allow
 489              	       // handleReadEvent to distinguish between a 
 490              	       // disconnect and partial read of an SSL record.
 491              	       //
 492                             incompleteSecureReadOccurred = !_socket->incompleteReadOccurred(n);
 493                          }
 494 chuck   1.43 
 495 mike    1.2  	    break;
 496 kumpf   1.38 	}
 497 mike    1.2  
 498              	_incomingBuffer.append(buffer, n);
 499              	bytesRead += n;
 500                  }
 501 mday    1.49 
 502                  
 503 mday    1.19     Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
 504 kumpf   1.7       "_socket->read bytesRead = %d", bytesRead);
 505 mday    1.18    
 506 mike    1.2      // -- If still waiting for beginning of content!
 507              
 508                  if (_contentOffset == -1)
 509              	_getContentLengthAndContentOffset();
 510              
 511                  // -- See if the end of the message was reached (some peers signal end of 
 512                  // -- the message by closing the connection; others use the content length
 513                  // -- HTTP header and then there are those messages which have no bodies
 514                  // -- at all).
 515              
 516 kumpf   1.38     if ((bytesRead == 0 && !incompleteSecureReadOccurred) ||  
 517 mike    1.2  	_contentLength != -1 && 
 518              	(Sint32(_incomingBuffer.size()) >= _contentLength + _contentOffset))
 519                  {
 520              	HTTPMessage* message = new HTTPMessage(_incomingBuffer, getQueueId());
 521                      message->authInfo = _authInfo;
 522              
 523                      //
 524                      // increment request count 
 525                      //
 526                      _requestCount++;
 527 kumpf   1.7          Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
 528                        "_requestCount = %d", _requestCount.value());
 529 mday    1.6  	message->dest = _outputMessageQueue->getQueueId();
 530              //	SendForget(message);
 531              	
 532 kumpf   1.22 #ifndef LOCK_CONNECTION_ENABLED
 533 mike    1.2  	_outputMessageQueue->enqueue(message);
 534 kumpf   1.22 #endif
 535 mike    1.2  	_clearIncoming();
 536              
 537 kumpf   1.22 #ifdef LOCK_CONNECTION_ENABLED
 538                      unlock_connection();
 539              
 540              	if (bytesRead > 0)
 541                      {
 542              	   _outputMessageQueue->enqueue(message);
 543                      }
 544                      else 
 545              #else
 546 mike    1.2  	if (bytesRead == 0)
 547 kumpf   1.22 #endif
 548 mike    1.2  	{
 549 mday    1.19 	   Tracer::trace(TRC_HTTP, Tracer::LEVEL3,
 550              			 "HTTPConnection::_handleReadEvent - bytesRead == 0 - Conection being closed.");
 551              	   _closeConnection();
 552              	   
 553              	   //
 554              	   // decrement request count
 555              	   //
 556              	   _requestCount--;
 557              	   Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
 558              			 "_requestCount = %d", _requestCount.value());
 559              	   
 560              	   PEG_METHOD_EXIT();
 561              	   return;
 562 mike    1.2  	}
 563                  }
 564 kumpf   1.7      PEG_METHOD_EXIT();
 565 mike    1.2  }
 566              
 567              Uint32 HTTPConnection::getRequestCount()
 568              {
 569                  return(_requestCount.value());
 570              }
 571 mday    1.18 
 572 mday    1.19 
 573              Boolean HTTPConnection::run(Uint32 milliseconds)
 574              {
 575                 if( _dying.value() > 0)
 576                    return false;
 577                 
 578 mday    1.23    Boolean handled_events = false;
 579                 int events = 0;
 580                 
 581 mday    1.26    fd_set fdread; // , fdwrite;
 582 mday    1.23    do 
 583                 {
 584 mday    1.25       struct timeval tv = { 0, 1 };
 585 mday    1.23       FD_ZERO(&fdread);
 586                    FD_SET(getSocket(), &fdread);
 587 mday    1.26       events = select(FD_SETSIZE, &fdread, NULL, NULL, &tv);
 588 kumpf   1.20 #ifdef PEGASUS_OS_TYPE_WINDOWS
 589 mday    1.23       if(events && events != SOCKET_ERROR && _dying.value() == 0 )
 590 kumpf   1.20 #else
 591 mday    1.23       if(events && events != -1 && _dying.value() == 0 )
 592 kumpf   1.20 #endif
 593 mday    1.19       {
 594 mday    1.23 	 events = 0;
 595              	 if( FD_ISSET(getSocket(), &fdread))
 596              	 {
 597              	    events |= SocketMessage::READ;
 598 mday    1.26 	    Message *msg = new SocketMessage(getSocket(), events);
 599 mday    1.30 	    try 
 600              	    {
 601              	       handleEnqueue(msg);
 602              	    }
 603              	    catch(...)
 604              	    {
 605              	       _monitor->_entries[_entry_index]._status = _MonitorEntry::IDLE;
 606              	       return true;
 607              	    }
 608 mday    1.26 	    handled_events = true;
 609 mday    1.23 	 }
 610 mday    1.26 	 else 
 611              	    break;
 612 mday    1.19       }
 613 mday    1.23       else
 614              	 break;
 615 mday    1.24    } while(events != 0 && _dying.value() == 0);
 616 mday    1.30    _monitor->_entries[_entry_index]._status = _MonitorEntry::IDLE;
 617 mday    1.23    return handled_events;
 618 mday    1.19 }
 619 mike    1.2  
 620 mday    1.47 
 621              AtomicInt HTTPConnection2::_requestCount(0);
 622              
 623              
 624              HTTPConnection2::HTTPConnection2(pegasus_socket socket,
 625              				 MessageQueue* outputMessageQueue)
 626                  : 
 627                 Base(PEGASUS_QUEUENAME_HTTPCONNECTION), 
 628                 _socket(socket), 
 629                 _outputMessageQueue(outputMessageQueue),
 630                 _contentOffset(-1),
 631                 _contentLength(-1)
 632              {
 633                 PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection2::HTTPConnection2");
 634              
 635                 _authInfo = new AuthenticationInfo(true);
 636              
 637                 PEG_METHOD_EXIT();
 638              }
 639              
 640              HTTPConnection2::~HTTPConnection2()
 641 mday    1.47 {
 642                 PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection2::~HTTPConnection2");
 643              
 644                  delete _authInfo;
 645              
 646                 PEG_METHOD_EXIT();
 647              }
 648              
 649              
 650              void HTTPConnection2::handleEnqueue(Message *message)
 651              {
 652                 PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection2::handleEnqueue");
 653              
 654                 if( ! message || _dying.value() > 0 )
 655                 {
 656                    PEG_METHOD_EXIT();
 657                    return;
 658                 }
 659              
 660                 
 661                 Boolean LockAcquired = false;
 662 mday    1.47 
 663                if (pegasus_thread_self() != _connection_mut.get_owner())
 664                {
 665                   _connection_mut.lock(pegasus_thread_self());  // Use lock_connection() ?
 666                   LockAcquired = true;
 667                }
 668              
 669                 switch (message->getType())
 670                 {
 671                    case SOCKET_MESSAGE:
 672                    {
 673              
 674                       Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
 675                          "HTTPConnection2::handleEnqueue - SOCKET_MESSAGE");
 676              	 
 677              	 SocketMessage* socketMessage = (SocketMessage*)message;
 678              
 679 mday    1.50 // 	 if (socketMessage->events & SocketMessage::READ)
 680              // 	    _handleReadEvent();
 681 mday    1.47 
 682              	 break;
 683                    }
 684              
 685                    case HTTP_MESSAGE:
 686                    {
 687                       Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
 688                          "HTTPConnection2::handleEnqueue - HTTP_MESSAGE");
 689              	 
 690              	 HTTPMessage* httpMessage = (HTTPMessage*)message;
 691              
 692              #ifdef PEGASUS_KERBEROS_AUTHENTICATION
 693                       // TODO::KERBEROS complete and verify code
 694                       CIMKerberosSecurityAssociation *sa = _authInfo->getSecurityAssociation();
 695                       // Determine if message came from CIMOperationResponseEncoder and Kerberos is being used.
 696                       if ((int)httpMessage->authInfo == 99 && sa)
 697                       {
 698                           char* outmessage = NULL;
 699                           Uint64   outlength = 0;
 700                           Array<Sint8> final_buffer;
 701                           final_buffer.clear();
 702 mday    1.47              Array<Sint8> header_buffer;
 703                           header_buffer.clear();
 704                           Array<Sint8> unwrapped_content_buffer;
 705                           unwrapped_content_buffer.clear();
 706                           if (sa->getClientAuthenticated())
 707                           { 
 708                               // TODO::KERBEROS Question - will parse be able to distinguish headers from 
 709                               //     contents when the contents is wrapped??? I am thinking we are okay
 710                               //     because the code breaks out of the loop as soon as it finds the 
 711                               //     double separator that terminates the headers.
 712                               // Parse the HTTP message:
 713                               String startLine;
 714                               Array<HTTPHeader> headers;
 715                               Uint32 contentLength;
 716                               httpMessage->parse(startLine, headers, contentLength);
 717              
 718                               for (Uint64 i = 0; i < (httpMessage->message.size()-contentLength); i++)
 719                               {
 720                                   header_buffer.append(httpMessage->message[i]);
 721                               }
 722              
 723 mday    1.47                  for (Uint64 i = (httpMessage->message.size()-contentLength); i < httpMessage->message.size(); i++)
 724                               {
 725                                    unwrapped_content_buffer.append(outmessage[i]);
 726                               }
 727              
 728                               if (sa->wrap_message((const char*)unwrapped_content_buffer.getData(),
 729                                                    (Uint64)unwrapped_content_buffer.size(),
 730                                                     outmessage,
 731                                                     outlength))
 732                               {
 733                                       // build a bad request
 734                                       final_buffer = XmlWriter::formatHttpErrorRspMessage(HTTP_STATUS_BADREQUEST);
 735                               }
 736                           }
 737                           //  Note:  wrap_message can result in the client no longer being authenticated so the 
 738                           //  flag needs to be checked.  
 739                           if (!sa->getClientAuthenticated())
 740                           {
 741                                if (final_buffer.size() == 0)
 742                                {
 743                                    // set authenticated flag in _authInfo to not authenticated because the
 744 mday    1.47                       // wrap resulted in an expired token or credential.
 745                                    _authInfo->setAuthStatus(AuthenticationInfoRep::CHALLENGE_SENT);
 746                                    // build a 401 response 
 747                                    // do we need to add a token here or just restart the negotiate again???
 748                                    // authResponse.append(sa->getServerToken());
 749                                    XmlWriter::appendUnauthorizedResponseHeader(final_buffer, KERBEROS_CHALLENGE_HEADER);
 750                                }
 751                           }
 752                           else
 753                           {
 754                                if (final_buffer.size() == 0 && outlength > 0)
 755                                {
 756                                    Array<Sint8> wrapped_content_buffer;
 757                                    wrapped_content_buffer.clear();
 758                                    for (Uint64 i = 0; i < outlength; i++)
 759                                    {
 760                                        wrapped_content_buffer.append(outmessage[i]);
 761                                    }
 762                                    final_buffer.appendArray(header_buffer);
 763                                    final_buffer.appendArray(wrapped_content_buffer);
 764                                }
 765 mday    1.47              }
 766              
 767                           if (outmessage)
 768                               delete [] outmessage;  // outmessage is no longer needed
 769              
 770                           if (final_buffer.size())
 771                           {
 772                               httpMessage->message.clear();
 773                               httpMessage->message = final_buffer;
 774                           }
 775                       }
 776              #endif
 777              
 778              	 // ATTN: convert over to asynchronous write scheme:
 779              
 780              	 // Send response message to the client (use synchronous I/O for now:
 781              
 782              
 783              	 const Array<Sint8>& buffer = httpMessage->message;
 784               
 785              	 const Uint32 CHUNK_SIZE = 16 * 1024;
 786 mday    1.47 
 787              	 SignalHandler::ignore(PEGASUS_SIGPIPE);
 788              
 789              	 // use the next four lines to test the SIGABRT handler
 790              	 //getSigHandle()->registerHandler(PEGASUS_SIGABRT, sig_act);
 791              	 //getSigHandle()->activate(PEGASUS_SIGABRT);
 792              	 //Thread t(sigabrt_generator, NULL, false);
 793              	 //t.run();
 794              
 795                       Uint32 totalBytesWritten = 0;
 796              	 for (Uint32 bytesRemaining = buffer.size(); bytesRemaining > 0; )
 797              	 {
 798              	    Uint32 bytesToWrite = _Min(bytesRemaining, CHUNK_SIZE);
 799              
 800              	    Sint32 bytesWritten = _socket.write(
 801              	       buffer.getData() + buffer.size() - bytesRemaining, 
 802              	       bytesToWrite);
 803              
 804              	    if (bytesWritten < 0)
 805              	       break;
 806              	    //throw ConnectionBroken();
 807 mday    1.47 
 808                          totalBytesWritten += bytesWritten;
 809              	    bytesRemaining -= bytesWritten;
 810              	 }
 811              	 //
 812              	 // decrement request count
 813              	 //
 814              	 _requestCount--;
 815              
 816                       Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
 817                          "Total bytes written = %d; Buffer Size = %d; _requestCount = %d",
 818                           totalBytesWritten,  buffer.size(), _requestCount.value());
 819              
 820              	 break;
 821                    }
 822              
 823                    default:
 824              	 // ATTN: need unexpected message error!
 825              	 break;
 826                 }
 827              
 828 mday    1.47    delete message;
 829              
 830                 if (LockAcquired)
 831                 {
 832                    _connection_mut.unlock();  // Use unlock_connection() ?
 833                 }
 834                 PEG_METHOD_EXIT();
 835              }
 836              
 837              
 838              void HTTPConnection2::handleEnqueue()
 839              {
 840                 Message* message = dequeue();
 841              
 842                  if (!message)
 843                      return;
 844                  handleEnqueue(message);
 845              }
 846              
 847              void HTTPConnection2::_getContentLengthAndContentOffset()
 848              {
 849 mday    1.47     char* data = (char*)_incomingBuffer.getData();
 850                  Uint32 size = _incomingBuffer.size();
 851                  char* line = (char*)data;
 852                  char* sep;
 853                  Uint32 lineNum = 0;
 854                  Boolean bodylessMessage = false;
 855              
 856                  while ((sep = _FindSeparator(line, size - (line - data))))
 857                  {
 858              	char save = *sep;
 859              	*sep = '\0';
 860              
 861              	// Did we find the double separator which terminates the headers?
 862              
 863              	if (line == sep)
 864              	{
 865              	    *sep = save;
 866              	    line = sep + ((save == '\r') ? 2 : 1);
 867              	    _contentOffset = line - _incomingBuffer.getData();
 868              	    break;
 869              	}
 870 mday    1.47 
 871              	// If this is one of the bodyless methods, then we can assume the
 872              	// message is complete when the "\r\n\r\n" is encountered.
 873              
 874              	if (lineNum == 0 && _IsBodylessMessage(line))
 875              	    bodylessMessage = true;
 876              
 877              	// Look for the content-length if not already found:
 878              
 879              	char* colon = strchr(line, ':');
 880              
 881              	if (colon)
 882              	{
 883              	    *colon  = '\0';
 884              
 885              	    if (System::strcasecmp(line, "content-length") == 0)
 886              		_contentLength = atoi(colon + 1);
 887              
 888              	    *colon = ':';
 889              	}
 890              
 891 mday    1.47 	*sep = save;
 892              	line = sep + ((save == '\r') ? 2 : 1);
 893              	lineNum++;
 894                  }
 895              
 896                  if (_contentOffset != -1 && bodylessMessage)
 897              	_contentLength = 0;
 898              }
 899              
 900              void HTTPConnection2::_clearIncoming()
 901              {
 902                  _contentOffset = -1;
 903                  _contentLength = -1;
 904                  _incomingBuffer.clear();
 905              }
 906              
 907              void HTTPConnection2::_closeConnection()
 908              {
 909                 // return - don't send the close connection message. 
 910                 // let the monitor dispatch function do the cleanup. 
 911                 PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection2::_closeConnection");
 912 mday    1.50    
 913 mday    1.47    PEG_METHOD_EXIT();
 914              
 915              }
 916              
 917 mday    1.50 void HTTPConnection2::_handleReadEvent(monitor_2_entry* entry)
 918 mday    1.47 {
 919                  PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection2::_handleReadEvent");
 920              
 921                  // -- Append all data waiting on socket to incoming buffer:
 922              
 923              #ifdef LOCK_CONNECTION_ENABLED
 924                  lock_connection();
 925              #endif
 926 mday    1.49     _socket.disableBlocking();
 927 mday    1.47     Sint32 bytesRead = 0;
 928                  Boolean incompleteSecureReadOccurred = false;
 929                  for (;;)
 930                  {
 931              	char buffer[4096];
 932                      Sint32 n = _socket.read(buffer, sizeof(buffer));
 933              
 934              	if (n <= 0)
 935              	{
 936              	    if (_socket.is_secure() && bytesRead == 0)
 937                          {
 938              	       // It is possible that SSL_read was not able to 
 939              	       // read the entire SSL record.  This could happen
 940              	       // if the record was send in multiple packets
 941              	       // over the network and only some of the packets
 942              	       // are available.  Since SSL requires the entire
 943              	       // record to successfully decrypt, the SSL_read
 944              	       // operation will return "0 bytes" read.
 945              	       // Once all the bytes of the SSL record have been read,
 946              	       // SSL_read will return the entire record.
 947              	       // The following test was added to allow
 948 mday    1.47 	       // handleReadEvent to distinguish between a 
 949              	       // disconnect and partial read of an SSL record.
 950              	       //
 951                             incompleteSecureReadOccurred = !_socket.incompleteReadOccurred(n);
 952                          }
 953              
 954              	    break;
 955              	}
 956              
 957              	_incomingBuffer.append(buffer, n);
 958              	bytesRead += n;
 959                  }
 960 mday    1.49     _socket.enableBlocking();
 961 mday    1.47     Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
 962                   "_socket.read bytesRead = %d", bytesRead);
 963                 
 964                  // -- If still waiting for beginning of content!
 965              
 966                  if (_contentOffset == -1)
 967              	_getContentLengthAndContentOffset();
 968              
 969                  // -- See if the end of the message was reached (some peers signal end of 
 970                  // -- the message by closing the connection; others use the content length
 971                  // -- HTTP header and then there are those messages which have no bodies
 972                  // -- at all).
 973              
 974                  if ((bytesRead == 0 && !incompleteSecureReadOccurred) ||  
 975              	_contentLength != -1 && 
 976              	(Sint32(_incomingBuffer.size()) >= _contentLength + _contentOffset))
 977                  {
 978              	HTTPMessage* message = new HTTPMessage(_incomingBuffer, getQueueId());
 979                      message->authInfo = _authInfo;
 980              
 981                      //
 982 mday    1.47         // increment request count 
 983                      //
 984                      _requestCount++;
 985                      Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
 986                        "_requestCount = %d", _requestCount.value());
 987              	message->dest = _outputMessageQueue->getQueueId();
 988              //	SendForget(message);
 989              	
 990              #ifndef LOCK_CONNECTION_ENABLED
 991              	_outputMessageQueue->enqueue(message);
 992              #endif
 993              	_clearIncoming();
 994              
 995              #ifdef LOCK_CONNECTION_ENABLED
 996                      unlock_connection();
 997              
 998              	if (bytesRead > 0)
 999                      {
1000              	   _outputMessageQueue->enqueue(message);
1001                      }
1002                      else 
1003 mday    1.47 #else
1004              	if (bytesRead == 0)
1005              #endif
1006              	{
1007              	   Tracer::trace(TRC_HTTP, Tracer::LEVEL3,
1008              			 "HTTPConnection2::_handleReadEvent - bytesRead == 0 - Conection being closed.");
1009              	   _closeConnection();
1010 mday    1.50 	   entry->set_state(CLOSED);
1011 mday    1.47 	   
1012              	   //
1013              	   // decrement request count
1014              	   //
1015              	   _requestCount--;
1016              	   Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
1017              			 "_requestCount = %d", _requestCount.value());
1018              	   
1019              	   PEG_METHOD_EXIT();
1020              	   return;
1021              	}
1022                  }
1023                  PEG_METHOD_EXIT();
1024              }
1025              
1026              Uint32 HTTPConnection2::getRequestCount()
1027              {
1028                  return(_requestCount.value());
1029              }
1030              
1031              
1032 mday    1.47 Boolean HTTPConnection2::operator ==(const HTTPConnection2& h2)
1033              {
1034                if(this == &h2)
1035                  return true;
1036                return false;
1037              }
1038              
1039              Boolean HTTPConnection2::operator ==(void* h2)
1040              {
1041                if((void *)this == h2)
1042                  return true;
1043                return false;
1044              }
1045              
1046              
1047 mday    1.48 void HTTPConnection2::connection_dispatch(monitor_2_entry* entry)
1048              {
1049                HTTPConnection2* myself = (HTTPConnection2*) entry->get_dispatch();
1050                myself->_socket = entry->get_sock();
1051 mday    1.50   myself->_handleReadEvent(entry);
1052 mday    1.48 }
1053              
1054              
1055 mike    1.2  PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2