Week 32 contribution of PDK documentation content. See release notes for details. Fixes bug Bug 3582
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License
"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:
-->
<!DOCTYPE concept
PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept xml:lang="en" id="GUID-81253CA0-2B57-5A3E-9ACD-469D4B922047"><title>Handling request body data</title><prolog><metadata><keywords/></metadata></prolog><conbody><p>HTTP methods POST and PUT both require a request body to be specified by the client before a transaction is submitted. Also required in the request is a Content-Type header, to inform the HTTP server of the body data's media (MIME) type. </p> <p>If the body or Content-Type header are absent, an error will be returned as an event. See <xref href="GUID-AA2A730E-A7C9-5647-AD42-11C3BAF4C38D.dita#GUID-AA2A730E-A7C9-5647-AD42-11C3BAF4C38D/GUID-8DB0C8B3-4ED6-59D6-A796-F4EA2DE5DC5B">Validation filter</xref> for details of errors that can be sent. </p> <section id="GUID-3FD76282-A3E5-4613-A852-CDF7A0E9879A"><title>Specifying a request data supplier</title> <p>The following code fragment from <filepath>HTTPEXAMPLECLIENT</filepath> demonstrates a request body being set: </p> <codeblock id="GUID-51D78C10-21D9-5DEC-A84D-AADCD7A675CA" xml:space="preserve">void CHttpClient::InvokeHttpMethodL(const TDesC8& aUri, RStringF aMethod)
{
...
iTrans = iSess.OpenTransactionL(uri, *iTransObs, aMethod);
RHTTPHeaders hdr = iTrans.Request().GetHeaderCollection();
...
// Add headers and body data for methods that use request bodies
if (iHasARequestBody)
{
// Content type header
TBuf8<KMaxContentTypeSize> contTypeBuf;
contTypeBuf.Copy(iReqBodyContentType);
RStringF contTypeStr = iSess.StringPool().OpenFStringL(contTypeBuf);
CleanupClosePushL(contTypeStr);
THTTPHdrVal contType(contTypeStr);
hdr.SetFieldL(iSess.StringPool().StringF(HTTP::EContentType,RHTTPSession::GetTable()), contType);
MHTTPDataSupplier* dataSupplier = this;
if (iManualPost)
dataSupplier = iFormEncoder;
iTrans.Request().SetBody(*dataSupplier);
CleanupStack::PopAndDestroy(&contTypeStr);
}
// submit the transaction
iTrans.SubmitL();</codeblock> <p>The example uses two alternative alterative implementations of <xref href="GUID-1B03F068-9552-37BA-A284-8E54FAC2AAC5.dita"><apiname>MHTTPDataSupplier</apiname></xref>: the first method, not described here, is the <xref href="GUID-604D8C43-93F7-3835-8810-BD1CC891D086.dita"><apiname>CHTTPFormEncoder</apiname></xref> class, a utility that encodes a series of field name-value pairs into the URI-encoded form, as used by Web/WAP browsers to send data the user has entered into text boxes. </p> <p>The second method sets the request body data supplier to be the <codeph>CHttpClient</codeph> object itself. From the header file <filepath>httpexampleclient.h</filepath>: </p> <codeblock id="GUID-1FB82DEB-6400-55C9-9E71-D54C3F4F41F6" xml:space="preserve">class CHttpClient : public CBase, public MHTTPDataSupplier, ...
{
...
public: // methods inherited from MHTTPDataSupplier
virtual TBool GetNextDataPart(TPtrC8& aDataPart);
virtual void ReleaseData();
virtual TInt OverallDataSize();
...
};</codeblock> <p>The client must implement the three pure-virtual methods of <codeph>MHTTPDataSupplier</codeph> to allow HTTP to obtain the body data it needs as it assembles an HTTP request. </p> <ul><li id="GUID-C1213E1D-56EA-5E08-984B-E418BDC025D8"><p> <codeph>GetNextDataPart()</codeph>: when this method is invoked, the client must set the <codeph>aDataChunk</codeph> parameter to point at an 8-bit data buffer that is populated with the next piece of body data to be transmitted. If this buffer holds the last part of the request body, the method must return <codeph>ETrue</codeph>. </p> </li> <li id="GUID-536C0C3B-4E24-5F14-A4B7-6E10A38D78BC"><p> <codeph>ReleaseData()</codeph>: when this method is invoked, the client can free the data buffer it last returned from <codeph>GetDataChunk()</codeph>, and can start to assemble the next buffer for transmission. </p> </li> <li id="GUID-D88FC36E-99A2-5740-837A-9A46DB19E90B"><p> <codeph>OverallDataSize()</codeph>: when this method is invoked, the client should return the size of the whole request body data, if it is known. If unknown, it should return <codeph>KErrNotFound</codeph>. </p> </li> </ul> <p>There is no need for the client to set a 'Content-Length' header. The API does this automatically, based on what it gets from calling <codeph>OverallDataSize()</codeph>. </p> </section> <section id="GUID-195A967A-410F-480F-8E4E-37109F5E6A31"><title>Signalling new body data</title> <p>After <codeph>ReleaseData()</codeph> has been invoked, the client must prepare the next buffer of data for transmission. Since the API cannot predict when each buffer will be ready, it will pause the request transmission until an event is sent by the client to notify the availability of new data. This is done using the <xref href="GUID-2E673024-239B-3965-8880-C47B7CC24EF6.dita#GUID-2E673024-239B-3965-8880-C47B7CC24EF6/GUID-908A430D-9CCC-350D-B6EB-06E6EB94B0DD"><apiname>RHTTPTransaction::NotifyNewRequestBodyPartL()</apiname></xref> method. </p> <codeblock id="GUID-E97E6DBB-C8E9-5EE5-8703-680FCE2CEE0F" xml:space="preserve">void CHttpClient::ReleaseData()
{
// Clear out the submit buffer
TPtr8 buff = iReqBodySubmitBuffer->Des();
buff.Zero();
// Notify HTTP of more data available immediately, since it's being read from file
TRAPD(err, iTrans.NotifyNewRequestBodyPartL());
if (err != KErrNone)
User::Panic(KHttpExampleClientPanic, KCouldntNotifyBodyDataPart);
}</codeblock> <p>When <codeph>THTTPEvent::ENotifyNewRequestBodyPart</codeph> is processed by the API, it resumes transmission of body data and calls the client's <codeph>GetNextDataPart()</codeph> method again. </p> </section> <section id="GUID-29C4B920-D6E4-467D-9AA0-2F59B266F86F"><title>Streaming body data</title> <p>If a client application is using HTTP POST to stream data to a server, then it is unlikely to know at the start of the transaction how much data is to be sent. </p> <p>As described previously, the client's <codeph>OverallDataSize()</codeph> method should return <codeph>KErrNotFound</codeph> to indicate this. The result is that the API will automatically switch over to use the 'chunked' transfer encoding. The API automatically generates the 'Transfer-Encoding: chunked' header and will not send a Content-Length header. </p> </section> </conbody></concept>