|
1 // Test the plaintext-or-binary sniffer |
|
2 |
|
3 Cu.import("resource://testing-common/httpd.js"); |
|
4 |
|
5 // List of Content-Type headers to test. For each header we have an array. |
|
6 // The first element in the array is the Content-Type header string. The |
|
7 // second element in the array is a boolean indicating whether we allow |
|
8 // sniffing for that type. |
|
9 var contentTypeHeaderList = |
|
10 [ |
|
11 [ "text/plain", true ], |
|
12 [ "text/plain; charset=ISO-8859-1", true ], |
|
13 [ "text/plain; charset=iso-8859-1", true ], |
|
14 [ "text/plain; charset=UTF-8", true ], |
|
15 [ "text/plain; charset=unknown", false ], |
|
16 [ "text/plain; param", false ], |
|
17 [ "text/plain; charset=ISO-8859-1; param", false ], |
|
18 [ "text/plain; charset=iso-8859-1; param", false ], |
|
19 [ "text/plain; charset=UTF-8; param", false ], |
|
20 [ "text/plain; charset=utf-8", false ], |
|
21 [ "text/plain; charset=utf8", false ], |
|
22 [ "text/plain; charset=UTF8", false ], |
|
23 [ "text/plain; charset=iSo-8859-1", false ] |
|
24 ]; |
|
25 |
|
26 // List of response bodies to test. For each response we have an array. The |
|
27 // first element in the array is the body string. The second element in the |
|
28 // array is a boolean indicating whether that string should sniff as binary. |
|
29 var bodyList = |
|
30 [ |
|
31 [ "Plaintext", false ] |
|
32 ]; |
|
33 |
|
34 // List of possible BOMs |
|
35 var BOMList = |
|
36 [ |
|
37 "\xFE\xFF", // UTF-16BE |
|
38 "\xFF\xFE", // UTF-16LE |
|
39 "\xEF\xBB\xBF", // UTF-8 |
|
40 "\x00\x00\xFE\xFF", // UCS-4BE |
|
41 "\x00\x00\xFF\xFE" // UCS-4LE |
|
42 ]; |
|
43 |
|
44 // Build up bodyList. The things we treat as binary are ASCII codes 0-8, |
|
45 // 14-26, 28-31. That is, the control char range, except for tab, newline, |
|
46 // vertical tab, form feed, carriage return, and ESC (this last being used by |
|
47 // Shift_JIS, apparently). |
|
48 function isBinaryChar(ch) { |
|
49 return (0 <= ch && ch <= 8) || (14 <= ch && ch <= 26) || |
|
50 (28 <= ch && ch <= 31); |
|
51 } |
|
52 |
|
53 // Test chars on their own |
|
54 var i; |
|
55 for (i = 0; i <= 127; ++i) { |
|
56 bodyList.push([ String.fromCharCode(i), isBinaryChar(i) ]); |
|
57 } |
|
58 |
|
59 // Test that having a BOM prevents plaintext sniffing |
|
60 var j; |
|
61 for (i = 0; i <= 127; ++i) { |
|
62 for (j = 0; j < BOMList.length; ++j) { |
|
63 bodyList.push([ BOMList[j] + String.fromCharCode(i, i), false ]); |
|
64 } |
|
65 } |
|
66 |
|
67 // Test that having a BOM requires at least 4 chars to kick in |
|
68 for (i = 0; i <= 127; ++i) { |
|
69 for (j = 0; j < BOMList.length; ++j) { |
|
70 bodyList.push([ BOMList[j] + String.fromCharCode(i), |
|
71 BOMList[j].length == 2 && isBinaryChar(i) ]); |
|
72 } |
|
73 } |
|
74 |
|
75 function makeChan(headerIdx, bodyIdx) { |
|
76 var ios = Components.classes["@mozilla.org/network/io-service;1"] |
|
77 .getService(Components.interfaces.nsIIOService); |
|
78 var chan = |
|
79 ios.newChannel("http://localhost:" + httpserv.identity.primaryPort + |
|
80 "/" + headerIdx + "/" + bodyIdx, null, null) |
|
81 .QueryInterface(Components.interfaces.nsIHttpChannel); |
|
82 |
|
83 chan.loadFlags |= |
|
84 Components.interfaces.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS; |
|
85 |
|
86 return chan; |
|
87 } |
|
88 |
|
89 function makeListener(headerIdx, bodyIdx) { |
|
90 var listener = { |
|
91 onStartRequest : function test_onStartR(request, ctx) { |
|
92 try { |
|
93 var chan = request.QueryInterface(Components.interfaces.nsIChannel); |
|
94 |
|
95 do_check_eq(chan.status, Components.results.NS_OK); |
|
96 |
|
97 var type = chan.contentType; |
|
98 |
|
99 var expectedType = |
|
100 contentTypeHeaderList[headerIdx][1] && bodyList[bodyIdx][1] ? |
|
101 "application/x-vnd.mozilla.guess-from-ext" : "text/plain"; |
|
102 if (expectedType != type) { |
|
103 do_throw("Unexpected sniffed type '" + type + "'. " + |
|
104 "Should be '" + expectedType + "'. " + |
|
105 "Header is ['" + |
|
106 contentTypeHeaderList[headerIdx][0] + "', " + |
|
107 contentTypeHeaderList[headerIdx][1] + "]. " + |
|
108 "Body is ['" + |
|
109 bodyList[bodyIdx][0].toSource() + "', " + |
|
110 bodyList[bodyIdx][1] + |
|
111 "]."); |
|
112 } |
|
113 do_check_eq(expectedType, type); |
|
114 } catch (e) { |
|
115 do_throw("Unexpected exception: " + e); |
|
116 } |
|
117 |
|
118 throw Components.results.NS_ERROR_ABORT; |
|
119 }, |
|
120 |
|
121 onDataAvailable: function test_ODA() { |
|
122 do_throw("Should not get any data!"); |
|
123 }, |
|
124 |
|
125 onStopRequest: function test_onStopR(request, ctx, status) { |
|
126 // Advance to next test |
|
127 ++headerIdx; |
|
128 if (headerIdx == contentTypeHeaderList.length) { |
|
129 headerIdx = 0; |
|
130 ++bodyIdx; |
|
131 } |
|
132 |
|
133 if (bodyIdx == bodyList.length) { |
|
134 do_test_pending(); |
|
135 httpserv.stop(do_test_finished); |
|
136 } else { |
|
137 doTest(headerIdx, bodyIdx); |
|
138 } |
|
139 |
|
140 do_test_finished(); |
|
141 } |
|
142 }; |
|
143 |
|
144 return listener; |
|
145 } |
|
146 |
|
147 function doTest(headerIdx, bodyIdx) { |
|
148 var chan = makeChan(headerIdx, bodyIdx); |
|
149 |
|
150 var listener = makeListener(headerIdx, bodyIdx); |
|
151 |
|
152 chan.asyncOpen(listener, null); |
|
153 |
|
154 do_test_pending(); |
|
155 } |
|
156 |
|
157 function createResponse(headerIdx, bodyIdx, metadata, response) { |
|
158 response.setHeader("Content-Type", contentTypeHeaderList[headerIdx][0], false); |
|
159 response.bodyOutputStream.write(bodyList[bodyIdx][0], |
|
160 bodyList[bodyIdx][0].length); |
|
161 } |
|
162 |
|
163 function makeHandler(headerIdx, bodyIdx) { |
|
164 var f = |
|
165 function handlerClosure(metadata, response) { |
|
166 return createResponse(headerIdx, bodyIdx, metadata, response); |
|
167 }; |
|
168 return f; |
|
169 } |
|
170 |
|
171 var httpserv; |
|
172 function run_test() { |
|
173 // disable again for everything for now (causes sporatic oranges) |
|
174 return; |
|
175 |
|
176 // disable on Windows for now, because it seems to leak sockets and die. |
|
177 // Silly operating system! |
|
178 // This is a really nasty way to detect Windows. I wish we could do better. |
|
179 if ("@mozilla.org/windows-registry-key;1" in Cc) { |
|
180 return; |
|
181 } |
|
182 |
|
183 httpserv = new HttpServer(); |
|
184 |
|
185 for (i = 0; i < contentTypeHeaderList.length; ++i) { |
|
186 for (j = 0; j < bodyList.length; ++j) { |
|
187 httpserv.registerPathHandler("/" + i + "/" + j, makeHandler(i, j)); |
|
188 } |
|
189 } |
|
190 |
|
191 httpserv.start(-1); |
|
192 |
|
193 doTest(0, 0); |
|
194 } |