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 COPYING 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 #include <QScriptEngine>
28 #include <QSslConfiguration>
29 #include <QSslSocket>
30 #include <QSslCipher>
31 #include <QSslCertificate>
32 #include <QUuid>
33 
34 // MythTV headers
35 #include "upnputil.h"
36 #include "upnp.h" // only needed for Config... remove once config is moved.
37 #include "compat.h"
38 #include "mythdirs.h"
39 #include "mythlogging.h"
40 #include "htmlserver.h"
41 #include "mythversion.h"
42 #include "mythcorecontext.h"
43 
45 
46 using namespace std;
47 
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;
62  if (m_nSupportedMethods & RequestTypeGet)
63  allowedMethods.append("GET");
64  if (m_nSupportedMethods & RequestTypeHead)
65  allowedMethods.append("HEAD");
66  if (m_nSupportedMethods & RequestTypePost)
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");
74  if (m_nSupportedMethods & RequestTypeOptions)
75  allowedMethods.append("OPTIONS");
76 // if (m_nSupportedMethods & RequestTypeTrace)
77 // allowedMethods.append("TRACE");
78  if (m_nSupportedMethods & RequestTypeMSearch)
79  allowedMethods.append("M-SEARCH");
80  if (m_nSupportedMethods & RequestTypeSubscribe)
81  allowedMethods.append("SUBSCRIBE");
82  if (m_nSupportedMethods & RequestTypeUnsubscribe)
83  allowedMethods.append("UNSUBSCRIBE");
84  if (m_nSupportedMethods & RequestTypeNotify)
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"), m_running(true),
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 = 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).arg(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 #if QT_VERSION < QT_VERSION_CHECK(5,5,0)
194  QList<QSslCipher> availableCiphers = QSslSocket::supportedCiphers();
195 #else
196  QList<QSslCipher> availableCiphers = QSslConfiguration::supportedCiphers();
197 #endif
198  QList<QSslCipher> secureCiphers;
199  QList<QSslCipher>::iterator it;
200  for (it = availableCiphers.begin(); it != availableCiphers.end(); ++it)
201  {
202  // Remove weak ciphers from the cipher list
203  if ((*it).usedBits() < 128)
204  continue;
205 
206  if ((*it).name().startsWith("RC4") || // Weak cipher
207  (*it).name().startsWith("EXP") || // Weak authentication
208  (*it).name().startsWith("ADH") || // No authentication
209  (*it).name().contains("NULL")) // No encryption
210  continue;
211 
212  secureCiphers.append(*it);
213  }
214  m_sslConfig.setCiphers(secureCiphers);
215 #endif
216 
217  QString hostKeyPath = gCoreContext->GetSetting("hostSSLKey", "");
218 
219  if (hostKeyPath.isEmpty()) // No key, assume no SSL
220  return;
221 
222  QFile hostKeyFile(hostKeyPath);
223  if (!hostKeyFile.exists() || !hostKeyFile.open(QIODevice::ReadOnly))
224  {
225  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer: SSL Host key file (%1) does not exist or is not readable").arg(hostKeyPath));
226  return;
227  }
228 
229 #ifndef QT_NO_OPENSSL
230  QByteArray rawHostKey = hostKeyFile.readAll();
231  QSslKey hostKey = QSslKey(rawHostKey, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
232  if (!hostKey.isNull())
233  m_sslConfig.setPrivateKey(hostKey);
234  else
235  {
236  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer: Unable to load host key from file (%1)").arg(hostKeyPath));
237  return;
238  }
239 
240  QString hostCertPath = gCoreContext->GetSetting("hostSSLCertificate", "");
241  QSslCertificate hostCert;
242  QList<QSslCertificate> certList = QSslCertificate::fromPath(hostCertPath);
243  if (!certList.isEmpty())
244  hostCert = certList.first();
245 
246  if (!hostCert.isNull())
247  {
248  if (hostCert.effectiveDate() > QDateTime::currentDateTime())
249  {
250  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer: Host certificate start date in future (%1)").arg(hostCertPath));
251  return;
252  }
253 
254  if (hostCert.expiryDate() < QDateTime::currentDateTime())
255  {
256  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer: Host certificate has expired (%1)").arg(hostCertPath));
257  return;
258  }
259 
260  m_sslConfig.setLocalCertificate(hostCert);
261  }
262  else
263  {
264  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer: Unable to load host cert from file (%1)").arg(hostCertPath));
265  return;
266  }
267 
268  QString caCertPath = gCoreContext->GetSetting("caSSLCertificate", "");
269  QList< QSslCertificate > CACertList = QSslCertificate::fromPath(caCertPath);
270 
271  if (!CACertList.isEmpty())
272  m_sslConfig.setCaCertificates(CACertList);
273  else if (!caCertPath.isEmpty()) // Only warn if a path was actually configured, this isn't an error otherwise
274  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer: Unable to load CA cert file (%1)").arg(caCertPath));
275 #endif
276 }
277 
279 //
281 
283 {
284  QMutexLocker locker(&s_platformLock);
285  return s_platform;
286 }
287 
289 //
291 
293 {
294  QString mythVersion = MYTH_SOURCE_VERSION;
295  if (mythVersion.startsWith("v"))
296  mythVersion = mythVersion.right(mythVersion.length() - 1); // Trim off the leading 'v'
297  return QString("MythTV/%2 %1 UPnP/1.0").arg(HttpServer::GetPlatform())
298  .arg(mythVersion);
299 }
300 
302 //
304 
306 {
308  PrivTcpServer *server = dynamic_cast<PrivTcpServer *>(QObject::sender());
309  if (server)
310  type = server->GetServerType();
311 
313  new HttpWorker(*this, socket, type
314 #ifndef QT_NO_OPENSSL
315  , m_sslConfig
316 #endif
317  ),
318  QString("HttpServer%1").arg(socket));
319 }
320 
322 //
324 
326 {
327  if (pExtension != nullptr )
328  {
329  LOG(VB_HTTP, LOG_INFO, QString("HttpServer: Registering %1 extension").arg(pExtension->m_sName));
330  m_rwlock.lockForWrite();
331  m_extensions.append( pExtension );
332 
333  // Add to multimap for quick lookup.
334 
335  QStringList list = pExtension->GetBasePaths();
336 
337  for( int nIdx = 0; nIdx < list.size(); nIdx++)
338  m_basePaths.insert( list[ nIdx ], pExtension );
339 
340  m_rwlock.unlock();
341  }
342 }
343 
345 //
347 
349 {
350  if (pExtension != nullptr )
351  {
352  m_rwlock.lockForWrite();
353 
354  QStringList list = pExtension->GetBasePaths();
355 
356  for( int nIdx = 0; nIdx < list.size(); nIdx++)
357  m_basePaths.remove( list[ nIdx ], pExtension );
358 
359  m_extensions.removeAll(pExtension);
360 
361  delete pExtension;
362 
363  m_rwlock.unlock();
364  }
365 }
366 
368 //
370 
372 {
373  bool bProcessed = false;
374 
375  LOG(VB_HTTP, LOG_DEBUG, QString("m_sBaseUrl: %1").arg( pRequest->m_sBaseUrl ));
376  m_rwlock.lockForRead();
377 
378  QList< HttpServerExtension* > list = m_basePaths.values( pRequest->m_sBaseUrl );
379 
380  for (int nIdx=0; nIdx < list.size() && !bProcessed; nIdx++ )
381  {
382  try
383  {
384  if (pRequest->m_eType == RequestTypeOptions)
385  bProcessed = list[ nIdx ]->ProcessOptions(pRequest);
386  else
387  bProcessed = list[ nIdx ]->ProcessRequest(pRequest);
388  }
389  catch(...)
390  {
391  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer::DelegateRequest - "
392  "Unexpected Exception - "
393  "pExtension->ProcessRequest()."));
394  }
395  }
396 
397  HttpServerExtensionList::iterator it = m_extensions.begin();
398 
399  for (; (it != m_extensions.end()) && !bProcessed; ++it)
400  {
401  try
402  {
403  if (pRequest->m_eType == RequestTypeOptions)
404  bProcessed = (*it)->ProcessOptions(pRequest);
405  else
406  bProcessed = (*it)->ProcessRequest(pRequest);
407  }
408  catch(...)
409  {
410  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer::DelegateRequest - "
411  "Unexpected Exception - "
412  "pExtension->ProcessRequest()."));
413  }
414  }
415  m_rwlock.unlock();
416 
417 // if (!bProcessed)
418 // bProcessed = m_pHtmlServer->ProcessRequest(pRequest);
419 
420  if (!bProcessed)
421  {
422  pRequest->m_eResponseType = ResponseTypeHTML;
423  pRequest->m_nResponseStatus = 404;
424  pRequest->m_response.write( pRequest->GetResponsePage() );
425  }
426 }
427 
429 {
430  int timeout = -1;
431 
432  m_rwlock.lockForRead();
433  QList< HttpServerExtension* > list = m_basePaths.values( pRequest->m_sBaseUrl );
434  if (!list.isEmpty())
435  timeout = list.first()->GetSocketTimeout();
436  m_rwlock.unlock();
437 
438  if (timeout < 0)
439  timeout = gCoreContext->GetNumSetting("HTTP/KeepAliveTimeoutSecs", 10);
440 
441  return timeout;
442 }
443 
446 //
447 // HttpWorkerThread Class Implementation
448 //
451 
454 #ifndef QT_NO_OPENSSL
455  , const QSslConfiguration& sslConfig
456 #endif
457 )
458  : m_httpServer(httpServer), m_socket(sock),
459  m_socketTimeout(5 * 1000), m_connectionType(type)
460 #ifndef QT_NO_OPENSSL
461  , m_sslConfig(sslConfig)
462 #endif
463 {
464  LOG(VB_HTTP, LOG_INFO, QString("HttpWorker(%1): New connection")
465  .arg(m_socket));
466 }
467 
469 //
471 
472 void HttpWorker::run(void)
473 {
474 #if 0
475  LOG(VB_HTTP, LOG_DEBUG,
476  QString("HttpWorker::run() socket=%1 -- begin").arg(m_socket));
477 #endif
478 
479  bool bTimeout = false;
480  bool bKeepAlive = true;
481  HTTPRequest *pRequest = nullptr;
482  QTcpSocket *pSocket;
483  bool bEncrypted = false;
484 
486  {
487 
488 #ifndef QT_NO_OPENSSL
489  QSslSocket *pSslSocket = new QSslSocket();
490  if (pSslSocket->setSocketDescriptor(m_socket)
491  && gCoreContext->CheckSubnet(pSslSocket))
492  {
493  pSslSocket->setSslConfiguration(m_sslConfig);
494  pSslSocket->startServerEncryption();
495  if (pSslSocket->waitForEncrypted(5000))
496  {
497  LOG(VB_HTTP, LOG_INFO, "SSL Handshake occurred, connection encrypted");
498  LOG(VB_HTTP, LOG_INFO, QString("Using %1 cipher").arg(pSslSocket->sessionCipher().name()));
499  bEncrypted = true;
500  }
501  else
502  {
503  LOG(VB_HTTP, LOG_WARNING, "SSL Handshake FAILED, connection terminated");
504  delete pSslSocket;
505  pSslSocket = nullptr;
506  }
507  }
508  else
509  {
510  delete pSslSocket;
511  pSslSocket = nullptr;
512  }
513 
514  if (pSslSocket)
515  pSocket = dynamic_cast<QTcpSocket *>(pSslSocket);
516  else
517  return;
518 #else
519  return;
520 #endif
521  }
522  else // Plain old unencrypted socket
523  {
524  pSocket = new QTcpSocket();
525  pSocket->setSocketDescriptor(m_socket);
526  if (!gCoreContext->CheckSubnet(pSocket))
527  {
528  delete pSocket;
529  pSocket = nullptr;
530  return;
531  }
532 
533  }
534 
535  pSocket->setSocketOption(QAbstractSocket::KeepAliveOption, QVariant(1));
536  int nRequestsHandled = 0; // Allow debugging of keep-alive and connection re-use
537 
538  try
539  {
540  while (m_httpServer.IsRunning() && bKeepAlive && pSocket->isValid() &&
541  pSocket->state() == QAbstractSocket::ConnectedState)
542  {
543  // We set a timeout on keep-alive connections to avoid blocking
544  // new clients from connecting - Default at time of writing was
545  // 5 seconds for initial connection, then up to 10 seconds of idle
546  // time between each subsequent request on the same connection
547  bTimeout = !(pSocket->waitForReadyRead(m_socketTimeout));
548 
549  if (bTimeout) // Either client closed the socket or we timed out waiting for new data
550  break;
551 
552  int64_t nBytes = pSocket->bytesAvailable();
553  if (!m_httpServer.IsRunning())
554  break;
555 
556  if ( nBytes > 0)
557  {
558  // ----------------------------------------------------------
559  // See if this is a valid request
560  // ----------------------------------------------------------
561 
562  pRequest = new BufferedSocketDeviceRequest( pSocket );
563  if (pRequest != nullptr)
564  {
565  pRequest->m_bEncrypted = bEncrypted;
566  if ( pRequest->ParseRequest() )
567  {
568  bKeepAlive = pRequest->GetKeepAlive();
569  // The timeout is defined by the Server/Server Extension
570  // but must appear in the response headers
571  uint nTimeout = m_httpServer.GetSocketTimeout(pRequest); // Seconds
572  pRequest->SetKeepAliveTimeout(nTimeout);
573  m_socketTimeout = nTimeout * 1000; // Milliseconds
574 
575  // ------------------------------------------------------
576  // Request Parsed... Pass on to Main HttpServer class to
577  // delegate processing to HttpServerExtensions.
578  // ------------------------------------------------------
579  if ((pRequest->m_nResponseStatus != 400) &&
580  (pRequest->m_nResponseStatus != 401) &&
581  (pRequest->m_nResponseStatus != 403) &&
582  pRequest->m_eType != RequestTypeUnknown)
583  m_httpServer.DelegateRequest(pRequest);
584 
585  nRequestsHandled++;
586  }
587  else
588  {
589  LOG(VB_HTTP, LOG_ERR, "ParseRequest Failed.");
590 
591  pRequest->m_nResponseStatus = 501;
592  pRequest->m_response.write( pRequest->GetResponsePage() );
593  bKeepAlive = false;
594  }
595 
596  // -------------------------------------------------------
597  // Always MUST send a response.
598  // -------------------------------------------------------
599  if (pRequest->SendResponse() < 0)
600  {
601  bKeepAlive = false;
602  LOG(VB_HTTP, LOG_ERR,
603  QString("socket(%1) - Error returned from "
604  "SendResponse... Closing connection")
605  .arg(pSocket->socketDescriptor()));
606  }
607 
608  // -------------------------------------------------------
609  // Check to see if a PostProcess was registered
610  // -------------------------------------------------------
611  if ( pRequest->m_pPostProcess != nullptr )
612  pRequest->m_pPostProcess->ExecutePostProcess();
613 
614  delete pRequest;
615  pRequest = nullptr;
616  }
617  else
618  {
619  LOG(VB_GENERAL, LOG_ERR,
620  "Error Creating BufferedSocketDeviceRequest");
621  bKeepAlive = false;
622  }
623  }
624  else
625  {
626  bKeepAlive = false;
627  }
628  }
629  }
630  catch(...)
631  {
632  LOG(VB_GENERAL, LOG_ERR,
633  "HttpWorkerThread::ProcessWork - Unexpected Exception.");
634  }
635 
636  delete pRequest;
637 
638  if ((pSocket->error() != QAbstractSocket::UnknownSocketError) &&
639  !(bKeepAlive && pSocket->error() == QAbstractSocket::SocketTimeoutError)) // This 'error' isn't an error when keep-alive is active
640  {
641  LOG(VB_HTTP, LOG_WARNING, QString("HttpWorker(%1): Error %2 (%3)")
642  .arg(m_socket)
643  .arg(pSocket->errorString())
644  .arg(pSocket->error()));
645  }
646 
647  int writeTimeout = 5000; // 5 Seconds
648  // Make sure any data in the buffer is flushed before the socket is closed
649  while (m_httpServer.IsRunning() &&
650  pSocket->isValid() &&
651  pSocket->state() == QAbstractSocket::ConnectedState &&
652  pSocket->bytesToWrite() > 0)
653  {
654  LOG(VB_HTTP, LOG_DEBUG, QString("HttpWorker(%1): "
655  "Waiting for %2 bytes to be written "
656  "before closing the connection.")
657  .arg(m_socket)
658  .arg(pSocket->bytesToWrite()));
659 
660  // If the client stops reading for longer than 'writeTimeout' then
661  // stop waiting for them. We can't afford to leave the socket
662  // connected indefinately, it could be used by another client.
663  //
664  // NOTE: Some clients deliberately stall as a way of 'pausing' A/V
665  // streaming. We should create a new server extension or adjust the
666  // timeout according to the User-Agent, instead of increasing the
667  // standard timeout. However we should ALWAYS have a timeout.
668  if (!pSocket->waitForBytesWritten(writeTimeout))
669  {
670  LOG(VB_GENERAL, LOG_WARNING, QString("HttpWorker(%1): "
671  "Timed out waiting to write bytes to "
672  "the socket, waited %2 seconds")
673  .arg(m_socket)
674  .arg(writeTimeout / 1000));
675  break;
676  }
677  }
678 
679  if (pSocket->bytesToWrite() > 0)
680  {
681  LOG(VB_HTTP, LOG_WARNING, QString("HttpWorker(%1): "
682  "Failed to write %2 bytes to "
683  "socket, (%3)")
684  .arg(m_socket)
685  .arg(pSocket->bytesToWrite())
686  .arg(pSocket->errorString()));
687  }
688 
689  LOG(VB_HTTP, LOG_INFO, QString("HttpWorker(%1): Connection %2 closed. %3 requests were handled")
690  .arg(m_socket)
691  .arg(pSocket->socketDescriptor())
692  .arg(nRequestsHandled));
693 
694  pSocket->close();
695  delete pSocket;
696  pSocket = nullptr;
697 
698 #if 0
699  LOG(VB_HTTP, LOG_DEBUG, "HttpWorkerThread::run() -- end");
700 #endif
701 }
702 
703 
void setMaxThreadCount(int maxThreadCount)
int maxThreadCount(void) const
static QMutex s_platformLock
Definition: httpserver.h:153
MThreadPool m_threadPool
Definition: httpserver.h:150
QString m_sBaseUrl
Definition: httprequest.h:123
void startReserved(QRunnable *runnable, QString debugName, int waitForAvailMS=0)
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
void UnregisterExtension(HttpServerExtension *)
Definition: httpserver.cpp:348
HttpServerExtensionList m_extensions
Definition: httpserver.h:146
static QString s_platform
Definition: httpserver.h:154
QString toString(MarkTypes type)
void Stop(void)
PoolServerType m_connectionType
Definition: httpserver.h:199
virtual ~HttpServer()
Definition: httpserver.cpp:170
void RegisterExtension(HttpServerExtension *)
Definition: httpserver.cpp:325
long m_nResponseStatus
Definition: httprequest.h:148
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
bool ParseRequest()
QMultiMap< QString, HttpServerExtension * > m_basePaths
Definition: httpserver.h:148
PoolServerType GetServerType(void)
Definition: serverpool.h:47
qintptr qt_socket_fd_t
Definition: mythqtcompat.h:4
void LoadSSLConfig()
Definition: httpserver.cpp:184
QSslConfiguration m_sslConfig
Definition: httpserver.h:202
bool IsRunning(void) const
Definition: httpserver.h:133
int m_socketTimeout
Definition: httpserver.h:198
QByteArray GetResponsePage(void)
bool m_bEncrypted
Definition: httprequest.h:138
void SetKeepAliveTimeout(int nTimeout)
Definition: httprequest.h:252
IPostProcess * m_pPostProcess
Definition: httprequest.h:155
uint GetSocketTimeout(HTTPRequest *) const
Get the idle socket timeout value for the relevant extension.
Definition: httpserver.cpp:428
bool GetKeepAlive()
Definition: httprequest.h:233
qt_socket_fd_t m_socket
Definition: httpserver.h:197
QString GetSetting(const QString &key, const QString &defaultval="")
QString GetShareDir(void)
Definition: mythdirs.cpp:222
void run(void) override
Definition: httpserver.cpp:472
HttpWorker(HttpServer &httpServer, qt_socket_fd_t sock, PoolServerType type, const QSslConfiguration &sslConfig)
Definition: httpserver.cpp:452
void SetResponseHeader(const QString &sKey, const QString &sValue, bool replace=false)
QSslConfiguration m_sslConfig
Definition: httpserver.h:157
int GetNumSetting(const QString &key, int defaultval=0)
HttpServer & m_httpServer
Definition: httpserver.h:196
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
enum PoolServerTypes PoolServerType
virtual void ExecutePostProcess()=0
QReadWriteLock m_rwlock
Definition: httpserver.h:145
QString m_sSharePath
Definition: httpserver.h:149
virtual bool ProcessOptions(HTTPRequest *pRequest)
Handle an OPTIONS request.
Definition: httpserver.cpp:52
static QString GetPlatform(void)
Definition: httpserver.cpp:282
virtual QStringList GetBasePaths()=0
QBuffer m_response
Definition: httprequest.h:153
void setMaxPendingConnections(int n)
Definition: serverpool.h:94
HttpResponseType m_eResponseType
Definition: httprequest.h:145
qint64 SendResponse(void)
static QString GetServerVersion(void)
Definition: httpserver.cpp:292
void DelegateRequest(HTTPRequest *)
Definition: httpserver.cpp:371
bool m_running
Definition: httpserver.h:151
HttpRequestType m_eType
Definition: httprequest.h:116
void newTcpConnection(qt_socket_fd_t socket) override
Definition: httpserver.cpp:305
bool CheckSubnet(const QAbstractSocket *socket)
Check if a socket is connected to an approved peer.