(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               MessageQueue* ownerMessageQueue,
103               MessageQueue* outputMessageQueue)
104               : 
105 mday  1.4    Base("HTTPConnection", MessageQueue::getNextQueueId()),
106              _monitor(monitor),
107              _socket(socket), 
108              _ownerMessageQueue(ownerMessageQueue),
109              _outputMessageQueue(outputMessageQueue),
110              _contentOffset(-1),
111              _contentLength(-1)
112 mike  1.2 {
113 mday  1.4    //Socket::disableBlocking(_socket);
114              _socket->disableBlocking();
115              _authInfo = new AuthenticationInfo();
116 mike  1.2 }
117           
118           HTTPConnection::~HTTPConnection()
119           {
120               _socket->close();
121               delete _socket;
122               delete _authInfo;
123           }
124           
125           void HTTPConnection::handleEnqueue()
126           {
127 kumpf 1.3     const char METHOD_NAME[] = "HTTPConnection::handleEnqueue";
128           
129               PEG_FUNC_ENTER(TRC_HTTP, METHOD_NAME);
130           
131           #ifdef ENABLETIMEOUTWORKAROUNDHACK
132               static Mutex handleEnqueue_mut = Mutex();
133           #endif
134           
135 mike  1.2     Message* message = dequeue();
136           
137               if (!message)
138                   return;
139           
140 kumpf 1.3 #ifdef ENABLETIMEOUTWORKAROUNDHACK
141               handleEnqueue_mut.lock(pegasus_thread_self());
142           #endif
143           
144 mike  1.2     switch (message->getType())
145               {
146           	case SOCKET_MESSAGE:
147           	{
148           	    SocketMessage* socketMessage = (SocketMessage*)message;
149           
150           	    if (socketMessage->events & SocketMessage::READ)
151           		_handleReadEvent();
152           
153           	    break;
154           	}
155           
156           	case HTTP_MESSAGE:
157           	{
158           	    HTTPMessage* httpMessage = (HTTPMessage*)message;
159           
160           	    // ATTN: convert over to asynchronous write scheme:
161           
162           	    // Send response message to the client (use synchronous I/O for now:
163           
164                       _socket->enableBlocking();
165 mike  1.2 
166           	    const Array<Sint8>& buffer = httpMessage->message;
167           	    const Uint32 CHUNK_SIZE = 16 * 1024;
168           
169           #ifdef PEGASUS_PLATFORM_LINUX_IX86_GNU
170                       SignalHandler::ignore(SIGPIPE);
171           
172                       //getSigHandle()->registerHandler(SIGSEGV,sig_act);
173                       //getSigHandle()->activate(SIGSEGV);
174                       // use the next two lines to test the SIGSEGV handler
175                       //Thread t(::segmentation_faulter,NULL,false);
176                       //t.run();
177           #endif
178           	    for (Uint32 bytesRemaining = buffer.size(); bytesRemaining > 0; )
179           	    {
180           		Uint32 bytesToWrite = _Min(bytesRemaining, CHUNK_SIZE);
181           
182           		Sint32 bytesWritten = _socket->write(
183           		    buffer.getData() + buffer.size() - bytesRemaining, 
184           		    bytesToWrite);
185           
186 mike  1.2 		if (bytesWritten < 0)
187           		    break;
188                               //throw ConnectionBroken();
189           
190           		bytesRemaining -= bytesWritten;
191           	    }
192                       //
193                       // decrement request count
194                       //
195                       _requestCount--;
196           
197                       _socket->disableBlocking();
198 kumpf 1.3             break;
199 mike  1.2 	}
200           
201           	default:
202           	    // ATTN: need unexpected message error!
203           	    break;
204               };
205           
206               delete message;
207 kumpf 1.3 
208           #ifdef ENABLETIMEOUTWORKAROUNDHACK
209               handleEnqueue_mut.unlock();
210           #endif
211           
212               PEG_FUNC_EXIT(TRC_HTTP, METHOD_NAME);
213 mike  1.2 }
214           
215           const char* HTTPConnection::getQueueName() const
216           {
217               return "HTTPConnection";
218           }
219           
220           Boolean _IsBodylessMessage(const char* line)
221           {
222               //ATTN: Make sure this is the right place to check for HTTP/1.1 and
223               //      HTTP/1.0 that is part of the authentication challenge header.
224               //
225               const char* METHOD_NAMES[] =
226               {
227                   "GET",
228                   "HTTP/1.1 401",
229                   "HTTP/1.0 401"
230               };
231           
232               const Uint32 METHOD_NAMES_SIZE = sizeof(METHOD_NAMES) / sizeof(char*);
233           
234 mike  1.2     for (Uint32 i = 0; i < METHOD_NAMES_SIZE; i++)
235               {
236           	Uint32 n = strlen(METHOD_NAMES[i]);
237           
238           	if (strncmp(line, METHOD_NAMES[i], n) == 0 && isspace(line[n]))
239           	    return true;
240               }
241           
242               return false;
243           }
244           
245           void HTTPConnection::_getContentLengthAndContentOffset()
246           {
247               char* data = (char*)_incomingBuffer.getData();
248               Uint32 size = _incomingBuffer.size();
249               char* line = (char*)data;
250               char* sep;
251               Uint32 lineNum = 0;
252               Boolean bodylessMessage = false;
253           
254               while ((sep = _FindSeparator(line, size - (line - data))))
255 mike  1.2     {
256           	char save = *sep;
257           	*sep = '\0';
258           
259           	// Did we find the double separator which terminates the headers?
260           
261           	if (line == sep)
262           	{
263           	    *sep = save;
264           	    line = sep + ((save == '\r') ? 2 : 1);
265           	    _contentOffset = line - _incomingBuffer.getData();
266           	    break;
267           	}
268           
269           	// If this is one of the bodyless methods, then we can assume the
270           	// message is complete when the "\r\n\r\n" is encountered.
271           
272           	if (lineNum == 0 && _IsBodylessMessage(line))
273           	    bodylessMessage = true;
274           
275           	// Look for the content-length if not already found:
276 mike  1.2 
277           	char* colon = strchr(line, ':');
278           
279           	if (colon)
280           	{
281           	    *colon  = '\0';
282           
283           	    if (String::compareNoCase(line, "content-length") == 0)
284           		_contentLength = atoi(colon + 1);
285           
286           	    *colon = ':';
287           	}
288           
289           	*sep = save;
290           	line = sep + ((save == '\r') ? 2 : 1);
291           	lineNum++;
292               }
293           
294               if (_contentOffset != -1 && bodylessMessage)
295           	_contentLength = 0;
296           }
297 mike  1.2 
298           void HTTPConnection::_clearIncoming()
299           {
300               _contentOffset = -1;
301               _contentLength = -1;
302               _incomingBuffer.clear();
303           }
304           
305           void HTTPConnection::_closeConnection()
306           {
307 kumpf 1.3     const char METHOD_NAME[] = "HTTPConnection::_closeConnection";
308           
309               PEG_FUNC_ENTER(TRC_HTTP, METHOD_NAME);
310           
311 mike  1.2     Message* message= new CloseConnectionMessage(_socket->getSocket());
312               _ownerMessageQueue->enqueue(message);
313 kumpf 1.3 
314               PEG_FUNC_EXIT(TRC_HTTP, METHOD_NAME);
315 mike  1.2 }
316           
317           void HTTPConnection::_handleReadEvent()
318           {
319               // -- Append all data waiting on socket to incoming buffer:
320           
321               Sint32 bytesRead = 0;
322           
323               for (;;)
324               {
325           	char buffer[4096];
326                   Sint32 n = _socket->read(buffer, sizeof(buffer));
327           
328           	if (n <= 0)
329           	    break;
330           
331           	_incomingBuffer.append(buffer, n);
332           	bytesRead += n;
333               }
334           
335               // -- If still waiting for beginning of content!
336 mike  1.2 
337               if (_contentOffset == -1)
338           	_getContentLengthAndContentOffset();
339           
340               // -- See if the end of the message was reached (some peers signal end of 
341               // -- the message by closing the connection; others use the content length
342               // -- HTTP header and then there are those messages which have no bodies
343               // -- at all).
344           
345               if (bytesRead == 0 || 
346           	_contentLength != -1 && 
347           	(Sint32(_incomingBuffer.size()) >= _contentLength + _contentOffset))
348               {
349           	HTTPMessage* message = new HTTPMessage(_incomingBuffer, getQueueId());
350                   message->authInfo = _authInfo;
351           
352                   //
353                   // increment request count 
354                   //
355                   _requestCount++;
356           
357 mike  1.2 	_outputMessageQueue->enqueue(message);
358           	_clearIncoming();
359           
360           	if (bytesRead == 0)
361           	{
362           	    _closeConnection();
363           
364                       //
365                       // decrement request count
366                       //
367                       _requestCount--;
368           
369           	    return;
370           	}
371               }
372           }
373           
374           Uint32 HTTPConnection::getRequestCount()
375           {
376               return(_requestCount.value());
377           }
378 mike  1.2 
379           PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2