• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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