|
||
HTTP request and response headers are handled by the classes
RHTTPHeaders
and THTTPHdrVal
. Calling
GetHeaderCollection()
on RHTTPRequest
and
RHTTPResponse
objects returns the
RHTTPHeaders
for the HTTP request and HTTP response respectively.
RHTTPHeaders
represents the entire message header, that is,
the entire set of header fields in a request or a response.
THTTPHdrVal
represents a value that a single header field can
take.
HTTP will set some header fields automatically. The client is not required to add the following to requests:
Content-Length: This is derived from the client's
request MHTTPDataSupplier
.
Connection: This is handled automatically to manage a HTTP/1.1 persistent connection. If a client wants to indicate that the persistent connection is to close, it must add a Connection header.
Host: This is taken from the client's request URL. If a relative URL is supplied, the client must add a Host header.
Transfer-Encoding: This is added automatically if the
client's request MHTTPDataSupplier
specifies an unknown overall
data size.
Authorisation: This is added automatically by the Authentication filter.
Also, HTTP's filters and protocol handler deals automatically with some headers contained in the server response. These are:
Content-Length: This value is provided through the
response body MHTTPDataSupplier
.
Connection: This is handled automatically to manage the HTTP/1.1 persistent connection.
Location: This is handled automatically by the Redirection filter.
Transfer-Encoding: This is handled automatically by the protocol handler, and 'chunked' encodings are removed before presenting the response body to the client.
WWW-Authenticate: This is added automatically by the Authentication filter.
HTTP represents headers as a composition of parts and parameters. A simple header will have only one part, for example:
Location: www.symbian.com
More complex headers consist of a number of parts, separated by semicolon (;) or comma (,) characters. In RFC 2616, these are defined with the EBNF notation 'rule - A construct "#" is defined, similar to "*", for defining lists of elements...'
An example of a multiple-part header is:
Accept: text/*, text/html, */*
The three parts have values text/*, text/html and */* respectively. When setting up a header like this, the client only needs to specify the parts, and need not be concerned with separator characters. Separators are handled automatically by the built-in header codec.
Some header fields allow one or more parameters to be associated with individual header parts. An example of a header with parameters is:
Content-Type: text/html; charset=ISO-8859-4
The Content-Type header has a single part (value 'text/html') that has a single parameter (named 'charset', value 'ISO-8859-4'). Again, the client need only be concerned with setting part and parameter values; the separators including the '=' character are dealt with automatically.
Header field parts are added by repeated invocation of the
RHTTPHeaders::SetFieldL()
method. On the first invocation,
when no field of that name exists in the header, a new field is created with a
single part. On subsequent invocations, additional parts are added to the
existing header field.
This behaviour is consistent with HTTP/1.1 in which:
Accept: text/*, text/html
is preferable to
Accept: text/* text/html
Although the two are semantically equivalent, the API will not output the second variant under any circumstance.
When parts are added to a header field, they are given an index number.
The first part to be added has index 0, the second is index 1, and so on. This
index is necessary when identifying parts for retrieval (using
RHTTPHeaders::GetField()
).
To remove a single header field part,
RHTTPHeaders::RemoveFieldPart()
is used, specifying a part
index. To remove a header field entirely,
RHTTPHeaders::RemoveField()
is used.
Part values are accessed using
RHTTPHeaders::GetField()
. The client must supply a part
index and an uninitialized THTTPHdrVal
, which will be
filled by the method. This example, from HTTPEXAMPLECLIENT
,
retrieves all response headers and prints their values:
void CHttpEventHandler::DumpRespHeadersL(RHTTPTransaction& aTrans)
{
RHTTPResponse resp = aTrans.Response();
RStringPool strP = aTrans.Session().StringPool();
RHTTPHeaders hdr = resp.GetHeaderCollection();
THTTPHdrFieldIter it = hdr.Fields();
TBuf<KMaxHeaderNameLen> fieldName16;
TBuf<KMaxHeaderValueLen> fieldVal16;
while (it.AtEnd() == EFalse)
{
RStringTokenF fieldName = it();
RStringF fieldNameStr = strP.StringF(fieldName);
THTTPHdrVal fieldVal;
if (hdr.GetField(fieldNameStr,0,fieldVal) == KErrNone)
{
const TDesC8& fieldNameDesC = fieldNameStr.DesC();
fieldName16.Copy(fieldNameDesC.Left(KMaxHeaderNameLen));
switch (fieldVal.Type())
{
case THTTPHdrVal::KTIntVal:
iUtils.Test().Printf(_L("%S: %d\n"), &fieldName16, fieldVal.Int());
break;
case THTTPHdrVal::KStrFVal:
{
RStringF fieldValStr = strP.StringF(fieldVal.StrF());
const TDesC8& fieldValDesC = fieldValStr.DesC();
fieldVal16.Copy(fieldValDesC.Left(KMaxHeaderValueLen));
iUtils.Test().Printf(_L("%S: %S\n"), &fieldName16, &fieldVal16);
fieldValStr.Close();
}
break;
case THTTPHdrVal::KStrVal:
{
RString fieldValStr = strP.String(fieldVal.Str());
const TDesC8& fieldValDesC = fieldValStr.DesC();
fieldVal16.Copy(fieldValDesC.Left(KMaxHeaderValueLen));
iUtils.Test().Printf(_L("%S: %S\n"), &fieldName16, &fieldVal16);
fieldValStr.Close();
}
break;
case THTTPHdrVal::KDateVal:
{
TDateTime date = fieldVal.DateTime();
TBuf<40> dateTimeString;
TTime t(date);
t.FormatL(dateTimeString,KDateFormat);
iUtils.Test().Printf(_L("%S: %S\n"), &fieldName16, &dateTimeString);
}
break;
default:
iUtils.Test().Printf(_L("%S: <unrecognised value type>\n"), &fieldName16);
break;
}
...
}
// Advance the iterator to get the next field
++it;
}
}
Note that in this example, only the first part of each header field is displayed.
Parameters can be associated with header field parts at the time of
adding the part. There are two variants of
RHTTPHeaders::SetFieldL()
: the first is described
previously. The second variant takes four parameters, of which two specify the
part name/value and two specify the parameter name/value.
To associate more than one parameter with the part, the function must be invoked repeatedly. This does not create duplicate parts; rather it locates the part with the specified value, and then adds additional parameters.
To remove parameters from header parts, the entire part must be removed
using RHTTPHeaders::RemoveFieldPart()
, and then added
again.
To access parameter values, the header name and parameter name must be
specified. RHTTPHeaders::GetParam()
is used, and has an
optional fourth parameter in which the part index can be provided. If not, the
API assumes that the first header part contains the parameter.
The following code from HTTPEXAMPLECLIENT
illustrates the
use of header parameters with the WWW-Authenticate
header:
// Display realm for WWW-Authenticate header
RStringF wwwAuth = strP.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable());
if (fieldNameStr == wwwAuth)
{
// check the auth scheme is 'basic'
RStringF basic = strP.StringF(HTTP::EBasic,RHTTPSession::GetTable());
RStringF realm = strP.StringF(HTTP::ERealm,RHTTPSession::GetTable());
THTTPHdrVal realmVal;
if ((fieldVal.StrF() == basic) &&
(!hdr.GetParam(wwwAuth, realm, realmVal)))
{
RStringF realmValStr = strP.StringF(realmVal.StrF());
fieldVal16.Copy(realmValStr.DesC());
iUtils.Test().Printf(_L("Realm is: %S\n"), &fieldVal16);
realmValStr.Close();
}
basic.Close();
realm.Close();
}
wwwAuth.Close();
This section describes the headers that have specific support for encoding or decoding using parts and parameters. Other headers not listed are encoded and decoded using a default mechanism that assumes the header field has a single part with a string value.
This is a client request header.
RHTTPHeaders hdr = aReq.GetHeaderCollection();
// Setting a single media range with no parameter, i.e. Accept: text/html
RStringF textHtml = iStrTb.OpenFStringL(_L8("text/html"));
CleanupClosePushL(textHtml);
THTTPHdrVal accVal(textHtml);
hdr.SetFieldL(iStrTb.String(HTTP::EAccept,RHTTPSession::GetTable()), accVal);
CleanupStack::PopAndDestroy(&textHtml);
// Setting several media ranges with no parameters, i.e. Accept: text/html; text/vnd.wap.wml
RStringF textHtml = iStrTb.OpenFStringL(_L8("text/html"));
CleanupClosePushL(textHtml);
RStringF textWml = iStrTb.OpenFStringL(_L8("text/vnd.wap.wml"));
CleanupClosePushL(textWml);
THTTPHdrVal accVal(textHtml);
hdr.SetFieldL(iStrTb.String(HTTP::EAccept,RHTTPSession::GetTable()), accVal);
accVal.SetStr(textWml);
hdr.SetFieldL(iStrTb.String(HTTP::EAccept,RHTTPSession::GetTable()), accVal);
CleanupStack::PopAndDestroy(&textHtml);
CleanupStack::PopAndDestroy(&textWml);
// Setting a media range with a 'q' parameter, Accept: text/html; q=0.8
RStringF textHtml = iStrTb.OpenFStringL(_L8("text/html"));
CleanupClosePushL(textHtml);
THTTPHdrVal accVal(textHtml);
THTTPHdrVal q(THTTPHdrVal::TQConv(0.8));
hdr.SetFieldL(iStrTb.String(HTTP::EAccept,RHTTPSession::GetTable()), accVal, iStrTb.String(HTTP::EQ,RHTTPSession::GetTable()), q);
CleanupStack::PopAndDestroy(&textHtml);
// Using an accept extension, Accept: text/html; extended=value
RStringF textHtml = iStrTb.OpenFStringL(_L8("text/html"));
CleanupClosePushL(textHtml);
RStringF extended = iStrTb.OpenFStringL(_L8("extended"));
CleanupClosePushL(extended);
RStringF extendVal = iStrTb.OpenFStringL(_L8("value"));
CleanupClosePushL(extendVal);
THTTPHdrVal accVal(textHtml);
THTTPHdrVal extVal(extendVal);
hdr.SetFieldL(iStrTb.String(HTTP::EAccept,RHTTPSession::GetTable()), accVal, extended, extVal);
CleanupStack::PopAndDestroy(3); // textHtml, extended, extendVal
This is a client request header.
RHTTPHeaders hdr = aReq.GetHeaderCollection();
// Setting up two accepted character sets, i.e. Accept-Charset: us-ascii, utf-8
RStringF usAscii = iStrTb.OpenFStringL(_L8("us-ascii"));
CleanupClosePushL(usAscii);
RStringF utf8 = iStrTb.OpenFStringL(_L8("utf-8"));
CleanupClosePushL(utf8);
THTTPHdrVal accChSetVal(usAscii);
hdr.SetFieldL(iStrTb.String(HTTP::EAcceptCharset,RHTTPSession::GetTable()), accChSetVal);
// sets the first part accChSetVal.(SetStrutf8);
hdr.SetFieldL(iStrTb.String(HTTP::EAcceptCharset,RHTTPSession::GetTable()), accChSetVal);
// adds an additional part usAscii.Close();
CleanupStack::PopAndDestroy(2);
This is a client request header. Note: The client need not set this header for most normal requests.
RHTTPHeaders hdr = aReq.GetHeaderCollection();
// Setting an authorization credential, i.e. Authorization: Basic c3ltYmlhbjpmMXN5bmNtbA==
RStringF basicCred = iStrTb.OpenFStringL(_L8("c3ltYmlhbjpmMXN5bmNtbA=="));
CleanupClosePushL(basicCred);
THTTPHdrVal authVal(iStrTb.String(HTTP::EBasic,RHTTPSession::GetTable()));
hdr.SetFieldL(iStrTb.String(HTTP::EAuthorization,RHTTPSession::GetTable()), authVal);
authVal.(SetStrbasicCred);
hdr.SetFieldL(iStrTb.String(HTTP::EAuthorization,RHTTPSession::GetTable()), authVal);
CleanupStack::PopAndDestroy(&basicCred);
This is a general header, that is, it applies to the connection between client and server. Note: The client need not set this header for normal, persistent HTTP/1.1 requests.
RHTTPHeaders hdr = aReq.GetHeaderCollection();
// Indicate that the connection is to close, i.e. Connection: close
THTTPHdrVal closeVal(iStrTb.String(HTTP::EClose,RHTTPSession::GetTable()));
hdr.SetFieldL(iStrTb.String(HTTP::EConnection,RHTTPSession::GetTable()), closeVal);
This is an entity header, that is, it applies to the body present in a request or a response. Note: The client should not set this header for any request: it will be ignored.
RHTTPHeaders hdr = aReq.GetHeaderCollection();
// Set a content length of 12345, i.e. Content-Length: 12345
THTTPHdrVal lengthVal(12345);
hdr.SetFieldL(iStrTb.String(HTTP::EContentLength,RHTTPSession::GetTable()), lengthVal);
This is an entity header, that is, it applies to the body present in a request or a response.
RHTTPHeaders hdr = aReq.GetHeaderCollection();
// Set a content type of text/html, i.e. Content-Type: text/html
THTTPHdrVal contTypeVal(iStrTb.String(HTTP::ETextHtml,RHTTPSession::GetTable()));
hdr.SetFieldL(iStrTb.String(HTTP::EContentType,RHTTPSession::GetTable()), contTypeVal);
This is a general header, that is, it applies to the connection between client and server. All three date formats specified in RFC2616 are supported in responses. Requests will be made using the RFC1123 format only.
RHTTPHeaders hdr = aReq.GetHeaderCollection();
// Set a date of 9th August 2001, time 13:45:00.000, i.e. Date: Thu, 09 Aug 2001 13:45:00 GMT
THTTPHdrVal dateVal(TDateTime(2001, EAugust, 8, 13, 45, 0, 0));
// note, the day starts at 0
hdr.SetFieldL(iStrTb.String(HTTP::EDate,RHTTPSession::GetTable()), dateVal);
This is a client request header. Note: The client should not set this header for any request unless the URL is relative.
RHTTPHeaders hdr = aReq.GetHeaderCollection();
// Set a host 'www.symbian.com', i.e. Host: www.symbian.com
_LIT8(host, "www.symbian.com");
RStringF hostValStr = iStrTb.OpenFStringL(host);
CleanupClosePushL(hostValStr);
THTTPHdrVal hostVal(hostValStr);
hdr.SetFieldL(hostStr, hostVal);
CleanupStack::PopAndDestroy(&hostValStr);
This is a general header, that is, it applies to the connection between client and server. Note: The client should not set this header for any request, as it will be ignored.
RHTTPHeaders hdr = aReq.GetHeaderCollection();
// Set the transfer encoding to be 'chunked', i.e. Transfer-Encoding: chunked
THTTPHdrVal xferEncVal;
xferEncVal.SetStrF(iStrTb.StringF(HTTP::EChunked,RHTTPSession::GetTable()));
hdr.SetFieldL(iStrTb.StringF(HTTP::ETransferEncoding,RHTTPSession::GetTable()), xferEncVal);
This is a client request header.
RHTTPHeaders hdr = aReq.GetHeaderCollection();
// Set up a user agent with two part, i.e. User-Agent: CERN-LineMode/2.15 libwww/2.17b3
RStringF ua1Str = iStrP.OpenFStringL(_L8("CERN-LineMode/2.15"));
CleanupClosePushL(ua1Str);
RStringF ua2Str = iStrP.OpenFStringL(_L8("libwww/2.17b3"));
CleanupClosePushL(ua2Str);
RStringF uaStr = iStrP.StringF(HTTP::EUserAgent,RHTTPSession::GetTable());
THTTPHdrVal uaVal(ua1Str);
hdr.SetFieldL(uaStr, uaVal);
// sets part 1 uaVal.SetStrF(ua2Str);
hdr.SetFieldL(uaStr, uaVal);
// sets part 2
CleanupStack::PopAndDestroy(2);
This is a server response header. Note: The client need not read this header for most normal responses.
RHTTPHeaders hdr = aReq.GetHeaderCollection();
...
// Display realm for WWW-Authenticate header
RStringF wwwAuth = strP.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable());
if (fieldNameStr == wwwAuth)
{
// check the auth scheme is 'basic'
RStringF basic = strP.StringF(HTTP::EBasic,RHTTPSession::GetTable());
RStringF realm = strP.StringF(HTTP::ERealm,RHTTPSession::GetTable());
THTTPHdrVal realmVal;
if ((fieldVal.StrF() == basic) &&
(!hdr.GetParam(wwwAuth, realm, realmVal)))
{
RStringF realmValStr = strP.StringF(realmVal.StrF());
fieldVal16.Copy(realmValStr.DesC());
iUtils.Test().Printf(_L("Realm is: %S\n"), &fieldVal16);
realmValStr.Close();
}
basic.Close();
realm.Close();
}
wwwAuth.Close();
hdr.Close();