1 // Copyright (c) 2012 Jeff Ichnowski 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions 6 // are met: 7 // 8 // * Redistributions of source code must retain the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer. 11 // 12 // * Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following 14 // disclaimer in the documentation and/or other materials 15 // provided with the distribution. 16 // 17 // * Neither the name of the OWASP nor the names of its 18 // contributors may be used to endorse or promote products 19 // derived from this software without specific prior written 20 // permission. 21 // 22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 // COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 33 // OF THE POSSIBILITY OF SUCH DAMAGE. 34 package org.owasp.encoder; 35 36 import java.util.HashMap; 37 import java.util.Map; 38 39 /** 40 * Encoders -- Public factory method for obtaining instances of Encoders. 41 * Classes implementing the encoders are not directly exposed as part of the API 42 * since encoding strategies are subject to change. In many cases encoders will 43 * share the same implementation, but have different internal flags for how to 44 * handle varied content. For example the XML_CONTENT and XML_ATTRIBUTE contexts 45 * may currently share the same class with each instances having a different set 46 * of flags. Future version may optimize them into different classes. 47 * 48 * <p> 49 * All encoders returned by the factory are thread-safe.</p> 50 * 51 * @author Jeff Ichnowski 52 */ 53 public final class Encoders { 54 55 /** 56 * Name of {@linkplain Encode#forHtml(String) HTML general} context. 57 */ 58 public static final String HTML = "html"; 59 /** 60 * Name of {@linkplain Encode#forHtmlContent(String) HTML content} context. 61 */ 62 public static final String HTML_CONTENT = "html-content"; 63 /** 64 * Name of {@linkplain Encode#forHtmlAttribute(String) HTML attribute} 65 * context. 66 */ 67 public static final String HTML_ATTRIBUTE = "html-attribute"; 68 /** 69 * Name of 70 * {@linkplain Encode#forHtmlUnquotedAttribute(String) unquoted HTML attribute} 71 * context. 72 */ 73 public static final String HTML_UNQUOTED_ATTRIBUTE = "html-attribute-unquoted"; 74 /** 75 * Name of {@linkplain Encode#forXml(String) XML general} context. 76 */ 77 public static final String XML = "xml"; 78 /** 79 * Name of {@linkplain Encode#forXmlContent(String) XML content} context. 80 */ 81 public static final String XML_CONTENT = "xml-content"; 82 /** 83 * Name of {@linkplain Encode#forXmlAttribute(String) XML attribute} 84 * context. 85 */ 86 public static final String XML_ATTRIBUTE = "xml-attribute"; 87 /** 88 * Name of {@linkplain Encode#forXmlComment(String) XML comment} context. 89 */ 90 public static final String XML_COMMENT = "xml-comment"; 91 /** 92 * Name of {@linkplain Encode#forCDATA(String) CDATA} context. 93 */ 94 public static final String CDATA = "cdata"; 95 /** 96 * Name of {@linkplain Encode#forCssString(String) CSS string} context. 97 */ 98 public static final String CSS_STRING = "css-string"; 99 /** 100 * Name of {@linkplain Encode#forCssUrl(String) CSS URL} context. 101 */ 102 public static final String CSS_URL = "css-url"; 103 /** 104 * Name of {@linkplain Encode#forJava(String) Java String} context. 105 */ 106 public static final String JAVA = "java"; 107 /** 108 * Name of {@linkplain Encode#forJavaScript(String) JavaScript general} 109 * context. 110 */ 111 public static final String JAVASCRIPT = "javascript"; 112 /** 113 * Name of 114 * {@linkplain Encode#forJavaScriptAttribute(String) JavaScript attribute} 115 * context. 116 */ 117 public static final String JAVASCRIPT_ATTRIBUTE = "javascript-attribute"; 118 /** 119 * Name of {@linkplain Encode#forJavaScriptBlock(String) JavaScript block} 120 * context. 121 */ 122 public static final String JAVASCRIPT_BLOCK = "javascript-block"; 123 /** 124 * Name of {@linkplain Encode#forJavaScriptSource(String) JavaScript source} 125 * context. 126 */ 127 public static final String JAVASCRIPT_SOURCE = "javascript-source"; 128 /** 129 * Name of {@linkplain Encode#forUri(String) URI} context. 130 */ 131 public static final String URI = "uri"; 132 /** 133 * Name of {@linkplain Encode#forUriComponent(String) URI component} 134 * context. 135 */ 136 public static final String URI_COMPONENT = "uri-component"; 137 /** 138 * Map from encoder name to encoder singleton. 139 */ 140 private static final Map<String, Encoder> ENCODERS_MAP 141 = new HashMap<String, Encoder>(32); 142 // XML and HTML use the same encoder implementations currently 143 /** 144 * Encoder for general XML/HTML contexts. 145 */ 146 static final XMLEncoder XML_ENCODER 147 = map(HTML, map(XML, new XMLEncoder(XMLEncoder.Mode.ALL))); 148 /** 149 * Encoder for XML/HTML content contexts. 150 */ 151 static final XMLEncoder XML_CONTENT_ENCODER 152 = map(HTML_CONTENT, map(XML_CONTENT, new XMLEncoder(XMLEncoder.Mode.CONTENT))); 153 /** 154 * Encoder for XML/HTML attribute contexts. 155 */ 156 static final XMLEncoder XML_ATTRIBUTE_ENCODER 157 = map(HTML_ATTRIBUTE, map(XML_ATTRIBUTE, new XMLEncoder(XMLEncoder.Mode.ATTRIBUTE))); 158 /** 159 * Encoder for XML comments. 160 */ 161 static final XMLCommentEncoder XML_COMMENT_ENCODER 162 = map(XML_COMMENT, new XMLCommentEncoder()); 163 /** 164 * Encoder for CDATA contexts. 165 */ 166 static final CDATAEncoder CDATA_ENCODER 167 = map(CDATA, new CDATAEncoder()); 168 /** 169 * Encoder for unquoted HTML attributes. 170 */ 171 static final HTMLEncoder HTML_UNQUOTED_ATTRIBUTE_ENCODER 172 = map(HTML_UNQUOTED_ATTRIBUTE, new HTMLEncoder()); 173 /** 174 * Encoder for general JavaScript contexts. 175 */ 176 static final JavaScriptEncoder JAVASCRIPT_ENCODER 177 = map(JAVASCRIPT, new JavaScriptEncoder(JavaScriptEncoder.Mode.HTML, false)); 178 /** 179 * Encoder for JavaScript appearing in XML/HTML attributes. 180 */ 181 static final JavaScriptEncoder JAVASCRIPT_ATTRIBUTE_ENCODER 182 = map(JAVASCRIPT_ATTRIBUTE, new JavaScriptEncoder(JavaScriptEncoder.Mode.ATTRIBUTE, false)); 183 /** 184 * Encoder for JavaScript appearing in HTML script blocks. 185 */ 186 static final JavaScriptEncoder JAVASCRIPT_BLOCK_ENCODER 187 = map(JAVASCRIPT_BLOCK, new JavaScriptEncoder(JavaScriptEncoder.Mode.BLOCK, false)); 188 /** 189 * Encoder for JavaScript in stand-alone contexts. 190 */ 191 static final JavaScriptEncoder JAVASCRIPT_SOURCE_ENCODER 192 = map(JAVASCRIPT_SOURCE, new JavaScriptEncoder(JavaScriptEncoder.Mode.SOURCE, false)); 193 /** 194 * Encoder for full URIs. 195 */ 196 static final URIEncoder URI_ENCODER 197 = map(URI, new URIEncoder(URIEncoder.Mode.FULL_URI)); 198 /** 199 * Encoder for components of URIs. 200 */ 201 static final URIEncoder URI_COMPONENT_ENCODER 202 = map(URI_COMPONENT, new URIEncoder(URIEncoder.Mode.COMPONENT)); 203 /** 204 * Encoder for Java strings. 205 */ 206 static final JavaEncoder JAVA_ENCODER 207 = map(JAVA, new JavaEncoder()); 208 /** 209 * Encoder for CSS strings. 210 */ 211 static final CSSEncoder CSS_STRING_ENCODER 212 = map(CSS_STRING, new CSSEncoder(CSSEncoder.Mode.STRING)); 213 /** 214 * Encoder for CSS URL values. 215 */ 216 static final CSSEncoder CSS_URL_ENCODER 217 = map(CSS_URL, new CSSEncoder(CSSEncoder.Mode.URL)); 218 219 /** 220 * Internal method to setup and map encoder singletons. 221 * 222 * @param name -- name of the encoder (one of the constants above) 223 * @param encoder -- the encoder singleton instance 224 * @param <T> the encoder type 225 * @return the encoder argument. 226 */ map(String name, T encoder)227 private static <T extends Encoder> T map(String name, T encoder) { 228 Encoder old = ENCODERS_MAP.put(name, encoder); 229 assert old == null; 230 return encoder; 231 } 232 233 /** 234 * Returns a new instance of an Encoder for the specified context. The 235 * returned instance is thread-safe. 236 * 237 * @param contextName the context name (one of the String constants defined 238 * in this class) 239 * @return an encoder for the specified context. 240 * @throws NullPointerException if {@code contextName} is null 241 * @throws UnsupportedContextException if {@code contextName} is not 242 * recognized. 243 */ forName(String contextName)244 public static Encoder forName(String contextName) throws NullPointerException, UnsupportedContextException { 245 if (contextName == null) { 246 throw new NullPointerException(); 247 } 248 Encoder encoder = ENCODERS_MAP.get(contextName); 249 if (encoder == null) { 250 throw new UnsupportedContextException(contextName); 251 } 252 return encoder; 253 } 254 255 /** 256 * No instances. 257 */ Encoders()258 private Encoders() { 259 } 260 } 261