From ee1388e3290bedc374b53fd53c5b1f0b356c50fe Mon Sep 17 00:00:00 2001 From: shogo-ohta Date: Wed, 8 Jun 2011 18:36:45 +0900 Subject: [PATCH] add header support --- lib/capybara/driver/webkit.rb | 4 ++ lib/capybara/driver/webkit/browser.rb | 4 ++ spec/integration/session_spec.rb | 55 +++++++++++++++++++++++++++ src/Connection.cpp | 1 + src/Header.cpp | 18 +++++++++ src/Header.h | 11 ++++++ src/NetworkAccessManager.cpp | 22 +++++++++++ src/NetworkAccessManager.h | 18 +++++++++ src/Reset.cpp | 3 ++ src/Visit.cpp | 6 ++- src/WebPage.cpp | 16 ++++++++ src/WebPage.h | 3 ++ src/find_command.h | 1 + src/webkit_server.pro | 4 +- 14 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 src/Header.cpp create mode 100644 src/Header.h create mode 100644 src/NetworkAccessManager.cpp create mode 100644 src/NetworkAccessManager.h diff --git a/lib/capybara/driver/webkit.rb b/lib/capybara/driver/webkit.rb index 7ccfd32..188ef4c 100644 --- a/lib/capybara/driver/webkit.rb +++ b/lib/capybara/driver/webkit.rb @@ -36,6 +36,10 @@ class Capybara::Driver::Webkit source end + def header(key, value) + browser.header(key, value) + end + def execute_script(script) browser.execute_script script end diff --git a/lib/capybara/driver/webkit/browser.rb b/lib/capybara/driver/webkit/browser.rb index 2f5448d..b06d146 100644 --- a/lib/capybara/driver/webkit/browser.rb +++ b/lib/capybara/driver/webkit/browser.rb @@ -14,6 +14,10 @@ class Capybara::Driver::Webkit command "Visit", url end + def header(key, value) + command("Header", key, value) + end + def find(query) command("Find", query).split(",") end diff --git a/spec/integration/session_spec.rb b/spec/integration/session_spec.rb index e8c4f75..d533542 100644 --- a/spec/integration/session_spec.rb +++ b/spec/integration/session_spec.rb @@ -79,6 +79,61 @@ describe Capybara::Session do subject.click_button('ボタン') end end + context "custom header" do + before(:all) do + @app = lambda do |env| + body = <<-HTML + +
#{env['HTTP_USER_AGENT']}
+
#{env['HTTP_X_CAPYBARA_WEBKIT_HEADER']}
+
#{env['HTTP_ACCEPT']}
+ / + + HTML + [200, + { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, + [body]] + end + end + + it "can set user_agent" do + subject.driver.header('user-agent', 'capybara-webkit/custom-user-agent') + subject.visit('/') + subject.should have_content('capybara-webkit/custom-user-agent') + subject.should be_true subject.driver.evaluate_script('navigator.userAgent').eql?('capybara-webkit/custom-user-agent') + end + + it "reset default user_agent" do + subject.visit('/') + subject.should have_content('Mozilla/5.0') + subject.should be_true subject.driver.evaluate_script('navigator.userAgent').start_with?('Mozilla/5.0') + end + it "keep user_agent in next page" do + subject.driver.header('user-agent', 'capybara-webkit/custom-user-agent') + subject.visit('/') + subject.click_link('/') + subject.should have_content('capybara-webkit/custom-user-agent') + subject.should be_true subject.evaluate_script('navigator.userAgent').eql?('capybara-webkit/custom-user-agent') + end + + it "can set custom header" do + subject.driver.header('x-capybara-webkit-header', 'x-capybara-webkit-spec') + subject.visit('/') + subject.should have_content('x-capybara-webkit-spec') + end + + it "does not keep custom header" do + subject.visit('/') + subject.should_not have_content('x-capybara-webkit-spec') + end + + it "can set Accept" do + subject.driver.header('accept', 'application/xhtml+xml') + subject.visit('/') + subject.should have_content('application/xhtml+xml') + end + end + end describe Capybara::Session, "with TestApp" do diff --git a/src/Connection.cpp b/src/Connection.cpp index f63b9a3..901bc75 100644 --- a/src/Connection.cpp +++ b/src/Connection.cpp @@ -10,6 +10,7 @@ #include "Evaluate.h" #include "Execute.h" #include "FrameFocus.h" +#include "Header.h" #include #include diff --git a/src/Header.cpp b/src/Header.cpp new file mode 100644 index 0000000..1f74e94 --- /dev/null +++ b/src/Header.cpp @@ -0,0 +1,18 @@ +#include "Header.h" +#include "WebPage.h" +#include "NetworkAccessManager.h" + +Header::Header(WebPage *page, QObject *parent) : Command(page, parent) { +} + +void Header::start(QStringList &arguments) { + QString key = arguments[0]; + QString value = arguments[1]; + NetworkAccessManager* nam = qobject_cast(page()->networkAccessManager()); + if (key.toLower().replace("-", "_") == "user_agent") { + page()->setUserAgent(value); + } else { + nam->addHeader(key, value); + } + emit finished(new Response(true)); +} diff --git a/src/Header.h b/src/Header.h new file mode 100644 index 0000000..90289b1 --- /dev/null +++ b/src/Header.h @@ -0,0 +1,11 @@ +#include "Command.h" + +class WebPage; + +class Header : public Command { + Q_OBJECT + + public: + Header(WebPage *page, QObject *parent = 0); + virtual void start(QStringList &arguments); +}; diff --git a/src/NetworkAccessManager.cpp b/src/NetworkAccessManager.cpp new file mode 100644 index 0000000..c45162b --- /dev/null +++ b/src/NetworkAccessManager.cpp @@ -0,0 +1,22 @@ +#include "NetworkAccessManager.h" +#include "WebPage.h" +#include + + +NetworkAccessManager::NetworkAccessManager(QObject *parent):QNetworkAccessManager(parent) { +} + +QNetworkReply* NetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice * outgoingData = 0) { + QNetworkRequest new_req(req); + QHashIterator item(m_headers); + while (item.hasNext()) { + item.next(); + new_req.setRawHeader(item.key().toAscii(), item.value().toAscii()); + } + return QNetworkAccessManager::createRequest(op, new_req, outgoingData); +}; + +void NetworkAccessManager::addHeader(QString key, QString value) { + m_headers.insert(key, value); +}; + diff --git a/src/NetworkAccessManager.h b/src/NetworkAccessManager.h new file mode 100644 index 0000000..1f4b107 --- /dev/null +++ b/src/NetworkAccessManager.h @@ -0,0 +1,18 @@ +#include +#include +#include + +class NetworkAccessManager : public QNetworkAccessManager { + + Q_OBJECT + + public: + NetworkAccessManager(QObject *parent = 0); + void addHeader(QString key, QString value); + + protected: + QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice * outgoingData); + + private: + QHash m_headers; +}; \ No newline at end of file diff --git a/src/Reset.cpp b/src/Reset.cpp index f1b4f97..b7a92e9 100644 --- a/src/Reset.cpp +++ b/src/Reset.cpp @@ -1,5 +1,6 @@ #include "Reset.h" #include "WebPage.h" +#include "NetworkAccessManager.h" Reset::Reset(WebPage *page, QObject *parent) : Command(page, parent) { } @@ -10,6 +11,8 @@ void Reset::start(QStringList &arguments) { page()->triggerAction(QWebPage::Stop); page()->currentFrame()->setHtml(""); page()->networkAccessManager()->setCookieJar(new QNetworkCookieJar()); + page()->setNetworkAccessManager(new NetworkAccessManager()); + page()->setUserAgent(NULL); emit finished(new Response(true)); } diff --git a/src/Visit.cpp b/src/Visit.cpp index 7592a84..3a5046b 100644 --- a/src/Visit.cpp +++ b/src/Visit.cpp @@ -8,11 +8,13 @@ Visit::Visit(WebPage *page, QObject *parent) : Command(page, parent) { void Visit::start(QStringList &arguments) { QUrl requestedUrl = QUrl(arguments[0]); - page()->currentFrame()->setUrl(QUrl(requestedUrl)); + QNetworkRequest req; + req.setUrl(requestedUrl); if(requestedUrl.hasFragment()) { // workaround for https://bugs.webkit.org/show_bug.cgi?id=32723 - page()->currentFrame()->setUrl(QUrl(requestedUrl)); + req.setUrl(QUrl(requestedUrl)); } + page()->currentFrame()->load(req); } void Visit::loadFinished(bool success) { diff --git a/src/WebPage.cpp b/src/WebPage.cpp index 6b1a138..ee068ad 100644 --- a/src/WebPage.cpp +++ b/src/WebPage.cpp @@ -1,5 +1,6 @@ #include "WebPage.h" #include "JavascriptInvocation.h" +#include "NetworkAccessManager.h" #include #include @@ -15,12 +16,27 @@ WebPage::WebPage(QObject *parent) : QWebPage(parent) { m_capybaraJavascript = javascriptString; } m_loading = false; + + this->setNetworkAccessManager(new NetworkAccessManager()); + connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted())); connect(this, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool))); connect(this, SIGNAL(frameCreated(QWebFrame *)), this, SLOT(frameCreated(QWebFrame *))); } +QString WebPage::userAgentForUrl(const QUrl &url ) const { + if (!m_user_agent.isEmpty()) { + return m_user_agent; + } else { + return QWebPage::userAgentForUrl(url); + } +} + +void WebPage::setUserAgent(QString ua) { + m_user_agent = ua; +} + void WebPage::frameCreated(QWebFrame * frame) { connect(frame, SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(injectJavascriptHelpers())); diff --git a/src/WebPage.h b/src/WebPage.h index 1ad634a..f670642 100644 --- a/src/WebPage.h +++ b/src/WebPage.h @@ -8,6 +8,8 @@ class WebPage : public QWebPage { QVariant invokeCapybaraFunction(const char *name, QStringList &arguments); QVariant invokeCapybaraFunction(QString &name, QStringList &arguments); QString failureString(); + QString userAgentForUrl(const QUrl &url ) const; + void setUserAgent(QString ua); public slots: bool shouldInterruptJavaScript(); @@ -25,6 +27,7 @@ class WebPage : public QWebPage { private: QString m_capybaraJavascript; + QString m_user_agent; bool m_loading; }; diff --git a/src/find_command.h b/src/find_command.h index 9744c1a..04e55bb 100644 --- a/src/find_command.h +++ b/src/find_command.h @@ -12,3 +12,4 @@ CHECK_COMMAND(Source) CHECK_COMMAND(Evaluate) CHECK_COMMAND(Execute) CHECK_COMMAND(FrameFocus) +CHECK_COMMAND(Header) \ No newline at end of file diff --git a/src/webkit_server.pro b/src/webkit_server.pro index 29090e5..e22f2b4 100644 --- a/src/webkit_server.pro +++ b/src/webkit_server.pro @@ -1,8 +1,8 @@ TEMPLATE = app TARGET = webkit_server DESTDIR = . -HEADERS = WebPage.h Server.h Connection.h Command.h Visit.h Find.h Reset.h Node.h JavascriptInvocation.h Url.h Source.h Evaluate.h Execute.h FrameFocus.h Response.h -SOURCES = main.cpp WebPage.cpp Server.cpp Connection.cpp Command.cpp Visit.cpp Find.cpp Reset.cpp Node.cpp JavascriptInvocation.cpp Url.cpp Source.cpp Evaluate.cpp Execute.cpp FrameFocus.cpp Response.cpp +HEADERS = WebPage.h Server.h Connection.h Command.h Visit.h Find.h Reset.h Node.h JavascriptInvocation.h Url.h Source.h Evaluate.h Execute.h FrameFocus.h Response.h NetworkAccessManager.h Header.h +SOURCES = main.cpp WebPage.cpp Server.cpp Connection.cpp Command.cpp Visit.cpp Find.cpp Reset.cpp Node.cpp JavascriptInvocation.cpp Url.cpp Source.cpp Evaluate.cpp Execute.cpp FrameFocus.cpp Response.cpp NetworkAccessManager.cpp Header.cpp RESOURCES = webkit_server.qrc QT += network webkit CONFIG += console