Reviewed by Darin.
[WebKit-https.git] / WebKitTools / iExploder / htdocs / iexploder.cgi
1 #!/usr/bin/ruby
2 # iExploder - Generates bad HTML files to perform QA for web browsers.
3 # Developed for the Mozilla Foundation.
4 #####################
5 #
6 # Copyright (c) 2005 Thomas Stromberg <thomas%stromberg.org>
7
8 # This software is provided 'as-is', without any express or implied warranty.
9 # In no event will the authors be held liable for any damages arising from the
10 # use of this software.
11
12 # Permission is granted to anyone to use this software for any purpose,
13 # including commercial applications, and to alter it and redistribute it
14 # freely, subject to the following restrictions:
15
16 # 1. The origin of this software must not be misrepresented; you must not
17 # claim that you wrote the original software. If you use this software in a
18 # product, an acknowledgment in the product documentation would be appreciated
19 # but is not required.
20
21 # 2. Altered source versions must be plainly marked as such, and must not be
22 # misrepresented as being the original software.
23
24 # 3. This notice may not be removed or altered from any source distribution.
25
26 # 4. Any bug reports, patches, or other publications which are based on the 
27 # usage of iExploder must reference iExploder as the source of the discovery.
28
29
30 require 'cgi';
31
32 $VERSION = "1.2";
33 $maxTags = 32;
34 $maxAttrs = 4;
35 $maxCSS = 5;
36 $mangledTagTotal = 0
37
38
39 def readTagFile(filename)
40     list = Array.new
41     File.new(filename).readlines.each { |line|
42         line.chop!
43         
44         # Don't include comments.
45         if (line !~ /^# /) && (line.length > 0)
46             list << line
47         end
48     }
49     return  list
50 end
51
52 # based on make_up_value, essentially.
53 def inventValue
54     value = rand(19);
55     case value
56     when 1..3 then return ($htmlValues[rand($htmlValues.length)])
57     when 4..5 then return ($htmlValues[rand($htmlValues.length)] + inventValue())
58     when 6 then return ($htmlValues[rand($htmlValues.length)] + "//" + inventValue())
59     when 7 then return ''
60     when 8..10 then return rand(255).chr * (rand(256)+8)
61     when 11 then return rand(255).chr * (rand(2048)+8)
62     when 12 then return "#" + rand(999999).to_s
63     when 13 then return rand(999999).to_s + "%"
64     when 14..15 then return "&" + rand(999999).to_s + ";"
65         # filters
66     when 16 then
67         return inventValue() + "=" + inventValue()
68         
69     when 17 then return inventValue() + "," + inventValue()
70     else
71         if rand(5) > 3
72             return "-" + rand(999999).to_s
73         else
74             return rand(999999).to_s
75         end
76     end
77 end
78
79 # based on make_up_value, essentially.
80 def inventCssValue(tag)
81     value = rand(23);
82     case value
83     when 1..10 then return $cssValues[rand($cssValues.length)]
84     when 11 then return ''
85     when 12 then return rand(255).chr * (rand(8192)+8)
86     when 13
87         length = rand(1024) + 8
88         return (rand(255).chr * length) + " " + (rand(255).chr * length) + " " + (rand(255).chr * length)
89     when 14 then return (rand(255).chr * (rand(1024)+3)) + "px"
90     when 15 then return (rand(255).chr * (rand(1024)+3)) + "em"
91     when 16 then return "url(" + inventValue() + ")"
92     when 17..18 then return "#" + rand(999999999).to_s
93     when 19 then return "-" + rand(99999999).to_s
94     else return rand(99999999).to_s;
95     end
96 end
97
98
99 def mangleTag(tag)
100     $mangledTagTotal += 1
101     out = ''
102         
103     # 20% chance of closing a tag instead of opening it.
104     if rand(10) > 8
105         out = "</" + tag + ">"
106         return out
107     end
108     
109     # we're opening it.
110     out = "<" + tag
111     
112     # forgot the space between the tag and the attributes
113     if rand(15) > 1
114         out << ' '
115     end
116     
117     attrNum = rand($maxAttrs) + 1
118     
119     1.upto(attrNum) {
120         attr = $htmlAttr[rand($htmlAttr.length)]
121         
122         out << attr
123         
124         # 7.5% of the time we skip the = sign. Don't prefix it
125         # if the attribute ends with a ( however.
126         
127         
128         if rand(15) > 1
129             out << '='
130         end
131         
132         # sometimes quote it, sometimes not. I doubt the importance
133         # of this test, but mangleme-1.2 added it, and adding more
134         # random-ness never hurt anything but time. I'll do it less often.
135         
136         quote = rand(2)
137         if (quote > 1)
138             out << "\""
139         end
140         
141         out << inventValue()
142         
143         # end the quote when you are done
144         if (quote > 1)
145             out << "\" "
146         end
147         
148         # 5% chance we skip the space at the end of the name
149         if rand(20) > 1
150             out << ' '
151         end
152         
153     }
154     
155     # CSS styles!
156     if rand(4) > 1
157         out << " style=\""
158         1.upto(rand($maxCSS)+1) {
159             out << $cssTags[rand($cssTags.length)]
160             
161             # very small chance we let the tag run on.
162             if rand(50) > 1
163                 out << ": "
164             end
165             
166             out << inventCssValue(tag)
167             # we almost always put the ; there.
168             if rand(50) > 1
169                 out << '; '
170             end
171         }
172         out << "\""
173     end
174     
175     # support our local troops!    
176     if ($paramSubTestNum > 0) && ($paramSubTestNum != $mangledTagTotal) 
177         if tag =~ /html|body|head/
178                 return '<' + tag + '>'
179         else
180             return '<subtest-ignored>'
181         end
182     end
183     
184     out << ">\n"
185 end
186
187 # These if statements are so that mod_ruby doesn't have to reload the files
188 # each time
189
190 if (! $cssTags)
191     $cssTags = readTagFile('cssproperties.in');
192 end
193
194 if (! $htmlTags)
195     $htmlTags = readTagFile('htmltags.in');
196 end
197 if (! $htmlAttr)
198     $htmlAttr = readTagFile('htmlattrs.in');
199 end
200
201 if (! $htmlValues)
202     $htmlValues = readTagFile('htmlvalues.in');
203 end
204
205 if (! $cssValues)
206     $cssValues = readTagFile('cssvalues.in');
207 end
208
209 ### THE INTERACTION ##################################
210 cgi = CGI.new("html4");
211
212 $paramTestNum = cgi.params['test'][0].to_i
213 $paramRandomMode = cgi.params['random'][0]
214 $paramLookupMode = cgi.params['lookup'][0]
215 $paramSubTestNum = cgi.params['subtest'][0].to_i || 0
216
217 if ($paramTestNum)
218     srand($paramTestNum)
219 else
220     srand
221 end
222
223 if $paramSubTestNum
224     if $paramSubTestNum > $maxTags
225         $paramSubTestNum = 0
226         $paramLookupMode = 1
227     else
228         maxTags=$paramSubTestNum
229     end
230 else
231     maxTags=$maxTags
232 end
233
234 if $paramRandomMode
235     nextTest = rand(99999999)
236 else
237     if $paramTestNum
238         nextTest = $paramTestNum + 1
239     end
240 end
241
242
243 if (! nextTest)
244     nextTest = 1
245 end
246
247 # building the HTML
248 bodyText = mangleTag('html')
249 bodyText << "\n<head>\n"
250
251 # Only do redirects if lookup=1 has not been specified.
252 if (! $paramLookupMode) && ($paramSubTestNum != $maxTags)
253     newpage = "iexploder.cgi?"
254     if $paramSubTestNum > 0
255         newpage << "test=" << $paramTestNum.to_s << "&subtest=" << ($paramSubTestNum + 1).to_s
256     else
257         newpage << "test=" << nextTest.to_s
258     end
259     
260     if $paramRandomMode
261         newpage << "&random=1"
262     end
263
264
265     bodyText << "\t<META HTTP-EQUIV=\"Refresh\" content=\"0;URL=#{newpage}\">\n" 
266     # use both techniques, because you never know how you might be corrupting yourself.
267     bodyText << "\t<script language=\"javascript\">setTimeout('window.location=\"#{newpage}\"', 1000);</script>\n" 
268 end
269
270 # If they have no test number, don't crash them, just redirect them to the next test.
271 if (! $paramTestNum)
272     cgi.out {
273         cgi.html { bodyText }
274     }
275     exit
276 end
277
278 bodyText << "\t" << mangleTag('meta')
279 bodyText << "\t" <<  mangleTag('meta')
280 bodyText << "\t" <<  mangleTag('link')
281
282 bodyText << "\t<title>(#{cgi['test']}) iExploder #{$VERSION}  - #{inventValue()}</title>\n"
283 bodyText << "</head>\n\n"
284
285 # What tags will we be messing with ######################
286 tagList = [ 'body']
287
288 1.upto($maxTags) { tagList << $htmlTags[rand($htmlTags.length)] }
289
290
291 tagList.each { |tag|
292     bodyText << mangleTag(tag)
293     bodyText << inventValue() + "\n"
294 }
295 bodyText << "</body>\n</html>"
296
297 cgi.out('type' => 'text/html') do
298     bodyText
299 end