(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            //%/////////////////////////////////////////////////////////////////////////////
 33            
 34            #include <Pegasus/Common/Config.h>
 35            #include <iostream>
 36 mike  1.29 #include <cstring>
 37 mike  1.2  #include "HTTPMessage.h"
 38 mike  1.34 #include "ArrayIterator.h"
 39 mike  1.2  
 40            PEGASUS_USING_STD;
 41            
 42            PEGASUS_NAMESPACE_BEGIN
 43            
 44 mike  1.33 static const String _HTTP_HEADER_CONTENT_TYPE = "content-type";
 45 mike  1.2  
 46            //------------------------------------------------------------------------------
 47            //
 48            // Implementation notes:
 49            //
 50 david.dillard 1.22 //     According to the HTTP specification:
 51 mike          1.2  //
 52                    //         1.  Method names are case-sensitive.
 53                    //         2.  Field names are case-insensitive.
 54                    //         3.  The first line of a message is known as the "start-line".
 55                    //         4.  Subsequent lines are known as headers.
 56                    //         5.  Headers have a field-name and field-value.
 57                    //         6.  Start-lines may be request-lines or status-lines. Request lines
 58                    //             have this form:
 59                    //
 60                    //             Request-Line = Method SP Request-URI SP HTTP-Version CRLF
 61                    //
 62                    //             Status-lines have this form:
 63                    //
 64                    //             Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
 65                    //
 66                    //------------------------------------------------------------------------------
 67                    
 68 sushma.fernandes 1.41 char* HTTPMessage::findSeparator(const char* data, Uint32 size)
 69 mike             1.2  {
 70 mike             1.31     const char* p = data;
 71 mike             1.2      const char* end = p + size;
 72                       
 73                           while (p != end)
 74                           {
 75 kumpf            1.36         if (*p == '\r')
 76                               {
 77 a.dunfey         1.38             size_t n = end - p;
 78 kumpf            1.36 
 79                                   if (n >= 2 && p[1] == '\n')
 80                                       return (char*)p;
 81                               }
 82                               else if (*p == '\n')
 83                                   return (char*)p;
 84 mike             1.2  
 85 kumpf            1.36         p++;
 86 mike             1.2      }
 87                       
 88                           return 0;
 89                       }
 90                       
 91 sushma.fernandes 1.41 void HTTPMessage::skipHeaderWhitespace(const char*& str)
 92 venkat.puvvada   1.40 {
 93 sushma.fernandes 1.41     while (*str && (*str == ' ' || *str == '\t'))
 94 venkat.puvvada   1.40     {
 95                               ++str;
 96                           }
 97                       }
 98                       
 99 sushma.fernandes 1.41 Boolean HTTPMessage::expectHeaderToken(const char*& str, const char *token)
100 venkat.puvvada   1.40 {
101                           PEGASUS_ASSERT(token);
102 sushma.fernandes 1.41 
103                           skipHeaderWhitespace(str);
104 venkat.puvvada   1.40     for ( ; *token ; ++str, ++token)
105                           {
106                               if (!*str || tolower(*str) != tolower(*token))
107                               {
108                                   return false;
109                               }
110                           }
111                           return true;
112                       }
113                       
114 mike             1.2  HTTPMessage::HTTPMessage(
115 mike             1.28     const Buffer& message_,
116 brian.campbell   1.16     Uint32 queueId_, const CIMException *cimException_)
117 mike             1.2      :
118 david.dillard    1.22     Message(HTTP_MESSAGE),
119                           message(message_),
120 humberto         1.15     queueId(queueId_),
121 kumpf            1.26     authInfo(0),
122 humberto         1.15     acceptLanguagesDecoded(false),
123                           contentLanguagesDecoded(false)
124 mike             1.2  {
125 kumpf            1.36     if (cimException_)
126                               cimException = *cimException_;
127 mike             1.2  }
128                       
129 mday             1.3  
130 se.gupta         1.18 HTTPMessage::HTTPMessage(const HTTPMessage & msg)
131 kumpf            1.36     : Base(msg)
132 mday             1.3  {
133 kumpf            1.36     message = msg.message;
134                           queueId = msg.queueId;
135                           authInfo = msg.authInfo;
136                           acceptLanguages = msg.acceptLanguages;
137                           contentLanguages = msg.contentLanguages;
138                           acceptLanguagesDecoded = msg.acceptLanguagesDecoded;
139                           contentLanguagesDecoded = msg.contentLanguagesDecoded;
140                           cimException = msg.cimException;
141                       }
142 mday             1.3  
143                       
144 mike             1.2  void HTTPMessage::parse(
145                           String& startLine,
146                           Array<HTTPHeader>& headers,
147                           Uint32& contentLength) const
148                       {
149                           startLine.clear();
150                           headers.clear();
151                           contentLength = 0;
152                       
153                           char* data = (char*)message.getData();
154 kumpf            1.39     Uint32 size = message.size();
155 david.dillard    1.20     char* line = data;
156 mike             1.2      char* sep;
157                           Boolean firstTime = true;
158                       
159 sushma.fernandes 1.41     while ((sep = findSeparator(line, (Uint32)(size - (line - data)))))
160 mike             1.2      {
161 kumpf            1.36         // Look for double separator which terminates the header?
162 mike             1.2  
163 kumpf            1.36         if (line == sep)
164                               {
165                                   // Establish pointer to content (account for "\n" and "\r\n").
166                       
167                                   char* content = line + ((*sep == '\r') ? 2 : 1);
168                       
169                                   // Determine length of content:
170                       
171 a.dunfey         1.38             contentLength = (Uint32)(message.size() - (content - data));
172 kumpf            1.36             break;
173                               }
174                       
175 a.dunfey         1.38         Uint32 lineLength = (Uint32)(sep - line);
176 kumpf            1.36 
177                               if (firstTime)
178                                   startLine.assign(line, lineLength);
179                               else
180                               {
181                                   // Find the colon:
182                       
183                                   char* colon = 0;
184                       
185                                   for (Uint32 i = 0; i < lineLength; i++)
186                                   {
187                                       if (line[i] == ':')
188                                       {
189                                           colon = &line[i];
190                                           break;
191                                       }
192                                   }
193                       
194                                   // This should always be true:
195                       
196                                   if (colon)
197 kumpf            1.36             {
198                                       // Get the name part:
199                       
200                                       char* end;
201                       
202                                       for (end = colon - 1; end > line && isspace(*end); end--)
203                                           ;
204                       
205                                       end++;
206                       
207 a.dunfey         1.38                 String name(line, (Uint32)(end - line));
208 kumpf            1.36 
209                                       // Get the value part:
210                       
211                                       char* start;
212                       
213                                       for (start = colon + 1; start < sep && isspace(*start); start++)
214                                           ;
215                       
216 a.dunfey         1.38                 String value(start, (Uint32)(sep - start));
217 kumpf            1.36 
218                                       // From the HTTP/1.1 specification (RFC 2616) section 4.2
219                                       // Message Headers:
220                                       //
221                                       // Multiple message-header fields with the same field-name
222                                       // MAY be present in a message if and only if the entire
223                                       // field-value for that header field is defined as a
224                                       // comma-separated list [i.e., #(values)]. It MUST be
225                                       // possible to combine the multiple header fields into one
226                                       // "field-name: field-value" pair, without changing the
227                                       // semantics of the message, by appending each subsequent
228                                       // field-value to the first, each separated by a comma.  The
229                                       // order in which header fields with the same field-name are
230                                       // received is therefore significant to the interpretation
231                                       // of the combined field value, and thus a proxy MUST NOT
232                                       // change the order of these field values when a message is
233                                       // forwarded.
234                       
235                                       // This implementation concatenates duplicate header values,
236                                       // with a comma separator.  If the resulting value is invalid,
237                                       // that should be detected when the value is used.
238 kumpf            1.36 
239                                       Uint32 headerIndex = 0;
240                                       for (; headerIndex < headers.size(); headerIndex++)
241                                       {
242                                           if (headers[headerIndex].first == name)
243                                           {
244                                               break;
245                                           }
246                                       }
247                       
248                                       if (headerIndex == headers.size())
249                                       {
250                                           headers.append(HTTPHeader(name, value));
251                                       }
252                                       else
253                                       {
254                                           headers[headerIndex].second.append(", ").append(value);
255                                       }
256                                   }
257                               }
258 mike             1.2  
259 kumpf            1.36         line = sep + ((*sep == '\r') ? 2 : 1);
260                               firstTime = false;
261 mike             1.2      }
262                       }
263                       
264 joyce.j          1.24 
265                       #ifdef PEGASUS_DEBUG
266 mike             1.2  void HTTPMessage::printAll(ostream& os) const
267                       {
268                           Message::print(os);
269                       
270                           String startLine;
271                           Array<HTTPHeader> headers;
272                           Uint32 contentLength;
273                           parse(startLine, headers, contentLength);
274                       
275 karl             1.13     // get pointer to start of data.
276 david.dillard    1.20     const char* content = message.getData() + message.size() - contentLength;
277 mike             1.2      // Print the first line:
278                       
279 karl             1.13     os << endl << startLine << endl;
280 mike             1.2  
281                           // Print the headers:
282                       
283                           Boolean image = false;
284                       
285                           for (Uint32 i = 0; i < headers.size(); i++)
286                           {
287 kumpf            1.36         cout << headers[i].first << ": " << headers[i].second << endl;
288 david.dillard    1.22 
289 kumpf            1.36         if (String::equalNoCase(headers[i].first, _HTTP_HEADER_CONTENT_TYPE))
290                               {
291                                   if (headers[i].second.find("image/") == 0)
292                                       image = true;
293                               }
294 mike             1.2      }
295                       
296 karl             1.13     os << endl;
297 mike             1.2  
298                           // Print the content:
299                       
300                           for (Uint32 i = 0; i < contentLength; i++)
301                           {
302 kumpf            1.36         //char c = content[i];
303 mike             1.2  
304 kumpf            1.36         if (image)
305                               {
306                                   if ((i % 60) == 0)
307                                       os << endl;
308                       
309                                   char c = content[i];
310                       
311                                   if (c >= ' ' && c < '~')
312                                       os << c;
313                                   else
314                                       os << '.';
315                               }
316                               else
317                                   cout << content[i];
318 mike             1.2      }
319                       
320 karl             1.13     os << endl;
321 mike             1.2  }
322 joyce.j          1.24 #endif
323 mike             1.2  
324 brian.campbell   1.16 /*
325                        * Find the header prefix (i.e 2-digit number in front of cim keyword) if any.
326 david.dillard    1.22  * If a fieldName is given it will use that, otherwise the FIRST field
327                        * starting with the standard keyword will be used. Given field names that do
328 brian.campbell   1.16  * not start with the standard keyword will never match.
329                        * if there is a keyword match, the prefix will be populated, else set to empty
330                        */
331                       
332                       void HTTPMessage::lookupHeaderPrefix(
333 mike             1.34     Array<HTTPHeader>& headers_,
334 brian.campbell   1.16     const String& fieldName,
335                           String& prefix)
336                       {
337 kumpf            1.36     ArrayIterator<HTTPHeader> headers(headers_);
338 mike             1.34 
339 kumpf            1.36     static const char keyword[] = "CIM";
340                           prefix.clear();
341 brian.campbell   1.16 
342 kumpf            1.36     for (Uint32 i = 0, n = headers.size(); i < n; i++)
343                           {
344                               const String &h = headers[i].first;
345 brian.campbell   1.16 
346 kumpf            1.25                 if ((h.size() >= 3) &&
347                                           (h[0] >= '0') && (h[0] <= '9') &&
348                                           (h[1] >= '0') && (h[1] <= '9') &&
349                                           (h[2] == Char16('-')))
350 kumpf            1.36         {
351                                   String fieldNameCurrent = h.subString(3);
352 brian.campbell   1.16 
353 kumpf            1.37             // ONLY fields starting with keyword can have prefixed according
354                                   // to spec
355 kumpf            1.36             if (String::equalNoCase(fieldNameCurrent, keyword) == false)
356                                       continue;
357                       
358                                   prefix = h.subString(0,3);
359                       
360                                   // no field name given, just return the first prefix encountered
361                                   if (fieldName.size() == 0)
362                                       break;
363                       
364                                   if (String::equalNoCase(fieldNameCurrent, fieldName) == false)
365                                       prefix.clear();
366                                   else break;
367                               }
368                           }
369 brian.campbell   1.16 }
370                       
371 mike             1.2  Boolean HTTPMessage::lookupHeader(
372 mike             1.34     Array<HTTPHeader>& headers_,
373 mike             1.2      const String& fieldName,
374                           String& fieldValue,
375 kumpf            1.5      Boolean allowNamespacePrefix)
376 mike             1.2  {
377 mike             1.34     ArrayIterator<HTTPHeader> headers(headers_);
378                       
379 mike             1.2      for (Uint32 i = 0, n = headers.size(); i < n; i++)
380                           {
381 kumpf            1.5          if (String::equalNoCase(headers[i].first, fieldName) ||
382                                   (allowNamespacePrefix && (headers[i].first.size() >= 3) &&
383 kumpf            1.25              (headers[i].first[0] >= '0') && (headers[i].first[0] <= '9') &&
384                                    (headers[i].first[1] >= '0') && (headers[i].first[1] <= '9') &&
385 kumpf            1.5               (headers[i].first[2] == Char16('-')) &&
386                                    String::equalNoCase(headers[i].first.subString(3), fieldName)))
387 kumpf            1.36         {
388                                   fieldValue = headers[i].second;
389                                   return true;
390                               }
391 mike             1.2      }
392                       
393                           // Not found:
394                           return false;
395                       }
396                       
397                       Boolean HTTPMessage::parseRequestLine(
398                           const String& startLine,
399                           String& methodName,
400                           String& requestUri,
401                           String& httpVersion)
402                       {
403                           // Request-Line = Method SP Request-URI SP HTTP-Version CRLF
404                       
405                           // Extract the method-name:
406                       
407                           Uint32 space1 = startLine.find(' ');
408                       
409 kumpf            1.10     if (space1 == PEG_NOT_FOUND)
410 kumpf            1.36         return false;
411 mike             1.2  
412                           methodName = startLine.subString(0, space1);
413                       
414                           // Extrat the request-URI:
415                       
416                           Uint32 space2 = startLine.find(space1 + 1, ' ');
417                       
418 kumpf            1.10     if (space2 == PEG_NOT_FOUND)
419 kumpf            1.36         return false;
420 mike             1.2  
421                           Uint32 uriPos = space1 + 1;
422                       
423                           requestUri = startLine.subString(uriPos, space2 - uriPos);
424                       
425                           // Extract the HTTP version:
426                       
427                           httpVersion = startLine.subString(space2 + 1);
428 kumpf            1.4  
429                           return true;
430                       }
431                       
432                       Boolean HTTPMessage::parseStatusLine(
433                           const String& statusLine,
434                           String& httpVersion,
435                           Uint32& statusCode,
436                           String& reasonPhrase)
437                       {
438                           // Request-Line = Method SP Request-URI SP HTTP-Version CRLF
439                           // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
440                       
441                           // Extract the HTTP version:
442                       
443                           Uint32 space1 = statusLine.find(' ');
444                       
445 kumpf            1.10     if (space1 == PEG_NOT_FOUND)
446 kumpf            1.36         return false;
447 kumpf            1.4  
448                           httpVersion = statusLine.subString(0, space1);
449                       
450                           // Extract the status code:
451                       
452                           Uint32 space2 = statusLine.find(space1 + 1, ' ');
453                       
454 kumpf            1.10     if (space2 == PEG_NOT_FOUND)
455 kumpf            1.36         return false;
456 kumpf            1.4  
457                           Uint32 statusCodePos = space1 + 1;
458                           String statusCodeStr;
459                           statusCodeStr = statusLine.subString(statusCodePos, space2 - statusCodePos);
460 kumpf            1.11     if (!sscanf(statusCodeStr.getCString(), "%u", &statusCode))
461 kumpf            1.4          return false;
462                       
463                           // Extract the reason phrase:
464                       
465                           reasonPhrase = statusLine.subString(space2 + 1);
466 mike             1.2  
467                           return true;
468                       }
469                       
470 kumpf            1.44 Boolean HTTPMessage::parseContentTypeHeader(
471                           const String& contentTypeHeader,
472                           String& type,
473                           String& charset)
474 venkat.puvvada   1.40 {
475 kumpf            1.44     CString cstr = contentTypeHeader.getCString();
476                           const char* str = (const char*) cstr;
477                           skipHeaderWhitespace(str);
478                       
479                           // Get the type string
480 venkat.puvvada   1.40 
481 kumpf            1.44     const char* end = str;
482                           while (*end && (*end != ' ') && (*end != '\t') && (*end != ';'))
483 venkat.puvvada   1.40     {
484 kumpf            1.44         end++;
485 venkat.puvvada   1.40     }
486                       
487 kumpf            1.44     type.assign(str, end-str);
488                           str = end;
489 sushma.fernandes 1.41     skipHeaderWhitespace(str);
490 venkat.puvvada   1.40 
491 kumpf            1.44     // Get the charset
492                       
493                           if (*str == ';')
494 venkat.puvvada   1.40     {
495 kumpf            1.44         str++;
496                               if (!expectHeaderToken(str, "charset") ||
497                                   !expectHeaderToken(str, "="))
498                               {
499                                   return false;
500                               }
501                               skipHeaderWhitespace(str);
502 venkat.puvvada   1.40 
503 kumpf            1.44         // The value may optionally be enclosed in quotes
504                               if (*str == '"')
505                               {
506                                   str++;
507                                   end = strchr(str, '"');
508                                   if (!end)
509                                   {
510                                       return false;
511                                   }
512                                   charset.assign(str, end-str);
513                                   str = end + 1;
514                               }
515                               else
516 dave.sudlik      1.42         {
517 kumpf            1.44             end = str;
518                                   while (*end && (*end != ' ') && (*end != '\t'))
519                                   {
520                                       end++;
521                                   }
522                                   charset.assign(str, end-str);
523                                   str = end;
524 dave.sudlik      1.42         }
525                           }
526 kumpf            1.44     else
527                           {
528                               // No charset specified; assume UTF-8.
529                               charset = "utf-8";
530                           }
531 dave.sudlik      1.42 
532 sushma.fernandes 1.41     skipHeaderWhitespace(str);
533 venkat.puvvada   1.40 
534 kumpf            1.44     // Check for unexpected characters at the end of the value
535 venkat.puvvada   1.40     return !*str;
536                       }
537                       
538 thilo.boehm      1.43 //
539                       // parse the local authentication header
540                       //
541                       Boolean HTTPMessage::parseLocalAuthHeader(
542                           const String& authHeader,
543                           String& authType,
544                           String& userName,
545                           String& cookie)
546                       {
547                           PEG_METHOD_ENTER(TRC_HTTP, "HTTPMessage::parseLocalAuthHeader()");
548                       
549                           //
550                           // Extract the authentication type:
551                           //
552                           Uint32 space = authHeader.find(' ');
553                       
554                           if ( space == PEG_NOT_FOUND )
555                           {
556                               PEG_METHOD_EXIT();
557                               return false;
558                           }
559 thilo.boehm      1.43 
560                           authType = authHeader.subString(0, space);
561                       
562                           Uint32 startQuote = authHeader.find(space, '"');
563                       
564                           if ( startQuote == PEG_NOT_FOUND )
565                           {
566                               PEG_METHOD_EXIT();
567                               return false;
568                           }
569                       
570                           Uint32 endQuote = authHeader.find(startQuote + 1, '"');
571                       
572                           if ( endQuote == PEG_NOT_FOUND )
573                           {
574                               PEG_METHOD_EXIT();
575                               return false;
576                           }
577                       
578                           String temp = authHeader.subString(
579                               startQuote + 1, (endQuote - startQuote - 1));
580 thilo.boehm      1.43 
581                           //
582                           // Extract the user name and cookie:
583                           //
584                           Uint32 colon = temp.find(0, ':');
585                       
586                           if ( colon == PEG_NOT_FOUND )
587                           {
588                               userName = temp;
589                           }
590                           else
591                           {
592                               userName = temp.subString(0, colon);
593                               cookie = temp;
594                           }
595                       
596                           PEG_METHOD_EXIT();
597                       
598                           return true;
599                       }
600                       
601 thilo.boehm      1.43 //
602                       // parse the HTTP authentication header
603                       //
604                       Boolean HTTPMessage::parseHttpAuthHeader(
605                           const String& authHeader, String& authTypeString, String& cookie)
606                       {
607                           PEG_METHOD_ENTER(TRC_HTTP, "HTTPMessage::parseHttpAuthHeader()");
608                       
609                           //
610                           // Extract the authentication type:
611                           //
612                           Uint32 space = authHeader.find(' ');
613                       
614                           if ( space == PEG_NOT_FOUND )
615                           {
616                               PEG_METHOD_EXIT();
617                               return false;
618                           }
619                       
620                           authTypeString = authHeader.subString(0, space);
621                       
622 thilo.boehm      1.43     //
623                           // Extract the cookie:
624                           //
625                           cookie = authHeader.subString(space + 1);
626                       
627                           PEG_METHOD_EXIT();
628                       
629                           return true;
630                       }
631                       
632 mike             1.2  PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2