This question already has answers here:
Why split the <script> tag when writing it with document.write()?
(5 answers)
Closed 8 years ago.
What exactly needs to be escaped in javascript strings. Or, more specifically, why does
var snaphtml = '<script src="http://seadragon.com/embed/lxe.js?width=auto&height=400px"></script>';
give a syntax error? Escaping the final <\/script> seems to fix the syntax error, but this doesn't make sense to me as a javascript beginner.
The problem may be that the web browser sees the "</script>" sequence and decides that's the end of the script block.
Another way to fix the problem aside from using an escape sequence like you did is to break it apart into 2 strings that are concatenated:
"<" + "/script>"
The behavior you're seeing isn't a bug n the part of the browser.
Browsers don't "look inside" a script block, they just pass the content to the script engine. The "</script>" sequence is how they know they've come to the end of the block, and since the browser doesn't interpret the contents of the block, it has no way to know that it's in the context of a literal string in the script code.
Remember that browsers can support more script languages than just Javascript, even if it's not commonly seen. Internet Explorer supports VBscript (and I think any scripting language that can be run by a windows script host, but I'm not sure about that). And when the ability to have script blocks was put into browsers way back when, no one could be sure that Javascript would end up being so universal.
You're actually running into an html-escaping issue: the browser interprets </script> in your string as the close-tag for the script element in which your javascript is embedded -- so to the browser, your line looks like it's missing the close single-quote:
var snaphtml = '<script src="http://seadragon.com/embed/lxe.js?width=auto&height=400px">
To fix it, as you've found, you just need to change </script> to anything else, like <\/script> or \074/script>, etc.
The only characters you normally need to worry about in a javascript string are double-quote (if you're quoting the string with a double-quote), single-quote (if you're quoting the string with a single-quote), backslash, carriage-return (\r), or linefeed (\n).
The HTML parser will interpret the end of tag token (ETAGO delimiter </) in your string, as the end of the current script tag, giving you the unterminated string SyntaxError.
There are several workarounds, including the use of CDATA blocks, but the simplest way is to escape that character, or make a string concatenation:
var snaphtml = '<script src="...">\x3C/script>';
var snaphtml = '<script src="..."><' + '/script>';
And of course, you can also create your script element programmatically and append it to the head:
var newScript = document.createElement("script");
newScript.src = "...";
//...
See Everything you always wanted to know about </, aka. the end-tag open (ETAGO) delimiter for a detailed explanation. TL;DR there’s no need for crazy hacks like string concatenation or char literal escapes — just escape it as such:
var snaphtml = '<\/script>';
Also, note that this is only necessary for inline scripts.
Related
I am using rhino javascript engine to evaluate the json. The Json structure is as following :
{"DataName":"111","Id":"222","Date":"2015-12-31T00:00:00","TextValue":"{\"Id\":\"1\",\"Name\":\"Daugherty\",\"ContactName\":\"May C\",\"ContactEmail\":\"may.c#gamil.com\",\"Total\":25,\"Phone\":\"111-111-1111\",\"Type\":\"Daily\",\"Notes\":[{\"Comments\":\"One\",\"Date\":\"2014-11-27T00:00:00.000\"},{\"Comments\":\"Two\",\"Date\":\"2014-11-28T00:00:00.000\"}],\"ImportComplete\":true,\"RunComplete\":true,\"CompleteDate\":\"2014-07-31T00:00:00.000\",\"Amount\":2400.00,\"ProcessingComplete\":true}","NumberValue":4444.5555,"DateValue":"2014-12-01T00:00:00"}
Since I am using Rhino js engine I can't use JSON.parse and JSON.stringify.
As you can see the json has embedded json, this json I am getting from a .net web api which is putting the escape character '\'. I am trying to replace that escape character in javascript but no help.
Is there any way in javascript where we can replace that escape character and use 'eval()' to evaluate the json.
Here's the code that I am trying
var json = '{"DataName":"111","Id":"222","Date":"2015-12-31T00:00:00","TextValue":"{\"Id\":\"1\",\"Name\":\"Daugherty\",\"ContactName\":\"May C\",\"ContactEmail\":\"may.c#gamil.com\",\"Total\":25,\"Phone\":\"111-111-1111\",\"Type\":\"Daily\",\"Notes\":[{\"Comments\":\"One\",\"Date\":\"2014-11-27T00:00:00.000\"},{\"Comments\":\"Two\",\"Date\":\"2014-11-28T00:00:00.000\"}],\"ImportComplete\":true,\"RunComplete\":true,\"CompleteDate\":\"2014-07-31T00:00:00.000\",\"Amount\":2400.00,\"ProcessingComplete\":true}","NumberValue":4444.5555,"DateValue":"2014-12-01T00:00:00"}';
var find = '\"';
var regex = new RegExp(find,'g');
var inj = json.replace(regex,'"');
var pl = eval('(' + inj +')');
confusing backslashes
The problem you are getting is due to the fact of not fully understanding escape characters, when you are more than one level of "string" deep. Whilst a single slash is fine for one level i.e:
"It is no coincidence that in no known language does the " +
"phrase \"As pretty as an Airport\" appear.";
If you take that and then wrap it in outer quotes:
'"It is no coincidence that in no known language does the "' +
'"phrase \"As pretty as an Airport\" appear."';
The backslashes (if supported as escape characters by the system parsing the string) work for the outer-most wrapping quote, not any of the inner quotes/strings as they were before. This means once the js engine has parsed the string, internally the string will be.
'"It is no coincidence that in no known language does the phrase "As pretty as an Airport" appear."';
Which makes it impossible to tell the difference between the " and the \" from the original string. In order to get around this, you need to escape the backslashes in the original string, before you wrap it. This has the result of one level of escaping being used by the JavaScript engine, but still leaving another level remaining within the string. e.g.
'"It is no coincidence that in no known language does the "' +
'"phrase \\"As pretty as an Airport\\" appear."';
Now when the string is parsed, internally it will be:
'"It is no coincidence that in no known language does the phrase \"As pretty as an Airport\" appear."';
ignore the my random Douglas Adams quotes being separated onto more than one line (using +), I've only done that for ease of reading within a fix width area. I've kept it parsable by JavaScript, just in case people copy and paste and expect things to work.
So in order to fix your issue, your JSON source (before placing in the JavaScript code) will have to look like this:
var json = '{"DataName":"111","Id":"222","Date":"2015-12-31T00:00:00","TextValue":"{\\"Id\\":\\"1\\",\\"Name\\":\\"Daugherty\\",\\"ContactName\\":\\"May C\\",\\"ContactEmail\\":\\"may.c#gamil.com\\",\\"Total\\":25,\\"Phone\\":\\"111-111-1111\\",\\"Type\\":\\"Daily\\",\\"Notes\\":[{\\"Comments\\":\\"One\\",\\"Date\\":\\"2014-11-27T00:00:00.000\\"},{\\"Comments\\":\\"Two\\",\\"Date\\":\\"2014-11-28T00:00:00.000\\"}],\\"ImportComplete\\":true,\\"RunComplete\\":true,\\"CompleteDate\\":\\"2014-07-31T00:00:00.000\\",\\"Amount\\":2400.00,\\"ProcessingComplete\\":true}","NumberValue":4444.5555,"DateValue":"2014-12-01T00:00:00"}';
You should find the above will eval directly, without any replacements.
In order to achieve the above programatically, you will have to see what the .NET system you are using offers in the way of escaping backslashes. I mainly work with PHP or Python on the server side. Using those languages you could use:
the $s and s strings below have been cropped for brevity.
<?php
$s = '{"DataName":"111","Id":"222"...';
$s = str_replace("\\", "\\\\", $s);
echo "var json = '$s';";
or ...
#!/usr/bin/env python
s = r'{"DataName":"111","Id":"222"...'
s = s.replace("\\", "\\\\")
print "var json = '" + s + "';"
another solution
It all depends on how you are requesting the content you are wrapping in the string in JavaScript. If you have the ability to write out your js from the server side (most likely with .NET). Like I have shown above with PHP or Python, you don't need to wrap the content in a string at all. You can instead just output the content without being wrapped in single quotes. JavaScript will then just parse and treat it as a literal object structure:
var jso = {"DataName":"111","Id":"222","Date":"2015-12-31T00:00:00","TextValue":"{\"Id\":\"1\",\"Name\":\"Daugherty\",\"ContactName\":\"May C\",\"ContactEmail\":\"may.c#gamil.com\",\"Total\":25,\"Phone\":\"111-111-1111\",\"Type\":\"Daily\",\"Notes\":[{\"Comments\":\"One\",\"Date\":\"2014-11-27T00:00:00.000\"},{\"Comments\":\"Two\",\"Date\":\"2014-11-28T00:00:00.000\"}],\"ImportComplete\":true,\"RunComplete\":true,\"CompleteDate\":\"2014-07-31T00:00:00.000\",\"Amount\":2400.00,\"ProcessingComplete\":true}","NumberValue":4444.5555,"DateValue":"2014-12-01T00:00:00"};
This works because JSON is just a more strict version of a JavaScript Object, and the quote/escape level you already have will work fine.
The only downside to the above solution is that you have to implicitly trust the source of where you are getting this data from, and it will always have to be well formed. If not, you could introduce parse errors or unwanted js into your code; which could be avoided with an eval/JSON.parse system.
Here is a section of code used by CKEditor on my website:
CKEDITOR.config.IPS_BBCODE = {"acronym":{"id":"8","title":"Acronym","desc":"Allows you to make an acronym that will display a description when moused over","tag":"acronym","useoption":"1","example":"[acronym='Laugh Out Loud']lol[/acronym]", ...
If you scroll to the right just a little, you will see this:
"[acronym='Laugh Out Loud']lol[/acronym]"
I need to store all of the CKEditor code inside a javascript string, but I can't figure out how to do it because the string has both " and ' in it. See the problem? Furthermore, I don't think I can just escape the quotes because I tried doing that and the editor didn't work.
Any idea what I can do?
You might try taking the string and injecting JavaScript escape codes into it. JavaScript can essentially use any unicode value when using the format: \u#### - so, for a ' character, the code is \u0039, and for the " character, the code is \u0034.
So - you could encode your example portion of the string as:
\u0034[acronym=\u0039Laugh Out Loud\u0039]lol[/acronym]\u0034
Alternatively, you could attempt to simply escape the quotes as in:
\"[acronym=\'Laugh Out Loud\']lol[/acronym]\"
The problem here occurs when you wind up with this kind of situation:
"data:{'prop1':'back\\slash'}"
Which, when escaped in this manner, becomes:
"data:{\'prop\':\'back\\\\slash\'}\"
While this is somewhat more readable than the first version - de-serializing it can be a little tricky when going across object-spaces, such as a javascript object being passed to a C# parser which needs to deserialize into objects, then re-serialize and come back down. Both languages use \ as their escape character, and it is possible to get funky scenarios which are brain-teasers to solve.
The advantage of the \u#### method is that only JavaScript generally uses it in a typical stack - so it is pretty easy to understand what part should be unescaped by what application piece.
hmm.. you said you already tried to escape the quotes and it gave problems.
This shouldn't give problems at all, so try this:
$newstring = addslashes($oldstring);
There's no need to use Unicode escape sequences. Just surround your string with double quotes, and put a backslash before any double quotes within the string.
var x = "\"[acronym='Laugh Out Loud']lol[/acronym]\"";
I have a UIWebView and I want to inject some HTML to the end of it after its been loaded.
NSString* javaScript = [NSString stringWithFormat:#"document.body.innerHTML += '%#'", arbitraryHTML];
[self.webView stringByEvaluatingJavaScriptFromString:javaScript];
The above code works, but only if arbitraryHTML is properly formated. E.g. the single quote ' is escaped as \'
I'd like to clean up HTML in genearl so that I can pass it to a javascript function.
What are other characters that I need to escape or strings that could cause problems?
Here's an example of some HTML that breaks the above code:
<span><a onmouseover=\\\"jQuery\\'# >Test</a></span>"
Can this be done in genearl? What else am I missing?
Thanks!
You need to make sure the JS engine does not throw up. So you need to escape single quotes and backslashes. This should do the trick:
arbitraryHTML = [[arbitraryHTML
stringByReplacingOccurrencesOfString:#"\\" withString:#"\\\\"]
stringByReplacingOccurrencesOfString:#"'" withString:#"\\'"]];
Note that you also need to escape backslashes inside Objective-C strings as seen above.
Turns out that its not enough to escape just the single quote character. I also needed to escape /n and /r to make this work with all HTML in general.
There may be some other character that I missed, if I find a case I'll post it.
The reason for this "escapes" me.
JSON escapes the forward slash, so a hash {a: "a/b/c"} is serialized as {"a":"a\/b\/c"} instead of {"a":"a/b/c"}.
Why?
JSON doesn't require you to do that, it allows you to do that. It also allows you to use "\u0061" for "A", but it's not required, like Harold L points out:
The JSON spec says you CAN escape forward slash, but you don't have to.
Harold L answered Oct 16 '09 at 21:59
Allowing \/ helps when embedding JSON in a <script> tag, which doesn't allow </ inside strings, like Seb points out:
This is because HTML does not allow a string inside a <script> tag to contain </, so in case that substring's there, you should escape every forward slash.
Seb answered Oct 16 '09 at 22:00 (#1580667)
Some of Microsoft's ASP.NET Ajax/JSON API's use this loophole to add extra information, e.g., a datetime will be sent as "\/Date(milliseconds)\/". (Yuck)
The JSON spec says you CAN escape forward slash, but you don't have to.
I asked the same question some time ago and had to answer it myself. Here's what I came up with:
It seems, my first thought [that it comes from its JavaScript
roots] was correct.
'\/' === '/' in JavaScript, and JSON is valid JavaScript. However,
why are the other ignored escapes (like \z) not allowed in JSON?
The key for this was reading
http://www.cs.tut.fi/~jkorpela/www/revsol.html, followed by
http://www.w3.org/TR/html4/appendix/notes.html#h-B.3.2. The feature of
the slash escape allows JSON to be embedded in HTML (as SGML) and XML.
PHP escapes forward slashes by default which is probably why this appears so commonly. I suspect it's because embedding the string "</script>" inside a <script> tag is considered unsafe.
Example:
<script>
var searchData = <?= json_encode(['searchTerm' => $_GET['search'], ...]) ?>;
// Do something else with the data...
</script>
Based on this code, an attacker could append this to the page's URL:
?search=</script> <some attack code here>
Which, if PHP's protection was not in place, would produce the following HTML:
<script>
var searchData = {"searchTerm":"</script> <some attack code here>"};
...
</script>
Even though the closing script tag is inside a string, it will cause many (most?) browsers to exit the script tag and interpret the items following as valid HTML.
With PHP's protection in place, it will appear instead like this, which will NOT break out of the script tag:
<script>
var searchData = {"searchTerm":"<\/script> <some attack code here>"};
...
</script>
This functionality can be disabled by passing in the JSON_UNESCAPED_SLASHES flag but most developers will not use this since the original result is already valid JSON.
Yes, some JSON utiltiy libraries do it for various good but mostly legacy reasons. But then they should also offer something like setEscapeForwardSlashAlways method to set this behaviour OFF.
In Java, org.codehaus.jettison.json.JSONObject does offer a method called
setEscapeForwardSlashAlways(boolean escapeForwardSlashAlways)
to switch this default behaviour off.
So I have 1000 lines of javascript. I need to turn it into a Java String so that I can output (via System.out.println or whatever).
I'm looking for an online tool to escape all the quotes... something geared toward my specific need would be nice as I don't want other special characters changed. Lines like:
var rgx = /(\d+)(\d{3})/;
need to stay intact.
The situation mandates the JavaScript be put into a String so please no workarounds.
Here's a link which features Crockford's implementation of the quote() function. Use it to build your own JavaScript converter.
Edit: I also slightly modified the function to output an ascii-safe string by default.
Edit2: Just a suggestion: It might be smarter to keep the JavaScript in an external file and read it at runtime instead of hardcoding it...
Edit3: And here's a fully-featured solution - just copy to a .html file and replace the dummy script:
<script src="quote.js"></script>
<script>
// this is the JavaScript to be converted:
var foo = 'bar';
var spam = 'eggs';
function fancyFunction() {
return 'cool';
}
</script>
<pre><script>
document.writeln(quote(
document.getElementsByTagName('script')[1].firstChild.nodeValue, true));
</script></pre>
You can compress the file using one of the available tools to achieve this effect:
YUI Compressor Online
Dean Edward's Packer
Douglas Crockford's JSMIN
You can use the jsmin tool to compress the Javascript to a single line (hopefully), but it doesn't escape the quotes. This can be done with search/replace in an editor or the server side scripting language used.
So everything I tried ended up breaking the javascript. I finally got it to work by doing the following:
Using Notepad++:
Hit Shift + Tab a bunch of times to unindent every line
Do View -> Show End Of Line
Highlight the LF char and do a Replace All to replace with empty string
Repeat for the CR char
Highlight a " (quote character) and do a Replace All with \" (escaped quote)... just typing the quote character into the Replace prompt only grabbed some of the quotes for some reason.
Now You have 1 enormously long line... I ended up having to break the 1 string apart into about 2000 character long lines.... The crazy long line was killing IE and/or breaking the Java String limit.