imseng-capybara-webkit 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|