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
|