12using namespace stefanfrings;
14StaticFileController::StaticFileController(
const QSettings *settings, QObject* parent)
17 maxAge=settings->value(
"maxAge",
"60000").toInt();
18 encoding=settings->value(
"encoding",
"UTF-8").toString();
19 docroot=settings->value(
"path",
".").toString();
20 if(!(docroot.startsWith(
":/") || docroot.startsWith(
"qrc://")))
24 if (QDir::isRelativePath(docroot) && settings->format()!=QSettings::NativeFormat)
26 if (QDir::isRelativePath(docroot))
29 QFileInfo configFile(settings->fileName());
30 docroot=QFileInfo(configFile.absolutePath(),docroot).absoluteFilePath();
33 qDebug(
"StaticFileController: docroot=%s, encoding=%s, maxAge=%i",qPrintable(docroot),qPrintable(encoding),maxAge);
34 maxCachedFileSize=settings->value(
"maxCachedFileSize",
"65536").toInt();
35 cache.setMaxCost(settings->value(
"cacheSize",
"1000000").toInt());
36 cacheTimeout=settings->value(
"cacheTime",
"60000").toInt();
37 long int cacheMaxCost=(
long int)cache.maxCost();
38 qDebug(
"StaticFileController: cache timeout=%i, size=%li",cacheTimeout,cacheMaxCost);
44 QByteArray path=request.
getPath();
46 qint64 now=QDateTime::currentMSecsSinceEpoch();
48 CacheEntry* entry=cache.object(path);
49 if (entry && (cacheTimeout==0 || entry->created>now-cacheTimeout))
51 QByteArray document=entry->document;
52 QByteArray filename=entry->filename;
54 qDebug(
"StaticFileController: Cache hit for %s",path.data());
55 setContentType(filename,response);
56 response.
setHeader(
"Cache-Control",
"max-age="+QByteArray::number(maxAge/1000));
57 response.
write(document,
true);
63 qDebug(
"StaticFileController: Cache miss for %s",path.data());
65 if (path.contains(
"/.."))
67 qWarning(
"StaticFileController: detected forbidden characters in path %s",path.data());
69 response.
write(
"403 forbidden",
true);
73 if (QFileInfo(docroot+path).isDir())
78 QFile file(docroot+path);
79 qDebug(
"StaticFileController: Open file %s",qPrintable(file.fileName()));
80 if (file.open(QIODevice::ReadOnly))
82 setContentType(path,response);
83 response.
setHeader(
"Cache-Control",
"max-age="+QByteArray::number(maxAge/1000));
84 response.
setHeader(
"Content-Length",QByteArray::number(file.size()));
85 if (file.size()<=maxCachedFileSize)
88 entry=
new CacheEntry();
89 while (!file.atEnd() && !file.error())
91 QByteArray buffer=file.read(65536);
92 response.
write(buffer);
93 entry->document.append(buffer);
98 cache.insert(request.
getPath(),entry,entry->document.size());
104 while (!file.atEnd() && !file.error())
106 response.
write(file.read(65536));
114 qWarning(
"StaticFileController: Cannot open existing file %s for reading",qPrintable(file.fileName()));
116 response.
write(
"403 forbidden",
true);
121 response.
write(
"404 not found",
true);
127void StaticFileController::setContentType(
const QString fileName,
HttpResponse &response)
const
129 if (fileName.endsWith(
".png"))
131 response.
setHeader(
"Content-Type",
"image/png");
133 else if (fileName.endsWith(
".jpg"))
135 response.
setHeader(
"Content-Type",
"image/jpeg");
137 else if (fileName.endsWith(
".gif"))
139 response.
setHeader(
"Content-Type",
"image/gif");
141 else if (fileName.endsWith(
".pdf"))
143 response.
setHeader(
"Content-Type",
"application/pdf");
145 else if (fileName.endsWith(
".txt"))
147 response.
setHeader(
"Content-Type", qPrintable(
"text/plain; charset="+encoding));
149 else if (fileName.endsWith(
".html") || fileName.endsWith(
".htm"))
151 response.
setHeader(
"Content-Type", qPrintable(
"text/html; charset="+encoding));
153 else if (fileName.endsWith(
".css"))
155 response.
setHeader(
"Content-Type",
"text/css");
157 else if (fileName.endsWith(
".js"))
159 response.
setHeader(
"Content-Type",
"text/javascript");
161 else if (fileName.endsWith(
".svg"))
163 response.
setHeader(
"Content-Type",
"image/svg+xml");
165 else if (fileName.endsWith(
".woff"))
167 response.
setHeader(
"Content-Type",
"font/woff");
169 else if (fileName.endsWith(
".woff2"))
171 response.
setHeader(
"Content-Type",
"font/woff2");
173 else if (fileName.endsWith(
".ttf"))
175 response.
setHeader(
"Content-Type",
"application/x-font-ttf");
177 else if (fileName.endsWith(
".eot"))
179 response.
setHeader(
"Content-Type",
"application/vnd.ms-fontobject");
181 else if (fileName.endsWith(
".otf"))
183 response.
setHeader(
"Content-Type",
"application/font-otf");
185 else if (fileName.endsWith(
".json"))
187 response.
setHeader(
"Content-Type",
"application/json");
189 else if (fileName.endsWith(
".xml"))
191 response.
setHeader(
"Content-Type",
"text/xml");
196 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.