|
|
|
@ -31,7 +31,6 @@
@@ -31,7 +31,6 @@
|
|
|
|
|
|
|
|
|
|
#include <QStringList> |
|
|
|
|
#include <QUrl> |
|
|
|
|
//#include <QVariant>
|
|
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) |
|
|
|
|
#include <QUrlQuery> |
|
|
|
|
#endif |
|
|
|
@ -69,38 +68,32 @@ RequestParser::ErrorCode RequestParser::parseHttpRequest(const QByteArray& data,
@@ -69,38 +68,32 @@ RequestParser::ErrorCode RequestParser::parseHttpRequest(const QByteArray& data,
|
|
|
|
|
|
|
|
|
|
// Parse HTTP request header
|
|
|
|
|
const int header_end = data.indexOf(EOH); |
|
|
|
|
if (header_end < 0) |
|
|
|
|
{ |
|
|
|
|
if (header_end < 0) { |
|
|
|
|
qDebug() << Q_FUNC_INFO << "incomplete request"; |
|
|
|
|
return IncompleteRequest; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!parseHttpHeader(data.left(header_end))) |
|
|
|
|
{ |
|
|
|
|
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")) |
|
|
|
|
{ |
|
|
|
|
if (m_request.headers.contains("content-length")) { |
|
|
|
|
content_length = m_request.headers["content-length"].toInt(); |
|
|
|
|
if (content_length > static_cast<int>(m_maxContentLength)) |
|
|
|
|
{ |
|
|
|
|
if (content_length > static_cast<int>(m_maxContentLength)) { |
|
|
|
|
qWarning() << Q_FUNC_INFO << "bad request: message too long"; |
|
|
|
|
return BadRequest; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QByteArray content = data.mid(header_end + EOH.length(), content_length); |
|
|
|
|
if (content.length() < content_length) |
|
|
|
|
{ |
|
|
|
|
if (content.length() < content_length) { |
|
|
|
|
qDebug() << Q_FUNC_INFO << "incomplete request"; |
|
|
|
|
return IncompleteRequest; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!parseContent(content)) |
|
|
|
|
{ |
|
|
|
|
if (!parseContent(content)) { |
|
|
|
|
qWarning() << Q_FUNC_INFO << "message parsing error"; |
|
|
|
|
return BadRequest; |
|
|
|
|
} |
|
|
|
@ -118,8 +111,7 @@ bool RequestParser::parseStartingLine(const QString &line)
@@ -118,8 +111,7 @@ bool RequestParser::parseStartingLine(const QString &line)
|
|
|
|
|
{ |
|
|
|
|
const QRegExp rx("^([A-Z]+)\\s+(\\S+)\\s+HTTP/\\d\\.\\d$"); |
|
|
|
|
|
|
|
|
|
if (rx.indexIn(line.trimmed()) >= 0) |
|
|
|
|
{ |
|
|
|
|
if (rx.indexIn(line.trimmed()) >= 0) { |
|
|
|
|
m_request.method = rx.cap(1); |
|
|
|
|
|
|
|
|
|
QUrl url = QUrl::fromEncoded(rx.cap(2).toLatin1()); |
|
|
|
@ -131,8 +123,7 @@ bool RequestParser::parseStartingLine(const QString &line)
@@ -131,8 +123,7 @@ bool RequestParser::parseStartingLine(const QString &line)
|
|
|
|
|
#else |
|
|
|
|
QListIterator<QPair<QString, QString> > i(QUrlQuery(url).queryItems()); |
|
|
|
|
#endif |
|
|
|
|
while (i.hasNext()) |
|
|
|
|
{ |
|
|
|
|
while (i.hasNext()) { |
|
|
|
|
QPair<QString, QString> pair = i.next(); |
|
|
|
|
m_request.gets[pair.first] = pair.second; |
|
|
|
|
} |
|
|
|
@ -147,8 +138,7 @@ bool RequestParser::parseStartingLine(const QString &line)
@@ -147,8 +138,7 @@ bool RequestParser::parseStartingLine(const QString &line)
|
|
|
|
|
bool RequestParser::parseHeaderLine(const QString &line, QPair<QString, QString>& out) |
|
|
|
|
{ |
|
|
|
|
int i = line.indexOf(QLatin1Char(':')); |
|
|
|
|
if (i == -1) |
|
|
|
|
{ |
|
|
|
|
if (i == -1) { |
|
|
|
|
qWarning() << Q_FUNC_INFO << "invalid http header:" << line; |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
@ -163,18 +153,14 @@ bool RequestParser::parseHttpHeader(const QByteArray &data)
@@ -163,18 +153,14 @@ bool RequestParser::parseHttpHeader(const QByteArray &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
|
|
|
|
|
{ |
|
|
|
|
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 |
|
|
|
|
{ |
|
|
|
|
else { |
|
|
|
|
headerLines.append(line); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -187,8 +173,7 @@ bool RequestParser::parseHttpHeader(const QByteArray &data)
@@ -187,8 +173,7 @@ bool RequestParser::parseHttpHeader(const QByteArray &data)
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
++it; |
|
|
|
|
for (; it != headerLines.end(); ++it) |
|
|
|
|
{ |
|
|
|
|
for (; it != headerLines.end(); ++it) { |
|
|
|
|
QPair<QString, QString> header; |
|
|
|
|
if (!parseHeaderLine(*it, header)) |
|
|
|
|
return false; |
|
|
|
@ -206,12 +191,10 @@ QList<QByteArray> RequestParser::splitMultipartData(const QByteArray& data, cons
@@ -206,12 +191,10 @@ QList<QByteArray> RequestParser::splitMultipartData(const QByteArray& data, cons
|
|
|
|
|
const int sepLength = sep.size(); |
|
|
|
|
|
|
|
|
|
int start = 0, end = 0; |
|
|
|
|
if ((end = data.indexOf(sep, start)) >= 0) |
|
|
|
|
{ |
|
|
|
|
if ((end = data.indexOf(sep, start)) >= 0) { |
|
|
|
|
start = end + sepLength; // skip first boundary
|
|
|
|
|
|
|
|
|
|
while ((end = data.indexOf(sep, start)) >= 0) |
|
|
|
|
{ |
|
|
|
|
while ((end = data.indexOf(sep, start)) >= 0) { |
|
|
|
|
ret << data.mid(start, end - start); |
|
|
|
|
start = end + sepLength; |
|
|
|
|
} |
|
|
|
@ -232,8 +215,7 @@ bool RequestParser::parseContent(const QByteArray& data)
@@ -232,8 +215,7 @@ bool RequestParser::parseContent(const QByteArray& data)
|
|
|
|
|
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")) |
|
|
|
|
{ |
|
|
|
|
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); |
|
|
|
@ -242,8 +224,7 @@ bool RequestParser::parseContent(const QByteArray& data)
@@ -242,8 +224,7 @@ bool RequestParser::parseContent(const QByteArray& data)
|
|
|
|
|
url.setQuery(data); |
|
|
|
|
QListIterator<QPair<QString, QString> > i(QUrlQuery(url).queryItems(QUrl::FullyDecoded)); |
|
|
|
|
#endif |
|
|
|
|
while (i.hasNext()) |
|
|
|
|
{ |
|
|
|
|
while (i.hasNext()) { |
|
|
|
|
QPair<QString, QString> pair = i.next(); |
|
|
|
|
m_request.posts[pair.first.toLower()] = pair.second; |
|
|
|
|
} |
|
|
|
@ -271,26 +252,21 @@ Submit Query
@@ -271,26 +252,21 @@ Submit Query
|
|
|
|
|
--cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5-- |
|
|
|
|
**/ |
|
|
|
|
QString content_type = m_request.headers["content-type"]; |
|
|
|
|
if (content_type.startsWith("multipart/form-data")) |
|
|
|
|
{ |
|
|
|
|
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) |
|
|
|
|
{ |
|
|
|
|
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 |
|
|
|
|
{ |
|
|
|
|
else { |
|
|
|
|
boundary = "--" + boundaryRegexNotQuoted.cap(1).toLatin1(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
else { |
|
|
|
|
boundary = "--" + boundaryRegexQuoted.cap(1).toLatin1(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -298,8 +274,7 @@ Submit Query
@@ -298,8 +274,7 @@ Submit Query
|
|
|
|
|
QList<QByteArray> parts = splitMultipartData(data, boundary); |
|
|
|
|
qDebug() << parts.size() << "parts in data"; |
|
|
|
|
|
|
|
|
|
foreach (const QByteArray& part, parts) |
|
|
|
|
{ |
|
|
|
|
foreach (const QByteArray& part, parts) { |
|
|
|
|
if (!parseFormData(part)) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
@ -315,8 +290,7 @@ bool RequestParser::parseFormData(const QByteArray& data)
@@ -315,8 +290,7 @@ bool RequestParser::parseFormData(const QByteArray& data)
|
|
|
|
|
{ |
|
|
|
|
// Parse form data header
|
|
|
|
|
const int header_end = data.indexOf(EOH); |
|
|
|
|
if (header_end < 0) |
|
|
|
|
{ |
|
|
|
|
if (header_end < 0) { |
|
|
|
|
qDebug() << "Invalid form data: \n" << data; |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
@ -324,8 +298,7 @@ bool RequestParser::parseFormData(const QByteArray& data)
@@ -324,8 +298,7 @@ bool RequestParser::parseFormData(const QByteArray& data)
|
|
|
|
|
QString header_str = QString::fromUtf8(data.left(header_end)); |
|
|
|
|
QStringList lines = header_str.trimmed().split(EOL); |
|
|
|
|
QStringMap headers; |
|
|
|
|
foreach (const QString& line, lines) |
|
|
|
|
{ |
|
|
|
|
foreach (const QString& line, lines) { |
|
|
|
|
QPair<QString, QString> header; |
|
|
|
|
if (!parseHeaderLine(line, header)) |
|
|
|
|
return false; |
|
|
|
@ -334,16 +307,14 @@ bool RequestParser::parseFormData(const QByteArray& data)
@@ -334,16 +307,14 @@ bool RequestParser::parseFormData(const QByteArray& data)
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QStringMap disposition; |
|
|
|
|
if (!headers.contains("content-disposition") || |
|
|
|
|
!parseHeaderValue(headers["content-disposition"], disposition) || |
|
|
|
|
!disposition.contains("name")) |
|
|
|
|
{ |
|
|
|
|
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")) |
|
|
|
|
{ |
|
|
|
|
if (disposition.contains("filename")) { |
|
|
|
|
UploadedFile ufile; |
|
|
|
|
ufile.filename = disposition["filename"]; |
|
|
|
|
ufile.type = disposition["content-type"]; |
|
|
|
@ -351,8 +322,7 @@ bool RequestParser::parseFormData(const QByteArray& data)
@@ -351,8 +322,7 @@ bool RequestParser::parseFormData(const QByteArray& data)
|
|
|
|
|
|
|
|
|
|
m_request.files[disposition["name"]] = ufile; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
else { |
|
|
|
|
m_request.posts[disposition["name"]] = QString::fromUtf8(data.mid(header_end + EOH.length())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -364,8 +334,7 @@ bool RequestParser::parseHeaderValue(const QString& value, QStringMap& out)
@@ -364,8 +334,7 @@ bool RequestParser::parseHeaderValue(const QString& value, QStringMap& out)
|
|
|
|
|
QStringList items = value.split(QLatin1Char(';')); |
|
|
|
|
out[""] = items[0]; |
|
|
|
|
|
|
|
|
|
for (QStringList::size_type i = 1; i < items.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
for (QStringList::size_type i = 1; i < items.size(); ++i) { |
|
|
|
|
int pos = items[i].indexOf("="); |
|
|
|
|
if (pos < 0) |
|
|
|
|
return false; |
|
|
|
|