engine/src/HttpEventHandler.cpp
changeset 2 29cda98b007e
child 82 d87e984bd8b8
equal deleted inserted replaced
1:5f8e5adbbed9 2:29cda98b007e
       
     1 /*
       
     2 * Copyright (c) 2007-2010 Sebastian Brannstrom, Lars Persson, EmbedDev AB
       
     3 *
       
     4 * All rights reserved.
       
     5 * This component and the accompanying materials are made available
       
     6 * under the terms of the License "Eclipse Public License v1.0"
       
     7 * which accompanies this distribution, and is available
       
     8 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     9 *
       
    10 * Initial Contributors:
       
    11 * EmbedDev AB - initial contribution.
       
    12 *
       
    13 * Contributors:
       
    14 *
       
    15 * Description:
       
    16 *
       
    17 */
       
    18 
       
    19 // HttpEventHandler.cpp
       
    20 #include <e32debug.h>
       
    21 #include <httperr.h>
       
    22 
       
    23 #include "HttpEventHandler.h"
       
    24 #include "bautils.h"
       
    25 #include "Httpclient.h"
       
    26 
       
    27 void CHttpEventHandler::ConstructL()
       
    28 	{
       
    29 	//iVerbose = ETrue;	
       
    30 	}
       
    31 
       
    32 
       
    33 CHttpEventHandler::CHttpEventHandler(CHttpClient* aClient, MHttpClientObserver &aCallbacks, RFs& aFs): 
       
    34 	iFileServ(aFs), iHttpClient(aClient), iCallbacks(aCallbacks)
       
    35 	{
       
    36 	}
       
    37 
       
    38 
       
    39 CHttpEventHandler::~CHttpEventHandler()
       
    40 	{	
       
    41 	}
       
    42 
       
    43 
       
    44 CHttpEventHandler* CHttpEventHandler::NewLC(CHttpClient* aClient, MHttpClientObserver &aCallbacks, RFs& aFs)
       
    45 	{
       
    46 	CHttpEventHandler* me = new(ELeave)CHttpEventHandler(aClient, aCallbacks, aFs);
       
    47 	CleanupStack::PushL(me);
       
    48 	me->ConstructL();
       
    49 	return me;
       
    50 	}
       
    51 
       
    52 
       
    53 CHttpEventHandler* CHttpEventHandler::NewL(CHttpClient* aClient, MHttpClientObserver &aCallbacks, RFs& aFs)
       
    54 	{
       
    55 	CHttpEventHandler* me = NewLC(aClient, aCallbacks, aFs);
       
    56 	CleanupStack::Pop(me);
       
    57 	return me;
       
    58 	}
       
    59 
       
    60 void CHttpEventHandler::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
       
    61 	{
       
    62 	switch (aEvent.iStatus)
       
    63 		{
       
    64 		case THTTPEvent::EGotResponseHeaders:
       
    65 			{
       
    66 			// HTTP response headers have been received. We can determine now if there is
       
    67 			// going to be a response body to save.
       
    68 			RHTTPResponse resp = aTransaction.Response();
       
    69 			iLastStatusCode = resp.StatusCode();
       
    70 			RStringF statusStr = resp.StatusText();
       
    71 			TBuf<32> statusStr16;
       
    72 			statusStr16.Copy(statusStr.DesC());
       
    73 			DP2("Status: %d (%S)", iLastStatusCode, &statusStr16);
       
    74 
       
    75 			// Dump the headers if we're being verbose
       
    76 			//DumpRespHeadersL(aTransaction);
       
    77 
       
    78 			// Determine if the body will be saved to disk
       
    79 			iSavingResponseBody = ETrue;
       
    80 			TBool cancelling = EFalse;
       
    81 			if (resp.HasBody() && (iLastStatusCode >= 200) && (iLastStatusCode < 300) && (iLastStatusCode != 204))
       
    82 				{
       
    83 				//iBytesDownloaded = 0;
       
    84 				TInt dataSize = resp.Body()->OverallDataSize();
       
    85 				if (dataSize >= 0) {
       
    86 					DP1("Response body size is %d", dataSize);
       
    87 					iBytesTotal = dataSize;	
       
    88 				} else {
       
    89 					DP("Response body size is unknown");
       
    90 					iBytesTotal = -1;
       
    91 				}
       
    92 				iCallbacks.DownloadInfo(iHttpClient, dataSize);
       
    93 
       
    94 				cancelling = EFalse;
       
    95 				}
       
    96 
       
    97 			// If we're cancelling, must do it now..
       
    98 			if (cancelling)
       
    99 				{
       
   100 				DP("Transaction Cancelled");
       
   101 				aTransaction.Close();
       
   102 				iHttpClient->ClientRequestCompleteL(KErrCancel);
       
   103 				}
       
   104 			else if (iSavingResponseBody) // If we're saving, then open a file handle for the new file
       
   105 				{
       
   106 				iFileServ.Parse(iFileName, iParsedFileName);
       
   107 				TInt valid = iFileServ.IsValidName(iFileName);
       
   108 				if (!valid)
       
   109 					{
       
   110 					DP("The specified filename is not valid!.");
       
   111 					iSavingResponseBody = EFalse;
       
   112 					}
       
   113 				else
       
   114 					{
       
   115 					if (iContinue) {
       
   116 						TInt err = iRespBodyFile.Open(iFileServ, iParsedFileName.FullName(),EFileWrite);
       
   117 						if (err)
       
   118 							{
       
   119 							DP("There was an error opening file");
       
   120 							iSavingResponseBody = EFalse;
       
   121 							User::Leave(err);
       
   122 							} else {
       
   123 							int pos = -KByteOverlap;
       
   124 							if((err=iRespBodyFile.Seek(ESeekEnd, pos)) != KErrNone) {
       
   125 								DP("Failed to set position!");
       
   126 								User::Leave(err);
       
   127 							}
       
   128 							iBytesDownloaded = (pos > 0) ? pos : 0;
       
   129 							iBytesTotal += iBytesDownloaded;
       
   130 							DP1("Total bytes is now %u", iBytesTotal);
       
   131 							DP1("Seeking end: %d", pos);
       
   132 							}
       
   133 					} else {
       
   134 						TInt err = iRespBodyFile.Replace(iFileServ,
       
   135 														 iParsedFileName.FullName(),
       
   136 														 EFileWrite);
       
   137 						if (err)
       
   138 							{
       
   139 							DP("There was an error replacing file");
       
   140 							iSavingResponseBody = EFalse;
       
   141 							User::Leave(err);
       
   142 							}
       
   143 						}
       
   144 					}
       
   145 				}
       
   146 
       
   147 			} break;
       
   148 		case THTTPEvent::EGotResponseBodyData:
       
   149 			{
       
   150 			// Get the body data supplier
       
   151 			iRespBody = aTransaction.Response().Body();
       
   152 
       
   153 			// Some (more) body data has been received (in the HTTP response)
       
   154 			//DumpRespBody(aTransaction);
       
   155 			//DP1("Saving: %d", iSavingResponseBody);
       
   156 			// Append to the output file if we're saving responses
       
   157 			if (iSavingResponseBody)
       
   158 				{
       
   159 				TPtrC8 bodyData;
       
   160 				iRespBody->GetNextDataPart(bodyData);
       
   161 				iBytesDownloaded += bodyData.Length();
       
   162 				TInt error = iRespBodyFile.Write(bodyData);
       
   163 				
       
   164 				// on writing error we close connection 
       
   165 				if (error != KErrNone) {
       
   166 					//aTransaction.Close();
       
   167 					iCallbacks.FileError(error);
       
   168 					iHttpClient->ClientRequestCompleteL(error);
       
   169 					return;
       
   170 				}
       
   171 
       
   172 				if (!iSilent) {
       
   173 					iCallbacks.Progress(iHttpClient, iBytesDownloaded, iBytesTotal);
       
   174 				}
       
   175 				}
       
   176 
       
   177 			// Done with that bit of body data
       
   178 			iRespBody->ReleaseData();
       
   179 			} break;
       
   180 		case THTTPEvent::EResponseComplete:
       
   181 			{
       
   182 			// The transaction's response is complete
       
   183 
       
   184 			DP("Transaction Complete");
       
   185 			DP("Closing file");
       
   186 			iRespBodyFile.Close();
       
   187 			} break;
       
   188 		case THTTPEvent::ESucceeded:
       
   189 			{
       
   190 			DP("Transaction Successful");
       
   191 			aTransaction.Close();
       
   192 			iHttpClient->ClientRequestCompleteL(KErrNone);
       
   193 			} break;
       
   194 		case THTTPEvent::EFailed:
       
   195 			{
       
   196 			DP("Transaction Failed");
       
   197 			aTransaction.Close();
       
   198 			
       
   199 			if(iLastStatusCode == HTTPStatus::EOk || iLastStatusCode == HTTPStatus::ECreated || iLastStatusCode == HTTPStatus::EAccepted)
       
   200 				{
       
   201 				iLastStatusCode = KErrNone;
       
   202 				}
       
   203 			
       
   204 			iHttpClient->ClientRequestCompleteL(iLastStatusCode);
       
   205 			} break;
       
   206 		case THTTPEvent::ERedirectedPermanently:
       
   207 			{
       
   208 			DP("Permanent Redirection");
       
   209 			} break;
       
   210 		case THTTPEvent::ERedirectedTemporarily:
       
   211 			{
       
   212 			DP("Temporary Redirection");
       
   213 			} break;
       
   214 		default:
       
   215 			{
       
   216 			DP1("<unrecognised event: %d>", aEvent.iStatus);
       
   217 			// close off the transaction if it's an error
       
   218 			if (aEvent.iStatus < 0)
       
   219 				{
       
   220 				aTransaction.Close();
       
   221 				iHttpClient->ClientRequestCompleteL(aEvent.iStatus);
       
   222 				}
       
   223 			} break;
       
   224 		}
       
   225 	}
       
   226 
       
   227 TInt CHttpEventHandler::MHFRunError(TInt aError, RHTTPTransaction /*aTransaction*/, const THTTPEvent& /*aEvent*/)
       
   228 	{
       
   229 	DP1("MHFRunError fired with error code %d", aError);
       
   230 
       
   231 	return KErrNone;
       
   232 	}
       
   233 
       
   234 void CHttpEventHandler::SetSaveFileName(const TDesC &fName, TBool aContinue)
       
   235 	{
       
   236 	iFileName.Copy(fName);
       
   237 	iContinue = aContinue;
       
   238 	}
       
   239 
       
   240 void CHttpEventHandler::DumpRespHeadersL(RHTTPTransaction& aTrans)
       
   241 	{
       
   242 	RHTTPResponse resp = aTrans.Response();
       
   243 	RStringPool strP = aTrans.Session().StringPool();
       
   244 	RHTTPHeaders hdr = resp.GetHeaderCollection();
       
   245 	THTTPHdrFieldIter it = hdr.Fields();
       
   246 
       
   247 	TBuf<KMaxHeaderNameLen>  fieldName16;
       
   248 	TBuf<KMaxHeaderValueLen> fieldVal16;
       
   249 
       
   250 	while (it.AtEnd() == EFalse)
       
   251 		{
       
   252 		RStringTokenF fieldName = it();
       
   253 		RStringF fieldNameStr = strP.StringF(fieldName);
       
   254 		THTTPHdrVal fieldVal;
       
   255 		if (hdr.GetField(fieldNameStr,0,fieldVal) == KErrNone)
       
   256 			{
       
   257 			const TDesC8& fieldNameDesC = fieldNameStr.DesC();
       
   258 			fieldName16.Copy(fieldNameDesC.Left(KMaxHeaderNameLen));
       
   259 			switch (fieldVal.Type())
       
   260 				{
       
   261 			case THTTPHdrVal::KTIntVal:
       
   262 				DP2("%S: %d", &fieldName16, fieldVal.Int());
       
   263 				break;
       
   264 			case THTTPHdrVal::KStrFVal:
       
   265 				{
       
   266 				RStringF fieldValStr = strP.StringF(fieldVal.StrF());
       
   267 				const TDesC8& fieldValDesC = fieldValStr.DesC();
       
   268 				fieldVal16.Copy(fieldValDesC.Left(KMaxHeaderValueLen));
       
   269 				DP2("%S: %S", &fieldName16, &fieldVal16);
       
   270 				}
       
   271 				break;
       
   272 			case THTTPHdrVal::KStrVal:
       
   273 				{
       
   274 				RString fieldValStr = strP.String(fieldVal.Str());
       
   275 				const TDesC8& fieldValDesC = fieldValStr.DesC();
       
   276 				fieldVal16.Copy(fieldValDesC.Left(KMaxHeaderValueLen));
       
   277 				DP2("%S: %S", &fieldName16, &fieldVal16);
       
   278 				}
       
   279 				break;
       
   280 			case THTTPHdrVal::KDateVal:
       
   281 				{
       
   282 				TDateTime date = fieldVal.DateTime();
       
   283 				} 
       
   284 				break;
       
   285 			default:
       
   286 				DP1("%S: <unrecognised value type>", &fieldName16);
       
   287 				break;
       
   288 				}
       
   289 
       
   290 			// Display realm for WWW-Authenticate header
       
   291 			RStringF wwwAuth = strP.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable());
       
   292 			if (fieldNameStr == wwwAuth)
       
   293 				{
       
   294 				// check the auth scheme is 'basic'
       
   295 				RStringF basic = strP.StringF(HTTP::EBasic,RHTTPSession::GetTable());
       
   296 				RStringF realm = strP.StringF(HTTP::ERealm,RHTTPSession::GetTable());
       
   297 				THTTPHdrVal realmVal;
       
   298 				if ((fieldVal.StrF() == basic) && 
       
   299 					(!hdr.GetParam(wwwAuth, realm, realmVal)))
       
   300 					{
       
   301 					RStringF realmValStr = strP.StringF(realmVal.StrF());
       
   302 					fieldVal16.Copy(realmValStr.DesC());
       
   303 					DP1("Realm is: %S", &fieldVal16);
       
   304 					}
       
   305 				}
       
   306 			}
       
   307 		++it;
       
   308 		}
       
   309 	}
       
   310 
       
   311 void CHttpEventHandler::DumpRespBody(RHTTPTransaction& aTrans)
       
   312 	{
       
   313 	MHTTPDataSupplier* body = aTrans.Response().Body();
       
   314 	TPtrC8 dataChunk;
       
   315 	TBool isLast = body->GetNextDataPart(dataChunk);
       
   316 	DumpIt(dataChunk);
       
   317 	if (isLast)
       
   318 		DP("Got last data chunk.");
       
   319 	}
       
   320 
       
   321 
       
   322 void CHttpEventHandler::DumpIt(const TDesC8& aData)
       
   323 //Do a formatted dump of binary data
       
   324 	{
       
   325 	// Iterate the supplied block of data in blocks of cols=80 bytes
       
   326 	const TInt cols=16;
       
   327 	TInt pos = 0;
       
   328 	TBuf<KMaxFileName - 2> logLine;
       
   329 	TBuf<KMaxFileName - 2> anEntry;
       
   330 	const TInt dataLength = aData.Length();
       
   331 
       
   332 	while (pos < dataLength)
       
   333 		{
       
   334 		//start-line hexadecimal( a 4 digit number)
       
   335 		anEntry.Format(TRefByValue<const TDesC>_L("%04x : "), pos);
       
   336 		logLine.Append(anEntry);
       
   337 
       
   338 		// Hex output
       
   339 		TInt offset;
       
   340 		for (offset = 0; offset < cols; ++offset)
       
   341 			{
       
   342 			if (pos + offset < aData.Length())
       
   343 				{
       
   344 				TInt nextByte = aData[pos + offset];
       
   345 				anEntry.Format(TRefByValue<const TDesC>_L("%02x "), nextByte);
       
   346 				logLine.Append(anEntry);
       
   347 				}
       
   348 			else
       
   349 				{
       
   350 				//fill the remaining spaces with blanks untill the cols-th Hex number 
       
   351 				anEntry.Format(TRefByValue<const TDesC>_L("   "));
       
   352 				logLine.Append(anEntry);
       
   353 				}
       
   354 			}
       
   355 			anEntry.Format(TRefByValue<const TDesC>_L(": "));
       
   356 			logLine.Append(anEntry);
       
   357 
       
   358 		// Char output
       
   359 		for (offset = 0; offset < cols; ++offset)
       
   360 			{
       
   361 			if (pos + offset < aData.Length())
       
   362 				{
       
   363 				TInt nextByte = aData[pos + offset];
       
   364 				if ((nextByte >= ' ') && (nextByte <= '~'))
       
   365 					{
       
   366 					anEntry.Format(TRefByValue<const TDesC>_L("%c"), nextByte);
       
   367 					logLine.Append(anEntry);
       
   368 					}
       
   369 				else
       
   370 					{
       
   371 					anEntry.Format(TRefByValue<const TDesC>_L("."));
       
   372 					logLine.Append(anEntry);
       
   373 					}
       
   374 				}
       
   375 			else
       
   376 				{
       
   377 				anEntry.Format(TRefByValue<const TDesC>_L(" "));
       
   378 				logLine.Append(anEntry);
       
   379 				}
       
   380 			}
       
   381 			logLine.Zero();
       
   382 
       
   383 		// Advance to next  byte segment (1 seg= cols)
       
   384 		pos += cols;
       
   385 		}
       
   386 	}
       
   387 
       
   388 void CHttpEventHandler::SetSilent(TBool aSilent)
       
   389 	{
       
   390 	iSilent = aSilent;
       
   391 	}
       
   392 
       
   393 void CHttpEventHandler::CloseSaveFile()
       
   394 {
       
   395 	if(iRespBody != NULL)
       
   396 	{		
       
   397 		if(iRespBodyFile.SubSessionHandle() != 0)
       
   398 			{
       
   399 			TInt size;
       
   400 			iRespBodyFile.Size(size);
       
   401 			DP2("Closing file at size %d, bytes downloaded %d", size, iBytesDownloaded);
       
   402 			iRespBodyFile.Close();
       
   403 			}
       
   404 	}
       
   405 }
       
   406