quick_recipes (779892), страница 29
Текст из файла (страница 29)
The session is established by calling CSecureSocket::StartClientHandshake(). Once client handshake iscomplete, the application can use a subset of the RSocket send/receivemethods implemented in CSecureSocket to exchange data.Note that calling StartClientHandshake() may result in a dialogprompt asking for permission to establish the connection (since we haveset the dialog mode to EDialogModeAttended) in case an untrustedcertificate was received.
By default, any untrusted certificate is rejectedand client handshake completed with an error.At the time of writing, CSecureSocket supports both TLS 1.0 andSSL 3.0 protocols.Tip: Besides providing the basic communication methods, as wehave seen already, the CSecureSocket class provides various utilitymethods that allow the application to get the server–client certificatein use, the cipher suites currently available in the system for use, or setwhich ones to use, and so on. Be sure to check securesocket.hand its associated documentation in the Symbian Developer Library.164SYMBIAN C++ RECIPESWhat may go wrong when you do this: The CSecureSocket instanceeffectively takes ownership of the RSocket instance passed duringcreation and closes the socket when the secure socket is closed.
Anyattempt to use the RSocket instance without reopening it again willresult in the application being panicked!4.3.6.5Use HTTP POST RequestAmount of time required: 20 minutesLocation of example code: \HTTP\HTTPPostRequired library(s): http.lib, bafl.lib, inteprotutil.libRequired header file(s): http.hPlatform security capability(s): NetworkServicesProblem: You want to use a HTTP POST request.Solution: Create a transaction, specifying HTTP POST as method, alongwith the URI of the resource requested.You should be familiar with the HTTP GET Recipe (4.3.5.5) beforetrying a POST as we reuse a lot of its code.#include <http.h> // link to http.lib, bafl.lib, inetprotutil.libvoid CHTTPPostMultipart::PostMultipartDataL(const TDesC& aActionURI,RFile& aPostData, MHTTPTransactionCallback& aTransCallback){// Convert URL to RFC3629 compliant// 8 bit UTF-8 encoded URIRBuf8 uri8;CleanupClosePushL(uri8);uri8.CreateL(aActionURI.Length());uri8.Copy(aActionURI);TUriParser8 uri;User::LeaveIfError(uri.Parse(uri8));// Set method to HTTP POST and submit// the transactionRStringF method = iSession.StringPool().StringF(HTTP::EGET, RHTTPSession::GetTable());iTransaction = iSession.OpenTransactionL(uri, aTransCallback,method);// Store the file handle for// reading file content lateriPostData = aPostData;// Assign the data supplieriTransaction.Response().SetBody(*this);iTransaction.SubmitL();CleanupStack::PopAndDestroy(&uri8);}NETWORKING165TBool CHTTPPostMultipart::GetNextDataPart(TPtrC8& aDataPart){// Read from the post data fileiNoMoreData = EFalse;TInt err = iPostData.Read(iDataPart);if (KErrNone == err){aDataPart.Set(iDataPart);iNoMoreData = (iDataPart.Length() == 0);}return iNoMoreData;}void CHTTPPostMultipart::ReleaseData(){iDataPart.Zero();// We still haven’t posted the whole file yet;// notify the transactionif (!iNoMoreData){TRAP_IGNORE(iTransaction.NotifyNewRequestBodyPartL());}}TInt CHTTPPostMultipart::OverallDataSize(){TInt dataSize = 0;// Ignore error return from Size()iPostData.Size(dataSize);return (dataSize == 0 ? KErrNotFound : dataSize);}TInt CHTTPPostMultipart::Reset(){TInt pos = 0;return iPostData.Seek(ESeekStart, pos);}Discussion: The framework calls MHTTPDataSupplier::GetNextDataPart() to request the post body data.
For small post requests,the application can return the whole body data in one go. However,for larger requests, it is recommended that the application returns thedata in chunks, as seen in our example code. No matter what, the data(buffer) supplied in GetNextDataPart() must remain valid until theframework calls ReleaseData().ReleaseData() is called by the framework to indicate that the postdata supplied earlier in GetNextDataPart() has been processed by theframework and can be freed.
Applications supplying post data in chunksneed to call NotifyNewRequestBodyPartL() on the transactionobject if there is data still to be posted.If the framework encountered some problem posting the data, it callsReset() to indicate that it would like to restart the post request. Theapplication can choose to comply or decline the request, by returningKErrNone or an error code, respectively.166SYMBIAN C++ RECIPESOverallDataSize() is used by the framework to determine thelength of the post request data.
Applications should return the length ofthe post request data if known, or KErrNotFound otherwise.The HTTP framework provides a utility class, CHTTPFormEncoder,defined in chttpformencoder.h for posting requests where the content type is ‘application/x-www-form-urlencoded’, for example a searchengine query submission form. CHTTPFormEncoder implements theMHTTPDataSupplier interface described above and simplifies requestposting, as the example below illustrates:void CPostForm::SubmitFormL(const TDesC& aActionURI, const TDesC& aField,const TDesC& aValue, MHTTPTransactionCallback& aTransCallback){// Convert URL to RFC3629 compliant// 8 bit UTF-8 encoded URIRBuf8 uri8;CleanupClosePushL(uri8);uri8.CreateL(aActionURI.Length());uri8.Copy(aActionURI);TUriParser8 uri;User::LeaveIfError(uri.Parse(uri8));// Set method to HTTP POST and submit// the transactionRStringF method = iSession.StringPool().StringF(HTTP::EPOST, RHTTPSession::GetTable());RHTTPTransaction transaction = iSession.OpenTransactionL(uri,aTransCallback, method);// Create the form encoderif (iFormEncoder){delete iFormEncoder;iFormEncoder = NULL;}iFormEncoder = CHTTPFormEncoder::NewL();// Convert field and value to 8 bit counterparts// and add to the form encoderRBuf8 field8;field8.CreateL(aField.Length());field8.CleanupClosePushL();field8.Copy(aField);RBuf8 value8;value8.CreateL(aValue.Length());value8.CleanupClosePushL();value8.Copy(aValue);// Add field/value pairiFormEncoder->AddFieldL(field8, value8);// Assign form encoder as the data suppliertransaction.Response().SetBody(*iFormEncoder);NETWORKING167transaction.SubmitL();CleanupStack::PopAndDestroy(3); // uri8, field8, value8}4.3.6.6Set Advanced HTTP PropertiesAmount of time required: 20 minutesLocation of example code: \HTTP\HTTPConnectionConfigurationRequired header(s): http.hRequired library(s): http.lib, bafl.lib, inteprotutil.libRequired platform security capability(s): NoneProblem: You need to override the default system settings for a networkconnection.Solution: Set some commonly used connection parameters, includingproxy information and network connection.void CGetPage::SetConnectionInfoL(RSocketServ& ss, RConnection& conn){RStringPool strPool = iSession.StringPool();RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();connInfo.SetPropertyL(strPool.StringF(HTTP::EHttpSocketServ,RHTTPSession::GetTable()), THTTPHdrVal(ss.Handle()));connInfo.SetPropertyL(strPool.StringF(HTTP::EHttpSocketConnection,RHTTPSession::GetTable()),THTTPHdrVal(reinterpret_cast<TInt>(&conn)));}Discussion: The HTTP framework uses the system defaults for establishing the network connection, which is similar to using RConnection::Start() with no preferences set.
This recipe allows you tooverride this behavior.Note that when using an external connection, the framework assumesit has already been started. The framework also does not take ownershipof the specified connection; hence it is up to the application developerto ensure the lifetime of the connection is longer than the HTTP session.Apart from that, the RConnection object specified must have beenopened as a sub-session of the RSocketServ session object specified.The downside of using a user-specified connection is that the HTTPframework won’t automatically restart the connection once it has gonedown (signs for this are transaction fails with KErrNotReady).
It isrecommended that the application monitors the status of the connection(see Recipe 4.3.6.2) to handle resubmission of any failed transaction.168SYMBIAN C++ RECIPESThe connection proxy settings can also be overridden, both at theHTTP session level and at the HTTP transaction level:void CGetPage::SetProxyInfoL(const TDesC& aProxyAddr){RStringPool strPool = iSession.StringPool();RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();RBuf8 proxyAddr8;proxyAddr8.CreateL(aProxyAddr.Length());proxyAddr8.CleanupClosePushL();proxyAddr8.Copy(aProxyAddr);RStringF proxyAddr = strPool.OpenFStringL(proxyAddr8);CleanupClosePushL(proxyAddr);connInfo.SetPropertyL(strPool.StringF(HTTP::EProxyUsage,RHTTPSession::GetTable()), strPool.StringF(HTTP::EUseProxy,RHTTPSession::GetTable()));connInfo.SetPropertyL(strPool.StringF(HTTP::EProxyAddress,RHTTPSession::GetTable()), THTTPHdrVal(proxyAddr));CleanupStack::PopAndDestroy(2); // proxyAddr8, proxyAddr}void CGetPage::SetTransactionProxyInfoL(const TDesC& aProxyAddr,RHTTPTransaction aTransaction){RStringPool strPool = iSession.StringPool();RHTTPTransactionPropertySet propertySet = aTransaction.PropertySet();RBuf8 proxyAddr8;proxyAddr8.CreateL(aProxyAddr.Length());proxyAddr8.CleanupClosePushL();proxyAddr8.Copy(aProxyAddr);RStringF proxyAddr = strPool.OpenFStringL(proxyAddr8);CleanupClosePushL(proxyAddr);propertySet.SetPropertyL(strPool.StringF(HTTP::EProxyUsage,RHTTPSession::GetTable()), strPool.StringF(HTTP::EUseProxy,RHTTPSession::GetTable()));propertySet.SetPropertyL(strPool.StringF(HTTP::EProxyAddress,RHTTPSession::GetTable()), THTTPHdrVal(proxyAddr));CleanupStack::PopAndDestroy(2); // proxyAddr8, proxyAddr}4.3.6.7Extract Local Filename from URIAmount of time required: 10 minutesLocation of example code: \InetProtUtils\InetProtUtilsDemoNETWORKING169Required library(s): intetprotutils.libRequired header file(s): uri8.hRequired platform security capability(s): NoneSolution: Get the filename from a URI using TUriParser8::GetFileNameL().#include <uri8.h>void CInetProtUtilsDemoAppUi::UriToFileNameL(){TUriParser8 uriParser;_LIT8(KFixedFile, "file:///c/data/test.txt");User::LeaveIfError(uriParser.Parse(KFixedFile));// fixedFileName should now be// c:\data\test.txt, if the file existsHBufC* fixedFileName = uriParser.GetFileNameL();// Do something...delete fixedFileName;_LIT8(KRemovableFile, "file:///ext-media/data/test.txt");User::LeaveIfError(uriParser.Parse(KRemovableFile));// removableFileName should now be// e:\data\test.txt, if the file existsHBufC* removableFileName = uriParser.GetFileNameL();// Do something...delete removableFileName;_LIT8(KPrivateFixedFile, "file:///private/c/data/test.txt");User::LeaveIfError(uriParser.Parse(KPrivateFixedFile));// pvtFixedFileName should now be// c:\private\0xE34E47D5\data\test.txt, if the file existsHBufC* pvtFixedFileName = uriParser.GetFileNameL();// Do something...delete pvtFixedFileName;}Discussion: Earlier in Recipe 4.3.5.7 we saw how to get the URI, given afilename.