diff -r 000000000000 -r b16258d2340f applayerpluginsandutils/httpprotocolplugins/httpclient/chttprequestcomposer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/applayerpluginsandutils/httpprotocolplugins/httpclient/chttprequestcomposer.cpp Tue Feb 02 01:09:52 2010 +0200 @@ -0,0 +1,510 @@ +// Copyright (c) 2003-2009 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 "chttprequestcomposer.h" + +#include +#include + +#include "chttpresponseparser.h" +#include "mhttprequestobserver.h" +#include "chttpclienttransaction.h" + + +CHttpRequestComposer* CHttpRequestComposer::NewL(CProtTransaction& aProtTrans, MHttpRequestObserver& aObserver) + { + CHttpRequestComposer* self = new (ELeave) CHttpRequestComposer(aProtTrans, aObserver); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CHttpRequestComposer::~CHttpRequestComposer() + { + if(iCorkingEnabled) + { + // Disable corking. + iObserver.SendingBodyData(EFalse); + } + + iMessageComposer.Close(); + iTrailerHeaders.Reset(); + +// __FLOG_CLOSE; + } + +CHttpRequestComposer::CHttpRequestComposer(CProtTransaction& aProtTrans, MHttpRequestObserver& aObserver) +: CTxData(aProtTrans), iStringTable(RHTTPSession::GetTable()), + iObserver(aObserver), + iStringPool(aProtTrans.Transaction().Session().StringPool()), + iRequest(aProtTrans.Transaction().Request()), + iFields(aProtTrans.Transaction().Request().GetHeaderCollection().Fields()), + iPropertySet(aProtTrans.Transaction().PropertySet()) + + { +// __FLOG_OPEN("http", "httpclienthandler.txt"); + } + +void CHttpRequestComposer::ConstructL() + { + iMessageComposer.OpenL(*this); + } + +void CHttpRequestComposer::NotifyMoreRequestBodyData() + { + __FLOG_1(_T8("Trans %d : notify more request body data"), iProtTrans->Transaction().Id()); + + iMessageComposer.MessageInfoAvailable(); + } + +void CHttpRequestComposer::InitHeadersL() + { + // Extract header fields from the Trailer header, if it exists. + THTTPHdrVal trailerHeaderVal; + RHTTPHeaders headers = iRequest.GetHeaderCollection(); + RStringF trailerName = iStringPool.StringF(HTTP::ETrailer, iStringTable); + TInt index =0; + while( headers.GetField( + trailerName, + index, + trailerHeaderVal + ) != KErrNotFound ) + { + __ASSERT_DEBUG( trailerHeaderVal.Type() == THTTPHdrVal::KStrFVal, User::Invariant() ); + + // @todo should we check to see if header is not Content-Length, + // @todo Transfer-Encoding or Trailer? + + // Got a trailer header - append to the list + RStringF header = trailerHeaderVal.StrF(); + User::LeaveIfError(iTrailerHeaders.Append(header)); + + // Next... + ++index; + } + + if( iTrailerHeaders.Count() > 0 ) + { + // There are trailer headers - can only send as trailers if the request + // has a body and it is going to be chunk encoded. + MHTTPDataSupplier* body = iRequest.Body(); + + if( body == NULL || body->OverallDataSize() != KErrNotFound ) + { + // Either there is no body, or the body is not going to be chunk + // encoded - remove the Trailer header field. + headers.RemoveField(trailerName); + iTrailerHeaders.Reset(); + } + } + + // Reset the fields iterator + iFields.First(); + } + +TBool CHttpRequestComposer::IsTrailerHeader(RStringF aHeader) + { + TInt count = iTrailerHeaders.Count(); + TBool found = EFalse; + while( count > 0 && !found ) + { + if( iTrailerHeaders[--count] == aHeader ) + { + // aHeader is a trailer header + found = ETrue; + } + } + return found; + } + +/* + * Methods from MHTTPDataSupplier, via CTxData + */ + +TBool CHttpRequestComposer::GetNextDataPart(TPtrC8& /*aDataPart*/) + { + // @todo should we deprecate derivation from MHTTPDataSupplier? + User::Invariant(); + return EFalse; + } + +void CHttpRequestComposer::ReleaseData() + { + // @todo should we deprecate derivation from MHTTPDataSupplier? + User::Invariant(); + } + +TInt CHttpRequestComposer::OverallDataSize() + { + // @todo should we deprecate derivation from MHTTPDataSupplier? + User::Invariant(); + return KErrNotFound; + } + +TInt CHttpRequestComposer::Reset() + { + // @todo should we deprecate derivation from MHTTPDataSupplier? + User::Invariant(); + return KErrNotFound; + } + +/* + * Methods from MHttpRequest + */ + +void CHttpRequestComposer::StartRequest() + { + __FLOG_1(_T8("Trans %d : starting request"), iProtTrans->Transaction().Id()); + + RStringF notifyContinue = iStringPool.StringF(HTTP::ENotify100Continue, iStringTable); + RStringF enableNotification = iStringPool.StringF(HTTP::EEnableNotification, iStringTable); + THTTPHdrVal notifyContinueVal; + iPropertySet.Property(notifyContinue, notifyContinueVal); + + ((notifyContinueVal.Type()==THTTPHdrVal::KStrFVal) && (notifyContinueVal.StrF() == enableNotification))?(iSuspendRequest = ETrue):(iSuspendRequest = EFalse); + + iMessageComposer.MessageInfoAvailable(); + } + +void CHttpRequestComposer::CancelRequest() + { + __FLOG_1(_T8("-> Trans %d : request cancelled"), iProtTrans->Transaction().Id()); + + iMessageComposer.Reset(); + } + +void CHttpRequestComposer::RequestDataSent() + { + if(!IsSuspendedRequest()) + { + iMessageComposer.ReleaseMessageData(); + } + } + +void CHttpRequestComposer::OnRequestSendTimeOut() + { + // Notify the client of Request Send TimeOut. + RHTTPTransaction trans = iProtTrans->Transaction(); + if(trans.SendEvent(THTTPEvent::ESendTimeOut, THTTPEvent::EIncoming, THTTPFilterHandle(THTTPFilterHandle::EProtocolHandler)) != KErrNone) + { + trans.Fail(THTTPFilterHandle::EProtocolHandler); + } + else + { + // Notify the client that Transaction Failed. + if(trans.SendEvent(THTTPEvent::EFailed, THTTPEvent::EIncoming, THTTPFilterHandle(THTTPFilterHandle::EProtocolHandler)) != KErrNone) + { + trans.Fail(THTTPFilterHandle::EProtocolHandler); + } + } + } + +TInt CHttpRequestComposer::SendTimeOutValue() + { + RHTTPTransaction trans = iProtTrans->Transaction(); + RStringPool stringPool = trans.Session().StringPool(); + RStringF sendTimeOut = stringPool.StringF(HTTP::ESendTimeOutValue, iStringTable); + THTTPHdrVal sendTimeOutVal; + + TBool ret = trans.PropertySet().Property(sendTimeOut,sendTimeOutVal); + if(ret && (sendTimeOutVal.Type() == THTTPHdrVal::KTIntVal)) + { + return sendTimeOutVal.Int(); + } + return 0; + } + +/* + * Methods from MHttpMessageComposerObserver + */ + +void CHttpRequestComposer::StartLineL(TPtrC8& aMethod, TPtrC8& aRequestUri, TPtrC8& aVersion) + { + // The RFC2616 defines the Request-Line as follows - + // + // Request-Line = Method SP Request-URI SP HTTPVersion CRLF + // + // Get Method... + RStringF method = iStringPool.StringF(iRequest.Method()); + aMethod.Set(method.DesC()); + + RHTTPTransaction trans = iProtTrans->Transaction(); + + // Get the Request-URI... + THTTPHdrVal uri; + if( !trans.PropertySet().Property(iStringPool.StringF(HTTP::EUri, iStringTable), uri) ) + { + // The EUri property has not been set - leave! + User::Leave(KErrCorrupt); + } + aRequestUri.Set(uri.Str().DesC()); + + // Get HTTPVersion - check to see if client has set a version + RHTTPConnectionInfo connectionInfo = trans.Session().ConnectionInfo(); + THTTPHdrVal httpVersion; + if( connectionInfo.Property(iStringPool.StringF(HTTP::EHTTPVersion, iStringTable), httpVersion) ) + { + // Use the client specified version + aVersion.Set(httpVersion.StrF().DesC()); + } + else + { + // Assume HTTP/1.1 + aVersion.Set(iStringPool.StringF(HTTP::EHttp11, iStringTable).DesC()); + } + + __FLOG_4(_T8("Trans %d : request-line -> %S %S %S"), iProtTrans->Transaction().Id(), &aMethod, &aRequestUri, &aVersion); + + // Initialise header info + InitHeadersL(); + } + +TInt CHttpRequestComposer::NextHeaderL(TPtrC8& aHeaderName, TPtrC8& aHeaderValue) + { + // Are there any more headers? + TInt err = KErrNotFound; + TBool done = EFalse; + while( !iFields.AtEnd() && !done ) + { + // Get field current field. + RStringF name = iStringPool.StringF(iFields()); + + // Check to see if a trailer header + if( !IsTrailerHeader(name) ) + { + // Ok, found a header - done! + err = KErrNone; + done = ETrue; + + // Get the OTA version of the field value + TPtrC8 value; + iRequest.GetHeaderCollection().GetRawFieldL(name, value); + + // Pass back these values + aHeaderName.Set(name.DesC()); + aHeaderValue.Set(value); + + __FLOG_3(_T8("Trans %d : request header -> %S: %S"), iProtTrans->Transaction().Id(), &aHeaderName, &aHeaderValue); + } + + // Move onto next header field... + ++iFields; + } + return err; + } + +MHTTPDataSupplier* CHttpRequestComposer::HasBodyL() + { +#if defined (_DEBUG) && defined (_LOGGING) + MHTTPDataSupplier* body = iRequest.Body(); + + if( body == NULL ) + { + __FLOG_1(_T8("Trans %d : no request entity body"), iProtTrans->Transaction().Id()); + } + else if( body->OverallDataSize() == KErrNotFound ) + { + __FLOG_1(_T8("Trans %d : chunked request entity body"), iProtTrans->Transaction().Id()); + } + else + { + __FLOG_2(_T8("Trans %d : request entity body length = %d"), iProtTrans->Transaction().Id(), body->OverallDataSize()); + } +#endif + + return iRequest.Body(); + } + +TInt CHttpRequestComposer::NextTrailerL(TPtrC8& aHeaderName, TPtrC8& aHeaderValue) + { + TInt err = KErrNotFound; + + if( iTrailerHeaders.Count() > 0 ) + { + // Ok, still got trailers. + err = KErrNone; + + // Get trailer field. + RStringF name = iTrailerHeaders[0]; + + // Get the OTA version of the field value + TPtrC8 value; + iRequest.GetHeaderCollection().GetRawFieldL(name, value); + + // Pass back these values + aHeaderName.Set(name.DesC()); + aHeaderValue.Set(value); + + // Remove this trailer from the array. + iTrailerHeaders.Remove(0); + + __FLOG_3(_T8("Trans %d : request trailer -> %S: %S"), iProtTrans->Transaction().Id(), &aHeaderName, &aHeaderValue); + } + return err; + } + +void CHttpRequestComposer::MessageComplete() + { + __FLOG_1(_T8("Trans %d : request complete"), iProtTrans->Transaction().Id()); + if(iCorkingEnabled) + { + // Disable corking. + iCorkingEnabled = iRequestHeaderSent = EFalse; + iObserver.SendingBodyData(EFalse); + } + + iObserver.RequestComplete(); + iRequestSent = ETrue; + } + +void CHttpRequestComposer::MessageDataReadyL() + { + if(iRequestHeaderSent) + { + // If we hit this function that means we need to send body data. + // So we are sending the body data. Enable corking. + if(!iCorkingEnabled) + { + __FLOG_1(_T8("Trans %d : Corking is enabled"), iProtTrans->Transaction().Id()); + iCorkingEnabled = ETrue; + iObserver.SendingBodyData(ETrue); + } + else + { + __FLOG_1(_T8("Trans %d : Corking is already enabled"), iProtTrans->Transaction().Id()); + } + } + else + { + __FLOG_1(_T8("Trans %d : request header is set"), iProtTrans->Transaction().Id()); + iRequestHeaderSent = ETrue; + } + // Notify the observer that there is message data ready to send. + iMessageComposer.GetMessageData(iData); + + iObserver.SendRequestDataL(iData); + } + +TInt CHttpRequestComposer::HandleComposeError(TInt aError) + { + __FLOG_1(_T8("!! Error : %d"), aError); + __FLOG_1(_T8("-> Trans %d : request composing error - cancelling transaction"), iProtTrans->Transaction().Id()); + + return static_cast(iProtTrans->RxData()).CancelTransaction(aError); + } + +TBool CHttpRequestComposer::CheckRequestPendingComplete() + { + return iMessageComposer.CheckMessagePendingComplete(); + } +TBool CHttpRequestComposer::RequestSent () const + { + return iRequestSent; + } + +TBool CHttpRequestComposer::NeedDisconnectNotification () + { + CHttpClientTransaction* clientTrans = static_cast < CHttpClientTransaction* > ( iProtTrans ); + return clientTrans->NeedDisconnectNotification (); + } + +void CHttpRequestComposer::Reserved_MHttpMessageComposerObserver() + { + User::Invariant(); + } + +void CHttpRequestComposer::ResumeSuspendedRequest() + { + iSuspendRequest = EFalse; + iMessageComposer.ReleaseMessageData(); + } + +TBool CHttpRequestComposer::IsSuspendedRequest() const + { + return iSuspendRequest; + } + +void CHttpRequestComposer::CancelWaitFor100Continue() + { + __FLOG_1(_T8("Trans %d : client declined to wait for the 100-Continue Response"), iProtTrans->Transaction().Id()); + if(IsSuspendedRequest()) + { + ResumeSuspendedRequest(); + } + } + +MHttpDataOptimiser* CHttpRequestComposer::HttpDataOptimiser(TBool& aBatchingEnabled) + { + RHTTPTransaction trans = iProtTrans->Transaction(); + MHttpDataOptimiser* httpOptimiser = trans.HttpDataOptimiser(); + RHTTPSession sess = trans.Session(); + + RStringPool stringPool = sess.StringPool(); + THTTPHdrVal value; + RStringF string = stringPool.StringF(HTTP::EHttpBatching, iStringTable); + RStringF str = stringPool.StringF(HTTP::EEnableBatching, iStringTable); + if(sess.ConnectionInfo().Property(string, value)) + { + if(value.Type() == THTTPHdrVal::KStrFVal) + { + aBatchingEnabled = value.StrF() == str; + } + } + + if( httpOptimiser && !aBatchingEnabled ) + { + // the optimiser has not been set for the session. + __FLOG_1(_T8("-> Trans %d : Http optimiser has been set for this transaction"), iProtTrans->Transaction().Id()); + return (httpOptimiser); + } + + // the MHttpDataOptimiser hasn't been set for the transaction + // check whether the session encapsulating the transaction is having MHttpDataOptimiser. + httpOptimiser = sess.HttpDataOptimiser(); + if( httpOptimiser ) + { + // the optimiser has been set for the session. + __FLOG_1(_T8("-> Trans %d : HTTP optimiser has been set for the session encapsulating this transaction"), iProtTrans->Transaction().Id()); + // check if the client has disabled optimiser for a particular transaction. + TBool disableTransOptimiser = EFalse; + string = stringPool.StringF(HTTP::EHTTPTransOptimiser, iStringTable); + str = stringPool.StringF(HTTP::EDisableHTTPTransOptimiser, iStringTable); + if(iProtTrans->Transaction().PropertySet().Property(string, value)) + { + if(value.Type() == THTTPHdrVal::KStrFVal) + { + disableTransOptimiser = ( value.StrF() == str ); + } + } + + if ( disableTransOptimiser ) + { + // the client has disabled the optimiser for a particular transaction. + __FLOG_1(_T8("-> Trans %d : HTTP optimiser has been disabled by the client"), iProtTrans->Transaction().Id()); + // do not return the optimiser. + return NULL; + } + + // the client has not diasabled the optimiser for any transaction in particular. + // return the optimiser. + return (httpOptimiser); + } + + // MHttpDataOptimiser has not been set for the session and transaction + __FLOG_1(_T8("-> Trans %d : HTTP optimiser was never set for the transaction and the session enclosing it"), iProtTrans->Transaction().Id()); + return NULL; + } +