opal 1.6.1 → 1.7.0

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.
Files changed (212) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +17 -0
  3. data/CHANGELOG.md +35 -1
  4. data/Gemfile +1 -0
  5. data/HACKING.md +47 -26
  6. data/benchmark/benchmarks +415 -103
  7. data/benchmark/bm_call_overhead.yml +28 -0
  8. data/benchmark/run.rb +61 -40
  9. data/docs/cdp_common.json +3364 -0
  10. data/docs/cdp_common.md +18 -0
  11. data/docs/{headless_chrome.md → headless_browsers.md} +31 -12
  12. data/lib/opal/ast/builder.rb +1 -1
  13. data/lib/opal/builder.rb +6 -1
  14. data/lib/opal/builder_processors.rb +5 -3
  15. data/lib/opal/cache.rb +1 -7
  16. data/lib/opal/cli_options.rb +72 -58
  17. data/lib/opal/cli_runners/chrome.rb +47 -9
  18. data/lib/opal/cli_runners/chrome_cdp_interface.rb +238 -112
  19. data/lib/opal/cli_runners/compiler.rb +146 -13
  20. data/lib/opal/cli_runners/deno.rb +32 -0
  21. data/lib/opal/cli_runners/firefox.rb +350 -0
  22. data/lib/opal/cli_runners/firefox_cdp_interface.rb +212 -0
  23. data/lib/opal/cli_runners/node_modules/.bin/chrome-remote-interface.cmd +17 -0
  24. data/lib/opal/cli_runners/node_modules/.bin/chrome-remote-interface.ps1 +28 -0
  25. data/lib/opal/cli_runners/node_modules/.package-lock.json +41 -0
  26. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/LICENSE +1 -1
  27. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/README.md +322 -182
  28. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/bin/client.js +99 -114
  29. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/chrome-remote-interface.js +1 -11
  30. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/index.js +16 -11
  31. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/api.js +41 -33
  32. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/chrome.js +224 -214
  33. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/devtools.js +71 -191
  34. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/external-request.js +26 -6
  35. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/protocol.json +20788 -9049
  36. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/websocket-wrapper.js +10 -3
  37. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/package.json +59 -123
  38. data/lib/opal/cli_runners/node_modules/chrome-remote-interface/webpack.config.js +25 -32
  39. data/lib/opal/cli_runners/node_modules/commander/History.md +298 -0
  40. data/lib/opal/cli_runners/node_modules/commander/LICENSE +22 -0
  41. data/lib/opal/cli_runners/node_modules/commander/Readme.md +217 -61
  42. data/lib/opal/cli_runners/node_modules/commander/index.js +431 -145
  43. data/lib/opal/cli_runners/node_modules/commander/package.json +16 -79
  44. data/lib/opal/cli_runners/node_modules/ws/README.md +334 -98
  45. data/lib/opal/cli_runners/node_modules/ws/browser.js +8 -0
  46. data/lib/opal/cli_runners/node_modules/ws/index.js +5 -10
  47. data/lib/opal/cli_runners/node_modules/ws/lib/buffer-util.js +129 -0
  48. data/lib/opal/cli_runners/node_modules/ws/lib/constants.js +10 -0
  49. data/lib/opal/cli_runners/node_modules/ws/lib/event-target.js +184 -0
  50. data/lib/opal/cli_runners/node_modules/ws/lib/extension.js +223 -0
  51. data/lib/opal/cli_runners/node_modules/ws/lib/limiter.js +55 -0
  52. data/lib/opal/cli_runners/node_modules/ws/lib/permessage-deflate.js +518 -0
  53. data/lib/opal/cli_runners/node_modules/ws/lib/receiver.js +607 -0
  54. data/lib/opal/cli_runners/node_modules/ws/lib/sender.js +409 -0
  55. data/lib/opal/cli_runners/node_modules/ws/lib/stream.js +180 -0
  56. data/lib/opal/cli_runners/node_modules/ws/lib/validation.js +104 -0
  57. data/lib/opal/cli_runners/node_modules/ws/lib/websocket-server.js +447 -0
  58. data/lib/opal/cli_runners/node_modules/ws/lib/websocket.js +1195 -0
  59. data/lib/opal/cli_runners/node_modules/ws/package.json +40 -106
  60. data/lib/opal/cli_runners/package-lock.json +62 -0
  61. data/lib/opal/cli_runners/package.json +1 -1
  62. data/lib/opal/cli_runners.rb +26 -4
  63. data/lib/opal/nodes/args/prepare_post_args.rb +2 -2
  64. data/lib/opal/nodes/def.rb +8 -8
  65. data/lib/opal/nodes/iter.rb +12 -12
  66. data/lib/opal/nodes/logic.rb +1 -1
  67. data/lib/opal/nodes/masgn.rb +2 -2
  68. data/lib/opal/parser/with_ruby_lexer.rb +1 -1
  69. data/lib/opal/paths.rb +14 -0
  70. data/lib/opal/rewriter.rb +2 -0
  71. data/lib/opal/rewriters/forward_args.rb +52 -4
  72. data/lib/opal/rewriters/targeted_patches.rb +94 -0
  73. data/lib/opal/version.rb +1 -1
  74. data/opal/corelib/basic_object.rb +1 -1
  75. data/opal/corelib/boolean.rb +2 -2
  76. data/opal/corelib/class.rb +11 -0
  77. data/opal/corelib/constants.rb +3 -3
  78. data/opal/corelib/enumerable.rb +4 -0
  79. data/opal/corelib/enumerator.rb +1 -1
  80. data/opal/corelib/hash.rb +2 -2
  81. data/opal/corelib/helpers.rb +1 -1
  82. data/opal/corelib/kernel.rb +3 -3
  83. data/opal/corelib/method.rb +1 -1
  84. data/opal/corelib/module.rb +29 -8
  85. data/opal/corelib/proc.rb +7 -5
  86. data/opal/corelib/runtime.js +141 -78
  87. data/opal/corelib/set.rb +252 -0
  88. data/opal/corelib/string.rb +2 -1
  89. data/opal/corelib/time.rb +2 -2
  90. data/opal/opal.rb +1 -0
  91. data/opal.gemspec +1 -0
  92. data/spec/filters/bugs/array.rb +22 -13
  93. data/spec/filters/bugs/base64.rb +5 -5
  94. data/spec/filters/bugs/basicobject.rb +16 -8
  95. data/spec/filters/bugs/bigdecimal.rb +161 -160
  96. data/spec/filters/bugs/binding.rb +10 -10
  97. data/spec/filters/bugs/class.rb +8 -8
  98. data/spec/filters/bugs/complex.rb +2 -1
  99. data/spec/filters/bugs/date.rb +79 -81
  100. data/spec/filters/bugs/datetime.rb +29 -29
  101. data/spec/filters/bugs/delegate.rb +1 -3
  102. data/spec/filters/bugs/encoding.rb +69 -69
  103. data/spec/filters/bugs/enumerable.rb +22 -20
  104. data/spec/filters/bugs/enumerator.rb +88 -85
  105. data/spec/filters/bugs/exception.rb +46 -40
  106. data/spec/filters/bugs/file.rb +32 -32
  107. data/spec/filters/bugs/float.rb +26 -21
  108. data/spec/filters/bugs/freeze.rb +88 -0
  109. data/spec/filters/bugs/hash.rb +39 -38
  110. data/spec/filters/bugs/integer.rb +57 -44
  111. data/spec/filters/bugs/io.rb +1 -1
  112. data/spec/filters/bugs/kernel.rb +349 -269
  113. data/spec/filters/bugs/language.rb +220 -188
  114. data/spec/filters/bugs/main.rb +5 -3
  115. data/spec/filters/bugs/marshal.rb +38 -38
  116. data/spec/filters/bugs/math.rb +2 -1
  117. data/spec/filters/bugs/method.rb +73 -62
  118. data/spec/filters/bugs/module.rb +163 -143
  119. data/spec/filters/bugs/numeric.rb +6 -6
  120. data/spec/filters/bugs/objectspace.rb +16 -16
  121. data/spec/filters/bugs/openstruct.rb +1 -1
  122. data/spec/filters/bugs/pack_unpack.rb +51 -51
  123. data/spec/filters/bugs/pathname.rb +7 -7
  124. data/spec/filters/bugs/proc.rb +63 -63
  125. data/spec/filters/bugs/random.rb +7 -6
  126. data/spec/filters/bugs/range.rb +12 -9
  127. data/spec/filters/bugs/rational.rb +8 -7
  128. data/spec/filters/bugs/regexp.rb +49 -48
  129. data/spec/filters/bugs/ruby-32.rb +56 -0
  130. data/spec/filters/bugs/set.rb +30 -30
  131. data/spec/filters/bugs/singleton.rb +4 -4
  132. data/spec/filters/bugs/string.rb +187 -99
  133. data/spec/filters/bugs/stringio.rb +7 -0
  134. data/spec/filters/bugs/stringscanner.rb +68 -68
  135. data/spec/filters/bugs/struct.rb +11 -9
  136. data/spec/filters/bugs/symbol.rb +1 -1
  137. data/spec/filters/bugs/time.rb +78 -63
  138. data/spec/filters/bugs/trace_point.rb +4 -4
  139. data/spec/filters/bugs/unboundmethod.rb +32 -17
  140. data/spec/filters/bugs/warnings.rb +8 -12
  141. data/spec/filters/unsupported/array.rb +24 -107
  142. data/spec/filters/unsupported/basicobject.rb +12 -12
  143. data/spec/filters/unsupported/bignum.rb +27 -52
  144. data/spec/filters/unsupported/class.rb +1 -2
  145. data/spec/filters/unsupported/delegator.rb +3 -3
  146. data/spec/filters/unsupported/enumerable.rb +2 -9
  147. data/spec/filters/unsupported/enumerator.rb +2 -11
  148. data/spec/filters/unsupported/file.rb +1 -1
  149. data/spec/filters/unsupported/float.rb +28 -47
  150. data/spec/filters/unsupported/hash.rb +8 -14
  151. data/spec/filters/unsupported/integer.rb +75 -91
  152. data/spec/filters/unsupported/kernel.rb +17 -35
  153. data/spec/filters/unsupported/language.rb +11 -19
  154. data/spec/filters/unsupported/marshal.rb +22 -41
  155. data/spec/filters/unsupported/matchdata.rb +28 -52
  156. data/spec/filters/unsupported/math.rb +1 -1
  157. data/spec/filters/unsupported/privacy.rb +229 -285
  158. data/spec/filters/unsupported/range.rb +1 -5
  159. data/spec/filters/unsupported/regexp.rb +40 -66
  160. data/spec/filters/unsupported/set.rb +2 -2
  161. data/spec/filters/unsupported/singleton.rb +4 -4
  162. data/spec/filters/unsupported/string.rb +305 -508
  163. data/spec/filters/unsupported/struct.rb +3 -4
  164. data/spec/filters/unsupported/symbol.rb +15 -18
  165. data/spec/filters/unsupported/thread.rb +1 -7
  166. data/spec/filters/unsupported/time.rb +159 -202
  167. data/spec/filters/unsupported/usage_of_files.rb +170 -259
  168. data/spec/lib/builder_spec.rb +4 -4
  169. data/spec/lib/rewriters/forward_args_spec.rb +32 -12
  170. data/spec/mspec-opal/runner.rb +2 -0
  171. data/spec/ruby_specs +4 -0
  172. data/stdlib/deno/base.rb +28 -0
  173. data/stdlib/deno/file.rb +340 -0
  174. data/stdlib/{headless_chrome.rb → headless_browser/base.rb} +1 -1
  175. data/stdlib/headless_browser/file.rb +15 -0
  176. data/stdlib/headless_browser.rb +4 -0
  177. data/stdlib/native.rb +1 -1
  178. data/stdlib/nodejs/file.rb +5 -0
  179. data/stdlib/opal/platform.rb +8 -6
  180. data/stdlib/opal-platform.rb +14 -8
  181. data/stdlib/set.rb +1 -258
  182. data/tasks/benchmarking.rake +62 -19
  183. data/tasks/performance.rake +1 -1
  184. data/tasks/testing.rake +5 -3
  185. data/test/nodejs/test_file.rb +29 -10
  186. data/test/opal/http_server.rb +28 -11
  187. data/test/opal/unsupported_and_bugs.rb +2 -1
  188. metadata +89 -50
  189. data/lib/opal/cli_runners/node_modules/ultron/LICENSE +0 -22
  190. data/lib/opal/cli_runners/node_modules/ultron/index.js +0 -138
  191. data/lib/opal/cli_runners/node_modules/ultron/package.json +0 -112
  192. data/lib/opal/cli_runners/node_modules/ws/SECURITY.md +0 -33
  193. data/lib/opal/cli_runners/node_modules/ws/lib/BufferUtil.fallback.js +0 -56
  194. data/lib/opal/cli_runners/node_modules/ws/lib/BufferUtil.js +0 -15
  195. data/lib/opal/cli_runners/node_modules/ws/lib/ErrorCodes.js +0 -28
  196. data/lib/opal/cli_runners/node_modules/ws/lib/EventTarget.js +0 -158
  197. data/lib/opal/cli_runners/node_modules/ws/lib/Extensions.js +0 -69
  198. data/lib/opal/cli_runners/node_modules/ws/lib/PerMessageDeflate.js +0 -339
  199. data/lib/opal/cli_runners/node_modules/ws/lib/Receiver.js +0 -520
  200. data/lib/opal/cli_runners/node_modules/ws/lib/Sender.js +0 -438
  201. data/lib/opal/cli_runners/node_modules/ws/lib/Validation.fallback.js +0 -9
  202. data/lib/opal/cli_runners/node_modules/ws/lib/Validation.js +0 -17
  203. data/lib/opal/cli_runners/node_modules/ws/lib/WebSocket.js +0 -705
  204. data/lib/opal/cli_runners/node_modules/ws/lib/WebSocketServer.js +0 -336
  205. data/spec/filters/bugs/boolean.rb +0 -3
  206. data/spec/filters/bugs/matrix.rb +0 -3
  207. data/spec/filters/unsupported/fixnum.rb +0 -15
  208. data/spec/filters/unsupported/freeze.rb +0 -102
  209. data/spec/filters/unsupported/pathname.rb +0 -4
  210. data/spec/filters/unsupported/proc.rb +0 -4
  211. data/spec/filters/unsupported/random.rb +0 -5
  212. data/spec/filters/unsupported/taint.rb +0 -162
@@ -0,0 +1,350 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'shellwords'
4
+ require 'socket'
5
+ require 'timeout'
6
+ require 'tmpdir'
7
+ require 'rbconfig'
8
+ require 'opal/os'
9
+ require 'json'
10
+ require 'fileutils'
11
+ require 'net/http'
12
+
13
+ module Opal
14
+ module CliRunners
15
+ class Firefox
16
+ SCRIPT_PATH = File.expand_path('firefox_cdp_interface.rb', __dir__).freeze
17
+
18
+ DEFAULT_CHROME_HOST = 'localhost'
19
+ DEFAULT_CHROME_PORT = 9333 # makes sure it doesn't accidentally connect to a lingering chrome
20
+
21
+ def self.call(data)
22
+ runner = new(data)
23
+ runner.run
24
+ end
25
+
26
+ def initialize(data)
27
+ builder = data[:builder].call
28
+ options = data[:options]
29
+ argv = data[:argv]
30
+
31
+ if argv && argv.any?
32
+ warn "warning: ARGV is not supported by the Firefox runner #{argv.inspect}"
33
+ end
34
+
35
+ @output = options.fetch(:output, $stdout)
36
+ @builder = builder
37
+ end
38
+
39
+ attr_reader :output, :exit_status, :builder
40
+
41
+ def run
42
+ mktmpdir do |dir|
43
+ with_firefox_server do
44
+ prepare_files_in(dir)
45
+
46
+ env = {
47
+ 'CHROME_HOST' => chrome_host,
48
+ 'CHROME_PORT' => chrome_port.to_s,
49
+ 'NODE_PATH' => File.join(__dir__, 'node_modules')
50
+ }
51
+ env['OPAL_CDP_EXT'] = builder.output_extension
52
+
53
+ cmd = [
54
+ RbConfig.ruby,
55
+ "#{__dir__}/../../../exe/opal",
56
+ '--no-exit',
57
+ '-I', __dir__,
58
+ '-r', 'source-map-support-node',
59
+ SCRIPT_PATH,
60
+ dir
61
+ ]
62
+
63
+ Kernel.exec(env, *cmd)
64
+ end
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def prepare_files_in(dir)
71
+ js = builder.to_s
72
+ map = builder.source_map.to_json
73
+ ext = builder.output_extension
74
+ module_type = ' type="module"' if builder.esm?
75
+
76
+ # CDP can't handle huge data passed to `addScriptToEvaluateOnLoad`
77
+ # https://groups.google.com/a/chromium.org/forum/#!topic/chromium-discuss/U5qyeX_ydBo
78
+ # The only way is to create temporary files and pass them to the browser.
79
+ File.binwrite("#{dir}/index.#{ext}", js)
80
+ File.binwrite("#{dir}/index.#{ext}.map", map)
81
+ File.binwrite("#{dir}/index.html", <<~HTML)
82
+ <!DOCTYPE html>
83
+ <html><head>
84
+ <meta charset='utf-8'>
85
+ <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
86
+ <script>
87
+ window.opalheadlessfirefox = true;
88
+ </script>
89
+ </head><body>
90
+ <script src='/index.#{ext}'#{module_type}></script>
91
+ </body></html>
92
+ HTML
93
+ end
94
+
95
+ def chrome_host
96
+ ENV['CHROME_HOST'] || DEFAULT_CHROME_HOST
97
+ end
98
+
99
+ def chrome_port
100
+ ENV['CHROME_PORT'] || DEFAULT_CHROME_PORT
101
+ end
102
+
103
+ def with_firefox_server
104
+ if firefox_server_running?
105
+ yield
106
+ else
107
+ run_firefox_server { yield }
108
+ end
109
+ end
110
+
111
+ def run_firefox_server
112
+ raise 'Firefox server can be started only on localhost' if chrome_host != DEFAULT_CHROME_HOST
113
+
114
+ profile = mktmpprofile
115
+
116
+ # For options see https://github.com/puppeteer/puppeteer/blob/main/packages/puppeteer-core/src/node/FirefoxLauncher.ts
117
+ firefox_server_cmd = %{#{OS.shellescape(firefox_executable)} \
118
+ --no-remote \
119
+ --profile #{profile} \
120
+ --headless \
121
+ --remote-debugging-port #{chrome_port} \
122
+ #{ENV['FIREFOX_OPTS']}}
123
+
124
+ firefox_pid = Process.spawn(firefox_server_cmd, in: OS.dev_null, out: OS.dev_null, err: OS.dev_null)
125
+
126
+ Timeout.timeout(30) do
127
+ loop do
128
+ break if firefox_server_running?
129
+ sleep 0.5
130
+ end
131
+ end
132
+
133
+ yield
134
+ rescue Timeout::Error
135
+ puts 'Failed to start firefox server'
136
+ puts 'Make sure that you have it installed and that its version is > 100'
137
+ exit(1)
138
+ ensure
139
+ if OS.windows? && firefox_pid
140
+ Process.kill('KILL', firefox_pid) unless system("taskkill /f /t /pid #{firefox_pid} >NUL 2>NUL")
141
+ elsif firefox_pid
142
+ Process.kill('HUP', firefox_pid)
143
+ end
144
+ FileUtils.rm_rf(profile) if profile
145
+ end
146
+
147
+ def firefox_server_running?
148
+ puts "Connecting to #{chrome_host}:#{chrome_port}..."
149
+ TCPSocket.new(chrome_host, chrome_port).close
150
+ # Firefox CDP endpoints are initialized after the CDP port is ready
151
+ # this causes first requests to fail
152
+ # wait until the CDP endpoints are ready
153
+ response = Net::HTTP.get_response('localhost', '/json/list', chrome_port)
154
+ raise Errno::EADDRNOTAVAIL if response.code != '200'
155
+ true
156
+ rescue Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL
157
+ false
158
+ end
159
+
160
+ def firefox_executable
161
+ ENV['MOZILLA_FIREFOX_BINARY'] ||
162
+ if OS.windows?
163
+ [
164
+ 'C:/Program Files/Mozilla Firefox/firefox.exe'
165
+ ].each do |path|
166
+ next unless File.exist? path
167
+ return path
168
+ end
169
+ elsif OS.macos?
170
+ '/Applications/Firefox.app/Contents/MacOS/Firefox'
171
+ else
172
+ %w[
173
+ firefox
174
+ firefox-esr
175
+ ].each do |name|
176
+ next unless system('sh', '-c', "command -v #{name.shellescape}", out: '/dev/null')
177
+ return name
178
+ end
179
+ raise 'Cannot find firefox executable'
180
+ end
181
+ end
182
+
183
+ def mktmpdir(&block)
184
+ Dir.mktmpdir('firefox-opal-', &block)
185
+ end
186
+
187
+ def mktmpprofile
188
+ profile = Dir.mktmpdir('firefox-opal-profile-')
189
+ default_prefs = {
190
+ # Make sure Shield doesn't hit the network.
191
+ 'app.normandy.api_url': '',
192
+ # Disable Firefox old build background check
193
+ 'app.update.checkInstallTime': false,
194
+ # Disable automatically upgrading Firefox
195
+ 'app.update.disabledForTesting': true,
196
+ # Increase the APZ content response timeout to 1 minute
197
+ 'apz.content_response_timeout': 60_000,
198
+ # Prevent various error message on the console
199
+ 'browser.contentblocking.features.standard':
200
+ '-tp,tpPrivate,cookieBehavior0,-cm,-fp',
201
+ # Enable the dump function: which sends messages to the system console
202
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1543115
203
+ 'browser.dom.window.dump.enabled': true,
204
+ # Disable topstories
205
+ 'browser.newtabpage.activity-stream.feeds.system.topstories': false,
206
+ # Always display a blank page
207
+ 'browser.newtabpage.enabled': false,
208
+ # Background thumbnails in particular cause grief: and disabling
209
+ # thumbnails in general cannot hurt
210
+ 'browser.pagethumbnails.capturing_disabled': true,
211
+ # Disable safebrowsing components.
212
+ 'browser.safebrowsing.blockedURIs.enabled': false,
213
+ 'browser.safebrowsing.downloads.enabled': false,
214
+ 'browser.safebrowsing.malware.enabled': false,
215
+ 'browser.safebrowsing.passwords.enabled': false,
216
+ 'browser.safebrowsing.phishing.enabled': false,
217
+ # Disable updates to search engines.
218
+ 'browser.search.update': false,
219
+ # Do not restore the last open set of tabs if the browser has crashed
220
+ 'browser.sessionstore.resume_from_crash': false,
221
+ # Skip check for default browser on startup
222
+ 'browser.shell.checkDefaultBrowser': false,
223
+ # Disable newtabpage
224
+ 'browser.startup.homepage': 'about:blank',
225
+ # Do not redirect user when a milstone upgrade of Firefox is detected
226
+ 'browser.startup.homepage_override.mstone': 'ignore',
227
+ # Start with a blank page about:blank
228
+ 'browser.startup.page': 0,
229
+ # Do not allow background tabs to be zombified on Android: otherwise for
230
+ # tests that open additional tabs: the test harness tab itself might get unloaded
231
+ 'browser.tabs.disableBackgroundZombification': false,
232
+ # Do not warn when closing all other open tabs
233
+ 'browser.tabs.warnOnCloseOtherTabs': false,
234
+ # Do not warn when multiple tabs will be opened
235
+ 'browser.tabs.warnOnOpen': false,
236
+ # Disable the UI tour.
237
+ 'browser.uitour.enabled': false,
238
+ # Turn off search suggestions in the location bar so as not to trigger
239
+ # network connections.
240
+ 'browser.urlbar.suggest.searches': false,
241
+ # Disable first run splash page on Windows 10
242
+ 'browser.usedOnWindows10.introURL': '',
243
+ # Do not warn on quitting Firefox
244
+ 'browser.warnOnQuit': false,
245
+ # Defensively disable data reporting systems
246
+ 'datareporting.healthreport.documentServerURI': 'http://localhost/dummy/healthreport/',
247
+ 'datareporting.healthreport.logging.consoleEnabled': false,
248
+ 'datareporting.healthreport.service.enabled': false,
249
+ 'datareporting.healthreport.service.firstRun': false,
250
+ 'datareporting.healthreport.uploadEnabled': false,
251
+ # Do not show datareporting policy notifications which can interfere with tests
252
+ 'datareporting.policy.dataSubmissionEnabled': false,
253
+ 'datareporting.policy.dataSubmissionPolicyBypassNotification': true,
254
+ # DevTools JSONViewer sometimes fails to load dependencies with its require.js.
255
+ # This doesn't affect Puppeteer but spams console (Bug 1424372)
256
+ 'devtools.jsonview.enabled': false,
257
+ # Disable popup-blocker
258
+ 'dom.disable_open_during_load': false,
259
+ # Enable the support for File object creation in the content process
260
+ # Required for |Page.setFileInputFiles| protocol method.
261
+ 'dom.file.createInChild': true,
262
+ # Disable the ProcessHangMonitor
263
+ 'dom.ipc.reportProcessHangs': false,
264
+ # Disable slow script dialogues
265
+ 'dom.max_chrome_script_run_time': 0,
266
+ 'dom.max_script_run_time': 0,
267
+ # Only load extensions from the application and user profile
268
+ # AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
269
+ 'extensions.autoDisableScopes': 0,
270
+ 'extensions.enabledScopes': 5,
271
+ # Disable metadata caching for installed add-ons by default
272
+ 'extensions.getAddons.cache.enabled': false,
273
+ # Disable installing any distribution extensions or add-ons.
274
+ 'extensions.installDistroAddons': false,
275
+ # Disabled screenshots extension
276
+ 'extensions.screenshots.disabled': true,
277
+ # Turn off extension updates so they do not bother tests
278
+ 'extensions.update.enabled': false,
279
+ # Turn off extension updates so they do not bother tests
280
+ 'extensions.update.notifyUser': false,
281
+ # Make sure opening about:addons will not hit the network
282
+ 'extensions.webservice.discoverURL': 'http://localhost/dummy/discoveryURL',
283
+ # Temporarily force disable BFCache in parent (https://bit.ly/bug-1732263)
284
+ 'fission.bfcacheInParent': false,
285
+ # Force all web content to use a single content process
286
+ 'fission.webContentIsolationStrategy': 0,
287
+ # Allow the application to have focus even it runs in the background
288
+ 'focusmanager.testmode': true,
289
+ # Disable useragent updates
290
+ 'general.useragent.updates.enabled': false,
291
+ # Always use network provider for geolocation tests so we bypass the
292
+ # macOS dialog raised by the corelocation provider
293
+ 'geo.provider.testing': true,
294
+ # Do not scan Wifi
295
+ 'geo.wifi.scan': false,
296
+ # No hang monitor
297
+ 'hangmonitor.timeout': 0,
298
+ # Show chrome errors and warnings in the error console
299
+ 'javascript.options.showInConsole': true,
300
+ # Disable download and usage of OpenH264: and Widevine plugins
301
+ 'media.gmp-manager.updateEnabled': false,
302
+ # Prevent various error message on the console
303
+ 'network.cookie.cookieBehavior': 0,
304
+ # Disable experimental feature that is only available in Nightly
305
+ 'network.cookie.sameSite.laxByDefault': false,
306
+ # Do not prompt for temporary redirects
307
+ 'network.http.prompt-temp-redirect': false,
308
+ # Disable speculative connections so they are not reported as leaking
309
+ # when they are hanging around
310
+ 'network.http.speculative-parallel-limit': 0,
311
+ # Do not automatically switch between offline and online
312
+ 'network.manage-offline-status': false,
313
+ # Make sure SNTP requests do not hit the network
314
+ 'network.sntp.pools': 'localhost',
315
+ # Disable Flash.
316
+ 'plugin.state.flash': 0,
317
+ 'privacy.trackingprotection.enabled': false,
318
+ # Can be removed once Firefox 89 is no longer supported
319
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1710839
320
+ 'remote.enabled': true,
321
+ # Don't do network connections for mitm priming
322
+ 'security.certerrors.mitm.priming.enabled': false,
323
+ # Local documents have access to all other local documents,
324
+ # including directory listings
325
+ 'security.fileuri.strict_origin_policy': false,
326
+ # Do not wait for the notification button security delay
327
+ 'security.notification_enable_delay': 0,
328
+ # Ensure blocklist updates do not hit the network
329
+ 'services.settings.server': 'http://localhost/dummy/blocklist/',
330
+ # Do not automatically fill sign-in forms with known usernames and passwords
331
+ 'signon.autofillForms': false,
332
+ # Disable password capture, so that tests that include forms are not
333
+ # influenced by the presence of the persistent doorhanger notification
334
+ 'signon.rememberSignons': false,
335
+ # Disable first-run welcome page
336
+ 'startup.homepage_welcome_url': 'about:blank',
337
+ # Disable first-run welcome page
338
+ 'startup.homepage_welcome_url.additional': '',
339
+ # Disable browser animations (tabs, fullscreen, sliding alerts)
340
+ 'toolkit.cosmeticAnimations.enabled': false,
341
+ # Prevent starting into safe mode after application crashes
342
+ 'toolkit.startup.max_resumed_crashes': -1,
343
+ }
344
+ prefs = default_prefs.map { |key, value| "user_pref(\"#{key}\", #{JSON.dump(value)});" }
345
+ File.binwrite(profile + '/prefs.js', prefs.join("\n"))
346
+ profile
347
+ end
348
+ end
349
+ end
350
+ end
@@ -0,0 +1,212 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This script I converted into Opal, so that I don't have to write
4
+ # buffer handling again. We have gets, Node has nothing close to it,
5
+ # even async.
6
+ # For CDP see docs/cdp_common.(md|json)
7
+
8
+ require 'opal/platform'
9
+ require 'nodejs/env'
10
+
11
+ %x{
12
+ var CDP = require("chrome-remote-interface");
13
+ var fs = require("fs");
14
+ var http = require("http");
15
+
16
+ var dir = #{ARGV.last};
17
+ // var ext = #{ENV['OPAL_CDP_EXT']}; // not used at the moment
18
+ var offset; // port offset for http server, depending on number of targets
19
+
20
+ // even though its Firefox, "chrome-remote-interface" expects CHROME_* vars
21
+ var options = {
22
+ host: #{ENV['CHROME_HOST'] || 'localhost'},
23
+ port: parseInt(#{ENV['CHROME_PORT'] || '9333'}) // makes sure it doesn't accidentally connect to a lingering chrome
24
+ };
25
+
26
+ // support functions
27
+
28
+ function perror(error) { console.error(error); }
29
+
30
+ var exiting = false;
31
+
32
+ function shutdown(exit_code) {
33
+ if (exiting) { return Promise.resolve(); }
34
+ exiting = true;
35
+ cdp_client.Target.closeTarget(target_id); // Promise doesn't get resolved
36
+ server.close();
37
+ process.exit(exit_code);
38
+ };
39
+
40
+ // simple HTTP server to deliver page, scripts to, and trigger commands from browser
41
+
42
+ function not_found(res) {
43
+ res.writeHead(404, { "Content-Type": "text/plain" });
44
+ res.end("NOT FOUND");
45
+ }
46
+
47
+ function response_ok(res) {
48
+ res.writeHead(200, { "Content-Type": "text/plain" });
49
+ res.end("OK");
50
+ }
51
+
52
+ function handle_post(req, res, fun) {
53
+ var data = "";
54
+ req.on('data', function(chunk) {
55
+ data += chunk;
56
+ })
57
+ req.on('end', function() {
58
+ var obj = JSON.parse(data);
59
+ fun.call(this, obj);
60
+ });
61
+ }
62
+
63
+ var server = http.createServer(function(req, res) {
64
+ if (req.method === "GET") {
65
+ var path = dir + '/' + req.url.slice(1);
66
+ if (path.includes('..') || !fs.existsSync(path)) {
67
+ not_found(res);
68
+ } else {
69
+ var content_type;
70
+ if (path.endsWith(".html")) {
71
+ content_type = "text/html"
72
+ } else if (path.endsWith(".map")) {
73
+ content_type = "application/json"
74
+ } else {
75
+ content_type = "application/javascript"
76
+ }
77
+ res.writeHead(200, { "Content-Type": content_type });
78
+ res.end(fs.readFileSync(path));
79
+ }
80
+ } else if (req.method === "POST") {
81
+ if (req.url === "/File.write") {
82
+ // totally insecure on purpose
83
+ handle_post(req, res, function(obj) {
84
+ fs.writeFileSync(obj.filename, obj.data);
85
+ response_ok(res);
86
+ });
87
+ } else {
88
+ not_found(res);
89
+ }
90
+ } else {
91
+ not_found(res);
92
+ }
93
+ });
94
+
95
+ // actual CDP code
96
+
97
+ CDP.List(options, function(err, targets) {
98
+ offset = targets ? targets.length + 1 : 1;
99
+
100
+ return CDP(options, function(browser_client) {
101
+
102
+ server.listen({port: offset + options.port, host: options.host });
103
+
104
+ browser_client.Target.createTarget({url: "about:blank"}).then(function(target) {
105
+ target_id = target;
106
+ options.target = target_id.targetId;
107
+
108
+ CDP(options, function(client) {
109
+ cdp_client = client;
110
+
111
+ var Log = client.Log,
112
+ Page = client.Page,
113
+ Runtime = client.Runtime;
114
+
115
+ // enable used CDP domains
116
+ Promise.all([
117
+ Log.enable(),
118
+ Page.enable(),
119
+ Runtime.enable()
120
+ ]).then(function() {
121
+
122
+ // receive and handle all kinds of log and console messages
123
+ Log.entryAdded(function(entry) {
124
+ process.stdout.write(entry.entry.level + ': ' + entry.entry.text + "\n");
125
+ });
126
+
127
+ Runtime.consoleAPICalled(function(entry) {
128
+ var args = entry.args;
129
+ var stack = null;
130
+ var i, arg, frame, value;
131
+
132
+ // output actual message
133
+ for(i = 0; i < args.length; i++) {
134
+ arg = args[i];
135
+ if (arg.type === "string") { value = arg.value; }
136
+ else { value = JSON.stringify(arg); }
137
+ process.stdout.write(value);
138
+ }
139
+
140
+ if (entry.stackTrace && entry.stackTrace.callFrames) { stack = entry.stackTrace.callFrames; }
141
+ if (entry.type === "error" && stack) {
142
+ // print full stack for errors
143
+ process.stdout.write("\n");
144
+ for(i = 0; i < stack.length; i++) {
145
+ frame = stack[i];
146
+ if (frame) {
147
+ value = frame.url + ':' + frame.lineNumer + ':' + frame.columnNumber + '\n';
148
+ process.stdout.write(value);
149
+ }
150
+ }
151
+ }
152
+ });
153
+
154
+ Runtime.exceptionThrown(function(exception) {
155
+ var ex = exception.exceptionDetails;
156
+ var stack = ex.stackTrace.callFrames;
157
+ var fr;
158
+ perror(ex.url + ':' + ex.lineNumber + ':' + ex.columnNumber + ': ' + ex.text);
159
+ for (var i = 0; i < stack.length; i++) {
160
+ fr = stack[i];
161
+ perror(fr.url + ':' + fr.lineNumber + ':' + fr.columnNumber + ': in ' + fr.functionName);
162
+ }
163
+ return shutdown(1);
164
+ });
165
+
166
+ Page.javascriptDialogOpening((dialog) => {
167
+ #{
168
+ if `dialog.type` == 'prompt'
169
+ message = gets&.chomp
170
+ if message
171
+ `Page.handleJavaScriptDialog({accept: true, promptText: #{message}})`
172
+ else
173
+ `Page.handleJavaScriptDialog({accept: false})`
174
+ end
175
+ elsif `dialog.type` == 'alert' && `dialog.message` == 'opalheadlessbrowserexit'
176
+ # A special case of an alert with a magic string "opalheadlessbrowserexit".
177
+ # This denotes that `Kernel#exit` has been called. We would have rather used
178
+ # an exception here, but they don't bubble sometimes.
179
+ %x{
180
+ Page.handleJavaScriptDialog({accept: true});
181
+ Runtime.evaluate({ expression: "window.OPAL_EXIT_CODE" }).then(function(output) {
182
+ var exit_code = 0;
183
+ if (typeof(output.result) !== "undefined" && output.result.type === "number") {
184
+ exit_code = output.result.value;
185
+ }
186
+ return shutdown(exit_code);
187
+ });
188
+ }
189
+ end
190
+ }
191
+ });
192
+
193
+ Page.loadEventFired(() => {
194
+ Runtime.evaluate({ expression: "window.OPAL_EXIT_CODE" }).then(function(output) {
195
+ if (typeof(output.result) !== "undefined" && output.result.type === "number") {
196
+ return shutdown(output.result.value);
197
+ } else if (typeof(output.result) !== "undefined" && output.result.type === "string" && output.result.value === "noexit") {
198
+ // do nothing, we have headless chrome support enabled and there are most probably async events awaiting
199
+ } else {
200
+ return shutdown(0);
201
+ }
202
+ })
203
+ });
204
+
205
+ Page.navigate({ url: "http://localhost:" + (offset + options.port).toString() + "/index.html" })
206
+ });
207
+ });
208
+ });
209
+ });
210
+ });
211
+ }
212
+ # end of code (marker to help see if brackets match above)
@@ -0,0 +1,17 @@
1
+ @ECHO off
2
+ GOTO start
3
+ :find_dp0
4
+ SET dp0=%~dp0
5
+ EXIT /b
6
+ :start
7
+ SETLOCAL
8
+ CALL :find_dp0
9
+
10
+ IF EXIST "%dp0%\node.exe" (
11
+ SET "_prog=%dp0%\node.exe"
12
+ ) ELSE (
13
+ SET "_prog=node"
14
+ SET PATHEXT=%PATHEXT:;.JS;=;%
15
+ )
16
+
17
+ endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\chrome-remote-interface\bin\client.js" %*
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env pwsh
2
+ $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
3
+
4
+ $exe=""
5
+ if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
6
+ # Fix case when both the Windows and Linux builds of Node
7
+ # are installed in the same directory
8
+ $exe=".exe"
9
+ }
10
+ $ret=0
11
+ if (Test-Path "$basedir/node$exe") {
12
+ # Support pipeline input
13
+ if ($MyInvocation.ExpectingInput) {
14
+ $input | & "$basedir/node$exe" "$basedir/../chrome-remote-interface/bin/client.js" $args
15
+ } else {
16
+ & "$basedir/node$exe" "$basedir/../chrome-remote-interface/bin/client.js" $args
17
+ }
18
+ $ret=$LASTEXITCODE
19
+ } else {
20
+ # Support pipeline input
21
+ if ($MyInvocation.ExpectingInput) {
22
+ $input | & "node$exe" "$basedir/../chrome-remote-interface/bin/client.js" $args
23
+ } else {
24
+ & "node$exe" "$basedir/../chrome-remote-interface/bin/client.js" $args
25
+ }
26
+ $ret=$LASTEXITCODE
27
+ }
28
+ exit $ret
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "cli_runners",
3
+ "lockfileVersion": 2,
4
+ "requires": true,
5
+ "packages": {
6
+ "node_modules/chrome-remote-interface": {
7
+ "version": "0.31.3",
8
+ "license": "MIT",
9
+ "dependencies": {
10
+ "commander": "2.11.x",
11
+ "ws": "^7.2.0"
12
+ },
13
+ "bin": {
14
+ "chrome-remote-interface": "bin/client.js"
15
+ }
16
+ },
17
+ "node_modules/commander": {
18
+ "version": "2.11.0",
19
+ "license": "MIT"
20
+ },
21
+ "node_modules/ws": {
22
+ "version": "7.5.9",
23
+ "license": "MIT",
24
+ "engines": {
25
+ "node": ">=8.3.0"
26
+ },
27
+ "peerDependencies": {
28
+ "bufferutil": "^4.0.1",
29
+ "utf-8-validate": "^5.0.2"
30
+ },
31
+ "peerDependenciesMeta": {
32
+ "bufferutil": {
33
+ "optional": true
34
+ },
35
+ "utf-8-validate": {
36
+ "optional": true
37
+ }
38
+ }
39
+ }
40
+ }
41
+ }
@@ -1,4 +1,4 @@
1
- Copyright (c) 2017 Andrea Cardaci <cyrus.and@gmail.com>
1
+ Copyright (c) 2021 Andrea Cardaci <cyrus.and@gmail.com>
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of
4
4
  this software and associated documentation files (the "Software"), to deal in