mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-14 16:39:57 +00:00
Add httpserver to contrib
.. see http://stefanfrings.de/qtwebapp/index-en.html .. this is a lightweight web server to allow GC to provide webservices. .. we will be providing web services on localhost to enable R integration. .. we will use web services to standardise the interface to provide something we can use in R but also anything else at a later date. .. gcconfig.pri contains $$HTPATH that points to the location of the code, if it is not set then the web server is not compiled in.
This commit is contained in:
136
httpserver/staticfilecontroller.cpp
Normal file
136
httpserver/staticfilecontroller.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
@file
|
||||
@author Stefan Frings
|
||||
*/
|
||||
|
||||
#include "staticfilecontroller.h"
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QDateTime>
|
||||
|
||||
StaticFileController::StaticFileController(QSettings* settings, QObject* parent)
|
||||
:HttpRequestHandler(parent)
|
||||
{
|
||||
maxAge=settings->value("maxAge","60000").toInt();
|
||||
encoding=settings->value("encoding","UTF-8").toString();
|
||||
docroot=settings->value("path",".").toString();
|
||||
if(!(docroot.startsWith(":/") || docroot.startsWith("qrc://")))
|
||||
{
|
||||
// Convert relative path to absolute, based on the directory of the config file.
|
||||
#ifdef Q_OS_WIN32
|
||||
if (QDir::isRelativePath(docroot) && settings->format()!=QSettings::NativeFormat)
|
||||
#else
|
||||
if (QDir::isRelativePath(docroot))
|
||||
#endif
|
||||
{
|
||||
QFileInfo configFile(settings->fileName());
|
||||
docroot=QFileInfo(configFile.absolutePath(),docroot).absoluteFilePath();
|
||||
}
|
||||
}
|
||||
qDebug("StaticFileController: docroot=%s, encoding=%s, maxAge=%i",qPrintable(docroot),qPrintable(encoding),maxAge);
|
||||
maxCachedFileSize=settings->value("maxCachedFileSize","65536").toInt();
|
||||
cache.setMaxCost(settings->value("cacheSize","1000000").toInt());
|
||||
cacheTimeout=settings->value("cacheTime","60000").toInt();
|
||||
qDebug("StaticFileController: cache timeout=%i, size=%i",cacheTimeout,cache.maxCost());
|
||||
}
|
||||
|
||||
|
||||
void StaticFileController::service(HttpRequest& request, HttpResponse& response) {
|
||||
QByteArray path=request.getPath();
|
||||
// Check if we have the file in cache
|
||||
qint64 now=QDateTime::currentMSecsSinceEpoch();
|
||||
mutex.lock();
|
||||
CacheEntry* entry=cache.object(path);
|
||||
if (entry && (cacheTimeout==0 || entry->created>now-cacheTimeout)) {
|
||||
QByteArray document=entry->document; //copy the cached document, because other threads may destroy the cached entry immediately after mutex unlock.
|
||||
QByteArray filename=entry->filename;
|
||||
mutex.unlock();
|
||||
qDebug("StaticFileController: Cache hit for %s",path.data());
|
||||
setContentType(filename,response);
|
||||
response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000));
|
||||
response.write(document);
|
||||
}
|
||||
else {
|
||||
mutex.unlock();
|
||||
// The file is not in cache.
|
||||
qDebug("StaticFileController: Cache miss for %s",path.data());
|
||||
// Forbid access to files outside the docroot directory
|
||||
if (path.contains("/..")) {
|
||||
qWarning("StaticFileController: detected forbidden characters in path %s",path.data());
|
||||
response.setStatus(403,"forbidden");
|
||||
response.write("403 forbidden",true);
|
||||
return;
|
||||
}
|
||||
// If the filename is a directory, append index.html.
|
||||
if (QFileInfo(docroot+path).isDir()) {
|
||||
path+="/index.html";
|
||||
}
|
||||
// Try to open the file
|
||||
QFile file(docroot+path);
|
||||
qDebug("StaticFileController: Open file %s",qPrintable(file.fileName()));
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
setContentType(path,response);
|
||||
response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000));
|
||||
if (file.size()<=maxCachedFileSize) {
|
||||
// Return the file content and store it also in the cache
|
||||
entry=new CacheEntry();
|
||||
while (!file.atEnd() && !file.error()) {
|
||||
QByteArray buffer=file.read(65536);
|
||||
response.write(buffer);
|
||||
entry->document.append(buffer);
|
||||
}
|
||||
entry->created=now;
|
||||
entry->filename=path;
|
||||
mutex.lock();
|
||||
cache.insert(request.getPath(),entry,entry->document.size());
|
||||
mutex.unlock();
|
||||
}
|
||||
else {
|
||||
// Return the file content, do not store in cache
|
||||
while (!file.atEnd() && !file.error()) {
|
||||
response.write(file.read(65536));
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
else {
|
||||
if (file.exists()) {
|
||||
qWarning("StaticFileController: Cannot open existing file %s for reading",qPrintable(file.fileName()));
|
||||
response.setStatus(403,"forbidden");
|
||||
response.write("403 forbidden",true);
|
||||
}
|
||||
else {
|
||||
response.setStatus(404,"not found");
|
||||
response.write("404 not found",true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StaticFileController::setContentType(QString fileName, HttpResponse& response) const {
|
||||
if (fileName.endsWith(".png")) {
|
||||
response.setHeader("Content-Type", "image/png");
|
||||
}
|
||||
else if (fileName.endsWith(".jpg")) {
|
||||
response.setHeader("Content-Type", "image/jpeg");
|
||||
}
|
||||
else if (fileName.endsWith(".gif")) {
|
||||
response.setHeader("Content-Type", "image/gif");
|
||||
}
|
||||
else if (fileName.endsWith(".pdf")) {
|
||||
response.setHeader("Content-Type", "application/pdf");
|
||||
}
|
||||
else if (fileName.endsWith(".txt")) {
|
||||
response.setHeader("Content-Type", qPrintable("text/plain; charset="+encoding));
|
||||
}
|
||||
else if (fileName.endsWith(".html") || fileName.endsWith(".htm")) {
|
||||
response.setHeader("Content-Type", qPrintable("text/html; charset="+encoding));
|
||||
}
|
||||
else if (fileName.endsWith(".css")) {
|
||||
response.setHeader("Content-Type", "text/css");
|
||||
}
|
||||
else if (fileName.endsWith(".js")) {
|
||||
response.setHeader("Content-Type", "text/javascript");
|
||||
}
|
||||
// Todo: add all of your content types
|
||||
}
|
||||
Reference in New Issue
Block a user