|
MythTV
0.26-pre
|
00001 00002 // Program Name: httpserver.cpp 00003 // Created : Oct. 1, 2005 00004 // 00005 // Purpose : HTTP 1.1 Mini Server Implmenetation 00006 // Used for UPnp/AV implementation & status information 00007 // 00008 // Copyright (c) 2005 David Blain <dblain@mythtv.org> 00009 // 00010 // Licensed under the GPL v2 or later, see COPYING for details 00011 // 00013 00014 // ANSI C headers 00015 #include <cmath> 00016 00017 // POSIX headers 00018 #include <compat.h> 00019 #ifndef USING_MINGW 00020 #include <sys/utsname.h> 00021 #endif 00022 00023 // Qt headers 00024 #include <QScriptEngine> 00025 00026 // MythTV headers 00027 #include "httpserver.h" 00028 #include "upnputil.h" 00029 #include "upnp.h" // only needed for Config... remove once config is moved. 00030 #include "compat.h" 00031 #include "mythdirs.h" 00032 #include "mythlogging.h" 00033 #include "htmlserver.h" 00034 00037 // 00038 // HttpServer Class Implementation 00039 // 00042 00043 QMutex HttpServer::s_platformLock; 00044 QString HttpServer::s_platform; 00045 00047 // 00049 00050 HttpServer::HttpServer(const QString sApplicationPrefix) : 00051 ServerPool(), m_sSharePath(GetShareDir()), 00052 m_pHtmlServer(new HtmlServerExtension(m_sSharePath, sApplicationPrefix)), 00053 m_threadPool("HttpServerPool"), m_running(true) 00054 { 00055 setMaxPendingConnections(20); 00056 00057 // ---------------------------------------------------------------------- 00058 // Build Platform String 00059 // ---------------------------------------------------------------------- 00060 { 00061 QMutexLocker locker(&s_platformLock); 00062 #ifdef USING_MINGW 00063 s_platform = QString("Windows %1.%2") 00064 .arg(LOBYTE(LOWORD(GetVersion()))) 00065 .arg(HIBYTE(LOWORD(GetVersion()))); 00066 #else 00067 struct utsname uname_info; 00068 uname( &uname_info ); 00069 s_platform = QString("%1 %2") 00070 .arg(uname_info.sysname).arg(uname_info.release); 00071 #endif 00072 } 00073 00074 LOG(VB_UPNP, LOG_INFO, QString("HttpServer() - SharePath = %1") 00075 .arg(m_sSharePath)); 00076 00077 // -=>TODO: Load Config XML 00078 // -=>TODO: Load & initialize - HttpServerExtensions 00079 } 00080 00082 // 00084 00085 HttpServer::~HttpServer() 00086 { 00087 m_rwlock.lockForWrite(); 00088 m_running = false; 00089 m_rwlock.unlock(); 00090 00091 m_threadPool.Stop(); 00092 00093 while (!m_extensions.empty()) 00094 { 00095 delete m_extensions.takeFirst(); 00096 } 00097 00098 if (m_pHtmlServer != NULL) 00099 delete m_pHtmlServer; 00100 } 00101 00103 // 00105 00106 QString HttpServer::GetPlatform(void) 00107 { 00108 QMutexLocker locker(&s_platformLock); 00109 return s_platform; 00110 } 00111 00113 // 00115 00116 QScriptEngine* HttpServer::ScriptEngine() 00117 { 00118 return ((HtmlServerExtension *)m_pHtmlServer)->ScriptEngine(); 00119 } 00120 00122 // 00124 00125 void HttpServer::newTcpConnection(int nSocket) 00126 { 00127 m_threadPool.startReserved( 00128 new HttpWorker(*this, nSocket), 00129 QString("HttpServer%1").arg(nSocket)); 00130 } 00131 00133 // 00135 00136 void HttpServer::RegisterExtension( HttpServerExtension *pExtension ) 00137 { 00138 if (pExtension != NULL ) 00139 { 00140 m_rwlock.lockForWrite(); 00141 m_extensions.append( pExtension ); 00142 00143 // Add to multimap for quick lookup. 00144 00145 QStringList list = pExtension->GetBasePaths(); 00146 00147 for( int nIdx = 0; nIdx < list.size(); nIdx++) 00148 m_basePaths.insert( list[ nIdx ], pExtension ); 00149 00150 m_rwlock.unlock(); 00151 } 00152 } 00153 00155 // 00157 00158 void HttpServer::UnregisterExtension( HttpServerExtension *pExtension ) 00159 { 00160 if (pExtension != NULL ) 00161 { 00162 m_rwlock.lockForWrite(); 00163 00164 QStringList list = pExtension->GetBasePaths(); 00165 00166 for( int nIdx = 0; nIdx < list.size(); nIdx++) 00167 m_basePaths.remove( list[ nIdx ], pExtension ); 00168 00169 m_extensions.removeAll(pExtension); 00170 00171 delete pExtension; 00172 00173 m_rwlock.unlock(); 00174 } 00175 } 00176 00178 // 00180 00181 void HttpServer::DelegateRequest(HTTPRequest *pRequest) 00182 { 00183 bool bProcessed = false; 00184 00185 m_rwlock.lockForRead(); 00186 00187 QList< HttpServerExtension* > list = m_basePaths.values( pRequest->m_sBaseUrl ); 00188 00189 for (int nIdx=0; nIdx < list.size() && !bProcessed; nIdx++ ) 00190 { 00191 try 00192 { 00193 bProcessed = list[ nIdx ]->ProcessRequest(pRequest); 00194 } 00195 catch(...) 00196 { 00197 LOG(VB_GENERAL, LOG_ERR, QString("HttpServer::DelegateRequest - " 00198 "Unexpected Exception - " 00199 "pExtension->ProcessRequest().")); 00200 } 00201 } 00202 00203 #if 0 00204 HttpServerExtensionList::iterator it = m_extensions.begin(); 00205 00206 for (; (it != m_extensions.end()) && !bProcessed; ++it) 00207 { 00208 try 00209 { 00210 bProcessed = (*it)->ProcessRequest(pRequest); 00211 } 00212 catch(...) 00213 { 00214 LOG(VB_GENERAL, LOG_ERR, QString("HttpServer::DelegateRequest - " 00215 "Unexpected Exception - " 00216 "pExtension->ProcessRequest().")); 00217 } 00218 } 00219 #endif 00220 m_rwlock.unlock(); 00221 00222 if (!bProcessed) 00223 bProcessed = m_pHtmlServer->ProcessRequest(pRequest); 00224 00225 if (!bProcessed) 00226 { 00227 pRequest->m_eResponseType = ResponseTypeHTML; 00228 pRequest->m_nResponseStatus = 404; 00229 } 00230 } 00231 00234 // 00235 // HttpWorkerThread Class Implementation 00236 // 00239 00240 HttpWorker::HttpWorker(HttpServer &httpServer, int sock) : 00241 m_httpServer(httpServer), m_socket(sock), m_socketTimeout(10000) 00242 { 00243 m_socketTimeout = 1000 * 00244 UPnp::GetConfiguration()->GetValue("HTTP/KeepAliveTimeoutSecs", 10); 00245 } 00246 00248 // 00250 00251 void HttpWorker::run(void) 00252 { 00253 #if 0 00254 LOG(VB_UPNP, LOG_DEBUG, 00255 QString("HttpWorker::run() socket=%1 -- begin").arg(m_socket)); 00256 #endif 00257 00258 bool bTimeout = false; 00259 bool bKeepAlive = true; 00260 BufferedSocketDevice *pSocket = NULL; 00261 HTTPRequest *pRequest = NULL; 00262 00263 try 00264 { 00265 if ((pSocket = new BufferedSocketDevice( m_socket )) == NULL) 00266 { 00267 LOG(VB_GENERAL, LOG_ERR, "Error Creating BufferedSocketDevice"); 00268 return; 00269 } 00270 00271 pSocket->SocketDevice()->setBlocking( true ); 00272 00273 while (m_httpServer.IsRunning() && bKeepAlive && pSocket->IsValid()) 00274 { 00275 bTimeout = false; 00276 00277 int64_t nBytes = pSocket->WaitForMore(m_socketTimeout, &bTimeout); 00278 if (!m_httpServer.IsRunning()) 00279 break; 00280 00281 if ( nBytes > 0) 00282 { 00283 // ---------------------------------------------------------- 00284 // See if this is a valid request 00285 // ---------------------------------------------------------- 00286 00287 pRequest = new BufferedSocketDeviceRequest( pSocket ); 00288 if (pRequest != NULL) 00289 { 00290 if ( pRequest->ParseRequest() ) 00291 { 00292 bKeepAlive = pRequest->GetKeepAlive(); 00293 00294 // ------------------------------------------------------ 00295 // Request Parsed... Pass on to Main HttpServer class to 00296 // delegate processing to HttpServerExtensions. 00297 // ------------------------------------------------------ 00298 00299 if (pRequest->m_nResponseStatus != 401) 00300 m_httpServer.DelegateRequest(pRequest); 00301 } 00302 else 00303 { 00304 LOG(VB_UPNP, LOG_ERR, "ParseRequest Failed."); 00305 00306 pRequest->m_nResponseStatus = 501; 00307 bKeepAlive = false; 00308 } 00309 00310 #if 0 00311 // Dump Request Header 00312 if (!bKeepAlive ) 00313 { 00314 for ( QStringMap::iterator it = pRequest->m_mapHeaders.begin(); 00315 it != pRequest->m_mapHeaders.end(); 00316 ++it ) 00317 { 00318 LOG(VB_GENERAL, LOG_DEBUG, QString("%1: %2") 00319 .arg(it.key()) .arg(it.data())); 00320 } 00321 } 00322 #endif 00323 00324 // ------------------------------------------------------- 00325 // Always MUST send a response. 00326 // ------------------------------------------------------- 00327 00328 if (pRequest->SendResponse() < 0) 00329 { 00330 bKeepAlive = false; 00331 LOG(VB_UPNP, LOG_ERR, 00332 QString("socket(%1) - Error returned from " 00333 "SendResponse... Closing connection") 00334 .arg(m_socket)); 00335 } 00336 00337 // ------------------------------------------------------- 00338 // Check to see if a PostProcess was registered 00339 // ------------------------------------------------------- 00340 00341 if ( pRequest->m_pPostProcess != NULL ) 00342 pRequest->m_pPostProcess->ExecutePostProcess(); 00343 00344 delete pRequest; 00345 pRequest = NULL; 00346 } 00347 else 00348 { 00349 LOG(VB_GENERAL, LOG_ERR, 00350 "Error Creating BufferedSocketDeviceRequest"); 00351 bKeepAlive = false; 00352 } 00353 } 00354 else 00355 { 00356 bKeepAlive = false; 00357 } 00358 } 00359 } 00360 catch(...) 00361 { 00362 LOG(VB_GENERAL, LOG_ERR, 00363 "HttpWorkerThread::ProcessWork - Unexpected Exception."); 00364 } 00365 00366 if (pRequest != NULL) 00367 delete pRequest; 00368 00369 pSocket->Close(); 00370 00371 delete pSocket; 00372 m_socket = 0; 00373 00374 #if 0 00375 LOG(VB_UPNP, LOG_DEBUG, "HttpWorkerThread::run() -- end"); 00376 #endif 00377 } 00378 00379
1.7.6.1