mirror of
https://github.com/YACReader/yacreader
synced 2025-06-03 00:58:32 -04:00
236 lines
9.1 KiB
C++
236 lines
9.1 KiB
C++
/**
|
||
@file
|
||
@author Stefan Frings
|
||
*/
|
||
|
||
#include "staticfilecontroller.h"
|
||
#include <QFileInfo>
|
||
#include <QDir>
|
||
#include <QDateTime>
|
||
#include "httpsession.h"
|
||
#include "static.h"
|
||
#include <QCoreApplication>
|
||
|
||
|
||
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","./server/docroot").toString();
|
||
// 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
|
||
{
|
||
#if defined Q_OS_UNIX && ! defined Q_OS_MAC
|
||
QFileInfo configFile(QString(DATADIR)+"/yacreader");
|
||
docroot=QFileInfo(QString(DATADIR)+"/yacreader",docroot).absoluteFilePath();
|
||
#else
|
||
QFileInfo configFile(QCoreApplication::applicationDirPath());
|
||
docroot=QFileInfo(QCoreApplication::applicationDirPath(),docroot).absoluteFilePath();
|
||
#endif
|
||
}
|
||
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();
|
||
// Forbid access to files outside the docroot directory
|
||
if (path.startsWith("/..")) {
|
||
qWarning("StaticFileController: somebody attempted to access a file outside the docroot directory");
|
||
response.setStatus(403,"forbidden");
|
||
response.write("403 forbidden",true);
|
||
}
|
||
|
||
//TODO(DONE) carga sensible al dispositivo y a la localizaci<63>n
|
||
QString stringPath = path;
|
||
QStringList paths = QString(path).split('/');
|
||
QString fileName = paths.last();
|
||
stringPath.remove(fileName);
|
||
HttpSession session=Static::sessionStore->getSession(request,response,false);
|
||
QString device = session.getDeviceType();
|
||
QString display = session.getDisplayType();
|
||
if(fileName.endsWith(".png"))
|
||
fileName = getDeviceAwareFileName(fileName, device, display, request.getHeader("Accept-Language"), stringPath);
|
||
else
|
||
fileName = getDeviceAwareFileName(fileName, device, request.getHeader("Accept-Language"), stringPath);
|
||
QString newPath = stringPath.append(fileName);
|
||
path = newPath.toLocal8Bit();
|
||
|
||
//CAMBIADO
|
||
response.setHeader("Connection","close");
|
||
//END_TODO
|
||
|
||
// 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.
|
||
// mutex.unlock();
|
||
// qDebug("StaticFileController: Cache hit for %s",path.data());
|
||
// setContentType(path,response);
|
||
// response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000));
|
||
// response.write(document);
|
||
//}
|
||
//else {
|
||
|
||
// mutex.unlock();
|
||
//qDebug("StaticFileController: Cache miss for %s",path.data());
|
||
// The file is not in cache.
|
||
// If the filename is a directory, append index.html.
|
||
if (QFileInfo(docroot+path).isDir()) {
|
||
path+="/index.html";
|
||
}
|
||
|
||
|
||
QFile file(docroot+path);
|
||
if (file.exists()) {
|
||
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;
|
||
// 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(131072));
|
||
//}
|
||
}
|
||
file.close();
|
||
}
|
||
else {
|
||
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
|
||
}
|
||
|
||
bool StaticFileController::exists(QString localizedName, QString path) const
|
||
{
|
||
QString fileName=docroot+"/"+path + localizedName;
|
||
QFile file(fileName);
|
||
return file.exists();
|
||
}
|
||
|
||
//retorna fileName si no se encontr<74> alternativa traducida <20> fileName-locale.extensi<73>n si se encontr<74>
|
||
QString StaticFileController::getLocalizedFileName(QString fileName, QString locales, QString path) const
|
||
{
|
||
QSet<QString> tried; // used to suppress duplicate attempts
|
||
QStringList locs=locales.split(',',QString::SkipEmptyParts);
|
||
QStringList fileNameParts = fileName.split('.');
|
||
QString file = fileNameParts.first();
|
||
QString extension = fileNameParts.last();
|
||
// Search for exact match
|
||
foreach (QString loc,locs) {
|
||
loc.replace(QRegExp(";.*"),"");
|
||
loc.replace('-','_');
|
||
QString localizedName=file+"-"+loc.trimmed()+"."+extension;
|
||
if (!tried.contains(localizedName)) {
|
||
if(exists(localizedName, path))
|
||
return localizedName;
|
||
tried.insert(localizedName);
|
||
}
|
||
}
|
||
|
||
// Search for correct language but any country
|
||
foreach (QString loc,locs) {
|
||
loc.replace(QRegExp("[;_-].*"),"");
|
||
QString localizedName=file+"-"+loc.trimmed()+"."+extension;
|
||
if (!tried.contains(localizedName)) {
|
||
if(exists(localizedName, path))
|
||
return localizedName;
|
||
tried.insert(localizedName);
|
||
}
|
||
}
|
||
|
||
return fileName;
|
||
}
|
||
|
||
QString StaticFileController::getDeviceAwareFileName(QString fileName, QString device, QString locales, QString path) const
|
||
{
|
||
QFileInfo fi(fileName);
|
||
QString baseName = fi.baseName();
|
||
QString extension = fi.completeSuffix();
|
||
|
||
QString completeFileName = getLocalizedFileName(baseName+"_"+device+"."+extension,locales,path);
|
||
|
||
if(QFile(docroot+"/"+path+completeFileName).exists())
|
||
return completeFileName; //existe un archivo espec<65>fico para este dispositivo y locales
|
||
else
|
||
return getLocalizedFileName(fileName,locales,path); //no hay archivo espec<65>fico para el dispositivo, pero puede haberlo para estas locales
|
||
}
|
||
|
||
QString StaticFileController::getDeviceAwareFileName(QString fileName, QString device, QString display, QString locales, QString path) const
|
||
{
|
||
QFileInfo fi(fileName);
|
||
QString baseName = fi.baseName();
|
||
QString extension = fi.completeSuffix();
|
||
|
||
QString completeFileName = baseName+display+"."+extension;
|
||
if(QFile(docroot+"/"+path+completeFileName).exists())
|
||
return completeFileName;
|
||
else
|
||
{
|
||
completeFileName = baseName+"_"+device+display+"."+extension;
|
||
if((QFile(docroot+"/"+path+completeFileName).exists()))
|
||
return completeFileName;
|
||
}
|
||
|
||
return fileName;
|
||
}
|