Archived:Modifying web content using an HTTP filter on Symbian
Article Metadata
Code Example
Tested with
Compatibility
S60 3rd Edition FP1
S60 3rd Edition FP2
S60 5th Edition
Article
Last updated: October 20, 2010)
Contents |
Description
HTTP filters are add-on modules that provide additional features to an HTTP session beyond the simple request-response transaction. A filter can be written so that it can perform certain encoding on the content received from the server and then pass this modified content to the client.
Note that there are high capability requirements for HTTP filters, including ProtServ, NetworkControl, and SwEvent. See the related example application File:SampleFilter.zip for more information.
Solution
The filter must be inherited from MHTTPDataSupplier so that it can replace the content.
class CSampleFilter : public CEComFilter, public MHTTPFilter, public MHTTPDataSupplier
{
public:
static CEComFilter* CreateFilterL(TAny* aHttpSession);
// virtuals from the HTTP filter M classes
void MHFUnload(RHTTPSession aSession, THTTPFilterHandle aHandle);
void MHFLoad(RHTTPSession aSession, THTTPFilterHandle aHandle);
void MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent);
void MHFSessionRunL(const THTTPSessionEvent& aEvent);
TInt MHFRunError(TInt aError, RHTTPTransaction aTransaction, const THTTPEvent& aEvent);
TInt MHFSessionRunError(TInt aError, const THTTPSessionEvent& aEvent);
//methods inherited from MHTTPDataSupplier
TBool GetNextDataPart(TPtrC8& aDataPart);
TInt OverallDataSize();
void ReleaseData();
TInt Reset();
~CSampleFilter();
private:
void ConstructL(RHTTPSession& aHttpSession);
private:
RStringF iFilterName;
TBool isLast;
HBufC8* iPostData;
TInt iOverallDataSize;
MHTTPDataSupplier* iBody;
};
The content is modified in the MHFRunL function of the filter.
void CSampleFilter ::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
{
// called when a RHTTPTransaction event happens.
switch ( aEvent.iStatus )
{
case THTTPEvent::EGotResponseHeaders:
{
}
break;
case THTTPEvent::EGotResponseBodyData:
{
iBody = aTransaction.Response().Body();
TPtrC8 dataChunk;
isLast = iBody->GetNextDataPart(dataChunk);
iOverallDataSize = iBody->OverallDataSize();
TRAPD(err,iPostData = dataChunk.AllocL());
// The last datachunk of every transaction
// is replaced with the iPostData of the filter.
if(!err && isLast)
{
TPtr8 tempDataPtr = iPostData->Des(); //This pointer can be used
//to modify the received content.
aTransaction.Response().RemoveBody();
MHTTPDataSupplier* dataSupplier = this;
//Replacing the Transaction body
aTransaction.Response().SetBody(*dataSupplier);
}
}
break;
default:
// There are more events in THTTPEvent, but they are usually not
// needed. However, event status smaller than zero should be handled
// correctly since it is an error.
{
}
break;
}
}
The inherited functions of MHTTPDataSupplier are to be overridden as shown below.
//OverallDataSize() function of MHTTPDataSupplier
TInt CSampleFilter::OverallDataSize()
{
return iOverallDataSize;
}
//ReleaseData() function of MHTTPDataSupplier
void CSampleFilter::ReleaseData()
{
iBody->ReleaseData();
if(iPostData)
{
delete iPostData;
iPostData = 0;
}
}
//Reset() function of MHTTPDataSupplier
TInt CSampleFilter::Reset()
{
return KErrNone;
}
//GetNextDataPart() function of MHTTPDataSupplier
TBool CSampleFilter::GetNextDataPart(TPtrC8& aDataPart)
{
if(iPostData)
{
aDataPart.Set(iPostData->Des();
}
return isLast;
}
Inspecting request headers
Additionally, it is possible to iterate through all headers in an HTTP request using the following piece of code:
_LIT( KDateFormat,"%D%M%Y%/0%1%/1%2%/2%3%/3 %:0%H%:1%T%:2%S.%C%:3" );
void CSampleFilter::DumpHeadersL( RHTTPTransaction& aTransaction )
{
RHTTPRequest resp = aTransaction.Request();
RStringPool strP = aTransaction.Session().StringPool();
RHTTPHeaders hdr = resp.GetHeaderCollection();
THTTPHdrFieldIter it = hdr.Fields();
while( it.AtEnd() == EFalse )
{
RStringTokenF fieldName = it();
RStringF fieldNameStr = strP.StringF( fieldName );
// fieldNameStr now contains the header field name
THTTPHdrVal fieldVal;
TInt fieldPart = 0;
while( hdr.GetField( fieldNameStr, fieldPart++, fieldVal ) == KErrNone )
{
TBuf8<512> buf;
switch( fieldVal.Type() )
{
case THTTPHdrVal::KTIntVal: // integer
{
buf.Num( fieldVal.Int() );
break;
}
case THTTPHdrVal::KStrFVal: // case-insensitive string
{
RStringF fieldValStr = strP.StringF( fieldVal.StrF() );
const TDesC8& fieldValDesC = fieldValStr.DesC();
buf.Copy( fieldValDesC );
}
break;
case THTTPHdrVal::KStrVal: // case-sensitive string
{
RString fieldValStr = strP.String( fieldVal.Str() );
const TDesC8& fieldValDesC = fieldValStr.DesC();
buf.Copy( fieldValDesC );
}
break;
case THTTPHdrVal::KDateVal: // date
{
TDateTime date = fieldVal.DateTime();
TBuf<64> dateTimeString;
TTime tim( date );
tim.FormatL( dateTimeString, KDateFormat );
buf.Copy( dateTimeString );
}
break;
default:
break;
}
// buf now contains (all or part of) the field value(s)
}
++it;
}
}
Example application
This example filter application shows how to modify the HTML content received from an HTTP server and pass the modified content to the client.


(no comments yet)