00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00012
00013 #include <QDomDocument>
00014
00015 #include "mythlogging.h"
00016 #include "servicehost.h"
00017 #include "wsdl.h"
00018 #include "xsd.h"
00019
00020 #define _MAX_PARAMS 256
00021
00023
00025
00026 MethodInfo::MethodInfo()
00027 {
00028 m_eRequestType = (RequestType)(RequestTypeGet | RequestTypePost |
00029 RequestTypeHead);
00030 }
00031
00033
00035
00036 QVariant MethodInfo::Invoke( Service *pService, const QStringMap &reqParams )
00037 {
00038 HttpRedirectException exception;
00039 bool bExceptionThrown = false;
00040
00041 if (!pService)
00042 throw;
00043
00044 QList<QByteArray> paramNames = m_oMethod.parameterNames();
00045 QList<QByteArray> paramTypes = m_oMethod.parameterTypes();
00046
00047
00048
00049
00050
00051
00052 void *param[ _MAX_PARAMS ];
00053 int types[ _MAX_PARAMS ];
00054
00055 memset( param, 0, _MAX_PARAMS * sizeof(void *));
00056 memset( types, 0, _MAX_PARAMS * sizeof(int));
00057
00058 try
00059 {
00060
00061
00062
00063
00064 int nRetIdx = QMetaType::type( m_oMethod.typeName() );
00065
00066 if (nRetIdx != 0)
00067 {
00068 param[ 0 ] = QMetaType::construct( nRetIdx );
00069 types[ 0 ] = nRetIdx;
00070 }
00071 else
00072 {
00073 param[ 0 ] = NULL;
00074 types[ 0 ] = 0;
00075 }
00076
00077
00078
00079
00080
00081 for( int nIdx = 0; nIdx < paramNames.length(); nIdx++ )
00082 {
00083 QString sValue = reqParams[ paramNames[ nIdx ] ];
00084 QString sParamType = paramTypes[ nIdx ];
00085
00086 int nId = QMetaType::type( paramTypes[ nIdx ] );
00087 void *pParam = NULL;
00088
00089 if (nId != 0)
00090 {
00091 pParam = QMetaType::construct( nId );
00092 }
00093 else
00094 {
00095 LOG(VB_GENERAL, LOG_ERR,
00096 QString("MethodInfo::Invoke - Type unknown '%1'")
00097 .arg(sParamType));
00098 }
00099
00100 types[nIdx+1] = nId;
00101 param[nIdx+1] = pService->ConvertToParameterPtr( nId, sParamType,
00102 pParam, sValue );
00103 }
00104
00105 #if 0
00106 QThread *currentThread = QThread::currentThread();
00107 QThread *objectThread = pService->thread();
00108
00109 if (currentThread == objectThread)
00110 LOG(VB_UPNP, LOG_DEBUG, "*** Threads are same ***");
00111 else
00112 LOG(VB_UPNP, LOG_DEBUG, "*** Threads are Different!!! ***");
00113 #endif
00114
00115 pService->qt_metacall( QMetaObject::InvokeMetaMethod,
00116 m_nMethodIndex,
00117 param );
00118
00119
00120
00121
00122
00123
00124 for (int nIdx=1; nIdx < paramNames.length()+1; nIdx++)
00125 {
00126 if ((types[ nIdx ] != 0) && (param[ nIdx ] != NULL))
00127 QMetaType::destroy( types[ nIdx ], param[ nIdx ] );
00128 }
00129 }
00130 catch (QString &sMsg)
00131 {
00132 LOG(VB_GENERAL, LOG_ERR,
00133 QString("MethodInfo::Invoke - An Exception Occurred: %1")
00134 .arg(sMsg));
00135
00136 if ((types[ 0 ] != 0) && (param[ 0 ] != NULL ))
00137 QMetaType::destroy( types[ 0 ], param[ 0 ] );
00138
00139 throw;
00140 }
00141 catch (HttpRedirectException &ex)
00142 {
00143 bExceptionThrown = true;
00144 exception = ex;
00145 }
00146 catch (...)
00147 {
00148 LOG(VB_GENERAL, LOG_INFO,
00149 "MethodInfo::Invoke - An Exception Occurred" );
00150 }
00151
00152
00153
00154
00155
00156 QVariant vReturn;
00157
00158 if ( param[ 0 ] != NULL)
00159 {
00160 vReturn = pService->ConvertToVariant( types[ 0 ], param[ 0 ] );
00161
00162 if (types[ 0 ] != 0)
00163 QMetaType::destroy( types[ 0 ], param[ 0 ] );
00164 }
00165
00166
00167
00168
00169
00170 if (bExceptionThrown)
00171 throw exception;
00172
00173 return vReturn;
00174 }
00175
00178
00179
00180
00183
00184 ServiceHost::ServiceHost(const QMetaObject &metaObject,
00185 const QString &sExtensionName,
00186 const QString &sBaseUrl,
00187 const QString &sSharePath )
00188 : HttpServerExtension ( sExtensionName, sSharePath )
00189 {
00190 m_oMetaObject = metaObject;
00191 m_sBaseUrl = sBaseUrl;
00192
00193
00194
00195
00196
00197 for (int nIdx = 0; nIdx < m_oMetaObject.methodCount(); nIdx++)
00198 {
00199 QMetaMethod method = m_oMetaObject.method( nIdx );
00200
00201 if ((method.methodType() == QMetaMethod::Slot ) &&
00202 (method.access() == QMetaMethod::Public ))
00203 {
00204 QString sName( method.signature() );
00205
00206
00207
00208
00209
00210 if (sName == "deleteLater()")
00211 continue;
00212
00213
00214
00215 MethodInfo oInfo;
00216
00217 oInfo.m_nMethodIndex = nIdx;
00218 oInfo.m_sName = sName.section( '(', 0, 0 );
00219 oInfo.m_oMethod = method;
00220 oInfo.m_eRequestType = (RequestType)(RequestTypeGet |
00221 RequestTypePost |
00222 RequestTypeHead);
00223
00224 QString sMethodClassInfo = oInfo.m_sName + "_Method";
00225
00226 int nClassIdx =
00227 m_oMetaObject.indexOfClassInfo(sMethodClassInfo.toAscii());
00228
00229 if (nClassIdx >=0)
00230 {
00231 QString sRequestType =
00232 m_oMetaObject.classInfo(nClassIdx).value();
00233
00234 if (sRequestType == "POST")
00235 oInfo.m_eRequestType = RequestTypePost;
00236 else if (sRequestType == "GET" )
00237 oInfo.m_eRequestType = (RequestType)(RequestTypeGet |
00238 RequestTypeHead);
00239 }
00240
00241 m_Methods.insert( oInfo.m_sName, oInfo );
00242 }
00243 }
00244 }
00245
00247
00249
00250 ServiceHost::~ServiceHost()
00251 {
00252 }
00253
00255
00257
00258 QStringList ServiceHost::GetBasePaths()
00259 {
00260 return QStringList( m_sBaseUrl );
00261 }
00262
00264
00266
00267 bool ServiceHost::ProcessRequest( HTTPRequest *pRequest )
00268 {
00269 bool bHandled = false;
00270 Service *pService = NULL;
00271
00272 try
00273 {
00274 if (pRequest)
00275 {
00276 if (pRequest->m_sBaseUrl != m_sBaseUrl)
00277 return false;
00278
00279 LOG(VB_UPNP, LOG_INFO,
00280 QString("ServiceHost::ProcessRequest: %1 : %2")
00281 .arg(pRequest->m_sMethod) .arg(pRequest->m_sRawRequest));
00282
00283
00284
00285
00286
00287 if (( pRequest->m_eType == RequestTypeGet ) &&
00288 ( pRequest->m_sMethod == "wsdl" ))
00289 {
00290 pService = qobject_cast<Service*>(m_oMetaObject.newInstance());
00291
00292 Wsdl wsdl( this );
00293
00294 wsdl.GetWSDL( pRequest );
00295
00296 delete pService;
00297 return true;
00298 }
00299
00300
00301
00302
00303
00304 if (( pRequest->m_eType == RequestTypeGet ) &&
00305 ( pRequest->m_sMethod == "xsd" ))
00306 {
00307 if ( pRequest->m_mapParams.count() > 0)
00308 {
00309 pService = qobject_cast<Service*>(m_oMetaObject.newInstance());
00310
00311 Xsd xsd;
00312
00313 xsd.GetXSD( pRequest, pRequest->m_mapParams[ "type" ] );
00314
00315 delete pService;
00316 }
00317
00318 return true;
00319 }
00320
00321 if (( pRequest->m_eType == RequestTypeGet ) &&
00322 ( pRequest->m_sMethod == "version" ))
00323 {
00324
00325 int nClassIdx = m_oMetaObject.indexOfClassInfo( "version" );
00326
00327 if (nClassIdx >=0)
00328 {
00329 QString sVersion =
00330 m_oMetaObject.classInfo(nClassIdx).value();
00331
00332 return FormatResponse( pRequest, QVariant( sVersion ));
00333 }
00334 }
00335
00336
00337
00338
00339
00340
00341
00342 QString sMethodName = pRequest->m_sMethod;
00343 bool bMethodFound = false;
00344
00345 if (m_Methods.contains(sMethodName))
00346 bMethodFound = true;
00347 else
00348 {
00349 switch( pRequest->m_eType )
00350 {
00351 case RequestTypeHead:
00352 case RequestTypeGet :
00353 sMethodName = "Get" + sMethodName;
00354 break;
00355 case RequestTypePost:
00356 sMethodName = "Put" + sMethodName;
00357 break;
00358 }
00359
00360 if (m_Methods.contains(sMethodName))
00361 bMethodFound = true;
00362 }
00363
00364 if (bMethodFound)
00365 {
00366 MethodInfo oInfo = m_Methods.value( sMethodName );
00367
00368 if (( pRequest->m_eType & oInfo.m_eRequestType ) != 0)
00369 {
00370
00371
00372
00373
00374
00375
00376 pService =
00377 qobject_cast<Service*>(m_oMetaObject.newInstance());
00378
00379 QVariant vResult = oInfo.Invoke(pService,
00380 pRequest->m_mapParams);
00381
00382 bHandled = FormatResponse( pRequest, vResult );
00383 }
00384 }
00385
00386 if (!bHandled)
00387 UPnp::FormatErrorResponse( pRequest, UPnPResult_InvalidAction );
00388 }
00389 }
00390 catch (HttpRedirectException &ex)
00391 {
00392 UPnp::FormatRedirectResponse( pRequest, ex.hostName );
00393 bHandled = true;
00394 }
00395 catch (HttpException &ex)
00396 {
00397 LOG(VB_GENERAL, LOG_ERR, ex.msg);
00398 UPnp::FormatErrorResponse( pRequest, UPnPResult_ActionFailed, ex.msg );
00399
00400 bHandled = true;
00401
00402 }
00403 catch (QString &sMsg)
00404 {
00405 LOG(VB_GENERAL, LOG_ERR, sMsg);
00406 UPnp::FormatErrorResponse( pRequest, UPnPResult_ActionFailed, sMsg );
00407
00408 bHandled = true;
00409 }
00410 catch ( ...)
00411 {
00412 QString sMsg( "ServiceHost::ProcessRequest - Unexpected Exception" );
00413
00414 LOG(VB_GENERAL, LOG_ERR, sMsg);
00415 UPnp::FormatErrorResponse( pRequest, UPnPResult_ActionFailed, sMsg );
00416
00417 bHandled = true;
00418 }
00419
00420 if (pService != NULL)
00421 delete pService;
00422
00423 return bHandled;
00424 }
00425
00427
00429
00430 bool ServiceHost::FormatResponse( HTTPRequest *pRequest, QObject *pResults )
00431 {
00432 if (pResults != NULL)
00433 {
00434 Serializer *pSer = pRequest->GetSerializer();
00435
00436 pSer->Serialize( pResults );
00437
00438 pRequest->FormatActionResponse( pSer );
00439
00440 delete pResults;
00441
00442 return true;
00443 }
00444 else
00445 UPnp::FormatErrorResponse( pRequest, UPnPResult_ActionFailed, "Call to method failed" );
00446
00447 return false;
00448 }
00449
00451
00453
00454 bool ServiceHost::FormatResponse( HTTPRequest *pRequest, QFileInfo oInfo )
00455 {
00456 QString sName = oInfo.absoluteFilePath();
00457
00458 if (oInfo.exists())
00459 {
00460 if (oInfo.isSymLink())
00461 pRequest->FormatFileResponse( oInfo.symLinkTarget() );
00462 else
00463 pRequest->FormatFileResponse( oInfo.absoluteFilePath() );
00464 }
00465 else
00466 {
00467
00468 pRequest->FormatFileResponse( "" );
00469 }
00470
00471 return true;
00472 }
00473
00474
00476
00478
00479 bool ServiceHost::FormatResponse( HTTPRequest *pRequest, QVariant vValue )
00480 {
00481 if ( vValue.canConvert< QObject* >())
00482 {
00483 const QObject *pObject = vValue.value< QObject* >();
00484
00485 return FormatResponse( pRequest, (QObject *)pObject );
00486 }
00487
00488 if ( vValue.canConvert< QFileInfo >())
00489 {
00490 const QFileInfo oFileInfo = vValue.value< QFileInfo >();
00491
00492 return FormatResponse( pRequest, oFileInfo );
00493 }
00494
00495
00496
00497
00498
00499 Serializer *pSer = pRequest->GetSerializer();
00500
00501 pSer->Serialize( vValue, vValue.typeName() );
00502
00503 pRequest->FormatActionResponse( pSer );
00504
00505 return true;
00506 }