I am using a WebAssembly based software that uses multi-threading that requires SharedArrayBuffer. It runs fine both in Chromium local/deployed, and Firefox 89 deployed, but since the best performance is under Firefox, I want to test and tune it on my machine, so I run python -m SimpleHTTPServer. In this situation, when I open 127.0.0.1:8000 or 0.0.0.0:8000 in Firefox, SharedArrayBuffer is undefined. Perhaps this is a security setting, but when using localhost, I'm really not interested in Firefox's interpretation of the situation -- this should just run. How can I make it work? Do I need a different web server, different settings?
As you guessed correctly, it has to do with security restrictions. There have been changes in regards to the use of SharedArrayBuffer that have already been implemented in Firefox 79 and will land in Chrome shortly as well (starting with Chrome 92). (Time of writing this: July 13, 2021.)
The main purpose is to restrict the use of SharedArrayBuffers in postMessage. Any such attempt will throw an error unless certain restrictive COOP/COEP headers are set to prevent cross-origin attacks:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Unfortunately, without these headers, there is also no global SharedArrayBuffer constructor. Apparently, this restriction may be lifted in the future. The objects themselves still work though (only passing them through postMessage would throw), but you need a different way to instantiate them. You can use WebAssembly.Memory instead:
const memory = new WebAssembly.Memory({ initial: 10, maximum: 100, shared: true })
// memory.buffer is instanceof SharedMemoryBuffer
You could now go one step further and recover the constructor from that. Therefore, with the following code as "shim", your existing code should work as long as it doesn't try to pass the buffer through postMessage:
if (typeof SharedArrayBuffer === 'undefined') {
const dummyMemory = new WebAssembly.Memory({ initial: 0, maximum: 0, shared: true })
globalThis.SharedArrayBuffer = dummyMemory.buffer.constructor
}
// Now, `new SharedArrayBuffer(1024)` works again
Further reading:
Article about this change on MDN
Google blog post about the upcoming change
WebAssembly.Memory documentation
As #CherryDT pointed out in the comment, the problem is missing headers for the local server. Searching the net, there is a blog that walks through the process of developing WebAssembly in Firefox with a python web server. Instead of python -m SimpleHTTPServer, one has to add a file ./wasm-server.py with this contents (for Python 2):
# Python 2
import SimpleHTTPServer
import SocketServer
class WasmHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def end_headers(self):
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self)
# Python 3.7.5 adds in the WebAssembly Media Type. Version 2.x doesn't
# have this so add it in.
WasmHandler.extensions_map['.wasm'] = 'application/wasm'
if __name__ == '__main__':
PORT = 8080
httpd = SocketServer.TCPServer(("", PORT), WasmHandler)
print("Listening on port {}. Press Ctrl+C to stop.".format(PORT))
httpd.serve_forever()
then it is possible to test the application at 127.0.0.1:8080
Related
Edit: While I still do not understand the differences between the session and webFrame cache, webFrame.clearCache() can simply be called from the within the preload script.
Problem
I have an Electron application which involves renaming and reordering images on the local filesystem. This often results in files swapping their filenames which causes caching issues that are not resolved until the window is reloaded. I am unable to clear or disable the cache.
Methods that work (unsatisfactory)
Calling require("electron").webFrame.clearCache(); from within the renderer process. This is not a satisfactory solution as it requires nodeIntegration to be enabled. (The WebFrameMain class available to the main process does not have a clearCache method).
Checking "Disable cache" from Chrome DevTools. Obviously this is not a solution for production.
Methods that don't work
Clearing the session cache. I noted that the session cache size was always 0.
mainWindow.webContents.session.clearCache();
Clearing the session storage data.
mainWindow.webContents.session.clearStorageData();
Adding the following command line switches to the main process.
app.commandLine.appendSwitch("disk-cache-size", "0");
app.commandLine.appendSwitch("disable-http-cache");
Providing a session object with cache disabled when creating the window.
webPreferences: {
preload: path.join(__dirname, "preload.js"),
session: session.fromPartition("example", { cache: false })
}
There are clearly components to the caching system I do not understand. It seems that the session cache and webFrame cache must be two different things, and I can not find a way to access the later from the main process or without nodeIntegration.
A minimal project which shows this issue can be found here: https://github.com/jacob-c-bickel/electron-clear-cache-test. Clicking the button swaps the filenames of the two images, however no visible change occurs until the window is reloaded.
I am using Electron 13.1.4 and Windows 10 2004.
You can create a function to clearCache with require("electron").webFrame.clearCache(); and attach it to the windows object in your preLoad script, then use that in your isolated renderer.
Google "electron preload"
Yeah – webFrame is meant to be used inside the browser, so that's usually going to mean preload.js. You then can use Electron's Inter-Process Communication (IPC) techniques to expose that method globally on the window object, allowing use elsewhere in your app!
It's like you're carving out a path through each level of your app for access to the right functions.
Altogether, that will look like this:
preload.js:
import { contextBridge, webFrame } from 'electron';
export const RendererApi = {
clearCache() {
webFrame.clearCache()
},
};
contextBridge.exposeInMainWorld("api", RendererApi);
And then anywhere inside your rendering process:
window.api.clearCache();
I am trying to load an mp3 files (according to the examples) but I am getting
Unable to load bg.mp3.
The request status was: 0 ()
The error stack trace includes: loadSound
I have referenced my problem to this Github issue https://github.com/processing/p5.js-sound/issues/141 but I am unable to find a solution.
Also, I am using Brackets editor which starts a local server and opens a new Chrome instance.
let mySound;
function preload() {
soundFormats('mp3', 'ogg');
mySound = loadSound("bg.mp3");
}
function setup(){
createCanvas(displayWidth,displayHeight);
mySound.setVolume(0.1);
mySound.play();
}
Strange, the Sound: Load and Play Sound example seems to work fine.
The error seems to point to on an XHR load error, but it's unclear why.
It's worth trying the full version of loadSound() including the error callback:loadSound(path, [successCallback], [errorCallback], [whileLoading]).
Hopefully the errorCallback details will help solve the problem
e.g.
let mySound;
function onSoundLoadSuccess(e){
console.log("load sound success",e);
}
function onSoundLoadError(e){
console.log("load sound error",e);
}
function onSoundLoadProgress(e){
console.log("load sound progress",e);
}
function preload() {
soundFormats('mp3', 'ogg');
mySound = loadSound("bg.mp3",onSoundLoadSuccess,onSoundLoadError,onSoundLoadProgress);
}
function setup(){
createCanvas(displayWidth,displayHeight);
mySound.setVolume(0.1);
mySound.play();
}
Also try to navigate to the web server Brackets launches and access the file manually.
(e.g. http://localhost:BRACKETS_HTTP_PORT_HERE/bg.mp3). If everything is ok (bg.mp3 is in the same folder as the index.html file), your browser should load and display the default audio playback controls.
It's worth noting there are many other http servers you could try, here a few examples:
if you're on OSX you can use Python's HTTP Server (python -m SimpleHTTPServer in python 2 or python -m http.server)
if you use node.js there' an http-server module (e.g. npm install http-server then http-server in your project folder)
Apache variants (depending on OS, MAMP/WAMP/XAMPP, etc.), though might be overkill
The quick fix for anyone having this issue is to use a Local web server. (mamp/xamp/local etc). Then reference it in the preload/setup
sound = loadSound('http://localhost/audio.mp3', loaded);
The documentation does state -
you will need the p5.sound library and a running local server
Is there any way to dynamically change the proxy being used by Firefox when using selenium webdriver?
Currently I have proxy support using a proxy profile but is there a way to change the proxy when the browser is alive and running?
My current code:
proxy = Proxy({
'proxyType': 'MANUAL',
'httpProxy': proxy_ip,
'ftpProxy': proxy_ip,
'sslProxy': proxy_ip,
'noProxy': '' # set this value as desired
})
browser = webdriver.Firefox(proxy=proxy)
Thanks in advance.
This is a slightly old question.
But it is actually possible to change the proxies dynamically thru a "hacky way"
I am going to use Selenium JS with Firefox but you can follow thru in the language you want.
Step 1: Visiting "about:config"
driver.get("about:config");
Step 2 : Run script that changes proxy
var setupScript=`var prefs = Components.classes["#mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
prefs.setIntPref("network.proxy.type", 1);
prefs.setCharPref("network.proxy.http", "${proxyUsed.host}");
prefs.setIntPref("network.proxy.http_port", "${proxyUsed.port}");
prefs.setCharPref("network.proxy.ssl", "${proxyUsed.host}");
prefs.setIntPref("network.proxy.ssl_port", "${proxyUsed.port}");
prefs.setCharPref("network.proxy.ftp", "${proxyUsed.host}");
prefs.setIntPref("network.proxy.ftp_port", "${proxyUsed.port}");
`;
//running script below
driver.executeScript(setupScript);
//sleep for 1 sec
driver.sleep(1000);
Where use ${abcd} is where you put your variables, in the above example I am using ES6 which handles concatenation as shown, you can use other concatenation methods of your choice , depending on your language.
Step 3: : Visit your site
driver.get("http://whatismyip.com");
Explanation:the above code takes advantage of Firefox's API to change the preferences using JavaScript code.
As far as I know there are only two ways to change the proxy setting, one via a profile (which you are using) and the other using the capabilities of a driver when you instantiate it as per here. Sadly neither of these methods do what you want as they both happen before as you create your driver.
I have to ask, why is it you want to change your proxy settings? The only solution I can easily think of is to point firefox to a proxy that you can change at runtime. I am not sure but that might be possible with browsermob-proxy.
One possible solution is to close the webdriver instance and create it again after each operation by passing a new configuration in the browser profile
Have a try selenium-wire, It can even override header field
from seleniumwire import webdriver
options = {
'proxy': {
"http": "http://" + IP_PORT,
"https": "http://" + IP_PORT,
'custom_authorization':AUTH
},
'connection_keep_alive': True,
'connection_timeout': 30,
'verify_ssl': False
}
# Create a new instance of the Firefox driver
driver = webdriver.Firefox(seleniumwire_options=options)
driver.header_overrides = {
'Proxy-Authorization': AUTH
}
# Go to the Google home page
driver.get("http://whatismyip.com")
driver.close()
Is it possible to programmatically change settings on a Netgear wireless router using C#? I have settings that I change often and I would like to create my own interface for making those changes. Currently I navigate to the admin web page (10.0.0.1) and it prompts me for a username and password. After I authenticate I can use the web interface to change the router's configuration.
If this isn't possible with Netgear, do any outher wireless routers have an API for developers?
There aren't any APIs out there to do this, but you can write something to make HTTP requests to the router to simulate the webUI being used.
I'm guessing most consumer routers are probably pretty simple to talk to. Authentication is probably nothing more than basic realm.
Selenium offers a firefox plugin that lets you record manual interactions with your browser. And then you can export the steps to python, ruby, java or c#. It worked for me to programmatically adjust my router settings to turn off wifi. Clicking on the elements while recording identifies everything you need.
This code works on an Actiontec MI424WR (FIOS)
Edit the code to add your username, password, and router address.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re
class Routr(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://routerip_or_address"
self.verificationErrors = []
self.accept_next_alert = True
def test_routr(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_name("user_name").clear()
driver.find_element_by_name("user_name").send_keys("your_username")
driver.find_element_by_id("pass2").clear()
driver.find_element_by_id("pass2").send_keys("enter_your_password_here")
driver.find_element_by_link_text("OK").click()
driver.find_element_by_link_text("Change Wireless Settings").click()
driver.find_element_by_id("ws_off").click()
driver.find_element_by_link_text("Apply").click()
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException, e: return False
return True
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException, e: return False
return True
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()
If this is just a few things you want to change programmatically, simulating HTTP requests should be simple enough. Another option would be to install DD-WRT in your router, basically transforming it into a small Linux installation that allows full programmatic configuration through SSH using standard Linux commands.
I'm unaware of any consumer-grade routers that have an API like that, but you could always build something that (ab)uses the Web interface to do what you want, using something like selenium-rc or watir
MiktoTik sells customer grade routers that allow ssh configuration (mind that they use ssh, but not bash inside ssh). You can even roll your own PHP REST API for router (not that I like PHP, but people are doing it).
I'm not familiar with this router, but I have done similar stuff programmatically via a telnet connection the router with Python.
There's a cood telnet lib for C#:
http://www.codeproject.com/KB/IP/MinimalisticTelnet.aspx
There is a python based Github repo here that describes a SOAP based API. I've used it to program a device schedule for my kids devices. Not willing to pay Disney for Circle. Works great. There's also a js version here.
I know this is possible via a simple registry change to accomplish this as long as IE/firefox is being used. However, I am wondering if there is a reliable way to do so for other browsers,
I am specifically looking for a way to do this via an installer, so editing a preference inside a specific browser will not cut it.
Here is the best I can come up with:
IE: http://msdn.microsoft.com/en-us/library/aa767914(VS.85).aspx
FireFox: http://kb.mozillazine.org/Register_protocol
Chrome: Since every other browser in seems to support the same convention, I created a bug for chrome.
Opera: I can't find any documentation, but it appears to follow the same method as IE/Firefox (see above links)
Safari: Same thing as opera, it works, but I can't find any documentation on it
Yes. Here is how to do it with FireFox:
http://kb.mozillazine.org/Register_protocol
and Opera:
http://www.opera.com/support/kb/view/535/
If someone looks like a solution for an intranet web site (for all browsers, not only IE), that contains hyperlinks to a shared server folders (like in my case) this is a possible solution:
register protocol (URI scheme) via registry (this can be done for all corporative users i suppose). For example, "myfile:" scheme. (thanks to Greg Dean's answer)
The hyperlink href attribute will then should look like
<a href='myfile:\\mysharedserver\sharedfolder\' target='_self'>Shared server</a>
Write a console application that redirects argument to windows explorer (see step 1 for example of such application)
This is piece of mine test app:
const string prefix = "myfile:";
static string ProcessInput(string s)
{
// TODO Verify and validate the input
// string as appropriate for your application.
if (s.StartsWith(prefix))
s = s.Substring(prefix.Length);
s = System.Net.WebUtility.UrlDecode(s);
Process.Start("explorer", s);
return s;
}
I think this app can be easily installed by your admins for all intranet users :)
I couldn't set up scheme setting to open such links in explorer without this separate app.