--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/webservices/wshttpchanneltransportplugin/src/senmultiparttxnstate.cpp Thu Jan 07 16:19:19 2010 +0200
@@ -0,0 +1,559 @@
+/*
+* Copyright (c) 2002-2005 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:
+*
+*/
+
+
+
+
+
+
+
+
+// INCLUDE FILES
+#include <http.h>
+
+#include "senmultiparttxnstate.h"
+#include "senhttpchannel.h"
+#include "sendebug.h"
+#include "senlogger.h"
+
+
+// =========================== MEMBER FUNCTIONS ===============================
+
+// ----------------------------------------------------------------------------
+// CSenMultiPartTxnState::CSenMultiPartTxnState
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// ----------------------------------------------------------------------------
+//
+CSenMultiPartTxnState::CSenMultiPartTxnState(MSenResponseObserver& aObserver)
+ : CSenTxnState(aObserver),
+ iRootCid(NULL),
+ iMimeBoundaryOut(NULL),
+ iMimeBoundaryIn(NULL),
+ iMimeBoundaryEndIn(NULL),
+ iPartDataOut(1),
+ iLastPartOut(EFalse),
+ iPartDataIn(1),
+ iLastPartIn(EFalse),
+ iCurPart(EFalse),
+ iBinaryDataEnd(ETrue),
+ iChecked(EFalse),
+ iBinaryDataPart(NULL),
+ iBinaryDataParts(NULL),
+ iBinaryDataRest(NULL),
+ iFirst(ETrue)
+ {
+ }
+
+
+
+CSenMultiPartTxnState::~CSenMultiPartTxnState()
+ {
+ iMessage = NULL;
+ iBinaryDataList.Close();
+ iRootCid.Close();
+ iMimeBoundaryOut.Close();
+ iMimeBoundaryIn.Close();
+ iMimeBoundaryEndIn.Close();
+ iCurrentPart.Close();
+ iSoapAction.Close();
+ iXopEnvelopeResponse.Close();
+ iBlobHeader.Close();
+
+ for(TUint i(0); i < iFileNames.Count(); ++i) // iFileNames.Count() equals iCids.Count()
+ {
+ iFileNames[i].Close();
+ iCids[i].Close();
+ }
+ iFileNames.Close();
+ iCids.Close();
+ }
+
+
+
+// ---------------------------------------------------------------------
+// calculates number of parts in BLOB (every part = 10KB)
+// and how many bytes there are in the last part
+//----------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::SizeBinaryData(TUint aIndex)
+ {
+ TUint size = iBinaryDataList[aIndex].Size();
+ iBinaryDataParts = size/KTenKBytes;
+ iBinaryDataRest = size%KTenKBytes;
+ if (iBinaryDataParts > 0)
+ {
+ iBinaryDataEnd = EFalse;
+ }
+ }
+
+// ---------------------------------------------------------------------
+// creates header for Blob in Request
+// ---------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::BlobHeaderL()
+ {
+ // iCurrentPart == header, binary part
+ RBuf8 boundaryStart;
+ boundaryStart.CleanupClosePushL();
+ SenMultiPartUtils::BoundaryLineStartL(iMimeBoundaryOut, boundaryStart);
+
+ TUint index = (iPartDataOut - 3)/2;
+
+ RBuf8 headerBinaryData;
+ headerBinaryData.CleanupClosePushL();
+ SenMultiPartUtils::HeaderBinaryDataL(index, iBinaryDataList, headerBinaryData);
+
+ iCurrentPart.ReAllocL(2*KNewLine().Length()+boundaryStart.Length()+headerBinaryData.Length());
+ iCurrentPart.Append(KNewLine);
+ iCurrentPart.Append(KNewLine);
+ iCurrentPart.Append(boundaryStart);
+ iCurrentPart.Append(headerBinaryData);
+ CleanupStack::PopAndDestroy(&headerBinaryData);
+ CleanupStack::PopAndDestroy(&boundaryStart);
+ TLSLOG(KSenHttpChannelLogChannelBase , KMinLogLevel,(_L("CSenMultiPartTxnState::GetNextDataPart - aDataPart (header, binary part):")));
+ iCurPart = ETrue;
+ }
+
+// ---------------------------------------------------------------------
+// for case if Blob is kept in a file
+// this function passes Blob from a file part by part (every part = 10KB)
+// in Request
+// ---------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::FileContainerL(TUint aIndex)
+ {
+ if (!iChecked)
+ {
+ SizeBinaryData(aIndex);
+ iChecked = ETrue;
+ }
+ if (iBinaryDataPart < iBinaryDataParts)
+ {
+ SenMultiPartUtils::FileDataPartL(iBinaryDataPart, aIndex, iBinaryDataList, iCurrentPart);
+ }
+ else if (iBinaryDataRest != 0)
+ {
+ SenMultiPartUtils::FileDataRestL(iBinaryDataParts, iBinaryDataRest, aIndex, iBinaryDataList, iCurrentPart);
+ iBinaryDataEnd = ETrue;
+ }
+ iCurPart = ETrue;
+ }
+
+// ---------------------------------------------------------------------
+// creates the last part (MimeBoundaryEnd) in Request
+// ---------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::XopEndL()
+ {
+ // iCurrentPart == XOP end
+ SenMultiPartUtils::BoundaryLineEndL(iMimeBoundaryOut, iCurrentPart);
+ TLSLOG(KSenHttpChannelLogChannelBase , KMinLogLevel,(_L("CSenMultiPartTxnState::GetNextDataPart - aDataPart (boundary end):")));
+ iCurPart = ETrue;
+ iLastPartOut = ETrue;
+ }
+
+// ----------------------------------------------------------------------------
+// CSenMultiPartTxnState::GetNextDataPart
+// Implementation of the pure virtual method from MHTTPDataSupplier
+// ----------------------------------------------------------------------------
+//
+TBool CSenMultiPartTxnState::GetNextDataPart(TPtrC8& aDataPart)
+ {
+ TBool lastPart(EFalse);
+ TRAP_IGNORE(lastPart = GetNextDataPartL(aDataPart));
+ return lastPart;
+ }
+
+// ----------------------------------------------------------------------------
+// CSenMultiPartTxnState::ReleaseData
+// Implementation of the pure virtual method from MHTTPDataSupplier
+// ----------------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::ReleaseData()
+ {
+ TLSLOG(KSenHttpChannelLogChannelBase , KMinLogLevel,(_L("CSenMultiPartTxnState::ReleaseData")));
+ iCurPart = EFalse;
+ iCurrentPart.Close();
+ if (!iLastPartOut)
+ {
+ // Notify HTTP of more data available immediately
+ TRAP_IGNORE(Transaction().NotifyNewRequestBodyPartL());
+ if (iBinaryDataEnd)
+ {
+ iPartDataOut++;
+ iChecked = EFalse;
+ iBinaryDataPart = 0;
+ }
+ else
+ {
+ ++iBinaryDataPart;
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CSenMultiPartTxnState::OverallDataSize
+// Implementation of the pure virtual method from MHTTPDataSupplier
+// ----------------------------------------------------------------------------
+//
+TInt CSenMultiPartTxnState::OverallDataSize()
+ {
+ return KErrNotFound;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CSenMultiPartTxnState::Reset
+// Implementation of the pure virtual method from MHTTPDataSupplier
+// ----------------------------------------------------------------------------
+//
+TInt CSenMultiPartTxnState::Reset()
+ {
+ TLSLOG(KSenHttpChannelLogChannelBase , KMinLogLevel,(_L("CSenMultiPartTxnState::Reset")));
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// parses Response from server (MultiPart message) and extracts MimeBoundary part
+// and MimeBoundaryEnd part
+// ---------------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::MimeBoundaryInL(TPtrC8& aDataPartPtr, TInt& aOffset, TInt& aOffset1)
+ {
+ _LIT8(KDDash,"--");
+ aOffset = aDataPartPtr.Find(KDDash); //CodeScannerWarnings
+ if (aOffset == KErrNotFound)
+ {
+ User::Panic(KMultiPartResponseBodyInvalidPanicText, SenMultiPartUtils::EMultiPartResponseBodyInvalid);
+ }
+ aDataPartPtr.Set(aDataPartPtr.Right(aDataPartPtr.Length()-aOffset));
+ aOffset = aDataPartPtr.Find(_L8("\r\n"));
+
+ iMimeBoundaryIn.ReAllocL(aOffset);
+ iMimeBoundaryIn.Copy(aDataPartPtr.Left(aOffset));
+
+ iMimeBoundaryEndIn.ReAllocL(aOffset+2);
+ iMimeBoundaryEndIn.Append(iMimeBoundaryIn);
+ iMimeBoundaryEndIn.Append(KDDash);
+
+ aDataPartPtr.Set(aDataPartPtr.Right(aDataPartPtr.Length()-aOffset-2));
+
+ aOffset = aDataPartPtr.Find(_L8("\r\n\r\n"));
+ aOffset1 = aDataPartPtr.Find(iMimeBoundaryEndIn);
+ if (aOffset1 != KErrNotFound)
+ {
+ iLastPartIn = ETrue;
+ }
+ if (aOffset != KErrNotFound)
+ {
+ aDataPartPtr.Set(aDataPartPtr.Right(aDataPartPtr.Length()-aOffset-4));
+ iPartDataIn++;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// parses Response from server (MultiPart message) and extracts XopEnvelope part
+// ---------------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::XopEnvelopeResponseL(TPtrC8& aDataPartPtr, TInt& aOffset, TInt& aOffset1)
+ {
+ aOffset = aDataPartPtr.Find(iMimeBoundaryIn);
+ aOffset1 = aDataPartPtr.Find(iMimeBoundaryEndIn);
+ if (aOffset1 != KErrNotFound)
+ {
+ iLastPartIn = ETrue;
+ }
+ if (aOffset == KErrNotFound)
+ {
+ iXopEnvelopeResponse.ReAllocL(iXopEnvelopeResponse.Length()+aDataPartPtr.Length());
+ iXopEnvelopeResponse.Append(aDataPartPtr);
+ }
+ else
+ {
+ iXopEnvelopeResponse.ReAllocL(iXopEnvelopeResponse.Length()+aOffset-4);
+ iXopEnvelopeResponse.Append(aDataPartPtr.Left(aOffset-4));
+ aDataPartPtr.Set(aDataPartPtr.Right(aDataPartPtr.Length()-aOffset));
+ iPartDataIn++;
+ iObserver->FileProgress(iId, ETrue, ETrue,
+ iXopEnvelopeResponse, iXopEnvelopeResponse.Length());
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// parses Response from server (MultiPart message) and extracts header of Blob part
+// ---------------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::BlobHeaderResponseL(TPtrC8& aDataPartPtr, TInt& aOffset, TInt& aOffset1)
+ {
+ aOffset = aDataPartPtr.Find(_L8("\r\n\r\n"));
+ aOffset1 = aDataPartPtr.Find(iMimeBoundaryEndIn);
+
+ if (aOffset1 != KErrNotFound)
+ {
+ iLastPartIn = ETrue;
+ }
+ if (aOffset == KErrNotFound)
+ {
+ iBlobHeader.ReAllocL(iBlobHeader.Length()+aDataPartPtr.Length());
+ iBlobHeader.Append(aDataPartPtr);
+ }
+ else
+ {
+ iBlobHeader.ReAllocL(iBlobHeader.Length()+aOffset);
+ iBlobHeader.Append(aDataPartPtr.Left(aOffset));
+
+ // extract cids
+ SenMultiPartUtils::CidL(iBlobHeader, iCids);
+
+ iBlobHeader.Close();
+
+ aDataPartPtr.Set(aDataPartPtr.Right(aDataPartPtr.Length()-aOffset-4));
+ iPartDataIn++;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// parses Response from server (MultiPart message) and extracts Blob part
+// puts it in the file
+// ---------------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::BlobResponseL(TPtrC8& aDataPartPtr, TInt& aOffset, TInt& aOffset1)
+ {
+ TInt size(0);
+ aOffset = aDataPartPtr.Find(iMimeBoundaryIn);
+ aOffset1 = aDataPartPtr.Find(iMimeBoundaryEndIn);
+ if (aOffset1 != KErrNotFound)
+ {
+ iLastPartIn = ETrue;
+ }
+ TUint index = (iPartDataIn-4)/2;
+
+ if (aOffset == KErrNotFound)
+ {
+ size = SenMultiPartUtils::SetFileL(index, iFirst, aDataPartPtr, iFileNames);
+ iFirst = EFalse;
+ }
+ else
+ {
+ TPtrC8 blobPartPtr;
+ blobPartPtr.Set(aDataPartPtr.Left(aOffset-4));
+ size = SenMultiPartUtils::SetFileL(index, iFirst, blobPartPtr, iFileNames);
+ aDataPartPtr.Set(aDataPartPtr.Right(aDataPartPtr.Length()-aOffset));
+ iFirst = ETrue;
+ iPartDataIn++;
+ }
+ iObserver->FileProgress(iId, ETrue, EFalse, iCids[index], size);
+ }
+
+// ---------------------------------------------------------------------------
+// parses Response from server (MultiPart message)
+// ---------------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::ParseMultiPartResponseL(TDesC8& aDataPart)
+ {
+ TPtrC8 dataPartPtr;
+ dataPartPtr.Set(aDataPart);
+
+ TInt offset(0);
+ TInt offset1(-1);
+ if (!iLastPartIn)
+ {
+ while ((dataPartPtr.Length()) && (offset != offset1))
+ {
+ if (iPartDataIn == 1)
+ {
+ MimeBoundaryInL(dataPartPtr, offset, offset1);
+ }
+ else if (iPartDataIn == 2)
+ {
+ XopEnvelopeResponseL(dataPartPtr, offset, offset1);
+ }
+ else if ((iPartDataIn > 2) && (iPartDataIn%2 != 0))
+ {
+ BlobHeaderResponseL(dataPartPtr, offset, offset1);
+ }
+ else if ((iPartDataIn > 2) && (iPartDataIn%2 == 0))
+ {
+ BlobResponseL(dataPartPtr, offset, offset1);
+ }
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// added HttpTransportProperties about Cids of Blobs and File namess,
+// where Blobs are kept
+// and passes transport properties and XopEnvelope to an observer
+//------------------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::ResponseReceivedL(const SenMultiPartUtils::TMultiPartContentType& aMultiPartContentType)
+ {
+ TLSLOG_FORMAT((KSenHttpChannelLogChannelBase , KMinLogLevel, _L8("CSenMultiPartTxnState(%d)::ResponseReceivedL"), iId));
+ TLSLOG_L(KSenHttpChannelLogChannelBase , KMaxLogLevel,"iXopEnvelopeResponse:");
+ TLSLOG_ALL(KSenHttpChannelLogChannelBase , KMaxLogLevel,(iXopEnvelopeResponse));
+
+
+ if(iXopEnvelopeResponse.Length())
+ {
+ CSenHttpTransportProperties* pHttpProperties = CSenHttpTransportProperties::NewLC();
+
+ pHttpProperties->SetDownloadFolderL(KDownloadFolder);
+ for (TUint i=0; i < iCids.Count(); ++i)
+ {
+ pHttpProperties->SetFileAttachmentL(iCids[i], iFileNames[i]);
+ }
+ HBufC8* pResponse = iXopEnvelopeResponse.AllocL();
+ // delete allocated body
+ iXopEnvelopeResponse.Close();
+ iObserver->ResponseReceivedL(iId, &aMultiPartContentType, pResponse, pHttpProperties);
+ CleanupStack::PopAndDestroy(pHttpProperties);
+ }
+ else
+ {
+ TLSLOG_L(KSenHttpChannelLogChannelBase , KMinLogLevel,"Fatal: NULL response received in MultiPartTxnState!");
+ // delete allocated body
+ iXopEnvelopeResponse.Close();
+ }
+
+ }
+// ---------------------------------------------------------------------
+// creates header for SoapEnvelope in Request
+// ---------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::MessageHeaderL()
+ {
+ RBuf8 boundaryStart;
+ boundaryStart.CleanupClosePushL();
+
+ // Note: BoundaryLineStart re-allocates (and first de-allocates) boundaryStart
+ SenMultiPartUtils::BoundaryLineStartL(iMimeBoundaryOut, boundaryStart);
+
+ RBuf8 headerRoot;
+ headerRoot.CleanupClosePushL();
+
+ // Note: HeaderRootL re-allocates (and first de-allocates) iRootCid
+ SenMultiPartUtils::HeaderRootL(iMessage, iRootCid, headerRoot);
+
+ // iCurrentPart == header root:
+ iCurrentPart.ReAllocL(boundaryStart.Length()+headerRoot.Length());
+ iCurrentPart.Append(boundaryStart);
+ iCurrentPart.Append(headerRoot);
+ CleanupStack::PopAndDestroy(&headerRoot);
+ CleanupStack::PopAndDestroy(&boundaryStart);
+ TLSLOG(KSenHttpChannelLogChannelBase , KMinLogLevel,(_L("CSenMultiPartTxnState::MessageHeaderL")));
+ iCurPart = ETrue;
+ }
+
+// ---------------------------------------------------------------------
+// creates SoapEnvelope in Request
+// ---------------------------------------------------------------------
+//
+void CSenMultiPartTxnState::MessageL()
+ {
+ }
+
+
+// ----------------------------------------------------------------------------
+// creates Request for MultiPart message in MultiPart format
+// should be used to send MultiPart message through HTTP Channel
+// ----------------------------------------------------------------------------
+//
+TBool CSenMultiPartTxnState::GetNextDataPartL(TPtrC8& aDataPart)
+ {
+ TLSLOG(KSenHttpChannelLogChannelBase , KMinLogLevel,(_L("CSenMtomTxnState::GetNextDataPart")));
+
+ if(!HasRequestBody())
+ {
+ iLastPartOut = ETrue;
+ iPartDataOut = 0;
+ }
+ else
+ {
+ if(!iCurPart) // Note: this is zero only when new part is requested
+ {
+ if ((iPartDataOut == 1) && (iPartDataOut < iCountDataParts))
+ {
+ MessageHeaderL(); // First part of MultiPart message = header of SoapEnvelope
+ }
+ else if ((iPartDataOut == 2) && (iPartDataOut < iCountDataParts))
+ {
+ MessageL(); // Second part of MultiPart message = SoapEnvelope
+ }
+ else if ((iPartDataOut > 2) && (iPartDataOut%2 != 0) && (iPartDataOut < iCountDataParts))
+ {
+ BlobHeaderL(); // Third and then all odd parts = headers of Blobs
+ }
+ else if ((iPartDataOut > 2) && (iPartDataOut%2 == 0) && (iPartDataOut < iCountDataParts))
+ {
+ TUint index = (iPartDataOut - 4)/2;
+
+ switch (iBinaryDataList[index].NodeType()) // Fourth and then all even parts = Blobs
+ {
+ case TXmlEngNode::EChunkContainer: // blob is kept in Chunk
+ {
+ TInt offset = iBinaryDataList[index].AsChunkContainer().ChunkOffset();
+ aDataPart.Set(iBinaryDataList[index].AsChunkContainer().Chunk().Base()+offset,iBinaryDataList[index].Size());
+ TLSLOG_ALL(KSenHttpChannelLogChannelBase , KMaxLogLevel,aDataPart);
+ iBinaryDataEnd = ETrue;
+ return iLastPartOut;
+ }
+
+ case TXmlEngNode::EFileContainer: // blob is kept in File
+ {
+ FileContainerL(index);
+ break;
+ }
+
+ case TXmlEngNode::EBinaryContainer: // blob is kept as binary data
+ {
+ aDataPart.Set(iBinaryDataList[index].AsBinaryContainer().Contents());
+ return iLastPartOut;
+ }
+
+ default:
+ {
+ User::Panic(KMultiPartBlobContainerTypeInvalidPanicText,
+ SenMultiPartUtils::EMultiPartBlobContainerTypeInvalid); }
+ }
+
+ TLSLOG(KSenHttpChannelLogChannelBase , KMinLogLevel,(_L("CSenMtomTxnState::GetNextDataPart - aDataPart (binary data)")));
+ if (iBinaryDataPart)
+ {
+ iObserver->FileProgress(iId, EFalse, EFalse,
+ iBinaryDataList[index].Cid(), iBinaryDataPart*KTenKBytes);
+ }
+ }
+ else if (iPartDataOut == iCountDataParts)
+ {
+ TUint index = (iPartDataOut - 4)/2;
+ XopEndL(); // The last part of MultiPart message = MimeBoundaryEnd
+ if ((iPartDataOut > 2) && (iPartDataOut%2 == 0))
+ {
+ iObserver->FileProgress(iId, EFalse, EFalse,
+ iBinaryDataList[index].Cid(), iBinaryDataList[index].Size());
+ }
+
+ }
+ } // on first call, allocate the current part
+ aDataPart.Set(iCurrentPart); // .. otherwise, just re-use it
+ TLSLOG_ALL(KSenHttpChannelLogChannelBase , KMaxLogLevel,aDataPart);
+ }
+ return iLastPartOut;
+ }
+
+// End of File