--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/engine/src/HttpEventHandler.cpp Thu Feb 25 14:29:19 2010 +0000
@@ -0,0 +1,406 @@
+/*
+* Copyright (c) 2007-2010 Sebastian Brannstrom, Lars Persson, EmbedDev AB
+*
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* EmbedDev AB - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+// HttpEventHandler.cpp
+#include <e32debug.h>
+#include <httperr.h>
+
+#include "HttpEventHandler.h"
+#include "bautils.h"
+#include "Httpclient.h"
+
+void CHttpEventHandler::ConstructL()
+ {
+ //iVerbose = ETrue;
+ }
+
+
+CHttpEventHandler::CHttpEventHandler(CHttpClient* aClient, MHttpClientObserver &aCallbacks, RFs& aFs):
+ iFileServ(aFs), iHttpClient(aClient), iCallbacks(aCallbacks)
+ {
+ }
+
+
+CHttpEventHandler::~CHttpEventHandler()
+ {
+ }
+
+
+CHttpEventHandler* CHttpEventHandler::NewLC(CHttpClient* aClient, MHttpClientObserver &aCallbacks, RFs& aFs)
+ {
+ CHttpEventHandler* me = new(ELeave)CHttpEventHandler(aClient, aCallbacks, aFs);
+ CleanupStack::PushL(me);
+ me->ConstructL();
+ return me;
+ }
+
+
+CHttpEventHandler* CHttpEventHandler::NewL(CHttpClient* aClient, MHttpClientObserver &aCallbacks, RFs& aFs)
+ {
+ CHttpEventHandler* me = NewLC(aClient, aCallbacks, aFs);
+ CleanupStack::Pop(me);
+ return me;
+ }
+
+void CHttpEventHandler::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
+ {
+ switch (aEvent.iStatus)
+ {
+ case THTTPEvent::EGotResponseHeaders:
+ {
+ // HTTP response headers have been received. We can determine now if there is
+ // going to be a response body to save.
+ RHTTPResponse resp = aTransaction.Response();
+ iLastStatusCode = resp.StatusCode();
+ RStringF statusStr = resp.StatusText();
+ TBuf<32> statusStr16;
+ statusStr16.Copy(statusStr.DesC());
+ DP2("Status: %d (%S)", iLastStatusCode, &statusStr16);
+
+ // Dump the headers if we're being verbose
+ //DumpRespHeadersL(aTransaction);
+
+ // Determine if the body will be saved to disk
+ iSavingResponseBody = ETrue;
+ TBool cancelling = EFalse;
+ if (resp.HasBody() && (iLastStatusCode >= 200) && (iLastStatusCode < 300) && (iLastStatusCode != 204))
+ {
+ //iBytesDownloaded = 0;
+ TInt dataSize = resp.Body()->OverallDataSize();
+ if (dataSize >= 0) {
+ DP1("Response body size is %d", dataSize);
+ iBytesTotal = dataSize;
+ } else {
+ DP("Response body size is unknown");
+ iBytesTotal = -1;
+ }
+ iCallbacks.DownloadInfo(iHttpClient, dataSize);
+
+ cancelling = EFalse;
+ }
+
+ // If we're cancelling, must do it now..
+ if (cancelling)
+ {
+ DP("Transaction Cancelled");
+ aTransaction.Close();
+ iHttpClient->ClientRequestCompleteL(KErrCancel);
+ }
+ else if (iSavingResponseBody) // If we're saving, then open a file handle for the new file
+ {
+ iFileServ.Parse(iFileName, iParsedFileName);
+ TInt valid = iFileServ.IsValidName(iFileName);
+ if (!valid)
+ {
+ DP("The specified filename is not valid!.");
+ iSavingResponseBody = EFalse;
+ }
+ else
+ {
+ if (iContinue) {
+ TInt err = iRespBodyFile.Open(iFileServ, iParsedFileName.FullName(),EFileWrite);
+ if (err)
+ {
+ DP("There was an error opening file");
+ iSavingResponseBody = EFalse;
+ User::Leave(err);
+ } else {
+ int pos = -KByteOverlap;
+ if((err=iRespBodyFile.Seek(ESeekEnd, pos)) != KErrNone) {
+ DP("Failed to set position!");
+ User::Leave(err);
+ }
+ iBytesDownloaded = (pos > 0) ? pos : 0;
+ iBytesTotal += iBytesDownloaded;
+ DP1("Total bytes is now %u", iBytesTotal);
+ DP1("Seeking end: %d", pos);
+ }
+ } else {
+ TInt err = iRespBodyFile.Replace(iFileServ,
+ iParsedFileName.FullName(),
+ EFileWrite);
+ if (err)
+ {
+ DP("There was an error replacing file");
+ iSavingResponseBody = EFalse;
+ User::Leave(err);
+ }
+ }
+ }
+ }
+
+ } break;
+ case THTTPEvent::EGotResponseBodyData:
+ {
+ // Get the body data supplier
+ iRespBody = aTransaction.Response().Body();
+
+ // Some (more) body data has been received (in the HTTP response)
+ //DumpRespBody(aTransaction);
+ //DP1("Saving: %d", iSavingResponseBody);
+ // Append to the output file if we're saving responses
+ if (iSavingResponseBody)
+ {
+ TPtrC8 bodyData;
+ iRespBody->GetNextDataPart(bodyData);
+ iBytesDownloaded += bodyData.Length();
+ TInt error = iRespBodyFile.Write(bodyData);
+
+ // on writing error we close connection
+ if (error != KErrNone) {
+ //aTransaction.Close();
+ iCallbacks.FileError(error);
+ iHttpClient->ClientRequestCompleteL(error);
+ return;
+ }
+
+ if (!iSilent) {
+ iCallbacks.Progress(iHttpClient, iBytesDownloaded, iBytesTotal);
+ }
+ }
+
+ // Done with that bit of body data
+ iRespBody->ReleaseData();
+ } break;
+ case THTTPEvent::EResponseComplete:
+ {
+ // The transaction's response is complete
+
+ DP("Transaction Complete");
+ DP("Closing file");
+ iRespBodyFile.Close();
+ } break;
+ case THTTPEvent::ESucceeded:
+ {
+ DP("Transaction Successful");
+ aTransaction.Close();
+ iHttpClient->ClientRequestCompleteL(KErrNone);
+ } break;
+ case THTTPEvent::EFailed:
+ {
+ DP("Transaction Failed");
+ aTransaction.Close();
+
+ if(iLastStatusCode == HTTPStatus::EOk || iLastStatusCode == HTTPStatus::ECreated || iLastStatusCode == HTTPStatus::EAccepted)
+ {
+ iLastStatusCode = KErrNone;
+ }
+
+ iHttpClient->ClientRequestCompleteL(iLastStatusCode);
+ } break;
+ case THTTPEvent::ERedirectedPermanently:
+ {
+ DP("Permanent Redirection");
+ } break;
+ case THTTPEvent::ERedirectedTemporarily:
+ {
+ DP("Temporary Redirection");
+ } break;
+ default:
+ {
+ DP1("<unrecognised event: %d>", aEvent.iStatus);
+ // close off the transaction if it's an error
+ if (aEvent.iStatus < 0)
+ {
+ aTransaction.Close();
+ iHttpClient->ClientRequestCompleteL(aEvent.iStatus);
+ }
+ } break;
+ }
+ }
+
+TInt CHttpEventHandler::MHFRunError(TInt aError, RHTTPTransaction /*aTransaction*/, const THTTPEvent& /*aEvent*/)
+ {
+ DP1("MHFRunError fired with error code %d", aError);
+
+ return KErrNone;
+ }
+
+void CHttpEventHandler::SetSaveFileName(const TDesC &fName, TBool aContinue)
+ {
+ iFileName.Copy(fName);
+ iContinue = aContinue;
+ }
+
+void CHttpEventHandler::DumpRespHeadersL(RHTTPTransaction& aTrans)
+ {
+ RHTTPResponse resp = aTrans.Response();
+ RStringPool strP = aTrans.Session().StringPool();
+ RHTTPHeaders hdr = resp.GetHeaderCollection();
+ THTTPHdrFieldIter it = hdr.Fields();
+
+ TBuf<KMaxHeaderNameLen> fieldName16;
+ TBuf<KMaxHeaderValueLen> fieldVal16;
+
+ while (it.AtEnd() == EFalse)
+ {
+ RStringTokenF fieldName = it();
+ RStringF fieldNameStr = strP.StringF(fieldName);
+ THTTPHdrVal fieldVal;
+ if (hdr.GetField(fieldNameStr,0,fieldVal) == KErrNone)
+ {
+ const TDesC8& fieldNameDesC = fieldNameStr.DesC();
+ fieldName16.Copy(fieldNameDesC.Left(KMaxHeaderNameLen));
+ switch (fieldVal.Type())
+ {
+ case THTTPHdrVal::KTIntVal:
+ DP2("%S: %d", &fieldName16, fieldVal.Int());
+ break;
+ case THTTPHdrVal::KStrFVal:
+ {
+ RStringF fieldValStr = strP.StringF(fieldVal.StrF());
+ const TDesC8& fieldValDesC = fieldValStr.DesC();
+ fieldVal16.Copy(fieldValDesC.Left(KMaxHeaderValueLen));
+ DP2("%S: %S", &fieldName16, &fieldVal16);
+ }
+ break;
+ case THTTPHdrVal::KStrVal:
+ {
+ RString fieldValStr = strP.String(fieldVal.Str());
+ const TDesC8& fieldValDesC = fieldValStr.DesC();
+ fieldVal16.Copy(fieldValDesC.Left(KMaxHeaderValueLen));
+ DP2("%S: %S", &fieldName16, &fieldVal16);
+ }
+ break;
+ case THTTPHdrVal::KDateVal:
+ {
+ TDateTime date = fieldVal.DateTime();
+ }
+ break;
+ default:
+ DP1("%S: <unrecognised value type>", &fieldName16);
+ break;
+ }
+
+ // Display realm for WWW-Authenticate header
+ RStringF wwwAuth = strP.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable());
+ if (fieldNameStr == wwwAuth)
+ {
+ // check the auth scheme is 'basic'
+ RStringF basic = strP.StringF(HTTP::EBasic,RHTTPSession::GetTable());
+ RStringF realm = strP.StringF(HTTP::ERealm,RHTTPSession::GetTable());
+ THTTPHdrVal realmVal;
+ if ((fieldVal.StrF() == basic) &&
+ (!hdr.GetParam(wwwAuth, realm, realmVal)))
+ {
+ RStringF realmValStr = strP.StringF(realmVal.StrF());
+ fieldVal16.Copy(realmValStr.DesC());
+ DP1("Realm is: %S", &fieldVal16);
+ }
+ }
+ }
+ ++it;
+ }
+ }
+
+void CHttpEventHandler::DumpRespBody(RHTTPTransaction& aTrans)
+ {
+ MHTTPDataSupplier* body = aTrans.Response().Body();
+ TPtrC8 dataChunk;
+ TBool isLast = body->GetNextDataPart(dataChunk);
+ DumpIt(dataChunk);
+ if (isLast)
+ DP("Got last data chunk.");
+ }
+
+
+void CHttpEventHandler::DumpIt(const TDesC8& aData)
+//Do a formatted dump of binary data
+ {
+ // Iterate the supplied block of data in blocks of cols=80 bytes
+ const TInt cols=16;
+ TInt pos = 0;
+ TBuf<KMaxFileName - 2> logLine;
+ TBuf<KMaxFileName - 2> anEntry;
+ const TInt dataLength = aData.Length();
+
+ while (pos < dataLength)
+ {
+ //start-line hexadecimal( a 4 digit number)
+ anEntry.Format(TRefByValue<const TDesC>_L("%04x : "), pos);
+ logLine.Append(anEntry);
+
+ // Hex output
+ TInt offset;
+ for (offset = 0; offset < cols; ++offset)
+ {
+ if (pos + offset < aData.Length())
+ {
+ TInt nextByte = aData[pos + offset];
+ anEntry.Format(TRefByValue<const TDesC>_L("%02x "), nextByte);
+ logLine.Append(anEntry);
+ }
+ else
+ {
+ //fill the remaining spaces with blanks untill the cols-th Hex number
+ anEntry.Format(TRefByValue<const TDesC>_L(" "));
+ logLine.Append(anEntry);
+ }
+ }
+ anEntry.Format(TRefByValue<const TDesC>_L(": "));
+ logLine.Append(anEntry);
+
+ // Char output
+ for (offset = 0; offset < cols; ++offset)
+ {
+ if (pos + offset < aData.Length())
+ {
+ TInt nextByte = aData[pos + offset];
+ if ((nextByte >= ' ') && (nextByte <= '~'))
+ {
+ anEntry.Format(TRefByValue<const TDesC>_L("%c"), nextByte);
+ logLine.Append(anEntry);
+ }
+ else
+ {
+ anEntry.Format(TRefByValue<const TDesC>_L("."));
+ logLine.Append(anEntry);
+ }
+ }
+ else
+ {
+ anEntry.Format(TRefByValue<const TDesC>_L(" "));
+ logLine.Append(anEntry);
+ }
+ }
+ logLine.Zero();
+
+ // Advance to next byte segment (1 seg= cols)
+ pos += cols;
+ }
+ }
+
+void CHttpEventHandler::SetSilent(TBool aSilent)
+ {
+ iSilent = aSilent;
+ }
+
+void CHttpEventHandler::CloseSaveFile()
+{
+ if(iRespBody != NULL)
+ {
+ if(iRespBodyFile.SubSessionHandle() != 0)
+ {
+ TInt size;
+ iRespBodyFile.Size(size);
+ DP2("Closing file at size %d, bytes downloaded %d", size, iBytesDownloaded);
+ iRespBodyFile.Close();
+ }
+ }
+}
+