adds cookie management functions to Webkit::Browser
This commit is contained in:
parent
dc5130ce6b
commit
fb119f6ff8
|
@ -86,6 +86,20 @@ class Capybara::Driver::Webkit
|
||||||
command "Render", path, width, height
|
command "Render", path, width, height
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_cookie(cookie)
|
||||||
|
command "SetCookie", cookie
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear_cookies
|
||||||
|
command "ClearCookies"
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_cookies
|
||||||
|
command("GetCookies").lines
|
||||||
|
.map { |line| line.strip }
|
||||||
|
.select { |line| !line.empty? }
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def start_server
|
def start_server
|
||||||
|
|
|
@ -884,6 +884,61 @@ describe Capybara::Driver::Webkit do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "cookie-based app" do
|
||||||
|
before(:all) do
|
||||||
|
@cookie = 'cookie=abc; domain=127.0.0.1; path=/'
|
||||||
|
@app = lambda do |env|
|
||||||
|
request = ::Rack::Request.new(env)
|
||||||
|
|
||||||
|
body = <<-HTML
|
||||||
|
<html><body>
|
||||||
|
<p id="cookie">#{request.cookies["cookie"] || ""}</p>
|
||||||
|
</body></html>
|
||||||
|
HTML
|
||||||
|
[200,
|
||||||
|
{ 'Content-Type' => 'text/html; charset=UTF-8',
|
||||||
|
'Content-Length' => body.length.to_s,
|
||||||
|
'Set-Cookie' => @cookie,
|
||||||
|
},
|
||||||
|
[body]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def echoed_cookie
|
||||||
|
subject.find('id("cookie")').first.text
|
||||||
|
end
|
||||||
|
|
||||||
|
it "remembers the cookie on second visit" do
|
||||||
|
echoed_cookie.should == ""
|
||||||
|
subject.visit "/"
|
||||||
|
echoed_cookie.should == "abc"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses a custom cookie" do
|
||||||
|
subject.browser.set_cookie @cookie
|
||||||
|
subject.visit "/"
|
||||||
|
echoed_cookie.should == "abc"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "clears cookies" do
|
||||||
|
subject.browser.clear_cookies
|
||||||
|
subject.visit "/"
|
||||||
|
echoed_cookie.should == ""
|
||||||
|
end
|
||||||
|
|
||||||
|
it "allows enumeration of cookies" do
|
||||||
|
cookies = subject.browser.get_cookies
|
||||||
|
|
||||||
|
cookies.size.should == 1
|
||||||
|
|
||||||
|
cookie = Hash[cookies[0].split(/\s*;\s*/)
|
||||||
|
.map { |x| x.split("=", 2) }]
|
||||||
|
cookie["cookie"].should == "abc"
|
||||||
|
cookie["domain"].should include "127.0.0.1"
|
||||||
|
cookie["path"].should == "/"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "with socket debugger" do
|
context "with socket debugger" do
|
||||||
let(:socket_debugger_class){ Capybara::Driver::Webkit::SocketDebugger }
|
let(:socket_debugger_class){ Capybara::Driver::Webkit::SocketDebugger }
|
||||||
let(:browser_with_debugger){
|
let(:browser_with_debugger){
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include "ClearCookies.h"
|
||||||
|
#include "WebPage.h"
|
||||||
|
#include "NetworkCookieJar.h"
|
||||||
|
#include <QNetworkCookie>
|
||||||
|
|
||||||
|
ClearCookies::ClearCookies(WebPage *page, QObject *parent)
|
||||||
|
: Command(page, parent)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void ClearCookies::start(QStringList &arguments)
|
||||||
|
{
|
||||||
|
Q_UNUSED(arguments);
|
||||||
|
NetworkCookieJar *jar = qobject_cast<NetworkCookieJar*>(page()
|
||||||
|
->networkAccessManager()
|
||||||
|
->cookieJar());
|
||||||
|
jar->clearCookies();
|
||||||
|
emit finished(new Response(true));
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "Command.h"
|
||||||
|
|
||||||
|
class WebPage;
|
||||||
|
|
||||||
|
class ClearCookies : public Command {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClearCookies(WebPage *page, QObject *parent = 0);
|
||||||
|
virtual void start(QStringList &arguments);
|
||||||
|
};
|
|
@ -16,6 +16,9 @@
|
||||||
#include "Body.h"
|
#include "Body.h"
|
||||||
#include "Status.h"
|
#include "Status.h"
|
||||||
#include "Headers.h"
|
#include "Headers.h"
|
||||||
|
#include "SetCookie.h"
|
||||||
|
#include "ClearCookies.h"
|
||||||
|
#include "GetCookies.h"
|
||||||
|
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include "GetCookies.h"
|
||||||
|
#include "WebPage.h"
|
||||||
|
#include "NetworkCookieJar.h"
|
||||||
|
|
||||||
|
GetCookies::GetCookies(WebPage *page, QObject *parent)
|
||||||
|
: Command(page, parent)
|
||||||
|
{
|
||||||
|
m_buffer = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetCookies::start(QStringList &arguments)
|
||||||
|
{
|
||||||
|
Q_UNUSED(arguments);
|
||||||
|
NetworkCookieJar *jar = qobject_cast<NetworkCookieJar*>(page()
|
||||||
|
->networkAccessManager()
|
||||||
|
->cookieJar());
|
||||||
|
foreach (QNetworkCookie cookie, jar->getAllCookies()) {
|
||||||
|
m_buffer.append(cookie.toRawForm());
|
||||||
|
m_buffer.append("\n");
|
||||||
|
}
|
||||||
|
emit finished(new Response(true, m_buffer));
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include "Command.h"
|
||||||
|
|
||||||
|
class WebPage;
|
||||||
|
|
||||||
|
class GetCookies : public Command {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GetCookies(WebPage *page, QObject *parent = 0);
|
||||||
|
virtual void start(QStringList &arguments);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_buffer;
|
||||||
|
};
|
|
@ -0,0 +1,101 @@
|
||||||
|
#include "NetworkCookieJar.h"
|
||||||
|
#include "QtCore/qdatetime.h"
|
||||||
|
|
||||||
|
NetworkCookieJar::NetworkCookieJar(QObject *parent)
|
||||||
|
: QNetworkCookieJar(parent)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
QList<QNetworkCookie> NetworkCookieJar::getAllCookies() const
|
||||||
|
{
|
||||||
|
return allCookies();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkCookieJar::clearCookies()
|
||||||
|
{
|
||||||
|
setAllCookies(QList<QNetworkCookie>());
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isParentDomain(QString domain, QString reference)
|
||||||
|
{
|
||||||
|
if (!reference.startsWith(QLatin1Char('.')))
|
||||||
|
return domain == reference;
|
||||||
|
|
||||||
|
return domain.endsWith(reference) || domain == reference.mid(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkCookieJar::overwriteCookies(const QList<QNetworkCookie>& cookieList)
|
||||||
|
{
|
||||||
|
/* this function is basically a copy-and-paste of the original
|
||||||
|
QNetworkCookieJar::setCookiesFromUrl with the domain and
|
||||||
|
path validations removed */
|
||||||
|
|
||||||
|
QString defaultPath(QLatin1Char('/'));
|
||||||
|
QDateTime now = QDateTime::currentDateTime();
|
||||||
|
QList<QNetworkCookie> newCookies = allCookies();
|
||||||
|
|
||||||
|
foreach (QNetworkCookie cookie, cookieList) {
|
||||||
|
bool isDeletion = (!cookie.isSessionCookie() &&
|
||||||
|
cookie.expirationDate() < now);
|
||||||
|
|
||||||
|
// validate the cookie & set the defaults if unset
|
||||||
|
if (cookie.path().isEmpty())
|
||||||
|
cookie.setPath(defaultPath);
|
||||||
|
|
||||||
|
// don't do path checking. See http://bugreports.qt.nokia.com/browse/QTBUG-5815
|
||||||
|
// else if (!isParentPath(pathAndFileName, cookie.path())) {
|
||||||
|
// continue; // not accepted
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (cookie.domain().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// Ensure the domain starts with a dot if its field was not empty
|
||||||
|
// in the HTTP header. There are some servers that forget the
|
||||||
|
// leading dot and this is actually forbidden according to RFC 2109,
|
||||||
|
// but all browsers accept it anyway so we do that as well.
|
||||||
|
if (!cookie.domain().startsWith(QLatin1Char('.')))
|
||||||
|
cookie.setDomain(QLatin1Char('.') + cookie.domain());
|
||||||
|
|
||||||
|
QString domain = cookie.domain();
|
||||||
|
|
||||||
|
// the check for effective TLDs makes the "embedded dot" rule from RFC 2109 section 4.3.2
|
||||||
|
// redundant; the "leading dot" rule has been relaxed anyway, see above
|
||||||
|
// we remove the leading dot for this check
|
||||||
|
/*
|
||||||
|
if (QNetworkCookieJarPrivate::isEffectiveTLD(domain.remove(0, 1)))
|
||||||
|
continue; // not accepted
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < newCookies.size(); ++i) {
|
||||||
|
// does this cookie already exist?
|
||||||
|
const QNetworkCookie ¤t = newCookies.at(i);
|
||||||
|
if (cookie.name() == current.name() &&
|
||||||
|
cookie.domain() == current.domain() &&
|
||||||
|
cookie.path() == current.path()) {
|
||||||
|
// found a match
|
||||||
|
newCookies.removeAt(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// did not find a match
|
||||||
|
if (!isDeletion) {
|
||||||
|
int countForDomain = 0;
|
||||||
|
for (int i = newCookies.size() - 1; i >= 0; --i) {
|
||||||
|
// Start from the end and delete the oldest cookies to keep a maximum count of 50.
|
||||||
|
const QNetworkCookie ¤t = newCookies.at(i);
|
||||||
|
if (isParentDomain(cookie.domain(), current.domain())
|
||||||
|
|| isParentDomain(current.domain(), cookie.domain())) {
|
||||||
|
if (countForDomain >= 49)
|
||||||
|
newCookies.removeAt(i);
|
||||||
|
else
|
||||||
|
++countForDomain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newCookies += cookie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setAllCookies(newCookies);
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include <QtNetwork/QNetworkCookieJar>
|
||||||
|
#include <QtNetwork/QNetworkCookie>
|
||||||
|
|
||||||
|
class NetworkCookieJar : public QNetworkCookieJar {
|
||||||
|
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
NetworkCookieJar(QObject *parent = 0);
|
||||||
|
|
||||||
|
QList<QNetworkCookie> getAllCookies() const;
|
||||||
|
void clearCookies();
|
||||||
|
void overwriteCookies(const QList<QNetworkCookie>& cookieList);
|
||||||
|
};
|
|
@ -1,6 +1,7 @@
|
||||||
#include "Reset.h"
|
#include "Reset.h"
|
||||||
#include "WebPage.h"
|
#include "WebPage.h"
|
||||||
#include "NetworkAccessManager.h"
|
#include "NetworkAccessManager.h"
|
||||||
|
#include "NetworkCookieJar.h"
|
||||||
|
|
||||||
Reset::Reset(WebPage *page, QObject *parent) : Command(page, parent) {
|
Reset::Reset(WebPage *page, QObject *parent) : Command(page, parent) {
|
||||||
}
|
}
|
||||||
|
@ -10,7 +11,7 @@ void Reset::start(QStringList &arguments) {
|
||||||
|
|
||||||
page()->triggerAction(QWebPage::Stop);
|
page()->triggerAction(QWebPage::Stop);
|
||||||
page()->currentFrame()->setHtml("<html><body></body></html>");
|
page()->currentFrame()->setHtml("<html><body></body></html>");
|
||||||
page()->networkAccessManager()->setCookieJar(new QNetworkCookieJar());
|
page()->networkAccessManager()->setCookieJar(new NetworkCookieJar());
|
||||||
page()->setCustomNetworkAccessManager();
|
page()->setCustomNetworkAccessManager();
|
||||||
page()->setUserAgent(NULL);
|
page()->setUserAgent(NULL);
|
||||||
page()->resetResponseHeaders();
|
page()->resetResponseHeaders();
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include "SetCookie.h"
|
||||||
|
#include "WebPage.h"
|
||||||
|
#include "NetworkCookieJar.h"
|
||||||
|
#include <QNetworkCookie>
|
||||||
|
|
||||||
|
SetCookie::SetCookie(WebPage *page, QObject *parent)
|
||||||
|
: Command(page, parent)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void SetCookie::start(QStringList &arguments)
|
||||||
|
{
|
||||||
|
QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(arguments[0].toAscii());
|
||||||
|
NetworkCookieJar *jar = qobject_cast<NetworkCookieJar*>(page()
|
||||||
|
->networkAccessManager()
|
||||||
|
->cookieJar());
|
||||||
|
jar->overwriteCookies(cookies);
|
||||||
|
emit finished(new Response(true));
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "Command.h"
|
||||||
|
|
||||||
|
class WebPage;
|
||||||
|
|
||||||
|
class SetCookie : public Command {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SetCookie(WebPage *page, QObject *parent = 0);
|
||||||
|
virtual void start(QStringList &arguments);
|
||||||
|
};
|
|
@ -1,6 +1,7 @@
|
||||||
#include "WebPage.h"
|
#include "WebPage.h"
|
||||||
#include "JavascriptInvocation.h"
|
#include "JavascriptInvocation.h"
|
||||||
#include "NetworkAccessManager.h"
|
#include "NetworkAccessManager.h"
|
||||||
|
#include "NetworkCookieJar.h"
|
||||||
#include "UnsupportedContentHandler.h"
|
#include "UnsupportedContentHandler.h"
|
||||||
#include <QResource>
|
#include <QResource>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -23,6 +24,7 @@ WebPage::WebPage(QObject *parent) : QWebPage(parent) {
|
||||||
|
|
||||||
void WebPage::setCustomNetworkAccessManager() {
|
void WebPage::setCustomNetworkAccessManager() {
|
||||||
NetworkAccessManager *manager = new NetworkAccessManager();
|
NetworkAccessManager *manager = new NetworkAccessManager();
|
||||||
|
manager->setCookieJar(new NetworkCookieJar());
|
||||||
this->setNetworkAccessManager(manager);
|
this->setNetworkAccessManager(manager);
|
||||||
connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
|
connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,3 +17,6 @@ CHECK_COMMAND(Render)
|
||||||
CHECK_COMMAND(Body)
|
CHECK_COMMAND(Body)
|
||||||
CHECK_COMMAND(Status)
|
CHECK_COMMAND(Status)
|
||||||
CHECK_COMMAND(Headers)
|
CHECK_COMMAND(Headers)
|
||||||
|
CHECK_COMMAND(SetCookie)
|
||||||
|
CHECK_COMMAND(ClearCookies)
|
||||||
|
CHECK_COMMAND(GetCookies)
|
||||||
|
|
|
@ -18,12 +18,16 @@ HEADERS = \
|
||||||
FrameFocus.h \
|
FrameFocus.h \
|
||||||
Response.h \
|
Response.h \
|
||||||
NetworkAccessManager.h \
|
NetworkAccessManager.h \
|
||||||
|
NetworkCookieJar.h \
|
||||||
Header.h \
|
Header.h \
|
||||||
Render.h \
|
Render.h \
|
||||||
body.h \
|
body.h \
|
||||||
Status.h \
|
Status.h \
|
||||||
Headers.h \
|
Headers.h \
|
||||||
UnsupportedContentHandler.h \
|
UnsupportedContentHandler.h \
|
||||||
|
SetCookie.h \
|
||||||
|
ClearCookies.h \
|
||||||
|
GetCookies.h \
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
main.cpp \
|
main.cpp \
|
||||||
|
@ -43,12 +47,16 @@ SOURCES = \
|
||||||
FrameFocus.cpp \
|
FrameFocus.cpp \
|
||||||
Response.cpp \
|
Response.cpp \
|
||||||
NetworkAccessManager.cpp \
|
NetworkAccessManager.cpp \
|
||||||
|
NetworkCookieJar.cpp \
|
||||||
Header.cpp \
|
Header.cpp \
|
||||||
Render.cpp \
|
Render.cpp \
|
||||||
body.cpp \
|
body.cpp \
|
||||||
Status.cpp \
|
Status.cpp \
|
||||||
Headers.cpp \
|
Headers.cpp \
|
||||||
UnsupportedContentHandler.cpp \
|
UnsupportedContentHandler.cpp \
|
||||||
|
SetCookie.cpp \
|
||||||
|
ClearCookies.cpp \
|
||||||
|
GetCookies.cpp \
|
||||||
|
|
||||||
RESOURCES = webkit_server.qrc
|
RESOURCES = webkit_server.qrc
|
||||||
QT += network webkit
|
QT += network webkit
|
||||||
|
|
Loading…
Reference in New Issue