--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/gcfprotocols/http/src.s60/chttptransactionclient.cpp Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,1051 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: CHttpTransactionClient
+*
+*/
+
+
+#include <http/rhttpresponse.h>
+#include <http/rhttpheaders.h>
+#include <httpstringconstants.h>
+#include <http/thttphdrval.h>
+#include <http/mhttpauthenticationcallback.h>
+#include <httperr.h>
+#include <stringpool.h>
+#include <e32svr.h>
+#include <x509cert.h>
+#include <ssl.h>
+#include "logger.h"
+#include "chttptransactionclient.h"
+#include "httpsessionclient.h"
+#include "chttpscertinfo.h"
+#include "mrefhttpclientobserver.h"
+
+
+_LIT8(KSeperator , ";;");
+_LIT8(KComma , ",");
+_LIT8(KDot , ".");
+_LIT8(KCommaSpace , ", ");
+_LIT8(KSemiColonSpace , "; ");
+_LIT8(KEquals , "=");
+_LIT8(KDRMHeader1,"application/vnd.oma.drm.content");
+_LIT8(KDRMHeader2,"application/vnd.oma.drm.message");
+
+// A maximum length of the cipher suite description strings,
+// see CipherSuiteDescription().
+const TUint8 KMaxCipherSuiteDescriptionLength = 40;
+
+const TInt KCookieBufferAllocLength = 4096;
+
+
+CHttpTransactionClient::CHttpTransactionClient(HttpSessionClient& aSession, MRefHttpClientObserver* aObserver)
+ :iHttpSession(aSession) , iObserver(aObserver), iReleasedData(ETrue),iClosing(EFalse)
+{}
+
+
+CHttpTransactionClient* CHttpTransactionClient::NewL(HttpSessionClient& aSession,
+ MRefHttpClientObserver* aObserver,
+ const TDesC* aUri,
+ const TDesC* aRequestMethod)
+{
+ CHttpTransactionClient* self = new(ELeave) CHttpTransactionClient(aSession,aObserver);
+ CleanupStack::PushL(self);
+ self->ConstructL(aUri, aRequestMethod);
+ CleanupStack::Pop(self);
+ return self;
+}
+
+void CHttpTransactionClient::ConstructL(const TDesC* aUri, const TDesC* aRequestMethod)
+{
+ //open the transaction
+ LOG(ESOCKET,EInfo, "CHttpTransactionClient::ConstructL ");
+ iFlag = 0;
+ iDrmBuf = HBufC8::NewL(256);
+ OpenTransactionL(aUri , aRequestMethod);
+}
+
+void CHttpTransactionClient::OpenTransactionL(const TDesC* aUri, const TDesC* aRequestMethod)
+{
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::OpenTransactionL + ");
+ TUriParser8 uri;
+ HBufC8* uriBuf= HBufC8::NewLC(aUri->Length());
+ TPtr8 uriPtr = uriBuf->Des();
+ uriPtr.Copy(*aUri);
+ uri.Parse(*uriBuf);
+ //Get Request Method String
+ TBuf8<32> reqestType; //GET //POST // HEAD // Only options available in Midp 2.0 Http
+
+ LOG(ESOCKET,EInfo,"Open TransactionL : Transaction Uri ");
+ reqestType.Copy(*aRequestMethod);
+ LOG(ESOCKET,EInfo,"Open TransactionL : ReqestType ");
+
+ RStringF requestMethoStr = iHttpSession.Session().StringPool().OpenFStringL(reqestType);
+ CleanupClosePushL(requestMethoStr);
+ iTransaction = iHttpSession.Session().OpenTransactionL(uri,*this,requestMethoStr);
+
+ CleanupStack::PopAndDestroy(2);//requestMethoStr// uriBuf
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::OpenTransactionL - ");
+}
+
+void CHttpTransactionClient::SubmitL(RPointerArray<HBufC8>* aRawHeaders , TDesC8* aPostData, int aResponseTimeout)
+{
+ //ELOG(ESOCKET,"CHttpTransactionClient::SubmitL + ");
+ //retrieve the headers
+ TInt respTimeOut = aResponseTimeout;
+ delete iBuf;
+ iBuf=NULL;
+ if (aPostData!=NULL && aPostData->Length()>0)
+ {
+ HBufC8* buf = aPostData->AllocL();
+ iBuf=buf;
+ LOG(ESOCKET,EInfo,"SubmitL : Posting Data ");
+ }
+
+ // Disable pipelining on this transaction
+ RStringPool stringPool = iHttpSession.Session().StringPool();
+ RStringF property = stringPool.StringF(HTTP::EHttpPipelining, RHTTPSession::GetTable());
+ THTTPHdrVal disablePipelining = stringPool.StringF(HTTP::EDisablePipelining, RHTTPSession::GetTable());
+ iTransaction.PropertySet().SetPropertyL(property, disablePipelining);
+
+ if (respTimeOut != -1)
+ {
+ LOG1(ESOCKET,EInfo,"Setting response timeout to http stack with value = %d ",aResponseTimeout);
+ property = stringPool.StringF(HTTP::EReceiveTimeOutValue, RHTTPSession::GetTable());
+ THTTPHdrVal responseTimeout(respTimeOut);
+ iTransaction.PropertySet().SetPropertyL(property, responseTimeout);
+ }
+
+ //Submit the transaction
+ RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection();
+ TInt headerCount = aRawHeaders->Count();
+ for (TInt ii=0; ii < headerCount; ++ii)
+ {
+ SetHeaderL(hdr, (*aRawHeaders)[ii]);
+ }
+
+ //iHttpSession.CustomiseHeadersL(hdr);
+
+ //Set Data
+ if (iBuf && iBuf->Length() > KErrNone)
+ iTransaction.Request().SetBody(*this);
+ /* The data will be requested from MHttpDataSupplier*/
+ iJavaWaitingOnCallBack=ETrue;
+ iJavaWaitingOnReadCallBack=ETrue; // Assume somebody opened an input Stream
+ LOG1(ESOCKET,EInfo,"CHttpTransactionClient::SubmitL :iTransaction.Id %d ",iTransaction.Id());
+ TRAP_IGNORE(iTransaction.SubmitL());
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::SubmitL - ");
+}
+
+
+void CHttpTransactionClient::SetHeaderL(RHTTPHeaders& aHeaders, const TDesC8* aRawField)
+{
+ /*Raw Headers are passed in from java of the format
+ * ValueKey ;; property
+ * HTTP requires all request properties which can legally have
+ * multiple instances with the same key to use a comma-separated list
+ * syntax which enables multiple properties to be appended into a
+ * single property.
+ */
+ //Find the value field
+ //Seperated from values in Java by KSeperator
+ TInt valueIndex = aRawField->Find(KSeperator);
+ User::LeaveIfError(valueIndex);
+ TPtrC8 value =aRawField->Left(valueIndex);
+ RStringF valueF = iHttpSession.Session().StringPool().OpenFStringL(value);
+ CleanupClosePushL(valueF);
+ TPtrC8 propertyRaw= aRawField->Mid(valueIndex+2);
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient Add header value ");
+ aHeaders.SetRawFieldL(valueF, propertyRaw , KComma);
+ CleanupStack::PopAndDestroy();//valueF
+}
+
+void CHttpTransactionClient::GetResponseL(RPointerArray<HBufC8>* aRawHeaders)
+{
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::GetResponseL(RPointerArray<HBufC8>* aRawHeaders)");
+ RStringPool strP = iTransaction.Session().StringPool();
+ //First element in response array is the status line of the form
+ //HTTP-Version (major.minor) ;; Status-Code ;; Reason-Phrase
+ LOG1(ESOCKET,EInfo,"CHttpTransactionClient::GetResponseL :iTransaction.Id %d ",iTransaction.Id());
+ RHTTPResponse response = iTransaction.Response();
+
+ TInt statusLineLength=0;
+
+ //HTTP-Version
+ TVersion serverVersion = response.Version();
+ TBuf<16> major;
+ major.Num(serverVersion.iMajor);
+ TBuf<16> minor;
+ minor.Num(serverVersion.iMinor);
+ statusLineLength+=major.Length();
+ statusLineLength+=1;//KDot
+ statusLineLength+=minor.Length();
+
+ //Status code
+ TBuf<16> stausCode;
+ TInt serverStatusCode = response.StatusCode();
+ stausCode.Num(serverStatusCode);
+ statusLineLength+=stausCode.Length();
+
+ //Status Text
+ RStringF serverResponseTextF = response.StatusText();
+ statusLineLength+= serverResponseTextF.DesC().Length();
+
+ //Sepearators KSeperator *2
+ statusLineLength+=4;//
+
+ HBufC8* responseText = HBufC8::NewLC(statusLineLength);
+ //Create Status Line
+ //Version
+ responseText->Des().Append(major);
+ responseText->Des().Append(KDot);
+ responseText->Des().Append(minor);
+ //Status Code
+ responseText->Des().Append(KSeperator);
+ responseText->Des().Append(stausCode);
+ //Status Text
+ responseText->Des().Append(KSeperator);
+ responseText->Des().Append(serverResponseTextF.DesC());
+ aRawHeaders->Append(responseText);
+ CleanupStack::Pop(responseText);
+
+ //Package up all the transaction headers in to an array of java strings
+ RHTTPHeaders headers =response.GetHeaderCollection();
+ THTTPHdrFieldIter it = headers.Fields();
+ RStringTokenF token;
+ RStringF fieldNameStr;
+ TPtrC8 rawFldPtr;
+ HBufC8* rawHeader = NULL; // field name and values
+ TInt rawFieldLength=0;
+ do
+ {
+ token = it();
+ fieldNameStr=strP.StringF(token);
+ //Get the field data assume we get comma seperated values and
+ //don't have to use aPartIdx
+
+ RStringF setCookie = strP.StringF(HTTP::ESetCookie,RHTTPSession::GetTable());
+ if (fieldNameStr == setCookie)
+ {
+ // Buffer for storing a single cookie
+ HBufC8* cookieBuf = HBufC8::NewLC(KCookieBufferAllocLength);
+
+ cookieBuf->Des().Append(fieldNameStr.DesC());
+ cookieBuf->Des().Append(KSeperator);
+ iMinLength = cookieBuf->Des().Length();
+
+ TInt totalCookiesLength = 0;
+ TInt cookieCount = headers.FieldPartsL(setCookie);
+
+ if (cookieCount != 0)
+ {
+ for (TInt ii = 0; ii < cookieCount; ii++)
+ {
+ iDiscardCookie = false;
+ StoreOneCookieL(cookieBuf, headers, ii, setCookie);
+ if (ii < cookieCount-1)
+ {
+ // Replace last semicolon with comma
+ if (iDiscardCookie!=true)
+ {
+ cookieBuf->Des().SetLength(cookieBuf->Des().Length() - KSemiColonSpace().Length());
+ cookieBuf->Des().Append(KCommaSpace);
+ }
+ else
+ {
+ cookieBuf->Des().Append(KCommaSpace);
+ }
+ }
+
+ if (ii > 0)
+ {
+ totalCookiesLength += cookieBuf->Des().Length();
+ rawHeader = rawHeader->ReAllocL(totalCookiesLength);
+ rawHeader->Des().Append(*cookieBuf);
+ }
+ else
+ {
+ rawHeader = cookieBuf->AllocL();
+ totalCookiesLength = rawHeader->Length();
+ }
+
+ cookieBuf->Des().Zero();
+ }
+ }
+ else
+ {
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::GetResponseL 'Set-Cookie:' header field is empty");
+ rawHeader = cookieBuf->AllocL();
+ }
+
+ CleanupStack::PopAndDestroy(cookieBuf);
+ aRawHeaders->Append(rawHeader);
+ }
+ else
+ {
+ TInt err = headers.GetRawField(fieldNameStr,rawFldPtr);
+
+ if (err==KErrNone)
+ {
+ rawFieldLength += fieldNameStr.DesC().Length();
+ rawFieldLength += 2;//KSeperator Length;
+ rawFieldLength += rawFldPtr.Length();
+ rawHeader = HBufC8::NewL(rawFieldLength);
+ rawHeader->Des().Append(fieldNameStr.DesC());
+ rawHeader->Des().Append(KSeperator);
+ rawHeader->Des().Append(rawFldPtr);
+ aRawHeaders->Append(rawHeader);
+ rawFieldLength=0;
+ }
+ }
+ ++it;
+ }
+ while (!it.AtEnd());
+}
+
+
+/*
+* Returns the total number of bytes read into the buffer,
+* or -1 if there is no more data because the end of the stream
+* has been reached.
+*/
+TInt CHttpTransactionClient::ReadBytes(TDes8& aBytesPtr)
+{
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient:: ReadBytes");
+ TInt maxBufLength = aBytesPtr.MaxLength();
+ TInt bodyDataPartLength = 0;
+ if (iDrmDownload == false)
+ {
+ bodyDataPartLength = iBuf->Length();
+ }
+ else
+ {
+ bodyDataPartLength = iDrmBuf->Length();
+ }
+ LOG1(ESOCKET,EInfo,"CHttpTransactionClient::ReadBytes: maxRead: %d," , maxBufLength);
+ LOG1(ESOCKET,EInfo,"CHttpTransactionClient::ReadBytes: bodyDataPartLength:: %d " ,bodyDataPartLength);
+ TInt bytesRead = (maxBufLength+iJavaReadOffset > bodyDataPartLength) ? (bodyDataPartLength - iJavaReadOffset) : maxBufLength;
+ if (bytesRead>0)
+ {
+ LOG1(ESOCKET,EInfo,"Bytes read : %d " ,bytesRead);
+
+ if (iDrmDownload == false)
+ {
+ TPtrC8 bufPtr = iBuf->Mid(iJavaReadOffset,bytesRead);
+ aBytesPtr.Copy(bufPtr);
+ }
+ else
+ {
+ TPtrC8 bufPtr = iDrmBuf->Mid(iJavaReadOffset,bytesRead);
+ aBytesPtr.Copy(bufPtr);
+ }
+
+ LOG1(ESOCKET,EInfo,"CHttpTransactionClient::ReadBytes: iJavaReadOffset:: %d " ,iJavaReadOffset);
+ if (iDrmDownload == false)
+ {
+ if ((iJavaReadOffset+bytesRead) == bodyDataPartLength && iLastChunk)
+ {
+ //All body data from the http transaction has been read
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::ReadBytes: EOF iLastChunk");
+ iRead = ETrue;
+
+ iJavaWaitingOnReadCallBack=EFalse;
+ TRAP_IGNORE(iObserver->DataReadyForRead(-1));
+ }
+ }
+ else
+ {
+ if ((iJavaReadOffset+bytesRead) == iDrmBuf->Length() && iLastChunk)
+ {
+ //All DRM body data from the http transaction has been read
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::ReadBytes: EOF iLastChunk");
+ iRead = ETrue;
+
+ iJavaWaitingOnReadCallBack=EFalse;
+ TRAP_IGNORE(iObserver->DataReadyForRead(-1));
+ }
+ }
+ } // if(bytesread > 0)
+ if ((iJavaReadOffset+bytesRead)<=bodyDataPartLength)
+ {
+
+ if (iJavaReadOffset+bytesRead < bodyDataPartLength)
+ {
+ //Java hasn't read all the current body data buffer, inform java
+ //amount of bytes left to read in buffer.
+
+ iJavaReadOffset+=bytesRead;
+ TInt bytesLeftInBuffer = bodyDataPartLength-iJavaReadOffset;
+ LOG1(ESOCKET,EInfo," CHttpTransactionClient::ReadBytes: bytesLeftInBuffer: %d",bytesLeftInBuffer);
+ //Unblock java so it can read the remaining buffered data
+ iJavaWaitingOnReadCallBack=ETrue;
+ TRAP_IGNORE(iObserver->DataReadyForRead(bytesLeftInBuffer));
+ }
+ else
+ {
+ // in this call, the iBuf data was completely read, so call release data to get the next chunk(part) of body from
+ // the native stack
+
+ if (iDrmDownload == false)
+ {
+ // Non-Drm case, offset is reset to 0, starting reading newly from iBuf from the next call
+ iJavaReadOffset=0;
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient:: ReadBytes ReleaseData!");
+ iReleasedData=ETrue;
+ if (iBuf)
+ {
+ delete iBuf;
+ iBuf = NULL;
+ }
+ iRespBody->ReleaseData(); // tell the stack to send the next response body data, stack will call mhfrunl after this
+ }
+ else
+ {
+ // DRM file download, index is never reset to 0 , continue reading from drm buffer
+ iJavaReadOffset+=bytesRead;
+
+ }
+
+ }
+
+ }
+
+ LOG1(ESOCKET,EInfo,"CHttpTransactionClient::ReadBytes: return bytesRead %d " , bytesRead);
+ return bytesRead;
+}
+
+
+
+void CHttpTransactionClient::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
+{
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::MHFRunL +");
+
+ if (iTransaction== aTransaction)
+ {
+ LOG1(ESOCKET,EInfo,"before switch aEvent.iStatus = %d ",aEvent.iStatus);
+ switch (aEvent.iStatus)
+ {
+ case THTTPEvent::ESubmit:
+ LOG1(ESOCKET,EInfo,"MHFRunL::ESubmit : aEvent.iStatus = %d",aEvent.iStatus);
+ iStatus= CHttpTransactionClient::ESubmitted;
+ //Only send an event to Java when we've got a response
+ break;
+ case THTTPEvent::ECancel:
+ LOG(ESOCKET,EInfo,"MHFRunL::ECancel");
+ iStatus =CHttpTransactionClient:: ECancelled;
+ if (iJavaWaitingOnCallBack)
+ {
+ iObserver->SubmitComplete(iStatus);
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::MHFRunL ECancel ");
+ iJavaWaitingOnCallBack=EFalse;
+ }
+
+ if (iJavaWaitingOnReadCallBack)
+ {
+ LOG(ESOCKET,EInfo,"Notifiy Read EOF / Cancel");
+ iJavaWaitingOnCallBack=EFalse;
+ iObserver->DataReadyForRead(-1);
+ }
+
+ break;
+ case THTTPEvent::EClosed:
+ LOG(ESOCKET,EInfo,"MHFRunL::EClosed");
+ iStatus = CHttpTransactionClient::EClosed;
+ if (iJavaWaitingOnCallBack)
+ {
+ iJavaWaitingOnCallBack=EFalse;
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::MHFRunL EClosed");
+ iObserver->SubmitComplete(iStatus);
+ }
+ if (iJavaWaitingOnReadCallBack)
+ {
+ LOG(ESOCKET,EInfo,"Notifiy Read EOF / Cancel");
+ iJavaWaitingOnCallBack=EFalse;
+ iObserver->DataReadyForRead(-1);
+ }
+
+ break;
+ /*Receiving transaction events*/
+ case THTTPEvent::EGotResponseTrailerHeaders:
+ {
+ LOG(ESOCKET,EInfo,"MHFRunL EGotResponseTrailerHeaders");
+ iStatus= CHttpTransactionClient::EGotResponse;
+ break;
+ }
+ case THTTPEvent::ESucceeded:
+ {
+ LOG(ESOCKET,EInfo,"MHFRunL ESucceeded");
+ break;
+ }
+ case THTTPEvent::EGotResponseHeaders:
+ {
+ LOG(ESOCKET,EInfo,"MHFRunL EGotResponseHeaders");
+ iStatus = CHttpTransactionClient::EGotResponse;
+ //If we are secure attempt to get the security information.
+ //At the moment the native HTTP stack only allows us to retrieve
+ //Server cert info after and a submission and before the transaction is
+ //complete, ignore any warnings as we may not be in sercure mode
+
+ RStringPool strP = iTransaction.Session().StringPool();
+ RHTTPResponse response = iTransaction.Response();
+ RHTTPHeaders headers =response.GetHeaderCollection();
+ THTTPHdrFieldIter it = headers.Fields();
+ RStringTokenF token;
+ RStringF fieldNameStr;
+ TPtrC8 rawFldPtr;
+ do
+ {
+ token = it();
+ fieldNameStr=strP.StringF(token);
+ // Work around for DRM download
+ RStringF contentType = strP.StringF(HTTP::EContentType,RHTTPSession::GetTable());
+ if (fieldNameStr == contentType)
+ {
+ //LOG(ESOCKET,EInfo,"content type header is present");
+ TInt err = headers.GetRawField(fieldNameStr,rawFldPtr);
+ TInt index = rawFldPtr.Match(KDRMHeader1);
+ // LOG1(ESOCKET,EInfo,"rawFldPtr = %s ",rawFldPtr.str());
+ //LOG1(ESOCKET,EInfo,"index of drm header is = %d",index);
+ if (index == 0)
+ {
+ iDrmDownload = true;
+ }
+ else
+ {
+ index = rawFldPtr.Match(KDRMHeader2);
+ if (index == 0)
+ iDrmDownload = true;
+ }
+ }
+ ++it;
+ }
+ while (!it.AtEnd());
+
+ GetSecurityInfo();
+ if (iJavaWaitingOnCallBack)
+ {
+ iJavaWaitingOnCallBack=EFalse;
+ //LOG(ESOCKET,EInfo,"CHttpTransactionClient::MHFRunL Notifiy Java Got Response");
+ iObserver->SubmitComplete(iStatus);
+ }
+ break;
+ }
+ case THTTPEvent::EResponseComplete:
+ {
+ LOG(ESOCKET,EInfo,"MHFRunL EResponseComplete");
+ if (iJavaWaitingOnReadCallBack)
+ {
+ LOG(ESOCKET,EInfo,"Notifiy Read EOF / Cancel");
+ iJavaWaitingOnCallBack=EFalse;
+ iStatus=CHttpTransactionClient::EComplete;
+ if (iDrmDownload == false)
+ iObserver->DataReadyForRead(-1);
+ }
+
+ break;
+ }
+ case THTTPEvent::EUnrecoverableError:
+ case THTTPEvent::ETooMuchRequestData:
+ case THTTPEvent::EFailed:
+ {
+ LOG(ESOCKET,EInfo, "MHFRunL EUnrecoverableError/EFailed");
+ iStatus=CHttpTransactionClient::EFailed;
+ NotifyErrorL(iStatus);
+ break;
+ }
+ case THTTPEvent::EGotResponseBodyData:
+ {
+ LOG(ESOCKET,EInfo,"MHFRunL EGotResponseBodyData");
+ iReleasedData=EFalse;
+ //More data is ready for Java to read.
+ iRespBody = aTransaction.Response().Body();
+
+ TPtrC8 bodyData;
+ iStatus=KErrNotReady;
+ //We may be closing if so we don't want to request more data.
+ if (!iClosing)
+ {
+ if (iDrmDownload == true)
+ {
+ iFlag = iFlag + 1;
+ iLastChunk = iRespBody->GetNextDataPart(bodyData);
+ TInt curLen = iDrmBuf->Length();
+ TInt reqLen = curLen + bodyData.Length();
+ LOG1(ESOCKET,EInfo," CHttpTransactionClient::MHFRunL DRM case bodyData.Length() = %d",bodyData.Length());
+ TRAP_IGNORE((iDrmBuf = iDrmBuf->ReAllocL(reqLen + bodyData.Length())));
+ TPtr8 bodyPtr1 = iDrmBuf->Des();
+ //HBufC8* bodyBuffer1 = HBufC8::NewLC(bodyData.Length());
+ LOG1(ESOCKET,EInfo,"length of iDrmBuf = %d", iDrmBuf->Length());
+ bodyPtr1.Append(bodyData);
+ iRespBody->ReleaseData();
+
+
+ iStatus = CHttpTransactionClient::EGotResponseBodyData;
+ //if(iFlag == 1)
+ TInt bodyDataPartLength;
+ bodyDataPartLength = iDrmBuf->Length();
+ TInt bytesLeftInBuffer = bodyDataPartLength-iJavaReadOffset;
+ if (bytesLeftInBuffer > 0)
+ iObserver->DataReadyForRead(bytesLeftInBuffer);
+ }
+ else
+ {
+ iLastChunk = iRespBody->GetNextDataPart(bodyData);
+ HBufC8* bodyBuffer = HBufC8::NewLC(bodyData.Length());
+ LOG1(ESOCKET,EInfo," CHttpTransactionClient::MHFRunL after getnextdatapart ,bodyData.Length() = %d",bodyData.Length());
+ TPtr8 bodyPtr = bodyBuffer->Des();
+ bodyPtr.Append(bodyData);
+ if (iBuf)
+ {
+ delete iBuf;
+ iBuf = NULL;
+ }
+ CleanupStack::Pop(bodyBuffer);
+ iBuf = bodyBuffer;
+ iStatus = CHttpTransactionClient::EGotResponseBodyData;
+ LOG(ESOCKET,EInfo," CHttpTransactionClient::MHFRunL Notify got more data");
+ iObserver->DataReadyForRead(iStatus);
+ }
+ }
+
+ break;
+ }
+ case THTTPEvent::ENotifyNewRequestBodyPart:
+ {
+ LOG(ESOCKET,EInfo,"MHFRunL ENotifyNewRequestBodyPart");
+ iStatus = CHttpTransactionClient::ERequestNextBodayData;
+ break;
+ }
+ /*
+ * -j2me expects the http stack to be able to post body data with no content type
+ * the native stack default validation filter does not allow this.
+ * -j2me expects the http stack to allow post requests to have body data
+ * the native stack default validation filter does not allow this. */
+ case KErrHttpEntityHeaderMissingContentType:
+ case KErrHttpInvalidHeaderInRequest:
+ case KErrHttpGeneralHeaderMissingHost:
+ break;
+
+ case THTTPEvent::ERedirectRequiresConfirmation:
+ {
+ LOG(ESOCKET,EInfo,"MHFRunL ERedirectRequiresConfirmation");
+ }
+ case THTTPEvent::ENeedTunnel:
+ {
+ LOG(ESOCKET,EInfo,"MHFRunL ENeedTunnel");
+ }
+ case THTTPEvent::EGetCipherSuite:
+ {
+ LOG(ESOCKET,EInfo,"MHFRunL EGetCipherSuite");
+ }
+ default:
+ {
+ LOG(ESOCKET,EInfo,"MHFRunL Unkown Event");
+ //__ASSERT_DEBUGCOMP( EFalse, User::Panic(_L("Unhandled native Http event"), aEvent.iStatus) );
+ NotifyErrorL(aEvent.iStatus);
+ break;
+ }
+ };
+ }
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::MHFRunL -");
+}
+
+TInt CHttpTransactionClient::MHFRunError(TInt aError, RHTTPTransaction aTransaction, const THTTPEvent& /*aEvent*/)
+{
+ LOG1(ESOCKET,EInfo," CHttpTransactionClient::MHFRunError: %d ",aError);
+ if (aError!=KErrNone && iTransaction== aTransaction)
+ {
+ iStatus=CHttpTransactionClient::EFailed;
+ if (iJavaWaitingOnCallBack)
+ iObserver->SubmitComplete(iStatus);
+
+
+ if (iJavaWaitingOnReadCallBack)
+ {
+ LOG(ESOCKET,EInfo,"Notifiy Read EOF / Cancel");
+ iJavaWaitingOnCallBack=EFalse;
+ iObserver->DataReadyForRead(-1);
+ }
+
+ }
+ return aError;
+}
+
+/*
+* Java may be waiting on an async call back
+* If this is the case notify of the error code so we don't block java.
+*/
+
+void CHttpTransactionClient::NotifyErrorL(TInt aErrorCode)
+{
+ LOG1(ESOCKET,EInfo," CHttpTransactionClient::NotifyErrorL: %d ",aErrorCode);
+ if ((aErrorCode == KErrNotReady))
+ {
+ iTransaction.Cancel();
+ iHttpSession.RestartConnection();
+
+
+ }
+ if (iJavaWaitingOnCallBack)
+ {
+ iJavaWaitingOnCallBack=EFalse;
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::MHFRunL Notifiy Java unknown Event");
+ iObserver->SubmitComplete(aErrorCode);
+ }
+ if (iJavaWaitingOnReadCallBack)
+ {
+ LOG(ESOCKET,EInfo,"Notifiy Read EOF / Cancel");
+ iJavaWaitingOnCallBack=EFalse;
+ //Notify Java of error if it is waiting for a read
+ iObserver->DataReadyForRead(-1);
+ }
+
+}
+
+
+void CHttpTransactionClient::CloseTransaction()
+{
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::CloseTransaction + ");
+ iClosing=ETrue;
+ if (!iReleasedData)
+ {
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::CloseTransaction NOT RELEASED DATA!!! release and close");
+ if (iDrmDownload == false)
+ iRespBody->ReleaseData();
+ iReleasedData=ETrue;
+ }
+ iTransaction.Close();
+ iClosing=EFalse;
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::CloseTransaction - ");
+}
+
+CHttpTransactionClient::~CHttpTransactionClient()
+{
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::~CHttpTransactionClient");
+ //CloseTransaction();
+ if (iBuf)
+ {
+ delete iBuf;
+ iBuf=NULL;
+ }
+ if (iDrmBuf)
+ {
+ delete iDrmBuf;
+ iDrmBuf=NULL;
+ }
+ delete iCertInfo;
+}
+
+
+/** Obtain a data part from the supplier. The data is guaranteed
+ to survive until a call is made to ReleaseData().
+ @param aDataPart - the data part
+ @return ETrue if this is the last part. EFalse otherwise */
+TBool CHttpTransactionClient::GetNextDataPart(TPtrC8& aDataPart)
+{
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::GetNextDataPart");
+ TBool lastPart=EFalse;
+ if (iBuf!=NULL)
+ {
+ lastPart = ETrue;
+ aDataPart.Set(iBuf->Des());
+ }
+ return lastPart;
+}
+
+/** Release the current data part being held at the data
+ supplier. This call indicates to the supplier that the part
+ is no longer needed, and another one can be supplied, if
+ appropriate. */
+void CHttpTransactionClient::ReleaseData()
+{
+ LOG(ESOCKET,EInfo," CHttpTransactionClient::ReleaseData: delete iBuf");
+ if (iBuf)
+ {
+ delete iBuf;
+ iBuf=NULL;
+ }
+}
+
+/** Obtain the overall size of the data being supplied, if known
+ to the supplier. Where a body of data is supplied in several
+ parts this size will be the sum of all the part sizes. If
+ the size is not known, KErrNotFound is returned; in this case
+ the client must use the return code of GetNextDataPart to find
+ out when the data is complete.
+
+ @return A size in bytes, or KErrNotFound if the size is not known. */
+TInt CHttpTransactionClient::OverallDataSize()
+{
+ TInt overallSize = KErrNotFound;
+ if (iBuf)
+ {
+ overallSize=iBuf->Length();
+ }
+ LOG1(ESOCKET,EInfo," CHttpTransactionClient::OverallDataSize: %d",overallSize);
+ return overallSize;
+}
+
+/** Reset the data supplier. This indicates to the data supplier that it should
+ return to the first part of the data. This could be used in a situation where
+ the data consumer has encountered an error and needs the data to be supplied
+ afresh. Even if the last part has been supplied (i.e. GetNextDataPart has
+ returned ETrue), the data supplier should reset to the first part.
+
+ If the supplier cannot reset it should return an error code; otherwise it should
+ return KErrNone, where the reset will be assumed to have succeeded*/
+TInt CHttpTransactionClient::Reset()
+{
+ LOG(ESOCKET,EInfo,"CHttpTransactionClient::Reset");
+ TInt err = KErrNone;
+ return err;
+}
+
+
+MNativeSecureConnectionInformation* CHttpTransactionClient::GetSecurityInfo()
+{
+ //LOG(ESOCKET,EInfo,"CHttpTransactionClient::GetSecurityInfo");
+ MNativeSecureConnectionInformation* handle=NULL;
+ if (!iCertInfo)
+ {
+ TRAP_IGNORE(GetCertInfoL());
+ //If we fail to read the cert java is returned a null handle.
+ }
+ if (iCertInfo)
+ {
+ handle = iCertInfo;
+ }
+ return handle;
+}
+
+void CHttpTransactionClient::GetCertInfoL()
+{
+ //LOG(ESOCKET,EInfo,"CHttpTransactionClient::GetCertInfoL ");
+ TCertInfo info;
+
+ //Get the server certificate
+ if (iCertInfo!=NULL)
+ {
+ delete iCertInfo;
+ iCertInfo= NULL;
+ }
+ const CX509Certificate* cert = static_cast<const CX509Certificate*>(iTransaction.ServerCert());
+
+ TInt err = iTransaction.ServerCert(info);
+ if (err==KErrNone)
+ {
+ //Get the cipher suite
+ const TDesC8& cipherCode = iTransaction.CipherSuite().DesC();
+ if (!cipherCode.Length())
+ {
+ //LOG(ESOCKET,EInfo, "CHttpTransactionClient::GetCertInfoL No Cipher Suite Name found in Transaction");
+ User::Leave(KErrNotFound);
+ }
+
+ HBufC* cipherSuiteBuf = HBufC::NewLC(KMaxCipherSuiteDescriptionLength);
+
+ const TDesC8& cipherDesc = CipherSuiteDescription(cipherCode);
+ if (cipherDesc.Length())
+ {
+ cipherSuiteBuf->Des().Copy(cipherDesc);
+ }
+ else
+ {
+ // We will use the code as no description is available.
+ //LOG(ESOCKET,EInfo, "CHttpTransactionClient::GetCertInfoL No Cipher Suite description found");
+ cipherSuiteBuf->Des().Copy(cipherCode);
+ }
+
+ CleanupStack::Pop(cipherSuiteBuf);
+ iCertInfo= CHttpsCertInfo::NewL(*cert,cipherSuiteBuf);
+ }
+}
+
+TInt CHttpTransactionClient::Available()
+{
+ TInt avail=KErrNone;
+ if (iBuf)
+ {
+ avail=(iBuf->Length()-iJavaReadOffset);
+ }
+ LOG1(ESOCKET,EInfo," CHttpTransactionClient::Available: %d ",avail);
+ return avail;
+}
+
+void CHttpTransactionClient::SetHTTPAuthenticationCallbackL(MHTTPAuthenticationCallback& aCallBack)
+{
+ aCallBack.InstallAuthenticationL(iHttpSession.Session());
+}
+
+
+// NOTE : When adding a new cipher description string,
+// make sure KMaxCipherSuiteDescriptionLength is greater than the length.
+const TDesC8& CHttpTransactionClient::CipherSuiteDescription(const TDesC8& aCode)
+{
+ TInt length = aCode.Length();
+ if (length < 2)
+ {
+ // This is not a TLS code we recognise.
+ //LOG(ESOCKET,EInfo,"CHttpTransactionClient::CipherSuiteDescription, unknown cipher suite");
+ return KNullDesC8;
+ }
+
+ TInt code = aCode[1];
+
+ //LOG1(ESOCKET,EInfo,"CHttpTransactionClient::CipherSuiteDescription, code=%d", code);
+
+ switch (code)
+ {
+// The Cipher Suite codes and matching string descriptions are taken from the TLS specification
+// (see A.5. The CipherSuite, The TLS Protocol, RFC 2246)
+// The list below contains those currently supported by Symbian. See tlstypedef.h
+
+ case 0x03:
+ _LIT8(KTls_03, "TLS_RSA_EXPORT_WITH_RC4_40_MD5");
+ return KTls_03();
+ case 0x04:
+ _LIT8(KTls_04, "TLS_RSA_WITH_RC4_128_MD5");
+ return KTls_04();
+ case 0x05:
+ _LIT8(KTls_05, "TLS_RSA_WITH_RC4_128_SHA");
+ return KTls_05();
+ case 0x08:
+ _LIT8(KTls_08, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA");
+ return KTls_08();
+ case 0x09:
+ _LIT8(KTls_09, "TLS_RSA_WITH_DES_CBC_SHA");
+ return KTls_09();
+ case 0x0A:
+ _LIT8(KTls_0A, "TLS_RSA_WITH_3DES_EDE_CBC_SHA");
+ return KTls_0A();
+ case 0x11:
+ _LIT8(KTls_11, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
+ return KTls_11();
+ case 0x12:
+ _LIT8(KTls_12, "TLS_DHE_DSS_WITH_DES_CBC_SHA");
+ return KTls_12();
+ case 0x13:
+ _LIT8(KTls_13, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA");
+ return KTls_13();
+ case 0x14:
+ _LIT8(KTls_14, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA");
+ return KTls_14();
+ case 0x16:
+ _LIT8(KTls_16, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
+ return KTls_16();
+ case 0x19:
+ _LIT8(KTls_19, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA");
+ return KTls_19();
+
+// from RFC 3268 : Advanced Encryption Standard (AES) Ciphersuites for Transport Layer Security (TLS)
+ case 0x2F:
+ _LIT8(KTls_2F, "TLS_RSA_WITH_AES_128_CBC_SHA");
+ return KTls_2F();
+ case 0x35:
+ _LIT8(KTls_35, "TLS_RSA_WITH_AES_256_CBC_SHA");
+ return KTls_35();
+ default:
+ return KNullDesC8;
+ } // end switch
+}
+
+void CHttpTransactionClient::StoreOneCookieL(HBufC8*& aRawHeader, RHTTPHeaders aHeaders, TInt aPartIndex, RStringF aFieldName)
+{
+ THTTPHdrVal name, value;
+ RStringPool strP = iTransaction.Session().StringPool();
+
+ RStringF cookieName = strP.StringF(HTTP::ECookieName, RHTTPSession::GetTable());
+ RStringF cookieValue= strP.StringF(HTTP::ECookieValue, RHTTPSession::GetTable());
+ RStringF cookiePath= strP.StringF(HTTP::EPath, RHTTPSession::GetTable());
+ RStringF cookieDomain= strP.StringF(HTTP::EDomain, RHTTPSession::GetTable());
+ RStringF cookieMaxAge= strP.StringF(HTTP::EMaxAge, RHTTPSession::GetTable());
+ RStringF cookiePort= strP.StringF(HTTP::ECookiePort, RHTTPSession::GetTable());
+ RStringF cookieComment= strP.StringF(HTTP::EComment, RHTTPSession::GetTable());
+ RStringF cookieCommentURL= strP.StringF(HTTP::ECommentURL, RHTTPSession::GetTable());
+ RStringF cookieSecure= strP.StringF(HTTP::ESecure, RHTTPSession::GetTable());
+ RStringF cookieDiscard= strP.StringF(HTTP::EDiscard, RHTTPSession::GetTable());
+ RStringF cookieVersion= strP.StringF(HTTP::EVersion, RHTTPSession::GetTable());
+ RStringF cookieExpires= strP.StringF(HTTP::EExpires, RHTTPSession::GetTable());
+
+ aHeaders.GetParam(aFieldName, cookieName , name, aPartIndex);
+ aHeaders.GetParam(aFieldName, cookieValue, value, aPartIndex);
+
+ TInt len1 = name.Str().DesC().Length();
+ TInt len2 = value.Str().DesC().Length();
+ HBufC8* temp = HBufC8::NewLC(KCookieBufferAllocLength);
+ if (((temp->Des().Length()+1+len1+len2)) <(KCookieBufferAllocLength-iMinLength))
+ {
+ temp->Des().Append(name.Str().DesC());
+ temp->Des().Append(KEquals);
+ temp->Des().Append(value.Str().DesC());
+ temp->Des().Append(KSemiColonSpace);
+ }
+ else
+ {
+ iDiscardCookie = true;
+ }
+
+ THTTPHdrVal hdrVal;
+
+ if (aHeaders.GetParam(aFieldName, cookieComment, hdrVal, aPartIndex) == KErrNone)
+ AddParam(temp, cookieComment.DesC(), hdrVal.StrF().DesC());
+
+ if (aHeaders.GetParam(aFieldName, cookieCommentURL, hdrVal, aPartIndex) == KErrNone)
+ AddParam(temp, cookieCommentURL.DesC(), hdrVal.StrF().DesC());
+
+ if (aHeaders.GetParam(aFieldName, cookieDiscard, hdrVal, aPartIndex) == KErrNone)
+ AddParam(temp, cookieDiscard.DesC(), hdrVal.StrF().DesC());
+
+ if (aHeaders.GetParam(aFieldName, cookieDomain, hdrVal, aPartIndex) == KErrNone)
+ AddParam(temp, cookieDomain.DesC(), hdrVal.StrF().DesC());
+
+ if (aHeaders.GetParam(aFieldName, cookieMaxAge, hdrVal, aPartIndex) == KErrNone)
+ AddParam(temp, cookieMaxAge.DesC(), hdrVal.StrF().DesC());
+
+ if (aHeaders.GetParam(aFieldName, cookiePath, hdrVal, aPartIndex) == KErrNone)
+ AddParam(temp, cookiePath.DesC(), hdrVal.StrF().DesC());
+
+ if (aHeaders.GetParam(aFieldName, cookiePort, hdrVal, aPartIndex) == KErrNone)
+ AddParam(temp, cookiePort.DesC(), hdrVal.StrF().DesC());
+
+ if (aHeaders.GetParam(aFieldName, cookieSecure, hdrVal, aPartIndex) == KErrNone)
+ AddParam(temp, cookieSecure.DesC(), hdrVal.StrF().DesC());
+
+ if (aHeaders.GetParam(aFieldName, cookieVersion, hdrVal, aPartIndex) == KErrNone)
+ AddParam(temp, cookieVersion.DesC(), hdrVal.StrF().DesC());
+
+ if (aHeaders.GetParam(aFieldName, cookieExpires, hdrVal, aPartIndex) == KErrNone)
+ AddParam(temp, cookieExpires.DesC(), hdrVal.StrF().DesC());
+
+// If the cookie size is more than 4K, the cookie is discarded
+ if (iDiscardCookie != true)
+ aRawHeader->Des().Append(*temp);
+
+ CleanupStack::PopAndDestroy(temp);
+}
+
+void CHttpTransactionClient::AddParam(HBufC8*& aTemp, const TDesC8& aName, const TDesC8& aValue)
+{
+ TInt len = aName.Length()+aValue.Length();
+ if ((aTemp->Des().Length()+len+1) < (KCookieBufferAllocLength - iMinLength))
+ {
+ aTemp->Des().Append(aName);
+ aTemp->Des().Append(KEquals);
+ aTemp->Des().Append(aValue);
+ aTemp->Des().Append(KSemiColonSpace);
+ }
+ else
+ {
+ iDiscardCookie = true;
+ }
+}