|
||
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.
If the body or Content-Type header are absent, an error will be returned as an event. See Validation filter for details of errors that can be sent.
The following code fragment from HTTPEXAMPLECLIENT
demonstrates a request body being set:
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();
The example uses two alternative alterative implementations of
MHTTPDataSupplier
: the first method, not described here,
is the CHTTPFormEncoder
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.
The second method sets the request body data supplier to be the
CHttpClient
object itself. From the header file
httpexampleclient.h
:
class CHttpClient : public CBase, public MHTTPDataSupplier, ...
{
...
public: // methods inherited from MHTTPDataSupplier
virtual TBool GetNextDataPart(TPtrC8& aDataPart);
virtual void ReleaseData();
virtual TInt OverallDataSize();
...
};
The client must implement the three pure-virtual methods of
MHTTPDataSupplier
to allow HTTP to obtain the body data it needs
as it assembles an HTTP request.
GetNextDataPart()
: when this method is invoked, the
client must set the aDataChunk
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
ETrue
.
ReleaseData()
: when this method is invoked, the client
can free the data buffer it last returned from GetDataChunk()
, and
can start to assemble the next buffer for transmission.
OverallDataSize()
: 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 KErrNotFound
.
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
OverallDataSize()
.
After ReleaseData()
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
RHTTPTransaction::NotifyNewRequestBodyPartL()
method.
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);
}
When THTTPEvent::ENotifyNewRequestBodyPart
is processed by
the API, it resumes transmission of body data and calls the client's
GetNextDataPart()
method again.
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.
As described previously, the client's OverallDataSize()
method should return KErrNotFound
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.