@@ -119,6 +119,11 @@ class HTMLSanitizerMixin(object):
119119 'mailto' , 'news' , 'gopher' , 'nntp' , 'telnet' , 'webcal' ,
120120 'xmpp' , 'callto' , 'feed' , 'urn' , 'aim' , 'rsync' , 'tag' ,
121121 'ssh' , 'sftp' , 'rtsp' , 'afs' ]
122+
123+
124+ # block elements whose contents will be stripped completely if we we are
125+ # stripping tokens during sanitization.
126+ unacceptable_block_elements = [ 'script' , 'style' ]
122127
123128 # subclasses may define their own versions of these constants
124129 allowed_elements = acceptable_elements + mathml_elements + svg_elements
@@ -139,7 +144,7 @@ class HTMLSanitizerMixin(object):
139144 # => <script> do_nasty_stuff() </script>
140145 # sanitize_html('<a href="javascript: sucker();">Click here for $100</a>')
141146 # => <a>Click here for $100</a>
142- def sanitize_token (self , token ):
147+ def sanitize_token (self , token , strip_tokens = False ):
143148 if token ["type" ] in (tokenTypes ["StartTag" ], tokenTypes ["EndTag" ],
144149 tokenTypes ["EmptyTag" ]):
145150 if token ["name" ] in self .allowed_elements :
@@ -172,6 +177,8 @@ def sanitize_token(self, token):
172177 token ["data" ] = [[name ,val ] for name ,val in attrs .items ()]
173178 return token
174179 else :
180+ if strip_tokens :
181+ return None
175182 if token ["type" ] == tokenTypes ["EndTag" ]:
176183 token ["data" ] = "</%s>" % token ["name" ]
177184 elif token ["data" ]:
@@ -216,15 +223,32 @@ def sanitize_css(self, style):
216223 return ' ' .join (clean )
217224
218225class HTMLSanitizer (HTMLTokenizer , HTMLSanitizerMixin ):
226+ # strip tokens instead of escaping them
227+ strip_tokens = False
228+
219229 def __init__ (self , stream , encoding = None , parseMeta = True , useChardet = True ,
220230 lowercaseElementName = False , lowercaseAttrName = False ):
221231 #Change case matching defaults as we only output lowercase html anyway
222232 #This solution doesn't seem ideal...
223233 HTMLTokenizer .__init__ (self , stream , encoding , parseMeta , useChardet ,
224234 lowercaseElementName , lowercaseAttrName )
235+ # flag to indicate if stripping is going on or not
236+ self .stripping = 0
225237
226238 def __iter__ (self ):
227239 for token in HTMLTokenizer .__iter__ (self ):
228- token = self .sanitize_token (token )
229- if token :
230- yield token
240+ # if its a start tag and is a risky block element (e.g. script), we
241+ # indicate that we are in striping mode. Its a counter which allows us
242+ # to handle nested risky block elements
243+ if self .strip_tokens and token ["type" ] in ["StartTag" , "EndTag" ] \
244+ and token ["name" ].lower () in HTMLSanitizerMixin .unacceptable_block_elements :
245+ if token ["type" ] == "StartTag" :
246+ self .stripping += 1
247+ elif token ["type" ] == "EndTag" :
248+ self .stripping -= 1
249+
250+ # Only yield tokens if we are not in stripping mode
251+ if self .stripping < 1 :
252+ token = self .sanitize_token (token , self .strip_tokens )
253+ if token :
254+ yield token
0 commit comments