1<HTML>
2<BODY BGCOLOR="white">
3<PRE>
4<FONT color="green">001</FONT>    // Copyright (c) 2011, Mike Samuel<a name="line.1"></a>
5<FONT color="green">002</FONT>    // All rights reserved.<a name="line.2"></a>
6<FONT color="green">003</FONT>    //<a name="line.3"></a>
7<FONT color="green">004</FONT>    // Redistribution and use in source and binary forms, with or without<a name="line.4"></a>
8<FONT color="green">005</FONT>    // modification, are permitted provided that the following conditions<a name="line.5"></a>
9<FONT color="green">006</FONT>    // are met:<a name="line.6"></a>
10<FONT color="green">007</FONT>    //<a name="line.7"></a>
11<FONT color="green">008</FONT>    // Redistributions of source code must retain the above copyright<a name="line.8"></a>
12<FONT color="green">009</FONT>    // notice, this list of conditions and the following disclaimer.<a name="line.9"></a>
13<FONT color="green">010</FONT>    // Redistributions in binary form must reproduce the above copyright<a name="line.10"></a>
14<FONT color="green">011</FONT>    // notice, this list of conditions and the following disclaimer in the<a name="line.11"></a>
15<FONT color="green">012</FONT>    // documentation and/or other materials provided with the distribution.<a name="line.12"></a>
16<FONT color="green">013</FONT>    // Neither the name of the OWASP nor the names of its contributors may<a name="line.13"></a>
17<FONT color="green">014</FONT>    // be used to endorse or promote products derived from this software<a name="line.14"></a>
18<FONT color="green">015</FONT>    // without specific prior written permission.<a name="line.15"></a>
19<FONT color="green">016</FONT>    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS<a name="line.16"></a>
20<FONT color="green">017</FONT>    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT<a name="line.17"></a>
21<FONT color="green">018</FONT>    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS<a name="line.18"></a>
22<FONT color="green">019</FONT>    // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE<a name="line.19"></a>
23<FONT color="green">020</FONT>    // COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,<a name="line.20"></a>
24<FONT color="green">021</FONT>    // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,<a name="line.21"></a>
25<FONT color="green">022</FONT>    // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;<a name="line.22"></a>
26<FONT color="green">023</FONT>    // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER<a name="line.23"></a>
27<FONT color="green">024</FONT>    // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<a name="line.24"></a>
28<FONT color="green">025</FONT>    // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN<a name="line.25"></a>
29<FONT color="green">026</FONT>    // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<a name="line.26"></a>
30<FONT color="green">027</FONT>    // POSSIBILITY OF SUCH DAMAGE.<a name="line.27"></a>
31<FONT color="green">028</FONT>    <a name="line.28"></a>
32<FONT color="green">029</FONT>    package org.owasp.html;<a name="line.29"></a>
33<FONT color="green">030</FONT>    <a name="line.30"></a>
34<FONT color="green">031</FONT>    import java.util.List;<a name="line.31"></a>
35<FONT color="green">032</FONT>    import java.util.Map;<a name="line.32"></a>
36<FONT color="green">033</FONT>    import java.util.Set;<a name="line.33"></a>
37<FONT color="green">034</FONT>    import java.util.regex.Pattern;<a name="line.34"></a>
38<FONT color="green">035</FONT>    <a name="line.35"></a>
39<FONT color="green">036</FONT>    import javax.annotation.Nullable;<a name="line.36"></a>
40<FONT color="green">037</FONT>    import javax.annotation.concurrent.NotThreadSafe;<a name="line.37"></a>
41<FONT color="green">038</FONT>    <a name="line.38"></a>
42<FONT color="green">039</FONT>    import com.google.common.base.Predicate;<a name="line.39"></a>
43<FONT color="green">040</FONT>    import com.google.common.collect.ImmutableList;<a name="line.40"></a>
44<FONT color="green">041</FONT>    import com.google.common.collect.ImmutableMap;<a name="line.41"></a>
45<FONT color="green">042</FONT>    import com.google.common.collect.ImmutableSet;<a name="line.42"></a>
46<FONT color="green">043</FONT>    import com.google.common.collect.Maps;<a name="line.43"></a>
47<FONT color="green">044</FONT>    import com.google.common.collect.Sets;<a name="line.44"></a>
48<FONT color="green">045</FONT>    <a name="line.45"></a>
49<FONT color="green">046</FONT>    <a name="line.46"></a>
50<FONT color="green">047</FONT>    /**<a name="line.47"></a>
51<FONT color="green">048</FONT>     * Conveniences for configuring policies for the {@link HtmlSanitizer}.<a name="line.48"></a>
52<FONT color="green">049</FONT>     *<a name="line.49"></a>
53<FONT color="green">050</FONT>     * &lt;h3&gt;Usage&lt;/h3&gt;<a name="line.50"></a>
54<FONT color="green">051</FONT>     * &lt;p&gt;<a name="line.51"></a>
55<FONT color="green">052</FONT>     * To create a policy, first construct an instance of this class; then call<a name="line.52"></a>
56<FONT color="green">053</FONT>     * &lt;code&gt;allow&amp;hellip;&lt;/code&gt; methods to turn on tags, attributes, and other<a name="line.53"></a>
57<FONT color="green">054</FONT>     * processing modes; and finally call &lt;code&gt;build(renderer)&lt;/code&gt; or<a name="line.54"></a>
58<FONT color="green">055</FONT>     * &lt;code&gt;toFactory()&lt;/code&gt;.<a name="line.55"></a>
59<FONT color="green">056</FONT>     * &lt;/p&gt;<a name="line.56"></a>
60<FONT color="green">057</FONT>     * &lt;pre class="prettyprint lang-java"&gt;<a name="line.57"></a>
61<FONT color="green">058</FONT>     * // Define the policy.<a name="line.58"></a>
62<FONT color="green">059</FONT>     * Function&amp;lt;HtmlStreamEventReceiver, HtmlSanitizer.Policy&amp;gt; policy<a name="line.59"></a>
63<FONT color="green">060</FONT>     *     = new HtmlPolicyBuilder()<a name="line.60"></a>
64<FONT color="green">061</FONT>     *         .allowElements("a", "p")<a name="line.61"></a>
65<FONT color="green">062</FONT>     *         .allowAttributes("href").onElements("a")<a name="line.62"></a>
66<FONT color="green">063</FONT>     *         .toFactory();<a name="line.63"></a>
67<FONT color="green">064</FONT>     *<a name="line.64"></a>
68<FONT color="green">065</FONT>     * // Sanitize your output.<a name="line.65"></a>
69<FONT color="green">066</FONT>     * HtmlSanitizer.sanitize(myHtml, policy.apply(myHtmlStreamRenderer));<a name="line.66"></a>
70<FONT color="green">067</FONT>     * &lt;/pre&gt;<a name="line.67"></a>
71<FONT color="green">068</FONT>     *<a name="line.68"></a>
72<FONT color="green">069</FONT>     * &lt;h3&gt;Embedded Content&lt;/h3&gt;<a name="line.69"></a>
73<FONT color="green">070</FONT>     * &lt;p&gt;<a name="line.70"></a>
74<FONT color="green">071</FONT>     * Embedded URLs are filtered by<a name="line.71"></a>
75<FONT color="green">072</FONT>     * {@link HtmlPolicyBuilder#allowUrlProtocols protocol}.<a name="line.72"></a>
76<FONT color="green">073</FONT>     * There is a {@link HtmlPolicyBuilder#allowStandardUrlProtocols canned policy}<a name="line.73"></a>
77<FONT color="green">074</FONT>     * so you can easily white-list widely used policies that don't violate the<a name="line.74"></a>
78<FONT color="green">075</FONT>     * current pages origin.  See "Customization" below for ways to do further<a name="line.75"></a>
79<FONT color="green">076</FONT>     * filtering.  If you allow links it might be worthwhile to<a name="line.76"></a>
80<FONT color="green">077</FONT>     * {@link HtmlPolicyBuilder#requireRelNofollowOnLinks() require}<a name="line.77"></a>
81<FONT color="green">078</FONT>     * {@code rel=nofollow}.<a name="line.78"></a>
82<FONT color="green">079</FONT>     * &lt;/p&gt;<a name="line.79"></a>
83<FONT color="green">080</FONT>     * &lt;p&gt;<a name="line.80"></a>
84<FONT color="green">081</FONT>     * This class simply throws out all embedded JS.<a name="line.81"></a>
85<FONT color="green">082</FONT>     * Use a custom element or attribute policy to allow through<a name="line.82"></a>
86<FONT color="green">083</FONT>     * signed or otherwise known-safe code.<a name="line.83"></a>
87<FONT color="green">084</FONT>     * Check out the Caja project if you need a way to contain third-party JS.<a name="line.84"></a>
88<FONT color="green">085</FONT>     * &lt;/p&gt;<a name="line.85"></a>
89<FONT color="green">086</FONT>     * &lt;p&gt;<a name="line.86"></a>
90<FONT color="green">087</FONT>     * This class does not attempt to faithfully parse and sanitize CSS.<a name="line.87"></a>
91<FONT color="green">088</FONT>     * It does provide {@link HtmlPolicyBuilder#allowStyling() one} styling option<a name="line.88"></a>
92<FONT color="green">089</FONT>     * that allows through a few CSS properties that allow textual styling, but that<a name="line.89"></a>
93<FONT color="green">090</FONT>     * disallow image loading, history stealing, layout breaking, code execution,<a name="line.90"></a>
94<FONT color="green">091</FONT>     * etc.<a name="line.91"></a>
95<FONT color="green">092</FONT>     * &lt;/p&gt;<a name="line.92"></a>
96<FONT color="green">093</FONT>     *<a name="line.93"></a>
97<FONT color="green">094</FONT>     * &lt;h3&gt;Customization&lt;/h3&gt;<a name="line.94"></a>
98<FONT color="green">095</FONT>     * &lt;p&gt;<a name="line.95"></a>
99<FONT color="green">096</FONT>     * You can easily do custom processing on tags and attributes by supplying your<a name="line.96"></a>
100<FONT color="green">097</FONT>     * own {@link ElementPolicy element policy} or<a name="line.97"></a>
101<FONT color="green">098</FONT>     * {@link AttributePolicy attribute policy} when calling<a name="line.98"></a>
102<FONT color="green">099</FONT>     * &lt;code&gt;allow&amp;hellip;&lt;/code&gt;.<a name="line.99"></a>
103<FONT color="green">100</FONT>     * E.g. to convert headers into {@code &lt;div&gt;}s, you could use an element policy<a name="line.100"></a>
104<FONT color="green">101</FONT>     * &lt;/p&gt;<a name="line.101"></a>
105<FONT color="green">102</FONT>     * &lt;pre class="prettyprint lang-java"&gt;<a name="line.102"></a>
106<FONT color="green">103</FONT>     * new HtmlPolicyBuilder()<a name="line.103"></a>
107<FONT color="green">104</FONT>     *   .allowElement(<a name="line.104"></a>
108<FONT color="green">105</FONT>     *     new ElementPolicy() {<a name="line.105"></a>
109<FONT color="green">106</FONT>     *       public String apply(String elementName, List&amp;lt;String&gt; attributes) {<a name="line.106"></a>
110<FONT color="green">107</FONT>     *         attributes.add("class");<a name="line.107"></a>
111<FONT color="green">108</FONT>     *         attributes.add("header-" + elementName);<a name="line.108"></a>
112<FONT color="green">109</FONT>     *         return "div";<a name="line.109"></a>
113<FONT color="green">110</FONT>     *       }<a name="line.110"></a>
114<FONT color="green">111</FONT>     *     },<a name="line.111"></a>
115<FONT color="green">112</FONT>     *     "h1", "h2", "h3", "h4", "h5", "h6")<a name="line.112"></a>
116<FONT color="green">113</FONT>     *   .build(outputChannel)<a name="line.113"></a>
117<FONT color="green">114</FONT>     * &lt;/pre&gt;<a name="line.114"></a>
118<FONT color="green">115</FONT>     *<a name="line.115"></a>
119<FONT color="green">116</FONT>     * &lt;h3&gt;Rules of Thumb&lt;/h3&gt;<a name="line.116"></a>
120<FONT color="green">117</FONT>     * &lt;p&gt;<a name="line.117"></a>
121<FONT color="green">118</FONT>     * Throughout this class, several rules hold:<a name="line.118"></a>
122<FONT color="green">119</FONT>     * &lt;ul&gt;<a name="line.119"></a>
123<FONT color="green">120</FONT>     *   &lt;li&gt;Everything is denied by default.  There are<a name="line.120"></a>
124<FONT color="green">121</FONT>     *     &lt;code&gt;disallow&amp;hellip;&lt;/code&gt; methods, but those reverse<a name="line.121"></a>
125<FONT color="green">122</FONT>     *     allows instead of rolling back overly permissive defaults.<a name="line.122"></a>
126<FONT color="green">123</FONT>     *   &lt;li&gt;The order of allows and disallows does not matter.<a name="line.123"></a>
127<FONT color="green">124</FONT>     *     Disallows trump allows whether they occur before or after them.<a name="line.124"></a>
128<FONT color="green">125</FONT>     *     The only method that needs to be called in a particular place is<a name="line.125"></a>
129<FONT color="green">126</FONT>     *     {@link HtmlPolicyBuilder#build}.<a name="line.126"></a>
130<FONT color="green">127</FONT>     *     Allows or disallows after {@code build} is called have no<a name="line.127"></a>
131<FONT color="green">128</FONT>     *     effect on the already built policy.<a name="line.128"></a>
132<FONT color="green">129</FONT>     *   &lt;li&gt;Element and attribute policies are applied in the following order:<a name="line.129"></a>
133<FONT color="green">130</FONT>     *     element specific attribute policy, global attribute policy, element<a name="line.130"></a>
134<FONT color="green">131</FONT>     *     policy.<a name="line.131"></a>
135<FONT color="green">132</FONT>     *     Element policies come last so they can observe all the post-processed<a name="line.132"></a>
136<FONT color="green">133</FONT>     *     attributes, and so they can add attributes that are exempt from<a name="line.133"></a>
137<FONT color="green">134</FONT>     *     attribute policies.<a name="line.134"></a>
138<FONT color="green">135</FONT>     *     Element specific policies go first, so they can normalize content to<a name="line.135"></a>
139<FONT color="green">136</FONT>     *     a form that might be acceptable to a more simplistic global policy.<a name="line.136"></a>
140<FONT color="green">137</FONT>     * &lt;/ul&gt;<a name="line.137"></a>
141<FONT color="green">138</FONT>     *<a name="line.138"></a>
142<FONT color="green">139</FONT>     * &lt;h3&gt;Thread safety and efficiency&lt;/h3&gt;<a name="line.139"></a>
143<FONT color="green">140</FONT>     * &lt;p&gt;<a name="line.140"></a>
144<FONT color="green">141</FONT>     * This class is not thread-safe.  The resulting policy will not violate its<a name="line.141"></a>
145<FONT color="green">142</FONT>     * security guarantees as a result of race conditions, but is not thread safe<a name="line.142"></a>
146<FONT color="green">143</FONT>     * because it maintains state to track whether text inside disallowed elements<a name="line.143"></a>
147<FONT color="green">144</FONT>     * should be suppressed.<a name="line.144"></a>
148<FONT color="green">145</FONT>     * &lt;p&gt;<a name="line.145"></a>
149<FONT color="green">146</FONT>     * The resulting policy can be reused, but if you use the<a name="line.146"></a>
150<FONT color="green">147</FONT>     * {@link HtmlPolicyBuilder#toFactory()} method instead of {@link #build}, then<a name="line.147"></a>
151<FONT color="green">148</FONT>     * binding policies to output channels is cheap so there's no need.<a name="line.148"></a>
152<FONT color="green">149</FONT>     * &lt;/p&gt;<a name="line.149"></a>
153<FONT color="green">150</FONT>     *<a name="line.150"></a>
154<FONT color="green">151</FONT>     * @author Mike Samuel &lt;mikesamuel@gmail.com&gt;<a name="line.151"></a>
155<FONT color="green">152</FONT>     */<a name="line.152"></a>
156<FONT color="green">153</FONT>    @TCB<a name="line.153"></a>
157<FONT color="green">154</FONT>    @NotThreadSafe<a name="line.154"></a>
158<FONT color="green">155</FONT>    public class HtmlPolicyBuilder {<a name="line.155"></a>
159<FONT color="green">156</FONT>      /**<a name="line.156"></a>
160<FONT color="green">157</FONT>       * The default set of elements that are removed if they have no attributes.<a name="line.157"></a>
161<FONT color="green">158</FONT>       * Since {@code &lt;img&gt;} is in this set, by default, a policy will remove<a name="line.158"></a>
162<FONT color="green">159</FONT>       * {@code &lt;img src=javascript:alert(1337)&gt;} because its URL is not allowed<a name="line.159"></a>
163<FONT color="green">160</FONT>       * and it has no other attributes that would warrant it appearing in the<a name="line.160"></a>
164<FONT color="green">161</FONT>       * output.<a name="line.161"></a>
165<FONT color="green">162</FONT>       */<a name="line.162"></a>
166<FONT color="green">163</FONT>      public static final ImmutableSet&lt;String&gt; DEFAULT_SKIP_IF_EMPTY<a name="line.163"></a>
167<FONT color="green">164</FONT>          = ImmutableSet.of("a", "font", "img", "input", "span");<a name="line.164"></a>
168<FONT color="green">165</FONT>    <a name="line.165"></a>
169<FONT color="green">166</FONT>      private final Map&lt;String, ElementPolicy&gt; elPolicies = Maps.newLinkedHashMap();<a name="line.166"></a>
170<FONT color="green">167</FONT>      private final Map&lt;String, Map&lt;String, AttributePolicy&gt;&gt; attrPolicies<a name="line.167"></a>
171<FONT color="green">168</FONT>          = Maps.newLinkedHashMap();<a name="line.168"></a>
172<FONT color="green">169</FONT>      private final Map&lt;String, AttributePolicy&gt; globalAttrPolicies<a name="line.169"></a>
173<FONT color="green">170</FONT>          = Maps.newLinkedHashMap();<a name="line.170"></a>
174<FONT color="green">171</FONT>      private final Set&lt;String&gt; allowedProtocols = Sets.newLinkedHashSet();<a name="line.171"></a>
175<FONT color="green">172</FONT>      private final Set&lt;String&gt; skipIfEmpty = Sets.newLinkedHashSet(<a name="line.172"></a>
176<FONT color="green">173</FONT>          DEFAULT_SKIP_IF_EMPTY);<a name="line.173"></a>
177<FONT color="green">174</FONT>      private final Map&lt;String, Boolean&gt; textContainers = Maps.newLinkedHashMap();<a name="line.174"></a>
178<FONT color="green">175</FONT>      private boolean requireRelNofollowOnLinks;<a name="line.175"></a>
179<FONT color="green">176</FONT>    <a name="line.176"></a>
180<FONT color="green">177</FONT>      /**<a name="line.177"></a>
181<FONT color="green">178</FONT>       * Allows the named elements.<a name="line.178"></a>
182<FONT color="green">179</FONT>       */<a name="line.179"></a>
183<FONT color="green">180</FONT>      public HtmlPolicyBuilder allowElements(String... elementNames) {<a name="line.180"></a>
184<FONT color="green">181</FONT>        return allowElements(ElementPolicy.IDENTITY_ELEMENT_POLICY, elementNames);<a name="line.181"></a>
185<FONT color="green">182</FONT>      }<a name="line.182"></a>
186<FONT color="green">183</FONT>    <a name="line.183"></a>
187<FONT color="green">184</FONT>      /**<a name="line.184"></a>
188<FONT color="green">185</FONT>       * Disallows the named elements.  Elements are disallowed by default, so<a name="line.185"></a>
189<FONT color="green">186</FONT>       * there is no need to disallow elements, unless you are making an exception<a name="line.186"></a>
190<FONT color="green">187</FONT>       * based on an earlier allow.<a name="line.187"></a>
191<FONT color="green">188</FONT>       */<a name="line.188"></a>
192<FONT color="green">189</FONT>      public HtmlPolicyBuilder disallowElements(String... elementNames) {<a name="line.189"></a>
193<FONT color="green">190</FONT>        return allowElements(ElementPolicy.REJECT_ALL_ELEMENT_POLICY, elementNames);<a name="line.190"></a>
194<FONT color="green">191</FONT>      }<a name="line.191"></a>
195<FONT color="green">192</FONT>    <a name="line.192"></a>
196<FONT color="green">193</FONT>      /**<a name="line.193"></a>
197<FONT color="green">194</FONT>       * Allow the given elements with the given policy.<a name="line.194"></a>
198<FONT color="green">195</FONT>       *<a name="line.195"></a>
199<FONT color="green">196</FONT>       * @param policy May remove or add attributes, change the element name, or<a name="line.196"></a>
200<FONT color="green">197</FONT>       *    deny the element.<a name="line.197"></a>
201<FONT color="green">198</FONT>       */<a name="line.198"></a>
202<FONT color="green">199</FONT>      public HtmlPolicyBuilder allowElements(<a name="line.199"></a>
203<FONT color="green">200</FONT>          ElementPolicy policy, String... elementNames) {<a name="line.200"></a>
204<FONT color="green">201</FONT>        invalidateCompiledState();<a name="line.201"></a>
205<FONT color="green">202</FONT>        for (String elementName : elementNames) {<a name="line.202"></a>
206<FONT color="green">203</FONT>          elementName = HtmlLexer.canonicalName(elementName);<a name="line.203"></a>
207<FONT color="green">204</FONT>          ElementPolicy newPolicy = ElementPolicy.Util.join(<a name="line.204"></a>
208<FONT color="green">205</FONT>              elPolicies.get(elementName), policy);<a name="line.205"></a>
209<FONT color="green">206</FONT>          // Don't remove if newPolicy is the always reject policy since we want<a name="line.206"></a>
210<FONT color="green">207</FONT>          // that to infect later allowElement calls for this particular element<a name="line.207"></a>
211<FONT color="green">208</FONT>          // name.  rejects should have higher priority than allows.<a name="line.208"></a>
212<FONT color="green">209</FONT>          elPolicies.put(elementName, newPolicy);<a name="line.209"></a>
213<FONT color="green">210</FONT>          if (!textContainers.containsKey(elementName)<a name="line.210"></a>
214<FONT color="green">211</FONT>              &amp;&amp; TagBalancingHtmlStreamEventReceiver<a name="line.211"></a>
215<FONT color="green">212</FONT>                  .allowsPlainTextualContent(elementName)) {<a name="line.212"></a>
216<FONT color="green">213</FONT>            textContainers.put(elementName, true);<a name="line.213"></a>
217<FONT color="green">214</FONT>          }<a name="line.214"></a>
218<FONT color="green">215</FONT>        }<a name="line.215"></a>
219<FONT color="green">216</FONT>        return this;<a name="line.216"></a>
220<FONT color="green">217</FONT>      }<a name="line.217"></a>
221<FONT color="green">218</FONT>    <a name="line.218"></a>
222<FONT color="green">219</FONT>      /**<a name="line.219"></a>
223<FONT color="green">220</FONT>       * A canned policy that allows a number of common formatting elements.<a name="line.220"></a>
224<FONT color="green">221</FONT>       */<a name="line.221"></a>
225<FONT color="green">222</FONT>      public HtmlPolicyBuilder allowCommonInlineFormattingElements() {<a name="line.222"></a>
226<FONT color="green">223</FONT>        return allowElements(<a name="line.223"></a>
227<FONT color="green">224</FONT>            "b", "i", "font", "s", "u", "o", "sup", "sub", "ins", "del", "strong",<a name="line.224"></a>
228<FONT color="green">225</FONT>            "strike", "tt", "code", "big", "small", "br", "span");<a name="line.225"></a>
229<FONT color="green">226</FONT>      }<a name="line.226"></a>
230<FONT color="green">227</FONT>    <a name="line.227"></a>
231<FONT color="green">228</FONT>      /**<a name="line.228"></a>
232<FONT color="green">229</FONT>       * A canned policy that allows a number of common block elements.<a name="line.229"></a>
233<FONT color="green">230</FONT>       */<a name="line.230"></a>
234<FONT color="green">231</FONT>      public HtmlPolicyBuilder allowCommonBlockElements() {<a name="line.231"></a>
235<FONT color="green">232</FONT>        return allowElements(<a name="line.232"></a>
236<FONT color="green">233</FONT>            "p", "div", "h1", "h2", "h3", "h4", "h5", "h6", "ul", "ol", "li",<a name="line.233"></a>
237<FONT color="green">234</FONT>            "blockquote");<a name="line.234"></a>
238<FONT color="green">235</FONT>      }<a name="line.235"></a>
239<FONT color="green">236</FONT>    <a name="line.236"></a>
240<FONT color="green">237</FONT>      /**<a name="line.237"></a>
241<FONT color="green">238</FONT>       * Allows text content in the named elements.<a name="line.238"></a>
242<FONT color="green">239</FONT>       * By default, text content is allowed in any<a name="line.239"></a>
243<FONT color="green">240</FONT>       * {@link #allowElements allowed elements} that can contain character data per<a name="line.240"></a>
244<FONT color="green">241</FONT>       * the HTML5 spec, but text content is not allowed by default in elements that<a name="line.241"></a>
245<FONT color="green">242</FONT>       * contain content of other kinds (like JavaScript in {@code &lt;script&gt;}<a name="line.242"></a>
246<FONT color="green">243</FONT>       * elements.<a name="line.243"></a>
247<FONT color="green">244</FONT>       * &lt;p&gt;<a name="line.244"></a>
248<FONT color="green">245</FONT>       * To write a policy that whitelists {@code &lt;script&gt;} or {@code &lt;style&gt;}<a name="line.245"></a>
249<FONT color="green">246</FONT>       * elements, first {@code allowTextIn("script")}.<a name="line.246"></a>
250<FONT color="green">247</FONT>       */<a name="line.247"></a>
251<FONT color="green">248</FONT>      public HtmlPolicyBuilder allowTextIn(String... elementNames) {<a name="line.248"></a>
252<FONT color="green">249</FONT>        invalidateCompiledState();<a name="line.249"></a>
253<FONT color="green">250</FONT>        for (String elementName : elementNames) {<a name="line.250"></a>
254<FONT color="green">251</FONT>          elementName = HtmlLexer.canonicalName(elementName);<a name="line.251"></a>
255<FONT color="green">252</FONT>          textContainers.put(elementName, true);<a name="line.252"></a>
256<FONT color="green">253</FONT>        }<a name="line.253"></a>
257<FONT color="green">254</FONT>        return this;<a name="line.254"></a>
258<FONT color="green">255</FONT>      }<a name="line.255"></a>
259<FONT color="green">256</FONT>    <a name="line.256"></a>
260<FONT color="green">257</FONT>      public HtmlPolicyBuilder disallowTextIn(String... elementNames) {<a name="line.257"></a>
261<FONT color="green">258</FONT>        invalidateCompiledState();<a name="line.258"></a>
262<FONT color="green">259</FONT>        for (String elementName : elementNames) {<a name="line.259"></a>
263<FONT color="green">260</FONT>          elementName = HtmlLexer.canonicalName(elementName);<a name="line.260"></a>
264<FONT color="green">261</FONT>          textContainers.put(elementName, false);<a name="line.261"></a>
265<FONT color="green">262</FONT>        }<a name="line.262"></a>
266<FONT color="green">263</FONT>        return this;<a name="line.263"></a>
267<FONT color="green">264</FONT>      }<a name="line.264"></a>
268<FONT color="green">265</FONT>    <a name="line.265"></a>
269<FONT color="green">266</FONT>      /**<a name="line.266"></a>
270<FONT color="green">267</FONT>       * Assuming the given elements are allowed, allows them to appear without<a name="line.267"></a>
271<FONT color="green">268</FONT>       * attributes.<a name="line.268"></a>
272<FONT color="green">269</FONT>       *<a name="line.269"></a>
273<FONT color="green">270</FONT>       * @see #DEFAULT_SKIP_IF_EMPTY<a name="line.270"></a>
274<FONT color="green">271</FONT>       * @see #disallowWithoutAttributes<a name="line.271"></a>
275<FONT color="green">272</FONT>       */<a name="line.272"></a>
276<FONT color="green">273</FONT>      public HtmlPolicyBuilder allowWithoutAttributes(String... elementNames) {<a name="line.273"></a>
277<FONT color="green">274</FONT>        invalidateCompiledState();<a name="line.274"></a>
278<FONT color="green">275</FONT>        for (String elementName : elementNames) {<a name="line.275"></a>
279<FONT color="green">276</FONT>          elementName = HtmlLexer.canonicalName(elementName);<a name="line.276"></a>
280<FONT color="green">277</FONT>          skipIfEmpty.remove(elementName);<a name="line.277"></a>
281<FONT color="green">278</FONT>        }<a name="line.278"></a>
282<FONT color="green">279</FONT>        return this;<a name="line.279"></a>
283<FONT color="green">280</FONT>      }<a name="line.280"></a>
284<FONT color="green">281</FONT>    <a name="line.281"></a>
285<FONT color="green">282</FONT>      /**<a name="line.282"></a>
286<FONT color="green">283</FONT>       * Disallows the given elements from appearing without attributes.<a name="line.283"></a>
287<FONT color="green">284</FONT>       *<a name="line.284"></a>
288<FONT color="green">285</FONT>       * @see #DEFAULT_SKIP_IF_EMPTY<a name="line.285"></a>
289<FONT color="green">286</FONT>       * @see #allowWithoutAttributes<a name="line.286"></a>
290<FONT color="green">287</FONT>       */<a name="line.287"></a>
291<FONT color="green">288</FONT>      public HtmlPolicyBuilder disallowWithoutAttributes(String... elementNames) {<a name="line.288"></a>
292<FONT color="green">289</FONT>        invalidateCompiledState();<a name="line.289"></a>
293<FONT color="green">290</FONT>        for (String elementName : elementNames) {<a name="line.290"></a>
294<FONT color="green">291</FONT>          elementName = HtmlLexer.canonicalName(elementName);<a name="line.291"></a>
295<FONT color="green">292</FONT>          skipIfEmpty.add(elementName);<a name="line.292"></a>
296<FONT color="green">293</FONT>        }<a name="line.293"></a>
297<FONT color="green">294</FONT>        return this;<a name="line.294"></a>
298<FONT color="green">295</FONT>      }<a name="line.295"></a>
299<FONT color="green">296</FONT>    <a name="line.296"></a>
300<FONT color="green">297</FONT>      /**<a name="line.297"></a>
301<FONT color="green">298</FONT>       * Returns an object that lets you associate policies with the given<a name="line.298"></a>
302<FONT color="green">299</FONT>       * attributes, and allow them globally or on specific elements.<a name="line.299"></a>
303<FONT color="green">300</FONT>       */<a name="line.300"></a>
304<FONT color="green">301</FONT>      public AttributeBuilder allowAttributes(String... attributeNames) {<a name="line.301"></a>
305<FONT color="green">302</FONT>        ImmutableList.Builder&lt;String&gt; b = ImmutableList.builder();<a name="line.302"></a>
306<FONT color="green">303</FONT>        for (String attributeName : attributeNames) {<a name="line.303"></a>
307<FONT color="green">304</FONT>          b.add(HtmlLexer.canonicalName(attributeName));<a name="line.304"></a>
308<FONT color="green">305</FONT>        }<a name="line.305"></a>
309<FONT color="green">306</FONT>        return new AttributeBuilder(b.build());<a name="line.306"></a>
310<FONT color="green">307</FONT>      }<a name="line.307"></a>
311<FONT color="green">308</FONT>    <a name="line.308"></a>
312<FONT color="green">309</FONT>      /**<a name="line.309"></a>
313<FONT color="green">310</FONT>       * Reverse an earlier attribute {@link #allowAttributes allow}.<a name="line.310"></a>
314<FONT color="green">311</FONT>       * &lt;p&gt;<a name="line.311"></a>
315<FONT color="green">312</FONT>       * For this to have an effect you must call at least one of<a name="line.312"></a>
316<FONT color="green">313</FONT>       * {@link AttributeBuilder#globally} and {@link AttributeBuilder#onElements}.<a name="line.313"></a>
317<FONT color="green">314</FONT>       * &lt;p&gt;<a name="line.314"></a>
318<FONT color="green">315</FONT>       * Attributes are disallowed by default, so there is no need to call this<a name="line.315"></a>
319<FONT color="green">316</FONT>       * with a laundry list of attribute/element pairs.<a name="line.316"></a>
320<FONT color="green">317</FONT>       */<a name="line.317"></a>
321<FONT color="green">318</FONT>      public AttributeBuilder disallowAttributes(String... attributeNames) {<a name="line.318"></a>
322<FONT color="green">319</FONT>        return this.allowAttributes(attributeNames)<a name="line.319"></a>
323<FONT color="green">320</FONT>            .matching(AttributePolicy.REJECT_ALL_ATTRIBUTE_POLICY);<a name="line.320"></a>
324<FONT color="green">321</FONT>      }<a name="line.321"></a>
325<FONT color="green">322</FONT>    <a name="line.322"></a>
326<FONT color="green">323</FONT>    <a name="line.323"></a>
327<FONT color="green">324</FONT>      private HtmlPolicyBuilder allowAttributesGlobally(<a name="line.324"></a>
328<FONT color="green">325</FONT>          AttributePolicy policy, List&lt;String&gt; attributeNames) {<a name="line.325"></a>
329<FONT color="green">326</FONT>        invalidateCompiledState();<a name="line.326"></a>
330<FONT color="green">327</FONT>        for (String attributeName : attributeNames) {<a name="line.327"></a>
331<FONT color="green">328</FONT>          // We reinterpret the identity policy later via policy joining since its<a name="line.328"></a>
332<FONT color="green">329</FONT>          // the default passed from the policy-less method, but we don't do<a name="line.329"></a>
333<FONT color="green">330</FONT>          // anything here since we don't know until build() is called whether the<a name="line.330"></a>
334<FONT color="green">331</FONT>          // policy author wants to allow certain URL protocols or wants to deal<a name="line.331"></a>
335<FONT color="green">332</FONT>          // with styles.<a name="line.332"></a>
336<FONT color="green">333</FONT>          AttributePolicy oldPolicy = globalAttrPolicies.get(attributeName);<a name="line.333"></a>
337<FONT color="green">334</FONT>          globalAttrPolicies.put(<a name="line.334"></a>
338<FONT color="green">335</FONT>              attributeName, AttributePolicy.Util.join(oldPolicy, policy));<a name="line.335"></a>
339<FONT color="green">336</FONT>        }<a name="line.336"></a>
340<FONT color="green">337</FONT>        return this;<a name="line.337"></a>
341<FONT color="green">338</FONT>      }<a name="line.338"></a>
342<FONT color="green">339</FONT>    <a name="line.339"></a>
343<FONT color="green">340</FONT>      private HtmlPolicyBuilder allowAttributesOnElements(<a name="line.340"></a>
344<FONT color="green">341</FONT>          AttributePolicy policy, List&lt;String&gt; attributeNames,<a name="line.341"></a>
345<FONT color="green">342</FONT>          List&lt;String&gt; elementNames) {<a name="line.342"></a>
346<FONT color="green">343</FONT>        invalidateCompiledState();<a name="line.343"></a>
347<FONT color="green">344</FONT>        for (String elementName : elementNames) {<a name="line.344"></a>
348<FONT color="green">345</FONT>          Map&lt;String, AttributePolicy&gt; policies = attrPolicies.get(elementName);<a name="line.345"></a>
349<FONT color="green">346</FONT>          if (policies == null) {<a name="line.346"></a>
350<FONT color="green">347</FONT>            policies = Maps.newLinkedHashMap();<a name="line.347"></a>
351<FONT color="green">348</FONT>            attrPolicies.put(elementName, policies);<a name="line.348"></a>
352<FONT color="green">349</FONT>          }<a name="line.349"></a>
353<FONT color="green">350</FONT>          for (String attributeName : attributeNames) {<a name="line.350"></a>
354<FONT color="green">351</FONT>            AttributePolicy oldPolicy = policies.get(attributeName);<a name="line.351"></a>
355<FONT color="green">352</FONT>            policies.put(<a name="line.352"></a>
356<FONT color="green">353</FONT>                attributeName,<a name="line.353"></a>
357<FONT color="green">354</FONT>                AttributePolicy.Util.join(oldPolicy, policy));<a name="line.354"></a>
358<FONT color="green">355</FONT>          }<a name="line.355"></a>
359<FONT color="green">356</FONT>        }<a name="line.356"></a>
360<FONT color="green">357</FONT>        return this;<a name="line.357"></a>
361<FONT color="green">358</FONT>      }<a name="line.358"></a>
362<FONT color="green">359</FONT>    <a name="line.359"></a>
363<FONT color="green">360</FONT>      /**<a name="line.360"></a>
364<FONT color="green">361</FONT>       * Adds &lt;a href="http://en.wikipedia.org/wiki/Nofollow"&gt;&lt;code&gt;rel=nofollow&lt;/code&gt;&lt;/a&gt;<a name="line.361"></a>
365<FONT color="green">362</FONT>       * to links.<a name="line.362"></a>
366<FONT color="green">363</FONT>       */<a name="line.363"></a>
367<FONT color="green">364</FONT>      public HtmlPolicyBuilder requireRelNofollowOnLinks() {<a name="line.364"></a>
368<FONT color="green">365</FONT>        invalidateCompiledState();<a name="line.365"></a>
369<FONT color="green">366</FONT>        this.requireRelNofollowOnLinks = true;<a name="line.366"></a>
370<FONT color="green">367</FONT>        return this;<a name="line.367"></a>
371<FONT color="green">368</FONT>      }<a name="line.368"></a>
372<FONT color="green">369</FONT>    <a name="line.369"></a>
373<FONT color="green">370</FONT>      /**<a name="line.370"></a>
374<FONT color="green">371</FONT>       * Adds to the set of protocols that are allowed in URL attributes.<a name="line.371"></a>
375<FONT color="green">372</FONT>       * For each URL attribute that is allowed, we further constrain it by<a name="line.372"></a>
376<FONT color="green">373</FONT>       * only allowing the value through if it specifies no protocol, or if it<a name="line.373"></a>
377<FONT color="green">374</FONT>       * specifies one in the allowedProtocols white-list.<a name="line.374"></a>
378<FONT color="green">375</FONT>       * This is done regardless of whether any protocols have been allowed, so<a name="line.375"></a>
379<FONT color="green">376</FONT>       * allowing the attribute "href" globally with the identity policy but<a name="line.376"></a>
380<FONT color="green">377</FONT>       * not white-listing any protocols, effectively disallows the "href"<a name="line.377"></a>
381<FONT color="green">378</FONT>       * attribute globally.<a name="line.378"></a>
382<FONT color="green">379</FONT>       * &lt;p&gt;<a name="line.379"></a>
383<FONT color="green">380</FONT>       * Do not allow any &lt;code&gt;*script&lt;/code&gt; such as &lt;code&gt;javascript&lt;/code&gt;<a name="line.380"></a>
384<FONT color="green">381</FONT>       * protocols if you might use this policy with untrusted code.<a name="line.381"></a>
385<FONT color="green">382</FONT>       */<a name="line.382"></a>
386<FONT color="green">383</FONT>      public HtmlPolicyBuilder allowUrlProtocols(String... protocols) {<a name="line.383"></a>
387<FONT color="green">384</FONT>        invalidateCompiledState();<a name="line.384"></a>
388<FONT color="green">385</FONT>        // If there is at least one allowed protocol, then allow URLs and<a name="line.385"></a>
389<FONT color="green">386</FONT>        // add a filter that checks href and src values.<a name="line.386"></a>
390<FONT color="green">387</FONT>    <a name="line.387"></a>
391<FONT color="green">388</FONT>        // Do not allow href and srcs through otherwise, and only allow on images<a name="line.388"></a>
392<FONT color="green">389</FONT>        // and links.<a name="line.389"></a>
393<FONT color="green">390</FONT>        for (String protocol : protocols) {<a name="line.390"></a>
394<FONT color="green">391</FONT>          protocol = Strings.toLowerCase(protocol);<a name="line.391"></a>
395<FONT color="green">392</FONT>          allowedProtocols.add(protocol);<a name="line.392"></a>
396<FONT color="green">393</FONT>        }<a name="line.393"></a>
397<FONT color="green">394</FONT>        return this;<a name="line.394"></a>
398<FONT color="green">395</FONT>      }<a name="line.395"></a>
399<FONT color="green">396</FONT>    <a name="line.396"></a>
400<FONT color="green">397</FONT>      /**<a name="line.397"></a>
401<FONT color="green">398</FONT>       * Reverses a decision made by {@link #allowUrlProtocols}.<a name="line.398"></a>
402<FONT color="green">399</FONT>       */<a name="line.399"></a>
403<FONT color="green">400</FONT>      public HtmlPolicyBuilder disallowUrlProtocols(String... protocols) {<a name="line.400"></a>
404<FONT color="green">401</FONT>        invalidateCompiledState();<a name="line.401"></a>
405<FONT color="green">402</FONT>        for (String protocol : protocols) {<a name="line.402"></a>
406<FONT color="green">403</FONT>          protocol = Strings.toLowerCase(protocol);<a name="line.403"></a>
407<FONT color="green">404</FONT>          allowedProtocols.remove(protocol);<a name="line.404"></a>
408<FONT color="green">405</FONT>        }<a name="line.405"></a>
409<FONT color="green">406</FONT>        return this;<a name="line.406"></a>
410<FONT color="green">407</FONT>      }<a name="line.407"></a>
411<FONT color="green">408</FONT>    <a name="line.408"></a>
412<FONT color="green">409</FONT>      /**<a name="line.409"></a>
413<FONT color="green">410</FONT>       * A canned URL protocol policy that allows &lt;code&gt;http&lt;/code&gt;,<a name="line.410"></a>
414<FONT color="green">411</FONT>       * &lt;code&gt;https&lt;/code&gt;, and &lt;code&gt;mailto&lt;/code&gt;.<a name="line.411"></a>
415<FONT color="green">412</FONT>       */<a name="line.412"></a>
416<FONT color="green">413</FONT>      public HtmlPolicyBuilder allowStandardUrlProtocols() {<a name="line.413"></a>
417<FONT color="green">414</FONT>        return allowUrlProtocols("http", "https", "mailto");<a name="line.414"></a>
418<FONT color="green">415</FONT>      }<a name="line.415"></a>
419<FONT color="green">416</FONT>    <a name="line.416"></a>
420<FONT color="green">417</FONT>      /**<a name="line.417"></a>
421<FONT color="green">418</FONT>       * Convert &lt;code&gt;style="&amp;lt;CSS&amp;gt;"&lt;/code&gt; to sanitized CSS which allows<a name="line.418"></a>
422<FONT color="green">419</FONT>       * color, font-size, type-face, and other styling using the default schema;<a name="line.419"></a>
423<FONT color="green">420</FONT>       * but which does not allow content to escape its clipping context.<a name="line.420"></a>
424<FONT color="green">421</FONT>       */<a name="line.421"></a>
425<FONT color="green">422</FONT>      public HtmlPolicyBuilder allowStyling() {<a name="line.422"></a>
426<FONT color="green">423</FONT>        allowStyling(CssSchema.DEFAULT);<a name="line.423"></a>
427<FONT color="green">424</FONT>        return this;<a name="line.424"></a>
428<FONT color="green">425</FONT>      }<a name="line.425"></a>
429<FONT color="green">426</FONT>    <a name="line.426"></a>
430<FONT color="green">427</FONT>      /**<a name="line.427"></a>
431<FONT color="green">428</FONT>       * Convert &lt;code&gt;style="&amp;lt;CSS&amp;gt;"&lt;/code&gt; to sanitized CSS which allows<a name="line.428"></a>
432<FONT color="green">429</FONT>       * color, font-size, type-face, and other styling using the given schema.<a name="line.429"></a>
433<FONT color="green">430</FONT>       */<a name="line.430"></a>
434<FONT color="green">431</FONT>      public HtmlPolicyBuilder allowStyling(CssSchema whitelist) {<a name="line.431"></a>
435<FONT color="green">432</FONT>        invalidateCompiledState();<a name="line.432"></a>
436<FONT color="green">433</FONT>        allowAttributesGlobally(<a name="line.433"></a>
437<FONT color="green">434</FONT>            new StylingPolicy(whitelist), ImmutableList.of("style"));<a name="line.434"></a>
438<FONT color="green">435</FONT>        return this;<a name="line.435"></a>
439<FONT color="green">436</FONT>      }<a name="line.436"></a>
440<FONT color="green">437</FONT>    <a name="line.437"></a>
441<FONT color="green">438</FONT>      /**<a name="line.438"></a>
442<FONT color="green">439</FONT>       * Names of attributes from HTML 4 whose values are URLs.<a name="line.439"></a>
443<FONT color="green">440</FONT>       * Other attributes, e.g. &lt;code&gt;style&lt;/code&gt; may contain URLs even though<a name="line.440"></a>
444<FONT color="green">441</FONT>       * there values are not URLs.<a name="line.441"></a>
445<FONT color="green">442</FONT>       */<a name="line.442"></a>
446<FONT color="green">443</FONT>      private static final Set&lt;String&gt; URL_ATTRIBUTE_NAMES = ImmutableSet.of(<a name="line.443"></a>
447<FONT color="green">444</FONT>          "action", "archive", "background", "cite", "classid", "codebase", "data",<a name="line.444"></a>
448<FONT color="green">445</FONT>          "dsync", "formaction", "href", "icon", "longdesc", "manifest", "poster",<a name="line.445"></a>
449<FONT color="green">446</FONT>          "profile", "src", "srcset", "usemap");<a name="line.446"></a>
450<FONT color="green">447</FONT>    <a name="line.447"></a>
451<FONT color="green">448</FONT>      /**<a name="line.448"></a>
452<FONT color="green">449</FONT>       * Produces a policy based on the allow and disallow calls previously made.<a name="line.449"></a>
453<FONT color="green">450</FONT>       *<a name="line.450"></a>
454<FONT color="green">451</FONT>       * @param out receives calls to open only tags allowed by<a name="line.451"></a>
455<FONT color="green">452</FONT>       *      previous calls to this object.<a name="line.452"></a>
456<FONT color="green">453</FONT>       *      Typically a {@link HtmlStreamRenderer}.<a name="line.453"></a>
457<FONT color="green">454</FONT>       */<a name="line.454"></a>
458<FONT color="green">455</FONT>      public HtmlSanitizer.Policy build(HtmlStreamEventReceiver out) {<a name="line.455"></a>
459<FONT color="green">456</FONT>        return toFactory().apply(out);<a name="line.456"></a>
460<FONT color="green">457</FONT>      }<a name="line.457"></a>
461<FONT color="green">458</FONT>    <a name="line.458"></a>
462<FONT color="green">459</FONT>      /**<a name="line.459"></a>
463<FONT color="green">460</FONT>       * Produces a policy based on the allow and disallow calls previously made.<a name="line.460"></a>
464<FONT color="green">461</FONT>       *<a name="line.461"></a>
465<FONT color="green">462</FONT>       * @param out receives calls to open only tags allowed by<a name="line.462"></a>
466<FONT color="green">463</FONT>       *      previous calls to this object.<a name="line.463"></a>
467<FONT color="green">464</FONT>       *      Typically a {@link HtmlStreamRenderer}.<a name="line.464"></a>
468<FONT color="green">465</FONT>       * @param listener is notified of dropped tags and attributes so that<a name="line.465"></a>
469<FONT color="green">466</FONT>       *      intrusion detection systems can be alerted to questionable HTML.<a name="line.466"></a>
470<FONT color="green">467</FONT>       *      If {@code null} then no notifications are sent.<a name="line.467"></a>
471<FONT color="green">468</FONT>       * @param context if {@code (listener != null)} then the context value passed<a name="line.468"></a>
472<FONT color="green">469</FONT>       *      with alerts.  This can be used to let the listener know from which<a name="line.469"></a>
473<FONT color="green">470</FONT>       *      connection or request the questionable HTML was received.<a name="line.470"></a>
474<FONT color="green">471</FONT>       */<a name="line.471"></a>
475<FONT color="green">472</FONT>      public &lt;CTX&gt; HtmlSanitizer.Policy build(<a name="line.472"></a>
476<FONT color="green">473</FONT>          HtmlStreamEventReceiver out,<a name="line.473"></a>
477<FONT color="green">474</FONT>          @Nullable HtmlChangeListener&lt;? super CTX&gt; listener,<a name="line.474"></a>
478<FONT color="green">475</FONT>          @Nullable CTX context) {<a name="line.475"></a>
479<FONT color="green">476</FONT>        return toFactory().apply(out, listener, context);<a name="line.476"></a>
480<FONT color="green">477</FONT>      }<a name="line.477"></a>
481<FONT color="green">478</FONT>    <a name="line.478"></a>
482<FONT color="green">479</FONT>      /**<a name="line.479"></a>
483<FONT color="green">480</FONT>       * Like {@link #build} but can be reused to create many different policies<a name="line.480"></a>
484<FONT color="green">481</FONT>       * each backed by a different output channel.<a name="line.481"></a>
485<FONT color="green">482</FONT>       */<a name="line.482"></a>
486<FONT color="green">483</FONT>      public PolicyFactory toFactory() {<a name="line.483"></a>
487<FONT color="green">484</FONT>        ImmutableSet.Builder&lt;String&gt; textContainers = ImmutableSet.builder();<a name="line.484"></a>
488<FONT color="green">485</FONT>        for (Map.Entry&lt;String, Boolean&gt; textContainer<a name="line.485"></a>
489<FONT color="green">486</FONT>             : this.textContainers.entrySet()) {<a name="line.486"></a>
490<FONT color="green">487</FONT>          if (Boolean.TRUE.equals(textContainer.getValue())) {<a name="line.487"></a>
491<FONT color="green">488</FONT>            textContainers.add(textContainer.getKey());<a name="line.488"></a>
492<FONT color="green">489</FONT>          }<a name="line.489"></a>
493<FONT color="green">490</FONT>        }<a name="line.490"></a>
494<FONT color="green">491</FONT>        return new PolicyFactory(compilePolicies(), textContainers.build(),<a name="line.491"></a>
495<FONT color="green">492</FONT>                                 ImmutableMap.copyOf(globalAttrPolicies));<a name="line.492"></a>
496<FONT color="green">493</FONT>      }<a name="line.493"></a>
497<FONT color="green">494</FONT>    <a name="line.494"></a>
498<FONT color="green">495</FONT>      // Speed up subsequent builds by caching the compiled policies.<a name="line.495"></a>
499<FONT color="green">496</FONT>      private transient ImmutableMap&lt;String, ElementAndAttributePolicies&gt;<a name="line.496"></a>
500<FONT color="green">497</FONT>          compiledPolicies;<a name="line.497"></a>
501<FONT color="green">498</FONT>    <a name="line.498"></a>
502<FONT color="green">499</FONT>      /** Called by mutators to signal that any compiled policy is out-of-date. */<a name="line.499"></a>
503<FONT color="green">500</FONT>      private void invalidateCompiledState() {<a name="line.500"></a>
504<FONT color="green">501</FONT>        compiledPolicies = null;<a name="line.501"></a>
505<FONT color="green">502</FONT>      }<a name="line.502"></a>
506<FONT color="green">503</FONT>    <a name="line.503"></a>
507<FONT color="green">504</FONT>      private ImmutableMap&lt;String, ElementAndAttributePolicies&gt; compilePolicies() {<a name="line.504"></a>
508<FONT color="green">505</FONT>        if (compiledPolicies != null) { return compiledPolicies; }<a name="line.505"></a>
509<FONT color="green">506</FONT>    <a name="line.506"></a>
510<FONT color="green">507</FONT>        // Copy maps before normalizing in case builder is reused.<a name="line.507"></a>
511<FONT color="green">508</FONT>        Map&lt;String, ElementPolicy&gt; elPolicies<a name="line.508"></a>
512<FONT color="green">509</FONT>            = Maps.newLinkedHashMap(this.elPolicies);<a name="line.509"></a>
513<FONT color="green">510</FONT>        Map&lt;String, Map&lt;String, AttributePolicy&gt;&gt; attrPolicies<a name="line.510"></a>
514<FONT color="green">511</FONT>            = Maps.newLinkedHashMap(this.attrPolicies);<a name="line.511"></a>
515<FONT color="green">512</FONT>        for (Map.Entry&lt;String, Map&lt;String, AttributePolicy&gt;&gt; e :<a name="line.512"></a>
516<FONT color="green">513</FONT>             attrPolicies.entrySet()) {<a name="line.513"></a>
517<FONT color="green">514</FONT>          e.setValue(Maps.newLinkedHashMap(e.getValue()));<a name="line.514"></a>
518<FONT color="green">515</FONT>        }<a name="line.515"></a>
519<FONT color="green">516</FONT>        Map&lt;String, AttributePolicy&gt; globalAttrPolicies<a name="line.516"></a>
520<FONT color="green">517</FONT>            = Maps.newLinkedHashMap(this.globalAttrPolicies);<a name="line.517"></a>
521<FONT color="green">518</FONT>        Set&lt;String&gt; allowedProtocols = ImmutableSet.copyOf(this.allowedProtocols);<a name="line.518"></a>
522<FONT color="green">519</FONT>    <a name="line.519"></a>
523<FONT color="green">520</FONT>        // Implement requireRelNofollowOnLinks<a name="line.520"></a>
524<FONT color="green">521</FONT>        if (requireRelNofollowOnLinks) {<a name="line.521"></a>
525<FONT color="green">522</FONT>          ElementPolicy linkPolicy = elPolicies.get("a");<a name="line.522"></a>
526<FONT color="green">523</FONT>          if (linkPolicy == null) {<a name="line.523"></a>
527<FONT color="green">524</FONT>            linkPolicy = ElementPolicy.REJECT_ALL_ELEMENT_POLICY;<a name="line.524"></a>
528<FONT color="green">525</FONT>          }<a name="line.525"></a>
529<FONT color="green">526</FONT>          elPolicies.put(<a name="line.526"></a>
530<FONT color="green">527</FONT>              "a",<a name="line.527"></a>
531<FONT color="green">528</FONT>              ElementPolicy.Util.join(<a name="line.528"></a>
532<FONT color="green">529</FONT>                  linkPolicy,<a name="line.529"></a>
533<FONT color="green">530</FONT>                  new ElementPolicy() {<a name="line.530"></a>
534<FONT color="green">531</FONT>                    public String apply(String elementName, List&lt;String&gt; attrs) {<a name="line.531"></a>
535<FONT color="green">532</FONT>                      for (int i = 0, n = attrs.size(); i &lt; n; i += 2) {<a name="line.532"></a>
536<FONT color="green">533</FONT>                        if ("href".equals(attrs.get(i))) {<a name="line.533"></a>
537<FONT color="green">534</FONT>                          attrs.add("rel");<a name="line.534"></a>
538<FONT color="green">535</FONT>                          attrs.add("nofollow");<a name="line.535"></a>
539<FONT color="green">536</FONT>                          break;<a name="line.536"></a>
540<FONT color="green">537</FONT>                        }<a name="line.537"></a>
541<FONT color="green">538</FONT>                      }<a name="line.538"></a>
542<FONT color="green">539</FONT>                      return elementName;<a name="line.539"></a>
543<FONT color="green">540</FONT>                    }<a name="line.540"></a>
544<FONT color="green">541</FONT>                  }));<a name="line.541"></a>
545<FONT color="green">542</FONT>        }<a name="line.542"></a>
546<FONT color="green">543</FONT>    <a name="line.543"></a>
547<FONT color="green">544</FONT>        // Implement protocol policies.<a name="line.544"></a>
548<FONT color="green">545</FONT>        // For each URL attribute that is allowed, we further constrain it by<a name="line.545"></a>
549<FONT color="green">546</FONT>        // only allowing the value through if it specifies no protocol, or if it<a name="line.546"></a>
550<FONT color="green">547</FONT>        // specifies one in the allowedProtocols white-list.<a name="line.547"></a>
551<FONT color="green">548</FONT>        // This is done regardless of whether any protocols have been allowed, so<a name="line.548"></a>
552<FONT color="green">549</FONT>        // allowing the attribute "href" globally with the identity policy but<a name="line.549"></a>
553<FONT color="green">550</FONT>        // not white-listing any protocols, effectively disallows the "href"<a name="line.550"></a>
554<FONT color="green">551</FONT>        // attribute globally.<a name="line.551"></a>
555<FONT color="green">552</FONT>        {<a name="line.552"></a>
556<FONT color="green">553</FONT>          AttributePolicy urlAttributePolicy;<a name="line.553"></a>
557<FONT color="green">554</FONT>          if (allowedProtocols.size() == 3<a name="line.554"></a>
558<FONT color="green">555</FONT>              &amp;&amp; allowedProtocols.contains("mailto")<a name="line.555"></a>
559<FONT color="green">556</FONT>              &amp;&amp; allowedProtocols.contains("http")<a name="line.556"></a>
560<FONT color="green">557</FONT>              &amp;&amp; allowedProtocols.contains("https")) {<a name="line.557"></a>
561<FONT color="green">558</FONT>            urlAttributePolicy = StandardUrlAttributePolicy.INSTANCE;<a name="line.558"></a>
562<FONT color="green">559</FONT>          } else {<a name="line.559"></a>
563<FONT color="green">560</FONT>            urlAttributePolicy = new FilterUrlByProtocolAttributePolicy(<a name="line.560"></a>
564<FONT color="green">561</FONT>                allowedProtocols);<a name="line.561"></a>
565<FONT color="green">562</FONT>          }<a name="line.562"></a>
566<FONT color="green">563</FONT>          Set&lt;String&gt; toGuard = Sets.newLinkedHashSet(URL_ATTRIBUTE_NAMES);<a name="line.563"></a>
567<FONT color="green">564</FONT>          for (String urlAttributeName : URL_ATTRIBUTE_NAMES) {<a name="line.564"></a>
568<FONT color="green">565</FONT>            if (globalAttrPolicies.containsKey(urlAttributeName)) {<a name="line.565"></a>
569<FONT color="green">566</FONT>              toGuard.remove(urlAttributeName);<a name="line.566"></a>
570<FONT color="green">567</FONT>              globalAttrPolicies.put(urlAttributeName, AttributePolicy.Util.join(<a name="line.567"></a>
571<FONT color="green">568</FONT>                  urlAttributePolicy, globalAttrPolicies.get(urlAttributeName)));<a name="line.568"></a>
572<FONT color="green">569</FONT>            }<a name="line.569"></a>
573<FONT color="green">570</FONT>          }<a name="line.570"></a>
574<FONT color="green">571</FONT>          // Implement guards not implemented on global policies in the per-element<a name="line.571"></a>
575<FONT color="green">572</FONT>          // policy maps.<a name="line.572"></a>
576<FONT color="green">573</FONT>          for (Map.Entry&lt;String, Map&lt;String, AttributePolicy&gt;&gt; e<a name="line.573"></a>
577<FONT color="green">574</FONT>               : attrPolicies.entrySet()) {<a name="line.574"></a>
578<FONT color="green">575</FONT>            Map&lt;String, AttributePolicy&gt; policies = e.getValue();<a name="line.575"></a>
579<FONT color="green">576</FONT>            for (String urlAttributeName : toGuard) {<a name="line.576"></a>
580<FONT color="green">577</FONT>              if (policies.containsKey(urlAttributeName)) {<a name="line.577"></a>
581<FONT color="green">578</FONT>                policies.put(urlAttributeName, AttributePolicy.Util.join(<a name="line.578"></a>
582<FONT color="green">579</FONT>                    urlAttributePolicy, policies.get(urlAttributeName)));<a name="line.579"></a>
583<FONT color="green">580</FONT>              }<a name="line.580"></a>
584<FONT color="green">581</FONT>            }<a name="line.581"></a>
585<FONT color="green">582</FONT>          }<a name="line.582"></a>
586<FONT color="green">583</FONT>        }<a name="line.583"></a>
587<FONT color="green">584</FONT>    <a name="line.584"></a>
588<FONT color="green">585</FONT>        ImmutableMap.Builder&lt;String, ElementAndAttributePolicies&gt; policiesBuilder<a name="line.585"></a>
589<FONT color="green">586</FONT>            = ImmutableMap.builder();<a name="line.586"></a>
590<FONT color="green">587</FONT>        for (Map.Entry&lt;String, ElementPolicy&gt; e : elPolicies.entrySet()) {<a name="line.587"></a>
591<FONT color="green">588</FONT>          String elementName = e.getKey();<a name="line.588"></a>
592<FONT color="green">589</FONT>          ElementPolicy elPolicy = e.getValue();<a name="line.589"></a>
593<FONT color="green">590</FONT>          if (ElementPolicy.REJECT_ALL_ELEMENT_POLICY.equals(elPolicy)) {<a name="line.590"></a>
594<FONT color="green">591</FONT>            continue;<a name="line.591"></a>
595<FONT color="green">592</FONT>          }<a name="line.592"></a>
596<FONT color="green">593</FONT>    <a name="line.593"></a>
597<FONT color="green">594</FONT>          Map&lt;String, AttributePolicy&gt; elAttrPolicies<a name="line.594"></a>
598<FONT color="green">595</FONT>              = attrPolicies.get(elementName);<a name="line.595"></a>
599<FONT color="green">596</FONT>          if (elAttrPolicies == null) { elAttrPolicies = ImmutableMap.of(); }<a name="line.596"></a>
600<FONT color="green">597</FONT>          ImmutableMap.Builder&lt;String, AttributePolicy&gt; attrs<a name="line.597"></a>
601<FONT color="green">598</FONT>              = ImmutableMap.builder();<a name="line.598"></a>
602<FONT color="green">599</FONT>          for (Map.Entry&lt;String, AttributePolicy&gt; ape : elAttrPolicies.entrySet()) {<a name="line.599"></a>
603<FONT color="green">600</FONT>            String attributeName = ape.getKey();<a name="line.600"></a>
604<FONT color="green">601</FONT>            // Handle below so we don't end up putting the same key into the map<a name="line.601"></a>
605<FONT color="green">602</FONT>            // twice.  ImmutableMap.Builder hates that.<a name="line.602"></a>
606<FONT color="green">603</FONT>            if (globalAttrPolicies.containsKey(attributeName)) { continue; }<a name="line.603"></a>
607<FONT color="green">604</FONT>            AttributePolicy policy = ape.getValue();<a name="line.604"></a>
608<FONT color="green">605</FONT>            if (!AttributePolicy.REJECT_ALL_ATTRIBUTE_POLICY.equals(policy)) {<a name="line.605"></a>
609<FONT color="green">606</FONT>              attrs.put(attributeName, policy);<a name="line.606"></a>
610<FONT color="green">607</FONT>            }<a name="line.607"></a>
611<FONT color="green">608</FONT>          }<a name="line.608"></a>
612<FONT color="green">609</FONT>          for (Map.Entry&lt;String, AttributePolicy&gt; ape<a name="line.609"></a>
613<FONT color="green">610</FONT>               : globalAttrPolicies.entrySet()) {<a name="line.610"></a>
614<FONT color="green">611</FONT>            String attributeName = ape.getKey();<a name="line.611"></a>
615<FONT color="green">612</FONT>            AttributePolicy policy = AttributePolicy.Util.join(<a name="line.612"></a>
616<FONT color="green">613</FONT>                elAttrPolicies.get(attributeName), ape.getValue());<a name="line.613"></a>
617<FONT color="green">614</FONT>            if (!AttributePolicy.REJECT_ALL_ATTRIBUTE_POLICY.equals(policy)) {<a name="line.614"></a>
618<FONT color="green">615</FONT>              attrs.put(attributeName, policy);<a name="line.615"></a>
619<FONT color="green">616</FONT>            }<a name="line.616"></a>
620<FONT color="green">617</FONT>          }<a name="line.617"></a>
621<FONT color="green">618</FONT>    <a name="line.618"></a>
622<FONT color="green">619</FONT>          policiesBuilder.put(<a name="line.619"></a>
623<FONT color="green">620</FONT>              elementName,<a name="line.620"></a>
624<FONT color="green">621</FONT>              new ElementAndAttributePolicies(<a name="line.621"></a>
625<FONT color="green">622</FONT>                  elementName,<a name="line.622"></a>
626<FONT color="green">623</FONT>                  elPolicy, attrs.build(), skipIfEmpty.contains(elementName)));<a name="line.623"></a>
627<FONT color="green">624</FONT>        }<a name="line.624"></a>
628<FONT color="green">625</FONT>        return compiledPolicies = policiesBuilder.build();<a name="line.625"></a>
629<FONT color="green">626</FONT>      }<a name="line.626"></a>
630<FONT color="green">627</FONT>    <a name="line.627"></a>
631<FONT color="green">628</FONT>      /**<a name="line.628"></a>
632<FONT color="green">629</FONT>       * Builds the relationship between attributes, the values that they may have,<a name="line.629"></a>
633<FONT color="green">630</FONT>       * and the elements on which they may appear.<a name="line.630"></a>
634<FONT color="green">631</FONT>       *<a name="line.631"></a>
635<FONT color="green">632</FONT>       * @author Mike Samuel<a name="line.632"></a>
636<FONT color="green">633</FONT>       */<a name="line.633"></a>
637<FONT color="green">634</FONT>      public final class AttributeBuilder {<a name="line.634"></a>
638<FONT color="green">635</FONT>        private final List&lt;String&gt; attributeNames;<a name="line.635"></a>
639<FONT color="green">636</FONT>        private AttributePolicy policy = AttributePolicy.IDENTITY_ATTRIBUTE_POLICY;<a name="line.636"></a>
640<FONT color="green">637</FONT>    <a name="line.637"></a>
641<FONT color="green">638</FONT>        AttributeBuilder(List&lt;? extends String&gt; attributeNames) {<a name="line.638"></a>
642<FONT color="green">639</FONT>          this.attributeNames = ImmutableList.copyOf(attributeNames);<a name="line.639"></a>
643<FONT color="green">640</FONT>        }<a name="line.640"></a>
644<FONT color="green">641</FONT>    <a name="line.641"></a>
645<FONT color="green">642</FONT>        /**<a name="line.642"></a>
646<FONT color="green">643</FONT>         * Filters and/or transforms the attribute values<a name="line.643"></a>
647<FONT color="green">644</FONT>         * allowed by later {@code allow*} calls.<a name="line.644"></a>
648<FONT color="green">645</FONT>         * Multiple calls to {@code matching} are combined so that the policies<a name="line.645"></a>
649<FONT color="green">646</FONT>         * receive the value in order, each seeing the value after any<a name="line.646"></a>
650<FONT color="green">647</FONT>         * transformation by a previous policy.<a name="line.647"></a>
651<FONT color="green">648</FONT>         */<a name="line.648"></a>
652<FONT color="green">649</FONT>        public AttributeBuilder matching(AttributePolicy policy) {<a name="line.649"></a>
653<FONT color="green">650</FONT>          this.policy = AttributePolicy.Util.join(this.policy, policy);<a name="line.650"></a>
654<FONT color="green">651</FONT>          return this;<a name="line.651"></a>
655<FONT color="green">652</FONT>        }<a name="line.652"></a>
656<FONT color="green">653</FONT>    <a name="line.653"></a>
657<FONT color="green">654</FONT>        /**<a name="line.654"></a>
658<FONT color="green">655</FONT>         * Restrict the values allowed by later {@code allow*} calls to those<a name="line.655"></a>
659<FONT color="green">656</FONT>         * matching the pattern.<a name="line.656"></a>
660<FONT color="green">657</FONT>         * Multiple calls to {@code matching} are combined to restrict to the<a name="line.657"></a>
661<FONT color="green">658</FONT>         * intersection of possible matched values.<a name="line.658"></a>
662<FONT color="green">659</FONT>         */<a name="line.659"></a>
663<FONT color="green">660</FONT>        public AttributeBuilder matching(final Pattern pattern) {<a name="line.660"></a>
664<FONT color="green">661</FONT>          return matching(new AttributePolicy() {<a name="line.661"></a>
665<FONT color="green">662</FONT>            public @Nullable String apply(<a name="line.662"></a>
666<FONT color="green">663</FONT>                String elementName, String attributeName, String value) {<a name="line.663"></a>
667<FONT color="green">664</FONT>              return pattern.matcher(value).matches() ? value : null;<a name="line.664"></a>
668<FONT color="green">665</FONT>            }<a name="line.665"></a>
669<FONT color="green">666</FONT>          });<a name="line.666"></a>
670<FONT color="green">667</FONT>        }<a name="line.667"></a>
671<FONT color="green">668</FONT>    <a name="line.668"></a>
672<FONT color="green">669</FONT>        /**<a name="line.669"></a>
673<FONT color="green">670</FONT>         * Restrict the values allowed by later {@code allow*} calls to those<a name="line.670"></a>
674<FONT color="green">671</FONT>         * matching the given predicate.<a name="line.671"></a>
675<FONT color="green">672</FONT>         * Multiple calls to {@code matching} are combined to restrict to the<a name="line.672"></a>
676<FONT color="green">673</FONT>         * intersection of possible matched values.<a name="line.673"></a>
677<FONT color="green">674</FONT>         */<a name="line.674"></a>
678<FONT color="green">675</FONT>        public AttributeBuilder matching(<a name="line.675"></a>
679<FONT color="green">676</FONT>            final Predicate&lt;? super String&gt; filter) {<a name="line.676"></a>
680<FONT color="green">677</FONT>          return matching(new AttributePolicy() {<a name="line.677"></a>
681<FONT color="green">678</FONT>            public @Nullable String apply(<a name="line.678"></a>
682<FONT color="green">679</FONT>                String elementName, String attributeName, String value) {<a name="line.679"></a>
683<FONT color="green">680</FONT>              return filter.apply(value) ? value : null;<a name="line.680"></a>
684<FONT color="green">681</FONT>            }<a name="line.681"></a>
685<FONT color="green">682</FONT>          });<a name="line.682"></a>
686<FONT color="green">683</FONT>        }<a name="line.683"></a>
687<FONT color="green">684</FONT>    <a name="line.684"></a>
688<FONT color="green">685</FONT>        /**<a name="line.685"></a>
689<FONT color="green">686</FONT>         * Restrict the values allowed by later {@code allow*} calls to those<a name="line.686"></a>
690<FONT color="green">687</FONT>         * supplied.<a name="line.687"></a>
691<FONT color="green">688</FONT>         * Multiple calls to {@code matching} are combined to restrict to the<a name="line.688"></a>
692<FONT color="green">689</FONT>         * intersection of possible matched values.<a name="line.689"></a>
693<FONT color="green">690</FONT>         */<a name="line.690"></a>
694<FONT color="green">691</FONT>        public AttributeBuilder matching(<a name="line.691"></a>
695<FONT color="green">692</FONT>            boolean ignoreCase, String... allowedValues) {<a name="line.692"></a>
696<FONT color="green">693</FONT>          return matching(ignoreCase, ImmutableSet.copyOf(allowedValues));<a name="line.693"></a>
697<FONT color="green">694</FONT>        }<a name="line.694"></a>
698<FONT color="green">695</FONT>    <a name="line.695"></a>
699<FONT color="green">696</FONT>        /**<a name="line.696"></a>
700<FONT color="green">697</FONT>         * Restrict the values allowed by later {@code allow*} calls to those<a name="line.697"></a>
701<FONT color="green">698</FONT>         * supplied.<a name="line.698"></a>
702<FONT color="green">699</FONT>         * Multiple calls to {@code matching} are combined to restrict to the<a name="line.699"></a>
703<FONT color="green">700</FONT>         * intersection of possible matched values.<a name="line.700"></a>
704<FONT color="green">701</FONT>         */<a name="line.701"></a>
705<FONT color="green">702</FONT>        public AttributeBuilder matching(<a name="line.702"></a>
706<FONT color="green">703</FONT>            final boolean ignoreCase, Set&lt;? extends String&gt; allowedValues) {<a name="line.703"></a>
707<FONT color="green">704</FONT>          final ImmutableSet&lt;String&gt; allowed = ImmutableSet.copyOf(allowedValues);<a name="line.704"></a>
708<FONT color="green">705</FONT>          return matching(new AttributePolicy() {<a name="line.705"></a>
709<FONT color="green">706</FONT>            public @Nullable String apply(<a name="line.706"></a>
710<FONT color="green">707</FONT>                String elementName, String attributeName, String value) {<a name="line.707"></a>
711<FONT color="green">708</FONT>              if (ignoreCase) { value = Strings.toLowerCase(value); }<a name="line.708"></a>
712<FONT color="green">709</FONT>              return allowed.contains(value) ? value : null;<a name="line.709"></a>
713<FONT color="green">710</FONT>            }<a name="line.710"></a>
714<FONT color="green">711</FONT>          });<a name="line.711"></a>
715<FONT color="green">712</FONT>        }<a name="line.712"></a>
716<FONT color="green">713</FONT>    <a name="line.713"></a>
717<FONT color="green">714</FONT>        /**<a name="line.714"></a>
718<FONT color="green">715</FONT>         * Allows the given attributes on any elements but filters the<a name="line.715"></a>
719<FONT color="green">716</FONT>         * attributes' values based on previous calls to {@code matching(...)}.<a name="line.716"></a>
720<FONT color="green">717</FONT>         * Global attribute policies are applied after element specific policies.<a name="line.717"></a>
721<FONT color="green">718</FONT>         * Be careful of using this with attributes like &lt;code&gt;type&lt;/code&gt; which<a name="line.718"></a>
722<FONT color="green">719</FONT>         * have different meanings on different attributes.<a name="line.719"></a>
723<FONT color="green">720</FONT>         * Also be careful of allowing globally attributes like &lt;code&gt;href&lt;/code&gt;<a name="line.720"></a>
724<FONT color="green">721</FONT>         * which can have more far-reaching effects on tags like<a name="line.721"></a>
725<FONT color="green">722</FONT>         * &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; than on<a name="line.722"></a>
726<FONT color="green">723</FONT>         * &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; because in the former, they have an effect without<a name="line.723"></a>
727<FONT color="green">724</FONT>         * user interaction and can change the behavior of the current page.<a name="line.724"></a>
728<FONT color="green">725</FONT>         */<a name="line.725"></a>
729<FONT color="green">726</FONT>        public HtmlPolicyBuilder globally() {<a name="line.726"></a>
730<FONT color="green">727</FONT>          return HtmlPolicyBuilder.this.allowAttributesGlobally(<a name="line.727"></a>
731<FONT color="green">728</FONT>              policy, attributeNames);<a name="line.728"></a>
732<FONT color="green">729</FONT>        }<a name="line.729"></a>
733<FONT color="green">730</FONT>    <a name="line.730"></a>
734<FONT color="green">731</FONT>        /**<a name="line.731"></a>
735<FONT color="green">732</FONT>         * Allows the named attributes on the given elements but filters the<a name="line.732"></a>
736<FONT color="green">733</FONT>         * attributes' values based on previous calls to {@code matching(...)}.<a name="line.733"></a>
737<FONT color="green">734</FONT>         */<a name="line.734"></a>
738<FONT color="green">735</FONT>        public HtmlPolicyBuilder onElements(String... elementNames) {<a name="line.735"></a>
739<FONT color="green">736</FONT>          ImmutableList.Builder&lt;String&gt; b = ImmutableList.builder();<a name="line.736"></a>
740<FONT color="green">737</FONT>          for (String elementName : elementNames) {<a name="line.737"></a>
741<FONT color="green">738</FONT>            b.add(HtmlLexer.canonicalName(elementName));<a name="line.738"></a>
742<FONT color="green">739</FONT>          }<a name="line.739"></a>
743<FONT color="green">740</FONT>          return HtmlPolicyBuilder.this.allowAttributesOnElements(<a name="line.740"></a>
744<FONT color="green">741</FONT>              policy, attributeNames, b.build());<a name="line.741"></a>
745<FONT color="green">742</FONT>        }<a name="line.742"></a>
746<FONT color="green">743</FONT>      }<a name="line.743"></a>
747<FONT color="green">744</FONT>    }<a name="line.744"></a>
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808</PRE>
809</BODY>
810</HTML>
811