MythTV  master
httpserver.cpp
Go to the documentation of this file.
1 // Program Name: httpserver.cpp
3 // Created : Oct. 1, 2005
4 //
5 // Purpose : HTTP 1.1 Mini Server Implmenetation
6 // Used for UPnp/AV implementation & status information
7 //
8 // Copyright (c) 2005 David Blain <dblain@mythtv.org>
9 // 2014 Stuart Morgan <smorgan@mythtv.org>
10 //
11 // Licensed under the GPL v2 or later, see LICENSE for details
12 //
14 
15 // Own headers
16 #include "httpserver.h"
17 
18 // ANSI C headers
19 #include <cmath>
20 
21 // POSIX headers
22 #ifndef _WIN32
23 #include <sys/utsname.h>
24 #endif
25 
26 // Qt headers
27 #if CONFIG_QTSCRIPT
28 #include <QScriptEngine>
29 #endif
30 #include <QSslConfiguration>
31 #include <QSslSocket>
32 #include <QSslCipher>
33 #include <QSslCertificate>
34 #include <QUuid>
35 
36 // MythTV headers
37 #include "libmythbase/compat.h"
39 #include "libmythbase/mythdirs.h"
41 #include "libmythbase/mythversion.h"
42 
43 #include "upnputil.h"
44 #include "upnp.h" // only needed for Config... remove once config is moved.
45 #include "htmlserver.h"
46 
48 
53 {
55  pRequest->m_nResponseStatus = 200; // OK
56  // RFC 2616 Sect. 9.2 - If no response body is included, the response
57  // MUST include a Content-Length field with a
58  // field-value of "0".
59  pRequest->SetResponseHeader("Content-Length", "0");
60 
61  QStringList allowedMethods;
63  allowedMethods.append("GET");
65  allowedMethods.append("HEAD");
67  allowedMethods.append("POST");
68 // if (m_nSupportedMethods & RequestTypePut)
69 // allowedMethods.append("PUT");
70 // if (m_nSupportedMethods & RequestTypeDelete)
71 // allowedMethods.append("DELETE");
72 // if (m_nSupportedMethods & RequestTypeConnect)
73 // allowedMethods.append("CONNECT");
75  allowedMethods.append("OPTIONS");
76 // if (m_nSupportedMethods & RequestTypeTrace)
77 // allowedMethods.append("TRACE");
79  allowedMethods.append("M-SEARCH");
81  allowedMethods.append("SUBSCRIBE");
83  allowedMethods.append("UNSUBSCRIBE");
85  allowedMethods.append("NOTIFY");
86 
87  if (!allowedMethods.isEmpty())
88  {
89  pRequest->SetResponseHeader("Allow", allowedMethods.join(", "));
90  return true;
91  }
92 
93  LOG(VB_GENERAL, LOG_ERR, QString("HttpServerExtension::ProcessOptions(): "
94  "Error: No methods supported for "
95  "extension - %1").arg(m_sName));
96 
97  return false;
98 }
99 
100 
103 //
104 // HttpServer Class Implementation
105 //
108 
110 QString HttpServer::s_platform;
111 
113 //
115 
117  m_sSharePath(GetShareDir()),
118  m_threadPool("HttpServerPool"),
119  m_privateToken(QUuid::createUuid().toString()) // Cryptographically random and sufficiently long enough to act as a secure token
120 {
121  // Number of connections processed concurrently
122  int maxHttpWorkers = std::max(QThread::idealThreadCount() * 2, 2); // idealThreadCount can return -1
123  // Don't allow more connections than we can process, it causes browsers
124  // to open lots of new connections instead of reusing existing ones
125  setMaxPendingConnections(maxHttpWorkers);
126  m_threadPool.setMaxThreadCount(maxHttpWorkers);
127 
128  LOG(VB_HTTP, LOG_NOTICE, QString("HttpServer(): Max Thread Count %1")
129  .arg(m_threadPool.maxThreadCount()));
130 
131  // ----------------------------------------------------------------------
132  // Build Platform String
133  // ----------------------------------------------------------------------
134  {
135  QMutexLocker locker(&s_platformLock);
136 #ifdef _WIN32
137  s_platform = QString("Windows/%1.%2")
138  .arg(LOBYTE(LOWORD(GetVersion())))
139  .arg(HIBYTE(LOWORD(GetVersion())));
140 #else
141  struct utsname uname_info {};
142  uname( &uname_info );
143  s_platform = QString("%1/%2")
144  .arg(uname_info.sysname, uname_info.release);
145 #endif
146  }
147 
148  LOG(VB_HTTP, LOG_INFO, QString("HttpServer() - SharePath = %1")
149  .arg(m_sSharePath));
150 
151  // -=>TODO: Load Config XML
152  // -=>TODO: Load & initialize - HttpServerExtensions
153 
154  // ----------------------------------------------------------------------
155  // Enable Rtti Service for all instances of HttpServer
156  // and register with QtScript Engine.
157  // Rtti service is an alternative to using the xsd uri
158  // it returns xml/json/etc... definitions of types/enums
159  // ----------------------------------------------------------------------
160 
162 
163  LoadSSLConfig();
164 }
165 
167 //
169 
171 {
172  m_rwlock.lockForWrite();
173  m_running = false;
174  m_rwlock.unlock();
175 
176  m_threadPool.Stop();
177 
178  while (!m_extensions.empty())
179  {
180  delete m_extensions.takeFirst();
181  }
182 }
183 
185 {
186 #ifndef QT_NO_OPENSSL
187  m_sslConfig = QSslConfiguration::defaultConfiguration();
188 
189  m_sslConfig.setProtocol(QSsl::SecureProtocols); // Includes SSLv3 which is insecure, but can't be helped
190  m_sslConfig.setSslOption(QSsl::SslOptionDisableLegacyRenegotiation, true); // Potential DoS multiplier
191  m_sslConfig.setSslOption(QSsl::SslOptionDisableCompression, true); // CRIME attack
192 
193  QList<QSslCipher> availableCiphers = QSslConfiguration::supportedCiphers();
194  QList<QSslCipher> secureCiphers;
195  QList<QSslCipher>::iterator it;
196  for (it = availableCiphers.begin(); it != availableCiphers.end(); ++it)
197  {
198  // Remove weak ciphers from the cipher list
199  if ((*it).usedBits() < 128)
200  continue;
201 
202  if ((*it).name().startsWith("RC4") || // Weak cipher
203  (*it).name().startsWith("EXP") || // Weak authentication
204  (*it).name().startsWith("ADH") || // No authentication
205  (*it).name().contains("NULL")) // No encryption
206  continue;
207 
208  secureCiphers.append(*it);
209  }
210  m_sslConfig.setCiphers(secureCiphers);
211 #endif
212 
213  QString hostKeyPath = gCoreContext->GetSetting("hostSSLKey", "");
214 
215  if (hostKeyPath.isEmpty()) // No key, assume no SSL
216  return;
217 
218  QFile hostKeyFile(hostKeyPath);
219  if (!hostKeyFile.exists() || !hostKeyFile.open(QIODevice::ReadOnly))
220  {
221  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer: SSL Host key file (%1) does not exist or is not readable").arg(hostKeyPath));
222  return;
223  }
224 
225 #ifndef QT_NO_OPENSSL
226  QByteArray rawHostKey = hostKeyFile.readAll();
227  QSslKey hostKey = QSslKey(rawHostKey, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
228  if (!hostKey.isNull())
229  m_sslConfig.setPrivateKey(hostKey);
230  else
231  {
232  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer: Unable to load host key from file (%1)").arg(hostKeyPath));
233  return;
234  }
235 
236  QString hostCertPath = gCoreContext->GetSetting("hostSSLCertificate", "");
237  QSslCertificate hostCert;
238  QList<QSslCertificate> certList = QSslCertificate::fromPath(hostCertPath);
239  if (!certList.isEmpty())
240  hostCert = certList.first();
241 
242  if (!hostCert.isNull())
243  {
244  if (hostCert.effectiveDate() > QDateTime::currentDateTime())
245  {
246  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer: Host certificate start date in future (%1)").arg(hostCertPath));
247  return;
248  }
249 
250  if (hostCert.expiryDate() < QDateTime::currentDateTime())
251  {
252  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer: Host certificate has expired (%1)").arg(hostCertPath));
253  return;
254  }
255 
256  m_sslConfig.setLocalCertificate(hostCert);
257  }
258  else
259  {
260  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer: Unable to load host cert from file (%1)").arg(hostCertPath));
261  return;
262  }
263 
264  QString caCertPath = gCoreContext->GetSetting("caSSLCertificate", "");
265  QList< QSslCertificate > CACertList = QSslCertificate::fromPath(caCertPath);
266 
267  if (!CACertList.isEmpty())
268  m_sslConfig.setCaCertificates(CACertList);
269  else if (!caCertPath.isEmpty()) // Only warn if a path was actually configured, this isn't an error otherwise
270  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer: Unable to load CA cert file (%1)").arg(caCertPath));
271 #endif
272 }
273 
275 //
277 
279 {
280  QMutexLocker locker(&s_platformLock);
281  return s_platform;
282 }
283 
285 //
287 
289 {
290  QString mythVersion = GetMythSourceVersion();
291  if (mythVersion.startsWith("v"))
292  mythVersion = mythVersion.right(mythVersion.length() - 1); // Trim off the leading 'v'
293  return QString("MythTV/%2 %1 UPnP/1.0").arg(HttpServer::GetPlatform(),
294  mythVersion);
295 }
296 
298 //
300 
301 void HttpServer::newTcpConnection(qintptr socket)
302 {
304  auto *server = qobject_cast<PrivTcpServer *>(QObject::sender());
305  if (server)
306  type = server->GetServerType();
307 
309  new HttpWorker(*this, socket, type
310 #ifndef QT_NO_OPENSSL
311  , m_sslConfig
312 #endif
313  ),
314  QString("HttpServer%1").arg(socket));
315 }
316 
318 //
320 
322 {
323  if (pExtension != nullptr )
324  {
325  LOG(VB_HTTP, LOG_INFO, QString("HttpServer: Registering %1 extension").arg(pExtension->m_sName));
326  m_rwlock.lockForWrite();
327  m_extensions.append( pExtension );
328 
329  // Add to multimap for quick lookup.
330 
331  QStringList list = pExtension->GetBasePaths();
332 
333  for( const QString& base : std::as_const(list))
334  {
335  m_basePaths.insert( base, pExtension );
336  LOG(VB_HTTP, LOG_INFO, QString("HttpServer: Registering %1 extension path %2")
337  .arg(pExtension->m_sName, base));
338  }
339  m_rwlock.unlock();
340  }
341 }
342 
344 //
346 
348 {
349  if (pExtension != nullptr )
350  {
351  m_rwlock.lockForWrite();
352 
353  QStringList list = pExtension->GetBasePaths();
354 
355  for( const QString& base : std::as_const(list))
356  m_basePaths.remove( base, pExtension );
357 
358  m_extensions.removeAll(pExtension);
359 
360  delete pExtension;
361 
362  m_rwlock.unlock();
363  }
364 }
365 
367 //
369 
371 {
372  bool bProcessed = false;
373 
374  LOG(VB_HTTP, LOG_DEBUG, QString("m_sBaseUrl: %1").arg( pRequest->m_sBaseUrl ));
375  m_rwlock.lockForRead();
376 
377  QList< HttpServerExtension* > list = m_basePaths.values( pRequest->m_sBaseUrl );
378 
379  for (int nIdx=0; nIdx < list.size() && !bProcessed; nIdx++ )
380  {
381  try
382  {
383  if (pRequest->m_eType == RequestTypeOptions)
384  bProcessed = list[ nIdx ]->ProcessOptions(pRequest);
385  else
386  bProcessed = list[ nIdx ]->ProcessRequest(pRequest);
387  }
388  catch(...)
389  {
390  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer::DelegateRequest - "
391  "Unexpected Exception - "
392  "pExtension->ProcessRequest()."));
393  }
394  }
395 
396  HttpServerExtensionList::iterator it = m_extensions.begin();
397 
398  for (; (it != m_extensions.end()) && !bProcessed; ++it)
399  {
400  try
401  {
402  if (pRequest->m_eType == RequestTypeOptions)
403  bProcessed = (*it)->ProcessOptions(pRequest);
404  else
405  bProcessed = (*it)->ProcessRequest(pRequest);
406  }
407  catch(...)
408  {
409  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer::DelegateRequest - "
410  "Unexpected Exception - "
411  "pExtension->ProcessRequest()."));
412  }
413  }
414  m_rwlock.unlock();
415 
416 // if (!bProcessed)
417 // bProcessed = m_pHtmlServer->ProcessRequest(pRequest);
418 
419  if (!bProcessed)
420  {
421  pRequest->m_eResponseType = ResponseTypeHTML;
422  pRequest->m_nResponseStatus = 404;
423  pRequest->m_response.write( pRequest->GetResponsePage() );
424  }
425 }
426 
428 {
429  int timeout = -1;
430 
431  m_rwlock.lockForRead();
432  QList< HttpServerExtension* > list = m_basePaths.values( pRequest->m_sBaseUrl );
433  if (!list.isEmpty())
434  timeout = list.first()->GetSocketTimeout();
435  m_rwlock.unlock();
436 
437  if (timeout < 0)
438  timeout = gCoreContext->GetNumSetting("HTTP/KeepAliveTimeoutSecs", 10);
439 
440  return timeout;
441 }
442 
445 //
446 // HttpWorkerThread Class Implementation
447 //
450 
451 HttpWorker::HttpWorker(HttpServer &httpServer, qintptr sock,
453 #ifndef QT_NO_OPENSSL
454  , const QSslConfiguration& sslConfig
455 #endif
456 )
457  : m_httpServer(httpServer), m_socket(sock),
458  m_socketTimeout(5s), m_connectionType(type)
459 #ifndef QT_NO_OPENSSL
460  , m_sslConfig(sslConfig)
461 #endif
462 {
463  LOG(VB_HTTP, LOG_INFO, QString("HttpWorker(%1): New connection")
464  .arg(m_socket));
465 }
466 
468 //
470 
471 void HttpWorker::run(void)
472 {
473 #if 0
474  LOG(VB_HTTP, LOG_DEBUG,
475  QString("HttpWorker::run() socket=%1 -- begin").arg(m_socket));
476 #endif
477 
478  bool bTimeout = false;
479  bool bKeepAlive = true;
480  HTTPRequest *pRequest = nullptr;
481  QTcpSocket *pSocket = nullptr;
482  bool bEncrypted = false;
483 
485  {
486 
487 #ifndef QT_NO_OPENSSL
488  auto *pSslSocket = new QSslSocket();
489  if (pSslSocket->setSocketDescriptor(m_socket)
490  && gCoreContext->CheckSubnet(pSslSocket))
491  {
492  pSslSocket->setSslConfiguration(m_sslConfig);
493  pSslSocket->startServerEncryption();
494  if (pSslSocket->waitForEncrypted(5000))
495  {
496  LOG(VB_HTTP, LOG_INFO, "SSL Handshake occurred, connection encrypted");
497  LOG(VB_HTTP, LOG_INFO, QString("Using %1 cipher").arg(pSslSocket->sessionCipher().name()));
498  bEncrypted = true;
499  }
500  else
501  {
502  LOG(VB_HTTP, LOG_WARNING, "SSL Handshake FAILED, connection terminated");
503  delete pSslSocket;
504  pSslSocket = nullptr;
505  }
506  }
507  else
508  {
509  delete pSslSocket;
510  pSslSocket = nullptr;
511  }
512 
513  if (pSslSocket)
514  pSocket = pSslSocket;
515  else
516  return;
517 #else
518  return;
519 #endif
520  }
521  else // Plain old unencrypted socket
522  {
523  pSocket = new QTcpSocket();
524  pSocket->setSocketDescriptor(m_socket);
525  if (!gCoreContext->CheckSubnet(pSocket))
526  {
527  delete pSocket;
528  pSocket = nullptr;
529  return;
530  }
531 
532  }
533 
534  pSocket->setSocketOption(QAbstractSocket::KeepAliveOption, QVariant(1));
535  int nRequestsHandled = 0; // Allow debugging of keep-alive and connection re-use
536 
537  try
538  {
539  while (m_httpServer.IsRunning() && bKeepAlive && pSocket->isValid() &&
540  pSocket->state() == QAbstractSocket::ConnectedState)
541  {
542  // We set a timeout on keep-alive connections to avoid blocking
543  // new clients from connecting - Default at time of writing was
544  // 5 seconds for initial connection, then up to 10 seconds of idle
545  // time between each subsequent request on the same connection
546  bTimeout = !(pSocket->waitForReadyRead(m_socketTimeout.count()));
547 
548  if (bTimeout) // Either client closed the socket or we timed out waiting for new data
549  break;
550 
551  int64_t nBytes = pSocket->bytesAvailable();
552  if (!m_httpServer.IsRunning())
553  break;
554 
555  if ( nBytes > 0)
556  {
557  // ----------------------------------------------------------
558  // See if this is a valid request
559  // ----------------------------------------------------------
560 
561  pRequest = new BufferedSocketDeviceRequest( pSocket );
562  if (pRequest != nullptr)
563  {
564  pRequest->m_bEncrypted = bEncrypted;
565  if ( pRequest->ParseRequest() )
566  {
567  bKeepAlive = pRequest->GetKeepAlive();
568  // The timeout is defined by the Server/Server Extension
569  // but must appear in the response headers
570  auto nTimeout = std::chrono::seconds(m_httpServer.GetSocketTimeout(pRequest));
571  pRequest->SetKeepAliveTimeout(nTimeout);
572  m_socketTimeout = nTimeout; // Converts to milliseconds
573 
574  // ------------------------------------------------------
575  // Request Parsed... Pass on to Main HttpServer class to
576  // delegate processing to HttpServerExtensions.
577  // ------------------------------------------------------
578  if ((pRequest->m_nResponseStatus != 400) &&
579  (pRequest->m_nResponseStatus != 401) &&
580  (pRequest->m_nResponseStatus != 403) &&
581  pRequest->m_eType != RequestTypeUnknown)
582  m_httpServer.DelegateRequest(pRequest);
583 
584  nRequestsHandled++;
585  }
586  else
587  {
588  LOG(VB_HTTP, LOG_ERR, "ParseRequest Failed.");
589 
590  pRequest->m_nResponseStatus = 501;
591  pRequest->m_response.write( pRequest->GetResponsePage() );
592  bKeepAlive = false;
593  }
594 
595  // -------------------------------------------------------
596  // Always MUST send a response.
597  // -------------------------------------------------------
598  if (pRequest->SendResponse() < 0)
599  {
600  bKeepAlive = false;
601  LOG(VB_HTTP, LOG_ERR,
602  QString("socket(%1) - Error returned from "
603  "SendResponse... Closing connection")
604  .arg(pSocket->socketDescriptor()));
605  }
606 
607  // -------------------------------------------------------
608  // Check to see if a PostProcess was registered
609  // -------------------------------------------------------
610  if ( pRequest->m_pPostProcess != nullptr )
611  pRequest->m_pPostProcess->ExecutePostProcess();
612 
613  delete pRequest;
614  pRequest = nullptr;
615  }
616  else
617  {
618  LOG(VB_GENERAL, LOG_ERR,
619  "Error Creating BufferedSocketDeviceRequest");
620  bKeepAlive = false;
621  }
622  }
623  else
624  {
625  bKeepAlive = false;
626  }
627  }
628  }
629  catch(...)
630  {
631  LOG(VB_GENERAL, LOG_ERR,
632  "HttpWorkerThread::ProcessWork - Unexpected Exception.");
633  }
634 
635  delete pRequest;
636 
637  if ((pSocket->error() != QAbstractSocket::UnknownSocketError) &&
638  (!bKeepAlive || pSocket->error() != QAbstractSocket::SocketTimeoutError)) // This 'error' isn't an error when keep-alive is active
639  {
640  LOG(VB_HTTP, LOG_WARNING, QString("HttpWorker(%1): Error %2 (%3)")
641  .arg(m_socket)
642  .arg(pSocket->errorString())
643  .arg(pSocket->error()));
644  }
645 
646  std::chrono::milliseconds writeTimeout = 5s;
647  // Make sure any data in the buffer is flushed before the socket is closed
648  while (m_httpServer.IsRunning() &&
649  pSocket->isValid() &&
650  pSocket->state() == QAbstractSocket::ConnectedState &&
651  pSocket->bytesToWrite() > 0)
652  {
653  LOG(VB_HTTP, LOG_DEBUG, QString("HttpWorker(%1): "
654  "Waiting for %2 bytes to be written "
655  "before closing the connection.")
656  .arg(m_socket)
657  .arg(pSocket->bytesToWrite()));
658 
659  // If the client stops reading for longer than 'writeTimeout' then
660  // stop waiting for them. We can't afford to leave the socket
661  // connected indefinately, it could be used by another client.
662  //
663  // NOTE: Some clients deliberately stall as a way of 'pausing' A/V
664  // streaming. We should create a new server extension or adjust the
665  // timeout according to the User-Agent, instead of increasing the
666  // standard timeout. However we should ALWAYS have a timeout.
667  if (!pSocket->waitForBytesWritten(writeTimeout.count()))
668  {
669  LOG(VB_GENERAL, LOG_WARNING, QString("HttpWorker(%1): "
670  "Timed out waiting to write bytes to "
671  "the socket, waited %2 seconds")
672  .arg(m_socket)
673  .arg(writeTimeout.count() / 1000));
674  break;
675  }
676  }
677 
678  if (pSocket->bytesToWrite() > 0)
679  {
680  LOG(VB_HTTP, LOG_WARNING, QString("HttpWorker(%1): "
681  "Failed to write %2 bytes to "
682  "socket, (%3)")
683  .arg(m_socket)
684  .arg(pSocket->bytesToWrite())
685  .arg(pSocket->errorString()));
686  }
687 
688  LOG(VB_HTTP, LOG_INFO, QString("HttpWorker(%1): Connection %2 closed. %3 requests were handled")
689  .arg(m_socket)
690  .arg(pSocket->socketDescriptor())
691  .arg(nRequestsHandled));
692 
693  pSocket->close();
694  delete pSocket;
695  pSocket = nullptr;
696 
697 #if 0
698  LOG(VB_HTTP, LOG_DEBUG, "HttpWorkerThread::run() -- end");
699 #endif
700 }
701 
702 
HTTPRequest::m_sBaseUrl
QString m_sBaseUrl
Definition: httprequest.h:127
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:93
HttpServerExtension::m_nSupportedMethods
uint m_nSupportedMethods
Definition: httpserver.h:83
HTTPRequest
Definition: httprequest.h:109
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:102
ServerPool::setMaxPendingConnections
void setMaxPendingConnections(int n)
Definition: serverpool.h:94
HttpWorker
Definition: httpserver.h:177
HttpWorker::m_sslConfig
QSslConfiguration m_sslConfig
Definition: httpserver.h:202
HTTPRequest::SetKeepAliveTimeout
void SetKeepAliveTimeout(std::chrono::seconds nTimeout)
Definition: httprequest.h:257
HttpServer::GetServerVersion
static QString GetServerVersion(void)
Definition: httpserver.cpp:288
HttpServer::IsRunning
bool IsRunning(void) const
Definition: httpserver.h:133
HTTPRequest::ParseRequest
bool ParseRequest()
Definition: httprequest.cpp:1202
HttpServer::m_sSharePath
QString m_sSharePath
Definition: httpserver.h:149
RequestTypeUnknown
@ RequestTypeUnknown
Definition: httprequest.h:46
RequestTypeGet
@ RequestTypeGet
Definition: httprequest.h:48
MThreadPool::maxThreadCount
int maxThreadCount(void) const
Definition: mthreadpool.cpp:512
HttpServer::RegisterExtension
void RegisterExtension(HttpServerExtension *pExtension)
Definition: httpserver.cpp:321
HttpServer::LoadSSLConfig
void LoadSSLConfig()
Definition: httpserver.cpp:184
GetMythSourceVersion
const char * GetMythSourceVersion()
Definition: mythversion.cpp:5
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
HttpServer::newTcpConnection
void newTcpConnection(qintptr socket) override
Definition: httpserver.cpp:301
HttpWorker::run
void run(void) override
Definition: httpserver.cpp:471
mythdirs.h
HttpServerExtension::ProcessOptions
virtual bool ProcessOptions(HTTPRequest *pRequest)
Handle an OPTIONS request.
Definition: httpserver.cpp:52
HttpServer::s_platform
static QString s_platform
Definition: httpserver.h:154
MThreadPool::Stop
void Stop(void)
Definition: mthreadpool.cpp:267
MThreadPool::startReserved
void startReserved(QRunnable *runnable, const QString &debugName, std::chrono::milliseconds waitForAvailMS=0ms)
Definition: mthreadpool.cpp:361
HttpWorker::m_httpServer
HttpServer & m_httpServer
Definition: httpserver.h:196
RequestTypePost
@ RequestTypePost
Definition: httprequest.h:50
RttiServiceHost
Definition: rttiServiceHost.h:42
kSSLServer
@ kSSLServer
Definition: serverpool.h:33
PoolServerType
PoolServerType
Definition: serverpool.h:29
upnp.h
HttpServer::m_rwlock
QReadWriteLock m_rwlock
Definition: httpserver.h:145
HTTPRequest::m_nResponseStatus
long m_nResponseStatus
Definition: httprequest.h:152
mythlogging.h
HttpServer::GetPlatform
static QString GetPlatform(void)
Definition: httpserver.cpp:278
HTTPRequest::GetResponsePage
QByteArray GetResponsePage(void)
Definition: httprequest.cpp:957
HTTPRequest::m_bEncrypted
bool m_bEncrypted
Definition: httprequest.h:142
compat.h
HTTPRequest::m_pPostProcess
IPostProcess * m_pPostProcess
Definition: httprequest.h:159
RequestTypeUnsubscribe
@ RequestTypeUnsubscribe
Definition: httprequest.h:59
RequestTypeMSearch
@ RequestTypeMSearch
Definition: httprequest.h:57
HttpServer::m_running
bool m_running
Definition: httpserver.h:151
GetShareDir
QString GetShareDir(void)
Definition: mythdirs.cpp:261
ResponseTypeHeader
@ ResponseTypeHeader
Definition: httprequest.h:86
HttpServer::m_threadPool
MThreadPool m_threadPool
Definition: httpserver.h:150
IPostProcess::ExecutePostProcess
virtual void ExecutePostProcess()=0
kTCPServer
@ kTCPServer
Definition: serverpool.h:31
HttpServer::UnregisterExtension
void UnregisterExtension(HttpServerExtension *pExtension)
Definition: httpserver.cpp:347
RequestTypeNotify
@ RequestTypeNotify
Definition: httprequest.h:60
htmlserver.h
HttpWorker::m_connectionType
PoolServerType m_connectionType
Definition: httpserver.h:199
rttiServiceHost.h
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
RequestTypeOptions
@ RequestTypeOptions
Definition: httprequest.h:54
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:916
ResponseTypeHTML
@ ResponseTypeHTML
Definition: httprequest.h:79
RequestTypeHead
@ RequestTypeHead
Definition: httprequest.h:49
HttpServer::HttpServer
HttpServer()
Definition: httpserver.cpp:116
HttpServer::GetSocketTimeout
uint GetSocketTimeout(HTTPRequest *pRequest) const
Get the idle socket timeout value for the relevant extension.
Definition: httpserver.cpp:427
BufferedSocketDeviceRequest
Definition: httprequest.h:278
HttpServerExtension::GetBasePaths
virtual QStringList GetBasePaths()=0
mythcorecontext.h
HTTPRequest::SetResponseHeader
void SetResponseHeader(const QString &sKey, const QString &sValue, bool replace=false)
Definition: httprequest.cpp:2100
HttpServer::m_basePaths
QMultiMap< QString, HttpServerExtension * > m_basePaths
Definition: httpserver.h:148
HTTPRequest::m_eResponseType
HttpResponseType m_eResponseType
Definition: httprequest.h:149
HttpWorker::m_socket
qintptr m_socket
Definition: httpserver.h:197
HttpServer::~HttpServer
~HttpServer() override
Definition: httpserver.cpp:170
HttpServer::m_sslConfig
QSslConfiguration m_sslConfig
Definition: httpserver.h:157
HTTPRequest::GetKeepAlive
bool GetKeepAlive() const
Definition: httprequest.h:237
HttpServer
Definition: httpserver.h:112
HttpServer::m_extensions
HttpServerExtensionList m_extensions
Definition: httpserver.h:146
httpserver.h
MThreadPool::setMaxThreadCount
void setMaxThreadCount(int maxThreadCount)
Definition: mthreadpool.cpp:518
HttpServer::s_platformLock
static QMutex s_platformLock
Definition: httpserver.h:153
HttpWorker::HttpWorker
HttpWorker(HttpServer &httpServer, qintptr sock, PoolServerType type, const QSslConfiguration &sslConfig)
Definition: httpserver.cpp:451
HttpServer::DelegateRequest
void DelegateRequest(HTTPRequest *pRequest)
Definition: httpserver.cpp:370
HTTPRequest::SendResponse
qint64 SendResponse(void)
Definition: httprequest.cpp:301
HttpServerExtension::m_sName
QString m_sName
Definition: httpserver.h:77
HttpServerExtension
Definition: httpserver.h:71
HttpWorker::m_socketTimeout
std::chrono::milliseconds m_socketTimeout
Definition: httpserver.h:198
upnputil.h
MythCoreContext::CheckSubnet
bool CheckSubnet(const QAbstractSocket *socket)
Check if a socket is connected to an approved peer.
Definition: mythcorecontext.cpp:1276
RequestTypeSubscribe
@ RequestTypeSubscribe
Definition: httprequest.h:58
HTTPRequest::m_response
QBuffer m_response
Definition: httprequest.h:157
uint
unsigned int uint
Definition: freesurround.h:24
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:902
HTTPRequest::m_eType
HttpRequestType m_eType
Definition: httprequest.h:120