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

  1 mike  1.2 //%/////////////////////////////////////////////////////////////////////////////
  2           //
  3           // Copyright (c) 2000, 2001 BMC Software, Hewlett-Packard Company, IBM, 
  4           // The Open Group, Tivoli Systems
  5           //
  6           // Permission is hereby granted, free of charge, to any person obtaining a copy
  7           // 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           // 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           // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN 
 14           // 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           // 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           // 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 mike  1.2 //==============================================================================
 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           
 34           #ifdef PEGASUS_PLATFORM_LINUX_IX86_GNU
 35           #include <Pegasus/Common/Signal.h>
 36           #endif
 37           
 38           #include <iostream>
 39           #include <cctype>
 40           #include <cassert>
 41           #include <cstdlib>
 42           #include "Socket.h"
 43 mike  1.2 #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           PEGASUS_USING_STD;
 51           
 52           PEGASUS_NAMESPACE_BEGIN
 53           
 54           // initialize the request count
 55           
 56           AtomicInt HTTPConnection::_requestCount = 0;
 57           
 58           ////////////////////////////////////////////////////////////////////////////////
 59           //
 60           // Local routines:
 61           //
 62           ////////////////////////////////////////////////////////////////////////////////
 63           
 64           static inline Uint32 _Min(Uint32 x, Uint32 y) 
 65           {
 66               return x < y ? x : y; 
 67           }
 68           
 69           static char* _FindSeparator(const char* data, Uint32 size)
 70 mike  1.2 {
 71               const char* p = data;
 72               const char* end = p + size;
 73           
 74               while (p != end)
 75               {
 76           	if (*p == '\r')
 77           	{
 78           	    Uint32 n = end - p;
 79           
 80           	    if (n >= 2 && p[1] == '\n')
 81           		return (char*)p;
 82           	}
 83           	else if (*p == '\n')
 84           	    return (char*)p;
 85           
 86           	p++;
 87               }
 88           
 89               return 0;
 90           }
 91 mike  1.2 
 92           ////////////////////////////////////////////////////////////////////////////////
 93           //
 94           // HTTPConnection
 95           //
 96           ////////////////////////////////////////////////////////////////////////////////
 97           
 98           HTTPConnection::HTTPConnection(
 99               Monitor* monitor,
100               //Sint32 socket, 
101               MP_Socket* socket, 
102 mday  1.6     MessageQueueService* ownerMessageQueue,
103               MessageQueueService* outputMessageQueue)
104 mike  1.2     : 
105 mday  1.6    Base("HTTPConnection", MessageQueue::getNextQueueId()), 
106 mday  1.4    _monitor(monitor),
107              _socket(socket), 
108              _ownerMessageQueue(ownerMessageQueue),
109              _outputMessageQueue(outputMessageQueue),
110              _contentOffset(-1),
111              _contentLength(-1)
112 mike  1.2 {
113 kumpf 1.7    PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::HTTPConnection");
114           
115 mday  1.4    //Socket::disableBlocking(_socket);
116              _socket->disableBlocking();
117              _authInfo = new AuthenticationInfo();
118 kumpf 1.7 
119              PEG_METHOD_EXIT();
120 mike  1.2 }
121           
122           HTTPConnection::~HTTPConnection()
123           {
124 kumpf 1.7    PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::~HTTPConnection");
125           
126 mike  1.2     _socket->close();
127               delete _socket;
128               delete _authInfo;
129 kumpf 1.7 
130              PEG_METHOD_EXIT();
131 mike  1.2 }
132           
133 mday  1.5 
134           void HTTPConnection::handleEnqueue(Message *message)
135 mike  1.2 {
136 kumpf 1.7    PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::handleEnqueue");
137           
138              if( ! message)
139              {
140                 PEG_METHOD_EXIT();
141 mday  1.5       return;
142 kumpf 1.7    }
143 mday  1.5    
144 kumpf 1.3 #ifdef ENABLETIMEOUTWORKAROUNDHACK
145 mday  1.5    static Mutex handleEnqueue_mut = Mutex();
146 kumpf 1.3 #endif
147           
148 mike  1.2 
149 kumpf 1.3 #ifdef ENABLETIMEOUTWORKAROUNDHACK
150 mday  1.5    handleEnqueue_mut.lock(pegasus_thread_self());
151 kumpf 1.3 #endif
152           
153 mday  1.5    switch (message->getType())
154              {
155                 case SOCKET_MESSAGE:
156                 {
157 kumpf 1.7          Tracer::trace(TRC_HTTP, Tracer::LEVEL3,
158                       "HTTPConnection::handleEnqueue - SOCKET_MESSAGE");
159           
160 mday  1.5 	 SocketMessage* socketMessage = (SocketMessage*)message;
161 mike  1.2 
162 mday  1.5 	 if (socketMessage->events & SocketMessage::READ)
163           	    _handleReadEvent();
164 mike  1.2 
165 mday  1.5 	 break;
166                 }
167 mike  1.2 
168 mday  1.5       case HTTP_MESSAGE:
169                 {
170 kumpf 1.7          Tracer::trace(TRC_HTTP, Tracer::LEVEL3,
171                       "HTTPConnection::handleEnqueue - HTTP_MESSAGE");
172           
173 mday  1.5 	 HTTPMessage* httpMessage = (HTTPMessage*)message;
174 mike  1.2 
175 mday  1.5 	 // ATTN: convert over to asynchronous write scheme:
176 mike  1.2 
177 mday  1.5 	 // Send response message to the client (use synchronous I/O for now:
178 mike  1.2 
179 mday  1.5 	 _socket->enableBlocking();
180 mike  1.2 
181 mday  1.5 	 const Array<Sint8>& buffer = httpMessage->message;
182           	 const Uint32 CHUNK_SIZE = 16 * 1024;
183 mike  1.2 
184           #ifdef PEGASUS_PLATFORM_LINUX_IX86_GNU
185 mday  1.5 	 SignalHandler::ignore(SIGPIPE);
186 mike  1.2 
187 mday  1.5 	 //getSigHandle()->registerHandler(SIGSEGV,sig_act);
188           	 //getSigHandle()->activate(SIGSEGV);
189           	 // use the next two lines to test the SIGSEGV handler
190           	 //Thread t(::segmentation_faulter,NULL,false);
191           	 //t.run();
192 mike  1.2 #endif
193 mday  1.5 	 for (Uint32 bytesRemaining = buffer.size(); bytesRemaining > 0; )
194           	 {
195           	    Uint32 bytesToWrite = _Min(bytesRemaining, CHUNK_SIZE);
196           
197           	    Sint32 bytesWritten = _socket->write(
198           	       buffer.getData() + buffer.size() - bytesRemaining, 
199           	       bytesToWrite);
200           
201           	    if (bytesWritten < 0)
202           	       break;
203           	    //throw ConnectionBroken();
204           
205           	    bytesRemaining -= bytesWritten;
206 kumpf 1.7 
207                       Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
208                           "_socket->write bytesWritten = %d, bytesRemaining = %d",
209                           bytesWritten, bytesRemaining);
210 mday  1.5 	 }
211           	 //
212           	 // decrement request count
213           	 //
214           	 _requestCount--;
215 kumpf 1.7          Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
216                       "_requestCount = %d", _requestCount.value());
217 mday  1.5 
218           	 _socket->disableBlocking();
219           	 break;
220                 }
221           
222                 default:
223           	 // ATTN: need unexpected message error!
224           	 break;
225              };
226 mike  1.2 
227 mday  1.5    delete message;
228 kumpf 1.3 
229           #ifdef ENABLETIMEOUTWORKAROUNDHACK
230 mday  1.5    handleEnqueue_mut.unlock();
231 kumpf 1.3 #endif
232           
233 kumpf 1.7    PEG_METHOD_EXIT();
234 mday  1.5 }
235           
236           
237           void HTTPConnection::handleEnqueue()
238           {
239              Message* message = dequeue();
240           
241               if (!message)
242                   return;
243               handleEnqueue(message);
244 mike  1.2 }
245           
246           const char* HTTPConnection::getQueueName() const
247           {
248               return "HTTPConnection";
249           }
250           
251           Boolean _IsBodylessMessage(const char* line)
252           {
253               //ATTN: Make sure this is the right place to check for HTTP/1.1 and
254               //      HTTP/1.0 that is part of the authentication challenge header.
255               //
256               const char* METHOD_NAMES[] =
257               {
258                   "GET",
259                   "HTTP/1.1 401",
260                   "HTTP/1.0 401"
261               };
262           
263               const Uint32 METHOD_NAMES_SIZE = sizeof(METHOD_NAMES) / sizeof(char*);
264           
265 mike  1.2     for (Uint32 i = 0; i < METHOD_NAMES_SIZE; i++)
266               {
267           	Uint32 n = strlen(METHOD_NAMES[i]);
268           
269           	if (strncmp(line, METHOD_NAMES[i], n) == 0 && isspace(line[n]))
270           	    return true;
271               }
272           
273               return false;
274           }
275           
276           void HTTPConnection::_getContentLengthAndContentOffset()
277           {
278               char* data = (char*)_incomingBuffer.getData();
279               Uint32 size = _incomingBuffer.size();
280               char* line = (char*)data;
281               char* sep;
282               Uint32 lineNum = 0;
283               Boolean bodylessMessage = false;
284           
285               while ((sep = _FindSeparator(line, size - (line - data))))
286 mike  1.2     {
287           	char save = *sep;
288           	*sep = '\0';
289           
290           	// Did we find the double separator which terminates the headers?
291           
292           	if (line == sep)
293           	{
294           	    *sep = save;
295           	    line = sep + ((save == '\r') ? 2 : 1);
296           	    _contentOffset = line - _incomingBuffer.getData();
297           	    break;
298           	}
299           
300           	// If this is one of the bodyless methods, then we can assume the
301           	// message is complete when the "\r\n\r\n" is encountered.
302           
303           	if (lineNum == 0 && _IsBodylessMessage(line))
304           	    bodylessMessage = true;
305           
306           	// Look for the content-length if not already found:
307 mike  1.2 
308           	char* colon = strchr(line, ':');
309           
310           	if (colon)
311           	{
312           	    *colon  = '\0';
313           
314           	    if (String::compareNoCase(line, "content-length") == 0)
315           		_contentLength = atoi(colon + 1);
316           
317           	    *colon = ':';
318           	}
319           
320           	*sep = save;
321           	line = sep + ((save == '\r') ? 2 : 1);
322           	lineNum++;
323               }
324           
325               if (_contentOffset != -1 && bodylessMessage)
326           	_contentLength = 0;
327           }
328 mike  1.2 
329           void HTTPConnection::_clearIncoming()
330           {
331               _contentOffset = -1;
332               _contentLength = -1;
333               _incomingBuffer.clear();
334           }
335           
336           void HTTPConnection::_closeConnection()
337           {
338 kumpf 1.7     PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::_closeConnection");
339 kumpf 1.3 
340 mike  1.2     Message* message= new CloseConnectionMessage(_socket->getSocket());
341 mday  1.6     message->dest = _ownerMessageQueue->getQueueId();
342           //    SendForget(message);
343               
344 mike  1.2     _ownerMessageQueue->enqueue(message);
345 kumpf 1.3 
346 kumpf 1.7     PEG_METHOD_EXIT();
347 mike  1.2 }
348           
349           void HTTPConnection::_handleReadEvent()
350           {
351 kumpf 1.7     PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::_handleReadEvent");
352           
353 mike  1.2     // -- Append all data waiting on socket to incoming buffer:
354           
355               Sint32 bytesRead = 0;
356           
357               for (;;)
358               {
359           	char buffer[4096];
360                   Sint32 n = _socket->read(buffer, sizeof(buffer));
361           
362           	if (n <= 0)
363           	    break;
364           
365           	_incomingBuffer.append(buffer, n);
366           	bytesRead += n;
367               }
368 kumpf 1.7    Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
369                "_socket->read bytesRead = %d", bytesRead);
370 mike  1.2 
371               // -- If still waiting for beginning of content!
372           
373               if (_contentOffset == -1)
374           	_getContentLengthAndContentOffset();
375           
376               // -- See if the end of the message was reached (some peers signal end of 
377               // -- the message by closing the connection; others use the content length
378               // -- HTTP header and then there are those messages which have no bodies
379               // -- at all).
380           
381               if (bytesRead == 0 || 
382           	_contentLength != -1 && 
383           	(Sint32(_incomingBuffer.size()) >= _contentLength + _contentOffset))
384               {
385           	HTTPMessage* message = new HTTPMessage(_incomingBuffer, getQueueId());
386                   message->authInfo = _authInfo;
387           
388                   //
389                   // increment request count 
390                   //
391 mike  1.2         _requestCount++;
392 kumpf 1.7         Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
393                     "_requestCount = %d", _requestCount.value());
394           
395 mday  1.6 	message->dest = _outputMessageQueue->getQueueId();
396           //	SendForget(message);
397           	
398 mike  1.2 	_outputMessageQueue->enqueue(message);
399           	_clearIncoming();
400           
401           	if (bytesRead == 0)
402           	{
403 kumpf 1.7             Tracer::trace(TRC_HTTP, Tracer::LEVEL3,
404                          "HTTPConnection::_handleReadEvent - bytesRead == 0 - Conection being closed.");
405           
406 mike  1.2 	    _closeConnection();
407           
408                       //
409                       // decrement request count
410                       //
411                       _requestCount--;
412 kumpf 1.7             Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
413                          "_requestCount = %d", _requestCount.value());
414 mike  1.2 
415 kumpf 1.7             PEG_METHOD_EXIT();
416 mike  1.2 	    return;
417           	}
418               }
419 kumpf 1.7     PEG_METHOD_EXIT();
420 mike  1.2 }
421           
422           Uint32 HTTPConnection::getRequestCount()
423           {
424               return(_requestCount.value());
425           }
426           
427           PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2