browserutilities/feedsengine/FeedsServer/UrlHandler/src/HttpHandler.cpp
changeset 0 dd21522fd290
child 13 10e98eab6f85
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2 * Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  A class that fetches resources via HTTP 1.1.
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <EscapeUtils.h>
       
    20 #include <http.h>
       
    21 #include <http/mhttpdatasupplier.h>
       
    22 #include <HttpFilterCommonStringsAddition.h>
       
    23 
       
    24 #include "HttpConnection.h"
       
    25 #include "HttpHandler.h"
       
    26 #include "LeakTracker.h"
       
    27 #include "Logger.h"
       
    28 
       
    29 #include "CUserAgent.h"
       
    30 
       
    31 // -----------------------------------------------------------------------------
       
    32 // CHttpHandler::NewL
       
    33 //
       
    34 // Two-phased constructor.
       
    35 // -----------------------------------------------------------------------------
       
    36 //
       
    37 CHttpHandler* CHttpHandler::NewL(CHttpConnection& aHttpConnection)
       
    38     {
       
    39     CHttpHandler* self = new (ELeave) CHttpHandler(aHttpConnection);
       
    40     
       
    41     CleanupStack::PushL(self);
       
    42     self->ConstructL();
       
    43     CleanupStack::Pop();
       
    44 
       
    45     return self;
       
    46     }
       
    47 
       
    48         
       
    49 // -----------------------------------------------------------------------------
       
    50 // CHttpHandler::CHttpHandler
       
    51 // C++ default constructor can NOT contain any code, that
       
    52 // might leave.
       
    53 // -----------------------------------------------------------------------------
       
    54 //
       
    55 CHttpHandler::CHttpHandler(CHttpConnection& aHttpConnection):
       
    56         KTimerPeriod(40000000), iLeakTracker(CLeakTracker::EHttpHandler),
       
    57         iHttpConnection(&aHttpConnection), 
       
    58         iSession(aHttpConnection.Session()), iLastActivity(0), iStatusCode(KErrNone)
       
    59     {
       
    60     iTimerState.iFunction = TimerCallback;
       
    61     iTimerState.iPtr = static_cast<TAny*>(this);
       
    62     }
       
    63         
       
    64 
       
    65 // -----------------------------------------------------------------------------
       
    66 // CHttpHandler::ConstructL
       
    67 // Symbian 2nd phase constructor can leave.
       
    68 // -----------------------------------------------------------------------------
       
    69 //
       
    70 void CHttpHandler::ConstructL()
       
    71     {
       
    72     // Get the http connection.
       
    73     if (!iHttpConnection->IsConnected())
       
    74         {
       
    75         // Set this instance as the connection observer.
       
    76         
       
    77         // TODO: In 3.1 when multiple tasks are supported this needs to be
       
    78         //      changed to AddObserver as multiple tasks may need to be waken.
       
    79         iHttpConnection->SetObserver(this);
       
    80         iIsConnectionObserver = ETrue;
       
    81         }
       
    82 
       
    83     iTimer = CPeriodic::NewL(EPriorityHigh);
       
    84     
       
    85     iStringPool = iSession.StringPool();
       
    86     }        
       
    87 
       
    88 
       
    89 // -----------------------------------------------------------------------------
       
    90 // CHttpHandler::~CHttpHandler
       
    91 // Deconstructor.
       
    92 // -----------------------------------------------------------------------------
       
    93 //
       
    94 CHttpHandler::~CHttpHandler()
       
    95     {
       
    96     // If this happened to be the instances that is observing the connection 
       
    97     // then clear the connection's observer...
       
    98     if (iIsConnectionObserver)
       
    99         {
       
   100 	        if(iHttpConnection)
       
   101 	        {
       
   102 	        	iHttpConnection->SetObserver(NULL);	
       
   103 	        }
       
   104         
       
   105         }
       
   106 	RHTTPTransaction temp;
       
   107 	if (iTransaction != temp)
       
   108 	{
       
   109 		// Close the transaction.
       
   110 	    iTransaction.Close();	
       
   111 	}
       
   112     delete iResponseBuffer;    
       
   113     delete iTimer;
       
   114     }
       
   115 
       
   116 
       
   117 // -----------------------------------------------------------------------------
       
   118 // CHttpHandler::LoadUrl
       
   119 // 
       
   120 // Loads the given url -- asynchronously
       
   121 // -----------------------------------------------------------------------------
       
   122 //
       
   123 void CHttpHandler::LoadUrlL(const TDesC& aUrl, MLoadObserver& aObserver)
       
   124     {
       
   125     TUriParser8  uriParser;
       
   126     HBufC8*      url;
       
   127 
       
   128     // Set the observer.
       
   129     iObserver = &aObserver;
       
   130 
       
   131     // Parse the url.
       
   132     url = HBufC8::NewLC(aUrl.Length());
       
   133     url->Des().Copy(aUrl);
       
   134     User::LeaveIfError(uriParser.Parse(*url));
       
   135 
       
   136     // Create the transaction.
       
   137     iTransaction = iSession.OpenTransactionL(uriParser, *this,
       
   138 		iSession.StringPool().StringF(HTTP::EGET, RHTTPSession::GetTable()));
       
   139 
       
   140     // TODO: Set the headers if any.
       
   141 	//++PK Add UA header code
       
   142 	
       
   143 	iUserAgentHeader = iTransaction.Request().GetHeaderCollection();
       
   144 	
       
   145 	CUserAgent* tWebUtilsStandardUA = CUserAgent::NewL();
       
   146     CleanupStack::PushL(tWebUtilsStandardUA);
       
   147 	
       
   148 	HBufC8* tWebUtilsStandardUAHeaderValue = tWebUtilsStandardUA->UserAgentL();	
       
   149 	
       
   150 	RStringF tStringValue = iSession.StringPool().OpenFStringL(*tWebUtilsStandardUAHeaderValue);	
       
   151 	
       
   152 	THTTPHdrVal tHeaderValue( tStringValue );
       
   153 	
       
   154 	RStringF tStringUA = iSession.StringPool().StringF(HTTP::EUserAgent, RHTTPSession::GetTable());
       
   155 	
       
   156 	iUserAgentHeader.SetFieldL( tStringUA, tStringValue );
       
   157 	
       
   158 	//++PK
       
   159     // Submit the request.
       
   160 	iTransaction.SubmitL();
       
   161 
       
   162     // If the connection is available it is safe to tell to the observer
       
   163     // to display progress indicators (i.e. a wait-dialog).
       
   164     if (iHttpConnection->IsConnected())
       
   165         {
       
   166         iObserver->StartWait();
       
   167         
       
   168         // Start the inactive connection timer as well.
       
   169         iTimer->Start(KTimerPeriod, KTimerPeriod, iTimerState);
       
   170         iLastActivity.HomeTime();
       
   171         }
       
   172 
       
   173     CleanupStack::PopAndDestroy(tWebUtilsStandardUA);
       
   174     CleanupStack::PopAndDestroy(url);
       
   175     }
       
   176 
       
   177 
       
   178 // -----------------------------------------------------------------------------
       
   179 // CHttpHandler::ConnectionAvailable
       
   180 // 
       
   181 // Notifies the observer that the connection is available.
       
   182 // -----------------------------------------------------------------------------
       
   183 //
       
   184 void CHttpHandler::ConnectionAvailable()
       
   185     {
       
   186     // Now that the connection is available it is safe to tell to the observer
       
   187     // to display progress indicators (i.e. a wait-dialog).
       
   188     iObserver->StartWait();
       
   189 
       
   190     // Start the inactive connection timer.
       
   191     iTimer->Start(KTimerPeriod, KTimerPeriod, iTimerState);
       
   192     iLastActivity.HomeTime();
       
   193     }
       
   194 
       
   195 
       
   196 // -----------------------------------------------------------------------------
       
   197 // CHttpHandler::ConnectionFailed
       
   198 // 
       
   199 // Notifies the observer that the establishment of the connection failed.
       
   200 // -----------------------------------------------------------------------------
       
   201 //
       
   202 void CHttpHandler::ConnectionFailed(TInt aStatus)
       
   203     {
       
   204     // Cancel the transaction.
       
   205     iTransaction.Cancel();
       
   206 		aStatus = -aStatus;
       
   207     // Notify the observer.
       
   208     LoadCompleted(aStatus, NULL, KNullDesC, KNullDesC);  
       
   209     }
       
   210 
       
   211 
       
   212 // -----------------------------------------------------------------------------
       
   213 // CHttpHandler::MHFRunL
       
   214 // 
       
   215 // Called when the filter's registration conditions are satisfied for events that
       
   216 // occur on a transaction.
       
   217 // -----------------------------------------------------------------------------
       
   218 //
       
   219 void CHttpHandler::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
       
   220 	{
       
   221     // Some kind of connection activity occurred so update iLastActivity.
       
   222     iLastActivity.HomeTime();
       
   223 
       
   224 	switch (aEvent.iStatus)
       
   225 		{
       
   226 		case THTTPEvent::EGotResponseHeaders:
       
   227 			{
       
   228 			RHTTPResponse  resp = aTransaction.Response();
       
   229 
       
   230             // Get the headers
       
   231             iRespHeaders = resp.GetHeaderCollection();
       
   232 			}
       
   233 			break;
       
   234 
       
   235 		case THTTPEvent::EGotResponseBodyData:
       
   236 			{
       
   237 			MHTTPDataSupplier*  dataSupplier;
       
   238 			TPtrC8              ptr;
       
   239 
       
   240 			// Get the data.
       
   241             dataSupplier = aTransaction.Response().Body();
       
   242 			dataSupplier->GetNextDataPart(ptr);
       
   243             CleanupStack::PushL(TCleanupItem(&CleanupDataSupplier, dataSupplier));
       
   244 
       
   245 			// Append to iResponseBuffer
       
   246 			if (iResponseBuffer == NULL)
       
   247 				{
       
   248 				iResponseBuffer = ptr.AllocL();
       
   249 				}
       
   250 			else
       
   251 				{
       
   252 				iResponseBuffer = iResponseBuffer->ReAllocL(iResponseBuffer->Length() + ptr.Length());
       
   253 				iResponseBuffer->Des().Append(ptr);
       
   254 				}
       
   255 
       
   256 			// Release the body data.
       
   257             CleanupStack::PopAndDestroy(/*dataSupplier*/);
       
   258 			}
       
   259 			break;
       
   260 
       
   261 		case THTTPEvent::ESucceeded:
       
   262 			{
       
   263 			TDesC*   contentType = NULL;
       
   264             TDesC*   charSet = NULL;
       
   265             
       
   266             // Get the content-type and char-set.
       
   267             GetContentTypeL(contentType, charSet);
       
   268 
       
   269             // Pass the buffer to the observer.
       
   270 			LoadCompleted(KErrNone, iResponseBuffer, *contentType, *charSet);
       
   271             iResponseBuffer = NULL;
       
   272 
       
   273             delete contentType;
       
   274             contentType = NULL;
       
   275             delete charSet;
       
   276             charSet = NULL;
       
   277 			}
       
   278 			break;
       
   279 
       
   280         case THTTPEvent::EFailed:
       
   281         case THTTPEvent::EUnrecoverableError:
       
   282         	{
       
   283         	// Notify the observer.
       
   284         	RHTTPResponse  resp = aTransaction.Response();
       
   285         	TInt statusCode = resp.StatusCode();
       
   286         	if(iStatusCode == KErrNone)
       
   287         		{
       
   288         		iStatusCode = (statusCode + 20000); // Web server HTTP status code are lesser than -20000
       
   289         		}
       
   290         	if(iStatusCode == -(KErrNoMemory)) //KErrNoMemory is not HTTP error so it should be -ve
       
   291         		{
       
   292         		iStatusCode = KErrNoMemory;
       
   293         		}
       
   294             LoadCompleted( iStatusCode, NULL, KNullDesC, KNullDesC );  
       
   295 
       
   296             // Clean up the response buffer.
       
   297             delete iResponseBuffer;
       
   298             iResponseBuffer = NULL;
       
   299         	}
       
   300             break;
       
   301 
       
   302         default:
       
   303             FEED_LOG1(_L("Feeds"), _L("Feeds_Errors.log"), 
       
   304                     EFileLoggingModeAppend, _L("CHttpHandler::MHFRunL - Failure: default %d."), aEvent.iStatus);
       
   305             if(aEvent.iStatus < KErrNone)
       
   306             	{
       
   307             	// HTTP errors should always be +ve
       
   308             	iStatusCode = -(aEvent.iStatus); 
       
   309             	}
       
   310 			break;
       
   311 		}
       
   312 	}
       
   313 
       
   314 
       
   315 // -----------------------------------------------------------------------------
       
   316 // CHttpHandler::MHFRunError
       
   317 // 
       
   318 // Called when RunL leaves from a transaction event. This works in the same
       
   319 // way as CActve::RunError; return KErrNone if you have handled the error.
       
   320 // -----------------------------------------------------------------------------
       
   321 //
       
   322 TInt CHttpHandler::MHFRunError(TInt aError, RHTTPTransaction /*aTransaction*/, 
       
   323         const THTTPEvent& /*aEvent*/)
       
   324 	{
       
   325     FEED_LOG1(_L("Feeds"), _L("Feeds_Errors.log"), 
       
   326             EFileLoggingModeAppend, _L("CHttpHandler::MHFRunError: %d."), aError);
       
   327 
       
   328     // Notify the observer.
       
   329 	LoadCompleted(aError, NULL, KNullDesC, KNullDesC);
       
   330 
       
   331     // Clean up the response buffer.
       
   332     delete iResponseBuffer;
       
   333     iResponseBuffer = NULL;
       
   334 
       
   335     return KErrNone;
       
   336 	}
       
   337 
       
   338 
       
   339 // -----------------------------------------------------------------------------
       
   340 // CHttpHandler::CleanupDataSupplier
       
   341 // 
       
   342 // Cleanup stack callback method to release a DataSupplier.
       
   343 // -----------------------------------------------------------------------------
       
   344 //
       
   345 void CHttpHandler::CleanupDataSupplier(TAny *aPtr)
       
   346     {
       
   347     MHTTPDataSupplier*  supplier = static_cast<MHTTPDataSupplier*>(aPtr);
       
   348 
       
   349     // Release it
       
   350 	supplier->ReleaseData();
       
   351     }
       
   352 
       
   353 
       
   354 // -----------------------------------------------------------------------------
       
   355 // CHttpHandler::GetContentTypeL
       
   356 // 
       
   357 // Get the content-type and char-encoding from the response header.
       
   358 // -----------------------------------------------------------------------------
       
   359 //
       
   360 void CHttpHandler::GetContentTypeL(TDesC*& aContentType, TDesC*& aCharSet)
       
   361     {
       
   362     RStringF     fieldName;
       
   363     RStringF     fieldParam;
       
   364     THTTPHdrVal  value;
       
   365 
       
   366     // Get the content-type.
       
   367     fieldName = iStringPool.StringF(HTTP::EContentType, RHTTPSession::GetTable());
       
   368     if (iRespHeaders.GetField(fieldName, 0, value) == KErrNone)
       
   369         {
       
   370         aContentType = EscapeUtils::ConvertToUnicodeFromUtf8L(value.StrF().DesC());
       
   371         CleanupStack::PushL(aContentType);
       
   372         }
       
   373 
       
   374     // Get the char-encoding.
       
   375     fieldParam = iStringPool.StringF(HTTP::ECharset, RHTTPSession::GetTable());
       
   376     if (iRespHeaders.GetParam(fieldName, fieldParam, value) == KErrNone)
       
   377         {
       
   378         aCharSet = EscapeUtils::ConvertToUnicodeFromUtf8L(value.StrF().DesC());
       
   379         CleanupStack::PushL(aCharSet);
       
   380         }
       
   381 
       
   382     if (aContentType == NULL)
       
   383         {
       
   384         aContentType = KNullDesC().AllocL();
       
   385         CleanupStack::PushL(aContentType);
       
   386         }
       
   387 
       
   388     if (aCharSet == NULL)
       
   389         {
       
   390         aCharSet = KNullDesC().AllocL();
       
   391         CleanupStack::PushL(aCharSet);
       
   392         }
       
   393 
       
   394     CleanupStack::Pop(2);
       
   395     }
       
   396 
       
   397 
       
   398 // -----------------------------------------------------------------------------
       
   399 // CHttpHandler::LoadComplete
       
   400 // 
       
   401 // Passes the status code and responseBody to the observer.  The observer
       
   402 // adopts aResponseBody.
       
   403 // -----------------------------------------------------------------------------
       
   404 //
       
   405 void CHttpHandler::LoadCompleted(TInt aStatusCode, TDesC8* aResponseBody,
       
   406         const TDesC& aContentType, const TDesC& aCharSet)
       
   407     {
       
   408     delete iTimer;
       
   409     iTimer = NULL;
       
   410 
       
   411     RHTTPTransaction temp;
       
   412     if (iTransaction != temp)
       
   413         {
       
   414 		    // Close the transaction.
       
   415         iTransaction.Close();	
       
   416         }
       
   417     if (iIsConnectionObserver)
       
   418         {
       
   419         if(iHttpConnection)
       
   420             {
       
   421        	    iHttpConnection->SetObserver(NULL);	
       
   422             }
       
   423         iIsConnectionObserver = EFalse;
       
   424         }
       
   425 
       
   426     // Pass the buffer to the observer.
       
   427     iObserver->LoadCompleted(aStatusCode, aResponseBody, aContentType, aCharSet);
       
   428 
       
   429     if (aStatusCode != KErrNone)
       
   430         {
       
   431         FEED_LOG1(_L("Feeds"), _L("Feeds_Errors.log"), 
       
   432                 EFileLoggingModeAppend, _L("CHttpHandler::LoadCompleted: %d."), aStatusCode);
       
   433         }
       
   434     }
       
   435 
       
   436 
       
   437 // -----------------------------------------------------------------------------
       
   438 // CHttpHandler::TimerCallback
       
   439 // 
       
   440 // The timer's callback used to abort connections that stop responding.
       
   441 // -----------------------------------------------------------------------------
       
   442 //
       
   443 TInt CHttpHandler::TimerCallback(TAny* aPtr)
       
   444     {
       
   445     CHttpHandler*  self = static_cast<CHttpHandler*>(aPtr);
       
   446     TTime          now;
       
   447 
       
   448     // Get the current time.
       
   449     now.HomeTime();
       
   450 
       
   451     // If the connection is inactive then delete the timer and cancel the load.
       
   452     if ((self->iLastActivity + self->KTimerPeriod) < now)
       
   453         {
       
   454         delete self->iTimer;
       
   455         self->iTimer = NULL;
       
   456 
       
   457         FEED_LOG(_L("Feeds"), _L("Feeds_Errors.log"), 
       
   458                 EFileLoggingModeAppend, _L("CHttpHandler::TimerCallback. TIMEDOUT"));
       
   459 
       
   460         // Cancel the transaction.
       
   461         self->iTransaction.Cancel();
       
   462 
       
   463         // Notify the observer.
       
   464         self->LoadCompleted(KErrTimedOut, NULL, KNullDesC, KNullDesC);  
       
   465         }
       
   466 
       
   467     return KErrNone;
       
   468     }