opal 1.6.1 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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