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

  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 mike           1.29 #include <cstring>
 45 mike           1.2  #include "HTTPMessage.h"
 46                     
 47                     PEGASUS_USING_STD;
 48                     
 49                     PEGASUS_NAMESPACE_BEGIN
 50                     
 51 mike           1.32 static const String _CONTENT_TYPE = "content-type";
 52 mike           1.2  
 53                     //------------------------------------------------------------------------------
 54                     //
 55                     // Implementation notes:
 56                     //
 57 david.dillard  1.22 //     According to the HTTP specification:
 58 mike           1.2  //
 59                     //         1.  Method names are case-sensitive.
 60                     //         2.  Field names are case-insensitive.
 61                     //         3.  The first line of a message is known as the "start-line".
 62                     //         4.  Subsequent lines are known as headers.
 63                     //         5.  Headers have a field-name and field-value.
 64                     //         6.  Start-lines may be request-lines or status-lines. Request lines
 65                     //             have this form:
 66                     //
 67                     //             Request-Line = Method SP Request-URI SP HTTP-Version CRLF
 68                     //
 69                     //             Status-lines have this form:
 70                     //
 71                     //             Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
 72                     //
 73                     //------------------------------------------------------------------------------
 74                     
 75                     static char* _FindSeparator(const char* data, Uint32 size)
 76                     {
 77 mike           1.31     const char* p = data;
 78 mike           1.30 
 79                         // Short-circuit by using memchr(). This will work whenever there is a
 80                         // "\r\n" sequence. Some clients may send incorrect headers which are
 81                         // only separated by "\n". In this case the code below this block 
 82                         // will handle it.
 83                         {
 84                             const char* q = (char*)memchr(data, '\r', size);
 85                     
 86                             if (q && q[1] == '\n')
 87                               return (char*)q;
 88                         }
 89 mike           1.29 
 90 mike           1.2      const char* end = p + size;
 91                     
 92                         while (p != end)
 93                         {
 94                     	if (*p == '\r')
 95                     	{
 96                     	    Uint32 n = end - p;
 97                     
 98                     	    if (n >= 2 && p[1] == '\n')
 99                     		return (char*)p;
100                     	}
101                     	else if (*p == '\n')
102                     	    return (char*)p;
103                     
104                     	p++;
105                         }
106                     
107                         return 0;
108                     }
109                     
110                     HTTPMessage::HTTPMessage(
111 mike           1.28     const Buffer& message_,
112 brian.campbell 1.16     Uint32 queueId_, const CIMException *cimException_)
113 mike           1.2      :
114 david.dillard  1.22     Message(HTTP_MESSAGE),
115                         message(message_),
116 humberto       1.15     queueId(queueId_),
117 kumpf          1.26     authInfo(0),
118 humberto       1.15     acceptLanguagesDecoded(false),
119                         contentLanguagesDecoded(false)
120 mike           1.2  {
121 brian.campbell 1.16 	if (cimException_)
122                     		cimException = *cimException_;
123 mike           1.2  }
124                     
125 mday           1.3  
126 se.gupta       1.18 HTTPMessage::HTTPMessage(const HTTPMessage & msg)
127 mday           1.3     : Base(msg)
128                     {
129                           message = msg.message;
130                           queueId = msg.queueId;
131 se.gupta       1.18       authInfo = msg.authInfo;
132 humberto       1.15       acceptLanguages = msg.acceptLanguages;
133                           contentLanguages = msg.contentLanguages;
134                           acceptLanguagesDecoded = msg.acceptLanguagesDecoded;
135                           contentLanguagesDecoded = msg.contentLanguagesDecoded;
136 brian.campbell 1.16 			cimException = msg.cimException;
137 se.gupta       1.18  }
138 mday           1.3  
139                     
140 mike           1.2  void HTTPMessage::parse(
141                         String& startLine,
142                         Array<HTTPHeader>& headers,
143                         Uint32& contentLength) const
144                     {
145                         startLine.clear();
146                         headers.clear();
147                         contentLength = 0;
148                     
149                         char* data = (char*)message.getData();
150                         Uint32 size = message.size();
151 david.dillard  1.20     char* line = data;
152 mike           1.2      char* sep;
153                         Boolean firstTime = true;
154                     
155                         while ((sep = _FindSeparator(line, size - (line - data))))
156                         {
157                     	// Look for double separator which terminates the header?
158                     
159                     	if (line == sep)
160                     	{
161                     	    // Establish pointer to content (account for "\n" and "\r\n").
162                     
163 david.dillard  1.20 	    char* content = line + ((*sep == '\r') ? 2 : 1);
164 mike           1.2  
165                     	    // Determine length of content:
166                     
167                     	    contentLength = message.size() - (content - data);
168                     	    break;
169                     	}
170                     
171                     	Uint32 lineLength = sep - line;
172                     
173                     	if (firstTime)
174                     	    startLine.assign(line, lineLength);
175                     	else
176                     	{
177                     	    // Find the colon:
178                     
179 david.dillard  1.20 	    char* colon = 0;
180 mike           1.2  
181                     	    for (Uint32 i = 0; i < lineLength; i++)
182                     	    {
183                     		if (line[i] == ':')
184                     		{
185                     		    colon = &line[i];
186                     		    break;
187                     		}
188                     	    }
189                     
190                     	    // This should always be true:
191                     
192                     	    if (colon)
193                     	    {
194                     		// Get the name part:
195                     
196 david.dillard  1.20 		char* end;
197 mike           1.2  
198                     		for (end = colon - 1; end > line && isspace(*end); end--)
199                     		    ;
200                     
201                     		end++;
202                     
203                     		String name(line, end - line);
204                     
205                     		// Get the value part:
206                     
207 david.dillard  1.20 		char* start;
208 mike           1.2  
209                     		for (start = colon + 1; start < sep && isspace(*start); start++)
210                     		    ;
211                     
212                     		String value(start, sep - start);
213                     
214                     		headers.append(HTTPHeader(name, value));
215 david          1.12 
216 mike           1.27 		PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0,
217                     		    "HTTPMessage - HTTP header name: $0  HTTP header value: $1",
218                     		    name,value));
219 mike           1.2  	    }
220                     	}
221                     
222                     	line = sep + ((*sep == '\r') ? 2 : 1);
223                     	firstTime = false;
224                         }
225                     }
226                     
227 joyce.j        1.24 
228                     #ifdef PEGASUS_DEBUG
229 mike           1.2  void HTTPMessage::printAll(ostream& os) const
230                     {
231                         Message::print(os);
232                     
233                         String startLine;
234                         Array<HTTPHeader> headers;
235                         Uint32 contentLength;
236                         parse(startLine, headers, contentLength);
237                     
238 karl           1.13     // get pointer to start of data.
239 david.dillard  1.20     const char* content = message.getData() + message.size() - contentLength;
240 mike           1.2      // Print the first line:
241                     
242 karl           1.13     os << endl << startLine << endl;
243 mike           1.2  
244                         // Print the headers:
245                     
246                         Boolean image = false;
247                     
248                         for (Uint32 i = 0; i < headers.size(); i++)
249                         {
250 karl           1.13     	cout << headers[i].first << ": " << headers[i].second << endl;
251 david.dillard  1.22 
252 mike           1.32     	if (String::equalNoCase(headers[i].first, _CONTENT_TYPE))
253 karl           1.13     	{
254                         	    if (headers[i].second.find("image/") == 0)
255                         		image = true;
256                         	}
257 mike           1.2      }
258                     
259 karl           1.13     os << endl;
260 mike           1.2  
261                         // Print the content:
262                     
263                         for (Uint32 i = 0; i < contentLength; i++)
264                         {
265 david.dillard  1.20 	//char c = content[i];
266 mike           1.2  
267                     	if (image)
268                     	{
269                     	    if ((i % 60) == 0)
270 karl           1.13 		os << endl;
271 mike           1.2  
272 david.dillard  1.20 	    char c = content[i];
273 mike           1.2  
274                     	    if (c >= ' ' && c < '~')
275 karl           1.13 		os << c;
276 mike           1.2  	    else
277 karl           1.13 		os << '.';
278 mike           1.2  	}
279                     	else
280 karl           1.13 	    cout << content[i];
281 mike           1.2      }
282                     
283 karl           1.13     os << endl;
284 mike           1.2  }
285 joyce.j        1.24 #endif
286 mike           1.2  
287 brian.campbell 1.16 /*
288                      * Find the header prefix (i.e 2-digit number in front of cim keyword) if any.
289 david.dillard  1.22  * If a fieldName is given it will use that, otherwise the FIRST field
290                      * starting with the standard keyword will be used. Given field names that do
291 brian.campbell 1.16  * not start with the standard keyword will never match.
292                      * if there is a keyword match, the prefix will be populated, else set to empty
293                      */
294                     
295                     void HTTPMessage::lookupHeaderPrefix(
296                         Array<HTTPHeader>& headers,
297                         const String& fieldName,
298                         String& prefix)
299                     {
300                     	static const char keyword[] = "CIM";
301                     	prefix.clear();
302                     
303                     	for (Uint32 i = 0, n = headers.size(); i < n; i++)
304                     	{
305                     		const String &h = headers[i].first;
306                     
307 kumpf          1.25                 if ((h.size() >= 3) &&
308                                         (h[0] >= '0') && (h[0] <= '9') &&
309                                         (h[1] >= '0') && (h[1] <= '9') &&
310                                         (h[2] == Char16('-')))
311 brian.campbell 1.16 		{
312                     			String fieldNameCurrent = h.subString(3);
313                     
314                     			// ONLY fields starting with keyword can have prefixed according to spec
315                     			if (String::equalNoCase(fieldNameCurrent, keyword) == false)
316                     				continue;
317                     
318                     			prefix = h.subString(0,3);
319                     
320                     			// no field name given, just return the first prefix encountered
321                     			if (fieldName.size() == 0)
322                     				break;
323                     
324                     			if (String::equalNoCase(fieldNameCurrent, fieldName) == false)
325                     				prefix.clear();
326 david.dillard  1.22 			else break;
327 brian.campbell 1.16 		}
328                     	}
329                     }
330                     
331 mike           1.2  Boolean HTTPMessage::lookupHeader(
332                         Array<HTTPHeader>& headers,
333                         const String& fieldName,
334                         String& fieldValue,
335 kumpf          1.5      Boolean allowNamespacePrefix)
336 mike           1.2  {
337                         for (Uint32 i = 0, n = headers.size(); i < n; i++)
338                         {
339 kumpf          1.5          if (String::equalNoCase(headers[i].first, fieldName) ||
340                                 (allowNamespacePrefix && (headers[i].first.size() >= 3) &&
341 kumpf          1.25              (headers[i].first[0] >= '0') && (headers[i].first[0] <= '9') &&
342                                  (headers[i].first[1] >= '0') && (headers[i].first[1] <= '9') &&
343 kumpf          1.5               (headers[i].first[2] == Char16('-')) &&
344                                  String::equalNoCase(headers[i].first.subString(3), fieldName)))
345 mike           1.2  	{
346                     	    fieldValue = headers[i].second;
347                     	    return true;
348                     	}
349                         }
350                     
351                         // Not found:
352                         return false;
353                     }
354                     
355                     Boolean HTTPMessage::parseRequestLine(
356                         const String& startLine,
357                         String& methodName,
358                         String& requestUri,
359                         String& httpVersion)
360                     {
361                         // Request-Line = Method SP Request-URI SP HTTP-Version CRLF
362                     
363                         // Extract the method-name:
364                     
365                         Uint32 space1 = startLine.find(' ');
366 mike           1.2  
367 kumpf          1.10     if (space1 == PEG_NOT_FOUND)
368 mike           1.2  	return false;
369                     
370                         methodName = startLine.subString(0, space1);
371                     
372                         // Extrat the request-URI:
373                     
374                         Uint32 space2 = startLine.find(space1 + 1, ' ');
375                     
376 kumpf          1.10     if (space2 == PEG_NOT_FOUND)
377 mike           1.2  	return false;
378                     
379                         Uint32 uriPos = space1 + 1;
380                     
381                         requestUri = startLine.subString(uriPos, space2 - uriPos);
382                     
383                         // Extract the HTTP version:
384                     
385                         httpVersion = startLine.subString(space2 + 1);
386 kumpf          1.4  
387                         return true;
388                     }
389                     
390                     Boolean HTTPMessage::parseStatusLine(
391                         const String& statusLine,
392                         String& httpVersion,
393                         Uint32& statusCode,
394                         String& reasonPhrase)
395                     {
396                         // Request-Line = Method SP Request-URI SP HTTP-Version CRLF
397                         // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
398                     
399                         // Extract the HTTP version:
400                     
401                         Uint32 space1 = statusLine.find(' ');
402                     
403 kumpf          1.10     if (space1 == PEG_NOT_FOUND)
404 kumpf          1.4  	return false;
405                     
406                         httpVersion = statusLine.subString(0, space1);
407                     
408                         // Extract the status code:
409                     
410                         Uint32 space2 = statusLine.find(space1 + 1, ' ');
411                     
412 kumpf          1.10     if (space2 == PEG_NOT_FOUND)
413 kumpf          1.4  	return false;
414                     
415                         Uint32 statusCodePos = space1 + 1;
416                         String statusCodeStr;
417                         statusCodeStr = statusLine.subString(statusCodePos, space2 - statusCodePos);
418 kumpf          1.11     if (!sscanf(statusCodeStr.getCString(), "%u", &statusCode))
419 kumpf          1.4          return false;
420                     
421                         // Extract the reason phrase:
422                     
423                         reasonPhrase = statusLine.subString(space2 + 1);
424 mike           1.2  
425                         return true;
426                     }
427                     
428                     PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2