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
|