Follow project coding style (Issue #2192).

This commit is contained in:
Vladimir Golovnev (Glassez) 2015-02-05 19:54:15 +03:00
commit 898d454b78
11 changed files with 710 additions and 766 deletions

View file

@ -40,13 +40,13 @@
using namespace Http;
Connection::Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent)
: QObject(parent)
, m_socket(socket)
, m_requestHandler(requestHandler)
: QObject(parent)
, m_socket(socket)
, m_requestHandler(requestHandler)
{
m_socket->setParent(this);
connect(m_socket, SIGNAL(readyRead()), SLOT(read()));
connect(m_socket, SIGNAL(disconnected()), SLOT(deleteLater()));
m_socket->setParent(this);
connect(m_socket, SIGNAL(readyRead()), SLOT(read()));
connect(m_socket, SIGNAL(disconnected()), SLOT(deleteLater()));
}
Connection::~Connection()
@ -55,57 +55,56 @@ Connection::~Connection()
void Connection::read()
{
m_receivedData.append(m_socket->readAll());
m_receivedData.append(m_socket->readAll());
Request request;
RequestParser::ErrorCode err = RequestParser::parse(m_receivedData, request);
switch (err)
{
case RequestParser::IncompleteRequest:
// Partial request waiting for the rest
break;
case RequestParser::BadRequest:
sendResponse(Response(400, "Bad Request"));
break;
case RequestParser::NoError:
Environment env;
env.clientAddress = m_socket->peerAddress();
Response response = m_requestHandler->processRequest(request, env);
if (acceptsGzipEncoding(request.headers["accept-encoding"]))
response.headers[HEADER_CONTENT_ENCODING] = "gzip";
sendResponse(response);
break;
}
Request request;
RequestParser::ErrorCode err = RequestParser::parse(m_receivedData, request);
switch (err) {
case RequestParser::IncompleteRequest:
// Partial request waiting for the rest
break;
case RequestParser::BadRequest:
sendResponse(Response(400, "Bad Request"));
break;
case RequestParser::NoError:
Environment env;
env.clientAddress = m_socket->peerAddress();
Response response = m_requestHandler->processRequest(request, env);
if (acceptsGzipEncoding(request.headers["accept-encoding"]))
response.headers[HEADER_CONTENT_ENCODING] = "gzip";
sendResponse(response);
break;
}
}
void Connection::sendResponse(const Response &response)
{
m_socket->write(ResponseGenerator::generate(response));
m_socket->disconnectFromHost();
m_socket->write(ResponseGenerator::generate(response));
m_socket->disconnectFromHost();
}
bool Connection::acceptsGzipEncoding(const QString &encoding)
{
int pos = encoding.indexOf("gzip", 0, Qt::CaseInsensitive);
if (pos == -1)
return false;
int pos = encoding.indexOf("gzip", 0, Qt::CaseInsensitive);
if (pos == -1)
return false;
// Let's see if there's a qvalue of 0.0 following
if (encoding[pos + 4] != ';') //there isn't, so it accepts gzip anyway
return true;
//So let's find = and the next comma
pos = encoding.indexOf("=", pos + 4, Qt::CaseInsensitive);
int comma_pos = encoding.indexOf(",", pos, Qt::CaseInsensitive);
QString value;
if (comma_pos == -1)
value = encoding.mid(pos + 1, comma_pos);
else
value = encoding.mid(pos + 1, comma_pos - (pos + 1));
if (value.toDouble() == 0.0)
return false;
// Let's see if there's a qvalue of 0.0 following
if (encoding[pos + 4] != ';') //there isn't, so it accepts gzip anyway
return true;
//So let's find = and the next comma
pos = encoding.indexOf("=", pos + 4, Qt::CaseInsensitive);
int comma_pos = encoding.indexOf(",", pos, Qt::CaseInsensitive);
QString value;
if (comma_pos == -1)
value = encoding.mid(pos + 1, comma_pos);
else
value = encoding.mid(pos + 1, comma_pos - (pos + 1));
if (value.toDouble() == 0.0)
return false;
return true;
}

View file

@ -47,23 +47,23 @@ class IRequestHandler;
class Connection : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Connection)
Q_OBJECT
Q_DISABLE_COPY(Connection)
public:
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = 0);
~Connection();
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = 0);
~Connection();
private slots:
void read();
void read();
private:
static bool acceptsGzipEncoding(const QString &encoding);
void sendResponse(const Response &response);
static bool acceptsGzipEncoding(const QString &encoding);
void sendResponse(const Response &response);
QTcpSocket *m_socket;
IRequestHandler *m_requestHandler;
QByteArray m_receivedData;
QTcpSocket *m_socket;
IRequestHandler *m_requestHandler;
QByteArray m_receivedData;
};
}

View file

@ -31,7 +31,6 @@
#include <QStringList>
#include <QUrl>
//#include <QVariant>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
#include <QUrlQuery>
#endif
@ -45,214 +44,196 @@ const QByteArray EOH("\r\n\r\n");
inline QString unquoted(const QString& str)
{
if ((str[0] == '\"') && (str[str.length() - 1] == '\"'))
return str.mid(1, str.length() - 2);
if ((str[0] == '\"') && (str[str.length() - 1] == '\"'))
return str.mid(1, str.length() - 2);
return str;
return str;
}
using namespace Http;
RequestParser::ErrorCode RequestParser::parse(const QByteArray& data, Request& request, uint maxContentLength)
{
return RequestParser(maxContentLength).parseHttpRequest(data, request);
return RequestParser(maxContentLength).parseHttpRequest(data, request);
}
RequestParser::RequestParser(uint maxContentLength)
: m_maxContentLength(maxContentLength)
: m_maxContentLength(maxContentLength)
{
}
RequestParser::ErrorCode RequestParser::parseHttpRequest(const QByteArray& data, Request& request)
{
m_request = Request();
m_request = Request();
// Parse HTTP request header
const int header_end = data.indexOf(EOH);
if (header_end < 0)
{
qDebug() << Q_FUNC_INFO << "incomplete request";
return IncompleteRequest;
}
if (!parseHttpHeader(data.left(header_end)))
{
qWarning() << Q_FUNC_INFO << "header parsing error";
return BadRequest;
}
// Parse HTTP request message
int content_length = 0;
if (m_request.headers.contains("content-length"))
{
content_length = m_request.headers["content-length"].toInt();
if (content_length > static_cast<int>(m_maxContentLength))
{
qWarning() << Q_FUNC_INFO << "bad request: message too long";
return BadRequest;
// Parse HTTP request header
const int header_end = data.indexOf(EOH);
if (header_end < 0) {
qDebug() << Q_FUNC_INFO << "incomplete request";
return IncompleteRequest;
}
QByteArray content = data.mid(header_end + EOH.length(), content_length);
if (content.length() < content_length)
{
qDebug() << Q_FUNC_INFO << "incomplete request";
return IncompleteRequest;
if (!parseHttpHeader(data.left(header_end))) {
qWarning() << Q_FUNC_INFO << "header parsing error";
return BadRequest;
}
if (!parseContent(content))
{
qWarning() << Q_FUNC_INFO << "message parsing error";
return BadRequest;
}
}
// qDebug() << Q_FUNC_INFO;
// qDebug() << "HTTP Request header:";
// qDebug() << data.left(header_end) << "\n";
// Parse HTTP request message
int content_length = 0;
if (m_request.headers.contains("content-length")) {
content_length = m_request.headers["content-length"].toInt();
if (content_length > static_cast<int>(m_maxContentLength)) {
qWarning() << Q_FUNC_INFO << "bad request: message too long";
return BadRequest;
}
request = m_request;
return NoError;
QByteArray content = data.mid(header_end + EOH.length(), content_length);
if (content.length() < content_length) {
qDebug() << Q_FUNC_INFO << "incomplete request";
return IncompleteRequest;
}
if (!parseContent(content)) {
qWarning() << Q_FUNC_INFO << "message parsing error";
return BadRequest;
}
}
// qDebug() << Q_FUNC_INFO;
// qDebug() << "HTTP Request header:";
// qDebug() << data.left(header_end) << "\n";
request = m_request;
return NoError;
}
bool RequestParser::parseStartingLine(const QString &line)
{
const QRegExp rx("^([A-Z]+)\\s+(\\S+)\\s+HTTP/\\d\\.\\d$");
const QRegExp rx("^([A-Z]+)\\s+(\\S+)\\s+HTTP/\\d\\.\\d$");
if (rx.indexIn(line.trimmed()) >= 0)
{
m_request.method = rx.cap(1);
if (rx.indexIn(line.trimmed()) >= 0) {
m_request.method = rx.cap(1);
QUrl url = QUrl::fromEncoded(rx.cap(2).toLatin1());
m_request.path = url.path(); // Path
QUrl url = QUrl::fromEncoded(rx.cap(2).toLatin1());
m_request.path = url.path(); // Path
// Parse GET parameters
// Parse GET parameters
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
QListIterator<QPair<QString, QString> > i(url.queryItems());
QListIterator<QPair<QString, QString> > i(url.queryItems());
#else
QListIterator<QPair<QString, QString> > i(QUrlQuery(url).queryItems());
QListIterator<QPair<QString, QString> > i(QUrlQuery(url).queryItems());
#endif
while (i.hasNext())
{
QPair<QString, QString> pair = i.next();
m_request.gets[pair.first] = pair.second;
while (i.hasNext()) {
QPair<QString, QString> pair = i.next();
m_request.gets[pair.first] = pair.second;
}
return true;
}
return true;
}
qWarning() << Q_FUNC_INFO << "invalid http header:" << line;
return false;
qWarning() << Q_FUNC_INFO << "invalid http header:" << line;
return false;
}
bool RequestParser::parseHeaderLine(const QString &line, QPair<QString, QString>& out)
{
int i = line.indexOf(QLatin1Char(':'));
if (i == -1)
{
qWarning() << Q_FUNC_INFO << "invalid http header:" << line;
return false;
}
int i = line.indexOf(QLatin1Char(':'));
if (i == -1) {
qWarning() << Q_FUNC_INFO << "invalid http header:" << line;
return false;
}
out = qMakePair(line.left(i).trimmed().toLower(), line.mid(i + 1).trimmed());
return true;
out = qMakePair(line.left(i).trimmed().toLower(), line.mid(i + 1).trimmed());
return true;
}
bool RequestParser::parseHttpHeader(const QByteArray &data)
{
QString str = QString::fromUtf8(data);
QStringList lines = str.trimmed().split(EOL);
QString str = QString::fromUtf8(data);
QStringList lines = str.trimmed().split(EOL);
QStringList headerLines;
foreach (const QString& line, lines)
{
if (line[0].isSpace()) // header line continuation
{
if (!headerLines.isEmpty()) // really continuation
{
headerLines.last() += QLatin1Char(' ');
headerLines.last() += line.trimmed();
}
QStringList headerLines;
foreach (const QString& line, lines) {
if (line[0].isSpace()) { // header line continuation
if (!headerLines.isEmpty()) { // really continuation
headerLines.last() += QLatin1Char(' ');
headerLines.last() += line.trimmed();
}
}
else {
headerLines.append(line);
}
}
else
{
headerLines.append(line);
if (headerLines.isEmpty())
return false; // Empty header
QStringList::Iterator it = headerLines.begin();
if (!parseStartingLine(*it))
return false;
++it;
for (; it != headerLines.end(); ++it) {
QPair<QString, QString> header;
if (!parseHeaderLine(*it, header))
return false;
m_request.headers[header.first] = header.second;
}
}
if (headerLines.isEmpty())
return false; // Empty header
QStringList::Iterator it = headerLines.begin();
if (!parseStartingLine(*it))
return false;
++it;
for (; it != headerLines.end(); ++it)
{
QPair<QString, QString> header;
if (!parseHeaderLine(*it, header))
return false;
m_request.headers[header.first] = header.second;
}
return true;
return true;
}
QList<QByteArray> RequestParser::splitMultipartData(const QByteArray& data, const QByteArray& boundary)
{
QList<QByteArray> ret;
QByteArray sep = boundary + EOL;
const int sepLength = sep.size();
QList<QByteArray> ret;
QByteArray sep = boundary + EOL;
const int sepLength = sep.size();
int start = 0, end = 0;
if ((end = data.indexOf(sep, start)) >= 0)
{
start = end + sepLength; // skip first boundary
int start = 0, end = 0;
if ((end = data.indexOf(sep, start)) >= 0) {
start = end + sepLength; // skip first boundary
while ((end = data.indexOf(sep, start)) >= 0)
{
ret << data.mid(start, end - start);
start = end + sepLength;
while ((end = data.indexOf(sep, start)) >= 0) {
ret << data.mid(start, end - start);
start = end + sepLength;
}
// last or single part
sep = boundary + "--" + EOL;
if ((end = data.indexOf(sep, start)) >= 0)
ret << data.mid(start, end - start);
}
// last or single part
sep = boundary + "--" + EOL;
if ((end = data.indexOf(sep, start)) >= 0)
ret << data.mid(start, end - start);
}
return ret;
return ret;
}
bool RequestParser::parseContent(const QByteArray& data)
{
// Parse message content
qDebug() << Q_FUNC_INFO << "Content-Length: " << m_request.headers["content-length"];
qDebug() << Q_FUNC_INFO << "data.size(): " << data.size();
// Parse message content
qDebug() << Q_FUNC_INFO << "Content-Length: " << m_request.headers["content-length"];
qDebug() << Q_FUNC_INFO << "data.size(): " << data.size();
// Parse url-encoded POST data
if (m_request.headers["content-type"].startsWith("application/x-www-form-urlencoded"))
{
QUrl url;
// Parse url-encoded POST data
if (m_request.headers["content-type"].startsWith("application/x-www-form-urlencoded")) {
QUrl url;
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
url.setEncodedQuery(data);
QListIterator<QPair<QString, QString> > i(url.queryItems());
url.setEncodedQuery(data);
QListIterator<QPair<QString, QString> > i(url.queryItems());
#else
url.setQuery(data);
QListIterator<QPair<QString, QString> > i(QUrlQuery(url).queryItems(QUrl::FullyDecoded));
url.setQuery(data);
QListIterator<QPair<QString, QString> > i(QUrlQuery(url).queryItems(QUrl::FullyDecoded));
#endif
while (i.hasNext())
{
QPair<QString, QString> pair = i.next();
m_request.posts[pair.first.toLower()] = pair.second;
while (i.hasNext()) {
QPair<QString, QString> pair = i.next();
m_request.posts[pair.first.toLower()] = pair.second;
}
return true;
}
return true;
}
// Parse multipart/form data (torrent file)
/**
// Parse multipart/form data (torrent file)
/**
data has the following format (if boundary is "cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5")
--cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5
@ -270,108 +251,96 @@ Content-Disposition: form-data; name=\"Upload\"
Submit Query
--cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5--
**/
QString content_type = m_request.headers["content-type"];
if (content_type.startsWith("multipart/form-data"))
{
const QRegExp boundaryRegexQuoted("boundary=\"([ \\w'()+,-\\./:=\\?]+)\"");
const QRegExp boundaryRegexNotQuoted("boundary=([\\w'()+,-\\./:=\\?]+)");
QString content_type = m_request.headers["content-type"];
if (content_type.startsWith("multipart/form-data")) {
const QRegExp boundaryRegexQuoted("boundary=\"([ \\w'()+,-\\./:=\\?]+)\"");
const QRegExp boundaryRegexNotQuoted("boundary=([\\w'()+,-\\./:=\\?]+)");
QByteArray boundary;
if (boundaryRegexQuoted.indexIn(content_type) < 0)
{
if (boundaryRegexNotQuoted.indexIn(content_type) < 0)
{
qWarning() << "Could not find boundary in multipart/form-data header!";
return false;
}
else
{
boundary = "--" + boundaryRegexNotQuoted.cap(1).toLatin1();
}
}
else
{
boundary = "--" + boundaryRegexQuoted.cap(1).toLatin1();
QByteArray boundary;
if (boundaryRegexQuoted.indexIn(content_type) < 0) {
if (boundaryRegexNotQuoted.indexIn(content_type) < 0) {
qWarning() << "Could not find boundary in multipart/form-data header!";
return false;
}
else {
boundary = "--" + boundaryRegexNotQuoted.cap(1).toLatin1();
}
}
else {
boundary = "--" + boundaryRegexQuoted.cap(1).toLatin1();
}
qDebug() << "Boundary is " << boundary;
QList<QByteArray> parts = splitMultipartData(data, boundary);
qDebug() << parts.size() << "parts in data";
foreach (const QByteArray& part, parts) {
if (!parseFormData(part))
return false;
}
return true;
}
qDebug() << "Boundary is " << boundary;
QList<QByteArray> parts = splitMultipartData(data, boundary);
qDebug() << parts.size() << "parts in data";
foreach (const QByteArray& part, parts)
{
if (!parseFormData(part))
return false;
}
return true;
}
qWarning() << Q_FUNC_INFO << "unknown content type:" << qPrintable(content_type);
return false;
qWarning() << Q_FUNC_INFO << "unknown content type:" << qPrintable(content_type);
return false;
}
bool RequestParser::parseFormData(const QByteArray& data)
{
// Parse form data header
const int header_end = data.indexOf(EOH);
if (header_end < 0)
{
qDebug() << "Invalid form data: \n" << data;
return false;
}
// Parse form data header
const int header_end = data.indexOf(EOH);
if (header_end < 0) {
qDebug() << "Invalid form data: \n" << data;
return false;
}
QString header_str = QString::fromUtf8(data.left(header_end));
QStringList lines = header_str.trimmed().split(EOL);
QStringMap headers;
foreach (const QString& line, lines)
{
QPair<QString, QString> header;
if (!parseHeaderLine(line, header))
return false;
QString header_str = QString::fromUtf8(data.left(header_end));
QStringList lines = header_str.trimmed().split(EOL);
QStringMap headers;
foreach (const QString& line, lines) {
QPair<QString, QString> header;
if (!parseHeaderLine(line, header))
return false;
headers[header.first] = header.second;
}
headers[header.first] = header.second;
}
QStringMap disposition;
if (!headers.contains("content-disposition") ||
!parseHeaderValue(headers["content-disposition"], disposition) ||
!disposition.contains("name"))
{
qDebug() << "Invalid form data header: \n" << header_str;
return false;
}
QStringMap disposition;
if (!headers.contains("content-disposition")
|| !parseHeaderValue(headers["content-disposition"], disposition)
|| !disposition.contains("name")) {
qDebug() << "Invalid form data header: \n" << header_str;
return false;
}
if (disposition.contains("filename"))
{
UploadedFile ufile;
ufile.filename = disposition["filename"];
ufile.type = disposition["content-type"];
ufile.data = data.mid(header_end + EOH.length());
if (disposition.contains("filename")) {
UploadedFile ufile;
ufile.filename = disposition["filename"];
ufile.type = disposition["content-type"];
ufile.data = data.mid(header_end + EOH.length());
m_request.files[disposition["name"]] = ufile;
}
else
{
m_request.posts[disposition["name"]] = QString::fromUtf8(data.mid(header_end + EOH.length()));
}
m_request.files[disposition["name"]] = ufile;
}
else {
m_request.posts[disposition["name"]] = QString::fromUtf8(data.mid(header_end + EOH.length()));
}
return true;
return true;
}
bool RequestParser::parseHeaderValue(const QString& value, QStringMap& out)
{
QStringList items = value.split(QLatin1Char(';'));
out[""] = items[0];
QStringList items = value.split(QLatin1Char(';'));
out[""] = items[0];
for (QStringList::size_type i = 1; i < items.size(); ++i)
{
int pos = items[i].indexOf("=");
if (pos < 0)
return false;
for (QStringList::size_type i = 1; i < items.size(); ++i) {
int pos = items[i].indexOf("=");
if (pos < 0)
return false;
out[items[i].left(pos).trimmed()] = unquoted(items[i].mid(pos + 1).trimmed());
}
out[items[i].left(pos).trimmed()] = unquoted(items[i].mid(pos + 1).trimmed());
}
return true;
return true;
}

View file

@ -40,28 +40,33 @@ namespace Http
class RequestParser
{
public:
enum ErrorCode { NoError = 0, IncompleteRequest, BadRequest };
enum ErrorCode
{
NoError = 0,
IncompleteRequest,
BadRequest
};
// when result != NoError parsed request is undefined
// Warning! Header names are converted to lower-case.
static ErrorCode parse(const QByteArray& data, Request& request, uint maxContentLength = 10000000 /* ~10MB */);
// when result != NoError parsed request is undefined
// Warning! Header names are converted to lower-case.
static ErrorCode parse(const QByteArray &data, Request &request, uint maxContentLength = 10000000 /* ~10MB */);
private:
RequestParser(uint maxContentLength);
RequestParser(uint maxContentLength);
ErrorCode parseHttpRequest(const QByteArray& data, Request& request);
ErrorCode parseHttpRequest(const QByteArray &data, Request &request);
bool parseHttpHeader(const QByteArray& data);
bool parseStartingLine(const QString &line);
bool parseContent(const QByteArray& data);
bool parseFormData(const QByteArray& data);
QList<QByteArray> splitMultipartData(const QByteArray& data, const QByteArray& boundary);
bool parseHttpHeader(const QByteArray &data);
bool parseStartingLine(const QString &line);
bool parseContent(const QByteArray &data);
bool parseFormData(const QByteArray &data);
QList<QByteArray> splitMultipartData(const QByteArray &data, const QByteArray &boundary);
static bool parseHeaderLine(const QString& line, QPair<QString, QString>& out);
static bool parseHeaderValue(const QString& value, QStringMap& out);
static bool parseHeaderLine(const QString &line, QPair<QString, QString> &out);
static bool parseHeaderValue(const QString &value, QStringMap &out);
const uint m_maxContentLength;
Request m_request;
const uint m_maxContentLength;
Request m_request;
};
}

View file

@ -38,96 +38,87 @@ using namespace Http;
QByteArray ResponseGenerator::generate(Response response)
{
if (response.headers[HEADER_CONTENT_ENCODING] == "gzip")
{
// A gzip seems to have 23 bytes overhead.
// Also "Content-Encoding: gzip\r\n" is 26 bytes long
// So we only benefit from gzip if the message is bigger than 23+26 = 49
// If the message is smaller than 49 bytes we actually send MORE data if we gzip
QByteArray dest_buf;
if ((response.content.size() > 49) && (gCompress(response.content, dest_buf)))
{
response.content = dest_buf;
if (response.headers[HEADER_CONTENT_ENCODING] == "gzip") {
// A gzip seems to have 23 bytes overhead.
// Also "Content-Encoding: gzip\r\n" is 26 bytes long
// So we only benefit from gzip if the message is bigger than 23+26 = 49
// If the message is smaller than 49 bytes we actually send MORE data if we gzip
QByteArray dest_buf;
if ((response.content.size() > 49) && (gCompress(response.content, dest_buf)))
response.content = dest_buf;
else
response.headers.remove(HEADER_CONTENT_ENCODING);
}
else
{
response.headers.remove(HEADER_CONTENT_ENCODING);
}
}
if (response.content.length() > 0)
response.headers[HEADER_CONTENT_LENGTH] = QString::number(response.content.length());
if (response.content.length() > 0)
response.headers[HEADER_CONTENT_LENGTH] = QString::number(response.content.length());
QString ret(QLatin1String("HTTP/1.1 %1 %2\r\n%3\r\n"));
QString ret(QLatin1String("HTTP/1.1 %1 %2\r\n%3\r\n"));
QString header;
foreach (const QString& key, response.headers.keys())
header += QString("%1: %2\r\n").arg(key).arg(response.headers[key]);
QString header;
foreach (const QString& key, response.headers.keys())
header += QString("%1: %2\r\n").arg(key).arg(response.headers[key]);
ret = ret.arg(response.status.code).arg(response.status.text).arg(header);
// qDebug() << Q_FUNC_INFO;
// qDebug() << "HTTP Response header:";
// qDebug() << ret;
return ret.toUtf8() + response.content;
ret = ret.arg(response.status.code).arg(response.status.text).arg(header);
// qDebug() << Q_FUNC_INFO;
// qDebug() << "HTTP Response header:";
// qDebug() << ret;
return ret.toUtf8() + response.content;
}
bool gCompress(QByteArray data, QByteArray& dest_buffer)
{
static const int BUFSIZE = 128 * 1024;
char tmp_buf[BUFSIZE];
int ret;
static const int BUFSIZE = 128 * 1024;
char tmp_buf[BUFSIZE];
int ret;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.next_in = reinterpret_cast<unsigned char*>(data.data());
strm.avail_in = data.length();
strm.next_out = reinterpret_cast<unsigned char*>(tmp_buf);
strm.avail_out = BUFSIZE;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.next_in = reinterpret_cast<unsigned char*>(data.data());
strm.avail_in = data.length();
strm.next_out = reinterpret_cast<unsigned char*>(tmp_buf);
strm.avail_out = BUFSIZE;
//windowBits = 15+16 to enable gzip
//From the zlib manual: windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits
//to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper.
ret = deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, 15+16, 8, Z_DEFAULT_STRATEGY);
//windowBits = 15+16 to enable gzip
//From the zlib manual: windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits
//to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper.
ret = deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
if (ret != Z_OK)
return false;
while (strm.avail_in != 0)
{
ret = deflate(&strm, Z_NO_FLUSH);
if (ret != Z_OK)
return false;
return false;
if (strm.avail_out == 0)
{
dest_buffer.append(tmp_buf, BUFSIZE);
strm.next_out = reinterpret_cast<unsigned char*>(tmp_buf);
strm.avail_out = BUFSIZE;
}
}
while (strm.avail_in != 0) {
ret = deflate(&strm, Z_NO_FLUSH);
if (ret != Z_OK)
return false;
int deflate_res = Z_OK;
while (deflate_res == Z_OK)
{
if (strm.avail_out == 0)
{
dest_buffer.append(tmp_buf, BUFSIZE);
strm.next_out = reinterpret_cast<unsigned char*>(tmp_buf);
strm.avail_out = BUFSIZE;
if (strm.avail_out == 0) {
dest_buffer.append(tmp_buf, BUFSIZE);
strm.next_out = reinterpret_cast<unsigned char*>(tmp_buf);
strm.avail_out = BUFSIZE;
}
}
deflate_res = deflate(&strm, Z_FINISH);
}
int deflate_res = Z_OK;
while (deflate_res == Z_OK) {
if (strm.avail_out == 0) {
dest_buffer.append(tmp_buf, BUFSIZE);
strm.next_out = reinterpret_cast<unsigned char*>(tmp_buf);
strm.avail_out = BUFSIZE;
}
if (deflate_res != Z_STREAM_END)
return false;
deflate_res = deflate(&strm, Z_FINISH);
}
dest_buffer.append(tmp_buf, BUFSIZE - strm.avail_out);
deflateEnd(&strm);
if (deflate_res != Z_STREAM_END)
return false;
return true;
dest_buffer.append(tmp_buf, BUFSIZE - strm.avail_out);
deflateEnd(&strm);
return true;
}

View file

@ -39,8 +39,8 @@
using namespace Http;
Server::Server(IRequestHandler *requestHandler, QObject* parent)
: QTcpServer(parent)
, m_requestHandler(requestHandler)
: QTcpServer(parent)
, m_requestHandler(requestHandler)
#ifndef QT_NO_OPENSSL
, m_https(false)
#endif
@ -54,16 +54,16 @@ Server::~Server()
#ifndef QT_NO_OPENSSL
void Server::enableHttps(const QSslCertificate &certificate, const QSslKey &key)
{
m_certificate = certificate;
m_key = key;
m_https = true;
m_certificate = certificate;
m_key = key;
m_https = true;
}
void Server::disableHttps()
{
m_https = false;
m_certificate.clear();
m_key.clear();
m_https = false;
m_certificate.clear();
m_key.clear();
}
#endif
@ -73,28 +73,26 @@ void Server::incomingConnection(qintptr socketDescriptor)
void Server::incomingConnection(int socketDescriptor)
#endif
{
QTcpSocket *serverSocket;
#ifndef QT_NO_OPENSSL
if (m_https)
serverSocket = new QSslSocket(this);
else
#endif
serverSocket = new QTcpSocket(this);
if (serverSocket->setSocketDescriptor(socketDescriptor))
{
QTcpSocket *serverSocket;
#ifndef QT_NO_OPENSSL
if (m_https)
{
static_cast<QSslSocket*>(serverSocket)->setProtocol(QSsl::AnyProtocol);
static_cast<QSslSocket*>(serverSocket)->setPrivateKey(m_key);
static_cast<QSslSocket*>(serverSocket)->setLocalCertificate(m_certificate);
static_cast<QSslSocket*>(serverSocket)->startServerEncryption();
}
serverSocket = new QSslSocket(this);
else
#endif
new Connection(serverSocket, m_requestHandler, this);
}
else
{
serverSocket->deleteLater();
}
serverSocket = new QTcpSocket(this);
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
#ifndef QT_NO_OPENSSL
if (m_https) {
static_cast<QSslSocket*>(serverSocket)->setProtocol(QSsl::AnyProtocol);
static_cast<QSslSocket*>(serverSocket)->setPrivateKey(m_key);
static_cast<QSslSocket*>(serverSocket)->setLocalCertificate(m_certificate);
static_cast<QSslSocket*>(serverSocket)->startServerEncryption();
}
#endif
new Connection(serverSocket, m_requestHandler, this);
}
else {
serverSocket->deleteLater();
}
}

View file

@ -47,31 +47,31 @@ class Connection;
class Server : public QTcpServer
{
Q_OBJECT
Q_DISABLE_COPY(Server)
Q_OBJECT
Q_DISABLE_COPY(Server)
public:
Server(IRequestHandler *requestHandler, QObject *parent = 0);
~Server();
Server(IRequestHandler *requestHandler, QObject *parent = 0);
~Server();
#ifndef QT_NO_OPENSSL
void enableHttps(const QSslCertificate &certificate, const QSslKey &key);
void disableHttps();
void enableHttps(const QSslCertificate &certificate, const QSslKey &key);
void disableHttps();
#endif
private:
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
void incomingConnection(qintptr socketDescriptor);
void incomingConnection(qintptr socketDescriptor);
#else
void incomingConnection(int socketDescriptor);
void incomingConnection(int socketDescriptor);
#endif
private:
IRequestHandler *m_requestHandler;
IRequestHandler *m_requestHandler;
#ifndef QT_NO_OPENSSL
bool m_https;
QSslCertificate m_certificate;
QSslKey m_key;
bool m_https;
QSslCertificate m_certificate;
QSslKey m_key;
#endif
};