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
|