diff -r e8e63152f320 -r 2a9601315dfc javacommons/gcfprotocols/http/src.s60/chttptransactionclient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javacommons/gcfprotocols/http/src.s60/chttptransactionclient.cpp Mon May 03 12:27:20 2010 +0300 @@ -0,0 +1,1075 @@ +/* +* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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* 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* aRawHeaders) +{ + LOG(ESOCKET,EInfo,"CHttpTransactionClient::GetResponseL(RPointerArray* 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); + + // 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 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; +// } +// } + 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()); +} + +// RHTTPResponse CHttpTransactionClient::GetResponseL() +// { +// LOG(ESOCKET,EInfo,"CHttpTransactionClient::GetResponseL"); +// return iTransaction.Response(); +// } +/* +* 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() +{ + //__ASSERT_DEBUGCOMP(iJavaWaitingOnCallBack==EFalse, User::Panic(_L("Http Java Waiting on notification"), KErrGeneral )); + 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(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; + } +}