|
1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // @file |
|
15 // @internalComponent |
|
16 // |
|
17 // |
|
18 |
|
19 |
|
20 // System includes |
|
21 #include <es_sock.h> |
|
22 |
|
23 |
|
24 #include <http/thttptable.h> |
|
25 #include <httpstringconstants.h> |
|
26 #include <httperr.h> |
|
27 #include <utf.h> |
|
28 #include <inetprottextutils.h> |
|
29 #include <upnp/tupnptable.h> |
|
30 |
|
31 // Local includes |
|
32 #include "upnpserverconstants.h" |
|
33 #include "upnplog.h" |
|
34 #include "chttpclienthandler.h" |
|
35 #include "upnpmemoryutils.h" |
|
36 |
|
37 |
|
38 const TUint KInactivityTimeOutVal = 60000000; // 60secs, DLNA Requirements [7.2.8.7] |
|
39 |
|
40 __FLOG_STMT(_LIT8(KComponent,"Flow");) |
|
41 |
|
42 // |
|
43 CHTTPClientTransaction* CHTTPClientTransaction::NewL ( CHeaderCodec& aCodec, RStringPool& aStringPool, TNodeCtxId aNodeCtxId ) |
|
44 { |
|
45 CHTTPClientTransaction* self = new ( ELeave ) CHTTPClientTransaction ( aNodeCtxId ); |
|
46 CleanupStack::PushL ( self ); |
|
47 self->ConstructL ( aCodec, aStringPool ); |
|
48 CleanupStack::Pop ( self ); |
|
49 return self; |
|
50 } |
|
51 |
|
52 CHTTPClientTransaction::CHTTPClientTransaction ( TNodeCtxId aNodeCtxId ) |
|
53 :CTransaction ( ), iNodeCtxId ( aNodeCtxId ), iComposingStarted ( EFalse ) |
|
54 { |
|
55 } |
|
56 |
|
57 CHTTPClientTransaction::~CHTTPClientTransaction ( ) |
|
58 { |
|
59 RemoveAllBodyParts ( ); |
|
60 } |
|
61 |
|
62 |
|
63 // |
|
64 CHTTPClientHandler* CHTTPClientHandler::NewL ( MHttpEventObserver& aObserver, CChunkManager* aChunkMgr, TSockAddr* aAddr ) |
|
65 { |
|
66 CHTTPClientHandler* self = new ( ELeave ) CHTTPClientHandler ( aObserver, aChunkMgr, aAddr ); |
|
67 CleanupStack::PushL ( self ); |
|
68 self->ConstructL ( ); |
|
69 CleanupStack::Pop ( self ); |
|
70 return self; |
|
71 } |
|
72 |
|
73 CHTTPClientHandler::CHTTPClientHandler ( MHttpEventObserver& aObserver, CChunkManager* aChunkMgr, TSockAddr* aAddr ) |
|
74 : CProtocolHandler ( ), iObserver ( aObserver ) |
|
75 { |
|
76 if ( aAddr ) |
|
77 iRemoteAddr = *aAddr; |
|
78 iFlags = 0; |
|
79 iFirstTrans = ETrue; |
|
80 SetSocketIdle ( ); |
|
81 iAllocator.SetChunkManager(aChunkMgr); |
|
82 SetComposerIdle ( ); |
|
83 SetParserIdle ( ); |
|
84 SetReq100Continue ( EFalse ); |
|
85 } |
|
86 |
|
87 void CHTTPClientHandler::ConstructL ( ) |
|
88 { |
|
89 CProtocolHandler::ConstructL (); |
|
90 iComposer = CUpnpRequestComposer::NewL ( *this ); |
|
91 iParser = CUpnpResponseParser::NewL ( *this ); |
|
92 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("Created CHTTPClientHandler"))); |
|
93 } |
|
94 |
|
95 CHTTPClientHandler::~CHTTPClientHandler ( ) |
|
96 { |
|
97 CloseLink ( ); |
|
98 delete iComposer; |
|
99 delete iParser; |
|
100 if ( !iExcessData.IsEmpty() ) |
|
101 iExcessData.Free ( ); |
|
102 |
|
103 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("Deleted CHTTPClientHandler"))); |
|
104 } |
|
105 |
|
106 CTransactionWrapper* CHTTPClientHandler::GetTransactionWrapperL ( ) |
|
107 { |
|
108 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::GetTransactionWrapperL"))); |
|
109 return new (ELeave ) CTransactionWrapper ( iTransactions ); |
|
110 } |
|
111 |
|
112 void CHTTPClientHandler::SetConnectionInfo ( TSockAddr& aAddr ) |
|
113 { |
|
114 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::SetConnectionInfo"))); |
|
115 iRemoteAddr = aAddr; |
|
116 if ( !SocketIdle ( ) ) |
|
117 { |
|
118 // socket is connected & there is no network traffic. This happens only when pipelining is enabled |
|
119 // Flow can call this API inorder to reuse. so connection is no longer useful, close it. |
|
120 CloseLink ( ); |
|
121 } |
|
122 } |
|
123 |
|
124 void CHTTPClientHandler::SubmitTransaction ( CTransaction* aTransaction ) |
|
125 { |
|
126 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::SubmitTransaction"))); |
|
127 TInt pos = FindTransaction ( aTransaction ); |
|
128 TInt err = KErrNone; |
|
129 |
|
130 if ( KErrNotFound == pos ) |
|
131 { |
|
132 TRAP_IGNORE ( iTransactions.Append ( aTransaction ) ); |
|
133 } |
|
134 |
|
135 // Set data supplier for body |
|
136 CRequest* request = aTransaction->Request ( ); |
|
137 request->AddBody ( this ); |
|
138 |
|
139 err = OpenLink ( ); |
|
140 if ( err != KErrNone ) // memory failures |
|
141 { |
|
142 NotifyPendingTransactions ( err ); |
|
143 CloseLink ( ); |
|
144 } |
|
145 else |
|
146 { |
|
147 ProcessPendingTransactions ( iTransactions.Count () - 1 ); |
|
148 iTimer->StopTimer (); |
|
149 } |
|
150 } |
|
151 |
|
152 |
|
153 void CHTTPClientHandler::NotifyNewRequestBodyData ( CTransaction* aTransaction, RMBufChain& aData ) |
|
154 { |
|
155 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::NotifyNewRequestBodyData"))); |
|
156 |
|
157 // CheckToNotifyNewBodyPart |
|
158 CHTTPClientTransaction* ctrans = static_cast<CHTTPClientTransaction*> ( CurrentTransaction ( ) ); |
|
159 TInt availableBufCount = ctrans->BodyParts( ).NumBufs ( ); |
|
160 TInt currentPartId = ctrans->RequestPartIdx( ); |
|
161 |
|
162 if ( currentPartId == availableBufCount ) |
|
163 { |
|
164 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("New Body part is added"))); |
|
165 |
|
166 // all available parts are send, and a new one is just added |
|
167 // notify waiting upnp message composer |
|
168 iComposer->NotifyNewBodyData( ); |
|
169 } |
|
170 |
|
171 aTransaction->AddBodyPart( aData ); |
|
172 } |
|
173 |
|
174 void CHTTPClientHandler::CancelTransaction ( CTransaction* aTransaction ) |
|
175 { |
|
176 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CancelTransaction"))); |
|
177 TInt reqPos = FindTransaction ( aTransaction ); |
|
178 __ASSERT_DEBUG ( reqPos != KErrNotFound, User::Invariant ( ) ); |
|
179 |
|
180 // Cleanup response headers |
|
181 aTransaction->Response( )->Handle( ).GetHeaderCollection ( ).RemoveAllFields ( ); |
|
182 RemoveTransaction ( reqPos ); |
|
183 |
|
184 CHTTPClientTransaction* trans = static_cast<CHTTPClientTransaction*>( aTransaction ); |
|
185 if ( trans->ComposingStarted () ) |
|
186 { |
|
187 ResetTransactions (); // until request positions. |
|
188 iComposer->ResetComposer (); |
|
189 iParser->ResetParser (); |
|
190 |
|
191 ReOpenLink (); |
|
192 } |
|
193 } |
|
194 |
|
195 CTransaction* CHTTPClientHandler::CurrentTransaction ( ) const |
|
196 { |
|
197 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CurrentTransaction"))); |
|
198 __ASSERT_DEBUG ( iTransactions.Count ( ) > 0, User::Invariant ( ) ); |
|
199 return iTransactions[0]; |
|
200 } |
|
201 |
|
202 void CHTTPClientHandler::ProcessPendingTransactions ( TInt aNextTransIdx ) |
|
203 { |
|
204 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::ProcessPendingTransactions"))); |
|
205 if ( HasPendingTransactions () && CanPipeLine () ) |
|
206 { |
|
207 StartComposer ( iTransactions[aNextTransIdx] ); |
|
208 } |
|
209 } |
|
210 |
|
211 TInt CHTTPClientHandler::OpenLink ( ) |
|
212 { |
|
213 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::OpenLink"))); |
|
214 TInt err = KErrNone; |
|
215 |
|
216 if ( HasPendingTransactions ( ) && SocketIdle ( ) ) |
|
217 { |
|
218 TRAP ( err, OpenSocketL ( KAfInet, KSockStream, KProtocolInetTcp ) ); |
|
219 if ( err != KErrNone ) |
|
220 { |
|
221 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::OpenLink - Returned with error %d"), err)); |
|
222 return err; |
|
223 } |
|
224 ResetSocketIdle ( ); |
|
225 } |
|
226 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::OpenLink - Returned with error %d"), err)); |
|
227 return err; |
|
228 } |
|
229 |
|
230 void CHTTPClientHandler::OpenSocketL ( TUint aAddrFamily, TUint aSockType, TUint aProtocol ) |
|
231 { |
|
232 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::OpenSocketL"))); |
|
233 if ( NULL == iSocketOpener ) |
|
234 { |
|
235 iSocketOpener = CSocketOpener::NewL ( *this ); |
|
236 } |
|
237 iSocketOpener->MakeSocket ( aAddrFamily, aSockType, aProtocol ); |
|
238 } |
|
239 |
|
240 void CHTTPClientHandler::MakeConnection ( ) |
|
241 { |
|
242 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::MakeConnection"))); |
|
243 iSocketHandler.Connect ( iRemoteAddr ); |
|
244 } |
|
245 |
|
246 void CHTTPClientHandler::StartComposer ( CTransaction* aTransaction ) |
|
247 { |
|
248 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::StartComposer"))); |
|
249 if ( ComposerIdle ( ) ) |
|
250 { |
|
251 ResetComposerIdle ( ); |
|
252 |
|
253 CHTTPClientTransaction* ctrans = static_cast<CHTTPClientTransaction*>( aTransaction ); |
|
254 |
|
255 SetReq100Continue ( CheckFor100ContinueHeader ( * ( aTransaction->Request () ) ) ); |
|
256 ctrans->SetComposingStarted ( ETrue ); |
|
257 iComposer->ComposeRequest ( aTransaction->Request () ); |
|
258 } |
|
259 } |
|
260 |
|
261 void CHTTPClientHandler::StartParser ( CTransaction* aTransaction, RMemChunk& aData ) |
|
262 { |
|
263 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::StartParser"))); |
|
264 |
|
265 ResetParserIdle ( ); |
|
266 |
|
267 iParser->ParseResponse ( aData, aTransaction->Response ( ) ); |
|
268 } |
|
269 |
|
270 void CHTTPClientHandler::CloseLink ( ) |
|
271 { |
|
272 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CloseLink"))); |
|
273 if ( iSocketOpener ) |
|
274 { |
|
275 delete iSocketOpener; |
|
276 iSocketOpener = NULL; |
|
277 } |
|
278 |
|
279 // Cancel all socket operations |
|
280 iSocketHandler.CancelAll ( ); |
|
281 iSocket.Close ( ); |
|
282 |
|
283 iFlags = 0; |
|
284 iFirstTrans = ETrue; |
|
285 SetSocketIdle ( ); |
|
286 SetComposerIdle ( ); |
|
287 SetParserIdle (); |
|
288 SetReq100Continue ( EFalse ); |
|
289 } |
|
290 |
|
291 TBool CHTTPClientHandler::CheckForConnectionPersistence ( ) |
|
292 { |
|
293 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CheckForConnectionPersistence"))); |
|
294 CResponse* response = CurrentTransaction( )->Response ( ); |
|
295 TVersion version = response->Version( ); |
|
296 |
|
297 if ( version.iMajor == 1 && version.iMinor == 0 ) |
|
298 { // non-persistent |
|
299 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CheckForConnectionPersistence - HTTP v1.0 in use. Connection is non-persistant"))); |
|
300 return EFalse; |
|
301 } |
|
302 |
|
303 const RStringPool& strP = response->StringPool ( ); |
|
304 RStringF name = strP.StringF ( HTTP::EConnection, THTTPTable::Table() ); |
|
305 RHTTPHeaders headers = response->Handle( ).GetHeaderCollection ( ); |
|
306 THTTPHdrVal value; |
|
307 |
|
308 if ( version.iMajor == 1 && version.iMinor == 1 ) |
|
309 { |
|
310 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CheckForConnectionPersistence - HTTP v1.1 in use"))); |
|
311 // Check for Connection: close header |
|
312 if ( headers.GetField ( name, 0, value ) == KErrNone && |
|
313 value.Type ( ) == THTTPHdrVal::KStrFVal && |
|
314 value.StrF ( ).Index ( THTTPTable::Table() ) == HTTP::EClose ) |
|
315 { |
|
316 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CheckForConnectionPersistence - Connection: Close found"))); |
|
317 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CheckForConnectionPersistence - Connection is non-persistant"))); |
|
318 // Connection header has "close" value, non-persistent |
|
319 return EFalse; |
|
320 } |
|
321 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CheckForConnectionPersistence - Connection is persistant"))); |
|
322 // connection is non-persistent |
|
323 return ETrue; |
|
324 } |
|
325 // else HTTP 1.x |
|
326 if ( headers.GetField ( name, 0, value ) == KErrNone && |
|
327 value.Type ( ) == THTTPHdrVal::KStrFVal && |
|
328 value.StrF ( ).Index ( THTTPTable::Table() ) == HTTP::EKeepAlive ) |
|
329 { |
|
330 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CheckForConnectionPersistence - HTTP v1.x in use"))); |
|
331 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CheckForConnectionPersistence - Connection:: Keep-Alive found"))); |
|
332 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CheckForConnectionPersistence - Connection is persistant"))); |
|
333 // Connection header has "keep-alive" value, persistent |
|
334 return ETrue; |
|
335 } |
|
336 |
|
337 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CheckForConnectionPersistence - Connection is non-persistant"))); |
|
338 // non-persistent |
|
339 return EFalse; |
|
340 } |
|
341 |
|
342 TBool CHTTPClientHandler::CheckFor100ContinueHeader ( CRequest& aRequest ) |
|
343 { |
|
344 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::CheckFor100ContinueHeader"))); |
|
345 |
|
346 TBool value = EFalse; |
|
347 if ( aRequest.Method ( ).Index ( THTTPTable::Table() ) == HTTP::EPOST |
|
348 || aRequest.Method ( ).Index ( TUPnPTable::Table() ) == UPnP::EMPost ) |
|
349 { |
|
350 const RStringPool& strP = aRequest.StringPool ( ); |
|
351 |
|
352 // Check for Except: 100-continue header |
|
353 RStringF name = strP.StringF ( HTTP::EExpect, THTTPTable::Table() ); |
|
354 THTTPHdrVal hdrValue; |
|
355 RHTTPHeaders headers = aRequest.Handle( ).GetHeaderCollection ( ); |
|
356 |
|
357 if ( headers.GetField ( name, 0, hdrValue ) == KErrNone && hdrValue.Type ( ) == THTTPHdrVal::KStrFVal ) |
|
358 { |
|
359 // what's the value? |
|
360 if( hdrValue.StrF ( ).Index ( THTTPTable::Table() ) == HTTP::E100Continue ) |
|
361 { |
|
362 // Expect header has a value of 100-continue |
|
363 value = ETrue; |
|
364 } |
|
365 } |
|
366 } |
|
367 |
|
368 return value; |
|
369 } |
|
370 |
|
371 void CHTTPClientHandler::NotifyPendingTransactions ( TInt aError ) |
|
372 { |
|
373 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::NotifyPendingTransactions"))); |
|
374 TInt ii = iTransactions.Count ( ); |
|
375 |
|
376 while ( ii > 0 ) |
|
377 { |
|
378 // Notify waiting transaction of the error |
|
379 THTTPEvent event ( aError ); |
|
380 iObserver.OnHttpEvent ( iTransactions[--ii], event ); |
|
381 } |
|
382 |
|
383 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::NotifyPendingTransactions - Pending transaction queue has been reset"))); |
|
384 // Reset the pending transaction queue. |
|
385 iTransactions.Reset ( ); |
|
386 } |
|
387 |
|
388 |
|
389 // MSocketHandler |
|
390 void CHTTPClientHandler::OpenComplete ( RInternalSocket& aSocket ) |
|
391 { |
|
392 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::OpenComplete"))); |
|
393 iSocket = aSocket; |
|
394 iSocketHandler.Attach ( aSocket ); |
|
395 |
|
396 if ( HasPendingTransactions ( ) ) |
|
397 { |
|
398 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::OpenComplete - Pending transactions found"))); |
|
399 MakeConnection ( ); |
|
400 } |
|
401 else |
|
402 { |
|
403 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::OpenComplete - Found no pending transactions"))); |
|
404 CloseLink ( ); |
|
405 } |
|
406 } |
|
407 |
|
408 void CHTTPClientHandler::ConnectComplete ( ) |
|
409 { |
|
410 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::ConnectComplete"))); |
|
411 if ( HasPendingTransactions ( ) ) |
|
412 { |
|
413 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::ConnectComplete - Pending transactions found"))); |
|
414 StartComposer ( CurrentTransaction ( ) ); |
|
415 } |
|
416 else |
|
417 { |
|
418 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::ConnectComplete - Found no pending transactions"))); |
|
419 CloseLink ( ); |
|
420 } |
|
421 } |
|
422 |
|
423 void CHTTPClientHandler::SendComplete ( TInt /*aLength*/ ) |
|
424 { |
|
425 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::SendComplete"))); |
|
426 // Handle 100-continue |
|
427 if ( Request100Continue () ) |
|
428 { |
|
429 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::SendComplete - Expect: 100-Continue found"))); |
|
430 |
|
431 // headers sent to server. before sending body, read socket for 100-continue response |
|
432 iSocketHandler.Recv (); |
|
433 SetReadTriggered (); |
|
434 |
|
435 SetReq100Continue ( EFalse ); |
|
436 } |
|
437 else |
|
438 { |
|
439 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::SendComplete - Expect: 100-Continue not found"))); |
|
440 |
|
441 iComposer->RequestDataSent ( ); // enables composer to release send data chain |
|
442 } |
|
443 } |
|
444 |
|
445 void CHTTPClientHandler::RecvComplete ( RMBufChain& aData ) |
|
446 { |
|
447 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::RecvComplete"))); |
|
448 if ( HasPendingTransactions () ) |
|
449 {// Parser should be in Idle state, else something is happening seriously wrong. |
|
450 |
|
451 RMemChunk memChunk; |
|
452 TUPnPMemoryUtils::CreateMemChunk(memChunk, aData, iAllocator); |
|
453 |
|
454 StartParser ( CurrentTransaction ( ), memChunk ); |
|
455 } |
|
456 |
|
457 //parser takes ownership of aData, so it can be cleaned-up |
|
458 aData.Free ( ); |
|
459 |
|
460 ResetReadTriggered ( ); |
|
461 } |
|
462 |
|
463 void CHTTPClientHandler::Error ( TOperation aOperation, TInt aError ) |
|
464 { |
|
465 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::Error"))); |
|
466 switch ( aOperation ) |
|
467 { |
|
468 case EOpenByProtocol: |
|
469 case EConnect: |
|
470 { |
|
471 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::Error - TOperation::EConnect"))); |
|
472 CloseLink ( ); |
|
473 NotifyPendingTransactions ( aError ); |
|
474 } |
|
475 break; |
|
476 |
|
477 case EMBufSend: |
|
478 iComposer->DataSentFailed (); |
|
479 case ERecv: |
|
480 { |
|
481 LOG(ESockLogExternal::Printf(KSubsysHttpClntTrans, KComponent, _L8("CHTTPClientHandler::Error - TOperation::ERecv"))); |
|
482 |
|
483 iComposer->ResetComposer (); |
|
484 iParser->ResetParser (); |
|
485 CloseLink ( ); |
|
486 |
|
487 if ( aError == KErrEof || aError == KErrCancel ) |
|
488 { |
|
489 ResetTransactions (); |
|
490 ReOpenLink (); |
|
491 } |
|
492 else |
|
493 { |
|
494 NotifyPendingTransactions ( aError ); |
|
495 } |
|
496 } |
|
497 break; |
|
498 |
|
499 default: |
|
500 __ASSERT_DEBUG ( 0, User::Invariant ( ) ); |
|
501 break; |
|
502 } |
|
503 } |
|
504 |
|
505 void CHTTPClientHandler::ResetTransactions () |
|
506 { |
|
507 for ( TInt i = 0; i < iTransactions.Count (); i++ ) |
|
508 { |
|
509 CHTTPClientTransaction* ctrans = static_cast<CHTTPClientTransaction*>( iTransactions[i] ); |
|
510 ctrans->ResetRequestPart (); |
|
511 ctrans->SetComposingStarted ( EFalse ); |
|
512 } |
|
513 } |
|
514 |
|
515 // MComposerObserver |
|
516 void CHTTPClientHandler::MessageDataReadyL ( RBuf8& aData ) |
|
517 { |
|
518 RMBufChain data; //Need to Check |
|
519 data.CreateL(aData); |
|
520 iSocketHandler.Send ( data ); |
|
521 SetWriteTriggered ( ); |
|
522 } |
|
523 |
|
524 void CHTTPClientHandler::ComposingConcluded ( ) |
|
525 { |
|
526 if ( !ReadTriggered ( ) ) |
|
527 { |
|
528 iSocketHandler.Recv ( ); // should call this before compose conclude for 100-continue |
|
529 SetReadTriggered ( ); |
|
530 } |
|
531 |
|
532 TInt nextTransId = FindTransaction ( & (iComposer->Request () ) ) + 1; |
|
533 |
|
534 ResetWriteTriggered ( ); |
|
535 SetComposerIdle ( ); |
|
536 iComposer->ResetComposer (); |
|
537 |
|
538 if ( nextTransId < iTransactions.Count () ) |
|
539 { |
|
540 ProcessPendingTransactions ( nextTransId ); |
|
541 } |
|
542 } |
|
543 |
|
544 void CHTTPClientHandler::ComposerError ( TInt aError ) |
|
545 { |
|
546 // Report there is an Error in the transaction(iCurrentRequest) |
|
547 // and do cleanup, process next transaction or close link |
|
548 TInt pos = FindTransaction ( &(iComposer->Request( )) ); |
|
549 __ASSERT_DEBUG ( pos != KErrNotFound, User::Invariant ( ) ); |
|
550 |
|
551 THTTPEvent event ( aError ); |
|
552 iObserver.OnHttpEvent ( iTransactions[pos], event ); |
|
553 RemoveTransaction ( pos ); |
|
554 |
|
555 SetComposerIdle (); |
|
556 iComposer->ResetComposer (); |
|
557 |
|
558 if ( WriteTriggered ( ) ) // request data is half sent to server. |
|
559 { |
|
560 ReOpenLink (); |
|
561 return; |
|
562 } |
|
563 |
|
564 if ( iTransactions[pos] != NULL ) // no request data is sent, process next transaction |
|
565 { |
|
566 StartComposer ( iTransactions[pos] ); |
|
567 } |
|
568 } |
|
569 |
|
570 |
|
571 // MParserObserver |
|
572 void CHTTPClientHandler::GotHeaders ( ) |
|
573 { |
|
574 // check for connection persistance |
|
575 if ( CheckForConnectionPersistence ( ) ) |
|
576 { |
|
577 EnablePipeLining (); |
|
578 } |
|
579 else |
|
580 { |
|
581 DisablePipeLining ( ); |
|
582 } |
|
583 |
|
584 // 100-continue status is not notified to clients, but resume composer to send body |
|
585 CResponse* response = CurrentTransaction( )->Response( ); |
|
586 if ( response->Status ( ) == HTTPStatus::EContinue ) |
|
587 { |
|
588 iComposer->RequestDataSent ( ); // enables composer to send first body part. |
|
589 } |
|
590 else |
|
591 { |
|
592 THTTPEvent event ( THTTPEvent::EGotResponseHeaders ); |
|
593 iObserver.OnHttpEvent ( CurrentTransaction ( ), event); |
|
594 } |
|
595 } |
|
596 |
|
597 void CHTTPClientHandler::GotBodyData ( ) |
|
598 { |
|
599 THTTPEvent event ( THTTPEvent::EGotResponseBodyData ); |
|
600 iObserver.OnHttpEvent ( CurrentTransaction ( ), event ); |
|
601 } |
|
602 |
|
603 void CHTTPClientHandler::DataParsed ( ) |
|
604 { |
|
605 if ( HasPendingTransactions ( ) && !ReadTriggered ( ) ) |
|
606 { |
|
607 iSocketHandler.Recv ( ); |
|
608 SetReadTriggered ( ); |
|
609 } |
|
610 |
|
611 if ( ParserIdle () ) |
|
612 { |
|
613 iParser->ResetParser (); |
|
614 } |
|
615 |
|
616 if ( !iExcessData.IsEmpty ( ) ) |
|
617 { |
|
618 StartParser ( CurrentTransaction ( ), iExcessData ); |
|
619 iExcessData.Free ( ); |
|
620 } |
|
621 } |
|
622 |
|
623 void CHTTPClientHandler::ParsingComplete ( RMemChunk& aExcessData ) |
|
624 { |
|
625 // notify the observer response complete and cleanup it. |
|
626 CTransaction* ctrans = CurrentTransaction ( ); |
|
627 RemoveTransaction ( 0 ); |
|
628 THTTPEvent event ( THTTPEvent::EResponseComplete ); |
|
629 iObserver.OnHttpEvent ( ctrans, event ); |
|
630 |
|
631 SetParserIdle ( ); |
|
632 |
|
633 //check for pipelining |
|
634 if ( !CanPipeLine ( ) ) |
|
635 { |
|
636 // Pipelining is diabled and discard the junk data received |
|
637 aExcessData.Free (); |
|
638 ReOpenLink (); |
|
639 } |
|
640 else |
|
641 { |
|
642 if ( iFirstTrans ) // Note, when pipelining is enabled and |
|
643 // first transaction is completed, composer is waiting to start next transaction |
|
644 { |
|
645 iFirstTrans = EFalse; |
|
646 ProcessPendingTransactions (); |
|
647 } |
|
648 if ( HasPendingTransactions ( ) ) |
|
649 { |
|
650 // PipeLining is enabled so next transaction response is received, start parser |
|
651 iExcessData.Assign ( aExcessData ); |
|
652 } |
|
653 else |
|
654 { |
|
655 aExcessData.Free (); |
|
656 iTimer->StartTimer ( KInactivityTimeOutVal ); |
|
657 } |
|
658 } |
|
659 } |
|
660 |
|
661 void CHTTPClientHandler::ParserError ( TInt aError ) |
|
662 { |
|
663 // Report there is an Error in the transaction(0) |
|
664 THTTPEvent event ( aError ); |
|
665 iObserver.OnHttpEvent ( CurrentTransaction ( ), event ); |
|
666 RemoveTransaction ( 0 ); |
|
667 |
|
668 iParser->ResetParser (); |
|
669 ReOpenLink (); |
|
670 } |
|
671 |
|
672 void CHTTPClientHandler::RemoveTransaction ( TInt aPos ) |
|
673 { |
|
674 if ( aPos < iTransactions.Count () ) |
|
675 { |
|
676 iTransactions.Remove ( aPos ); |
|
677 } |
|
678 } |
|
679 |
|
680 void CHTTPClientHandler::ReOpenLink ( ) |
|
681 { |
|
682 CloseLink ( ); |
|
683 TInt err = OpenLink ( ); |
|
684 if ( err != KErrNone ) |
|
685 { |
|
686 NotifyPendingTransactions ( err ); |
|
687 CloseLink ( ); |
|
688 } |
|
689 } |
|
690 |
|
691 // From MUPnPTimerObserver |
|
692 void CHTTPClientHandler::TimeOut () |
|
693 { |
|
694 CloseLink (); |
|
695 } |
|
696 |
|
697 // From MHttpDataSupplier |
|
698 TBool CHTTPClientHandler::GetNextDataPart ( TPtrC8& aDataPart ) |
|
699 { |
|
700 CHTTPClientTransaction* ctrans = static_cast<CHTTPClientTransaction*> ( CurrentTransaction ( ) ); |
|
701 ctrans->GetBodyPart( aDataPart ); |
|
702 return ctrans->IsLastBodyPart( ); |
|
703 } |
|
704 |
|
705 void CHTTPClientHandler::ReleaseData ( ) |
|
706 { |
|
707 CHTTPClientTransaction* ctrans = static_cast<CHTTPClientTransaction*> ( CurrentTransaction ( ) ); |
|
708 ctrans->RemoveBodyPart( ); |
|
709 |
|
710 // Note! No need for checking NumBufs will crash if Empty, since removeBodyPart |
|
711 // will just increment the requestPartIdx |
|
712 |
|
713 // Call NotifyNewBodyData only if currentPartIdx != available MBuf |
|
714 TInt availableBufCount = ctrans->BodyParts( ).NumBufs ( ); |
|
715 TInt currentPartId = ctrans->RequestPartIdx( ); |
|
716 |
|
717 if ( currentPartId != availableBufCount ) |
|
718 { |
|
719 iComposer->NotifyNewBodyData( ); |
|
720 } |
|
721 else |
|
722 { |
|
723 // ..nothing to do, http message composer should say composing is concluded |
|
724 // or it waits for more data, which should be triggered by clientflow |
|
725 } |
|
726 } |
|
727 |
|
728 TInt CHTTPClientHandler::OverallDataSize ( ) |
|
729 { |
|
730 CHTTPClientTransaction* ctrans = static_cast<CHTTPClientTransaction*> ( CurrentTransaction ( ) ); |
|
731 |
|
732 // field or Content-Length |
|
733 TInt dataSize = MHttpMessageParserObserver::ENoBody; |
|
734 // Check is there a Content-Length field? |
|
735 CRequest* request = ctrans->Request ( ); |
|
736 RStringF contentLength = request->StringPool ( ).StringF ( HTTP::EContentLength, THTTPTable::Table() ); |
|
737 THTTPHdrVal value; |
|
738 TInt err = request->Handle( ).GetHeaderCollection ( ).GetField ( contentLength, 0, value ); |
|
739 if ( err == KErrNone ) |
|
740 { |
|
741 dataSize = value.Int ( ); |
|
742 } |
|
743 return dataSize; |
|
744 } |