views:

126

answers:

3

I'm trying to pass the output of a SQL Server exception to the client using the RegisterStartUpScript method of the MS ScriptManager. This works fine for some errors but when the exception contains single quotes the alert fails.

I dont want to only escape single quotes though - Is there a standard function i can call to escape any special chars for use in Javascript?

string scriptstring = "alert('" + ex.Message + "');";         
ScriptManager.RegisterStartupScript(this, this.GetType(), "Alert", scriptstring , true);

Thanks tpeczek, the code almost worked for me :) but with a slight amendment (the escaping of single quotes) it works a treat.

I've included my amended version here...

public class JSEncode
{
    /// <summary>
    /// Encodes a string to be represented as a string literal. The format
    /// is essentially a JSON string.
    /// 
    /// The string returned includes outer quotes 
    /// Example Output: "Hello \"Rick\"!\r\nRock on"
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public static string EncodeJsString(string s)
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("\"");
        foreach (char c in s)
        {
            switch (c)
            {
                case '\'':
                    sb.Append("\\\'");
                    break;
                case '\"':
                    sb.Append("\\\"");
                    break;
                case '\\':
                    sb.Append("\\\\");
                    break;
                case '\b':
                    sb.Append("\\b");
                    break;
                case '\f':
                    sb.Append("\\f");
                    break;
                case '\n':
                    sb.Append("\\n");
                    break;
                case '\r':
                    sb.Append("\\r");
                    break;
                case '\t':
                    sb.Append("\\t");
                    break;
                default:
                    int i = (int)c;
                    if (i < 32 || i > 127)
                    {
                        sb.AppendFormat("\\u{0:X04}", i);
                    }
                    else
                    {
                        sb.Append(c);
                    }
                    break;
            }
        }
        sb.Append("\"");

        return sb.ToString();
    }
}

As mentioned below - original source: here

+2  A: 

You can read this article, which shows a nice method of encoding string for javascript: http://www.west-wind.com/weblog/posts/114530.aspx

tpeczek
+1  A: 

A probem with this function is that it doesn't encode characters that are typically out-of-band in encapsulating HTML... so you'd have trouble if you tried to include a string with " inside an attribute value, or if you had a string with the sequence </script> inside a script element. That could lead to script-injection and XSS.

You could add:

            case '<':
                sb.Append("\\x3C");
                break;
            case '"':
                sb.Append("\\x22");
                break;
            case '&':
                sb.Append("\\x26");
                break;

In general it would probably be better to use a standard JSON encoder than brew your own JS string literal encoder. This will allow you to pass any simple datatype to JS rather than just strings.

In .NET 3.5 you get JavaScriptSerializer, however note that whilst this does encode < to \u003C (so the output will be suitable for use in a <script> element), it doesn't encode & or ", so HTML-escaping would be needed to include such content in an attribute value and a CDATA wrapper would be needed for XHTML script elements.

(In common with many JSON encoders, it also fails to encode the U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR characters. The above code does, due to escaping all non-ASCII characters. This causes ‘unterminated string literal’ errors when these characters are included in a JS string literal, because JavaScript unhelpfully treats them the same as an ASCII newline.)

bobince
bdukes
+2  A: 

Have you had a look at HttpUtility.JavascriptStringEncode?

Russ Cam
Upvoted because its a great answer - only works in .NET 4 though
Rich Andrews