StaticFileServing.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #include "StaticFileServing.h"
  2. #include "QtHttpHeader.h"
  3. #include <utils/QStringUtils.h>
  4. #include <QStringBuilder>
  5. #include <QUrlQuery>
  6. #include <QList>
  7. #include <QPair>
  8. #include <QFile>
  9. #include <QFileInfo>
  10. #include <QResource>
  11. #include <exception>
  12. StaticFileServing::StaticFileServing (QObject * parent)
  13. : QObject (parent)
  14. , _baseUrl ()
  15. , _cgi(this)
  16. , _log(Logger::getInstance("WEBSERVER"))
  17. {
  18. Q_INIT_RESOURCE(WebConfig);
  19. _mimeDb = new QMimeDatabase;
  20. }
  21. StaticFileServing::~StaticFileServing ()
  22. {
  23. delete _mimeDb;
  24. }
  25. void StaticFileServing::setBaseUrl(const QString& url)
  26. {
  27. _baseUrl = url;
  28. _cgi.setBaseUrl(url);
  29. }
  30. void StaticFileServing::setSSDPDescription(const QString& desc)
  31. {
  32. if(desc.isEmpty())
  33. _ssdpDescription.clear();
  34. else
  35. _ssdpDescription = desc.toLocal8Bit();
  36. }
  37. void StaticFileServing::printErrorToReply (QtHttpReply * reply, QtHttpReply::StatusCode code, QString errorMessage)
  38. {
  39. reply->setStatusCode(code);
  40. reply->addHeader ("Content-Type", QByteArrayLiteral ("text/html"));
  41. QFile errorPageHeader(_baseUrl % "/errorpages/header.html" );
  42. QFile errorPageFooter(_baseUrl % "/errorpages/footer.html" );
  43. QFile errorPage (_baseUrl % "/errorpages/" % QString::number((int)code) % ".html" );
  44. if (errorPageHeader.open (QFile::ReadOnly))
  45. {
  46. QByteArray data = errorPageHeader.readAll();
  47. reply->appendRawData (data);
  48. errorPageHeader.close ();
  49. }
  50. if (errorPage.open (QFile::ReadOnly))
  51. {
  52. QByteArray data = errorPage.readAll();
  53. data = data.replace("{MESSAGE}", errorMessage.toLocal8Bit() );
  54. reply->appendRawData (data);
  55. errorPage.close ();
  56. }
  57. else
  58. {
  59. reply->appendRawData (QString(QString::number(code) + " - " +errorMessage).toLocal8Bit());
  60. }
  61. if (errorPageFooter.open (QFile::ReadOnly))
  62. {
  63. QByteArray data = errorPageFooter.readAll ();
  64. reply->appendRawData (data);
  65. errorPageFooter.close ();
  66. }
  67. }
  68. void StaticFileServing::onRequestNeedsReply (QtHttpRequest * request, QtHttpReply * reply)
  69. {
  70. QString command = request->getCommand ();
  71. if (command == QStringLiteral ("GET"))
  72. {
  73. QString path = request->getUrl ().path ();
  74. QStringList uri_parts = QStringUtils::split(path,'/', QStringUtils::SplitBehavior::SkipEmptyParts);
  75. // special uri handling for server commands
  76. if ( ! uri_parts.empty() )
  77. {
  78. if(uri_parts.at(0) == "cgi")
  79. {
  80. uri_parts.removeAt(0);
  81. try
  82. {
  83. _cgi.exec(uri_parts, request, reply);
  84. }
  85. catch(std::exception &e)
  86. {
  87. Error(_log,"Exception while executing cgi %s : %s", path.toStdString().c_str(), e.what());
  88. printErrorToReply (reply, QtHttpReply::InternalError, "script failed (" % path % ")");
  89. }
  90. return;
  91. }
  92. else if(uri_parts.at(0) == "description.xml" && !_ssdpDescription.isNull())
  93. {
  94. reply->addHeader ("Content-Type", "text/xml");
  95. reply->appendRawData (_ssdpDescription);
  96. return;
  97. }
  98. }
  99. QFileInfo info(_baseUrl % "/" % path);
  100. if ( path == "/" || path.isEmpty() )
  101. {
  102. path = "index.html";
  103. }
  104. else if (info.isDir() && path.endsWith("/") )
  105. {
  106. path += "index.html";
  107. }
  108. else if (info.isDir() && ! path.endsWith("/") )
  109. {
  110. path += "/index.html";
  111. }
  112. // get static files
  113. QFile file(_baseUrl % "/" % path);
  114. if (file.exists())
  115. {
  116. QMimeType mime = _mimeDb->mimeTypeForFile (file.fileName ());
  117. if (file.open (QFile::ReadOnly)) {
  118. QByteArray data = file.readAll ();
  119. reply->addHeader ("Content-Type", mime.name ().toLocal8Bit ());
  120. reply->addHeader(QtHttpHeader::AccessControlAllow, "*" );
  121. reply->appendRawData (data);
  122. file.close ();
  123. }
  124. else
  125. {
  126. printErrorToReply (reply, QtHttpReply::Forbidden ,"Requested file: " % path);
  127. }
  128. }
  129. else
  130. {
  131. printErrorToReply (reply, QtHttpReply::NotFound, "Requested file: " % path);
  132. }
  133. }
  134. else
  135. {
  136. printErrorToReply (reply, QtHttpReply::MethodNotAllowed,"Unhandled HTTP/1.1 method " % command);
  137. }
  138. }