11 using namespace stefanfrings;
16 maxAge=settings->value(
"maxAge",
"60000").toInt();
17 encoding=settings->value(
"encoding",
"UTF-8").toString();
18 docroot=settings->value(
"path",
".").toString();
19 if(!(docroot.startsWith(
":/") || docroot.startsWith(
"qrc://")))
23 if (QDir::isRelativePath(docroot) && settings->format()!=QSettings::NativeFormat)
25 if (QDir::isRelativePath(docroot))
28 QFileInfo configFile(settings->fileName());
29 docroot=QFileInfo(configFile.absolutePath(),docroot).absoluteFilePath();
32 qDebug(
"StaticFileController: docroot=%s, encoding=%s, maxAge=%i",qPrintable(docroot),qPrintable(encoding),maxAge);
33 maxCachedFileSize=settings->value(
"maxCachedFileSize",
"65536").toInt();
34 cache.setMaxCost(settings->value(
"cacheSize",
"1000000").toInt());
35 cacheTimeout=settings->value(
"cacheTime",
"60000").toInt();
36 long int cacheMaxCost=(
long int)cache.maxCost();
37 qDebug(
"StaticFileController: cache timeout=%i, size=%li",cacheTimeout,cacheMaxCost);
43 QByteArray path=request.
getPath();
45 qint64 now=QDateTime::currentMSecsSinceEpoch();
47 CacheEntry* entry=cache.object(path);
48 if (entry && (cacheTimeout==0 || entry->created>now-cacheTimeout))
50 QByteArray document=entry->document;
51 QByteArray filename=entry->filename;
53 qDebug(
"StaticFileController: Cache hit for %s",path.data());
54 setContentType(filename,response);
55 response.
setHeader(
"Cache-Control",
"max-age="+QByteArray::number(maxAge/1000));
56 response.
write(document,
true);
62 qDebug(
"StaticFileController: Cache miss for %s",path.data());
64 if (path.contains(
"/.."))
66 qWarning(
"StaticFileController: detected forbidden characters in path %s",path.data());
68 response.
write(
"403 forbidden",
true);
72 if (QFileInfo(docroot+path).isDir())
77 QFile file(docroot+path);
78 qDebug(
"StaticFileController: Open file %s",qPrintable(file.fileName()));
79 if (file.open(QIODevice::ReadOnly))
81 setContentType(path,response);
82 response.
setHeader(
"Cache-Control",
"max-age="+QByteArray::number(maxAge/1000));
83 response.
setHeader(
"Content-Length",QByteArray::number(file.size()));
84 if (file.size()<=maxCachedFileSize)
87 entry=
new CacheEntry();
88 while (!file.atEnd() && !file.error())
90 QByteArray buffer=file.read(65536);
91 response.
write(buffer);
92 entry->document.append(buffer);
97 cache.insert(request.
getPath(),entry,entry->document.size());
103 while (!file.atEnd() && !file.error())
105 response.
write(file.read(65536));
113 qWarning(
"StaticFileController: Cannot open existing file %s for reading",qPrintable(file.fileName()));
115 response.
write(
"403 forbidden",
true);
120 response.
write(
"404 not found",
true);
126 void StaticFileController::setContentType(
const QString fileName,
HttpResponse &response)
const
128 if (fileName.endsWith(
".png"))
130 response.
setHeader(
"Content-Type",
"image/png");
132 else if (fileName.endsWith(
".jpg"))
134 response.
setHeader(
"Content-Type",
"image/jpeg");
136 else if (fileName.endsWith(
".gif"))
138 response.
setHeader(
"Content-Type",
"image/gif");
140 else if (fileName.endsWith(
".pdf"))
142 response.
setHeader(
"Content-Type",
"application/pdf");
144 else if (fileName.endsWith(
".txt"))
146 response.
setHeader(
"Content-Type", qPrintable(
"text/plain; charset="+encoding));
148 else if (fileName.endsWith(
".html") || fileName.endsWith(
".htm"))
150 response.
setHeader(
"Content-Type", qPrintable(
"text/html; charset="+encoding));
152 else if (fileName.endsWith(
".css"))
154 response.
setHeader(
"Content-Type",
"text/css");
156 else if (fileName.endsWith(
".js"))
158 response.
setHeader(
"Content-Type",
"text/javascript");
160 else if (fileName.endsWith(
".svg"))
162 response.
setHeader(
"Content-Type",
"image/svg+xml");
164 else if (fileName.endsWith(
".woff"))
166 response.
setHeader(
"Content-Type",
"font/woff");
168 else if (fileName.endsWith(
".woff2"))
170 response.
setHeader(
"Content-Type",
"font/woff2");
172 else if (fileName.endsWith(
".ttf"))
174 response.
setHeader(
"Content-Type",
"application/x-font-ttf");
176 else if (fileName.endsWith(
".eot"))
178 response.
setHeader(
"Content-Type",
"application/vnd.ms-fontobject");
180 else if (fileName.endsWith(
".otf"))
182 response.
setHeader(
"Content-Type",
"application/font-otf");
184 else if (fileName.endsWith(
".json"))
186 response.
setHeader(
"Content-Type",
"application/json");
188 else if (fileName.endsWith(
".xml"))
190 response.
setHeader(
"Content-Type",
"text/xml");
195 qDebug(
"StaticFileController: unknown MIME type for filename '%s'", qPrintable(fileName));
The request handler generates a response for each HTTP request.
This object represents a single HTTP request.
QByteArray getPath() const
Get the decoded path of the HTPP request (e.g.
This object represents a HTTP response, used to return something to the web client.
void setHeader(const QByteArray name, const QByteArray value)
Set a HTTP response header.
void setStatus(const int statusCode, const QByteArray description=QByteArray())
Set status code and description.
void write(const QByteArray data, const bool lastPart=false)
Write body data to the socket.
void service(HttpRequest &request, HttpResponse &response)
Generates the response.
StaticFileController(const QSettings *settings, QObject *parent=nullptr)
Constructor.