diff -r 000000000000 -r dd21522fd290 browserutilities/feedsengine/FeedsServer/UrlHandler/src/HttpHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/browserutilities/feedsengine/FeedsServer/UrlHandler/src/HttpHandler.cpp Mon Mar 30 12:54:55 2009 +0300 @@ -0,0 +1,468 @@ +/* +* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: A class that fetches resources via HTTP 1.1. +* +*/ + + +#include +#include +#include +#include + +#include "HttpConnection.h" +#include "HttpHandler.h" +#include "LeakTracker.h" +#include "Logger.h" + +#include "CUserAgent.h" + +// ----------------------------------------------------------------------------- +// CHttpHandler::NewL +// +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CHttpHandler* CHttpHandler::NewL(CHttpConnection& aHttpConnection) + { + CHttpHandler* self = new (ELeave) CHttpHandler(aHttpConnection); + + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + + return self; + } + + +// ----------------------------------------------------------------------------- +// CHttpHandler::CHttpHandler +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CHttpHandler::CHttpHandler(CHttpConnection& aHttpConnection): + KTimerPeriod(40000000), iLeakTracker(CLeakTracker::EHttpHandler), + iHttpConnection(&aHttpConnection), + iSession(aHttpConnection.Session()), iLastActivity(0), iStatusCode(KErrNone) + { + iTimerState.iFunction = TimerCallback; + iTimerState.iPtr = static_cast(this); + } + + +// ----------------------------------------------------------------------------- +// CHttpHandler::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CHttpHandler::ConstructL() + { + // Get the http connection. + if (!iHttpConnection->IsConnected()) + { + // Set this instance as the connection observer. + + // TODO: In 3.1 when multiple tasks are supported this needs to be + // changed to AddObserver as multiple tasks may need to be waken. + iHttpConnection->SetObserver(this); + iIsConnectionObserver = ETrue; + } + + iTimer = CPeriodic::NewL(EPriorityHigh); + + iStringPool = iSession.StringPool(); + } + + +// ----------------------------------------------------------------------------- +// CHttpHandler::~CHttpHandler +// Deconstructor. +// ----------------------------------------------------------------------------- +// +CHttpHandler::~CHttpHandler() + { + // If this happened to be the instances that is observing the connection + // then clear the connection's observer... + if (iIsConnectionObserver) + { + if(iHttpConnection) + { + iHttpConnection->SetObserver(NULL); + } + + } + RHTTPTransaction temp; + if (iTransaction != temp) + { + // Close the transaction. + iTransaction.Close(); + } + delete iResponseBuffer; + delete iTimer; + } + + +// ----------------------------------------------------------------------------- +// CHttpHandler::LoadUrl +// +// Loads the given url -- asynchronously +// ----------------------------------------------------------------------------- +// +void CHttpHandler::LoadUrlL(const TDesC& aUrl, MLoadObserver& aObserver) + { + TUriParser8 uriParser; + HBufC8* url; + + // Set the observer. + iObserver = &aObserver; + + // Parse the url. + url = HBufC8::NewLC(aUrl.Length()); + url->Des().Copy(aUrl); + User::LeaveIfError(uriParser.Parse(*url)); + + // Create the transaction. + iTransaction = iSession.OpenTransactionL(uriParser, *this, + iSession.StringPool().StringF(HTTP::EGET, RHTTPSession::GetTable())); + + // TODO: Set the headers if any. + //++PK Add UA header code + + iUserAgentHeader = iTransaction.Request().GetHeaderCollection(); + + CUserAgent* tWebUtilsStandardUA = CUserAgent::NewL(); + CleanupStack::PushL(tWebUtilsStandardUA); + + HBufC8* tWebUtilsStandardUAHeaderValue = tWebUtilsStandardUA->UserAgentL(); + + RStringF tStringValue = iSession.StringPool().OpenFStringL(*tWebUtilsStandardUAHeaderValue); + + THTTPHdrVal tHeaderValue( tStringValue ); + + RStringF tStringUA = iSession.StringPool().StringF(HTTP::EUserAgent, RHTTPSession::GetTable()); + + iUserAgentHeader.SetFieldL( tStringUA, tStringValue ); + + //++PK + // Submit the request. + iTransaction.SubmitL(); + + // If the connection is available it is safe to tell to the observer + // to display progress indicators (i.e. a wait-dialog). + if (iHttpConnection->IsConnected()) + { + iObserver->StartWait(); + + // Start the inactive connection timer as well. + iTimer->Start(KTimerPeriod, KTimerPeriod, iTimerState); + iLastActivity.HomeTime(); + } + + CleanupStack::PopAndDestroy(tWebUtilsStandardUA); + CleanupStack::PopAndDestroy(url); + } + + +// ----------------------------------------------------------------------------- +// CHttpHandler::ConnectionAvailable +// +// Notifies the observer that the connection is available. +// ----------------------------------------------------------------------------- +// +void CHttpHandler::ConnectionAvailable() + { + // Now that the connection is available it is safe to tell to the observer + // to display progress indicators (i.e. a wait-dialog). + iObserver->StartWait(); + + // Start the inactive connection timer. + iTimer->Start(KTimerPeriod, KTimerPeriod, iTimerState); + iLastActivity.HomeTime(); + } + + +// ----------------------------------------------------------------------------- +// CHttpHandler::ConnectionFailed +// +// Notifies the observer that the establishment of the connection failed. +// ----------------------------------------------------------------------------- +// +void CHttpHandler::ConnectionFailed(TInt aStatus) + { + // Cancel the transaction. + iTransaction.Cancel(); + aStatus = -aStatus; + // Notify the observer. + LoadCompleted(aStatus, NULL, KNullDesC, KNullDesC); + } + + +// ----------------------------------------------------------------------------- +// CHttpHandler::MHFRunL +// +// Called when the filter's registration conditions are satisfied for events that +// occur on a transaction. +// ----------------------------------------------------------------------------- +// +void CHttpHandler::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent) + { + // Some kind of connection activity occurred so update iLastActivity. + iLastActivity.HomeTime(); + + switch (aEvent.iStatus) + { + case THTTPEvent::EGotResponseHeaders: + { + RHTTPResponse resp = aTransaction.Response(); + + // Get the headers + iRespHeaders = resp.GetHeaderCollection(); + } + break; + + case THTTPEvent::EGotResponseBodyData: + { + MHTTPDataSupplier* dataSupplier; + TPtrC8 ptr; + + // Get the data. + dataSupplier = aTransaction.Response().Body(); + dataSupplier->GetNextDataPart(ptr); + CleanupStack::PushL(TCleanupItem(&CleanupDataSupplier, dataSupplier)); + + // Append to iResponseBuffer + if (iResponseBuffer == NULL) + { + iResponseBuffer = ptr.AllocL(); + } + else + { + iResponseBuffer = iResponseBuffer->ReAllocL(iResponseBuffer->Length() + ptr.Length()); + iResponseBuffer->Des().Append(ptr); + } + + // Release the body data. + CleanupStack::PopAndDestroy(/*dataSupplier*/); + } + break; + + case THTTPEvent::ESucceeded: + { + TDesC* contentType = NULL; + TDesC* charSet = NULL; + + // Get the content-type and char-set. + GetContentTypeL(contentType, charSet); + + // Pass the buffer to the observer. + LoadCompleted(KErrNone, iResponseBuffer, *contentType, *charSet); + iResponseBuffer = NULL; + + delete contentType; + contentType = NULL; + delete charSet; + charSet = NULL; + } + break; + + case THTTPEvent::EFailed: + case THTTPEvent::EUnrecoverableError: + { + // Notify the observer. + RHTTPResponse resp = aTransaction.Response(); + TInt statusCode = resp.StatusCode(); + if(iStatusCode == KErrNone) + { + iStatusCode = (statusCode + 20000); // Web server HTTP status code are lesser than -20000 + } + if(iStatusCode == -(KErrNoMemory)) //KErrNoMemory is not HTTP error so it should be -ve + { + iStatusCode = KErrNoMemory; + } + LoadCompleted( iStatusCode, NULL, KNullDesC, KNullDesC ); + + // Clean up the response buffer. + delete iResponseBuffer; + iResponseBuffer = NULL; + } + break; + + default: + FEED_LOG1(_L("Feeds"), _L("Feeds_Errors.log"), + EFileLoggingModeAppend, _L("CHttpHandler::MHFRunL - Failure: default %d."), aEvent.iStatus); + if(aEvent.iStatus < KErrNone) + { + // HTTP errors should always be +ve + iStatusCode = -(aEvent.iStatus); + } + break; + } + } + + +// ----------------------------------------------------------------------------- +// CHttpHandler::MHFRunError +// +// Called when RunL leaves from a transaction event. This works in the same +// way as CActve::RunError; return KErrNone if you have handled the error. +// ----------------------------------------------------------------------------- +// +TInt CHttpHandler::MHFRunError(TInt aError, RHTTPTransaction /*aTransaction*/, + const THTTPEvent& /*aEvent*/) + { + FEED_LOG1(_L("Feeds"), _L("Feeds_Errors.log"), + EFileLoggingModeAppend, _L("CHttpHandler::MHFRunError: %d."), aError); + + // Notify the observer. + LoadCompleted(aError, NULL, KNullDesC, KNullDesC); + + // Clean up the response buffer. + delete iResponseBuffer; + iResponseBuffer = NULL; + + return KErrNone; + } + + +// ----------------------------------------------------------------------------- +// CHttpHandler::CleanupDataSupplier +// +// Cleanup stack callback method to release a DataSupplier. +// ----------------------------------------------------------------------------- +// +void CHttpHandler::CleanupDataSupplier(TAny *aPtr) + { + MHTTPDataSupplier* supplier = static_cast(aPtr); + + // Release it + supplier->ReleaseData(); + } + + +// ----------------------------------------------------------------------------- +// CHttpHandler::GetContentTypeL +// +// Get the content-type and char-encoding from the response header. +// ----------------------------------------------------------------------------- +// +void CHttpHandler::GetContentTypeL(TDesC*& aContentType, TDesC*& aCharSet) + { + RStringF fieldName; + RStringF fieldParam; + THTTPHdrVal value; + + // Get the content-type. + fieldName = iStringPool.StringF(HTTP::EContentType, RHTTPSession::GetTable()); + if (iRespHeaders.GetField(fieldName, 0, value) == KErrNone) + { + aContentType = EscapeUtils::ConvertToUnicodeFromUtf8L(value.StrF().DesC()); + CleanupStack::PushL(aContentType); + } + + // Get the char-encoding. + fieldParam = iStringPool.StringF(HTTP::ECharset, RHTTPSession::GetTable()); + if (iRespHeaders.GetParam(fieldName, fieldParam, value) == KErrNone) + { + aCharSet = EscapeUtils::ConvertToUnicodeFromUtf8L(value.StrF().DesC()); + CleanupStack::PushL(aCharSet); + } + + if (aContentType == NULL) + { + aContentType = KNullDesC().AllocL(); + CleanupStack::PushL(aContentType); + } + + if (aCharSet == NULL) + { + aCharSet = KNullDesC().AllocL(); + CleanupStack::PushL(aCharSet); + } + + CleanupStack::Pop(2); + } + + +// ----------------------------------------------------------------------------- +// CHttpHandler::LoadComplete +// +// Passes the status code and responseBody to the observer. The observer +// adopts aResponseBody. +// ----------------------------------------------------------------------------- +// +void CHttpHandler::LoadCompleted(TInt aStatusCode, TDesC8* aResponseBody, + const TDesC& aContentType, const TDesC& aCharSet) + { + delete iTimer; + iTimer = NULL; + + RHTTPTransaction temp; + if (iTransaction != temp) + { + // Close the transaction. + iTransaction.Close(); + } + if (iIsConnectionObserver) + { + if(iHttpConnection) + { + iHttpConnection->SetObserver(NULL); + } + iIsConnectionObserver = EFalse; + } + + // Pass the buffer to the observer. + iObserver->LoadCompleted(aStatusCode, aResponseBody, aContentType, aCharSet); + + if (aStatusCode != KErrNone) + { + FEED_LOG1(_L("Feeds"), _L("Feeds_Errors.log"), + EFileLoggingModeAppend, _L("CHttpHandler::LoadCompleted: %d."), aStatusCode); + } + } + + +// ----------------------------------------------------------------------------- +// CHttpHandler::TimerCallback +// +// The timer's callback used to abort connections that stop responding. +// ----------------------------------------------------------------------------- +// +TInt CHttpHandler::TimerCallback(TAny* aPtr) + { + CHttpHandler* self = static_cast(aPtr); + TTime now; + + // Get the current time. + now.HomeTime(); + + // If the connection is inactive then delete the timer and cancel the load. + if ((self->iLastActivity + self->KTimerPeriod) < now) + { + delete self->iTimer; + self->iTimer = NULL; + + FEED_LOG(_L("Feeds"), _L("Feeds_Errors.log"), + EFileLoggingModeAppend, _L("CHttpHandler::TimerCallback. TIMEDOUT")); + + // Cancel the transaction. + self->iTransaction.Cancel(); + + // Notify the observer. + self->LoadCompleted(KErrTimedOut, NULL, KNullDesC, KNullDesC); + } + + return KErrNone; + }