mirror of
https://github.com/thoughtbot/capybara-webkit
synced 2023-03-27 23:22:28 -04:00
144a43ff7b
* When WEBKIT_SERVER_START_TIMEOUT was reached, @port would get set to nil. If execution of the SERVER_PROCESS returned immediately, @port would get set to 0. This lead to odd cross-platform behavior in #connect, which would try to connect to a nonsense port.
101 lines
2.3 KiB
Ruby
101 lines
2.3 KiB
Ruby
require 'socket'
|
|
require 'timeout'
|
|
require 'thread'
|
|
require 'open3'
|
|
|
|
module Capybara::Webkit
|
|
class Connection
|
|
SERVER_PATH = File.expand_path("../../../../bin/webkit_server", __FILE__)
|
|
WEBKIT_SERVER_START_TIMEOUT = 15
|
|
|
|
attr_reader :port, :pid
|
|
|
|
def initialize(options = {})
|
|
@socket = nil
|
|
@socket_class = options[:socket_class] || TCPSocket
|
|
if options.has_key?(:stderr)
|
|
@output_target = options[:stderr]
|
|
elsif options.has_key?(:stdout)
|
|
warn '[DEPRECATION] The Capybara::Webkit::Connection `stdout` option ' \
|
|
'is deprecated. Please use `stderr` instead.'
|
|
@output_target = options[:stdout]
|
|
else
|
|
@output_target = $stderr
|
|
end
|
|
start_server
|
|
connect
|
|
end
|
|
|
|
def puts(string)
|
|
@socket.puts string
|
|
end
|
|
|
|
def print(string)
|
|
@socket.print string
|
|
end
|
|
|
|
def gets
|
|
@socket.gets
|
|
end
|
|
|
|
def read(length)
|
|
@socket.read(length)
|
|
end
|
|
|
|
private
|
|
|
|
def start_server
|
|
open_pipe
|
|
discover_port
|
|
discover_pid
|
|
forward_output_in_background_thread
|
|
end
|
|
|
|
def open_pipe
|
|
@pipe_stdin, @pipe_stdout, @pipe_stderr, @wait_thr = Open3.popen3(SERVER_PATH)
|
|
end
|
|
|
|
def parse_port(line)
|
|
if match = line.to_s.match(/listening on port: (\d+)/)
|
|
match[1].to_i
|
|
else
|
|
raise ConnectionError, "#{SERVER_PATH} failed to start."
|
|
end
|
|
end
|
|
|
|
def discover_port
|
|
if IO.select([@pipe_stdout], nil, nil, WEBKIT_SERVER_START_TIMEOUT)
|
|
@port = parse_port(@pipe_stdout.first)
|
|
else
|
|
raise ConnectionError, "#{SERVER_PATH} failed to start after #{WEBKIT_SERVER_START_TIMEOUT} seconds."
|
|
end
|
|
end
|
|
|
|
def discover_pid
|
|
@pid = @wait_thr[:pid]
|
|
end
|
|
|
|
def forward_output_in_background_thread
|
|
Thread.new do
|
|
Thread.current.abort_on_exception = true
|
|
IO.copy_stream(@pipe_stderr, @output_target) if @output_target
|
|
end
|
|
end
|
|
|
|
def connect
|
|
Timeout.timeout(5) do
|
|
while @socket.nil?
|
|
attempt_connect
|
|
end
|
|
end
|
|
end
|
|
|
|
def attempt_connect
|
|
@socket = @socket_class.open("127.0.0.1", @port)
|
|
if defined?(Socket::TCP_NODELAY)
|
|
@socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
|
|
end
|
|
rescue Errno::ECONNREFUSED
|
|
end
|
|
end
|
|
end
|