Symbian3/SDK/Source/GUID-1D32D093-1B7B-5CE8-B57D-5469C1E8E4B9.dita
changeset 7 51a74ef9ed63
parent 0 89d6a7a84779
equal deleted inserted replaced
6:43e37759235e 7:51a74ef9ed63
       
     1 <?xml version="1.0" encoding="utf-8"?>
       
     2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
       
     3 <!-- This component and the accompanying materials are made available under the terms of the License 
       
     4 "Eclipse Public License v1.0" which accompanies this distribution, 
       
     5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
       
     6 <!-- Initial Contributors:
       
     7     Nokia Corporation - initial contribution.
       
     8 Contributors: 
       
     9 -->
       
    10 <!DOCTYPE concept
       
    11   PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
       
    12 <concept xml:lang="en" id="GUID-1D32D093-1B7B-5CE8-B57D-5469C1E8E4B9"><title>A simple HTTP client session</title><prolog><metadata><keywords/></metadata></prolog><conbody><p>This page describes each of the stages needed to use HTTP for a single, simple transaction. The code fragments are taken from <filepath>HTTPEXAMPLECLIENT</filepath>. </p> <section id="GUID-01BCEE83-E671-4A92-B8FA-DC81A27C3CAA"><title>Opening a session</title> <p>A new HTTP Client session is started by declaring an <xref href="GUID-651801A5-5473-3856-9647-46823598C5C1.dita"><apiname>RHTTPSession</apiname></xref> object, which must remain in scope for the duration of the session, and invoking the <xref href="GUID-651801A5-5473-3856-9647-46823598C5C1.dita#GUID-651801A5-5473-3856-9647-46823598C5C1/GUID-77EA1EAA-F1E5-397D-BA5C-7BD3A5404B10"><apiname>RHTTPSession::OpenL()</apiname></xref> method. Usually, the <codeph>RHTTPSession</codeph> handle is a data member of a client class: </p> <p>From the example header file <filepath>httpexampleclient.h</filepath>: </p> <codeblock id="GUID-062810B9-419F-5EF3-B11F-67E88A8812EB" xml:space="preserve">class CHttpClient : public CBase, ...
       
    13     {
       
    14     ...
       
    15 private:
       
    16     RHTTPSession iSess;
       
    17     ...
       
    18     };</codeblock> <p>From the example implementation file <filepath>httpexampleclient.cpp</filepath>: </p> <codeblock id="GUID-C94B7759-D61F-5079-94D3-544F1195B65E" xml:space="preserve">void CHttpClient::ConstructL()
       
    19     {
       
    20     ...
       
    21     iSession.OpenL();
       
    22     ...
       
    23     }</codeblock> </section> <section id="GUID-63503283-9642-428C-B57E-8E3436D8BC87"><title>Creating a transaction</title> <p>To create a new transaction within the session, the client must specify a URI, an HTTP method, and a callback object that is used to receive events that arise during the transaction. The callback object must implement the <xref href="GUID-F34F7481-00CF-3A1B-8D45-D053AD6769A8.dita"><apiname>MHTTPTransactionCallback</apiname></xref> interface. </p> <p>The <xref href="GUID-2E673024-239B-3965-8880-C47B7CC24EF6.dita"><apiname>RHTTPTransaction</apiname></xref> handle returned by the session uniquely identifies the new transaction. It may be stored in a class data member, but this is not mandatory. </p> <codeblock id="GUID-59E8A81E-EE08-5770-9F59-773EA7613B89" xml:space="preserve">void CHttpClient::InvokeHttpMethodL(const TDesC8&amp; aUri, RStringF aMethod)
       
    24     {
       
    25     ...
       
    26     TUriParser8 uri; 
       
    27     uri.Parse(aUri);  
       
    28     iTrans = iSess.OpenTransactionL(uri, *iTransObs, aMethod);
       
    29     ...
       
    30     };</codeblock> <p>The second parameter to <xref href="GUID-651801A5-5473-3856-9647-46823598C5C1.dita#GUID-651801A5-5473-3856-9647-46823598C5C1/GUID-02249363-7FB0-39A5-8F43-7FC35E05E318"><apiname>RHTTPSession::OpenTransactionL()</apiname></xref> provides the transaction callback. The class which implements the callback is separate in <filepath>HTTPEXAMPLECLIENT</filepath>. From the header file <filepath>httpexampleclient.h</filepath>: </p> <codeblock id="GUID-2F967212-258B-5F06-A62C-2BB50BF4F564" xml:space="preserve">class CHttpEventHandler : public CBase, public MHTTPTransactionCallback
       
    31     {
       
    32 public:
       
    33  ...
       
    34     //
       
    35     // methods from MHTTPTransactionCallback
       
    36     //
       
    37     virtual void MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent&amp; aEvent);
       
    38     virtual TInt MHFRunError(TInt aError, RHTTPTransaction aTransaction, const THTTPEvent&amp; aEvent);
       
    39  ...
       
    40  };</codeblock> <p>The two callback methods are inherited from <xref href="GUID-57216A14-97B8-324C-BB00-63CA880CC779.dita"><apiname>MHTTPFilterBase</apiname></xref>: hence the MHF prefix to their names. This is an interesting feature of the HTTP Client design where the client code is treated as a filter. The use of these methods is described subsequently. </p> </section> <section id="GUID-B5AECC45-F560-40E7-B8E6-6E48CED6C8FE"><title>Setting request headers</title> <p>After opening the transaction, the client may set request headers, if required. Note that the use of request headers is optional for very simple transactions, as the few headers that RFC 2616 describes as mandatory for HTTP/1.1 are automatically generated. </p> <p>To access the headers associated with a transaction's request or response, the <xref href="GUID-54F9A87B-FE2F-3429-9793-0A24B83466B9.dita"><apiname>RHTTPHeaders</apiname></xref> class is used. The handle is obtained from either the <xref href="GUID-8D952FEE-0EA0-3DBC-AADB-6F4200B82687.dita"><apiname>RHTTPRequest</apiname></xref> or <xref href="GUID-BA9EA976-E4CF-37D7-9E73-420A6D50203F.dita"><apiname>RHTTPResponse</apiname></xref> objects associated with the transaction. </p> <p>From the implementation file <filepath>httpexampleclient.cpp</filepath>: </p> <codeblock id="GUID-1C49573C-00B3-5563-B422-9E4A94F39BBD" xml:space="preserve">RHTTPHeaders hdr = iTrans.Request().GetHeaderCollection();
       
    41     // Add headers appropriate to all methods
       
    42     SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
       
    43     SetHeaderL(hdr, HTTP::EAccept, KAccept);
       
    44 ...
       
    45 
       
    46 void CHttpClient::SetHeaderL(RHTTPHeaders aHeaders, TInt aHdrField, const TDesC8&amp; aHdrValue)
       
    47     {
       
    48     RStringF valStr = iSess.StringPool().OpenFStringL(aHdrValue);
       
    49     CleanupClosePushL(valStr);
       
    50     THTTPHdrVal val(valStr); 
       
    51     aHeaders.SetFieldL(iSess.StringPool().StringF(aHdrField,RHTTPSession::GetTable()), val);
       
    52     CleanupStack::PopAndDestroy(&amp;valStr);
       
    53     }</codeblock> <p>Note that the header field types are specified using enumerations from the <xref href="GUID-7BB3CFA5-4697-305D-B4FD-D8747BB56E04.dita"><apiname>HTTP</apiname></xref> namespace, e.g. <xref href="GUID-7BB3CFA5-4697-305D-B4FD-D8747BB56E04.dita#GUID-7BB3CFA5-4697-305D-B4FD-D8747BB56E04/GUID-600E343A-5081-3D42-95A2-B1957BE9719A"><apiname>HTTP::EUserAgent</apiname></xref>. The class used to hold the header field value, <xref href="GUID-DEE8279A-3BEC-316F-97B8-6C49FEDBD5B3.dita"><apiname>THTTPHdrVal</apiname></xref>, is like a C++ union, that is, it can hold different data types. In this example, it holds an <xref href="GUID-B886F0AA-DB9C-356C-9B96-33252820F93E.dita"><apiname>RStringF</apiname></xref> value which is initialized using the session's string-pool from the supplied descriptor. These must be 8-bit strings, as the RFC 2616 assumes a 7-bit encoding for all transmissions. </p> </section> <section id="GUID-435FE7DC-9BEA-4D70-B8D1-7189E546242D"><title>Starting the transaction</title> <p>When headers have been set, a simple transaction with no request body can be started immediately. This is the case for HTTP methods such as GET, HEAD, and TRACE. Some other HTTP methods include a body in the request, for example, POST. The data supplier that the client uses to supply request body data must be associated with the transaction before the transaction is started. </p> <p>In <filepath>HTTPEXAMPLECLIENT</filepath>, the <codeph>CHttpClient</codeph> class also acts as its own data supplier when the POST method is chosen in the menu. See <xref href="GUID-81253CA0-2B57-5A3E-9ACD-469D4B922047.dita">Handling request body data</xref> for examples of code that provides a request body. </p> <p>When the transaction ready to start, the client calls <xref href="GUID-2E673024-239B-3965-8880-C47B7CC24EF6.dita#GUID-2E673024-239B-3965-8880-C47B7CC24EF6/GUID-F3A8B916-5618-319D-89D8-9B7B04A8A2FC"><apiname>RHTTPTransaction::SubmitL()</apiname></xref> to indicate that the request should be submitted. From the implementation file <filepath>httpexampleclient.cpp</filepath>: </p> <codeblock id="GUID-A0564DB5-E381-5E08-A7A1-BA7568B06235" xml:space="preserve">...
       
    54     // submit the transaction
       
    55     iTrans.SubmitL();
       
    56     // Start the scheduler, once the transaction completes or is cancelled on an error the scheduler will be
       
    57     // stopped in the event handler
       
    58     CActiveScheduler::Start();</codeblock> <p>The <filepath>HTTPEXAMPLECLIENT</filepath> application is implemented as a synchronous client, hence the local <codeph>CActiveScheduler</codeph>. When <xref href="GUID-B4C76104-EA1B-3FC3-A31E-86A976598171.dita#GUID-B4C76104-EA1B-3FC3-A31E-86A976598171/GUID-B59D1017-1D81-3D5E-B0A2-73FC9C06194B"><apiname>CActiveScheduler::Stop()</apiname></xref> is called after completion of the transaction, execution continues from this point. More complex applications will have an active scheduler elsewhere that should already be running. </p> </section> <section id="GUID-B5520BFB-59D1-4800-80AB-901538216313"><title>Receiving transaction events</title> <p>The transaction is now processed by HTTP. All processing by the internal HTTP core and protocol and transport handlers is done in the client's thread. As data is received from the HTTP server, events are generated internally and passed back to the client using the session filters. When an event reaches the client, HTTP invokes the transaction callback. </p> <p>From the implementation file <filepath>httpexampleclient.cpp</filepath>: </p> <codeblock id="GUID-D555D720-4AEB-5877-A8CC-315E84F5EA35" xml:space="preserve">void CHttpEventHandler::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent&amp; aEvent)
       
    59     {
       
    60     switch (aEvent.iStatus)
       
    61         {
       
    62         case THTTPEvent::EGotResponseHeaders:
       
    63             {
       
    64             ...
       
    65             } 
       
    66             break;
       
    67         case THTTPEvent::EGotResponseBodyData:
       
    68             {
       
    69             ...
       
    70             } 
       
    71             break;
       
    72         case THTTPEvent::EResponseComplete:
       
    73             {
       
    74             ...
       
    75             } 
       
    76             break;
       
    77         case THTTPEvent::ESucceeded:
       
    78             {
       
    79             ...
       
    80             } 
       
    81             break;
       
    82         case THTTPEvent::EFailed:
       
    83             {
       
    84             ...
       
    85             } 
       
    86             break;
       
    87   case THTTPEvent::ERedirectedPermanently:
       
    88             {
       
    89             ...
       
    90             } 
       
    91             break;
       
    92   case THTTPEvent::ERedirectedTemporarily:
       
    93             {
       
    94             ...
       
    95             } 
       
    96             break;
       
    97         default:
       
    98             {
       
    99             ...
       
   100             } 
       
   101             break;
       
   102         }
       
   103     }</codeblock> <p>Events are processed in turn by the client. They arrive in the order shown in the preceding example code. The following list describes the events: </p> <ul><li id="GUID-8C726FB1-8448-5C52-9235-FA3977270A8D"><p> <xref href="GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3.dita#GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3/GUID-C2FB5091-13B7-305A-A14A-CA4BF23F0CF0"><apiname>THTTPEvent::EGotResponseHeaders</apiname></xref> indicates that the response status is known, and that the headers from the response are ready for access by the client. This event will always be the first received, unless an error condition has arisen. </p> </li> <li id="GUID-4F5623D8-BE02-5EEF-8A9E-8B9BDC76C0B2"><p> <xref href="GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3.dita#GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3/GUID-FED66222-97A9-376C-B35D-488C24477FF9"><apiname>THTTPEvent::EGotResponseBodyData</apiname></xref> indicates that some body data is ready for processing. Response bodies are generally large enough to require splitting into smaller pieces (due to the use of fixed-size internal buffers), so the event will arrive as many times as there are pieces, until the whole body has been retrieved. </p> </li> <li id="GUID-D0480035-1AA9-5046-828E-ABAF488E7D67"><p> <xref href="GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3.dita#GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3/GUID-0056851B-2933-3701-BFE2-E28162F4EE5B"><apiname>THTTPEvent::EResponseComplete</apiname></xref> indicates that the transaction's response has been completely received. The client can now expect to be told whether the transaction was successful or not. </p> </li> <li id="GUID-3E48FCA6-3571-540A-BBC8-11796B7E4450"><p> <xref href="GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3.dita#GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3/GUID-619AC671-5679-3036-82C9-DAAF5B892100"><apiname>THTTPEvent::ESucceeded</apiname></xref> is one of two possible final messages: it indicates success of the transaction. </p> </li> <li id="GUID-D945439E-973D-58A6-BEA4-CDA568463336"><p> <xref href="GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3.dita#GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3/GUID-6BC33448-9CB9-3488-87DD-EFB0C5435044"><apiname>THTTPEvent::EFailed</apiname></xref> is the second of the two possible final messages: it indicates failure of the transaction. </p> </li> <li id="GUID-B3BC98DE-A314-51A2-8C0A-B1C61911D7B0"><p> <xref href="GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3.dita#GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3/GUID-0A71A2A1-E5CC-33F2-A11A-94A998AA32C5"><apiname>THTTPEvent::ERedirectedPermanently</apiname></xref> indicates that the transaction has been redirected and the HTTP origin server indicated that it was a permanent redirection. The URI for the transaction is now the redirected location. </p> </li> <li id="GUID-7FF792D8-7B84-5827-B499-C2FFC2FA9007"><p> <xref href="GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3.dita#GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3/GUID-DEB91CA2-ECFA-3443-9489-AA9E2D50337B"><apiname>THTTPEvent::ERedirectedTemporarily</apiname></xref> indicates that the transaction has been redirected and the HTTP origin server indicated that it was a temporary redirection. </p> </li> <li id="GUID-B5BFE6F9-96D3-5942-BA9F-E2C2B6A52D73"><p> <codeph> default</codeph>: an unrecognised event. Negative values indicate an error propogated from filters or lower comms layers. If not understood by the client, error values may be safely ignored as a <xref href="GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3.dita#GUID-518CC5C3-1CE1-316E-9688-93DB12E58EB3/GUID-6BC33448-9CB9-3488-87DD-EFB0C5435044"><apiname>THTTPEvent::EFailed</apiname></xref> event is guaranteed to follow. Positive values are used for warning conditions. </p> </li> </ul> </section> <section id="GUID-2F0853C8-6764-40EC-A57C-E770A5D39859"><title>Obtaining the response status</title> <p>To obtain the response status code and text description, the transaction response is used: </p> <codeblock id="GUID-A5FB04A3-905A-5C0E-996E-B0CB0ED91BA8" xml:space="preserve">case THTTPEvent::EGotResponseHeaders:
       
   104     {
       
   105     RHTTPResponse resp = aTransaction.Response();
       
   106     TInt status = resp.StatusCode();
       
   107     RStringF statusStr = resp.StatusText();</codeblock> </section> <section id="GUID-225CEAAB-C9C1-4D80-A4E5-4267E5B123A5"><title>Obtaining the response headers</title> <p>The response headers can be iterated using the <xref href="GUID-9C6B4D0A-8499-36D6-8F07-A3C3DB6615DC.dita"><apiname>THTTPHdrFieldIter</apiname></xref> class. Individual header fields can be queried as shown in the following example: </p> <codeblock id="GUID-3643D54F-7430-56BE-B641-1C0F539DF8D9" xml:space="preserve">RHTTPResponse resp = aTrans.Response();
       
   108     RStringPool strP = aTrans.Session().StringPool();
       
   109     RHTTPHeaders hdr = resp.GetHeaderCollection();
       
   110     THTTPHdrFieldIter it = hdr.Fields();
       
   111 
       
   112     TBuf&lt;KMaxHeaderNameLen&gt;  fieldName16;
       
   113     TBuf&lt;KMaxHeaderValueLen&gt; fieldVal16;
       
   114 
       
   115     while (it.AtEnd() == EFalse)
       
   116     {
       
   117     // Get the name of the next header field
       
   118     RStringTokenF fieldName = it();
       
   119     RStringF fieldNameStr = strP.StringF(fieldName);
       
   120 
       
   121     // Check it does indeed exist
       
   122     THTTPHdrVal fieldVal;
       
   123     if (hdr.GetField(fieldNameStr,0,fieldVal) == KErrNone)
       
   124         {
       
   125         ...
       
   126         // Display realm for WWW-Authenticate header
       
   127         RStringF wwwAuth = strP.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable());
       
   128         if (fieldNameStr == wwwAuth)
       
   129             {
       
   130             // check the auth scheme is 'basic'
       
   131             RStringF basic = strP.StringF(HTTP::EBasic,RHTTPSession::GetTable());
       
   132             RStringF realm = strP.StringF(HTTP::ERealm,RHTTPSession::GetTable());
       
   133             THTTPHdrVal realmVal;
       
   134             if ((fieldVal.StrF() == basic) &amp;&amp; 
       
   135             // check the header has a 'realm' parameter 
       
   136             (!hdr.GetParam(wwwAuth, realm, realmVal)))
       
   137                 {
       
   138                 RStringF realmValStr = strP.StringF(realmVal.StrF());
       
   139                 fieldVal16.Copy(realmValStr.DesC());
       
   140                 iUtils.Test().Printf(_L("Realm is: %S\n"), &amp;fieldVal16);
       
   141                 realmValStr.Close();
       
   142                 }
       
   143             }
       
   144             basic.Close();
       
   145             realm.Close();
       
   146         }
       
   147         // Advance the iterator
       
   148         ++it;
       
   149         // Close all RStrings
       
   150         fieldName.Close();
       
   151         fieldNameStr.Close();
       
   152         wwwAuth.Close();
       
   153     }
       
   154     resp.Close();
       
   155     strP.Close();
       
   156     hdr.Close();</codeblock> </section> <section id="GUID-6FA09592-E909-4A24-81F0-A71F666B01C8"><title>Obtaining the response body</title> <p>To access the response body, the data supplier contained in the transaction response must be used. When the client has finished processing each piece of body data, the data must be released: </p> <codeblock id="GUID-60298F6A-BF73-5CB1-A31D-C34114F04E90" xml:space="preserve">case THTTPEvent::EGotResponseBodyData:
       
   157     {
       
   158     // Get the body data supplier
       
   159     iRespBody = aTransaction.Response().Body();
       
   160 
       
   161     // Some (more) body data has been received (in the HTTP response)
       
   162     if (iVerbose)
       
   163             DumpRespBody(aTransaction);
       
   164     else
       
   165             iUtils.Test().Printf(_L("*"));
       
   166     // Append to the output file if we're saving responses
       
   167     if (iSavingResponseBody)
       
   168             {
       
   169             TPtrC8 bodyData;
       
   170             TBool lastChunk = iRespBody-&gt;GetNextDataPart(bodyData);
       
   171             iRespBodyFile.Write(bodyData);
       
   172             if (lastChunk)
       
   173                 iRespBodyFile.Close();
       
   174             }
       
   175  // Done with that bit of body data
       
   176     iRespBody-&gt;ReleaseData();
       
   177     } break;</codeblock> <p>The <xref href="GUID-1B03F068-9552-37BA-A284-8E54FAC2AAC5.dita#GUID-1B03F068-9552-37BA-A284-8E54FAC2AAC5/GUID-D4E82D9A-7C88-30B4-B50B-D3CAF39B22F2"><apiname>MHTTPDataSupplier::OverallDataSize()</apiname></xref> method can be used to find out how large the entire body is before processing the body data. The value returned is based on the HTTP response Content-Length header. However, not all responses will include this header. For example, when the HTTP server is using the 'chunked' transfer encoding. In that case, the overall data size will be returned as <codeph>KErrNotFound</codeph>. </p> <p>Regardless of that, the final piece of body data will always cause <xref href="GUID-1B03F068-9552-37BA-A284-8E54FAC2AAC5.dita#GUID-1B03F068-9552-37BA-A284-8E54FAC2AAC5/GUID-F8D21ACA-E984-3686-9E45-44ECDEAA4B70"><apiname>MHTTPDataSupplier::GetNextDataPart()</apiname></xref> to return <codeph>ETrue</codeph>. </p> </section> <section id="GUID-AFE19311-E6A2-425F-B51F-4CFC287FC7A9"><title>Completing the transaction</title> <p>In <filepath>HTTPEXAMPLECLIENT</filepath>, the final completion of the transaction (indicated with a success or failure message) stops the local active scheduler. The <codeph>EResponseComplete</codeph> code is not used for anything here. Since each transaction is guaranteed to send either an <codeph>ESucceeded</codeph> event or an <codeph>EFailed</codeph> event, they can be used as a signal to finish. </p> <codeblock id="GUID-A212D790-98D1-527C-A269-B1722D1F053F" xml:space="preserve">case THTTPEvent::EResponseComplete:
       
   178             {
       
   179             // The transaction's response is complete
       
   180             iUtils.Test().Printf(_L("\nTransaction Complete\n"));
       
   181             } break;
       
   182         case THTTPEvent::ESucceeded:
       
   183             {
       
   184             iUtils.Test().Printf(_L("Transaction Successful\n"));
       
   185             aTransaction.Close();
       
   186             CActiveScheduler::Stop();
       
   187             } break;
       
   188         case THTTPEvent::EFailed:
       
   189             {
       
   190             iUtils.Test().Printf(_L("Transaction Failed\n"));
       
   191             aTransaction.Close();
       
   192             CActiveScheduler::Stop();
       
   193             } break;
       
   194         case THTTPEvent::ERedirectedPermanently:
       
   195             {
       
   196             iUtils.Test().Printf(_L("Permanent Redirection\n"));
       
   197             } break;
       
   198         case THTTPEvent::ERedirectedTemporarily:
       
   199             {
       
   200             iUtils.Test().Printf(_L("Temporary Redirection\n"));
       
   201             } break;</codeblock> <p>The transaction is closed using <xref href="GUID-2E673024-239B-3965-8880-C47B7CC24EF6.dita#GUID-2E673024-239B-3965-8880-C47B7CC24EF6/GUID-0ABF9404-EA7F-3CB3-B08B-D9154EF6F2D8"><apiname>RHTTPTransaction::Close()</apiname></xref>. This internally frees the resources associated with that transaction. The transaction should not be used again. </p> </section> <section id="GUID-8E708D45-31C2-4C6B-9BEF-260CBF94CDDF"><title>Terminating the session</title> <p>When the client is ready to terminate, the session is closed: </p> <codeblock id="GUID-DF6E28A1-A70A-52BF-B841-F85049F12D3A" xml:space="preserve">CHttpClient::~CHttpClient()
       
   202     {
       
   203     iSess.Close();
       
   204     ...
       
   205     }</codeblock> <p>When the session is closed, all resources are returned to the system. Transactions that were not complete are immediately cancelled. </p> </section> </conbody></concept>