Symbian OS Communications (779884), страница 71
Текст из файла (страница 71)
Example 11.1 setsboth the EHttpSocketServ and EHttpSocketConnection sessionproperties – the socket server property to save on resources by sharingthe socket server handle between the HTTP framework and the client,and the connection property to allow the client to specify the connectionwithout prompting the user1 .11.2.2 Transaction PropertiesSession properties apply to all transactions within a session. Some properties, such as the use of pipelining or a proxy, can also be set on aparticular transaction. These will override the session behavior.11.3 Creating and Submitting a TransactionThe request and response parts of an HTTP transaction are encapsulatedin an RHTTPTransaction.
Here are the most interesting methods:class RHTTPTransaction• {• public:•IMPORT_C void SubmitL(THTTPFilterHandle aStart =THTTPFilterHandle::EClient);•IMPORT_C void NotifyNewRequestBodyPartL(THTTPFilterHandle aStart =THTTPFilterHandle::EClient);•IMPORT_C void Cancel(THTTPFilterHandle aStart =THTTPFilterHandle::EClient);•IMPORT_C void Close();•IMPORT_C RHTTPRequest Request() const;•IMPORT_C RHTTPResponse Response() const;1As discussed in Chapter 6, applications may wish to allow the user to configure aconnection that should always be used to access the service, rather than prompting eachtime a connection needs to be created, or using the device-wide default connection.348HTTP•••IMPORT_C RHTTPSession Session() const;IMPORT_C RHTTPTransactionPropertySet PropertySet() const;IMPORT_C void SendEventL(THTTPEvent aStatus, THTTPEvent::TDirectionaDirection, THTTPFilterHandle aStart);•IMPORT_C const CCertificate* ServerCert();•IMPORT_C RString CipherSuite();• };A transaction consists of requests and responses, each of which areencapsulated into a ‘message’ (‘message’ is an abstraction defined inRFC 2616).
These requests and responses contain header fields and,optionally, body data.We now need to create a class derived from MTransactionCallback to monitor the progress of this transaction. The interface has twocallback functions:class MHTTPTransactionCallback{public:virtual void MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent&aEvent)=0;virtual TInt MHFRunError(TInt aError, RHTTPTransaction aTransaction,const THTTPEvent& aEvent)=0;};These are called by the framework, letting you know, asynchronouslyvia transaction events, how your request is progressing. There are moredetails on monitoring a transaction in Section 11.5.HTTP requests are created using OpenTransactionL(). You canthe use the returned RHTTPTransaction to configure the transaction,setting transaction properties via the RHTTPTransactionPropertySet returned from PropertySet(). You can also modify the requestvia the RHTTPRequest returned from Request().
You can add anyheaders needed in the request, for example Content-Type.For Post requests you need to specify where the body data is obtainedfrom using SetBody(). Further details on the use of SetBody() aregiven in section 11.4.Once you have finished customizing the request, you should submitit by calling SubmitL(). If you have not provided an RConnectionin the HTTP session properties, then submitting the first transaction willtrigger the creation of a network connection.If there is a problem with the request, the transaction will be cancelled.
The client application will receive an ECancel event via theirMTransactionCallback::MHFRunL().SUPPLYING BODY DATA349EXPORT_C void CFlickrRestAPI::IssueImagePostL(const TDesC& aFileName){...// Open a POST transactionRStringF postMethod;RStringPool stringPool = iSession.StringPool();postMethod=stringPool.StringF(HTTP::EPOST,RHTTPSession::GetTable());iPostTransaction = iSession.OpenTransactionL(uri, *this, postMethod);postMethod.Close();// We provide the bodyiPostTransaction.Request().SetBody(*this);...iPostTransaction.SubmitL();}Example 11.2Submitting a Post request11.4 Supplying Body DataExample 11.2 shows a Post request being made.
The Post method requiresa body in the request. To supply this you need to provide an object whichimplements the MHttpDataSupplier interface.class MHTTPDataSupplier{public:virtual TBool GetNextDataPart(TPtrC8& aDataPart) = 0;virtual void ReleaseData() = 0;virtual TInt Reset() = 0;};For small files you could return all of the data for the body in oneresponse to MHTTPDataSupplier::GetNextDataPart().
For largerfiles you should return the data in parts.If supplying data in parts it is important to implement Reset() andbe able to resupply the data if it is called. A Post request may need to beresent if, for example, the network connection is dropped, or the serverresponds with a redirect. If Reset() returns an error the request will fail.Once GetNextDataPart() has been called, the data supplied inaDataPart must remain valid, and must not be altered until ReleaseData() is called.35011.5HTTPMonitoring a Transaction11.5.1 Event HandlingThe client is notified about the current status of the transaction usingtransaction events.
There are two types of events:• Incoming – generated within the framework and notifying the client(and filters – see section 11.13) of the transaction’s current status.• Outgoing – most of these originate in client actions (e.g. cancelling atransaction will generate an ECancel event) and notify the frameworkof client actions.For an HTTP session we are only interested in transaction events;however, not all events are relevant. The ones of interest are shown inTable 11.1.11.5.2 Receiving Header DataWhen the event EGotResponseHeaders is called it indicates that thestatus line and response header fields have been received and are accessible. The status code is the most important information.
The headers can beretrieved with a call to RHttpResponse::GetHeaderCollection().Through RHTTPHeaders individual header values can be retrieved usingGetField(). Here are the methods provided by RHTTPHeaders:class RHTTPHeaders{public:IMPORT_C TInt FieldPartsL(RStringF aFieldName) const;IMPORT_C TInt GetField(RStringF aFieldName, TInt aPartIdx, THTTPHdrVal&aHeaderValue) const;IMPORT_C TInt GetRawField(RStringF aFieldName, TPtrC8& aRawFieldData)const;IMPORT_C TInt GetParam(RStringF aFieldName, RStringF aParamName,THTTPHdrVal& aReturn, TInt aPartIdx = 0) const;IMPORT_C THTTPHdrFieldIter Fields() const;IMPORT_C void SetFieldL(RStringF aFieldName, THTTPHdrVal aFieldValue);IMPORT_C void SetFieldL(RStringF aFieldName, THTTPHdrVal aFieldValue,RStringF aParamName, THTTPHdrVal aParamValue);IMPORT_C void SetParamL(RStringF aFieldName, RStringF aParamName,THTTPHdrVal aParamValue, TInt aPartIdx);IMPORT_C void SetRawFieldL(RStringF aFieldName, const TDesC8&aRawFieldData, const TDesC8& aFieldSeparator);IMPORT_C TInt RemoveField(RStringF aFieldName);IMPORT_C TInt RemoveFieldPart(RStringF aFieldName, TInt aIndex);IMPORT_C void RemoveAllFields();};MONITORING A TRANSACTION351Table 11.1 HTTP Transaction Event codesEvent NameDescriptionEGotResponseHeadersIndicates that the response has beenreceived and the status line andheader field information can beretrieved, for example Checktransaction for ContentType orContent-Length information ifexpecting response bodyEGotResponseBodyDataIndicates that body data is ready foraccess (need to callGetNextBodyPart() .
. . and thenReleaseData()). It may be theentire message body or a part. If it isthe last body part ETrue is returnedEGotResponseTrailerHeadersIndicates trailing headers have beenreceived and can be retrievedEResponseCompleteCan be taken as an indication of endof the body (if for some reason lastcall to GetNextBodyPart() failedto return Etrue)ESucceededTransaction completed OK – justneed to close itEFailedThe client needs to investigate thecause of the failure.
It may be afailing status received from the serveror a problem with the connectionERedirectedPermanentlyFramework will deal with resendingthe request to the new location butthe client should take note for thefutureERedirectedTemporarilyNo need for action. The redirectionwill be automaticERedirectRequiresConfirmation Client needs to make a decision:either to close the transaction orresubmit it to the new location(already set)352HTTP11.5.3 Receiving Body DataA response message may not be received in one go, especially if thebody is large. The framework will indicate that there is body data toretrieve by sending one or more EGotResponseBodyData events (seeExample 11.3)....case THTTPEvent::EGotResponseBodyData:{// Part (or all) of response’s body data received.
Use// aTransaction.Response().Body()->GetNextDataPart() to getthe actual// body data.// Get the body data supplierMHTTPDataSupplier* body = aTransaction.Response().Body();TPtrC8 dataChunk;TBool isLast = body->GetNextDataPart(dataChunk);if(iCurrentTansactionType == ETransactionGetAuthToken){iRestXMLHandler->ProcessGetTokenResponseL(dataChunk,iFlickrAuthStruct);if(iFlickrAuthStruct){StoreAuthorisationDetailsL();}else{iTransactionErrorCode = KErrArgument;}}else if(iCurrentTransactionType == ETransactionPostImage){TBuf8<50> imageId;iRestXMLHandler->ProcessPostImageResponseL(dataChunk,imageId);}// Always remember to release the body data.body->ReleaseData();}break;}...Example 11.3How to process body data from an HTTP ResponseWhen the event is received, the response body data part is accessiblevia GetNextDataPart(). It is important to call ReleaseData() onceyou have finished processing this part of the body data otherwise youwill not receive the rest of the body.
If it is the last (or only) part, GetNextDataPart() should return ETrue; but under some circumstances,especially when the server is using chunked transfer encoding, then theSTRINGPOOL353framework may not be able to reliably signal the end of the body. Asis it not possible to control whether the server uses chunked transferencoding or not, you should also watch for the EResponseCompleteevent, which reliably signals the end of the body data.11.6 Cancelling a TransactionAt any point after a transaction has been submitted it can be cancelled.The framework may also cancel a transaction, for example when aconnection error occurs.11.7 Closing a TransactionWhen the transaction has completed, either with EFailed or ESuccessful, it should be closed by calling Close() on the RHTTPTransaction.ReleaseData() must be called prior to closing a transaction. Thismay appear non-intuitive, however, failing to do so puts the connectionin a bad state, and it will not be usable by the subsequent transaction(if there is one queued).11.8 StringpoolStringpool (which is part of the BAFL APIs) is used by the HTTP framework.It has been designed for efficient comparison and storage of standardstrings.