messagingfw/wappushfw/pushutils/src/chttpresponse.cpp
changeset 62 db3f5fa34ec7
parent 0 8e480a14352b
equal deleted inserted replaced
60:9f5ae1728557 62:db3f5fa34ec7
       
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Purpose:  This file provides the definition of the CHTTPResponse class.
       
    15 // The HTTP Response class encodes HTTP response headers only. It
       
    16 // contains the methods used to transcode from WSP->HTTP fields
       
    17 // Local includes
       
    18 // 
       
    19 //
       
    20 
       
    21 
       
    22 
       
    23 // System includes
       
    24 //
       
    25 #include <wspdecoder.h>
       
    26 
       
    27 // User includes
       
    28 #include "chttpresponse.h"
       
    29 
       
    30 const TUint8 KWapQuote = 0x7F;
       
    31 const TUint8 KTop3BitSet = 0x70;
       
    32 const TUint8 KCarryBitMask = 0x80;
       
    33 
       
    34 // Default MIME type is text/plain if we can't identify any other
       
    35 //
       
    36 static const TText8* const defaultType = _S8("application/octet-stream");
       
    37 
       
    38 // Implementation of CHTTPResponse class
       
    39 //
       
    40 
       
    41 
       
    42 // Factory method to construct this class.
       
    43 //
       
    44 // Rtn: a new CHTTPResponse object, by ptr. Ownership is transferred to the
       
    45 //      caller.
       
    46 //
       
    47 
       
    48 CHTTPResponse* CHTTPResponse::NewL()
       
    49 	{
       
    50 	CHTTPResponse* me = new(ELeave)CHTTPResponse();
       
    51 	CleanupStack::PushL(me);
       
    52 	me->ConstructL();
       
    53 	CleanupStack::Pop();
       
    54 	return me;
       
    55 	}
       
    56 
       
    57 
       
    58 // Destructor for this class. Removes this object and releases memory held
       
    59 // by it
       
    60 //
       
    61 
       
    62 CHTTPResponse::~CHTTPResponse()
       
    63     {
       
    64     Reset();
       
    65 	//__CLOSE_LOG;
       
    66     }
       
    67 
       
    68 
       
    69 // Clean out the fields buffer
       
    70 //
       
    71 
       
    72 void CHTTPResponse::Reset()
       
    73     {
       
    74 	//__LOG_ENTER(_L("CHTTPResponse::Reset"));
       
    75     delete iResponse;
       
    76     iResponse = NULL;
       
    77 	//__LOG_RETURN;
       
    78     }
       
    79 
       
    80 
       
    81 // Set the fields buffer with the response received from the WAP Stack
       
    82 //
       
    83 // In:
       
    84 //  aResponse - an 8-bit descriptor field containing the origin server's
       
    85 //				WSP-encoded response header. Ownership is transferred to
       
    86 //				this class.
       
    87 //
       
    88 
       
    89 void CHTTPResponse::AddResponse(HBufC8* aResponse)
       
    90     {
       
    91 	//__LOG_ENTER(_L("CHTTPResponse::AddResponse"));
       
    92     delete iResponse;
       
    93     iResponse = aResponse;
       
    94 #ifdef _DEBUG
       
    95 	DumpToLog(*aResponse);
       
    96 #endif
       
    97 	//__LOG_RETURN;
       
    98     }
       
    99 
       
   100 
       
   101 // Accessor to the HTTP response fields buffer
       
   102 //
       
   103 // Rtn: a reference to the response. Ownership is _NOT_ transferred
       
   104 //
       
   105 // NOTE THIS SHOULD RETURN CONST - BUT CAN'T BE CHANGED SINCE IT WOULD
       
   106 // BREAK BC.
       
   107 
       
   108 HBufC8& CHTTPResponse::Response() const
       
   109     {
       
   110 	//__LOG_ENTER(_L("CHTTPResponse::Response"));
       
   111 	//__LOG_RETURN;
       
   112     return *iResponse;
       
   113     }
       
   114 
       
   115 
       
   116 // Accessor to the HTTP status code (e.g. 400, 300, 200, 500)
       
   117 //
       
   118 // Rtn: the status code - series number only.
       
   119 //
       
   120 
       
   121 THttpStatusCode CHTTPResponse::StatusCode() const
       
   122     {
       
   123 	//__LOG_ENTER(_L("CHTTPResponse::StatusCode"));
       
   124 	//__LOG_RETURN;
       
   125     return iStatusCode;
       
   126     }
       
   127 
       
   128 
       
   129 // Accessor to the HTTP detailed status code (e.g. 404, 304, 200, 501)
       
   130 //
       
   131 // Rtn: the status code - series and specific code value
       
   132 //
       
   133 
       
   134 THttpStatusCode CHTTPResponse::DetailedStatusCode() const
       
   135     {
       
   136 	//__LOG_ENTER(_L("CHTTPResponse::DetailedStatusCode"));
       
   137 	//__LOG_RETURN;
       
   138     return iDetailedStatusCode;
       
   139     }
       
   140 
       
   141 
       
   142 // Accessor to set the HTTP response status.
       
   143 //
       
   144 // In:
       
   145 //  aCode - the WSP-encoded status code
       
   146 //
       
   147 
       
   148 void CHTTPResponse::SetStatusCode(TInt aCode)
       
   149     {
       
   150 //	__LOG_ENTER(_L("CHTTPResponse::SetStatusCode"));
       
   151 //	__LOG1(_L("CHTTPResponse::SetStatusCode : 'aCode' = %d"), aCode);
       
   152     
       
   153 	// Set iDetailedStatusCode to a default
       
   154     iDetailedStatusCode = EHttpUnknown;
       
   155 
       
   156     // Magic no.s come from the WAP WSP specification, Appendix A, Table 36
       
   157     switch (aCode)
       
   158         {
       
   159     case 0x10:
       
   160         iStatusCode = EHttpContinue;
       
   161         break;
       
   162     case 0x11:
       
   163         iDetailedStatusCode = EHttpSwitchingProtocols;
       
   164         iStatusCode = EHttpContinue;
       
   165         break;
       
   166 
       
   167     case 0x20:
       
   168         iStatusCode = EHttpOK;
       
   169         break;
       
   170     case 0x21:
       
   171         iDetailedStatusCode = EHttpCreated;
       
   172         iStatusCode = EHttpOK;
       
   173         break;
       
   174     case 0x22:
       
   175         iDetailedStatusCode = EHttpAccepted;
       
   176         iStatusCode = EHttpOK;
       
   177         break;
       
   178     case 0x23:
       
   179         iDetailedStatusCode = EHttpNonAuthorativeInformation;
       
   180         iStatusCode = EHttpOK;
       
   181         break;
       
   182     case 0x24:
       
   183         iDetailedStatusCode = EHttpNoContent;
       
   184         iStatusCode = EHttpOK;
       
   185         break;
       
   186     case 0x25:
       
   187         iDetailedStatusCode = EHttpResetContent;
       
   188         iStatusCode = EHttpOK;
       
   189         break;
       
   190     case 0x26:
       
   191         iDetailedStatusCode = EHttpPartialContent;
       
   192         iStatusCode = EHttpOK;
       
   193         break;
       
   194 
       
   195     case 0x30:
       
   196         iStatusCode = EHttpMultipleChoices;
       
   197         break;
       
   198     case 0x31:
       
   199         iDetailedStatusCode = EHttpMovedPermanently;
       
   200         iStatusCode = EHttpMultipleChoices;
       
   201         break;
       
   202     case 0x32:
       
   203         iDetailedStatusCode = EHttpMovedTemporarily;
       
   204         iStatusCode = EHttpMultipleChoices;
       
   205         break;
       
   206     case 0x33:
       
   207         iDetailedStatusCode = EHttpSeeOther;
       
   208         iStatusCode = EHttpMultipleChoices;
       
   209         break;
       
   210     case 0x34:
       
   211         iDetailedStatusCode = EHttpNotModified;
       
   212         iStatusCode = EHttpMultipleChoices;
       
   213         break;
       
   214     case 0x35:
       
   215         iDetailedStatusCode = EHttpUseProxy;
       
   216         iStatusCode = EHttpMultipleChoices;
       
   217         break;
       
   218 
       
   219     case 0x40:
       
   220         iStatusCode = EHttpBadRequest;
       
   221         break;
       
   222     case 0x41:
       
   223         iDetailedStatusCode = EHttpUnauthorized;
       
   224         iStatusCode = EHttpBadRequest;
       
   225         break;
       
   226     case 0x42:
       
   227         iDetailedStatusCode = EHttpPaymentRequired;
       
   228         iStatusCode = EHttpBadRequest;
       
   229         break;
       
   230     case 0x43:
       
   231         iDetailedStatusCode = EHttpForbidden;
       
   232         iStatusCode = EHttpBadRequest;
       
   233         break;
       
   234     case 0x44:
       
   235         iDetailedStatusCode = EHttpNotFound;
       
   236         iStatusCode = EHttpBadRequest;
       
   237         break;
       
   238     case 0x45:
       
   239         iDetailedStatusCode = EHttpMethodNotAllowed;
       
   240         iStatusCode = EHttpBadRequest;
       
   241         break;
       
   242     case 0x46:
       
   243         iDetailedStatusCode = EHttpNotAcceptable;
       
   244         iStatusCode = EHttpBadRequest;
       
   245         break;
       
   246     case 0x47:
       
   247         iDetailedStatusCode = EHttpProxyAuthenticationRequired;
       
   248         iStatusCode = EHttpBadRequest;
       
   249         break;
       
   250     case 0x48:
       
   251         iDetailedStatusCode = EHttpRequestTimeout;
       
   252         iStatusCode = EHttpBadRequest;
       
   253         break;
       
   254     case 0x49:
       
   255         iDetailedStatusCode = EHttpConflict;
       
   256         iStatusCode = EHttpBadRequest;
       
   257         break;
       
   258     case 0x4a:
       
   259         iDetailedStatusCode = EHttpGone;
       
   260         iStatusCode = EHttpBadRequest;
       
   261         break;
       
   262     case 0x4b:
       
   263         iDetailedStatusCode = EHttpLengthRequired;
       
   264         iStatusCode = EHttpBadRequest;
       
   265         break;
       
   266     case 0x4c:
       
   267         iDetailedStatusCode = EHttpPreconditionFailed;
       
   268         iStatusCode = EHttpBadRequest;
       
   269         break;
       
   270     case 0x4d:
       
   271         iDetailedStatusCode = EHttpRequestEntityTooLarge;
       
   272         iStatusCode = EHttpBadRequest;
       
   273         break;
       
   274     case 0x4e:
       
   275         iDetailedStatusCode = EHttpRequestURITooLong;
       
   276         iStatusCode = EHttpBadRequest;
       
   277         break;
       
   278     case 0x4f:
       
   279         iDetailedStatusCode = EHttpUnsupportedMediaType;
       
   280         iStatusCode = EHttpBadRequest;
       
   281         break;
       
   282 
       
   283     case 0x60:
       
   284         iStatusCode = EHttpInternalServerError;
       
   285         break;
       
   286     case 0x61:
       
   287         iDetailedStatusCode = EHttpNotImplemented;
       
   288         iStatusCode = EHttpInternalServerError;
       
   289         break;
       
   290     case 0x62:
       
   291         iDetailedStatusCode = EHttpBadGateway;
       
   292         iStatusCode = EHttpInternalServerError;
       
   293         break;
       
   294     case 0x63:
       
   295         iDetailedStatusCode = EHttpServiceUnavailable;
       
   296         iStatusCode = EHttpInternalServerError;
       
   297         break;
       
   298     case 0x64:
       
   299         iDetailedStatusCode = EHttpGatewayTimeout;
       
   300         iStatusCode = EHttpInternalServerError;
       
   301         break;
       
   302     case 0x65:
       
   303         iDetailedStatusCode = EHttpHTTPVersionNotSupported;
       
   304         iStatusCode = EHttpInternalServerError;
       
   305         break;
       
   306 
       
   307     default:
       
   308         iStatusCode = EHttpUnknown;
       
   309         break;
       
   310         }
       
   311     if (iDetailedStatusCode == EHttpUnknown)
       
   312         iDetailedStatusCode = iStatusCode;
       
   313 //	__LOG1(_L("CHTTPResponse::SetStatusCode : status code = %d"), iStatusCode);
       
   314 //	__LOG1(_L("CHTTPResponse::SetStatusCode : detailed status code = %d"), iDetailedStatusCode);
       
   315 //	__LOG_RETURN;
       
   316     }
       
   317 
       
   318 
       
   319 // Method to find a named field, that returns null terminated 
       
   320 // WSP text strings. Note that there is no checking that it is a text string
       
   321 // which follows.
       
   322 //
       
   323 // In:
       
   324 //  aField		- the field type
       
   325 //  aStartIndex	- the index to search from (defaults to the buffer start)
       
   326 //
       
   327 // Out:
       
   328 //  aDesc - a pointer-type descriptor into the response buffer at the
       
   329 //			position where the field was located. The caller must NOT
       
   330 //			modify the descriptor contents
       
   331 //
       
   332 // Rtn: TBool - set to ETrue if the field was found, EFalse otherwise
       
   333 //
       
   334 
       
   335 TBool CHTTPResponse::FindField(THttpHeaderField aField,
       
   336 							   TPtrC8& aDesc,
       
   337 							   TInt aStartIndex) const
       
   338     {
       
   339 //	__LOG_ENTER(_L("CHTTPResponse::FindField (string)"));
       
   340 //	__LOG1(_L("CHTTPResponse::FindField : searching for field type = %d"), aField);
       
   341     TInt index = LocateField(aField, aStartIndex);
       
   342     if (index >0)
       
   343         {
       
   344         TInt count = 0;
       
   345         for (count = index; (count < iResponse->Length()) &&
       
   346 			(iResponse->Des()[count] != 0); count++) {};
       
   347         if (count <= iResponse->Length())
       
   348             {
       
   349             aDesc.Set(&(iResponse->Des()[index]), count-index);
       
   350 //			__LOG(_L("CHTTPResponse::FindField : found string:"));
       
   351 #ifdef _DEBUG
       
   352 			DumpToLog(aDesc);
       
   353 #endif
       
   354 //			__LOG_RETURN;
       
   355             return ETrue;
       
   356             }
       
   357         }
       
   358 //	__LOG(_L("CHTTPResponse::FindField : nothing found"));
       
   359 //	__LOG_RETURN;
       
   360     return EFalse;
       
   361     }
       
   362 
       
   363 
       
   364 // Method to find a named field, that returns 8-bit octet data (binary
       
   365 // or strings - not stipulated which).
       
   366 //
       
   367 // In:
       
   368 //  aField		- the field type
       
   369 //  aStartIndex	- the index to search from (defaults to the buffer start)
       
   370 //
       
   371 // Out:
       
   372 //  aDesc - a pointer-type descriptor into the response buffer at the
       
   373 //			position where the field was located. The caller must NOT
       
   374 //			modify the descriptor contents
       
   375 //
       
   376 // Rtn: TBool - set to ETrue if the field was found, EFalse otherwise
       
   377 //
       
   378 
       
   379 TBool CHTTPResponse::FindBinaryDescField(THttpHeaderField aField,
       
   380 										 TPtrC8& aDesc,
       
   381 										 TInt aStartIndex) const
       
   382     {
       
   383     TInt index = LocateField(aField, aStartIndex);
       
   384     if (index >= 0)
       
   385         {
       
   386 		TInt offset = 0;
       
   387 		TInt fieldLength = iResponse->Des()[index];	// assume the length is in
       
   388 													// a short integer
       
   389 		if(fieldLength == 31)
       
   390 			{
       
   391 			// Nope : Code 31 indicates that the following bytes make a
       
   392 			// UIntVar,  which indicates the number of data octets after it. 
       
   393 			// The UIntVar itself could be composed of upto 5 bytes
       
   394 			// Copy a full 5 bytes from the header
       
   395 			// Note that actually fewer might have been used; 
       
   396 			// the UIntVar to Int converter function returns the exact number 
       
   397 			// that were used.
       
   398 			TInt consumed = ParseUIntVar(iResponse->Des().Mid(index + 1), fieldLength);
       
   399 
       
   400 			__ASSERT_DEBUG( consumed >= KErrNone, User::Invariant() );
       
   401 			
       
   402 			offset += consumed;			
       
   403 			}
       
   404         else if (fieldLength > 127)
       
   405 			{
       
   406  			// Oops be sneaky and reuse this single byte
       
   407  			// Because this is a special code
       
   408  			fieldLength = 1;		
       
   409  			offset = -1;
       
   410  			}
       
   411 
       
   412 		if(fieldLength)
       
   413             {
       
   414             aDesc.Set(&(iResponse->Des()[index + offset + 1]), fieldLength);
       
   415 #ifdef _DEBUG
       
   416 			DumpToLog(aDesc);
       
   417 #endif
       
   418             return ETrue;
       
   419             }
       
   420         }
       
   421     return EFalse;
       
   422     }
       
   423 
       
   424 
       
   425 // Method to find a named field, that returns an EPOC date/time structure.
       
   426 //
       
   427 // In:
       
   428 //  aField		- the field type
       
   429 //  aStartIndex	- the index to search from (defaults to the buffer start)
       
   430 //
       
   431 // Out:
       
   432 //  aTime - a structure containing the time (and date) found in the header
       
   433 //
       
   434 // Rtn: TBool - set to ETrue if the field was found, EFalse otherwise
       
   435 //
       
   436 
       
   437 TBool CHTTPResponse::FindField(THttpHeaderField aField,
       
   438 							   TTime& aTime,
       
   439 							   TInt aStartIndex) const
       
   440     {
       
   441 	//__LOG_ENTER(_L("CHTTPResponse::FindField (time)"));
       
   442 	TBool result = EFalse;
       
   443     TInt index = LocateField(aField, aStartIndex);
       
   444     if (index > 0)
       
   445         {
       
   446  		TPtr8 respChars  = iResponse->Des();
       
   447    		ExtractFieldDateValue(respChars,index,aTime);
       
   448 		result = ETrue;
       
   449         }
       
   450 	//__LOG_RETURN;
       
   451     return result;
       
   452     }
       
   453 
       
   454 
       
   455 // Method to find a named field within the Cache Control header
       
   456 //
       
   457 // In:
       
   458 //  aField		- the field type
       
   459 //
       
   460 // Out:
       
   461 //
       
   462 // Rtn: TBool - set to ETrue if the field was found, EFalse otherwise
       
   463 //
       
   464 
       
   465 TBool CHTTPResponse::FindCacheControlFieldValue(TCacheControlFieldValue aField) const
       
   466 	{
       
   467 	TPtrC8 cacheControl;
       
   468 	return FindCacheControlFieldValue(aField,cacheControl) != KErrNotFound;
       
   469 	}
       
   470 
       
   471 
       
   472 // Method to find a named field within the Cache Control header, 
       
   473 // that returns an EPOC date/time structure.
       
   474 //
       
   475 // In:
       
   476 //  aField		- the field type
       
   477 //
       
   478 // Out:
       
   479 //  aTime - a structure containing the time (and date) found in the header
       
   480 //			field
       
   481 //
       
   482 // Rtn: TBool - set to ETrue if the field was found, EFalse otherwise
       
   483 //
       
   484 
       
   485 TBool CHTTPResponse::ExtractCacheControlTime(TCacheControlFieldValue aField,
       
   486 											 TTime& aTime) const
       
   487 	{
       
   488 	//__LOG_ENTER(_L("CHTTPResponse::ExtractCacheControlTime"));
       
   489 	__ASSERT_DEBUG(aField == ECacheCtrlMaxAge || aField == ECacheCtrlMaxStale
       
   490 						|| aField == ECacheCtrlMinFresh, User::Invariant());
       
   491 	TBool result = EFalse;
       
   492 	TPtrC8 cacheControl;
       
   493 	aTime = 0;
       
   494 	TInt index = FindCacheControlFieldValue(aField, cacheControl);
       
   495 	if(index != KErrNotFound)
       
   496 		{
       
   497 		// Have the cache control and the field position
       
   498 		// Now we need to extract the field's delta-secs value
       
   499 		index++;
       
   500 		TInt time = 0;
       
   501 		TPtrC8 integerSource = cacheControl.Mid(index);
       
   502 
       
   503 		if(integerSource[0] >= 0x80)			// Short integer value
       
   504 			time = integerSource[0] & 0x7F;
       
   505 		else								// Otherwise its multi octet
       
   506 			ExtractMultiOctetInteger(time, integerSource);
       
   507 		
       
   508 		TTimeIntervalSeconds timeSeconds(time);
       
   509 		aTime += timeSeconds;			// Store the seconds in the time field
       
   510 		result = ETrue;
       
   511 		}
       
   512 	//__LOG_RETURN;
       
   513 	return result;
       
   514 	}
       
   515 
       
   516 
       
   517 // Method to search for the content type encoded in the response header
       
   518 //
       
   519 // Out:
       
   520 //  aDesc - a pointer-type descriptor into the appropriate element of an
       
   521 //			array prefilled with all the content types that have WSP
       
   522 //			encodings. e.g. "text/vnd.wap.wml".  The contents of the
       
   523 //			descriptor must NOT be modified.
       
   524 //
       
   525 
       
   526 void CHTTPResponse::ContentType(TPtrC8& aDesc) const
       
   527     {
       
   528 	// Decode the content-type data as per the WSP bnf...
       
   529 	// Note - There is no provision available here to handle content-type parameters
       
   530 	// so parameters are ignored here.
       
   531 	TInt error = LocateField(EHttpContentType);
       
   532 	TInt token = 0;
       
   533 	TBool isString = EFalse;
       
   534 	if (error != KErrNotFound)
       
   535 		{
       
   536 		TPtrC8 respChars(*iResponse);
       
   537 		TWspPrimitiveDecoder wspDecoder(respChars);
       
   538 		TWspPrimitiveDecoder::TWspHeaderType type = wspDecoder.VarType();
       
   539 		switch(type)
       
   540 			{
       
   541 			case TWspPrimitiveDecoder::E7BitVal:
       
   542 				{
       
   543 				// 128-255 - encoded 7 bit value, this header has no more data
       
   544 				TUint8 byteCode = 0;
       
   545 				error = wspDecoder.Val7Bit(byteCode); // error code
       
   546 				token = static_cast<TInt>(byteCode);
       
   547 				} break;
       
   548 			case TWspPrimitiveDecoder::EString:
       
   549 				{
       
   550 				// 32-127 - value is a text string, terminated by a '\0' 
       
   551 				// Content type is embedded as a text string
       
   552 				error = wspDecoder.String(aDesc); // error code
       
   553 				isString = ETrue;
       
   554 				} break;
       
   555 			case TWspPrimitiveDecoder::ELengthVal:
       
   556 				{
       
   557 				// 0-31 -  octet is a value length
       
   558 				TInt dataLength = 0;
       
   559 				error = wspDecoder.LengthVal(dataLength);
       
   560 				if( error >= KErrNone )
       
   561 					{
       
   562 					type = wspDecoder.VarType();
       
   563 					if( type == TWspPrimitiveDecoder::E7BitVal || type == TWspPrimitiveDecoder::ELengthVal )
       
   564 						{
       
   565 						TUint32 contentTypeToken = 0;
       
   566 						error = wspDecoder.Integer(contentTypeToken);
       
   567 						token = static_cast<TInt>(contentTypeToken);
       
   568 						}
       
   569 					else if( type == TWspPrimitiveDecoder::EString )
       
   570 						{
       
   571 						error = wspDecoder.String(aDesc);
       
   572 						isString = ETrue;
       
   573 						}
       
   574 					}
       
   575 
       
   576 				} break;
       
   577 			default:
       
   578 				{
       
   579 				error = KErrNotFound;
       
   580 				} break;
       
   581 			}
       
   582 		}
       
   583 
       
   584 	if(error < KErrNone)
       
   585 		token = KErrNotFound;
       
   586 
       
   587 	// Look up the appropriate content type, provided an error hasn't occurred or the string
       
   588 	// has not already been set
       
   589 	if (token == KErrNotFound || !isString)
       
   590 		{
       
   591 		// Convert the content type string to the supplied descriptor
       
   592 		const TText8* type = ContentType(token);
       
   593 		aDesc.Set(TPtrC8(type));
       
   594 //		__LOG1(_L("CHTTPResponse::ContentType : contentIndex = %d"), contentIndex);
       
   595 		}
       
   596 
       
   597 	}
       
   598 
       
   599 
       
   600 // Method to search for the realm encoded in the response header, when the
       
   601 // response challenges the client for HTTP authentication (code 401)
       
   602 //
       
   603 // Out:
       
   604 //  aDesc - a pointer-type descriptor into the response header buffer
       
   605 //			positioned at the realm string within the challenge. The
       
   606 //			contents of the descriptor must NOT be modified.
       
   607 //
       
   608 // Rtn: TBool - set to ETrue if a WWWAuthenticate header was found, EFalse
       
   609 //				otherwise
       
   610 //
       
   611 
       
   612 TBool CHTTPResponse::FindRealm(TPtrC8& aRealm) const
       
   613     {
       
   614 	//__LOG_ENTER(_L("CHTTPResponse::FindRealm"));
       
   615 	// Search for the WWWAuthenticate field
       
   616 	TPtrC8 realmPtr(aRealm);
       
   617     TBool retVal = FindField(EHttpWWWAuthenticate, realmPtr, 0);
       
   618     if (retVal)
       
   619         {
       
   620 		// realmPtr now points to the WWWAuthentication field value. This contains the Authentication scheme, realm
       
   621 		// value and optional parameters. Check authentication is Basic (encoded as 0x80). This is stored in the
       
   622 		// second byte of the header value (i.e. index [1]).
       
   623 		if (realmPtr[1] == 0x80)
       
   624 			{
       
   625 			// Set the realm descriptor passed in
       
   626             aRealm.Set(realmPtr.Mid(2));
       
   627 #ifdef _DEBUG
       
   628 			// In debug builds, convert the 8-bit realm to 16-bit UNICODE in order to log it.
       
   629 			HBufC16* aRealm16 = HBufC16::New(aRealm.Length());
       
   630 			if(aRealm16!=NULL)
       
   631 				{
       
   632 				TPtr16 aRealm16_Ptr = aRealm16->Des();
       
   633 				aRealm16_Ptr.Copy(aRealm);
       
   634 				//__LOG1(_L("CHTTPResponse::FindRealm : found realm string: %S"), &aRealm16_Ptr);
       
   635 				delete aRealm16;
       
   636 				}
       
   637 #endif
       
   638 			}
       
   639 		else
       
   640 			{
       
   641 			//__LOG(_L("CHTTPResponse::FindRealm : nothing found"));
       
   642 			retVal = EFalse;
       
   643 			}
       
   644 		}
       
   645 	//__LOG_RETURN;
       
   646     return retVal;
       
   647     }
       
   648 
       
   649 
       
   650 // Method to search for the character set encoded in the Content-Type field of
       
   651 // the response header
       
   652 //
       
   653 // Out:
       
   654 //  aDesc - a pointer-type descriptor into the appropriate element of an
       
   655 //			array prefilled with all the character sets that have WSP
       
   656 //			encodings. e.g. "utf-8".  The contents of the descriptor must
       
   657 //			NOT be modified.
       
   658 //
       
   659 // Rtn: TBool - set to ETrue if a character set was found, EFalse if not
       
   660 //
       
   661 
       
   662 TBool CHTTPResponse::CharSet(TPtrC8& aDesc) const
       
   663     {
       
   664 //	__LOG_ENTER(_L("CHTTPResponse::CharSet"));
       
   665 	// Find the byte index in the header for the content type value
       
   666     TInt index = LocateField(EHttpContentType);
       
   667 
       
   668     TUint8 byteCode = 0;
       
   669 	TInt paramByteCode = KErrNotFound;
       
   670 	TInt valueByteCode1 = KErrNotFound;
       
   671 	TInt charsetCode = 0;
       
   672 	// Read the byte code, unless KErrNotFound was returned
       
   673 	if (index != KErrNotFound)
       
   674 		{
       
   675 		TPtr8 respChars = iResponse->Des();
       
   676 		TInt respLength = iResponse->Length();
       
   677 
       
   678 		// If the byteCode is in the range 0-30 then a range of bytes is
       
   679 		// indicated: the following byte gives the content type and the
       
   680 		// remainder are arranged as a series of parameter attribute-value
       
   681 		// pairs. This method checks for the presence of a 'charset' parameter.
       
   682 		byteCode = respChars[index];
       
   683 //		__LOG1(_L("CHTTPResponse::CharSet : found bytecode = %d"), byteCode);
       
   684 
       
   685 		// Check valid range ... note that a range of zero could not contain a charset
       
   686 		// parameter anyway, so exclude it...
       
   687 		if ((byteCode > 0) && (byteCode <= 30))
       
   688 			{
       
   689 			// Check for overrun... if this occurs it should be an error.  Note that
       
   690 			// corruption _could_ occur in this response buffer - some gateways, which
       
   691 			// don't return error decks (e.g. AnyTime GW) send a response buffer 1 byte
       
   692 			// long, containing only the value 0x01 - which is invalid WSP.
       
   693 			// Be conservative and safe here - we can't overrun.  Use the value of byte-
       
   694 			// -Code (which should be the WSP encoding of how many bytes follow), or the
       
   695 			// total length of the response - whichever is smaller.
       
   696 			if (index + byteCode < respLength)
       
   697 				{
       
   698 				// e,g, header to illustrate use of offsets in this code:
       
   699 				// 03 94 81 84 : Content-Type: application/vnd.wap.wmlc; charset=iso-8859-1
       
   700 				// +0 +1 +2 +3 : 03 = no. bytes in Content-Type header
       
   701 				//			   : 94 = 14 | 80 = application/vnd.wap.wmlc
       
   702 				//			   : 81 = 01 | 80 = Charset parameter
       
   703 				//			   : 84 = 04 | 80 = iso-8859-1
       
   704 				paramByteCode = respChars[index + 2];
       
   705 
       
   706 				if ((paramByteCode & 0x7f) == EHttpCharset)
       
   707 					{
       
   708 					// We have a charset
       
   709 					paramByteCode &= 0x7f;
       
   710 					valueByteCode1 = respChars[index + 3];
       
   711 
       
   712 					if (valueByteCode1 & 0x80)
       
   713 						{
       
   714 						// A short one-byte value
       
   715 						charsetCode = valueByteCode1 & 0x7f;
       
   716 						}
       
   717 					else
       
   718 						{
       
   719 						// A multibyte value
       
   720 						ExtractMultiOctetInteger(charsetCode, 
       
   721 												 respChars.Mid(index + 3));
       
   722 						}
       
   723 					}
       
   724 				}
       
   725 			else
       
   726 				{
       
   727 				index = KErrNotFound;
       
   728 				}
       
   729 			}
       
   730 		}
       
   731 
       
   732 	// If a parameter-value pair was found, determine whether it encodes a
       
   733 	// charset
       
   734 	if ( (index != KErrNotFound) && (paramByteCode == EHttpCharset) )
       
   735 		{
       
   736 		// Look up the value from the charset table.
       
   737 		const TText8* chset;
       
   738 		chset = CharSet(charsetCode);
       
   739 
       
   740 		// Convert the charset string to the supplied descriptor
       
   741 		if (chset)
       
   742 			aDesc.Set(TPtrC8(chset));
       
   743 		else
       
   744 			index = KErrNotFound; // We've found a charset but we don't recognise it
       
   745 		}
       
   746 	else	// Either no content-type header (hence no charset) or a content-type
       
   747 			// header with a parameter other than charset
       
   748 		{
       
   749 		index = KErrNotFound;
       
   750 		}
       
   751 
       
   752 //	__LOG1(_L("CHTTPResponse::CharSet : CharSet = %S"), &aDesc);
       
   753 //	__LOG_RETURN;
       
   754 	return (index !=KErrNotFound);
       
   755     }
       
   756 
       
   757 
       
   758 // Normal constructor - do non-allocating creation of this class
       
   759 //
       
   760 
       
   761 CHTTPResponse::CHTTPResponse()
       
   762 	: iStatusCode(EHttpUnknown), iDetailedStatusCode(EHttpUnknown)
       
   763     {
       
   764 	// Does nothing here
       
   765     }
       
   766 
       
   767 
       
   768 // Second phase construction - any allocation for this class must take place
       
   769 // here. Sets up the resources required by an HTTP Response.
       
   770 //
       
   771 
       
   772 void CHTTPResponse::ConstructL()
       
   773     {
       
   774     // Does nothing
       
   775 	//__OPEN_LOG(__LOG_WAP_FILE_NAME); 
       
   776     }
       
   777 
       
   778 
       
   779 // Method to locate a named field in the response header, starting at the
       
   780 // specified index position.
       
   781 //
       
   782 // In:
       
   783 //  aField		- the header field type
       
   784 //  aStartIndex - the (optional) position in the header to start searching
       
   785 //
       
   786 // Rtn: TInt - the index position of the required field _value_ (not the
       
   787 //             field name), or KErrNotFound otherwise.
       
   788 //
       
   789 
       
   790 TInt CHTTPResponse::LocateField(THttpHeaderField aField,
       
   791 								TInt aStartIndex) const
       
   792     {
       
   793 	// Content-Type is a special case; it appears to always be at the first
       
   794 	// byte of the header, and doesn't have any encoding of the field name -
       
   795 	// just straight into the Field Value at byte 0.  This is an assumption
       
   796 	// however, since the WSP spec is not explicit - could it possibly be just
       
   797 	// the NWSS GW's implementation of WSP that does this?
       
   798 	if ( (aStartIndex == 0) && (aField == EHttpContentType) )
       
   799 		{
       
   800 		return aStartIndex; // the content-type field value position - ie. 0
       
   801 		}
       
   802 	
       
   803 	// Deal with other Field Names, (Possibly including Content-Type if the
       
   804 	// start index is offset into the header? Note that this is not likely to
       
   805 	// occur though, with the abbreviated encoding.)
       
   806 	TInt respLength = iResponse->Length();
       
   807 	TPtr8 respChars  = iResponse->Des();
       
   808     for (TInt index = aStartIndex; index < respLength; index++)
       
   809         {
       
   810 		// Examine the byte at this position in the header
       
   811         TUint8 byteCode = respChars[index];
       
   812 
       
   813 		// Expect byteCode to be a Field Name code (unless the search is at
       
   814 		// position zero, which has a missing content-type field name). Check
       
   815 		// for the search field, remembering to clear the top bit
       
   816         if ( ( (byteCode & 0x7f) == aField) && (index != 0) )
       
   817             {
       
   818 			// Got it - return the next position to locate the field value,
       
   819 			// checking for potential overrun
       
   820 			if (index < respLength - 1)
       
   821 				{
       
   822 				// Advance 1 to the header field value
       
   823 				++index;
       
   824 				return index;
       
   825 				}
       
   826 			else
       
   827 				{
       
   828 				return KErrNotFound;
       
   829 				}
       
   830             }
       
   831         else
       
   832             {
       
   833 			// Check that we aren't dealing with the Content-Type field
       
   834 			// (expected at position 0), since it doesn't use a field type
       
   835 			if (index != 0)
       
   836 				{
       
   837 				// WSP Spec Section 8.4.1.1 - Field Names
       
   838 				//
       
   839 				// If the byte is an alphanumeric, then it must be a field name that doesn't have
       
   840 				// a WSP encoding.  In this circumstance, we can't handle the field, and must
       
   841 				// therefore skip over it
       
   842 				if ((byteCode >= 32) && (byteCode <= 127))
       
   843 					{
       
   844 					// Hit the start of a Header Name string - this will be assumed
       
   845 					// continuous until the NUL is found or until the end
       
   846 					// of the header is hit (which would be an error)
       
   847 					while ( (respChars[index] != 0) && (index < respLength - 1) )
       
   848 						++index;
       
   849 					}
       
   850 
       
   851 				// WSP Spec Section 8.4.1.2 - Field Values
       
   852 				//
       
   853 				// Now examine the field value by advancing one place.  If that advance takes us off
       
   854 				// the end of the buffer, then (a) the WSP is invalid, and (b) the field is not found!
       
   855 				++index;
       
   856 				if (index == respLength)
       
   857 					return KErrNotFound;
       
   858 				}
       
   859 
       
   860 			// Read the next byte at this position in the header
       
   861             byteCode = respChars[index];
       
   862 
       
   863 			// Codes 0-30 represent that number of following data octets, so
       
   864 			// they should be skipped
       
   865 			if (byteCode == 0)			// 0 data octets follow !???? : (Strange but true)
       
   866 				{
       
   867 				// __DEBUGGER();
       
   868 				}
       
   869             else if (byteCode <= 30)
       
   870 				{
       
   871                 index += byteCode;
       
   872 				}
       
   873             else
       
   874                 {
       
   875 				// Code 31 indicates that the following bytes make a UIntVar,
       
   876 				// which indicates the number of data octets after it. The
       
   877 				// UIntVar itself could be composed of upto 5 bytes
       
   878                 if (byteCode == 31)
       
   879 					{
       
   880 					// Copy a full 5 bytes from the header - note that actually
       
   881 					// fewer might have been used; the UIntVar to Int
       
   882 					// converter function returns the exact number that were
       
   883 					// used.
       
   884 					TInt value = 0;
       
   885 					TInt consumed = ParseUIntVar(respChars.Mid(index + 1), value);
       
   886 					
       
   887 					if( consumed < KErrNone )
       
   888 						return KErrCorrupt;
       
   889 
       
   890 					// Advance to the last byte of data in this header
       
   891                     index += consumed + value;
       
   892 					}
       
   893                 else
       
   894 					// Codes 32-127 are alphanumerics representing a text
       
   895 					// string, up to a NUL termination
       
   896                     if (byteCode <= 127)
       
   897 						// Hit the start of a string - this will be assumed
       
   898 						// continuous until the NUL is found or until the end
       
   899 						// of the header is hit (which would be an error)
       
   900                         while ( (respChars[index] != 0) && (index < respLength - 1) )
       
   901 							++index;
       
   902                 }
       
   903             }
       
   904         }
       
   905 
       
   906 	// This return only occurs if the search ran off the end of the header
       
   907     return KErrNotFound;
       
   908     }
       
   909 
       
   910 
       
   911 // Perform a look-up of content type given a WSP encoding value, used as
       
   912 // an index.
       
   913 //
       
   914 // In:
       
   915 //  aIndex - the WSP encoding value
       
   916 //
       
   917 // Rtn: const TText* - the required content type text - NOT to be changed
       
   918 //
       
   919 
       
   920 const TText8* CHTTPResponse::ContentType(TInt aContentTypeCode) const
       
   921     {
       
   922 
       
   923     if ((aContentTypeCode >= 0) && (aContentTypeCode < KHttpNumContentTypes))
       
   924         return KHttpContentTypes[aContentTypeCode];
       
   925     else
       
   926         return defaultType;
       
   927     }
       
   928 
       
   929 
       
   930 // Perform a look-up of character set given a WSP encoding value, used as
       
   931 // an index.
       
   932 //
       
   933 // In:
       
   934 //  aCharsetCode - the index into the content types table/
       
   935 //
       
   936 // Rtn: const TText8* - the required 8-bit character set text - NOT to be
       
   937 //						changed by the caller
       
   938 //
       
   939 
       
   940 const TText8* CHTTPResponse::CharSet(TInt aCharSetCode) const
       
   941     {
       
   942 	// Search for an index for the supplied charset code
       
   943 	TInt charSetIdx = KErrNotFound;
       
   944 	for (TInt index = 0; ((index < KHttpNumCharacterSets) &&
       
   945 									(charSetIdx == KErrNotFound)); index++)
       
   946 		{
       
   947 		if (KHttpCharacterSetCodes[index] == aCharSetCode)
       
   948 			{
       
   949 			charSetIdx = index;
       
   950 			}
       
   951 		}
       
   952 
       
   953 	// If something was found, return the corresponding charset name
       
   954 	if (charSetIdx != KErrNotFound)
       
   955 		return KHttpCharacterSetNames[charSetIdx];
       
   956 	else
       
   957 		return NULL;
       
   958     }
       
   959 
       
   960 
       
   961 // Do a conversion from 32-bit UIntVar encoding into 32-bit integer
       
   962 //
       
   963 TInt CHTTPResponse::ParseUIntVar(const TDesC8& aBuffer, TInt& aVal) const
       
   964 	{
       
   965 	// Is there any buffer?
       
   966 	const TInt length = aBuffer.Length();
       
   967 	if( length == 0 )
       
   968 		return KErrCorrupt;
       
   969 
       
   970 	// initialize return val
       
   971 	aVal = 0;
       
   972 
       
   973 	// maximum length for a uintvar is 5
       
   974 	TInt lenLeft = Min(length, 5);
       
   975 
       
   976 	// get the first octet
       
   977 	TInt index = 0;
       
   978 	TUint8 byte = aBuffer[index++];
       
   979 	TInt numBytes = 1;
       
   980 
       
   981 	--lenLeft;	
       
   982 
       
   983 	// Check if any of the top 3 bits, ignoring the very top 'continue' bit, are set.  
       
   984 	// Later if we see that this is a 5 byte number - we'll know it is corrupt.  
       
   985 	// Encoding uses 7 bits/number 7x5=35 and we only support a maxiumum number 
       
   986 	// of 32 bits.
       
   987 	TBool topThreeBitsSet = byte & KTop3BitSet; 
       
   988 	
       
   989 	// copy over data from the byte into our return value (the top bit is a carry bit)
       
   990 	aVal = byte & KWapQuote;
       
   991 
       
   992 	// while the 'continue' bit is set and we have more data
       
   993 	while ((byte & KCarryBitMask) && (lenLeft > 0))
       
   994 		{
       
   995 		// shift our last value up
       
   996 		aVal <<= 7;
       
   997 		// get the next byte
       
   998 		byte = aBuffer[index++];
       
   999 		// copy it over to the lowest byte
       
  1000 		aVal |= byte & KWapQuote;
       
  1001 		--lenLeft;
       
  1002 		++numBytes;
       
  1003 		} 
       
  1004 
       
  1005 	// last octet has continue bit set ... NOT allowed Or
       
  1006 	// this was encoded wrong - can't have a number bigger than 32 bits
       
  1007 	if ((byte & KCarryBitMask) || (numBytes == 5 && topThreeBitsSet))
       
  1008 		return KErrCorrupt;
       
  1009 
       
  1010 	// number of bytes read
       
  1011 	return numBytes;
       
  1012 	}
       
  1013 
       
  1014 
       
  1015 // Extract a WSP encoded MultiOctet Integer encoding into 32-bit integer
       
  1016 //
       
  1017 // In:
       
  1018 //  aSource	- the source Multi-Octet integer
       
  1019 //
       
  1020 // Out:
       
  1021 //  aInt		- the 32-bit resulting integer
       
  1022 //
       
  1023 void CHTTPResponse::ExtractMultiOctetInteger(TInt& aInt, const TPtrC8& aSource) const
       
  1024  	// Extract a WSP encoded integer from the source descriptor
       
  1025 	{
       
  1026 	//__LOG_ENTER(_L("CHTTPResponse::ExtractMultiOctetInteger"));
       
  1027 	// Get num bytes encoding the integer - 
       
  1028 	// we are positioned at that location in the source descriptor
       
  1029 	TUint8 numBytes = aSource[0];
       
  1030 	aInt = 0;
       
  1031 	if (numBytes <= 30)
       
  1032  		{
       
  1033  		__ASSERT_DEBUG(numBytes <= aSource.Length(), User::Invariant());
       
  1034  		// Loop over the source, taking each byte and shifting it in to the count.
       
  1035  		for (TInt count = 1; (count <= numBytes); count++)
       
  1036  		        aInt = (aInt << 8) + aSource[count];
       
  1037  		}
       
  1038  	else if (numBytes & 0x80) //  check top bit is set
       
  1039  		aInt = numBytes & 0x7f;
       
  1040  	// anything between 30 and 127 is not handled...
       
  1041 	//__LOG_RETURN;
       
  1042 	}
       
  1043 
       
  1044 
       
  1045 // Method to find a named field within the Cache Control header
       
  1046 //
       
  1047 // In:
       
  1048 //  aSource		- the descriptor containing the date value
       
  1049 //	aFrom		- The position in the descriptor to start from
       
  1050 //
       
  1051 // Out:
       
  1052 //  aTime - a structure containing the time (and date) found in the descriptor
       
  1053 //
       
  1054 // NOTE THIS METHOD WAS EXPORTED FOR TESTING OF THE CACHE. IT SHOULDN'T BE
       
  1055 // NOW, BUT CAN'T BE CHANGED SINCE IT WOULD AFFECT BC.
       
  1056 void CHTTPResponse::ExtractFieldDateValue(const TPtrC8& aSource,
       
  1057 										  TInt aFrom,
       
  1058 										  TTime& aTime) const
       
  1059 	{
       
  1060 	//__LOG_ENTER(_L("CHTTPResponse::ExtractFieldDateValue"));
       
  1061 	// Get num bytes encoding the date - 
       
  1062 	// we are positioned at that location in the source descriptor
       
  1063     TInt time = 0;
       
  1064 	TPtrC8 integerSource = aSource.Mid(aFrom);
       
  1065 	ExtractMultiOctetInteger(time, integerSource);
       
  1066 	// The WSP Date encoding is the number of seconds since the start of the
       
  1067 	// UNIX epoch (00:00:00.000, 01-Jan-1970), as a long integer
       
  1068 	TDateTime unixEpocDT(1970, EJanuary, 0, 0, 0, 0, 0);
       
  1069 	TTime unixEpoch(unixEpocDT);
       
  1070     TTimeIntervalSeconds timeSeconds(time);
       
  1071     aTime = unixEpoch + timeSeconds;
       
  1072 	//__LOG_RETURN;
       
  1073 	}
       
  1074 
       
  1075 
       
  1076 // Method to find a named field within the Cache Control header
       
  1077 //
       
  1078 // In:
       
  1079 //  aField		- the field type
       
  1080 //
       
  1081 // Out:
       
  1082 //	the found aCacheControl string
       
  1083 //
       
  1084 // Rtn: TInt - set to KErrNotFound if the field was not found,
       
  1085 //		otherwise the position in the cache control descriptor that the field
       
  1086 //		was found
       
  1087 //
       
  1088 TInt CHTTPResponse::FindCacheControlFieldValue(TCacheControlFieldValue aField,
       
  1089 											   TPtrC8& aCacheControl) const
       
  1090 // Find a named field within the Cache Control header
       
  1091 	{
       
  1092 	//__LOG_ENTER(_L("CHTTPResponse::FindCacheControlFieldValue"));
       
  1093 	TInt pos = KErrNotFound;
       
  1094 	TInt index = LocateField(EHttpCacheControl, 0);
       
  1095     if (index >0)
       
  1096         {
       
  1097 		// Have the cache control descriptor
       
  1098 		// Now we need to search for the field
       
  1099 
       
  1100 		// The following rules are used to encode cache control values.
       
  1101 		// Cache-control-value	=	No-cache | No-store | Max-stale |
       
  1102 		//							Only-if-cached | Private | Public |
       
  1103 		//							No-transform | Must-revalidate | 
       
  1104 		//							Proxy-revalidate | Cache-extension | 
       
  1105 		//							Value-length Cache-directive
       
  1106 		// Cache-directive	=	No-cache 1*(Field-name) | 
       
  1107 		//						Max-age Delta-second-value |
       
  1108 		//						Max-stale Delta-second-value |
       
  1109 		//						Min-fresh Delta-second-value |
       
  1110 		//						Private 1*(Field-name) |
       
  1111 		//						Cache-extension Parameter
       
  1112 		TUint8 byteCode = iResponse->Des()[index];		// check the first byte for a recognised value
       
  1113 		if((byteCode >= 32) && (byteCode <= 127))
       
  1114 			{
       
  1115 			// Hit the start of a Header Name string - this will be assumed
       
  1116 			// continuous until the NUL is found or until the end
       
  1117 			// of the header is hit (which would be an error)
       
  1118 			// - not supported
       
  1119 			return pos;				
       
  1120 			}
       
  1121 		switch (byteCode)
       
  1122 			{
       
  1123 			case ECacheControlNoCache:		// "no-cache"
       
  1124 			case ECacheCtrlNoStore:			// "no-store"
       
  1125 			case ECacheCtrlMaxStale:		// "max-stale"
       
  1126 			case ECacheCtrlOnlyIfCached:	// "only-if-cached"
       
  1127 			case ECacheCtrlPublic:			// "public"
       
  1128 			case ECacheCtrlPrivate:			// "private"
       
  1129 			case ECacheCtrlNoTransform:		// "no-transform"
       
  1130 			case ECacheCtrlMustRevalidate:	// "must-revalidate"
       
  1131 			case ECacheCtrlProxyRevalidate:	// "proxy-revalidate"
       
  1132 				if( aField == byteCode )
       
  1133 					pos = index;			// Right here (right now).
       
  1134 				break;
       
  1135 			case ECacheCtrlCacheExtension:	// "cache-extension":
       
  1136 				break;						// Not handled
       
  1137 			default:
       
  1138 				{
       
  1139 			// Value-length Cache-directive
       
  1140 				if(FindBinaryDescField(EHttpCacheControl,aCacheControl))
       
  1141 					{
       
  1142 					TInt respLength = aCacheControl.Length();
       
  1143 					TUint8 byteCode = 0;
       
  1144 					for (TInt count = 0; count < respLength; count++)
       
  1145 						{
       
  1146 						byteCode = aCacheControl[count];
       
  1147 						if(aField == byteCode)
       
  1148 							{
       
  1149 							// Found the field we are looking for
       
  1150 							pos = count;
       
  1151 							break;
       
  1152 							}
       
  1153 						else if(count < (respLength - 1))	// Check for overrun... if this occurs it should be an error
       
  1154 							{
       
  1155 							if (byteCode <= 30)
       
  1156 								{
       
  1157 								// Codes 0-30 represent that number of following data
       
  1158 								// octets, check the cache directive field after the length
       
  1159 								if(aField == aCacheControl[count + 1])
       
  1160 									{
       
  1161 									// Found the one we want
       
  1162 									pos = count + 1;
       
  1163 									break;
       
  1164 									}
       
  1165 								else if(byteCode)
       
  1166 									{
       
  1167 									// so the following data octets should be skipped
       
  1168 									count += byteCode;
       
  1169 									}
       
  1170 								else
       
  1171 									{
       
  1172 									__DEBUGGER();
       
  1173 									count++;	// 0 data octets follow !???? : (Strange but true)
       
  1174 									}
       
  1175 								}
       
  1176 							else if (byteCode == 31)
       
  1177 								{
       
  1178 								// Code 31 indicates that the following bytes make a
       
  1179 								// UIntVar,  which indicates the number of data octets
       
  1180 								// after it. 
       
  1181 								// The UIntVar itself could be composed of upto 5 bytes
       
  1182 								// Copy a full 5 bytes from the header
       
  1183 								// Note that actually fewer might have been used; 
       
  1184 								// the UIntVar to Int converter function returns the exact
       
  1185 								// number that were used.
       
  1186 								TInt value = 0;
       
  1187 								TInt consumed = ParseUIntVar(aCacheControl.Mid(count + 1), value);
       
  1188 								
       
  1189 								if( consumed < KErrNone )
       
  1190 									return KErrCorrupt;
       
  1191 																
       
  1192 								if(aField == aCacheControl[count + 1 + consumed])
       
  1193 									{
       
  1194 									// Found the one we want
       
  1195 									pos = count + 1 + consumed;
       
  1196 									break;
       
  1197 									}
       
  1198 								else
       
  1199 									{
       
  1200 									// so the following data octets should be skipped
       
  1201 									count += 1 + consumed + value;
       
  1202 									}
       
  1203 								}
       
  1204 							}
       
  1205 						}
       
  1206 					}
       
  1207 				}
       
  1208 				break;
       
  1209 			}
       
  1210 		}
       
  1211 	//__LOG_RETURN;
       
  1212 	return pos;
       
  1213 	}
       
  1214 
       
  1215 
       
  1216 // Panic method
       
  1217 //
       
  1218 // In:
       
  1219 //  aPanicCode - a standard HTTP panic code (see <HttpStd.h>)
       
  1220 //
       
  1221 /*void CHTTPResponse::Panic(THttpPanicCode aPanicCode) const
       
  1222 	{
       
  1223 	_LIT(KWapCHTTPResponse, "CHTTPResp");
       
  1224 	User::Panic(KWapCHTTPResponse, aPanicCode);
       
  1225 	}
       
  1226 */
       
  1227 
       
  1228 #ifdef _DEBUG
       
  1229 // Debug method to dump to log the response header's binary content
       
  1230 //
       
  1231 void CHTTPResponse::DumpToLog(const TDesC8& aData) const
       
  1232     {
       
  1233 //	__LOG_ENTER(_L("CHTTPResponse::DumpToLog"));
       
  1234 
       
  1235 	// Iterate the supplied block of data in blocks of 16 bytes
       
  1236 	//__LOG(_L("CHTTPResponse::DumpToLog : START"));
       
  1237 	TInt pos = 0;
       
  1238 	TBuf<KMaxLogEntrySize> logLine;
       
  1239 	TBuf<KMaxLogEntrySize> anEntry;
       
  1240 	while (pos < aData.Length())
       
  1241 		{
       
  1242 		anEntry.Format(TRefByValue<const TDesC>_L("%04x : "), pos);
       
  1243 		logLine.Append(anEntry);
       
  1244 
       
  1245 		// Hex output
       
  1246 		for (TInt offset = 0; offset < 16; offset++)
       
  1247 			{
       
  1248 			if (pos + offset < aData.Length())
       
  1249 				{
       
  1250 				TInt nextByte = aData[pos + offset];
       
  1251 				anEntry.Format(TRefByValue<const TDesC>_L("%02x "), nextByte);
       
  1252 				logLine.Append(anEntry);
       
  1253 				}
       
  1254 			else
       
  1255 				{
       
  1256 				anEntry.Format(TRefByValue<const TDesC>_L("   "));
       
  1257 				logLine.Append(anEntry);
       
  1258 				}
       
  1259 			}
       
  1260 			anEntry.Format(TRefByValue<const TDesC>_L(": "));
       
  1261 			logLine.Append(anEntry);
       
  1262 
       
  1263 		// Char output
       
  1264 		for (TInt offset = 0; offset < 16; offset++)
       
  1265 			{
       
  1266 			if (pos + offset < aData.Length())
       
  1267 				{
       
  1268 				TInt nextByte = aData[pos + offset];
       
  1269 				if ((nextByte >= 32) && (nextByte <= 127))
       
  1270 					{
       
  1271 					anEntry.Format(TRefByValue<const TDesC>_L("%c"), nextByte);
       
  1272 					logLine.Append(anEntry);
       
  1273 					}
       
  1274 				else
       
  1275 					{
       
  1276 					anEntry.Format(TRefByValue<const TDesC>_L("."));
       
  1277 					logLine.Append(anEntry);
       
  1278 					}
       
  1279 				}
       
  1280 			else
       
  1281 				{
       
  1282 				anEntry.Format(TRefByValue<const TDesC>_L(" "));
       
  1283 				logLine.Append(anEntry);
       
  1284 				}
       
  1285 			}
       
  1286 			//__LOG1(_L("%S"), &logLine);
       
  1287 			logLine.Zero();
       
  1288 
       
  1289 		// Advance to next 16 byte segment
       
  1290 		pos += 16;
       
  1291 		}
       
  1292 	//__LOG(_L("CHTTPResponse::DumpToLog : END"));
       
  1293 //	__LOG_RETURN;
       
  1294     }
       
  1295 #endif
       
  1296 
       
  1297 
       
  1298 // Spare methods for future BC. Const- and non-const versions to assist
       
  1299 // the caller in preserving const-ness. IMPORT_C ensures they reserve a
       
  1300 // slot in the vtbl, which is essential to preseve future BC.
       
  1301 //
       
  1302 /*TAny* CHTTPResponse::Extend_CHTTPResponse(TAny* aArgs)
       
  1303 	{
       
  1304 	Panic(EHttpReservedForFutureExpansion);
       
  1305 	return (TAny*)aArgs;
       
  1306 	}
       
  1307 TAny* CHTTPResponse::Extend_CHTTPResponse_const(TAny* aArgs) const
       
  1308 	{
       
  1309 	Panic(EHttpReservedForFutureExpansion);
       
  1310 	return (TAny*)aArgs;
       
  1311 	}
       
  1312 */