Why does ExternalInterface breaks when I pass parameter with JSON like string? - javascript

I have a very odd problem with Flash 10 and ExternalInterface. I am currently using a homemade bridge to use RTMFP with Javascript and whenever I try to pass data that contains JSON, I get a wierd Javascript error that comes from Flash :
missing ) after argument list
try { __flash__toXML(Flash.Utilities.A..."")) ; } catch (e) { "<undefined/>"; }
It's impossible to get more information since this come from Flash and it's not bound to any Javascript file.
To reproduce this problem you can use this script :
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.external.ExternalInterface;
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
var test:String;
test = "\"\\\"\"";
ExternalInterface.call("console.log", test);
}
}
}
What can I do to avoid this problem and is it a known problem ?

This is apparently a known issue and it doesn't seems like Adobe is going to fix it anytime soon.
I found a detailled explaination of this problem and basicly the issue seems to be that Flash doesn't handle the \ and the & properly which can lead to javascript error or data corruption during the transfer from Flash to javascript.
What Flash attempts to do when you transfer data from Flash to JS is to execute the following thing :
try {
__flash__toXML(yourJavascriptFunction("[DATA]")) ;
} catch (e) { "<undefined/>"; }
The problem is that it puts your data raw and it doesn't escape the backslash at all. If your string contains only \ and you want to call console.log on it, it will try to do the following thing :
try {
__flash__toXML(console.log("\")) ;
} catch (e) { "<undefined/>"; }
As you can see this is invalid javascript. It will throws an error in your Javascript console and it will never call console.log.
The solution is to either ducktape Flash behavior or do some nasty hack to get around it.
To ducktape Flash buggyness you can escape the blackslash before you transfer them. This solution will work for now, but when Flash will fix it (most probably not in a near future, if you consider that this bug is known for more than 4 years), it will break your application.
The other possibility is to url encode the character that Flash doesn't handle well (\, ", &) and to decode them on the other side.
Flash :
data = data.split("%").join("%25")
.split("\\").join("%5c")
.split("\"").join("%22")
.split("&").join("%26");
Javascript :
data = data.replace(/%22/g, "\"")
.replace(/%5c/g, "\\")
.replace(/%26/g, "&")
.replace(/%25/g, "%");
It's ugly, but it works.

Admittedly this wouldn't work directly for output to the console in Firebug, but for most other applications (i.e. sending a potentially 'invalid' string to Javascript), escape and unescape should work just fine:
AS3:
var testString:String = "\"\\\"\"";
ExternalInterface.call("showString", escape(testString));
And then in Javascript:
function showString(msg) {
console.log(unescape(msg));
document.getElementById('messagebox').innerHTML = unescape(msg);
}
<div id="messagebox"></div>

Related

Swift JavaScriptCore not working with large files?

https://github.com/gg2001/monero/blob/master/monero/NewWallet.js
I have a js file that is quite large 6000 lines and JavaScript core does not seem to be able to retrieve variable values whereas running the same file in any web browser works fine for me. When I try to retrieve the value of a variable it shows up as undefined, but when I use a js console in a browswer it shows up fine. I am speculating that this is due to the size of the file because when I put
var helloWorld = "Hello World";
in the front of the js file this swift code can retrieve it
func helloWorld() {
if let variableHelloWorld = self.jsContext.objectForKeyedSubscript("helloWorld") {
print(variableHelloWorld.toString())
}
}
but when I put it at the end it cannot.
Normally this indicates a parsing error. Try adding an error handler to self.jsContext before calling objectForKeyedSubscript() and see if it outputs anything insightful.
self.jsContext.exceptionHandler = { context, exception in
print("JS Error: \(exception?.description ?? "unknown error")")
}
Although your JS code may be valid in a browser console, iOS Safari doesn't support as many Javascript features as newer browsers.
I did see a line in your JS source code beginning with just a semicolon (followed immediately by (function). I wonder if the parser might complain about an empty line without a statement..? Maybe nothing, though.

Getting JavaScript runtime error: irrationalPath, what does it mean?

In my MasterPage i'm using the following script
<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=3.3"></script>
And in my application, i have this peace of JavaScript code
document.getElementById(menu_number).src = "<%=HttpContext.Current.Request.ApplicationPath%>/UI/Common/Images/down-arrow.gif";
I also have the Application_AcquireRequestState method below
public void Application_AcquireRequestState(object sender, EventArgs e)
{
// Get http context from the caller.
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
// Check for encrypted query string
string encryptedQueryString = context.Request.QueryString["request"];
try
{
if (!string.IsNullOrEmpty(encryptedQueryString))
{
// Decrypt query strings
string cryptoKey = System.Web.HttpContext.Current.Session["CryptoKey" + System.Web.HttpContext.Current.Session["UNIQUEKEY"]] == null ? HttpContext.Current.Application["CryptoKey"].ToString() : System.Web.HttpContext.Current.Session["CryptoKey" + System.Web.HttpContext.Current.Session["UNIQUEKEY"]].ToString();
string decryptedQueryString = CryptoQueryStringHandler.DecryptQueryStrings(encryptedQueryString, cryptoKey);
context.Server.Transfer(context.Request.AppRelativeCurrentExecutionFilePath + "?" + decryptedQueryString);
}
}
catch (Exception ex)
{
}
}
When document.getElementById(menu_number).src = "<%=HttpContext.Current.Request.ApplicationPath%>/UI/Common/Images/down-arrow.gif"; is being executed, it throws the below error in IE 11.
JavaScript runtime error: irrationalPath
It also throws an exception in method "Application_AcquireRequestState" but i'm not able to get the exception details. When i put a try -- catch in the method "Application_AcquireRequestState", the exception inner message being returned is
Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.
I'm finding it hard to debug this. The above line of JavaScript executes successfully on the initial page load but throws that error when i'm clicking particular hyperlinks after page load.
What could be the most likely causes of JavaScript error: irrationalPath?
And what does "Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack." actually mean?
Any suggestions on how i can effectively troubleshot this?
I have already seen observed that the IrrationalPath exception is defined in the javascript file at http://serverapi.arcgisonline.com/jsapi/arcgis/?v=3.3
The most likely cause of the JavaScript error: irrationalPath error probably has nothing to do with any of the code you posted in the question. It's a dojo error that is usually seen when there's a problem with the dojo loader. It probably has something to do with the paths or pacakges setup in dojoConfig. See here for more info.
The other error you are getting is a .NET error. I can't be certain without seeing more of your code but this Microsoft support article is a good starting place for troubleshooting that erroor
Have you tried to make the HttpContext.Current.Request.ApplicationPath as String in your js code (delimited with two quotes).
js code become :
document.getElementById(menu_number).src = <%="'"+HttpContext.Current.Request.ApplicationPath+"'"%>+"/UI/Common/Images/down-arrow.gif";

Disable JavaScript Alerts GeckoFX C#

I'm trying to disable JavaScript alert in GeckoFX-33 + xulrunner 33 ( winforms c# ) but I can't find a solution. I check the example codes, source code but I just can't find something that blocks the alert out. I searched in about:config as well without success.
Anybody knows where I could find a reference at last ?
In prior versions, you could do
webBrowser.JavascriptError += (sender, error) => {
// do something
}
However according to issue 7 on geckofx 33, there's some work that needs to be done to support the new debugging interface:
the geckofx service jsdIDebuggerService was removed from firefox 33. the JavascriptError event implementation used this service. So the JavascriptError event handler needs to be reimplemented using firefox new debugging interface.
geckoWebBrowser1.JavascriptError += (sender, error) =>
{
GeckoWebBrowser browser = geckoWebBrowser1;
string text = "window.alert = function(){};";
using (AutoJSContext context = new AutoJSContext(browser.Window.JSContext))
{
string result;
//toolStripLabel1.Text = "was is loaded?";
context.EvaluateScript(text, (nsISupports)browser.Window.DomWindow, out result);
}
};
Here is the final code for Gecko 29.

Access native JSON object when JSON2 has overloaded it

I am implementing a bookmarklet which communicates with a iframe through a JSON-RPC protocol.
However some sites, such as cnn.com load JSON2 into window.JSON although the browser already has a native JSON object.
The problem is that within my iframe I would not like to follow the same bad practice, and JSON2 does not seem to be compatible with the native JSON on Mozilla Firefox and Chrome:
So when I run stringify on the native JSON and JSON2, I get the following results:
JSON.stringify({key: "value"})
JSON2
{key:"value"}
Native JSON
{"key":"value"}
(Key is wrapped in ")
The problem is that the native JSON does not like it when the " is missing in the JSON2-produced string and throws an error:
Mozilla Firefox: SyntaxError: JSON.parse: expected property name or '}'
Google Chrome: SyntaxError: Unexpected token k
To solve the problem for good, I need to make sure that I use the same JSON library to encode the string as I do for decoding it.
One way of doing it is to make sure to use JSON2 or JSON3 on both sides, but I'd like to use the native json library where possible.
So now that sites like cnn.com have overriden the native JSON library, how can I get back to it?
I could perhaps create an iframe that points to the same domain and fetch the JSON object from its contentWindow, but that would be highly inefficient.
Isn't there a better way?
not sure if i understand your problem correctly
if you place an empty iframe like this
<iframe id="testFrame" name="testFrame" src="about:blank" style="display:none;"></iframe>
then you can also call from js
testFrame.JSON.stringify(obj);
the only problem is that if you use it in https: src could be javascript:false if you need to support IE6
EDIT: I still think i don't deserve the answer being accepted, so i've come up with a modified version of your code
(function($) {
var frm;
$.getNative = function(objectName, callback) {
if (!frm) {
frm= $("<iframe>", {
src: "javascript:false",
style: "display:none;"
}).appendTo("body").load(function(){
callback(this.contentWindow[objectName]);
// $(this).remove(); <-- this is commented to cache the iframe
});
}
callback(frm[0].contentWindow[objectName]);
}
})(jQuery)
this will enable you to use $.getNative() multiple times in a document without recreating the frame each time.
So far the best solution is to use an iframe, but as Crisim Il Numenoreano has pointed out, it should be pointed to about:blank or javascript:false. This seems to work fine so far:
function getNative(objectName, callback) {
$("<iframe>", {
src: "javascript:false",
style: "display:none;"
}).appendTo("body").load(function(){
callback(this.contentWindow[objectName]);
$(this).remove();
});
}
//Use like this:
getNative("JSON", function(JSON) {
console.log(JSON.stringify({key: "value"}));
});
Note that for bookmarklets jquery must be fetched from reliable sources and protected within a local scope too.

ExternalInterface

Hey, so I'm having a bunch of trouble getting ExternalInterface to work, which is odd, because I use it somewhat often.
I'm hoping it's something I just missed because I've been looking at it too long.
The flash_ready function is correctly returning the objectID, and as far as I can tell, everything else is in order.
Unfortunately, when I run it, I get an error (varying by browser) telling me that basically document.getElementById(<movename>).test() is not a valid method.
Here's the code:
javascript:
function flash_ready(i){
document.getElementById(i).test('success!');
}
Embed Html (Generated):
<script type="text/javascript">
swfobject.embedSWF("/chainmaille/includes/media/flash/upload_image.swf", "/chainmaille/includes/media/flash/upload_image", "500", "50", "9.0.0","expressInstall.swf", {}, {allowScriptAccess:'always', wmode:'transparent'},{id:'uploader_flash',name:'uploader_flash'});
</script>
<object type="application/x-shockwave-flash" id="uploader_flash" name="uploader_flash" data="/chainmaille/includes/media/flash/upload_image.swf" width="500" height="50"><param name="allowScriptAccess" value="always"><param name="wmode" value="transparent"></object>
AS3 :
package com.jesseditson.uploader {
import flash.display.MovieClip;
import flash.external.ExternalInterface;
import flash.system.Security;
public class UI extends MovieClip {
// Initialization:
public function UI() {
Security.allowDomain('*');
ExternalInterface.addCallback("test", test);
var jscommand:String = "flash_ready('"+ExternalInterface.objectID+"');";
var url:URLRequest = new URLRequest("javascript:" + jscommand + " void(0);");
navigateToURL(url, "_self");
}
public function test(t){
trace(t);
}
}
}
Swfobject is being included via google code, and the flash embeds just fine, so that's not the problem.
I've got a very similar setup working on another server, but can't seem to get it working on this one. It's a Hostgator shared server. Could it be the server's fault? Anybody see any obvious syntax problems?
Thanks in advance!
The Flash isn't actually finished constructing yet. You're calling your flash_ready callback from the constructor, and so the JS is trying to call in before the object is on the stage. Move your flash_ready call to, say, an Event.ADDED_TO_STAGE listener and it should start working.
Ok, so after further investigation, it appears that there was a problem with multiple instances of the flash object, because I was cloning it to a lightbox. I have gotten it working now.
Just spent 5 hours fighting with this. It was all really frustrating. In my case the solution was very very simple and I would have never guessed it.
So first of for all of you who have never seen the flash player debugger running on files inside your browser finding this link that walks you through the setup has resulted in a somewhat magical experience :)
Now to my ExternalInterface discovery: There was a sandbox violation inside the same domain. This meant that flash cannot access www.yourdomain.com from yourdomain.com. The weird thing of course is that you are not explicitly calling the domain with ExternalInterface.
Anyhow, the solution was very simple: add this to my .htaccess file and that was it!
# Redirect non-www to www
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule (.*) http://www.youtdomain.com/$1 [R=301,L]
Hope this helps someone
Is flash_ready receiving the objectID that you are expecting?
Also, why use:
var jscommand:String = "flash_ready('"+ExternalInterface.objectID+"');";
var url:URLRequest = new URLRequest("javascript:" + jscommand + " void(0);");
navigateToURL(url, "_self");
When this is designed to do that:
ExternalInterface.call("flash_ready", ExternalInterface.objectID);
Post your source (pre-generatred). When your browser says [Flash].Method is not a function, 99% of the time it means that you tried calling a function in Flash before the .swf was ready for it. I see that you tried to do that, but clearly its not working so something must be off. So post your pre-rendered source and I am sure we can find the problem.

Categories

Resources