imseng-capybara-webkit 0.12.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/Appraisals +7 -0
- data/CONTRIBUTING.md +47 -0
- data/ChangeLog +70 -0
- data/Gemfile +3 -0
- data/LICENSE +19 -0
- data/NEWS.md +36 -0
- data/README.md +114 -0
- data/Rakefile +65 -0
- data/bin/Info.plist +22 -0
- data/capybara-webkit.gemspec +28 -0
- data/extconf.rb +2 -0
- data/gemfiles/1.0.gemfile +7 -0
- data/gemfiles/1.0.gemfile.lock +70 -0
- data/gemfiles/1.1.gemfile +7 -0
- data/gemfiles/1.1.gemfile.lock +70 -0
- data/lib/capybara/driver/webkit/browser.rb +164 -0
- data/lib/capybara/driver/webkit/connection.rb +120 -0
- data/lib/capybara/driver/webkit/cookie_jar.rb +55 -0
- data/lib/capybara/driver/webkit/node.rb +118 -0
- data/lib/capybara/driver/webkit/socket_debugger.rb +43 -0
- data/lib/capybara/driver/webkit/version.rb +7 -0
- data/lib/capybara/driver/webkit.rb +136 -0
- data/lib/capybara/webkit/matchers.rb +37 -0
- data/lib/capybara/webkit.rb +13 -0
- data/lib/capybara-webkit.rb +1 -0
- data/lib/capybara_webkit_builder.rb +68 -0
- data/spec/browser_spec.rb +173 -0
- data/spec/capybara_webkit_builder_spec.rb +37 -0
- data/spec/connection_spec.rb +54 -0
- data/spec/cookie_jar_spec.rb +48 -0
- data/spec/driver_rendering_spec.rb +80 -0
- data/spec/driver_resize_window_spec.rb +59 -0
- data/spec/driver_spec.rb +1552 -0
- data/spec/integration/driver_spec.rb +20 -0
- data/spec/integration/session_spec.rb +137 -0
- data/spec/self_signed_ssl_cert.rb +42 -0
- data/spec/spec_helper.rb +46 -0
- data/src/Body.h +12 -0
- data/src/ClearCookies.cpp +15 -0
- data/src/ClearCookies.h +11 -0
- data/src/Command.cpp +19 -0
- data/src/Command.h +31 -0
- data/src/CommandFactory.cpp +37 -0
- data/src/CommandFactory.h +16 -0
- data/src/CommandParser.cpp +76 -0
- data/src/CommandParser.h +33 -0
- data/src/Connection.cpp +71 -0
- data/src/Connection.h +37 -0
- data/src/ConsoleMessages.cpp +10 -0
- data/src/ConsoleMessages.h +12 -0
- data/src/CurrentUrl.cpp +68 -0
- data/src/CurrentUrl.h +16 -0
- data/src/Evaluate.cpp +84 -0
- data/src/Evaluate.h +22 -0
- data/src/Execute.cpp +16 -0
- data/src/Execute.h +12 -0
- data/src/Find.cpp +19 -0
- data/src/Find.h +13 -0
- data/src/FrameFocus.cpp +66 -0
- data/src/FrameFocus.h +28 -0
- data/src/GetCookies.cpp +20 -0
- data/src/GetCookies.h +14 -0
- data/src/Header.cpp +18 -0
- data/src/Header.h +11 -0
- data/src/Headers.cpp +10 -0
- data/src/Headers.h +12 -0
- data/src/IgnoreSslErrors.cpp +12 -0
- data/src/IgnoreSslErrors.h +12 -0
- data/src/JavascriptInvocation.cpp +14 -0
- data/src/JavascriptInvocation.h +19 -0
- data/src/NetworkAccessManager.cpp +29 -0
- data/src/NetworkAccessManager.h +19 -0
- data/src/NetworkCookieJar.cpp +101 -0
- data/src/NetworkCookieJar.h +15 -0
- data/src/Node.cpp +14 -0
- data/src/Node.h +13 -0
- data/src/NullCommand.cpp +10 -0
- data/src/NullCommand.h +11 -0
- data/src/PageLoadingCommand.cpp +46 -0
- data/src/PageLoadingCommand.h +40 -0
- data/src/Render.cpp +18 -0
- data/src/Render.h +12 -0
- data/src/RequestedUrl.cpp +12 -0
- data/src/RequestedUrl.h +12 -0
- data/src/Reset.cpp +29 -0
- data/src/Reset.h +15 -0
- data/src/ResizeWindow.cpp +16 -0
- data/src/ResizeWindow.h +12 -0
- data/src/Response.cpp +24 -0
- data/src/Response.h +15 -0
- data/src/Server.cpp +24 -0
- data/src/Server.h +21 -0
- data/src/SetCookie.cpp +16 -0
- data/src/SetCookie.h +11 -0
- data/src/SetProxy.cpp +22 -0
- data/src/SetProxy.h +11 -0
- data/src/Source.cpp +18 -0
- data/src/Source.h +19 -0
- data/src/Status.cpp +12 -0
- data/src/Status.h +12 -0
- data/src/UnsupportedContentHandler.cpp +32 -0
- data/src/UnsupportedContentHandler.h +18 -0
- data/src/Url.cpp +12 -0
- data/src/Url.h +12 -0
- data/src/Visit.cpp +12 -0
- data/src/Visit.h +12 -0
- data/src/WebPage.cpp +239 -0
- data/src/WebPage.h +58 -0
- data/src/body.cpp +10 -0
- data/src/capybara.js +315 -0
- data/src/find_command.h +29 -0
- data/src/main.cpp +33 -0
- data/src/webkit_server.pro +85 -0
- data/src/webkit_server.qrc +5 -0
- data/templates/Command.cpp +10 -0
- data/templates/Command.h +12 -0
- data/webkit_server.pro +4 -0
- metadata +298 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'capybara/driver/webkit'
|
3
|
+
|
4
|
+
describe Capybara::Driver::Webkit do
|
5
|
+
before do
|
6
|
+
@driver = Capybara::Driver::Webkit.new(TestApp, :browser => $webkit_browser)
|
7
|
+
end
|
8
|
+
|
9
|
+
it_should_behave_like "driver"
|
10
|
+
it_should_behave_like "driver with javascript support"
|
11
|
+
it_should_behave_like "driver with cookies support"
|
12
|
+
it_should_behave_like "driver with header support"
|
13
|
+
it_should_behave_like "driver with status code support"
|
14
|
+
it_should_behave_like "driver with frame support"
|
15
|
+
|
16
|
+
it "returns the rack server port" do
|
17
|
+
@driver.server_port.should eq(@driver.instance_variable_get(:@rack_server).port)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# -*- encoding: UTF-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'capybara/webkit'
|
5
|
+
|
6
|
+
describe Capybara::Session do
|
7
|
+
subject { Capybara::Session.new(:reusable_webkit, @app) }
|
8
|
+
after { subject.reset! }
|
9
|
+
|
10
|
+
context "slow javascript app" do
|
11
|
+
before(:all) do
|
12
|
+
@app = lambda do |env|
|
13
|
+
body = <<-HTML
|
14
|
+
<html><body>
|
15
|
+
<form action="/next" id="submit_me"><input type="submit" value="Submit" /></form>
|
16
|
+
<p id="change_me">Hello</p>
|
17
|
+
|
18
|
+
<script type="text/javascript">
|
19
|
+
var form = document.getElementById('submit_me');
|
20
|
+
form.addEventListener("submit", function (event) {
|
21
|
+
event.preventDefault();
|
22
|
+
setTimeout(function () {
|
23
|
+
document.getElementById("change_me").innerHTML = 'Good' + 'bye';
|
24
|
+
}, 500);
|
25
|
+
});
|
26
|
+
</script>
|
27
|
+
</body></html>
|
28
|
+
HTML
|
29
|
+
[200,
|
30
|
+
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
31
|
+
[body]]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
before do
|
36
|
+
@default_wait_time = Capybara.default_wait_time
|
37
|
+
Capybara.default_wait_time = 1
|
38
|
+
end
|
39
|
+
|
40
|
+
after { Capybara.default_wait_time = @default_wait_time }
|
41
|
+
|
42
|
+
it "waits for a request to load" do
|
43
|
+
subject.visit("/")
|
44
|
+
subject.find_button("Submit").click
|
45
|
+
subject.should have_content("Goodbye");
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "simple app" do
|
50
|
+
before(:all) do
|
51
|
+
@app = lambda do |env|
|
52
|
+
body = <<-HTML
|
53
|
+
<html><body>
|
54
|
+
<strong>Hello</strong>
|
55
|
+
<span>UTF8文字列</span>
|
56
|
+
<input type="button" value="ボタン" />
|
57
|
+
</body></html>
|
58
|
+
HTML
|
59
|
+
[200,
|
60
|
+
{ 'Content-Type' => 'text/html; charset=UTF-8', 'Content-Length' => body.length.to_s },
|
61
|
+
[body]]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
before do
|
66
|
+
subject.visit("/")
|
67
|
+
end
|
68
|
+
|
69
|
+
it "inspects nodes" do
|
70
|
+
subject.all(:xpath, "//strong").first.inspect.should include("strong")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "can read utf8 string" do
|
74
|
+
utf8str = subject.all(:xpath, "//span").first.text
|
75
|
+
utf8str.should eq('UTF8文字列')
|
76
|
+
end
|
77
|
+
|
78
|
+
it "can click utf8 string" do
|
79
|
+
subject.click_button('ボタン')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "response headers with status code" do
|
84
|
+
before(:all) do
|
85
|
+
@app = lambda do |env|
|
86
|
+
params = ::Rack::Utils.parse_query(env['QUERY_STRING'])
|
87
|
+
if params["img"] == "true"
|
88
|
+
body = 'not found'
|
89
|
+
return [404, { 'Content-Type' => 'image/gif', 'Content-Length' => body.length.to_s }, [body]]
|
90
|
+
end
|
91
|
+
body = <<-HTML
|
92
|
+
<html>
|
93
|
+
<body>
|
94
|
+
<img src="?img=true">
|
95
|
+
</body>
|
96
|
+
</html>
|
97
|
+
HTML
|
98
|
+
[200,
|
99
|
+
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s, 'X-Capybara' => 'WebKit'},
|
100
|
+
[body]]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should get status code" do
|
105
|
+
subject.visit '/'
|
106
|
+
subject.status_code.should == 200
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should reset status code" do
|
110
|
+
subject.visit '/'
|
111
|
+
subject.status_code.should == 200
|
112
|
+
subject.reset!
|
113
|
+
subject.status_code.should == 0
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should get response headers" do
|
117
|
+
subject.visit '/'
|
118
|
+
subject.response_headers['X-Capybara'].should == 'WebKit'
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should reset response headers" do
|
122
|
+
subject.visit '/'
|
123
|
+
subject.response_headers['X-Capybara'].should == 'WebKit'
|
124
|
+
subject.reset!
|
125
|
+
subject.response_headers['X-Capybara'].should == nil
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe Capybara::Session, "with TestApp" do
|
131
|
+
before do
|
132
|
+
@session = Capybara::Session.new(:reusable_webkit, TestApp)
|
133
|
+
end
|
134
|
+
|
135
|
+
it_should_behave_like "session"
|
136
|
+
it_should_behave_like "session with javascript support"
|
137
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
pem = <<-PEM_ENCODED
|
4
|
+
-----BEGIN PRIVATE KEY-----
|
5
|
+
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKW+grT6YW3gv79y
|
6
|
+
P9JkQDtm3cDSUhAhd/TEyRBt/pSKz3pNSygsleBJl2d7g8k0fteec95a7YnYRKGH
|
7
|
+
XhIpUOvl/3uaV2NVipqxwB+Z+0M+7HegxL3e4unaRFy9kf9/UXJzmuA9BTMLrm/w
|
8
|
+
IoW17f+dz7BIFZhCvRurkrmvzraNAgMBAAECgYBv4uB3bYJx20N16Jk+3OAjeXh/
|
9
|
+
Hzu4me9Rc7pLdgVinyYaaK0wrJBsfSFRASdgnyh1RAjx9K3f3PfPlwMg/XUbA6Yd
|
10
|
+
YOYlMnBUwCJX09TH8RFFCzJzbBylpk/sTF1geICln2O2BloT2cM24PlEPvyz1xLa
|
11
|
+
XvxCOnJJfgNU1K6kvQJBANcEVyOMJ9RBfI8gj1o7S70J9yJRI4jvqxuvcOxJBCi6
|
12
|
+
CDatkh/getHswsE3sLj25VhrNsi6UQcN8Bjm8Yjt8BsCQQDFVe0uCwobseprMOuW
|
13
|
+
dPU4+saN1cFnIT5Gp0iwYRPinjUlkh6H/AuUtUulKFXVmxk1KElpp1E3bxpCDgCp
|
14
|
+
oe53AkArO1Mt8Ys8kSIzQO+xy8RRsQRAoSHM8atsuJyy1YeBjM4D+GguApuPQ9Rw
|
15
|
+
tvrQZcv9OCleuJ98FKBW0XB1AKpLAkEAmOR3bJofDdAuWTjA/4TEzo32MsRwIZBv
|
16
|
+
KNzJg+bjOkzrzp1EzIVrD5/b6S20O1j9EeOR5as+UN3jEVS6DLQrBwJAe5OTrDiQ
|
17
|
+
vKtUaAwquC4f4Ia05KwJw+vFrPVaOqgc4QLdxRwx4PfV/Uw3OOqMolpPAvpUi9JI
|
18
|
+
LAwIaTtCvo18OQ==
|
19
|
+
-----END PRIVATE KEY-----
|
20
|
+
-----BEGIN CERTIFICATE-----
|
21
|
+
MIICgDCCAemgAwIBAgIJANWcyeZB2ql1MA0GCSqGSIb3DQEBBQUAMFkxCzAJBgNV
|
22
|
+
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
23
|
+
aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xMTA5MjgyMDIx
|
24
|
+
MTFaFw0xMjA5MjcyMDIxMTFaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l
|
25
|
+
LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV
|
26
|
+
BAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApb6CtPph
|
27
|
+
beC/v3I/0mRAO2bdwNJSECF39MTJEG3+lIrPek1LKCyV4EmXZ3uDyTR+155z3lrt
|
28
|
+
idhEoYdeEilQ6+X/e5pXY1WKmrHAH5n7Qz7sd6DEvd7i6dpEXL2R/39RcnOa4D0F
|
29
|
+
Mwuub/AihbXt/53PsEgVmEK9G6uSua/Oto0CAwEAAaNQME4wHQYDVR0OBBYEFBAm
|
30
|
+
x19zpY8M8FEcMXB4WQeUhqIiMB8GA1UdIwQYMBaAFBAmx19zpY8M8FEcMXB4WQeU
|
31
|
+
hqIiMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAcznCusWS5Ws77IUl
|
32
|
+
b87vdfCPVphICyfGHGWhHp3BZ3WLOphauAMdOYIiJGtPExyWr4DYpzbvx0+Ljg7G
|
33
|
+
2FNaI0QRXqbR5ccpvwm6KELmU0XDhykNaXiXSdnvIanr3z/hZ5e03mXAywo+nGQj
|
34
|
+
UYTVCb6g/uHVNzXq1NgHGuqogKY=
|
35
|
+
-----END CERTIFICATE-----
|
36
|
+
PEM_ENCODED
|
37
|
+
|
38
|
+
key = OpenSSL::PKey::RSA.new(pem)
|
39
|
+
cert = OpenSSL::X509::Certificate.new(pem)
|
40
|
+
$openssl_self_signed_ctx = OpenSSL::SSL::SSLContext.new
|
41
|
+
$openssl_self_signed_ctx.key = key
|
42
|
+
$openssl_self_signed_ctx.cert = cert
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'rspec/autorun'
|
3
|
+
require 'rbconfig'
|
4
|
+
|
5
|
+
PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..')).freeze
|
6
|
+
|
7
|
+
$LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
|
8
|
+
|
9
|
+
Dir[File.join(PROJECT_ROOT, 'spec', 'support', '**', '*.rb')].each { |file| require(file) }
|
10
|
+
|
11
|
+
spec_dir = nil
|
12
|
+
$:.detect do |dir|
|
13
|
+
if File.exists? File.join(dir, "capybara.rb")
|
14
|
+
spec_dir = File.expand_path(File.join(dir,"..","spec"))
|
15
|
+
$:.unshift( spec_dir )
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec.configure do |c|
|
20
|
+
c.filter_run_excluding :skip_on_windows => !(RbConfig::CONFIG['host_os'] =~ /mingw32/).nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
require File.join(spec_dir, "spec_helper")
|
24
|
+
|
25
|
+
require 'capybara/driver/webkit/connection'
|
26
|
+
require 'capybara/driver/webkit/browser'
|
27
|
+
connection = Capybara::Driver::Webkit::Connection.new(:socket_class => TCPSocket, :stdout => nil)
|
28
|
+
$webkit_browser = Capybara::Driver::Webkit::Browser.new(connection)
|
29
|
+
|
30
|
+
Capybara.register_driver :reusable_webkit do |app|
|
31
|
+
Capybara::Driver::Webkit.new(app, :browser => $webkit_browser)
|
32
|
+
end
|
33
|
+
|
34
|
+
def with_env_vars(vars)
|
35
|
+
old_env_variables = {}
|
36
|
+
vars.each do |key, value|
|
37
|
+
old_env_variables[key] = ENV[key]
|
38
|
+
ENV[key] = value
|
39
|
+
end
|
40
|
+
|
41
|
+
yield
|
42
|
+
|
43
|
+
old_env_variables.each do |key, value|
|
44
|
+
ENV[key] = value
|
45
|
+
end
|
46
|
+
end
|
data/src/Body.h
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#include "ClearCookies.h"
|
2
|
+
#include "WebPage.h"
|
3
|
+
#include "NetworkCookieJar.h"
|
4
|
+
#include <QNetworkCookie>
|
5
|
+
|
6
|
+
ClearCookies::ClearCookies(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {}
|
7
|
+
|
8
|
+
void ClearCookies::start()
|
9
|
+
{
|
10
|
+
NetworkCookieJar *jar = qobject_cast<NetworkCookieJar*>(page()
|
11
|
+
->networkAccessManager()
|
12
|
+
->cookieJar());
|
13
|
+
jar->clearCookies();
|
14
|
+
emit finished(new Response(true));
|
15
|
+
}
|
data/src/ClearCookies.h
ADDED
data/src/Command.cpp
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#include "Command.h"
|
2
|
+
#include "WebPage.h"
|
3
|
+
|
4
|
+
Command::Command(WebPage *page, QStringList &arguments, QObject *parent) : QObject(parent) {
|
5
|
+
m_page = page;
|
6
|
+
m_arguments = arguments;
|
7
|
+
}
|
8
|
+
|
9
|
+
void Command::start() {
|
10
|
+
}
|
11
|
+
|
12
|
+
WebPage *Command::page() {
|
13
|
+
return m_page;
|
14
|
+
}
|
15
|
+
|
16
|
+
QStringList &Command::arguments() {
|
17
|
+
return m_arguments;
|
18
|
+
}
|
19
|
+
|
data/src/Command.h
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#ifndef COMMAND_H
|
2
|
+
#define COMMAND_H
|
3
|
+
|
4
|
+
#include <QObject>
|
5
|
+
#include <QStringList>
|
6
|
+
#include "Response.h"
|
7
|
+
|
8
|
+
class WebPage;
|
9
|
+
|
10
|
+
class Command : public QObject {
|
11
|
+
Q_OBJECT
|
12
|
+
|
13
|
+
public:
|
14
|
+
Command(WebPage *page, QStringList &arguments, QObject *parent = 0);
|
15
|
+
virtual void start();
|
16
|
+
|
17
|
+
signals:
|
18
|
+
void finished(Response *response);
|
19
|
+
|
20
|
+
protected:
|
21
|
+
WebPage *page();
|
22
|
+
QStringList &arguments();
|
23
|
+
|
24
|
+
private:
|
25
|
+
WebPage *m_page;
|
26
|
+
QStringList m_arguments;
|
27
|
+
|
28
|
+
};
|
29
|
+
|
30
|
+
#endif
|
31
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#include "CommandFactory.h"
|
2
|
+
#include "NullCommand.h"
|
3
|
+
#include "Visit.h"
|
4
|
+
#include "Find.h"
|
5
|
+
#include "Command.h"
|
6
|
+
#include "Reset.h"
|
7
|
+
#include "Node.h"
|
8
|
+
#include "Url.h"
|
9
|
+
#include "Source.h"
|
10
|
+
#include "Evaluate.h"
|
11
|
+
#include "Execute.h"
|
12
|
+
#include "FrameFocus.h"
|
13
|
+
#include "Header.h"
|
14
|
+
#include "Render.h"
|
15
|
+
#include "Body.h"
|
16
|
+
#include "Status.h"
|
17
|
+
#include "Headers.h"
|
18
|
+
#include "SetCookie.h"
|
19
|
+
#include "ClearCookies.h"
|
20
|
+
#include "GetCookies.h"
|
21
|
+
#include "SetProxy.h"
|
22
|
+
#include "ConsoleMessages.h"
|
23
|
+
#include "RequestedUrl.h"
|
24
|
+
#include "CurrentUrl.h"
|
25
|
+
#include "ResizeWindow.h"
|
26
|
+
#include "IgnoreSslErrors.h"
|
27
|
+
|
28
|
+
CommandFactory::CommandFactory(WebPage *page, QObject *parent) : QObject(parent) {
|
29
|
+
m_page = page;
|
30
|
+
}
|
31
|
+
|
32
|
+
Command *CommandFactory::createCommand(const char *name, QStringList &arguments) {
|
33
|
+
#include "find_command.h"
|
34
|
+
arguments.clear();
|
35
|
+
arguments.append(QString(name));
|
36
|
+
return new NullCommand(m_page, arguments);
|
37
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#include <QObject>
|
2
|
+
|
3
|
+
class Command;
|
4
|
+
class WebPage;
|
5
|
+
|
6
|
+
class CommandFactory : public QObject {
|
7
|
+
Q_OBJECT
|
8
|
+
|
9
|
+
public:
|
10
|
+
CommandFactory(WebPage *page, QObject *parent = 0);
|
11
|
+
Command *createCommand(const char *name, QStringList &arguments);
|
12
|
+
|
13
|
+
private:
|
14
|
+
WebPage *m_page;
|
15
|
+
};
|
16
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#include "CommandParser.h"
|
2
|
+
#include "CommandFactory.h"
|
3
|
+
#include "Command.h"
|
4
|
+
|
5
|
+
#include <QIODevice>
|
6
|
+
|
7
|
+
CommandParser::CommandParser(QIODevice *device, CommandFactory *commandFactory, QObject *parent) :
|
8
|
+
QObject(parent) {
|
9
|
+
m_device = device;
|
10
|
+
m_expectingDataSize = -1;
|
11
|
+
m_commandFactory = commandFactory;
|
12
|
+
connect(m_device, SIGNAL(readyRead()), this, SLOT(checkNext()));
|
13
|
+
}
|
14
|
+
|
15
|
+
void CommandParser::checkNext() {
|
16
|
+
if (m_expectingDataSize == -1) {
|
17
|
+
if (m_device->canReadLine()) {
|
18
|
+
readLine();
|
19
|
+
checkNext();
|
20
|
+
}
|
21
|
+
} else {
|
22
|
+
if (m_device->bytesAvailable() >= m_expectingDataSize) {
|
23
|
+
readDataBlock();
|
24
|
+
checkNext();
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
void CommandParser::readLine() {
|
30
|
+
char buffer[128];
|
31
|
+
qint64 lineLength = m_device->readLine(buffer, 128);
|
32
|
+
if (lineLength != -1) {
|
33
|
+
buffer[lineLength - 1] = 0;
|
34
|
+
processNext(buffer);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
void CommandParser::readDataBlock() {
|
39
|
+
char *buffer = new char[m_expectingDataSize + 1];
|
40
|
+
m_device->read(buffer, m_expectingDataSize);
|
41
|
+
buffer[m_expectingDataSize] = 0;
|
42
|
+
processNext(buffer);
|
43
|
+
m_expectingDataSize = -1;
|
44
|
+
delete[] buffer;
|
45
|
+
}
|
46
|
+
|
47
|
+
void CommandParser::processNext(const char *data) {
|
48
|
+
if (m_commandName.isNull()) {
|
49
|
+
m_commandName = data;
|
50
|
+
m_argumentsExpected = -1;
|
51
|
+
} else {
|
52
|
+
processArgument(data);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
void CommandParser::processArgument(const char *data) {
|
57
|
+
if (m_argumentsExpected == -1) {
|
58
|
+
m_argumentsExpected = QString(data).toInt();
|
59
|
+
} else if (m_expectingDataSize == -1) {
|
60
|
+
m_expectingDataSize = QString(data).toInt();
|
61
|
+
} else {
|
62
|
+
m_arguments.append(QString::fromUtf8(data));
|
63
|
+
}
|
64
|
+
|
65
|
+
if (m_arguments.length() == m_argumentsExpected) {
|
66
|
+
Command *command = m_commandFactory->createCommand(m_commandName.toAscii().constData(), m_arguments);
|
67
|
+
emit commandReady(command);
|
68
|
+
reset();
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
void CommandParser::reset() {
|
73
|
+
m_commandName = QString();
|
74
|
+
m_arguments.clear();
|
75
|
+
m_argumentsExpected = -1;
|
76
|
+
}
|
data/src/CommandParser.h
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#include <QObject>
|
2
|
+
#include <QStringList>
|
3
|
+
|
4
|
+
class QIODevice;
|
5
|
+
class CommandFactory;
|
6
|
+
class Command;
|
7
|
+
|
8
|
+
class CommandParser : public QObject {
|
9
|
+
Q_OBJECT
|
10
|
+
|
11
|
+
public:
|
12
|
+
CommandParser(QIODevice *device, CommandFactory *commandFactory, QObject *parent = 0);
|
13
|
+
|
14
|
+
public slots:
|
15
|
+
void checkNext();
|
16
|
+
|
17
|
+
signals:
|
18
|
+
void commandReady(Command *command);
|
19
|
+
|
20
|
+
private:
|
21
|
+
void readLine();
|
22
|
+
void readDataBlock();
|
23
|
+
void processNext(const char *line);
|
24
|
+
void processArgument(const char *data);
|
25
|
+
void reset();
|
26
|
+
QIODevice *m_device;
|
27
|
+
QString m_commandName;
|
28
|
+
QStringList m_arguments;
|
29
|
+
int m_argumentsExpected;
|
30
|
+
int m_expectingDataSize;
|
31
|
+
CommandFactory *m_commandFactory;
|
32
|
+
};
|
33
|
+
|
data/src/Connection.cpp
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
#include "Connection.h"
|
2
|
+
#include "WebPage.h"
|
3
|
+
#include "CommandParser.h"
|
4
|
+
#include "CommandFactory.h"
|
5
|
+
#include "PageLoadingCommand.h"
|
6
|
+
#include "Command.h"
|
7
|
+
|
8
|
+
#include <QTcpSocket>
|
9
|
+
|
10
|
+
Connection::Connection(QTcpSocket *socket, WebPage *page, QObject *parent) :
|
11
|
+
QObject(parent) {
|
12
|
+
m_socket = socket;
|
13
|
+
m_page = page;
|
14
|
+
m_commandFactory = new CommandFactory(page, this);
|
15
|
+
m_commandParser = new CommandParser(socket, m_commandFactory, this);
|
16
|
+
m_pageSuccess = true;
|
17
|
+
m_commandWaiting = false;
|
18
|
+
connect(m_socket, SIGNAL(readyRead()), m_commandParser, SLOT(checkNext()));
|
19
|
+
connect(m_commandParser, SIGNAL(commandReady(Command *)), this, SLOT(commandReady(Command *)));
|
20
|
+
connect(m_page, SIGNAL(pageFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
|
21
|
+
}
|
22
|
+
|
23
|
+
void Connection::commandReady(Command *command) {
|
24
|
+
m_queuedCommand = command;
|
25
|
+
if (m_page->isLoading())
|
26
|
+
m_commandWaiting = true;
|
27
|
+
else
|
28
|
+
startCommand();
|
29
|
+
}
|
30
|
+
|
31
|
+
void Connection::startCommand() {
|
32
|
+
m_commandWaiting = false;
|
33
|
+
if (m_pageSuccess) {
|
34
|
+
m_runningCommand = new PageLoadingCommand(m_queuedCommand, m_page, this);
|
35
|
+
connect(m_runningCommand, SIGNAL(finished(Response *)), this, SLOT(finishCommand(Response *)));
|
36
|
+
m_runningCommand->start();
|
37
|
+
} else {
|
38
|
+
writePageLoadFailure();
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
void Connection::pendingLoadFinished(bool success) {
|
43
|
+
m_pageSuccess = success;
|
44
|
+
if (m_commandWaiting)
|
45
|
+
startCommand();
|
46
|
+
}
|
47
|
+
|
48
|
+
void Connection::writePageLoadFailure() {
|
49
|
+
m_pageSuccess = true;
|
50
|
+
QString message = m_page->failureString();
|
51
|
+
writeResponse(new Response(false, message));
|
52
|
+
}
|
53
|
+
|
54
|
+
void Connection::finishCommand(Response *response) {
|
55
|
+
m_runningCommand->deleteLater();
|
56
|
+
writeResponse(response);
|
57
|
+
}
|
58
|
+
|
59
|
+
void Connection::writeResponse(Response *response) {
|
60
|
+
if (response->isSuccess())
|
61
|
+
m_socket->write("ok\n");
|
62
|
+
else
|
63
|
+
m_socket->write("failure\n");
|
64
|
+
|
65
|
+
QByteArray messageUtf8 = response->message();
|
66
|
+
QString messageLength = QString::number(messageUtf8.size()) + "\n";
|
67
|
+
m_socket->write(messageLength.toAscii());
|
68
|
+
m_socket->write(messageUtf8);
|
69
|
+
delete response;
|
70
|
+
}
|
71
|
+
|
data/src/Connection.h
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#include <QObject>
|
2
|
+
#include <QStringList>
|
3
|
+
|
4
|
+
class QTcpSocket;
|
5
|
+
class WebPage;
|
6
|
+
class Command;
|
7
|
+
class Response;
|
8
|
+
class CommandParser;
|
9
|
+
class CommandFactory;
|
10
|
+
class PageLoadingCommand;
|
11
|
+
|
12
|
+
class Connection : public QObject {
|
13
|
+
Q_OBJECT
|
14
|
+
|
15
|
+
public:
|
16
|
+
Connection(QTcpSocket *socket, WebPage *page, QObject *parent = 0);
|
17
|
+
|
18
|
+
public slots:
|
19
|
+
void commandReady(Command *command);
|
20
|
+
void finishCommand(Response *response);
|
21
|
+
void pendingLoadFinished(bool success);
|
22
|
+
|
23
|
+
private:
|
24
|
+
void startCommand();
|
25
|
+
void writeResponse(Response *response);
|
26
|
+
void writePageLoadFailure();
|
27
|
+
|
28
|
+
QTcpSocket *m_socket;
|
29
|
+
Command *m_queuedCommand;
|
30
|
+
WebPage *m_page;
|
31
|
+
CommandParser *m_commandParser;
|
32
|
+
CommandFactory *m_commandFactory;
|
33
|
+
PageLoadingCommand *m_runningCommand;
|
34
|
+
bool m_pageSuccess;
|
35
|
+
bool m_commandWaiting;
|
36
|
+
};
|
37
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#include "ConsoleMessages.h"
|
2
|
+
#include "WebPage.h"
|
3
|
+
|
4
|
+
ConsoleMessages::ConsoleMessages(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
|
5
|
+
}
|
6
|
+
|
7
|
+
void ConsoleMessages::start() {
|
8
|
+
emit finished(new Response(true, page()->consoleMessages()));
|
9
|
+
}
|
10
|
+
|