Fix status code and headers for iframes

QWebFrame::url() does not return a valid URL for iframes.  We can't just
look up the requested URL in m_responses because the request may have
been redirected, so instead we keep track of redirects and set up the
NetworkResponse when the final reply is received.
This commit is contained in:
Matthew Horan 2012-11-22 00:21:40 -05:00
parent e80a9c8b92
commit 5127c01366
10 changed files with 75 additions and 34 deletions

View File

@ -9,15 +9,29 @@ describe Capybara::Webkit::Driver do
let(:driver) do
driver_for_app do
get "/" do
if in_iframe_request?
p_id = "farewell"
msg = "goodbye"
iframe = nil
if params[:iframe] == "true"
redirect '/iframe'
else
p_id = "greeting"
msg = "hello"
iframe = "<iframe id=\"f\" src=\"/?iframe=true\"></iframe>"
<<-HTML
<html>
<head>
<style type="text/css">
#display_none { display: none }
</style>
</head>
<body>
<iframe id="f" src="/?iframe=true"></iframe>
<script type="text/javascript">
document.write("<p id='greeting'>hello</p>");
</script>
</body>
</html>
HTML
end
end
get '/iframe' do
headers 'X-Redirected' => 'true'
<<-HTML
<html>
<head>
@ -26,18 +40,13 @@ describe Capybara::Webkit::Driver do
</style>
</head>
<body>
#{iframe}
<script type="text/javascript">
document.write("<p id='#{p_id}'>#{msg}</p>");
document.write("<p id='farewell'>goodbye</p>");
</script>
</body>
</html>
HTML
end
def in_iframe_request?
params[:iframe] == "true"
end
end
end
@ -90,13 +99,7 @@ describe Capybara::Webkit::Driver do
it "returns the current URL" do
driver.within_frame("f") do
driver.current_url.should == driver_url(driver, "/?iframe=true")
end
end
it "returns the source code for the page" do
driver.within_frame("f") do
driver.source.should =~ %r{<html>.*farewell.*}m
driver.current_url.should == driver_url(driver, "/iframe")
end
end
@ -121,6 +124,18 @@ describe Capybara::Webkit::Driver do
driver.current_url.should == original_url
end
it "returns the headers for the page" do
driver.within_frame("f") do
driver.response_headers['X-Redirected'].should == "true"
end
end
it "returns the status code for the page" do
driver.within_frame("f") do
driver.status_code.should == 200
end
end
end
context "error iframe app" do
@ -150,8 +165,10 @@ describe Capybara::Webkit::Driver do
context "redirect app" do
let(:driver) do
driver_for_app do
enable :sessions
get '/target' do
headers 'X-Redirected' => 'true'
headers 'X-Redirected' => (session.delete(:redirected) || false).to_s
"<p>#{env['CONTENT_TYPE']}</p>"
end
@ -172,7 +189,12 @@ describe Capybara::Webkit::Driver do
end
get '/redirect-me' do
redirect '/target'
if session[:redirected]
redirect '/target'
else
session[:redirected] = true
redirect '/redirect-me'
end
end
end
end
@ -200,13 +222,16 @@ describe Capybara::Webkit::Driver do
it "should make headers available through response_headers" do
driver.visit('/redirect-me')
driver.response_headers['X-Redirected'].should == "true"
driver.visit('/target')
driver.response_headers['X-Redirected'].should == "false"
end
it "should make the status code available through status_code" do
driver.visit('/redirect-me')
driver.status_code.should == 200
driver.visit('/target')
driver.status_code.should == 200
end
end
context "css app" do

View File

@ -9,7 +9,7 @@ void Authenticate::start() {
QString username = arguments()[0];
QString password = arguments()[1];
NetworkAccessManager* networkAccessManager = qobject_cast<NetworkAccessManager*>(page()->networkAccessManager());
NetworkAccessManager* networkAccessManager = page()->networkAccessManager();
networkAccessManager->setUserName(username);
networkAccessManager->setPassword(password);

View File

@ -9,7 +9,7 @@ Header::Header(WebPageManager *manager, QStringList &arguments, QObject *parent)
void Header::start() {
QString key = arguments()[0];
QString value = arguments()[1];
NetworkAccessManager* networkAccessManager = qobject_cast<NetworkAccessManager*>(page()->networkAccessManager());
NetworkAccessManager* networkAccessManager = page()->networkAccessManager();
if (key.toLower().replace("-", "_") == "user_agent") {
page()->setUserAgent(value);
} else {

View File

@ -30,10 +30,18 @@ QNetworkReply* NetworkAccessManager::createRequest(QNetworkAccessManager::Operat
};
void NetworkAccessManager::finished(QNetworkReply *reply) {
NetworkResponse response;
response.statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
response.headers = reply->rawHeaderPairs();
m_responses[reply->url()] = response;
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
if (redirectUrl.isValid())
m_redirectMappings[reply->url().resolved(redirectUrl)] = reply->url();
else {
QUrl requestedUrl = reply->url();
while (m_redirectMappings.contains(requestedUrl))
requestedUrl = m_redirectMappings.take(requestedUrl);
NetworkResponse response;
response.statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
response.headers = reply->rawHeaderPairs();
m_responses[requestedUrl] = response;
}
}
void NetworkAccessManager::addHeader(QString key, QString value) {

View File

@ -35,6 +35,7 @@ class NetworkAccessManager : public QNetworkAccessManager {
QHash<QUrl, NetworkResponse> m_responses;
bool isBlacklisted(QUrl url);
QNetworkReply* noOpRequest();
QHash<QUrl, QUrl> m_redirectMappings;
private slots:
void provideAuthentication(QNetworkReply *reply, QAuthenticator *authenticator);

View File

@ -1,7 +1,7 @@
#include "SetProxy.h"
#include "WebPage.h"
#include "WebPageManager.h"
#include <QNetworkAccessManager>
#include "NetworkAccessManager.h"
#include <QNetworkProxy>
SetProxy::SetProxy(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {}

View File

@ -8,7 +8,7 @@ SetUrlBlacklist::SetUrlBlacklist(WebPageManager *manager, QStringList &arguments
}
void SetUrlBlacklist::start() {
NetworkAccessManager* networkAccessManager = qobject_cast<NetworkAccessManager*>(page()->networkAccessManager());
NetworkAccessManager* networkAccessManager = page()->networkAccessManager();
networkAccessManager->setUrlBlacklist(arguments());
emit finished(new Response(true));
}

View File

@ -1,12 +1,13 @@
#include "Source.h"
#include "WebPage.h"
#include "WebPageManager.h"
#include "NetworkAccessManager.h"
Source::Source(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
}
void Source::start() {
QNetworkAccessManager* accessManager = page()->networkAccessManager();
NetworkAccessManager* accessManager = page()->networkAccessManager();
QNetworkRequest request(page()->currentFrame()->requestedUrl());
reply = accessManager->get(request);

View File

@ -253,11 +253,15 @@ void WebPage::setSkipImageLoading(bool skip) {
}
int WebPage::getLastStatus() {
return qobject_cast<NetworkAccessManager *>(networkAccessManager())->statusFor(currentFrame()->url());
return networkAccessManager()->statusFor(currentFrame()->requestedUrl());
}
const QList<QNetworkReply::RawHeaderPair> &WebPage::pageHeaders() {
return qobject_cast<NetworkAccessManager *>(networkAccessManager())->headersFor(currentFrame()->url());
return networkAccessManager()->headersFor(currentFrame()->requestedUrl());
}
NetworkAccessManager *WebPage::networkAccessManager() {
return qobject_cast<NetworkAccessManager *>(QWebPage::networkAccessManager());
}
void WebPage::handleUnsupportedContent(QNetworkReply *reply) {

View File

@ -3,6 +3,7 @@
#include <QtWebKit>
class WebPageManager;
class NetworkAccessManager;
class WebPage : public QWebPage {
Q_OBJECT
@ -32,6 +33,7 @@ class WebPage : public QWebPage {
QString getWindowName();
bool matchesWindowSelector(QString);
void setFocus();
NetworkAccessManager *networkAccessManager();
public slots:
bool shouldInterruptJavaScript();