(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            //
 30            //%/////////////////////////////////////////////////////////////////////////////
 31            
 32            #include <Pegasus/Common/Config.h>
 33 kumpf 1.16 #include <Pegasus/Common/Constants.h>
 34 mike  1.2  
 35 kumpf 1.35 #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || defined(PEGASUS_PLATFORM_HPUX_ACC)
 36 mike  1.2  #include <Pegasus/Common/Signal.h>
 37            #endif
 38            
 39            #include <iostream>
 40            #include <cctype>
 41            #include <cstdlib>
 42            #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.2  
 50 kumpf 1.15 
 51 mike  1.2  PEGASUS_USING_STD;
 52            
 53            PEGASUS_NAMESPACE_BEGIN
 54            
 55            // initialize the request count
 56            
 57            AtomicInt HTTPConnection::_requestCount = 0;
 58            
 59            ////////////////////////////////////////////////////////////////////////////////
 60            //
 61            // Local routines:
 62            //
 63            ////////////////////////////////////////////////////////////////////////////////
 64            
 65            static inline Uint32 _Min(Uint32 x, Uint32 y) 
 66            {
 67                return x < y ? x : y; 
 68            }
 69            
 70            static char* _FindSeparator(const char* data, Uint32 size)
 71            {
 72 mike  1.2      const char* p = data;
 73                const char* end = p + size;
 74            
 75                while (p != end)
 76                {
 77            	if (*p == '\r')
 78            	{
 79            	    Uint32 n = end - p;
 80            
 81            	    if (n >= 2 && p[1] == '\n')
 82            		return (char*)p;
 83            	}
 84            	else if (*p == '\n')
 85            	    return (char*)p;
 86            
 87            	p++;
 88                }
 89            
 90                return 0;
 91            }
 92            
 93 mike  1.2  ////////////////////////////////////////////////////////////////////////////////
 94            //
 95            // HTTPConnection
 96            //
 97            ////////////////////////////////////////////////////////////////////////////////
 98            
 99            HTTPConnection::HTTPConnection(
100                Monitor* monitor,
101                //Sint32 socket, 
102                MP_Socket* socket, 
103 mday  1.19     MessageQueue* ownerMessageQueue,
104                MessageQueue* outputMessageQueue)
105 mike  1.2      : 
106 kumpf 1.16    Base(PEGASUS_QUEUENAME_HTTPCONNECTION), 
107 mday  1.4     _monitor(monitor),
108               _socket(socket), 
109               _ownerMessageQueue(ownerMessageQueue),
110               _outputMessageQueue(outputMessageQueue),
111               _contentOffset(-1),
112               _contentLength(-1)
113 mike  1.2  {
114 kumpf 1.7     PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::HTTPConnection");
115            
116 mday  1.4     //Socket::disableBlocking(_socket);
117               _socket->disableBlocking();
118 kumpf 1.12    _authInfo = new AuthenticationInfo(true);
119 kumpf 1.7  
120               PEG_METHOD_EXIT();
121 mike  1.2  }
122            
123            HTTPConnection::~HTTPConnection()
124            {
125 kumpf 1.7     PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::~HTTPConnection");
126            
127 mike  1.2      _socket->close();
128                delete _socket;
129                delete _authInfo;
130 kumpf 1.7  
131               PEG_METHOD_EXIT();
132 mike  1.2  }
133            
134 mday  1.5  
135            void HTTPConnection::handleEnqueue(Message *message)
136 mike  1.2  {
137 kumpf 1.7     PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::handleEnqueue");
138            
139 mday  1.19    if( ! message || _dying.value() > 0 )
140 kumpf 1.7     {
141                  PEG_METHOD_EXIT();
142 mday  1.5        return;
143 kumpf 1.7     }
144 mday  1.18 
145 mday  1.5     
146 mday  1.11 // #ifdef ENABLETIMEOUTWORKAROUNDHACK
147            // << Wed Mar  6 12:30:38 2002 mdd >>
148 mday  1.24    static Mutex handleEnqueue_mut = Mutex();
149               Boolean LockAcquired = false;
150 mday  1.11 // #endif
151 kumpf 1.3  
152 mike  1.2  
153 mday  1.11 // #ifdef ENABLETIMEOUTWORKAROUNDHACK
154            // << Wed Mar  6 12:30:48 2002 mdd >>
155 mday  1.24   if (pegasus_thread_self() != handleEnqueue_mut.get_owner())
156              {
157                 handleEnqueue_mut.lock(pegasus_thread_self());
158                 LockAcquired = true;
159              }
160 mday  1.11 // #endif
161 kumpf 1.3  
162 mday  1.5     switch (message->getType())
163               {
164                  case SOCKET_MESSAGE:
165                  {
166 mday  1.18 
167 kumpf 1.14          Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
168 kumpf 1.7              "HTTPConnection::handleEnqueue - SOCKET_MESSAGE");
169 mday  1.18 	 
170 mday  1.5  	 SocketMessage* socketMessage = (SocketMessage*)message;
171 mike  1.2  
172 mday  1.5  	 if (socketMessage->events & SocketMessage::READ)
173            	    _handleReadEvent();
174 mike  1.2  
175 mday  1.5  	 break;
176                  }
177 mike  1.2  
178 mday  1.5        case HTTP_MESSAGE:
179                  {
180 kumpf 1.14          Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
181 kumpf 1.7              "HTTPConnection::handleEnqueue - HTTP_MESSAGE");
182 mday  1.18 	 
183 mday  1.5  	 HTTPMessage* httpMessage = (HTTPMessage*)message;
184 mike  1.2  
185 mday  1.5  	 // ATTN: convert over to asynchronous write scheme:
186 mike  1.2  
187 mday  1.5  	 // Send response message to the client (use synchronous I/O for now:
188 mike  1.2  
189 kumpf 1.22 #ifdef LOCK_CONNECTION_ENABLED
190 mday  1.29 //          lock_connection();
191 kumpf 1.22 #endif
192 mday  1.5  	 _socket->enableBlocking();
193 mike  1.2  
194 mday  1.5  	 const Array<Sint8>& buffer = httpMessage->message;
195            	 const Uint32 CHUNK_SIZE = 16 * 1024;
196 mike  1.2  
197 kumpf 1.35 #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || defined(PEGASUS_PLATFORM_HPUX_ACC)
198 mday  1.5  	 SignalHandler::ignore(SIGPIPE);
199 mike  1.2  
200 mday  1.5  	 //getSigHandle()->registerHandler(SIGSEGV,sig_act);
201            	 //getSigHandle()->activate(SIGSEGV);
202            	 // use the next two lines to test the SIGSEGV handler
203            	 //Thread t(::segmentation_faulter,NULL,false);
204            	 //t.run();
205 mike  1.2  #endif
206 kumpf 1.22 
207                     Uint32 totalBytesWritten = 0;
208 mday  1.5  	 for (Uint32 bytesRemaining = buffer.size(); bytesRemaining > 0; )
209            	 {
210            	    Uint32 bytesToWrite = _Min(bytesRemaining, CHUNK_SIZE);
211            
212            	    Sint32 bytesWritten = _socket->write(
213            	       buffer.getData() + buffer.size() - bytesRemaining, 
214            	       bytesToWrite);
215            
216            	    if (bytesWritten < 0)
217            	       break;
218            	    //throw ConnectionBroken();
219            
220 kumpf 1.22             totalBytesWritten += bytesWritten;
221 mday  1.5  	    bytesRemaining -= bytesWritten;
222            	 }
223            	 //
224            	 // decrement request count
225            	 //
226            	 _requestCount--;
227 kumpf 1.22 	 _socket->disableBlocking();
228            
229            #ifdef LOCK_CONNECTION_ENABLED
230 mday  1.29 //          unlock_connection();
231 kumpf 1.22 #endif
232 kumpf 1.7           Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
233 kumpf 1.22             "Total bytes written = %d; Buffer Size = %d; _requestCount = %d",
234                         totalBytesWritten,  buffer.size(), _requestCount.value());
235 mday  1.5  
236            	 break;
237                  }
238            
239                  default:
240            	 // ATTN: need unexpected message error!
241            	 break;
242 mday  1.19    }
243 mike  1.2  
244 mday  1.5     delete message;
245 kumpf 1.3  
246 mday  1.11 // #ifdef ENABLETIMEOUTWORKAROUNDHACK
247            // << Wed Mar  6 12:31:03 2002 mdd >>
248 mday  1.24    if (LockAcquired)
249               {
250                  handleEnqueue_mut.unlock();
251               }
252 mday  1.11 // #endif
253 kumpf 1.7     PEG_METHOD_EXIT();
254 mday  1.5  }
255            
256            
257            void HTTPConnection::handleEnqueue()
258            {
259               Message* message = dequeue();
260            
261                if (!message)
262                    return;
263                handleEnqueue(message);
264 mike  1.2  }
265            
266            Boolean _IsBodylessMessage(const char* line)
267            {
268                //ATTN: Make sure this is the right place to check for HTTP/1.1 and
269                //      HTTP/1.0 that is part of the authentication challenge header.
270 kumpf 1.9      // ATTN-RK-P2-20020305: How do we make sure we have the complete list?
271 mike  1.2      const char* METHOD_NAMES[] =
272                {
273                    "GET",
274 kumpf 1.9          "HTTP/1.1 400",
275                    "HTTP/1.0 400",
276 mike  1.2          "HTTP/1.1 401",
277 kumpf 1.10         "HTTP/1.0 401",
278                    "HTTP/1.1 501",
279                    "HTTP/1.0 501"
280 mike  1.2      };
281            
282                const Uint32 METHOD_NAMES_SIZE = sizeof(METHOD_NAMES) / sizeof(char*);
283            
284                for (Uint32 i = 0; i < METHOD_NAMES_SIZE; i++)
285                {
286            	Uint32 n = strlen(METHOD_NAMES[i]);
287            
288            	if (strncmp(line, METHOD_NAMES[i], n) == 0 && isspace(line[n]))
289            	    return true;
290                }
291            
292                return false;
293            }
294            
295            void HTTPConnection::_getContentLengthAndContentOffset()
296            {
297                char* data = (char*)_incomingBuffer.getData();
298                Uint32 size = _incomingBuffer.size();
299                char* line = (char*)data;
300                char* sep;
301 mike  1.2      Uint32 lineNum = 0;
302                Boolean bodylessMessage = false;
303            
304                while ((sep = _FindSeparator(line, size - (line - data))))
305                {
306            	char save = *sep;
307            	*sep = '\0';
308            
309            	// Did we find the double separator which terminates the headers?
310            
311            	if (line == sep)
312            	{
313            	    *sep = save;
314            	    line = sep + ((save == '\r') ? 2 : 1);
315            	    _contentOffset = line - _incomingBuffer.getData();
316            	    break;
317            	}
318            
319            	// If this is one of the bodyless methods, then we can assume the
320            	// message is complete when the "\r\n\r\n" is encountered.
321            
322 mike  1.2  	if (lineNum == 0 && _IsBodylessMessage(line))
323            	    bodylessMessage = true;
324            
325            	// Look for the content-length if not already found:
326            
327            	char* colon = strchr(line, ':');
328            
329            	if (colon)
330            	{
331            	    *colon  = '\0';
332            
333 kumpf 1.34 	    if (EqualNoCase(line, "content-length"))
334 mike  1.2  		_contentLength = atoi(colon + 1);
335            
336            	    *colon = ':';
337            	}
338            
339            	*sep = save;
340            	line = sep + ((save == '\r') ? 2 : 1);
341            	lineNum++;
342                }
343            
344                if (_contentOffset != -1 && bodylessMessage)
345            	_contentLength = 0;
346            }
347            
348            void HTTPConnection::_clearIncoming()
349            {
350                _contentOffset = -1;
351                _contentLength = -1;
352                _incomingBuffer.clear();
353            }
354            
355 mike  1.2  void HTTPConnection::_closeConnection()
356            {
357 mday  1.19    // return - don't send the close connection message. 
358               // let the monitor dispatch function do the cleanup. 
359               PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::_closeConnection");
360               _dying = 1;
361               PEG_METHOD_EXIT();
362 kumpf 1.3  
363 mday  1.19 //     Message* message= new CloseConnectionMessage(_socket->getSocket());
364            //     message->dest = _ownerMessageQueue->getQueueId();
365 mday  1.6  //    SendForget(message);
366 mday  1.19 //    _ownerMessageQueue->enqueue(message);
367 mike  1.2  }
368            
369            void HTTPConnection::_handleReadEvent()
370            {
371 kumpf 1.7      PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::_handleReadEvent");
372            
373 mike  1.2      // -- Append all data waiting on socket to incoming buffer:
374            
375 kumpf 1.22 #ifdef LOCK_CONNECTION_ENABLED
376                lock_connection();
377            #endif
378            
379 mike  1.2      Sint32 bytesRead = 0;
380                for (;;)
381                {
382            	char buffer[4096];
383                    Sint32 n = _socket->read(buffer, sizeof(buffer));
384            
385            	if (n <= 0)
386            	    break;
387            
388            	_incomingBuffer.append(buffer, n);
389            	bytesRead += n;
390                }
391 mday  1.19     Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
392 kumpf 1.7       "_socket->read bytesRead = %d", bytesRead);
393 mday  1.18    
394 mike  1.2      // -- If still waiting for beginning of content!
395            
396                if (_contentOffset == -1)
397            	_getContentLengthAndContentOffset();
398            
399                // -- See if the end of the message was reached (some peers signal end of 
400                // -- the message by closing the connection; others use the content length
401                // -- HTTP header and then there are those messages which have no bodies
402                // -- at all).
403            
404                if (bytesRead == 0 || 
405            	_contentLength != -1 && 
406            	(Sint32(_incomingBuffer.size()) >= _contentLength + _contentOffset))
407                {
408            	HTTPMessage* message = new HTTPMessage(_incomingBuffer, getQueueId());
409                    message->authInfo = _authInfo;
410            
411                    //
412                    // increment request count 
413                    //
414                    _requestCount++;
415 kumpf 1.7          Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
416                      "_requestCount = %d", _requestCount.value());
417 mday  1.6  	message->dest = _outputMessageQueue->getQueueId();
418            //	SendForget(message);
419            	
420 kumpf 1.22 #ifndef LOCK_CONNECTION_ENABLED
421 mike  1.2  	_outputMessageQueue->enqueue(message);
422 kumpf 1.22 #endif
423 mike  1.2  	_clearIncoming();
424            
425 kumpf 1.22 #ifdef LOCK_CONNECTION_ENABLED
426                    unlock_connection();
427            
428            	if (bytesRead > 0)
429                    {
430            	   _outputMessageQueue->enqueue(message);
431                    }
432                    else 
433            #else
434 mike  1.2  	if (bytesRead == 0)
435 kumpf 1.22 #endif
436 mike  1.2  	{
437 mday  1.19 	   Tracer::trace(TRC_HTTP, Tracer::LEVEL3,
438            			 "HTTPConnection::_handleReadEvent - bytesRead == 0 - Conection being closed.");
439            	   _closeConnection();
440            	   
441            	   //
442            	   // decrement request count
443            	   //
444            	   _requestCount--;
445            	   Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
446            			 "_requestCount = %d", _requestCount.value());
447            	   
448            	   PEG_METHOD_EXIT();
449            	   return;
450 mike  1.2  	}
451                }
452 kumpf 1.7      PEG_METHOD_EXIT();
453 mike  1.2  }
454            
455            Uint32 HTTPConnection::getRequestCount()
456            {
457                return(_requestCount.value());
458            }
459 mday  1.18 
460 mday  1.19 
461            Boolean HTTPConnection::run(Uint32 milliseconds)
462            {
463               if( _dying.value() > 0)
464                  return false;
465               
466 mday  1.23    Boolean handled_events = false;
467               int events = 0;
468               
469 mday  1.26    fd_set fdread; // , fdwrite;
470 mday  1.23    do 
471               {
472 mday  1.25       struct timeval tv = { 0, 1 };
473 mday  1.23       FD_ZERO(&fdread);
474                  FD_SET(getSocket(), &fdread);
475 mday  1.26       events = select(FD_SETSIZE, &fdread, NULL, NULL, &tv);
476 kumpf 1.20 #ifdef PEGASUS_OS_TYPE_WINDOWS
477 mday  1.23       if(events && events != SOCKET_ERROR && _dying.value() == 0 )
478 kumpf 1.20 #else
479 mday  1.23       if(events && events != -1 && _dying.value() == 0 )
480 kumpf 1.20 #endif
481 mday  1.19       {
482 mday  1.23 	 events = 0;
483            	 if( FD_ISSET(getSocket(), &fdread))
484            	 {
485            	    events |= SocketMessage::READ;
486 mday  1.26 	    Message *msg = new SocketMessage(getSocket(), events);
487 mday  1.30 	    try 
488            	    {
489            	       handleEnqueue(msg);
490            	    }
491            	    catch(...)
492            	    {
493            	       _monitor->_entries[_entry_index]._status = _MonitorEntry::IDLE;
494            	       return true;
495            	    }
496 mday  1.26 	    handled_events = true;
497 mday  1.23 	 }
498 mday  1.26 	 else 
499            	    break;
500 mday  1.19       }
501 mday  1.23       else
502            	 break;
503 mday  1.24    } while(events != 0 && _dying.value() == 0);
504 mday  1.30    _monitor->_entries[_entry_index]._status = _MonitorEntry::IDLE;
505 mday  1.23    return handled_events;
506 mday  1.19 }
507 mike  1.2  
508            PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2