executeAndWait Javascript function and injected Javascript give error

55 views
Skip to first unread message

P5music

unread,
Oct 22, 2020, 7:26:53 AM10/22/20
to CodenameOne Discussions
In my CodenameOne app some Javascript code is injected to create a DOM, made of IFRAMES with HTML code inside.
The HTML code is correct but I am debugging in Chrome and I see that when the HTML code starts an error is detected (the error is also in the IntelliJ IDEA console):

The following text is the function that is made from the executeAndWait method:

(function(){var BASE_URL='https://www.codenameone.com/!cn1return/';function doCallback(val) {   var url = BASE_URL + encodeURIComponent(JSON.stringify(val));  if (window.cefQuery) { window.cefQuery({request:'shouldNavigate:'+url, onSuccess: function(response){}, onFailure:function(error_code, error_message) { console.log(error_message)}});}  else if (window.cn1application && window.cn1application.shouldNavigate) { window.cn1application.shouldNavigate(url) } else if (true) {window._cn1ready = window._cn1ready || []; window._cn1ready.push(function(){window.cn1application.shouldNavigate(url)});} else {window.location.href=url}} var result = {value:null, type:null, errorMessage:null, errorCode:0, callbackId:3};var callback = {  onSucess: function(val) { this.onSuccess(val);},   onSuccess: function(val) { result.value = val; result.type = typeof(val); if (val !== null && typeof val === 'object') {result.value = val.toString();} doCallback(result);},   onError: function(message, code) { if (message instanceof Error) {result.errorMessage = message.message; result.errorCode = 0;} else {result.errorMessage = message; result.errorCode = code;} doCallback(result);}};try { var div=document.createElement('DIV');div.addEventListener('mousedown', function (event) {callMouseDown(div.getAttribute("id"));});div.addEventListener('mouseup', function (event) {callMouseUp(div.getAttribute("id"));});var iframe=document.createElement("IFRAME");iframe.style.zIndex="0";iframe.style.pointerEvents="none";div.style.position="relative";div.id="0";iframe.setAttribute("scrolling","no");iframe.setAttribute("frameborder","no");iframe.setAttribute("noresize","noresize");iframe.setAttribute("height","100"); iframe.innerText="FALLBACK";iframe.setAttribute("srcdoc","<!DOCTYPE html>

I did not paste all the function body. I stopped when the first HTML code begins for the first IFRAME and the error is there.
As you can see in the attached image the red error starts at the comma (Uncaught SyntaxError: Invalid or unexpected token).

(The HTML code is a text with other quotes inside as it is in normal HTML but it is correctly escaped)

Can you help me? Do you see something? Could this be caused by the calling function?
Thanks in advance
Regards
2020-10-22 13-19-35.png

Steve Hannah

unread,
Oct 22, 2020, 7:46:25 AM10/22/20
to codenameone...@googlegroups.com
Perhaps it doesn't like the doctype tag.  Try splitting it up.  E.g.  

iframe.setAttribute('srcdoc', '<'+'!DOCTYPE html>...');

--
You received this message because you are subscribed to the Google Groups "CodenameOne Discussions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to codenameone-discu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/codenameone-discussions/42678b68-78f9-40fa-adb1-7f4740b9796fn%40googlegroups.com.


--
Steve Hannah
Software Developer
Codename One

P5music

unread,
Oct 22, 2020, 8:36:49 AM10/22/20
to CodenameOne Discussions
Hello,
The injected HTML is not under my control, it is a string. If it doesn't like '<!DOCTYPE as a single string, it also could be not liking other things.
In the provided code above it seems that it is written that way but it is a string
created this way:
" ... iframe.setAttribute(\"srcdoc\",\""+htmlText+"\");"
Also, as you can see double-quotes " have been replaced by single quotes ' by the executeAndWait method.

Steve Hannah

unread,
Oct 22, 2020, 8:50:54 AM10/22/20
to codenameone...@googlegroups.com
I see.  It isn't the DOCTYPE it has complaining about. It is that you are placing raw text.  You can't have new lines.

If you want to inject arbitrary strings you should use the execute(String js, Object[] params) variant:

E.g.  myBrowserComponent.execute("...iframe.setAttribute('srcdoc', ${0});...", new Object[]{htmlText});

That will properly encode the htmlText (e.g. escaping new lines and other problematic characters).

P5music

unread,
Oct 22, 2020, 9:10:44 AM10/22/20
to CodenameOne Discussions
I need the "wait" part too, is it possible to properly encode the raw text with a method? 
So I can keep using the executeAndWait variant?

Steve Hannah

unread,
Oct 22, 2020, 9:18:52 AM10/22/20
to codenameone...@googlegroups.com
There is an executeAndWait() variant that takes parameters.  

There are many variants listed in the javadocs.  One for every occasion.

P5music

unread,
Oct 22, 2020, 10:08:31 AM10/22/20
to CodenameOne Discussions
This variant seems to be encoding all text.
[1022/154808.805601:INFO:CONSOLE(1)] "Uncaught SyntaxError: Invalid or unexpected token", source: var%20div%3Ddocument.createelement%28%27div%27%29%3Bdiv.addeventlistener%28%27mouse.....

This just a snippet of what is being done. I think that the HTML was encoded, including the surrounding Javascript (I see it in Chrome debug console).
What's wrong?

Steve Hannah

unread,
Oct 22, 2020, 10:20:50 AM10/22/20
to codenameone...@googlegroups.com
Did you already pass that string through your own encoding/escaping?  If so, you may have some double-encoding going on.

P5music

unread,
Oct 22, 2020, 10:29:10 AM10/22/20
to CodenameOne Discussions
I am testing the two variants.

If I use the original variant executeAndWait I get what is the original error of this thread.

If I use the execute variant I get the new error and apparent double encoding.

I am not applying any encoding. I just escape the quotes (in both cases):
String htmlText=originalHtml.replace("\"","\\\"");
It has be done because I have to inject the HTML into the srcdoc attribute of the IFRAMEs.

Steve Hannah

unread,
Oct 22, 2020, 10:31:11 AM10/22/20
to codenameone...@googlegroups.com
Don't escape the quotes.  

P5music

unread,
Oct 22, 2020, 11:34:12 AM10/22/20
to CodenameOne Discussions
I tried your suggestion but it does not work, as expected if you consider that what is going to be executed is something that has quotes inside quotes, like
setAttribute("srcdoc","<HTML><div style="some styling here" ></DIV></HTML>");

that line is injected so it has to be
"setAttribute(\"srcdoc\",\"<HTML><div style="some styling here" ></DIV></HTML>\");"
This is what goes inside the function, 

but in the log you can see for example:

iframe.setAttribute("srcdoc","<!DOCTYPE html><html><head></head><body><p style="vertical-align:middle;font-size:2em;" >.............
when deep quotes are not escaped how you suggested.

While just applying the escaping of double quotes I get in the log
var%20div%3Ddocument.createelement%28%27div%27%29%3Bdiv.addeventlistener%28%27mouse

the error seems to be anticipated because that string continues and reaches to (the same code position even it belongs to a different IFRAME):
iframe.setattribute%28%22srcdoc%22%2C%22%3C%21doctype%20html%3E%3Chtml%3E%3Chead%3E%3Clink%20href%3D%5C%22https://
that is clearly different
and this change happens just if I escape instead of not escaping as you suggested.

Steve Hannah

unread,
Oct 22, 2020, 11:52:47 AM10/22/20
to codenameone...@googlegroups.com
Create a self-contained test cast and file an issue in the issue tracker.

P5music

unread,
Oct 22, 2020, 3:34:28 PM10/22/20
to CodenameOne Discussions
Before I file the issue, can you inspect the self-contained test case I created (see the attachment)? And please tell me what's the issue to be filed?
The results are the following:

Escaping double quotes in the IFRAME HTML text
execute
[1022/211419.412220:INFO:CONSOLE(1)] "Uncaught SyntaxError: Invalid or unexpected token", source: var%20iframe%3Ddocument.createelement%28%22iframe%22%29%3Biframe.setattribute%28%22srcdoc%22%2C%22%3C%21doctype%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3Cp%20style%3D%5C%22vertical-align:middle;font-size:2em;\" ><img style=\"vertical-align:middle;height:50px;\" src=\"https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/ios10-weather-app-icon.png\" />Meteo</p></body></html>"); (1)

executeAndWait
[1022/211610.194334:INFO:CONSOLE(1)] "Uncaught SyntaxError: Invalid or unexpected token", source: %28function%28%29%7Bvar%20base%5Furl%3D%27https://www.codenameone.com/!cn1return/';function doCallback(val) {   var url = BASE_URL + encodeURIComponent(JSON.stringify(val));  if (window.cefQuery) { window.cefQuery({request:'shouldNavigate:'+url, onSuccess: function(response){}, onFailure:function(error_code, error_message) { console.log(error_message)}});}  else if (window.cn1application && window.cn1application.shouldNavigate) { window.cn1application.shouldNavigate(url) } else if (true) {window._cn1ready = window._cn1ready || []; window._cn1ready.push(function(){window.cn1application.shouldNavigate(url)});} else {window.location.href=url}} var result = {value:null, type:null, errorMessage:null, errorCode:0, callbackId:0};var callback = {  onSucess: function(val) { this.onSuccess(val);},   onSuccess: function(val) { result.value = val; result.type = typeof(val); if (val !== null && typeof val === 'object') {result.value = val.toString();} doCallback(result);},   onError: function(message, code) { if (message instanceof Error) {result.errorMessage = message.message; result.errorCode = 0;} else {result.errorMessage = message; result.errorCode = code;} doCallback(result);}};try { var iframe=document.createElement("IFRAME");iframe.setAttribute("srcdoc","<!DOCTYPE html><html><head></head><body><p style=\"vertical-align:middle;font-size:2em;\" ><img style=\"vertical-align:middle;height:50px;\" src=\"https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/ios10-weather-app-icon.png\" />Meteo</p></body></html>");} catch (e) {try {callback.onError(e.message, 0);} catch (e2) {callback.onError('Unknown error', 0);}}})(); (1)

Without escaping double quotes in the IFRAME HTML text
execute
[1022/212307.710510:INFO:CONSOLE(1)] "Uncaught SyntaxError: Invalid or unexpected token", source: var%20iframe%3Ddocument.createelement%28%22iframe%22%29%3Biframe.setattribute%28%22srcdoc%22%2C%22%3C%21doctype%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3Cp%20style%3D%22vertical-align:middle;font-size:2em;" ><img style="vertical-align:middle;height:50px;" src="https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/ios10-weather-app-icon.png" />Meteo</p></body></html>"); (1)

executeAndWait
[1022/212214.198521:INFO:CONSOLE(1)] "Uncaught SyntaxError: Invalid or unexpected token", source: %28function%28%29%7Bvar%20base%5Furl%3D%27https://www.codenameone.com/!cn1return/';function doCallback(val) {   var url = BASE_URL + encodeURIComponent(JSON.stringify(val));  if (window.cefQuery) { window.cefQuery({request:'shouldNavigate:'+url, onSuccess: function(response){}, onFailure:function(error_code, error_message) { console.log(error_message)}});}  else if (window.cn1application && window.cn1application.shouldNavigate) { window.cn1application.shouldNavigate(url) } else if (true) {window._cn1ready = window._cn1ready || []; window._cn1ready.push(function(){window.cn1application.shouldNavigate(url)});} else {window.location.href=url}} var result = {value:null, type:null, errorMessage:null, errorCode:0, callbackId:1};var callback = {  onSucess: function(val) { this.onSuccess(val);},   onSuccess: function(val) { result.value = val; result.type = typeof(val); if (val !== null && typeof val === 'object') {result.value = val.toString();} doCallback(result);},   onError: function(message, code) { if (message instanceof Error) {result.errorMessage = message.message; result.errorCode = 0;} else {result.errorMessage = message; result.errorCode = code;} doCallback(result);}};try { var iframe=document.createElement("IFRAME");iframe.setAttribute("srcdoc","<!DOCTYPE html><html><head></head><body><p style="vertical-align:middle;font-size:2em;" ><img style="vertical-align:middle;height:50px;" src="https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/ios10-weather-app-icon.png" />Meteo</p></body></html>");} catch (e) {try {callback.onError(e.message, 0);} catch (e2) {callback.onError('Unknown error', 0);}}})(); (1)


MyApplication.java

Steve Hannah

unread,
Oct 22, 2020, 4:35:23 PM10/22/20
to codenameone...@googlegroups.com
That won't work.

Javascript, like Java, doesn't support multi-line string literals (at least using quotes).  Look at the JS you construct that includes your HTML.  You're escaping the quotes but not the new-lines.  The JS isn't valid.  If you use the execute(..., params) version, it will take care of this for you, but, you shouldn't include javascript code as parameters in execute(..., params).  Parameters should be strings, booleans, or numbers that you wish to have converted to Javascript equivalents.  That is likely why your attempts with execute(..., params) failed, because you were placing the entirety of your javascript code as a parameter.



Reply all
Reply to author
Forward
0 new messages