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  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 = MYTH_SOURCE_VERSION;
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  .arg(mythVersion);
295 }
296 
298 //
300 
302 {
304  auto *server = dynamic_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( int nIdx = 0; nIdx < list.size(); nIdx++)
334  m_basePaths.insert( list[ nIdx ], pExtension );
335 
336  m_rwlock.unlock();
337  }
338 }
339 
341 //
343 
345 {
346  if (pExtension != nullptr )
347  {
348  m_rwlock.lockForWrite();
349 
350  QStringList list = pExtension->GetBasePaths();
351 
352  for( int nIdx = 0; nIdx < list.size(); nIdx++)
353  m_basePaths.remove( list[ nIdx ], pExtension );
354 
355  m_extensions.removeAll(pExtension);
356 
357  delete pExtension;
358 
359  m_rwlock.unlock();
360  }
361 }
362 
364 //
366 
368 {
369  bool bProcessed = false;
370 
371  LOG(VB_HTTP, LOG_DEBUG, QString("m_sBaseUrl: %1").arg( pRequest->m_sBaseUrl ));
372  m_rwlock.lockForRead();
373 
374  QList< HttpServerExtension* > list = m_basePaths.values( pRequest->m_sBaseUrl );
375 
376  for (int nIdx=0; nIdx < list.size() && !bProcessed; nIdx++ )
377  {
378  try
379  {
380  if (pRequest->m_eType == RequestTypeOptions)
381  bProcessed = list[ nIdx ]->ProcessOptions(pRequest);
382  else
383  bProcessed = list[ nIdx ]->ProcessRequest(pRequest);
384  }
385  catch(...)
386  {
387  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer::DelegateRequest - "
388  "Unexpected Exception - "
389  "pExtension->ProcessRequest()."));
390  }
391  }
392 
393  HttpServerExtensionList::iterator it = m_extensions.begin();
394 
395  for (; (it != m_extensions.end()) && !bProcessed; ++it)
396  {
397  try
398  {
399  if (pRequest->m_eType == RequestTypeOptions)
400  bProcessed = (*it)->ProcessOptions(pRequest);
401  else
402  bProcessed = (*it)->ProcessRequest(pRequest);
403  }
404  catch(...)
405  {
406  LOG(VB_GENERAL, LOG_ERR, QString("HttpServer::DelegateRequest - "
407  "Unexpected Exception - "
408  "pExtension->ProcessRequest()."));
409  }
410  }
411  m_rwlock.unlock();
412 
413 // if (!bProcessed)
414 // bProcessed = m_pHtmlServer->ProcessRequest(pRequest);
415 
416  if (!bProcessed)
417  {
418  pRequest->m_eResponseType = ResponseTypeHTML;
419  pRequest->m_nResponseStatus = 404;
420  pRequest->m_response.write( pRequest->GetResponsePage() );
421  }
422 }
423 
425 {
426  int timeout = -1;
427 
428  m_rwlock.lockForRead();
429  QList< HttpServerExtension* > list = m_basePaths.values( pRequest->m_sBaseUrl );
430  if (!list.isEmpty())
431  timeout = list.first()->GetSocketTimeout();
432  m_rwlock.unlock();
433 
434  if (timeout < 0)
435  timeout = gCoreContext->GetNumSetting("HTTP/KeepAliveTimeoutSecs", 10);
436 
437  return timeout;
438 }
439 
442 //
443 // HttpWorkerThread Class Implementation
444 //
447 
450 #ifndef QT_NO_OPENSSL
451  , const QSslConfiguration& sslConfig
452 #endif
453 )
454  : m_httpServer(httpServer), m_socket(sock),
455  m_socketTimeout(5 * 1000), m_connectionType(type)
456 #ifndef QT_NO_OPENSSL
457  , m_sslConfig(sslConfig)
458 #endif
459 {
460  LOG(VB_HTTP, LOG_INFO, QString("HttpWorker(%1): New connection")
461  .arg(m_socket));
462 }
463 
465 //
467 
468 void HttpWorker::run(void)
469 {
470 #if 0
471  LOG(VB_HTTP, LOG_DEBUG,
472  QString("HttpWorker::run() socket=%1 -- begin").arg(m_socket));
473 #endif
474 
475  bool bTimeout = false;
476  bool bKeepAlive = true;
477  HTTPRequest *pRequest = nullptr;
478  QTcpSocket *pSocket = nullptr;
479  bool bEncrypted = false;
480 
482  {
483 
484 #ifndef QT_NO_OPENSSL
485  auto *pSslSocket = new QSslSocket();
486  if (pSslSocket->setSocketDescriptor(m_socket)
487  && gCoreContext->CheckSubnet(pSslSocket))
488  {
489  pSslSocket->setSslConfiguration(m_sslConfig);
490  pSslSocket->startServerEncryption();
491  if (pSslSocket->waitForEncrypted(5000))
492  {
493  LOG(VB_HTTP, LOG_INFO, "SSL Handshake occurred, connection encrypted");
494  LOG(VB_HTTP, LOG_INFO, QString("Using %1 cipher").arg(pSslSocket->sessionCipher().name()));
495  bEncrypted = true;
496  }
497  else
498  {
499  LOG(VB_HTTP, LOG_WARNING, "SSL Handshake FAILED, connection terminated");
500  delete pSslSocket;
501  pSslSocket = nullptr;
502  }
503  }
504  else
505  {
506  delete pSslSocket;
507  pSslSocket = nullptr;
508  }
509 
510  if (pSslSocket)
511  pSocket = dynamic_cast<QTcpSocket *>(pSslSocket);
512  else
513  return;
514 #else
515  return;
516 #endif
517  }
518  else // Plain old unencrypted socket
519  {
520  pSocket = new QTcpSocket();
521  pSocket->setSocketDescriptor(m_socket);
522  if (!gCoreContext->CheckSubnet(pSocket))
523  {
524  delete pSocket;
525  pSocket = nullptr;
526  return;
527  }
528 
529  }
530 
531  pSocket->setSocketOption(QAbstractSocket::KeepAliveOption, QVariant(1));
532  int nRequestsHandled = 0; // Allow debugging of keep-alive and connection re-use
533 
534  try
535  {
536  while (m_httpServer.IsRunning() && bKeepAlive && pSocket->isValid() &&
537  pSocket->state() == QAbstractSocket::ConnectedState)
538  {
539  // We set a timeout on keep-alive connections to avoid blocking
540  // new clients from connecting - Default at time of writing was
541  // 5 seconds for initial connection, then up to 10 seconds of idle
542  // time between each subsequent request on the same connection
543  bTimeout = !(pSocket->waitForReadyRead(m_socketTimeout));
544 
545  if (bTimeout) // Either client closed the socket or we timed out waiting for new data
546  break;
547 
548  int64_t nBytes = pSocket->bytesAvailable();
549  if (!m_httpServer.IsRunning())
550  break;
551 
552  if ( nBytes > 0)
553  {
554  // ----------------------------------------------------------
555  // See if this is a valid request
556  // ----------------------------------------------------------
557 
558  pRequest = new BufferedSocketDeviceRequest( pSocket );
559  if (pRequest != nullptr)
560  {
561  pRequest->m_bEncrypted = bEncrypted;
562  if ( pRequest->ParseRequest() )
563  {
564  bKeepAlive = pRequest->GetKeepAlive();
565  // The timeout is defined by the Server/Server Extension
566  // but must appear in the response headers
567  uint nTimeout = m_httpServer.GetSocketTimeout(pRequest); // Seconds
568  pRequest->SetKeepAliveTimeout(nTimeout);
569  m_socketTimeout = nTimeout * 1000; // Milliseconds
570 
571  // ------------------------------------------------------
572  // Request Parsed... Pass on to Main HttpServer class to
573  // delegate processing to HttpServerExtensions.
574  // ------------------------------------------------------
575  if ((pRequest->m_nResponseStatus != 400) &&
576  (pRequest->m_nResponseStatus != 401) &&
577  (pRequest->m_nResponseStatus != 403) &&
578  pRequest->m_eType != RequestTypeUnknown)
579  m_httpServer.DelegateRequest(pRequest);
580 
581  nRequestsHandled++;
582  }
583  else
584  {
585  LOG(VB_HTTP, LOG_ERR, "ParseRequest Failed.");
586 
587  pRequest->m_nResponseStatus = 501;
588  pRequest->m_response.write( pRequest->GetResponsePage() );
589  bKeepAlive = false;
590  }
591 
592  // -------------------------------------------------------
593  // Always MUST send a response.
594  // -------------------------------------------------------
595  if (pRequest->SendResponse() < 0)
596  {
597  bKeepAlive = false;
598  LOG(VB_HTTP, LOG_ERR,
599  QString("socket(%1) - Error returned from "
600  "SendResponse... Closing connection")
601  .arg(pSocket->socketDescriptor()));
602  }
603 
604  // -------------------------------------------------------
605  // Check to see if a PostProcess was registered
606  // -------------------------------------------------------
607  if ( pRequest->m_pPostProcess != nullptr )
608  pRequest->m_pPostProcess->ExecutePostProcess();
609 
610  delete pRequest;
611  pRequest = nullptr;
612  }
613  else
614  {
615  LOG(VB_GENERAL, LOG_ERR,
616  "Error Creating BufferedSocketDeviceRequest");
617  bKeepAlive = false;
618  }
619  }
620  else
621  {
622  bKeepAlive = false;
623  }
624  }
625  }
626  catch(...)
627  {
628  LOG(VB_GENERAL, LOG_ERR,
629  "HttpWorkerThread::ProcessWork - Unexpected Exception.");
630  }
631 
632  delete pRequest;
633 
634  if ((pSocket->error() != QAbstractSocket::UnknownSocketError) &&
635  !(bKeepAlive && pSocket->error() == QAbstractSocket::SocketTimeoutError)) // This 'error' isn't an error when keep-alive is active
636  {
637  LOG(VB_HTTP, LOG_WARNING, QString("HttpWorker(%1): Error %2 (%3)")
638  .arg(m_socket)
639  .arg(pSocket->errorString())
640  .arg(pSocket->error()));
641  }
642 
643  int writeTimeout = 5000; // 5 Seconds
644  // Make sure any data in the buffer is flushed before the socket is closed
645  while (m_httpServer.IsRunning() &&
646  pSocket->isValid() &&
647  pSocket->state() == QAbstractSocket::ConnectedState &&
648  pSocket->bytesToWrite() > 0)
649  {
650  LOG(VB_HTTP, LOG_DEBUG, QString("HttpWorker(%1): "
651  "Waiting for %2 bytes to be written "
652  "before closing the connection.")
653  .arg(m_socket)
654  .arg(pSocket->bytesToWrite()));
655 
656  // If the client stops reading for longer than 'writeTimeout' then
657  // stop waiting for them. We can't afford to leave the socket
658  // connected indefinately, it could be used by another client.
659  //
660  // NOTE: Some clients deliberately stall as a way of 'pausing' A/V
661  // streaming. We should create a new server extension or adjust the
662  // timeout according to the User-Agent, instead of increasing the
663  // standard timeout. However we should ALWAYS have a timeout.
664  if (!pSocket->waitForBytesWritten(writeTimeout))
665  {
666  LOG(VB_GENERAL, LOG_WARNING, QString("HttpWorker(%1): "
667  "Timed out waiting to write bytes to "
668  "the socket, waited %2 seconds")
669  .arg(m_socket)
670  .arg(writeTimeout / 1000));
671  break;
672  }
673  }
674 
675  if (pSocket->bytesToWrite() > 0)
676  {
677  LOG(VB_HTTP, LOG_WARNING, QString("HttpWorker(%1): "
678  "Failed to write %2 bytes to "
679  "socket, (%3)")
680  .arg(m_socket)
681  .arg(pSocket->bytesToWrite())
682  .arg(pSocket->errorString()));
683  }
684 
685  LOG(VB_HTTP, LOG_INFO, QString("HttpWorker(%1): Connection %2 closed. %3 requests were handled")
686  .arg(m_socket)
687  .arg(pSocket->socketDescriptor())
688  .arg(nRequestsHandled));
689 
690  pSocket->close();
691  delete pSocket;
692  pSocket = nullptr;
693 
694 #if 0
695  LOG(VB_HTTP, LOG_DEBUG, "HttpWorkerThread::run() -- end");
696 #endif
697 }
698 
699 
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:121
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
void UnregisterExtension(HttpServerExtension *)
Definition: httpserver.cpp:344
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:321
long m_nResponseStatus
Definition: httprequest.h:146
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
bool ParseRequest()
QMultiMap< QString, HttpServerExtension * > m_basePaths
Definition: httpserver.h:148
PoolServerType
Definition: serverpool.h:29
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:136
void SetKeepAliveTimeout(int nTimeout)
Definition: httprequest.h:250
IPostProcess * m_pPostProcess
Definition: httprequest.h:153
uint GetSocketTimeout(HTTPRequest *) const
Get the idle socket timeout value for the relevant extension.
Definition: httpserver.cpp:424
bool GetKeepAlive()
Definition: httprequest.h:231
qt_socket_fd_t m_socket
Definition: httpserver.h:197
QString GetSetting(const QString &key, const QString &defaultval="")
qintptr qt_socket_fd_t
Definition: mythqtcompat.h:4
QString GetShareDir(void)
Definition: mythdirs.cpp:222
void run(void) override
Definition: httpserver.cpp:468
HttpWorker(HttpServer &httpServer, qt_socket_fd_t sock, PoolServerType type, const QSslConfiguration &sslConfig)
Definition: httpserver.cpp:448
unsigned int uint
Definition: compat.h:140
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
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:278
virtual QStringList GetBasePaths()=0
QBuffer m_response
Definition: httprequest.h:151
void startReserved(QRunnable *runnable, const QString &debugName, int waitForAvailMS=0)
void setMaxPendingConnections(int n)
Definition: serverpool.h:94
HttpResponseType m_eResponseType
Definition: httprequest.h:143
qint64 SendResponse(void)
static QString GetServerVersion(void)
Definition: httpserver.cpp:288
void DelegateRequest(HTTPRequest *)
Definition: httpserver.cpp:367
bool m_running
Definition: httpserver.h:151
HttpRequestType m_eType
Definition: httprequest.h:114
void newTcpConnection(qt_socket_fd_t socket) override
Definition: httpserver.cpp:301
bool CheckSubnet(const QAbstractSocket *socket)
Check if a socket is connected to an approved peer.