Browse Source

workaround for GRAILS-10823

Lari Hotari 11 years ago
parent
commit
61e4a03bce

+ 19 - 0
grails/hello/grails-app/conf/JsonWorkaroundBootStrap.groovy

@@ -0,0 +1,19 @@
+import org.codehaus.groovy.grails.web.json.JSONObject
+import org.springframework.util.ClassUtils
+import org.springframework.util.ReflectionUtils
+
+class JsonWorkaroundBootStrap {
+    def init = { servletContext ->
+        // activate workaround for GRAILS-10823
+        println("activating workaround for GRAILS-10823 - use this only for Grails 2.3.3")
+        def encoderInstance = ClassUtils.forName("org.codehaus.groovy.grails.plugins.codecs.JSONEncoder", JSONObject.class.getClassLoader()).newInstance()
+        ['javascriptEncoderStateless', 'javascriptEncoder'].each { fieldName ->
+            ReflectionUtils.findField(JSONObject, fieldName).with {
+                accessible = true
+                set(null, encoderInstance)
+            }
+        }
+    }
+    def destroy = {
+    }
+}

+ 85 - 0
grails/hello/src/groovy/org/codehaus/groovy/grails/plugins/codecs/JSONEncoder.java

@@ -0,0 +1,85 @@
+/*
+ * Copyright 2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.grails.plugins.codecs;
+
+import org.apache.commons.lang.StringUtils;
+import org.codehaus.groovy.grails.support.encoding.CodecIdentifier;
+import org.codehaus.groovy.grails.support.encoding.DefaultCodecIdentifier;
+
+/**
+ * Escapes characters in JSON output
+ *
+ * @author Lari Hotari
+ * @since 2.3.4
+ */
+public class JSONEncoder extends AbstractCharReplacementEncoder {
+    public static final CodecIdentifier JSON_CODEC_IDENTIFIER = new DefaultCodecIdentifier(
+            "JSON", "Json") {
+        public boolean isEquivalent(CodecIdentifier other) {
+            return super.isEquivalent(other) || JavaScriptEncoder.JAVASCRIPT_CODEC_IDENTIFIER.getCodecName().equals(other.getCodecName());
+        };
+    };
+
+    public JSONEncoder() {
+        super(JSON_CODEC_IDENTIFIER);
+    }
+
+    /* (non-Javadoc)
+     * @see org.codehaus.groovy.grails.plugins.codecs.AbstractCharReplacementEncoder#escapeCharacter(char, char)
+     */
+    @Override
+    protected String escapeCharacter(char ch, char previousChar) {
+        switch (ch) {
+            case '"':
+                return "\\\"";
+            case '\\':
+                return "\\\\";
+            case '\t':
+                return "\\t";
+            case '\n':
+                return "\\n";
+            case '\r':
+                return "\\r";
+            case '\f':
+                return "\\f";
+            case '\b':
+                return "\\b";
+            case '\u000B': // vertical tab: http://bclary.com/2004/11/07/#a-7.8.4
+                return "\\v";
+            case '\u2028':
+                return "\\u2028"; // Line separator
+            case '\u2029':
+                return "\\u2029"; // Paragraph separator
+            case '/':
+                // preserve special handling that exists in JSONObject.quote to improve security if JSON is embedded in HTML document
+                // prevents outputting "</" gets outputted with unicode escaping for the slash
+                if (previousChar == '<') {
+                    return "\\u002f"; 
+                }
+                break;
+        }
+        if(ch < ' ') {
+            // escape all other control characters
+            return "\\u" + StringUtils.leftPad(Integer.toHexString(ch), 4, '0');
+        }
+        return null;
+    }
+
+    @Override
+    public boolean isApplyToSafelyEncoded() {
+        return true;
+    }
+}