mirror of
https://github.com/YACReader/yacreader
synced 2025-07-18 13:04:28 -04:00
Add .gitattributes rules for text and binary handling
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user