1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-20 10:46:35 +01:00

PageFormCompleter: Improved detecting sent form.

Also added new test.
This commit is contained in:
nowrep 2013-01-26 11:09:25 +01:00
parent c1c1b4130e
commit 3caf5535cd
4 changed files with 56 additions and 41 deletions

View File

@ -20,6 +20,7 @@
#include <QWebPage> #include <QWebPage>
#include <QWebFrame> #include <QWebFrame>
#include <QWebElement> #include <QWebElement>
#include <QDebug>
PageFormCompleter::PageFormCompleter(QWebPage* page) PageFormCompleter::PageFormCompleter(QWebPage* page)
: m_page(page) : m_page(page)
@ -39,6 +40,11 @@ PageFormData PageFormCompleter::extractFormData(const QByteArray &postData) cons
QByteArray data = convertWebKitFormBoundaryIfNecessary(postData); QByteArray data = convertWebKitFormBoundaryIfNecessary(postData);
PageFormData formData = {false, QString(), QString(), data}; PageFormData formData = {false, QString(), QString(), data};
if (!data.contains('=')) {
qDebug() << "PageFormCompleter: Invalid form data" << data;
return formData;
}
/* Find all form elements in page (in all frames) */ /* Find all form elements in page (in all frames) */
QList<QWebFrame*> frames; QList<QWebFrame*> frames;
frames.append(m_page->mainFrame()); frames.append(m_page->mainFrame());
@ -48,13 +54,16 @@ PageFormData PageFormCompleter::extractFormData(const QByteArray &postData) cons
frames += frame->childFrames(); frames += frame->childFrames();
} }
const QueryItems &queryItems = createQueryItems(data);
/* Find form that contains password value sent in data */ /* Find form that contains password value sent in data */
foreach(const QWebElement & formElement, allForms) { foreach(const QWebElement & formElement, allForms) {
foreach(const QWebElement & inputElement, formElement.findAll("input[type=\"password\"]")) { const QWebElementCollection &inputs = formElement.findAll("input[type=\"password\"]");
foreach(QWebElement inputElement, inputs) {
passwordName = inputElement.attribute("name"); passwordName = inputElement.attribute("name");
passwordValue = getValueFromData(data, inputElement); passwordValue = inputElement.evaluateJavaScript("this.value").toString();
if (!passwordValue.isEmpty() && dataContains(data, passwordName)) { if (queryItemsContains(queryItems, passwordName, passwordValue)) {
foundForm = formElement; foundForm = formElement;
break; break;
} }
@ -79,9 +88,10 @@ PageFormData PageFormCompleter::extractFormData(const QByteArray &postData) cons
<< "input:not([type=\"hidden\"])"; << "input:not([type=\"hidden\"])";
foreach(const QString & selector, selectors) { foreach(const QString & selector, selectors) {
foreach(const QWebElement & element, foundForm.findAll(selector)) { const QWebElementCollection &inputs = foundForm.findAll(selector);
foreach(QWebElement element, inputs) {
usernameName = element.attribute("name"); usernameName = element.attribute("name");
usernameValue = getValueFromData(data, element); usernameValue = element.evaluateJavaScript("this.value").toString();
if (!usernameName.isEmpty() && !usernameValue.isEmpty()) { if (!usernameName.isEmpty() && !usernameValue.isEmpty()) {
found = true; found = true;
@ -147,47 +157,24 @@ void PageFormCompleter::completePage(const QByteArray &data) const
} }
} }
bool PageFormCompleter::dataContains(const QByteArray &data, const QString &attributeName) const bool PageFormCompleter::queryItemsContains(const QueryItems &queryItems, const QString &attributeName,
const QString &attributeValue) const
{ {
const QueryItems &queryItems = createQueryItems(data); if (attributeName.isEmpty() || attributeValue.isEmpty()) {
return false;
}
for (int i = 0; i < queryItems.count(); i++) { for (int i = 0; i < queryItems.count(); i++) {
const QueryItem &item = queryItems.at(i); const QueryItem &item = queryItems.at(i);
if (item.first == attributeName) { if (item.first == attributeName) {
return !item.second.isEmpty(); return item.second == attributeValue;
} }
} }
return false; return false;
} }
QString PageFormCompleter::getValueFromData(const QByteArray &data, QWebElement element) const
{
QString name = element.attribute("name");
if (name.isEmpty()) {
return QString();
}
QString value = element.evaluateJavaScript("this.value").toString();
if (!value.isEmpty()) {
return value;
}
const QueryItems &queryItems = createQueryItems(data);
for (int i = 0; i < queryItems.count(); i++) {
const QueryItem &item = queryItems.at(i);
if (item.first == name) {
value = item.second.toUtf8();
}
}
return value;
}
QByteArray PageFormCompleter::convertWebKitFormBoundaryIfNecessary(const QByteArray &data) const QByteArray PageFormCompleter::convertWebKitFormBoundaryIfNecessary(const QByteArray &data) const
{ {
/* Sometimes, data are passed in this format: /* Sometimes, data are passed in this format:

View File

@ -46,8 +46,8 @@ private:
typedef QPair<QString, QString> QueryItem; typedef QPair<QString, QString> QueryItem;
typedef QList<QPair<QString, QString> > QueryItems; typedef QList<QPair<QString, QString> > QueryItems;
bool dataContains(const QByteArray &data, const QString &attributeName) const; bool queryItemsContains(const QueryItems &queryItems, const QString &attributeName,
QString getValueFromData(const QByteArray &data, QWebElement element) const; const QString &attributeValue) const;
QByteArray convertWebKitFormBoundaryIfNecessary(const QByteArray &data) const; QByteArray convertWebKitFormBoundaryIfNecessary(const QByteArray &data) const;
QueryItems createQueryItems(const QByteArray &data) const; QueryItems createQueryItems(const QByteArray &data) const;

View File

@ -145,13 +145,14 @@ void FormCompleterTest::extractFormTest1()
void FormCompleterTest::extractFormTest2() void FormCompleterTest::extractFormTest2()
{ {
// Test special characters // Test special characters (even in input name)
QByteArray data = "username=tst_username&password=tst_password"; QByteArray data = "use%C2%B6+_nam%C4%8D=%2B%C4%9B+%2B%2B+%C3%A9%C3%AD%C2%A7%60%5D%7C%7E%C4%9111+%2B%21%3A"
"&pA+%5DsQ+%2Bword=%2B%C4%9B%C5%A1+asn%7E%C4%91%C2%B0%23%26%23+%7C%E2%82%AC";
QString html = QString::fromUtf8("<form name='form1' method='post' action='foo.php'>" QString html = QString::fromUtf8("<form name='form1' method='post' action='foo.php'>"
"<input id='id1' type='text' name='username' value='+ě ++ éí§`]|~đ11 +!:'>" "<input id='id1' type='text' name='use¶ _namč' value='+ě ++ éí§`]|~đ11 +!:'>"
"<input id='id2' type='password' name='password' value='+ěš asn~đ°#&# |\€'>" "<input id='id2' type='password' name='pA ]sQ +word' value='+ěš asn~đ°#&# |€'>"
"<input type='submit' value='submit' name='submit'>" "<input type='submit' value='submit' name='submit'>"
"</form>"); "</form>");
@ -159,7 +160,33 @@ void FormCompleterTest::extractFormTest2()
QVERIFY(form.found == true); QVERIFY(form.found == true);
QCOMPARE(form.username, QString::fromUtf8("+ě ++ éí§`]|~đ11 +!:")); QCOMPARE(form.username, QString::fromUtf8("+ě ++ éí§`]|~đ11 +!:"));
QCOMPARE(form.password, QString::fromUtf8("+ěš asn~đ°#&# |\")); QCOMPARE(form.password, QString::fromUtf8("+ěš asn~đ°#&# |€"));
}
void FormCompleterTest::extractFormTest3()
{
// Test detecting sent form between 2 identical forms
// but only one form is filled with correct data
QByteArray data = "username=tst_username&password=tst_password";
QString html = "<form name='form1' method='post' action='foo.php'>"
"<input id='id1' type='text' name='username' value='wrong_username'>"
"<input id='id2' type='password' name='password' value='wrong_password'>"
"<input type='submit' value='submit' name='submit'>"
"</form>";
QString html2 = "<form name='form2' method='post' action='foo2.php'>"
"<input id='id3' type='text' name='username' value='tst_username'>"
"<input id='id4' type='password' name='password' value='tst_password'>"
"<input type='submit' value='submit' name='submit'>"
"</form>";
PageFormData form = extractFormData(html + html2, data);
QVERIFY(form.found == true);
QCOMPARE(form.username, QString("tst_username"));
QCOMPARE(form.password, QString("tst_password"));
} }
void FormCompleterTest::completeWithData(const QString &html, const QByteArray &data) void FormCompleterTest::completeWithData(const QString &html, const QByteArray &data)

View File

@ -40,6 +40,7 @@ private slots:
void extractFormTest1(); void extractFormTest1();
void extractFormTest2(); void extractFormTest2();
void extractFormTest3();
private: private:
void completeWithData(const QString &html, const QByteArray &data); void completeWithData(const QString &html, const QByteArray &data);