1 karl 1.21 //%2005////////////////////////////////////////////////////////////////////////
|
2 mike 1.2 //
|
3 karl 1.19 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
|
6 karl 1.14 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.19 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
|
9 karl 1.21 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 mike 1.2 //
12 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
13 kumpf 1.9 // of this software and associated documentation files (the "Software"), to
14 // deal in the Software without restriction, including without limitation the
15 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
16 mike 1.2 // sell copies of the Software, and to permit persons to whom the Software is
17 // furnished to do so, subject to the following conditions:
|
18 david.dillard 1.22 //
|
19 kumpf 1.9 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
20 mike 1.2 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
21 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
22 kumpf 1.9 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
23 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
25 mike 1.2 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 //==============================================================================
29 //
30 // Author: Mike Brasher (mbrasher@bmc.com)
31 //
|
32 kumpf 1.4 // Modified By: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
|
33 david 1.12 // Dave Rosckes (rosckes@us.ibm.com)
|
34 brian.campbell 1.16 // Brian G. Campbell, EMC (campbell_brian@emc.com) - PEP140/phase1
|
35 a.arora 1.17 // Amit K Arora, IBM (amita@in.ibm.com) for PEP101
|
36 se.gupta 1.18 // Seema Gupta (gseema@in.ibm.com) for Bug#1096
|
37 david.dillard 1.20 // David Dillard, VERITAS Software Corp.
38 // (david.dillard@veritas.com)
|
39 mike 1.2 //
40 //%/////////////////////////////////////////////////////////////////////////////
41
42 #include <Pegasus/Common/Config.h>
43 #include <iostream>
44 #include "HTTPMessage.h"
45
46 PEGASUS_USING_STD;
47
48 PEGASUS_NAMESPACE_BEGIN
49
50
51 //------------------------------------------------------------------------------
52 //
53 // Implementation notes:
54 //
|
55 david.dillard 1.22 // According to the HTTP specification:
|
56 mike 1.2 //
57 // 1. Method names are case-sensitive.
58 // 2. Field names are case-insensitive.
59 // 3. The first line of a message is known as the "start-line".
60 // 4. Subsequent lines are known as headers.
61 // 5. Headers have a field-name and field-value.
62 // 6. Start-lines may be request-lines or status-lines. Request lines
63 // have this form:
64 //
65 // Request-Line = Method SP Request-URI SP HTTP-Version CRLF
66 //
67 // Status-lines have this form:
68 //
69 // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
70 //
71 //------------------------------------------------------------------------------
72
73 static char* _FindSeparator(const char* data, Uint32 size)
74 {
75 const char* p = data;
76 const char* end = p + size;
77 mike 1.2
78 while (p != end)
79 {
80 if (*p == '\r')
81 {
82 Uint32 n = end - p;
83
84 if (n >= 2 && p[1] == '\n')
85 return (char*)p;
86 }
87 else if (*p == '\n')
88 return (char*)p;
89
90 p++;
91 }
92
93 return 0;
94 }
95
96 HTTPMessage::HTTPMessage(
|
97 david.dillard 1.22 const Array<char>& message_,
|
98 brian.campbell 1.16 Uint32 queueId_, const CIMException *cimException_)
|
99 mike 1.2 :
|
100 david.dillard 1.22 Message(HTTP_MESSAGE),
101 message(message_),
|
102 humberto 1.15 queueId(queueId_),
103 acceptLanguagesDecoded(false),
104 contentLanguagesDecoded(false)
|
105 mike 1.2 {
|
106 brian.campbell 1.16 if (cimException_)
107 cimException = *cimException_;
|
108 mike 1.2 }
109
|
110 mday 1.3
|
111 se.gupta 1.18 HTTPMessage::HTTPMessage(const HTTPMessage & msg)
|
112 mday 1.3 : Base(msg)
113 {
114 message = msg.message;
115 queueId = msg.queueId;
|
116 se.gupta 1.18 authInfo = msg.authInfo;
|
117 humberto 1.15 acceptLanguages = msg.acceptLanguages;
118 contentLanguages = msg.contentLanguages;
119 acceptLanguagesDecoded = msg.acceptLanguagesDecoded;
120 contentLanguagesDecoded = msg.contentLanguagesDecoded;
|
121 brian.campbell 1.16 cimException = msg.cimException;
|
122 se.gupta 1.18 }
|
123 mday 1.3
124
|
125 mike 1.2 void HTTPMessage::parse(
126 String& startLine,
127 Array<HTTPHeader>& headers,
128 Uint32& contentLength) const
129 {
130 startLine.clear();
131 headers.clear();
132 contentLength = 0;
133
134 char* data = (char*)message.getData();
135 Uint32 size = message.size();
|
136 david.dillard 1.20 char* line = data;
|
137 mike 1.2 char* sep;
138 Boolean firstTime = true;
139
140 while ((sep = _FindSeparator(line, size - (line - data))))
141 {
142 // Look for double separator which terminates the header?
143
144 if (line == sep)
145 {
146 // Establish pointer to content (account for "\n" and "\r\n").
147
|
148 david.dillard 1.20 char* content = line + ((*sep == '\r') ? 2 : 1);
|
149 mike 1.2
150 // Determine length of content:
151
152 contentLength = message.size() - (content - data);
153 break;
154 }
155
156 Uint32 lineLength = sep - line;
157
158 if (firstTime)
159 startLine.assign(line, lineLength);
160 else
161 {
162 // Find the colon:
163
|
164 david.dillard 1.20 char* colon = 0;
|
165 mike 1.2
166 for (Uint32 i = 0; i < lineLength; i++)
167 {
168 if (line[i] == ':')
169 {
170 colon = &line[i];
171 break;
172 }
173 }
174
175 // This should always be true:
176
177 if (colon)
178 {
179 // Get the name part:
180
|
181 david.dillard 1.20 char* end;
|
182 mike 1.2
183 for (end = colon - 1; end > line && isspace(*end); end--)
184 ;
185
186 end++;
187
188 String name(line, end - line);
189
190 // Get the value part:
191
|
192 david.dillard 1.20 char* start;
|
193 mike 1.2
194 for (start = colon + 1; start < sep && isspace(*start); start++)
195 ;
196
197 String value(start, sep - start);
198
199 headers.append(HTTPHeader(name, value));
|
200 david 1.12
201 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
202 "HTTPMessage - HTTP header name: $0 HTTP header value: $1"
203 ,name,value);
|
204 mike 1.2 }
205 }
206
207 line = sep + ((*sep == '\r') ? 2 : 1);
208 firstTime = false;
209 }
210 }
211
|
212 joyce.j 1.24
213 #ifdef PEGASUS_DEBUG
|
214 mike 1.2 void HTTPMessage::printAll(ostream& os) const
215 {
216 Message::print(os);
217
218 String startLine;
219 Array<HTTPHeader> headers;
220 Uint32 contentLength;
221 parse(startLine, headers, contentLength);
222
|
223 karl 1.13 // get pointer to start of data.
|
224 david.dillard 1.20 const char* content = message.getData() + message.size() - contentLength;
|
225 mike 1.2 // Print the first line:
226
|
227 karl 1.13 os << endl << startLine << endl;
|
228 mike 1.2
229 // Print the headers:
230
231 Boolean image = false;
232
233 for (Uint32 i = 0; i < headers.size(); i++)
234 {
|
235 karl 1.13 cout << headers[i].first << ": " << headers[i].second << endl;
|
236 david.dillard 1.22
|
237 karl 1.13 if (String::equalNoCase(headers[i].first, "content-type"))
238 {
239 if (headers[i].second.find("image/") == 0)
240 image = true;
241 }
|
242 mike 1.2 }
243
|
244 karl 1.13 os << endl;
|
245 mike 1.2
246 // Print the content:
247
248 for (Uint32 i = 0; i < contentLength; i++)
249 {
|
250 david.dillard 1.20 //char c = content[i];
|
251 mike 1.2
252 if (image)
253 {
254 if ((i % 60) == 0)
|
255 karl 1.13 os << endl;
|
256 mike 1.2
|
257 david.dillard 1.20 char c = content[i];
|
258 mike 1.2
259 if (c >= ' ' && c < '~')
|
260 karl 1.13 os << c;
|
261 mike 1.2 else
|
262 karl 1.13 os << '.';
|
263 mike 1.2 }
264 else
|
265 karl 1.13 cout << content[i];
|
266 mike 1.2 }
267
|
268 karl 1.13 os << endl;
|
269 mike 1.2 }
|
270 joyce.j 1.24 #endif
|
271 mike 1.2
|
272 brian.campbell 1.16 /*
273 * Find the header prefix (i.e 2-digit number in front of cim keyword) if any.
|
274 david.dillard 1.22 * If a fieldName is given it will use that, otherwise the FIRST field
275 * starting with the standard keyword will be used. Given field names that do
|
276 brian.campbell 1.16 * not start with the standard keyword will never match.
277 * if there is a keyword match, the prefix will be populated, else set to empty
278 */
279
280 void HTTPMessage::lookupHeaderPrefix(
281 Array<HTTPHeader>& headers,
282 const String& fieldName,
283 String& prefix)
284 {
285 static const char keyword[] = "CIM";
286 prefix.clear();
287
288 for (Uint32 i = 0, n = headers.size(); i < n; i++)
289 {
290 const String &h = headers[i].first;
291
|
292 kumpf 1.25 if ((h.size() >= 3) &&
293 (h[0] >= '0') && (h[0] <= '9') &&
294 (h[1] >= '0') && (h[1] <= '9') &&
295 (h[2] == Char16('-')))
|
296 brian.campbell 1.16 {
297 String fieldNameCurrent = h.subString(3);
298
299 // ONLY fields starting with keyword can have prefixed according to spec
300 if (String::equalNoCase(fieldNameCurrent, keyword) == false)
301 continue;
302
303 prefix = h.subString(0,3);
304
305 // no field name given, just return the first prefix encountered
306 if (fieldName.size() == 0)
307 break;
308
309 if (String::equalNoCase(fieldNameCurrent, fieldName) == false)
310 prefix.clear();
|
311 david.dillard 1.22 else break;
|
312 brian.campbell 1.16 }
313 }
314 }
315
|
316 mike 1.2 Boolean HTTPMessage::lookupHeader(
317 Array<HTTPHeader>& headers,
318 const String& fieldName,
319 String& fieldValue,
|
320 kumpf 1.5 Boolean allowNamespacePrefix)
|
321 mike 1.2 {
322 for (Uint32 i = 0, n = headers.size(); i < n; i++)
323 {
|
324 kumpf 1.5 if (String::equalNoCase(headers[i].first, fieldName) ||
325 (allowNamespacePrefix && (headers[i].first.size() >= 3) &&
|
326 kumpf 1.25 (headers[i].first[0] >= '0') && (headers[i].first[0] <= '9') &&
327 (headers[i].first[1] >= '0') && (headers[i].first[1] <= '9') &&
|
328 kumpf 1.5 (headers[i].first[2] == Char16('-')) &&
329 String::equalNoCase(headers[i].first.subString(3), fieldName)))
|
330 mike 1.2 {
331 fieldValue = headers[i].second;
332 return true;
333 }
334 }
335
336 // Not found:
337 return false;
338 }
339
340 Boolean HTTPMessage::parseRequestLine(
341 const String& startLine,
342 String& methodName,
343 String& requestUri,
344 String& httpVersion)
345 {
346 // Request-Line = Method SP Request-URI SP HTTP-Version CRLF
347
348 // Extract the method-name:
349
350 Uint32 space1 = startLine.find(' ');
351 mike 1.2
|
352 kumpf 1.10 if (space1 == PEG_NOT_FOUND)
|
353 mike 1.2 return false;
354
355 methodName = startLine.subString(0, space1);
356
357 // Extrat the request-URI:
358
359 Uint32 space2 = startLine.find(space1 + 1, ' ');
360
|
361 kumpf 1.10 if (space2 == PEG_NOT_FOUND)
|
362 mike 1.2 return false;
363
364 Uint32 uriPos = space1 + 1;
365
366 requestUri = startLine.subString(uriPos, space2 - uriPos);
367
368 // Extract the HTTP version:
369
370 httpVersion = startLine.subString(space2 + 1);
|
371 kumpf 1.4
372 return true;
373 }
374
375 Boolean HTTPMessage::parseStatusLine(
376 const String& statusLine,
377 String& httpVersion,
378 Uint32& statusCode,
379 String& reasonPhrase)
380 {
381 // Request-Line = Method SP Request-URI SP HTTP-Version CRLF
382 // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
383
384 // Extract the HTTP version:
385
386 Uint32 space1 = statusLine.find(' ');
387
|
388 kumpf 1.10 if (space1 == PEG_NOT_FOUND)
|
389 kumpf 1.4 return false;
390
391 httpVersion = statusLine.subString(0, space1);
392
393 // Extract the status code:
394
395 Uint32 space2 = statusLine.find(space1 + 1, ' ');
396
|
397 kumpf 1.10 if (space2 == PEG_NOT_FOUND)
|
398 kumpf 1.4 return false;
399
400 Uint32 statusCodePos = space1 + 1;
401 String statusCodeStr;
402 statusCodeStr = statusLine.subString(statusCodePos, space2 - statusCodePos);
|
403 kumpf 1.11 if (!sscanf(statusCodeStr.getCString(), "%u", &statusCode))
|
404 kumpf 1.4 return false;
405
406 // Extract the reason phrase:
407
408 reasonPhrase = statusLine.subString(space2 + 1);
|
409 mike 1.2
410 return true;
411 }
412
413 PEGASUS_NAMESPACE_END
|