Add .gitattributes rules for text and binary handling

This commit is contained in:
Felix Kauselmann
2018-07-01 21:29:59 +02:00
parent 4f6618c096
commit d5a11fb16b
377 changed files with 54049 additions and 53970 deletions

View File

@ -1,261 +1,261 @@
/**
@file
@author Stefan Frings
*/
#include "httpcookie.h"
HttpCookie::HttpCookie()
{
version=1;
maxAge=0;
secure=false;
}
HttpCookie::HttpCookie(const QByteArray name, const QByteArray value, const int maxAge, const QByteArray path, const QByteArray comment, const QByteArray domain, const bool secure, const bool httpOnly)
{
this->name=name;
this->value=value;
this->maxAge=maxAge;
this->path=path;
this->comment=comment;
this->domain=domain;
this->secure=secure;
this->httpOnly=httpOnly;
this->version=1;
}
HttpCookie::HttpCookie(const QByteArray source)
{
version=1;
maxAge=0;
secure=false;
QList<QByteArray> list=splitCSV(source);
foreach(QByteArray part, list)
{
// Split the part into name and value
QByteArray name;
QByteArray value;
int posi=part.indexOf('=');
if (posi)
{
name=part.left(posi).trimmed();
value=part.mid(posi+1).trimmed();
}
else
{
name=part.trimmed();
value="";
}
// Set fields
if (name=="Comment")
{
comment=value;
}
else if (name=="Domain")
{
domain=value;
}
else if (name=="Max-Age")
{
maxAge=value.toInt();
}
else if (name=="Path")
{
path=value;
}
else if (name=="Secure")
{
secure=true;
}
else if (name=="HttpOnly")
{
httpOnly=true;
}
else if (name=="Version")
{
version=value.toInt();
}
else {
if (this->name.isEmpty())
{
this->name=name;
this->value=value;
}
else
{
qWarning("HttpCookie: Ignoring unknown %s=%s",name.data(),value.data());
}
}
}
}
QByteArray HttpCookie::toByteArray() const
{
QByteArray buffer(name);
buffer.append('=');
buffer.append(value);
if (!comment.isEmpty())
{
buffer.append("; Comment=");
buffer.append(comment);
}
if (!domain.isEmpty())
{
buffer.append("; Domain=");
buffer.append(domain);
}
if (maxAge!=0)
{
buffer.append("; Max-Age=");
buffer.append(QByteArray::number(maxAge));
}
if (!path.isEmpty())
{
buffer.append("; Path=");
buffer.append(path);
}
if (secure) {
buffer.append("; Secure");
}
if (httpOnly) {
buffer.append("; HttpOnly");
}
buffer.append("; Version=");
buffer.append(QByteArray::number(version));
return buffer;
}
void HttpCookie::setName(const QByteArray name)
{
this->name=name;
}
void HttpCookie::setValue(const QByteArray value)
{
this->value=value;
}
void HttpCookie::setComment(const QByteArray comment)
{
this->comment=comment;
}
void HttpCookie::setDomain(const QByteArray domain)
{
this->domain=domain;
}
void HttpCookie::setMaxAge(const int maxAge)
{
this->maxAge=maxAge;
}
void HttpCookie::setPath(const QByteArray path)
{
this->path=path;
}
void HttpCookie::setSecure(const bool secure)
{
this->secure=secure;
}
void HttpCookie::setHttpOnly(const bool httpOnly)
{
this->httpOnly=httpOnly;
}
QByteArray HttpCookie::getName() const
{
return name;
}
QByteArray HttpCookie::getValue() const
{
return value;
}
QByteArray HttpCookie::getComment() const
{
return comment;
}
QByteArray HttpCookie::getDomain() const
{
return domain;
}
int HttpCookie::getMaxAge() const
{
return maxAge;
}
QByteArray HttpCookie::getPath() const
{
return path;
}
bool HttpCookie::getSecure() const
{
return secure;
}
bool HttpCookie::getHttpOnly() const
{
return httpOnly;
}
int HttpCookie::getVersion() const
{
return version;
}
QList<QByteArray> HttpCookie::splitCSV(const QByteArray source)
{
bool inString=false;
QList<QByteArray> list;
QByteArray buffer;
for (int i=0; i<source.size(); ++i)
{
char c=source.at(i);
if (inString==false)
{
if (c=='\"')
{
inString=true;
}
else if (c==';')
{
QByteArray trimmed=buffer.trimmed();
if (!trimmed.isEmpty())
{
list.append(trimmed);
}
buffer.clear();
}
else
{
buffer.append(c);
}
}
else
{
if (c=='\"')
{
inString=false;
}
else {
buffer.append(c);
}
}
}
QByteArray trimmed=buffer.trimmed();
if (!trimmed.isEmpty())
{
list.append(trimmed);
}
return list;
}
/**
@file
@author Stefan Frings
*/
#include "httpcookie.h"
HttpCookie::HttpCookie()
{
version=1;
maxAge=0;
secure=false;
}
HttpCookie::HttpCookie(const QByteArray name, const QByteArray value, const int maxAge, const QByteArray path, const QByteArray comment, const QByteArray domain, const bool secure, const bool httpOnly)
{
this->name=name;
this->value=value;
this->maxAge=maxAge;
this->path=path;
this->comment=comment;
this->domain=domain;
this->secure=secure;
this->httpOnly=httpOnly;
this->version=1;
}
HttpCookie::HttpCookie(const QByteArray source)
{
version=1;
maxAge=0;
secure=false;
QList<QByteArray> list=splitCSV(source);
foreach(QByteArray part, list)
{
// Split the part into name and value
QByteArray name;
QByteArray value;
int posi=part.indexOf('=');
if (posi)
{
name=part.left(posi).trimmed();
value=part.mid(posi+1).trimmed();
}
else
{
name=part.trimmed();
value="";
}
// Set fields
if (name=="Comment")
{
comment=value;
}
else if (name=="Domain")
{
domain=value;
}
else if (name=="Max-Age")
{
maxAge=value.toInt();
}
else if (name=="Path")
{
path=value;
}
else if (name=="Secure")
{
secure=true;
}
else if (name=="HttpOnly")
{
httpOnly=true;
}
else if (name=="Version")
{
version=value.toInt();
}
else {
if (this->name.isEmpty())
{
this->name=name;
this->value=value;
}
else
{
qWarning("HttpCookie: Ignoring unknown %s=%s",name.data(),value.data());
}
}
}
}
QByteArray HttpCookie::toByteArray() const
{
QByteArray buffer(name);
buffer.append('=');
buffer.append(value);
if (!comment.isEmpty())
{
buffer.append("; Comment=");
buffer.append(comment);
}
if (!domain.isEmpty())
{
buffer.append("; Domain=");
buffer.append(domain);
}
if (maxAge!=0)
{
buffer.append("; Max-Age=");
buffer.append(QByteArray::number(maxAge));
}
if (!path.isEmpty())
{
buffer.append("; Path=");
buffer.append(path);
}
if (secure) {
buffer.append("; Secure");
}
if (httpOnly) {
buffer.append("; HttpOnly");
}
buffer.append("; Version=");
buffer.append(QByteArray::number(version));
return buffer;
}
void HttpCookie::setName(const QByteArray name)
{
this->name=name;
}
void HttpCookie::setValue(const QByteArray value)
{
this->value=value;
}
void HttpCookie::setComment(const QByteArray comment)
{
this->comment=comment;
}
void HttpCookie::setDomain(const QByteArray domain)
{
this->domain=domain;
}
void HttpCookie::setMaxAge(const int maxAge)
{
this->maxAge=maxAge;
}
void HttpCookie::setPath(const QByteArray path)
{
this->path=path;
}
void HttpCookie::setSecure(const bool secure)
{
this->secure=secure;
}
void HttpCookie::setHttpOnly(const bool httpOnly)
{
this->httpOnly=httpOnly;
}
QByteArray HttpCookie::getName() const
{
return name;
}
QByteArray HttpCookie::getValue() const
{
return value;
}
QByteArray HttpCookie::getComment() const
{
return comment;
}
QByteArray HttpCookie::getDomain() const
{
return domain;
}
int HttpCookie::getMaxAge() const
{
return maxAge;
}
QByteArray HttpCookie::getPath() const
{
return path;
}
bool HttpCookie::getSecure() const
{
return secure;
}
bool HttpCookie::getHttpOnly() const
{
return httpOnly;
}
int HttpCookie::getVersion() const
{
return version;
}
QList<QByteArray> HttpCookie::splitCSV(const QByteArray source)
{
bool inString=false;
QList<QByteArray> list;
QByteArray buffer;
for (int i=0; i<source.size(); ++i)
{
char c=source.at(i);
if (inString==false)
{
if (c=='\"')
{
inString=true;
}
else if (c==';')
{
QByteArray trimmed=buffer.trimmed();
if (!trimmed.isEmpty())
{
list.append(trimmed);
}
buffer.clear();
}
else
{
buffer.append(c);
}
}
else
{
if (c=='\"')
{
inString=false;
}
else {
buffer.append(c);
}
}
}
QByteArray trimmed=buffer.trimmed();
if (!trimmed.isEmpty())
{
list.append(trimmed);
}
return list;
}

View File

@ -1,119 +1,119 @@
/**
@file
@author Stefan Frings
*/
#ifndef HTTPCOOKIE_H
#define HTTPCOOKIE_H
#include <QList>
#include <QByteArray>
#include "httpglobal.h"
/**
HTTP cookie as defined in RFC 2109. This class can also parse
RFC 2965 cookies, but skips fields that are not defined in RFC
2109.
*/
class DECLSPEC HttpCookie
{
public:
/** Creates an empty cookie */
HttpCookie();
/**
Create a cookie and set name/value pair.
@param name name of the cookie
@param value value of the cookie
@param maxAge maximum age of the cookie in seconds. 0=discard immediately
@param path Path for that the cookie will be sent, default="/" which means the whole domain
@param comment Optional comment, may be displayed by the web browser somewhere
@param domain Optional domain for that the cookie will be sent. Defaults to the current domain
@param secure If true, the cookie will be sent by the browser to the server only on secure connections
@param httpOnly If true, the browser does not allow client-side scripts to access the cookie
*/
HttpCookie(const QByteArray name, const QByteArray value, const int maxAge, const QByteArray path="/", const QByteArray comment=QByteArray(), const QByteArray domain=QByteArray(), const bool secure=false, const bool httpOnly=false);
/**
Create a cookie from a string.
@param source String as received in a HTTP Cookie2 header.
*/
HttpCookie(const QByteArray source);
/** Convert this cookie to a string that may be used in a Set-Cookie header. */
QByteArray toByteArray() const ;
/**
Split a string list into parts, where each part is delimited by semicolon.
Semicolons within double quotes are skipped. Double quotes are removed.
*/
static QList<QByteArray> splitCSV(const QByteArray source);
/** Set the name of this cookie */
void setName(const QByteArray name);
/** Set the value of this cookie */
void setValue(const QByteArray value);
/** Set the comment of this cookie */
void setComment(const QByteArray comment);
/** Set the domain of this cookie */
void setDomain(const QByteArray domain);
/** Set the maximum age of this cookie in seconds. 0=discard immediately */
void setMaxAge(const int maxAge);
/** Set the path for that the cookie will be sent, default="/" which means the whole domain */
void setPath(const QByteArray path);
/** Set secure mode, so that the cookie will be sent by the browser to the server only on secure connections */
void setSecure(const bool secure);
/** Set secure mode, so that he browser does not allow client-side scripts to access the cookie */
void setHttpOnly(const bool httpOnly);
/** Get the name of this cookie */
QByteArray getName() const;
/** Get the value of this cookie */
QByteArray getValue() const;
/** Get the comment of this cookie */
QByteArray getComment() const;
/** Get the domain of this cookie */
QByteArray getDomain() const;
/** Set the maximum age of this cookie in seconds. */
int getMaxAge() const;
/** Set the path of this cookie */
QByteArray getPath() const;
/** Get the secure flag of this cookie */
bool getSecure() const;
/** Get the httpOnly of this cookie */
bool getHttpOnly() const;
/** Returns always 1 */
int getVersion() const;
private:
QByteArray name;
QByteArray value;
QByteArray comment;
QByteArray domain;
int maxAge;
QByteArray path;
bool secure;
bool httpOnly;
int version;
};
#endif // HTTPCOOKIE_H
/**
@file
@author Stefan Frings
*/
#ifndef HTTPCOOKIE_H
#define HTTPCOOKIE_H
#include <QList>
#include <QByteArray>
#include "httpglobal.h"
/**
HTTP cookie as defined in RFC 2109. This class can also parse
RFC 2965 cookies, but skips fields that are not defined in RFC
2109.
*/
class DECLSPEC HttpCookie
{
public:
/** Creates an empty cookie */
HttpCookie();
/**
Create a cookie and set name/value pair.
@param name name of the cookie
@param value value of the cookie
@param maxAge maximum age of the cookie in seconds. 0=discard immediately
@param path Path for that the cookie will be sent, default="/" which means the whole domain
@param comment Optional comment, may be displayed by the web browser somewhere
@param domain Optional domain for that the cookie will be sent. Defaults to the current domain
@param secure If true, the cookie will be sent by the browser to the server only on secure connections
@param httpOnly If true, the browser does not allow client-side scripts to access the cookie
*/
HttpCookie(const QByteArray name, const QByteArray value, const int maxAge, const QByteArray path="/", const QByteArray comment=QByteArray(), const QByteArray domain=QByteArray(), const bool secure=false, const bool httpOnly=false);
/**
Create a cookie from a string.
@param source String as received in a HTTP Cookie2 header.
*/
HttpCookie(const QByteArray source);
/** Convert this cookie to a string that may be used in a Set-Cookie header. */
QByteArray toByteArray() const ;
/**
Split a string list into parts, where each part is delimited by semicolon.
Semicolons within double quotes are skipped. Double quotes are removed.
*/
static QList<QByteArray> splitCSV(const QByteArray source);
/** Set the name of this cookie */
void setName(const QByteArray name);
/** Set the value of this cookie */
void setValue(const QByteArray value);
/** Set the comment of this cookie */
void setComment(const QByteArray comment);
/** Set the domain of this cookie */
void setDomain(const QByteArray domain);
/** Set the maximum age of this cookie in seconds. 0=discard immediately */
void setMaxAge(const int maxAge);
/** Set the path for that the cookie will be sent, default="/" which means the whole domain */
void setPath(const QByteArray path);
/** Set secure mode, so that the cookie will be sent by the browser to the server only on secure connections */
void setSecure(const bool secure);
/** Set secure mode, so that he browser does not allow client-side scripts to access the cookie */
void setHttpOnly(const bool httpOnly);
/** Get the name of this cookie */
QByteArray getName() const;
/** Get the value of this cookie */
QByteArray getValue() const;
/** Get the comment of this cookie */
QByteArray getComment() const;
/** Get the domain of this cookie */
QByteArray getDomain() const;
/** Set the maximum age of this cookie in seconds. */
int getMaxAge() const;
/** Set the path of this cookie */
QByteArray getPath() const;
/** Get the secure flag of this cookie */
bool getSecure() const;
/** Get the httpOnly of this cookie */
bool getHttpOnly() const;
/** Returns always 1 */
int getVersion() const;
private:
QByteArray name;
QByteArray value;
QByteArray comment;
QByteArray domain;
int maxAge;
QByteArray path;
bool secure;
bool httpOnly;
int version;
};
#endif // HTTPCOOKIE_H

View File

@ -1,27 +1,27 @@
/**
@file
@author Stefan Frings
*/
#ifndef HTTPGLOBAL_H
#define HTTPGLOBAL_H
#include <QtGlobal>
// This is specific to Windows dll's
#if defined(Q_OS_WIN)
#if defined(QTWEBAPPLIB_EXPORT)
#define DECLSPEC Q_DECL_EXPORT
#elif defined(QTWEBAPPLIB_IMPORT)
#define DECLSPEC Q_DECL_IMPORT
#endif
#endif
#if !defined(DECLSPEC)
#define DECLSPEC
#endif
/** Get the library version number */
DECLSPEC const char* getQtWebAppLibVersion();
#endif // HTTPGLOBAL_H
/**
@file
@author Stefan Frings
*/
#ifndef HTTPGLOBAL_H
#define HTTPGLOBAL_H
#include <QtGlobal>
// This is specific to Windows dll's
#if defined(Q_OS_WIN)
#if defined(QTWEBAPPLIB_EXPORT)
#define DECLSPEC Q_DECL_EXPORT
#elif defined(QTWEBAPPLIB_IMPORT)
#define DECLSPEC Q_DECL_IMPORT
#endif
#endif
#if !defined(DECLSPEC)
#define DECLSPEC
#endif
/** Get the library version number */
DECLSPEC const char* getQtWebAppLibVersion();
#endif // HTTPGLOBAL_H

View File

@ -1,186 +1,186 @@
/**
@file
@author Stefan Frings
*/
#include "httpsession.h"
#include <QDateTime>
#include <QUuid>
HttpSession::HttpSession(bool canStore)
{
if (canStore)
{
dataPtr=new HttpSessionData();
dataPtr->refCount=1;
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
dataPtr->id=QUuid::createUuid().toString().toLocal8Bit();
#ifdef SUPERVERBOSE
qDebug("HttpSession: created new session data with id %s",dataPtr->id.data());
#endif
}
else
{
dataPtr=0;
}
}
HttpSession::HttpSession(const HttpSession& other)
{
dataPtr=other.dataPtr;
if (dataPtr)
{
dataPtr->lock.lockForWrite();
dataPtr->refCount++;
#ifdef SUPERVERBOSE
qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount);
#endif
dataPtr->lock.unlock();
}
}
HttpSession& HttpSession::operator= (const HttpSession& other)
{
HttpSessionData* oldPtr=dataPtr;
dataPtr=other.dataPtr;
if (dataPtr)
{
dataPtr->lock.lockForWrite();
dataPtr->refCount++;
#ifdef SUPERVERBOSE
qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount);
#endif
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
dataPtr->lock.unlock();
}
if (oldPtr)
{
int refCount;
oldPtr->lock.lockForRead();
refCount=oldPtr->refCount--;
#ifdef SUPERVERBOSE
qDebug("HttpSession: refCount of %s is %i",oldPtr->id.data(),oldPtr->refCount);
#endif
oldPtr->lock.unlock();
if (refCount==0)
{
delete oldPtr;
}
}
return *this;
}
HttpSession::~HttpSession()
{
if (dataPtr) {
int refCount;
dataPtr->lock.lockForRead();
refCount=--dataPtr->refCount;
#ifdef SUPERVERBOSE
qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount);
#endif
dataPtr->lock.unlock();
if (refCount==0)
{
qDebug("HttpSession: deleting data");
delete dataPtr;
}
}
}
QByteArray HttpSession::getId() const
{
if (dataPtr)
{
return dataPtr->id;
}
else
{
return QByteArray();
}
}
bool HttpSession::isNull() const {
return dataPtr==0;
}
void HttpSession::set(const QByteArray& key, const QVariant& value)
{
if (dataPtr)
{
dataPtr->lock.lockForWrite();
dataPtr->values.insert(key,value);
dataPtr->lock.unlock();
}
}
void HttpSession::remove(const QByteArray& key)
{
if (dataPtr)
{
dataPtr->lock.lockForWrite();
dataPtr->values.remove(key);
dataPtr->lock.unlock();
}
}
QVariant HttpSession::get(const QByteArray& key) const
{
QVariant value;
if (dataPtr)
{
dataPtr->lock.lockForRead();
value=dataPtr->values.value(key);
dataPtr->lock.unlock();
}
return value;
}
bool HttpSession::contains(const QByteArray& key) const
{
bool found=false;
if (dataPtr)
{
dataPtr->lock.lockForRead();
found=dataPtr->values.contains(key);
dataPtr->lock.unlock();
}
return found;
}
QMap<QByteArray,QVariant> HttpSession::getAll() const
{
QMap<QByteArray,QVariant> values;
if (dataPtr)
{
dataPtr->lock.lockForRead();
values=dataPtr->values;
dataPtr->lock.unlock();
}
return values;
}
qint64 HttpSession::getLastAccess() const
{
qint64 value=0;
if (dataPtr)
{
dataPtr->lock.lockForRead();
value=dataPtr->lastAccess;
dataPtr->lock.unlock();
}
return value;
}
void HttpSession::setLastAccess()
{
if (dataPtr)
{
dataPtr->lock.lockForRead();
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
dataPtr->lock.unlock();
}
}
/**
@file
@author Stefan Frings
*/
#include "httpsession.h"
#include <QDateTime>
#include <QUuid>
HttpSession::HttpSession(bool canStore)
{
if (canStore)
{
dataPtr=new HttpSessionData();
dataPtr->refCount=1;
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
dataPtr->id=QUuid::createUuid().toString().toLocal8Bit();
#ifdef SUPERVERBOSE
qDebug("HttpSession: created new session data with id %s",dataPtr->id.data());
#endif
}
else
{
dataPtr=0;
}
}
HttpSession::HttpSession(const HttpSession& other)
{
dataPtr=other.dataPtr;
if (dataPtr)
{
dataPtr->lock.lockForWrite();
dataPtr->refCount++;
#ifdef SUPERVERBOSE
qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount);
#endif
dataPtr->lock.unlock();
}
}
HttpSession& HttpSession::operator= (const HttpSession& other)
{
HttpSessionData* oldPtr=dataPtr;
dataPtr=other.dataPtr;
if (dataPtr)
{
dataPtr->lock.lockForWrite();
dataPtr->refCount++;
#ifdef SUPERVERBOSE
qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount);
#endif
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
dataPtr->lock.unlock();
}
if (oldPtr)
{
int refCount;
oldPtr->lock.lockForRead();
refCount=oldPtr->refCount--;
#ifdef SUPERVERBOSE
qDebug("HttpSession: refCount of %s is %i",oldPtr->id.data(),oldPtr->refCount);
#endif
oldPtr->lock.unlock();
if (refCount==0)
{
delete oldPtr;
}
}
return *this;
}
HttpSession::~HttpSession()
{
if (dataPtr) {
int refCount;
dataPtr->lock.lockForRead();
refCount=--dataPtr->refCount;
#ifdef SUPERVERBOSE
qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount);
#endif
dataPtr->lock.unlock();
if (refCount==0)
{
qDebug("HttpSession: deleting data");
delete dataPtr;
}
}
}
QByteArray HttpSession::getId() const
{
if (dataPtr)
{
return dataPtr->id;
}
else
{
return QByteArray();
}
}
bool HttpSession::isNull() const {
return dataPtr==0;
}
void HttpSession::set(const QByteArray& key, const QVariant& value)
{
if (dataPtr)
{
dataPtr->lock.lockForWrite();
dataPtr->values.insert(key,value);
dataPtr->lock.unlock();
}
}
void HttpSession::remove(const QByteArray& key)
{
if (dataPtr)
{
dataPtr->lock.lockForWrite();
dataPtr->values.remove(key);
dataPtr->lock.unlock();
}
}
QVariant HttpSession::get(const QByteArray& key) const
{
QVariant value;
if (dataPtr)
{
dataPtr->lock.lockForRead();
value=dataPtr->values.value(key);
dataPtr->lock.unlock();
}
return value;
}
bool HttpSession::contains(const QByteArray& key) const
{
bool found=false;
if (dataPtr)
{
dataPtr->lock.lockForRead();
found=dataPtr->values.contains(key);
dataPtr->lock.unlock();
}
return found;
}
QMap<QByteArray,QVariant> HttpSession::getAll() const
{
QMap<QByteArray,QVariant> values;
if (dataPtr)
{
dataPtr->lock.lockForRead();
values=dataPtr->values;
dataPtr->lock.unlock();
}
return values;
}
qint64 HttpSession::getLastAccess() const
{
qint64 value=0;
if (dataPtr)
{
dataPtr->lock.lockForRead();
value=dataPtr->lastAccess;
dataPtr->lock.unlock();
}
return value;
}
void HttpSession::setLastAccess()
{
if (dataPtr)
{
dataPtr->lock.lockForRead();
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
dataPtr->lock.unlock();
}
}

View File

@ -1,118 +1,118 @@
/**
@file
@author Stefan Frings
*/
#ifndef HTTPSESSION_H
#define HTTPSESSION_H
#include <QByteArray>
#include <QVariant>
#include <QReadWriteLock>
#include "httpglobal.h"
/**
This class stores data for a single HTTP session.
A session can store any number of key/value pairs. This class uses implicit
sharing for read and write access. This class is thread safe.
@see HttpSessionStore should be used to create and get instances of this class.
*/
class DECLSPEC HttpSession {
public:
/**
Constructor.
@param canStore The session can store data, if this parameter is true.
Otherwise all calls to set() and remove() do not have any effect.
*/
HttpSession(bool canStore=false);
/**
Copy constructor. Creates another HttpSession object that shares the
data of the other object.
*/
HttpSession(const HttpSession& other);
/**
Copy operator. Detaches from the current shared data and attaches to
the data of the other object.
*/
HttpSession& operator= (const HttpSession& other);
/**
Destructor. Detaches from the shared data.
*/
virtual ~HttpSession();
/** Get the unique ID of this session. This method is thread safe. */
QByteArray getId() const;
/**
Null sessions cannot store data. All calls to set() and remove()
do not have any effect.This method is thread safe.
*/
bool isNull() const;
/** Set a value. This method is thread safe. */
void set(const QByteArray& key, const QVariant& value);
/** Remove a value. This method is thread safe. */
void remove(const QByteArray& key);
/** Get a value. This method is thread safe. */
QVariant get(const QByteArray& key) const;
/** Check if a key exists. This method is thread safe. */
bool contains(const QByteArray& key) const;
/**
Get a copy of all data stored in this session.
Changes to the session do not affect the copy and vice versa.
This method is thread safe.
*/
QMap<QByteArray,QVariant> getAll() const;
/**
Get the timestamp of last access. That is the time when the last
HttpSessionStore::getSession() has been called.
This method is thread safe.
*/
qint64 getLastAccess() const;
/**
Set the timestamp of last access, to renew the timeout period.
Called by HttpSessionStore::getSession().
This method is thread safe.
*/
void setLastAccess();
private:
struct HttpSessionData {
/** Unique ID */
QByteArray id;
/** Timestamp of last access, set by the HttpSessionStore */
qint64 lastAccess;
/** Reference counter */
int refCount;
/** Used to synchronize threads */
QReadWriteLock lock;
/** Storage for the key/value pairs; */
QMap<QByteArray,QVariant> values;
};
/** Pointer to the shared data. */
HttpSessionData* dataPtr;
};
#endif // HTTPSESSION_H
/**
@file
@author Stefan Frings
*/
#ifndef HTTPSESSION_H
#define HTTPSESSION_H
#include <QByteArray>
#include <QVariant>
#include <QReadWriteLock>
#include "httpglobal.h"
/**
This class stores data for a single HTTP session.
A session can store any number of key/value pairs. This class uses implicit
sharing for read and write access. This class is thread safe.
@see HttpSessionStore should be used to create and get instances of this class.
*/
class DECLSPEC HttpSession {
public:
/**
Constructor.
@param canStore The session can store data, if this parameter is true.
Otherwise all calls to set() and remove() do not have any effect.
*/
HttpSession(bool canStore=false);
/**
Copy constructor. Creates another HttpSession object that shares the
data of the other object.
*/
HttpSession(const HttpSession& other);
/**
Copy operator. Detaches from the current shared data and attaches to
the data of the other object.
*/
HttpSession& operator= (const HttpSession& other);
/**
Destructor. Detaches from the shared data.
*/
virtual ~HttpSession();
/** Get the unique ID of this session. This method is thread safe. */
QByteArray getId() const;
/**
Null sessions cannot store data. All calls to set() and remove()
do not have any effect.This method is thread safe.
*/
bool isNull() const;
/** Set a value. This method is thread safe. */
void set(const QByteArray& key, const QVariant& value);
/** Remove a value. This method is thread safe. */
void remove(const QByteArray& key);
/** Get a value. This method is thread safe. */
QVariant get(const QByteArray& key) const;
/** Check if a key exists. This method is thread safe. */
bool contains(const QByteArray& key) const;
/**
Get a copy of all data stored in this session.
Changes to the session do not affect the copy and vice versa.
This method is thread safe.
*/
QMap<QByteArray,QVariant> getAll() const;
/**
Get the timestamp of last access. That is the time when the last
HttpSessionStore::getSession() has been called.
This method is thread safe.
*/
qint64 getLastAccess() const;
/**
Set the timestamp of last access, to renew the timeout period.
Called by HttpSessionStore::getSession().
This method is thread safe.
*/
void setLastAccess();
private:
struct HttpSessionData {
/** Unique ID */
QByteArray id;
/** Timestamp of last access, set by the HttpSessionStore */
qint64 lastAccess;
/** Reference counter */
int refCount;
/** Used to synchronize threads */
QReadWriteLock lock;
/** Storage for the key/value pairs; */
QMap<QByteArray,QVariant> values;
};
/** Pointer to the shared data. */
HttpSessionData* dataPtr;
};
#endif // HTTPSESSION_H

View File

@ -1,125 +1,125 @@
/**
@file
@author Stefan Frings
*/
#include "httpsessionstore.h"
#include <QDateTime>
#include <QUuid>
HttpSessionStore::HttpSessionStore(QSettings* settings, QObject* parent)
:QObject(parent)
{
this->settings=settings;
connect(&cleanupTimer,SIGNAL(timeout()),this,SLOT(sessionTimerEvent()));
cleanupTimer.start(60000);
cookieName=settings->value("cookieName","sessionid").toByteArray();
expirationTime=settings->value("expirationTime",3600000).toInt();
qDebug("HttpSessionStore: Sessions expire after %i milliseconds",expirationTime);
}
HttpSessionStore::~HttpSessionStore()
{
cleanupTimer.stop();
}
QByteArray HttpSessionStore::getSessionId(HttpRequest& request, HttpResponse& response)
{
// The session ID in the response has priority because this one will be used in the next request.
mutex.lock();
// Get the session ID from the response cookie
QByteArray sessionId=response.getCookies().value(cookieName).getValue();
if (sessionId.isEmpty())
{
// Get the session ID from the request cookie
sessionId=request.getCookie(cookieName);
}
// Clear the session ID if there is no such session in the storage.
if (!sessionId.isEmpty())
{
if (!sessions.contains(sessionId))
{
qDebug("HttpSessionStore: received invalid session cookie with ID %s",sessionId.data());
sessionId.clear();
}
}
mutex.unlock();
return sessionId;
}
HttpSession HttpSessionStore::getSession(HttpRequest& request, HttpResponse& response, bool allowCreate)
{
QByteArray sessionId=getSessionId(request,response);
mutex.lock();
if (!sessionId.isEmpty())
{
HttpSession session=sessions.value(sessionId);
if (!session.isNull())
{
mutex.unlock();
// Refresh the session cookie
QByteArray cookieName=settings->value("cookieName","sessionid").toByteArray();
QByteArray cookiePath=settings->value("cookiePath").toByteArray();
QByteArray cookieComment=settings->value("cookieComment").toByteArray();
QByteArray cookieDomain=settings->value("cookieDomain").toByteArray();
response.setCookie(HttpCookie(cookieName,session.getId(),expirationTime/1000,cookiePath,cookieComment,cookieDomain));
session.setLastAccess();
return session;
}
}
// Need to create a new session
if (allowCreate)
{
QByteArray cookieName=settings->value("cookieName","sessionid").toByteArray();
QByteArray cookiePath=settings->value("cookiePath").toByteArray();
QByteArray cookieComment=settings->value("cookieComment").toByteArray();
QByteArray cookieDomain=settings->value("cookieDomain").toByteArray();
HttpSession session(true);
qDebug("HttpSessionStore: create new session with ID %s",session.getId().data());
sessions.insert(session.getId(),session);
response.setCookie(HttpCookie(cookieName,session.getId(),expirationTime/1000,cookiePath,cookieComment,cookieDomain));
mutex.unlock();
return session;
}
// Return a null session
mutex.unlock();
return HttpSession();
}
HttpSession HttpSessionStore::getSession(const QByteArray id)
{
mutex.lock();
HttpSession session=sessions.value(id);
mutex.unlock();
session.setLastAccess();
return session;
}
void HttpSessionStore::sessionTimerEvent()
{
mutex.lock();
qint64 now=QDateTime::currentMSecsSinceEpoch();
QMap<QByteArray,HttpSession>::iterator i = sessions.begin();
while (i != sessions.end())
{
QMap<QByteArray,HttpSession>::iterator prev = i;
++i;
HttpSession session=prev.value();
qint64 lastAccess=session.getLastAccess();
if (now-lastAccess>expirationTime)
{
qDebug("HttpSessionStore: session %s expired",session.getId().data());
sessions.erase(prev);
}
}
mutex.unlock();
}
/** Delete a session */
void HttpSessionStore::removeSession(HttpSession session)
{
mutex.lock();
sessions.remove(session.getId());
mutex.unlock();
}
/**
@file
@author Stefan Frings
*/
#include "httpsessionstore.h"
#include <QDateTime>
#include <QUuid>
HttpSessionStore::HttpSessionStore(QSettings* settings, QObject* parent)
:QObject(parent)
{
this->settings=settings;
connect(&cleanupTimer,SIGNAL(timeout()),this,SLOT(sessionTimerEvent()));
cleanupTimer.start(60000);
cookieName=settings->value("cookieName","sessionid").toByteArray();
expirationTime=settings->value("expirationTime",3600000).toInt();
qDebug("HttpSessionStore: Sessions expire after %i milliseconds",expirationTime);
}
HttpSessionStore::~HttpSessionStore()
{
cleanupTimer.stop();
}
QByteArray HttpSessionStore::getSessionId(HttpRequest& request, HttpResponse& response)
{
// The session ID in the response has priority because this one will be used in the next request.
mutex.lock();
// Get the session ID from the response cookie
QByteArray sessionId=response.getCookies().value(cookieName).getValue();
if (sessionId.isEmpty())
{
// Get the session ID from the request cookie
sessionId=request.getCookie(cookieName);
}
// Clear the session ID if there is no such session in the storage.
if (!sessionId.isEmpty())
{
if (!sessions.contains(sessionId))
{
qDebug("HttpSessionStore: received invalid session cookie with ID %s",sessionId.data());
sessionId.clear();
}
}
mutex.unlock();
return sessionId;
}
HttpSession HttpSessionStore::getSession(HttpRequest& request, HttpResponse& response, bool allowCreate)
{
QByteArray sessionId=getSessionId(request,response);
mutex.lock();
if (!sessionId.isEmpty())
{
HttpSession session=sessions.value(sessionId);
if (!session.isNull())
{
mutex.unlock();
// Refresh the session cookie
QByteArray cookieName=settings->value("cookieName","sessionid").toByteArray();
QByteArray cookiePath=settings->value("cookiePath").toByteArray();
QByteArray cookieComment=settings->value("cookieComment").toByteArray();
QByteArray cookieDomain=settings->value("cookieDomain").toByteArray();
response.setCookie(HttpCookie(cookieName,session.getId(),expirationTime/1000,cookiePath,cookieComment,cookieDomain));
session.setLastAccess();
return session;
}
}
// Need to create a new session
if (allowCreate)
{
QByteArray cookieName=settings->value("cookieName","sessionid").toByteArray();
QByteArray cookiePath=settings->value("cookiePath").toByteArray();
QByteArray cookieComment=settings->value("cookieComment").toByteArray();
QByteArray cookieDomain=settings->value("cookieDomain").toByteArray();
HttpSession session(true);
qDebug("HttpSessionStore: create new session with ID %s",session.getId().data());
sessions.insert(session.getId(),session);
response.setCookie(HttpCookie(cookieName,session.getId(),expirationTime/1000,cookiePath,cookieComment,cookieDomain));
mutex.unlock();
return session;
}
// Return a null session
mutex.unlock();
return HttpSession();
}
HttpSession HttpSessionStore::getSession(const QByteArray id)
{
mutex.lock();
HttpSession session=sessions.value(id);
mutex.unlock();
session.setLastAccess();
return session;
}
void HttpSessionStore::sessionTimerEvent()
{
mutex.lock();
qint64 now=QDateTime::currentMSecsSinceEpoch();
QMap<QByteArray,HttpSession>::iterator i = sessions.begin();
while (i != sessions.end())
{
QMap<QByteArray,HttpSession>::iterator prev = i;
++i;
HttpSession session=prev.value();
qint64 lastAccess=session.getLastAccess();
if (now-lastAccess>expirationTime)
{
qDebug("HttpSessionStore: session %s expired",session.getId().data());
sessions.erase(prev);
}
}
mutex.unlock();
}
/** Delete a session */
void HttpSessionStore::removeSession(HttpSession session)
{
mutex.lock();
sessions.remove(session.getId());
mutex.unlock();
}

View File

@ -1,106 +1,106 @@
/**
@file
@author Stefan Frings
*/
#ifndef HTTPSESSIONSTORE_H
#define HTTPSESSIONSTORE_H
#include <QObject>
#include <QMap>
#include <QTimer>
#include <QMutex>
#include "httpglobal.h"
#include "httpsession.h"
#include "httpresponse.h"
#include "httprequest.h"
/**
Stores HTTP sessions and deletes them when they have expired.
The following configuration settings are required in the config file:
<code><pre>
expirationTime=3600000
cookieName=sessionid
</pre></code>
The following additional configurations settings are optionally:
<code><pre>
cookiePath=/
cookieComment=Session ID
;cookieDomain=stefanfrings.de
</pre></code>
*/
class DECLSPEC HttpSessionStore : public QObject {
Q_OBJECT
Q_DISABLE_COPY(HttpSessionStore)
public:
/** Constructor. */
HttpSessionStore(QSettings* settings, QObject* parent=NULL);
/** Destructor */
virtual ~HttpSessionStore();
/**
Get the ID of the current HTTP session, if it is valid.
This method is thread safe.
@warning Sessions may expire at any time, so subsequent calls of
getSession() might return a new session with a different ID.
@param request Used to get the session cookie
@param response Used to get and set the new session cookie
@return Empty string, if there is no valid session.
*/
QByteArray getSessionId(HttpRequest& request, HttpResponse& response);
/**
Get the session of a HTTP request, eventually create a new one.
This method is thread safe. New sessions can only be created before
the first byte has been written to the HTTP response.
@param request Used to get the session cookie
@param response Used to get and set the new session cookie
@param allowCreate can be set to false, to disable the automatic creation of a new session.
@return If autoCreate is disabled, the function returns a null session if there is no session.
@see HttpSession::isNull()
*/
HttpSession getSession(HttpRequest& request, HttpResponse& response, bool allowCreate=true);
/**
Get a HTTP session by it's ID number.
This method is thread safe.
@return If there is no such session, the function returns a null session.
@param id ID number of the session
@see HttpSession::isNull()
*/
HttpSession getSession(const QByteArray id);
/** Delete a session */
void removeSession(HttpSession session);
protected:
/** Storage for the sessions */
QMap<QByteArray,HttpSession> sessions;
private:
/** Configuration settings */
QSettings* settings;
/** Timer to remove expired sessions */
QTimer cleanupTimer;
/** Name of the session cookie */
QByteArray cookieName;
/** Time when sessions expire (in ms)*/
int expirationTime;
/** Used to synchronize threads */
QMutex mutex;
private slots:
/** Called every minute to cleanup expired sessions. */
void sessionTimerEvent();
};
#endif // HTTPSESSIONSTORE_H
/**
@file
@author Stefan Frings
*/
#ifndef HTTPSESSIONSTORE_H
#define HTTPSESSIONSTORE_H
#include <QObject>
#include <QMap>
#include <QTimer>
#include <QMutex>
#include "httpglobal.h"
#include "httpsession.h"
#include "httpresponse.h"
#include "httprequest.h"
/**
Stores HTTP sessions and deletes them when they have expired.
The following configuration settings are required in the config file:
<code><pre>
expirationTime=3600000
cookieName=sessionid
</pre></code>
The following additional configurations settings are optionally:
<code><pre>
cookiePath=/
cookieComment=Session ID
;cookieDomain=stefanfrings.de
</pre></code>
*/
class DECLSPEC HttpSessionStore : public QObject {
Q_OBJECT
Q_DISABLE_COPY(HttpSessionStore)
public:
/** Constructor. */
HttpSessionStore(QSettings* settings, QObject* parent=NULL);
/** Destructor */
virtual ~HttpSessionStore();
/**
Get the ID of the current HTTP session, if it is valid.
This method is thread safe.
@warning Sessions may expire at any time, so subsequent calls of
getSession() might return a new session with a different ID.
@param request Used to get the session cookie
@param response Used to get and set the new session cookie
@return Empty string, if there is no valid session.
*/
QByteArray getSessionId(HttpRequest& request, HttpResponse& response);
/**
Get the session of a HTTP request, eventually create a new one.
This method is thread safe. New sessions can only be created before
the first byte has been written to the HTTP response.
@param request Used to get the session cookie
@param response Used to get and set the new session cookie
@param allowCreate can be set to false, to disable the automatic creation of a new session.
@return If autoCreate is disabled, the function returns a null session if there is no session.
@see HttpSession::isNull()
*/
HttpSession getSession(HttpRequest& request, HttpResponse& response, bool allowCreate=true);
/**
Get a HTTP session by it's ID number.
This method is thread safe.
@return If there is no such session, the function returns a null session.
@param id ID number of the session
@see HttpSession::isNull()
*/
HttpSession getSession(const QByteArray id);
/** Delete a session */
void removeSession(HttpSession session);
protected:
/** Storage for the sessions */
QMap<QByteArray,HttpSession> sessions;
private:
/** Configuration settings */
QSettings* settings;
/** Timer to remove expired sessions */
QTimer cleanupTimer;
/** Name of the session cookie */
QByteArray cookieName;
/** Time when sessions expire (in ms)*/
int expirationTime;
/** Used to synchronize threads */
QMutex mutex;
private slots:
/** Called every minute to cleanup expired sessions. */
void sessionTimerEvent();
};
#endif // HTTPSESSIONSTORE_H

View File

@ -1,293 +1,293 @@
/**
@file
@author Stefan Frings
*/
#include "staticfilecontroller.h"
#include <QFileInfo>
#include <QDir>
#include <QDateTime>
//YACReader-----
#include "httpsession.h"
#include "yacreader_http_session.h"
#include "static.h"
//--
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();
//TODO(DONE) carga sensible al dispositivo y a la localización
QString stringPath = path;
QStringList paths = QString(path).split('/');
QString fileName = paths.last();
stringPath.remove(fileName);
HttpSession session=Static::sessionStore->getSession(request,response,false);
/**
@file
@author Stefan Frings
*/
#include "staticfilecontroller.h"
#include <QFileInfo>
#include <QDir>
#include <QDateTime>
//YACReader-----
#include "httpsession.h"
#include "yacreader_http_session.h"
#include "static.h"
//--
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();
//TODO(DONE) carga sensible al dispositivo y a la localización
QString stringPath = path;
QStringList paths = QString(path).split('/');
QString fileName = paths.last();
stringPath.remove(fileName);
HttpSession session=Static::sessionStore->getSession(request,response,false);
YACReaderHttpSession *ySession = Static::yacreaderSessionStore->getYACReaderSessionHttpSession(session.getId());
QString device = "ipad";
QString display = "@2x";
if (ySession != nullptr) {
device = ySession->getDeviceType();
if (ySession != nullptr) {
device = ySession->getDeviceType();
display = ySession->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
// 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");
}
else if (fileName.endsWith(".svg"))
{
response.setHeader("Content-Type", "image/svg+xml");
}
else if (fileName.endsWith(".woff"))
{
response.setHeader("Content-Type", "font/woff");
}
else if (fileName.endsWith(".woff2"))
{
response.setHeader("Content-Type", "font/woff2");
}
else if (fileName.endsWith(".ttf"))
{
response.setHeader("Content-Type", "application/x-font-ttf");
}
else if (fileName.endsWith(".eot"))
{
response.setHeader("Content-Type", "application/vnd.ms-fontobject");
}
else if (fileName.endsWith(".otf"))
{
response.setHeader("Content-Type", "application/font-otf");
}
// Todo: add all of your content types
else
{
qDebug("StaticFileController: unknown MIME type for filename '%s'", qPrintable(fileName));
}
}
//YACReader------------------------------------------------------------------------
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ó alternativa traducida ó fileName-locale.extensión si se encontró
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ífico para este dispositivo y locales
else
return getLocalizedFileName(fileName,locales,path); //no hay archivo especí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;
}
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
// 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");
}
else if (fileName.endsWith(".svg"))
{
response.setHeader("Content-Type", "image/svg+xml");
}
else if (fileName.endsWith(".woff"))
{
response.setHeader("Content-Type", "font/woff");
}
else if (fileName.endsWith(".woff2"))
{
response.setHeader("Content-Type", "font/woff2");
}
else if (fileName.endsWith(".ttf"))
{
response.setHeader("Content-Type", "application/x-font-ttf");
}
else if (fileName.endsWith(".eot"))
{
response.setHeader("Content-Type", "application/vnd.ms-fontobject");
}
else if (fileName.endsWith(".otf"))
{
response.setHeader("Content-Type", "application/font-otf");
}
// Todo: add all of your content types
else
{
qDebug("StaticFileController: unknown MIME type for filename '%s'", qPrintable(fileName));
}
}
//YACReader------------------------------------------------------------------------
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ó alternativa traducida ó fileName-locale.extensión si se encontró
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ífico para este dispositivo y locales
else
return getLocalizedFileName(fileName,locales,path); //no hay archivo especí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;
}

View File

@ -1,94 +1,94 @@
/**
@file
@author Stefan Frings
*/
#ifndef STATICFILECONTROLLER_H
#define STATICFILECONTROLLER_H
#include <QCache>
#include <QMutex>
#include "httpglobal.h"
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
/**
Delivers static files. It is usually called by the applications main request handler when
the caller requests a path that is mapped to static files.
<p>
The following settings are required in the config file:
<code><pre>
path=../docroot
encoding=UTF-8
maxAge=60000
cacheTime=60000
cacheSize=1000000
maxCachedFileSize=65536
</pre></code>
The path is relative to the directory of the config file. In case of windows, if the
settings are in the registry, the path is relative to the current working directory.
<p>
The encoding is sent to the web browser in case of text and html files.
<p>
The cache improves performance of small files when loaded from a network
drive. Large files are not cached. Files are cached as long as possible,
when cacheTime=0. The maxAge value (in msec!) controls the remote browsers cache.
<p>
Do not instantiate this class in each request, because this would make the file cache
useless. Better create one instance during start-up and call it when the application
received a related HTTP request.
*/
class DECLSPEC StaticFileController : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(StaticFileController)
public:
/** Constructor */
StaticFileController(QSettings* settings, QObject* parent = NULL);
/** Generates the response */
void service(HttpRequest& request, HttpResponse& response);
private:
/** Encoding of text files */
QString encoding;
/** Root directory of documents */
QString docroot;
/** Maximum age of files in the browser cache */
int maxAge;
struct CacheEntry {
QByteArray document;
qint64 created;
QByteArray filename;
};
/** Timeout for each cached file */
int cacheTimeout;
/** Maximum size of files in cache, larger files are not cached */
int maxCachedFileSize;
/** Cache storage */
QCache<QString,CacheEntry> cache;
/** Used to synchronize cache access for threads */
QMutex mutex;
/** Set a content-type header in the response depending on the ending of the filename */
void setContentType(QString file, HttpResponse& response) const;
//YACReader------------------------------------------------------------------------
QString getLocalizedFileName(QString fileName, QString locales, QString path) const;
QString getDeviceAwareFileName(QString fileName, QString device, QString locales, QString path) const;
QString getDeviceAwareFileName(QString fileName, QString device, QString display, QString locales, QString path) const;
bool exists(QString localizedName, QString path) const;
};
#endif // STATICFILECONTROLLER_H
/**
@file
@author Stefan Frings
*/
#ifndef STATICFILECONTROLLER_H
#define STATICFILECONTROLLER_H
#include <QCache>
#include <QMutex>
#include "httpglobal.h"
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
/**
Delivers static files. It is usually called by the applications main request handler when
the caller requests a path that is mapped to static files.
<p>
The following settings are required in the config file:
<code><pre>
path=../docroot
encoding=UTF-8
maxAge=60000
cacheTime=60000
cacheSize=1000000
maxCachedFileSize=65536
</pre></code>
The path is relative to the directory of the config file. In case of windows, if the
settings are in the registry, the path is relative to the current working directory.
<p>
The encoding is sent to the web browser in case of text and html files.
<p>
The cache improves performance of small files when loaded from a network
drive. Large files are not cached. Files are cached as long as possible,
when cacheTime=0. The maxAge value (in msec!) controls the remote browsers cache.
<p>
Do not instantiate this class in each request, because this would make the file cache
useless. Better create one instance during start-up and call it when the application
received a related HTTP request.
*/
class DECLSPEC StaticFileController : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(StaticFileController)
public:
/** Constructor */
StaticFileController(QSettings* settings, QObject* parent = NULL);
/** Generates the response */
void service(HttpRequest& request, HttpResponse& response);
private:
/** Encoding of text files */
QString encoding;
/** Root directory of documents */
QString docroot;
/** Maximum age of files in the browser cache */
int maxAge;
struct CacheEntry {
QByteArray document;
qint64 created;
QByteArray filename;
};
/** Timeout for each cached file */
int cacheTimeout;
/** Maximum size of files in cache, larger files are not cached */
int maxCachedFileSize;
/** Cache storage */
QCache<QString,CacheEntry> cache;
/** Used to synchronize cache access for threads */
QMutex mutex;
/** Set a content-type header in the response depending on the ending of the filename */
void setContentType(QString file, HttpResponse& response) const;
//YACReader------------------------------------------------------------------------
QString getLocalizedFileName(QString fileName, QString locales, QString path) const;
QString getDeviceAwareFileName(QString fileName, QString device, QString locales, QString path) const;
QString getDeviceAwareFileName(QString fileName, QString device, QString display, QString locales, QString path) const;
bool exists(QString localizedName, QString path) const;
};
#endif // STATICFILECONTROLLER_H