(file) Return to HTTPMessage.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2