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
|