|
1 /** @file |
|
2 * Copyright (c) 2008 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 "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: Definition of the CUpnpHttpMessageSender class |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <upnphttpmessage.h> |
|
20 #include <upnplist.h> |
|
21 #include <upnpcons.h> |
|
22 #include <upnpstring.h> |
|
23 |
|
24 #include "upnphttpmessagesender.h" |
|
25 #include "upnphttpmessagesenderowner.h" |
|
26 #include "upnphttptransaction.h" |
|
27 |
|
28 #ifdef _DEBUG |
|
29 #define KLogFile _L("HttpClientEngine.txt") |
|
30 #endif |
|
31 #include "upnpcustomlog.h" |
|
32 |
|
33 // ---------------------------------------------------------------------------- |
|
34 // CUpnpHttpMessageSender::NewL |
|
35 // Two-phased constructor. |
|
36 // ---------------------------------------------------------------------------- |
|
37 // |
|
38 CUpnpHttpMessageSender* CUpnpHttpMessageSender::NewL( CUpnpHttpTransaction& aUpnpTransaction, |
|
39 RHTTPSession aSession, MUpnpHttpMessageSenderOwner& aOwner ) |
|
40 { |
|
41 CUpnpHttpMessageSender* self = CUpnpHttpMessageSender::NewLC( aUpnpTransaction, |
|
42 aSession, aOwner ); |
|
43 CleanupStack::Pop( self ); |
|
44 return self; |
|
45 } |
|
46 |
|
47 // ---------------------------------------------------------------------------- |
|
48 // CUpnpHttpMessageSender::NewLC |
|
49 // Two-phased constructor. |
|
50 // ---------------------------------------------------------------------------- |
|
51 // |
|
52 CUpnpHttpMessageSender* CUpnpHttpMessageSender::NewLC( CUpnpHttpTransaction& aUpnpTransaction, |
|
53 RHTTPSession aSession, MUpnpHttpMessageSenderOwner& aOwner ) |
|
54 { |
|
55 CUpnpHttpMessageSender* self = new (ELeave) CUpnpHttpMessageSender( aUpnpTransaction, |
|
56 aSession, aOwner ); |
|
57 CleanupStack::PushL( self ); |
|
58 self->ConstructL(); |
|
59 return self; |
|
60 } |
|
61 |
|
62 // ---------------------------------------------------------------------------- |
|
63 // CUpnpHttpMessageSender::CUpnpHttpMessageSender |
|
64 // Constructor. |
|
65 // ---------------------------------------------------------------------------- |
|
66 // |
|
67 CUpnpHttpMessageSender::CUpnpHttpMessageSender( CUpnpHttpTransaction& aUpnpTransaction, |
|
68 RHTTPSession aSession, MUpnpHttpMessageSenderOwner& aOwner ) : |
|
69 iUpnpTransaction( aUpnpTransaction ), |
|
70 iSession( aSession ), |
|
71 iOwner( aOwner ) |
|
72 { |
|
73 } |
|
74 |
|
75 // ---------------------------------------------------------------------------- |
|
76 // CUpnpHttpMessageSender::ConstructL |
|
77 // Constructor of CUpnpHttpMessageSender |
|
78 // ---------------------------------------------------------------------------- |
|
79 // |
|
80 void CUpnpHttpMessageSender::ConstructL() |
|
81 { |
|
82 iTimer = CUpnpNotifyTimer::NewL( this ); |
|
83 } |
|
84 |
|
85 // ---------------------------------------------------------------------------- |
|
86 // CUpnpHttpMessageSender::~CUpnpHttpMessageSender |
|
87 // Destructor. |
|
88 // ---------------------------------------------------------------------------- |
|
89 // |
|
90 CUpnpHttpMessageSender::~CUpnpHttpMessageSender() |
|
91 { |
|
92 delete iBody; |
|
93 delete iTimer; |
|
94 iTransaction.Close(); |
|
95 } |
|
96 |
|
97 // ---------------------------------------------------------------------------- |
|
98 // CUpnpHttpMessageSender::UpnpTransaction |
|
99 // Returns upnp transaction object that is maintained by the object. |
|
100 // ---------------------------------------------------------------------------- |
|
101 // |
|
102 CUpnpHttpTransaction& CUpnpHttpMessageSender::UpnpTransaction() |
|
103 { |
|
104 return iUpnpTransaction; |
|
105 } |
|
106 |
|
107 // ---------------------------------------------------------------------------- |
|
108 // CUpnpHttpMessageSender::StartTransactionL |
|
109 // Start a new HTTP transaction maintained by the object. It will start |
|
110 // asynchronous sending of request message. |
|
111 // ---------------------------------------------------------------------------- |
|
112 // |
|
113 void CUpnpHttpMessageSender::StartTransactionL() |
|
114 { |
|
115 ASSERT( !iTimer->IsActive() && NULL == iBody ); //check if this method is called only once |
|
116 LOG_FUNC_NAME; |
|
117 |
|
118 PrepareRequestTransactionL(); |
|
119 PrepareRequestHeadersL(); |
|
120 PrepareRequestBody(); |
|
121 StartRequestTimer(); |
|
122 iTransaction.SubmitL(); |
|
123 |
|
124 ASSERT( iTimer->IsActive() ); //timer is set |
|
125 } |
|
126 |
|
127 // ---------------------------------------------------------------------------- |
|
128 // CUpnpHttpMessageSender::PrepareRequestTransactionL |
|
129 // Opens RHTTPTransaction with request method and uri, subscribe |
|
130 // for transaction's events |
|
131 // ---------------------------------------------------------------------------- |
|
132 // |
|
133 void CUpnpHttpMessageSender::PrepareRequestTransactionL() |
|
134 { |
|
135 HBufC8* uri = DestinationUriL( iUpnpTransaction.Request() ); |
|
136 CleanupStack::PushL( uri ); |
|
137 TUriParser8 uriParser; |
|
138 uriParser.Parse( *uri ); |
|
139 RStringF method = iSession.StringPool().OpenFStringL( iUpnpTransaction.Request()->Method() ); |
|
140 CleanupClosePushL( method ); |
|
141 iTransaction = iSession.OpenTransactionL( uriParser, *this, method ); |
|
142 CleanupStack::PopAndDestroy( &method ); |
|
143 //synchronize ids of both transactions |
|
144 iUpnpTransaction.Request()->SetSessionId( iTransaction.Id() ); |
|
145 CleanupStack::PopAndDestroy( uri ); |
|
146 } |
|
147 |
|
148 // ---------------------------------------------------------------------------- |
|
149 // CUpnpHttpMessageSender::PrepareRequestHeadersL |
|
150 // Sets http headers from UpnpHttpTransaction to RHTTPTransaction |
|
151 // ---------------------------------------------------------------------------- |
|
152 // |
|
153 void CUpnpHttpMessageSender::PrepareRequestHeadersL() |
|
154 { |
|
155 RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection(); |
|
156 hdr.RemoveAllFields(); |
|
157 CUpnpHttpHeaderList& headerList = *(iUpnpTransaction.Request()->HeaderList()); |
|
158 CUpnpHttpHeader* upnphdr = headerList.First(); |
|
159 upnphdr = headerList.Next(upnphdr); // first header is a method |
|
160 while ( upnphdr ) |
|
161 { |
|
162 RStringF valStr = iSession.StringPool().OpenFStringL( upnphdr->Value() ); |
|
163 CleanupClosePushL( valStr ); |
|
164 RStringF namStr = iSession.StringPool().OpenFStringL( upnphdr->Name() ); |
|
165 CleanupClosePushL( namStr ); |
|
166 |
|
167 hdr.SetFieldL( namStr, THTTPHdrVal( valStr ) ); |
|
168 upnphdr = headerList.Next(upnphdr); |
|
169 |
|
170 CleanupStack::PopAndDestroy( &namStr ); |
|
171 CleanupStack::PopAndDestroy( &valStr ); |
|
172 } |
|
173 } |
|
174 |
|
175 // ---------------------------------------------------------------------------- |
|
176 // CUpnpHttpMessageSender::CopyResponseHeadersL |
|
177 // Copies http headers from RHTTPTransaction to UpnpHttpTransaction |
|
178 // ---------------------------------------------------------------------------- |
|
179 // |
|
180 void CUpnpHttpMessageSender::CopyResponseHeadersL() |
|
181 { |
|
182 CUpnpHttpMessage* msg = iUpnpTransaction.Response(); |
|
183 RStringPool strPool = iSession.StringPool(); |
|
184 RHTTPHeaders headers = iTransaction.Response().GetHeaderCollection(); |
|
185 |
|
186 THTTPHdrFieldIter iter = headers.Fields(); |
|
187 while ( !iter.AtEnd() ) |
|
188 { |
|
189 RStringTokenF fieldName = iter(); |
|
190 RStringF fieldNameStr = strPool.StringF( fieldName ); |
|
191 const TDesC8& fieldNameDesC = fieldNameStr.DesC(); |
|
192 |
|
193 TPtrC8 rawFieldData; |
|
194 if ( headers.GetRawField( fieldNameStr, rawFieldData ) == KErrNone ) |
|
195 { |
|
196 msg->AddPairL( fieldNameDesC, rawFieldData ); |
|
197 } |
|
198 |
|
199 ++iter; |
|
200 } |
|
201 } |
|
202 |
|
203 // ---------------------------------------------------------------------------- |
|
204 // CUpnpHttpMessageSender::PrepareRequestBodyL |
|
205 // Sets http message body from UpnpHttpTransaction to RHTTPTransaction |
|
206 // ---------------------------------------------------------------------------- |
|
207 // |
|
208 void CUpnpHttpMessageSender::PrepareRequestBody() |
|
209 { |
|
210 if ( iUpnpTransaction.Request()->Method().Compare( KHttpPost ) == 0 |
|
211 || ( iUpnpTransaction.Request()->Method().Compare( UpnpGENA::KGenaNotify ) == 0 ) ) |
|
212 { |
|
213 iTransaction.Request().SetBody( *this ); |
|
214 } |
|
215 } |
|
216 |
|
217 // ---------------------------------------------------------------------------- |
|
218 // CUpnpHttpMessageSender::StartRequestTimer |
|
219 // Starts timer of request sending with TcpTimeout value. |
|
220 // ---------------------------------------------------------------------------- |
|
221 // |
|
222 void CUpnpHttpMessageSender::StartRequestTimer() |
|
223 { |
|
224 iTimer->After( iUpnpTransaction.Request()->TcpTimeout(), EFalse ); |
|
225 } |
|
226 |
|
227 // ---------------------------------------------------------------------------- |
|
228 // CUpnpHttpMessageSender::TimerEventL |
|
229 // From MNotifyTimerObserver function which indicate that request timeout |
|
230 // expired, so transaction failed. |
|
231 // ---------------------------------------------------------------------------- |
|
232 // |
|
233 void CUpnpHttpMessageSender::TimerEventL( CUpnpNotifyTimer* /*aTimer*/ ) |
|
234 { |
|
235 LOG_FUNC_NAME; |
|
236 TransactionFailed( EHttpRequestTimeout ); |
|
237 } |
|
238 |
|
239 // ---------------------------------------------------------------------------- |
|
240 // CUpnpHttpMessageSender::MHFRunL |
|
241 // Called by Symbian OS HTTP client framework to notify about transaction events. |
|
242 // ---------------------------------------------------------------------------- |
|
243 // |
|
244 void CUpnpHttpMessageSender::MHFRunL( RHTTPTransaction aTransaction, const THTTPEvent& aEvent ) |
|
245 { |
|
246 ASSERT( aTransaction == iTransaction ); |
|
247 switch ( aEvent.iStatus ) |
|
248 { |
|
249 case THTTPEvent::EGotResponseHeaders: |
|
250 { |
|
251 LOGS1( "THTTPEvent::EGotResponseHeaders trans id: %d", |
|
252 aTransaction.Id() ); |
|
253 } |
|
254 break; |
|
255 case THTTPEvent::EGotResponseBodyData: |
|
256 { |
|
257 GotResponseBodyDataL( *(aTransaction.Response().Body()) ); |
|
258 } |
|
259 break; |
|
260 case THTTPEvent::EResponseComplete: |
|
261 { |
|
262 LOGS( "THTTPEvent::EResponseComplete"); |
|
263 // Indicates that header & body of response is completely received. |
|
264 } |
|
265 break; |
|
266 //note: there is a guarantee that THTTPEvent::ESucceeded XOR THTTPEvent::EFailed |
|
267 //event will be provided, and it will be the last event for a transaction |
|
268 //so ESucceeded and EFailed are the only legal states |
|
269 //in which we can call TransactionSucceeded/TransactionFailed |
|
270 case THTTPEvent::ESucceeded: |
|
271 { |
|
272 LOGS( "THTTPEvent::ESucceeded"); |
|
273 TransactionSucceeded(); |
|
274 } |
|
275 break; |
|
276 case THTTPEvent::EFailed: |
|
277 { |
|
278 LOGS( "THTTPEvent::EFailed"); |
|
279 if ( KErrNone != iCurrentErrorNumber ) |
|
280 { |
|
281 TransactionFailed( EHttpRequestTimeout, iCurrentErrorNumber ); |
|
282 } |
|
283 else |
|
284 { |
|
285 TransactionFailed( aTransaction.Response().StatusCode() ); |
|
286 } |
|
287 } |
|
288 break; |
|
289 default: |
|
290 // There are more events in THTTPEvent, but they are not usually |
|
291 // needed. However, event status smaller than zero should be handled |
|
292 // correctly since it's error. |
|
293 { |
|
294 LOGS1( "Other THTTPEvent::%d", aEvent.iStatus ); |
|
295 if ( aEvent.iStatus < 0 ) |
|
296 { |
|
297 iCurrentErrorNumber = aEvent.iStatus; |
|
298 } |
|
299 } |
|
300 break; |
|
301 } |
|
302 } |
|
303 |
|
304 // ---------------------------------------------------------------------------- |
|
305 // CUpnpHttpMessageSender::MHFRunError |
|
306 // Called by Symbian OS HTTP client framework when *leave* occurs in handling |
|
307 // of transaction event |
|
308 // ---------------------------------------------------------------------------- |
|
309 // |
|
310 TInt CUpnpHttpMessageSender::MHFRunError( TInt aError, |
|
311 RHTTPTransaction /*aTransaction*/, |
|
312 const THTTPEvent& /*aEvent*/ ) |
|
313 { |
|
314 LOGS1( "Run error %d", aError ); |
|
315 //in case of serious errors we are receiving here we have to notify |
|
316 //error immediatly (we probably won't receive THTTPEvent::EFailed) |
|
317 TransactionFailed( EHttpRequestTimeout, aError ); |
|
318 return KErrNone; |
|
319 } |
|
320 |
|
321 // ----------------------------------------------------------------------------- |
|
322 // CUpnpHTTPMessageSender::TransactionSucceededL |
|
323 // Called when transaction succeeded. |
|
324 // Closes RHTTPTransaction, and forward result message to observer. |
|
325 // ----------------------------------------------------------------------------- |
|
326 void CUpnpHttpMessageSender::TransactionSucceeded() |
|
327 { |
|
328 //there is nothing we can do about error during notification upper layer |
|
329 //except retry (risky), or ignore |
|
330 TRAP_IGNORE( DoTransactionSucceededL() ); |
|
331 } |
|
332 |
|
333 // ----------------------------------------------------------------------------- |
|
334 // CUpnpHttpMessageSender::TransactionFailedL |
|
335 // Called in case of every fail of transaction. |
|
336 // Closes RHTTPTransaction, creates error message with given status, and forward it |
|
337 // to observer. |
|
338 // ----------------------------------------------------------------------------- |
|
339 void CUpnpHttpMessageSender::TransactionFailed( TInt aStatus, TInt aError ) |
|
340 { |
|
341 //see comment in TransactionSucceeded |
|
342 TRAP_IGNORE( DoTransactionFailedL( aStatus, aError ) ); |
|
343 } |
|
344 |
|
345 // ----------------------------------------------------------------------------- |
|
346 // CUpnpHTTPMessageSender::DoTransactionSucceededL |
|
347 // Internal, leaving code to notify that transaction succeeded |
|
348 // Do NOT use this method directly, but via TransactionSucceded |
|
349 // ----------------------------------------------------------------------------- |
|
350 void CUpnpHttpMessageSender::DoTransactionSucceededL() |
|
351 { |
|
352 LOG_FUNC_NAME; |
|
353 iTimer->Cancel(); |
|
354 iUpnpTransaction.CreateOkResponseL( iBody ? *iBody : KNullDesC8() ); |
|
355 CopyResponseHeadersL(); //to copy SID from service subscription http response |
|
356 iTransaction.Close(); |
|
357 delete iBody; |
|
358 iBody = NULL; |
|
359 iOwner.SenderFinishedLD( this ); |
|
360 } |
|
361 |
|
362 // ----------------------------------------------------------------------------- |
|
363 // CUpnpHTTPMessageSender::DoTransactionFailedL |
|
364 // Internal, leaving code to notify that transaction failed |
|
365 // Do NOT use this method directly, but via TransactionFailed |
|
366 // ----------------------------------------------------------------------------- |
|
367 void CUpnpHttpMessageSender::DoTransactionFailedL( TInt aStatus, TInt aError ) |
|
368 { |
|
369 LOG_FUNC_NAME; |
|
370 iTimer->Cancel(); |
|
371 iTransaction.Close(); |
|
372 if ( KErrNone != aError ) //in case of internal symbian error colected body isn't meaningful |
|
373 { |
|
374 delete iBody; |
|
375 iBody = NULL; |
|
376 } |
|
377 iUpnpTransaction.CreateFaultResponseL( iBody ? *iBody : KNullDesC8(), |
|
378 aStatus, |
|
379 aError ); |
|
380 delete iBody; |
|
381 iBody = NULL; |
|
382 iOwner.SenderFinishedLD( this ); |
|
383 } |
|
384 |
|
385 // ----------------------------------------------------------------------------- |
|
386 // CUpnpHttpMessageSender::GotResponseBodyDataL |
|
387 // Called when transaction got another part of body data. |
|
388 // Data is concatenated to iBody and when the last part of body is received |
|
389 // request message is created witin transaction. |
|
390 // ----------------------------------------------------------------------------- |
|
391 void CUpnpHttpMessageSender::GotResponseBodyDataL( |
|
392 MHTTPDataSupplier& aResponseBodySupplier ) |
|
393 { |
|
394 LOG_FUNC_NAME; |
|
395 |
|
396 TPtrC8 dataChunk; |
|
397 aResponseBodySupplier.GetNextDataPart( dataChunk ); |
|
398 |
|
399 if (!iBody) |
|
400 { |
|
401 iBody = dataChunk.AllocL(); |
|
402 } |
|
403 else |
|
404 { |
|
405 iBody = iBody->ReAllocL( iBody->Length() + dataChunk.Length() ); |
|
406 iBody->Des().Append( dataChunk ); |
|
407 } |
|
408 |
|
409 aResponseBodySupplier.ReleaseData(); |
|
410 } |
|
411 |
|
412 // ----------------------------------------------------------------------------- |
|
413 // CUpnpHTTPMessageSender::DestinationUriL |
|
414 // Helper method that allocate descriptor object with destination uri of message |
|
415 // passed as a parameter. |
|
416 // ----------------------------------------------------------------------------- |
|
417 HBufC8* CUpnpHttpMessageSender::DestinationUriL( CUpnpHttpMessage* aMessage ) |
|
418 { |
|
419 TInetAddr add( aMessage->Receiver() ); |
|
420 HBufC8* address = UpnpString::InetToStringL( add ); |
|
421 CleanupStack::PushL( address ); |
|
422 TPtrC8 path( aMessage->SenderPathFromHeader() ) ; |
|
423 HBufC8* uriBuf = HBufC8::NewL( |
|
424 UpnpHTTP::KHTTPUrl().Length() + address->Length() + path.Length() ); |
|
425 TPtr8 uri( uriBuf->Des() ); |
|
426 uri.Append( UpnpHTTP::KHTTPUrl ); |
|
427 uri.Append( *address ); |
|
428 uri.Append( path ); |
|
429 CleanupStack::PopAndDestroy( address ); |
|
430 return uriBuf; |
|
431 } |
|
432 |
|
433 // ----------------------------------------------------------------------------- |
|
434 // CUpnpHttpMessageSender::GetNextDataPart |
|
435 // Method from MHTTPDataSupplier used to supply body of request from |
|
436 // our UpnpMessage to Symian RHTTPRequest |
|
437 // ----------------------------------------------------------------------------- |
|
438 TBool CUpnpHttpMessageSender::GetNextDataPart( TPtrC8& aDataChunk ) |
|
439 { |
|
440 aDataChunk.Set( iUpnpTransaction.Request()->Body() ); |
|
441 return ETrue; |
|
442 } |
|
443 |
|
444 // ----------------------------------------------------------------------------- |
|
445 // CUpnpHttpMessageSender::ReleaseData() |
|
446 // Method from from MHTTPDataSupplier to supply body of request from |
|
447 // our UpnpMessage to Symian RHTTPRequest |
|
448 // ----------------------------------------------------------------------------- |
|
449 void CUpnpHttpMessageSender::ReleaseData() |
|
450 { |
|
451 } |
|
452 |
|
453 // ----------------------------------------------------------------------------- |
|
454 // CUpnpHttpMessageSender::OverallDataSize |
|
455 // Method from MHTTPDataSupplier used to supply body of request from |
|
456 // our UpnpMessage to Symian RHTTPRequest |
|
457 // ----------------------------------------------------------------------------- |
|
458 TInt CUpnpHttpMessageSender::OverallDataSize() |
|
459 { |
|
460 return iUpnpTransaction.Request()->Body().Length(); |
|
461 } |
|
462 |
|
463 // ----------------------------------------------------------------------------- |
|
464 // CUpnpHttpMessageSender::Reset |
|
465 // Method from MHTTPDataSupplier used to supply body of request from |
|
466 // our UpnpMessage to Symian RHTTPRequest |
|
467 // ----------------------------------------------------------------------------- |
|
468 TInt CUpnpHttpMessageSender::Reset() |
|
469 { |
|
470 return KErrNone; |
|
471 } |
|
472 |
|
473 // ---------------------------------------------------------------------------- |
|
474 // CUpnpHttpMessageSender::CancelTransaction |
|
475 // Cancels transaction |
|
476 // ---------------------------------------------------------------------------- |
|
477 // |
|
478 void CUpnpHttpMessageSender::CancelTransaction() |
|
479 { |
|
480 LOG_FUNC_NAME; |
|
481 iTransaction.Cancel(); |
|
482 iTimer->Cancel(); |
|
483 TransactionFailed( EHttpRequestTimeout );//no need to wait, notify timeout |
|
484 } |
|
485 |
|
486 //end of file |