diff --git a/mozilla/netwerk/test/httpserver/httpd.js b/mozilla/netwerk/test/httpserver/httpd.js
index d7cdb59113b..21728d52daf 100644
--- a/mozilla/netwerk/test/httpserver/httpd.js
+++ b/mozilla/netwerk/test/httpserver/httpd.js
@@ -61,7 +61,7 @@ function NS_ASSERT(cond, msg)
if (debugEnabled() && !cond)
{
dumpn("###!!!");
- dumpn("###!!! ASSERTION: " + msg);
+ dumpn("###!!! ASSERTION" + (msg ? ": " + msg : "!"));
dumpn("###!!! Stack follows:");
var stack = new Error().stack.split(/\n/);
@@ -549,17 +549,88 @@ function createHandlerFunc(handler)
return function(metadata, response) { handler.handle(metadata, response); };
}
+
/**
- * The default handler for directories.
+ * The default handler for directories; writes an HTML response containing a
+ * slightly-formatted directory listing.
*/
function defaultIndexHandler(metadata, response)
{
- var file = metadata.getProperty("directory");
- NS_ASSERT(file);
+ response.setHeader("Content-Type", "text/html", false);
- throw HTTP_501; // need directory listings ftw!
+ var path = htmlEscape(metadata.path);
+
+ //
+ // Just do a very basic bit of directory listings -- no need for too much
+ // fanciness, especially since we don't have a style sheet in which we can
+ // stick rules (don't want to pollute the default path-space).
+ //
+
+ var body = '\
+
\
+ ' + path + '\
+ \
+ \
+ ' + path + '
\
+ ';
+
+ var directory = metadata.getProperty("directory");
+ NS_ASSERT(directory && directory.isDirectory());
+
+ var fileList = [];
+ var files = directory.directoryEntries;
+ while (files.hasMoreElements())
+ {
+ var f = files.getNext().QueryInterface(Ci.nsIFile);
+ if (!f.isHidden())
+ fileList.push(f);
+ }
+
+ fileList.sort(fileSort);
+
+ for (var i = 0; i < fileList.length; i++)
+ {
+ var file = fileList[i];
+ try
+ {
+ var name = file.leafName;
+ var sep = file.isDirectory() ? "/" : "";
+
+ // Note: using " to delimit the attribute here because encodeURIComponent
+ // passes through '.
+ var item = '- ' +
+ htmlEscape(name) + sep +
+ '
';
+
+ body += item;
+ }
+ catch (e) { /* some file system error, ignore the file */ }
+ }
+
+ body += '
\
+ \
+ ';
+
+ response.bodyOutputStream.write(body, body.length);
}
+/**
+ * Sorts a and b (nsIFile objects) into an aesthetically pleasing order.
+ */
+function fileSort(a, b)
+{
+ var dira = a.isDirectory(), dirb = b.isDirectory();
+
+ if (dira && !dirb)
+ return -1;
+ if (dirb && !dira)
+ return 1;
+
+ var namea = a.leafName.toLowerCase(), nameb = b.leafName.toLowerCase();
+ return nameb > namea ? -1 : 1;
+}
+
+
/**
* An object which handles requests for a server, executing default and
* overridden behaviors as instructed by the code which uses and manipulates it.
diff --git a/mozilla/netwerk/test/httpserver/test/test_default_index_handler.js b/mozilla/netwerk/test/httpserver/test/test_default_index_handler.js
new file mode 100644
index 00000000000..69f64942246
--- /dev/null
+++ b/mozilla/netwerk/test/httpserver/test/test_default_index_handler.js
@@ -0,0 +1,268 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is MozJSHTTP code.
+ *
+ * The Initial Developer of the Original Code is
+ * Jeff Walden .
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// checks for correct output with the default index handler, mostly to do
+// escaping checks -- highly dependent on the default index handler output
+// format
+
+var paths =
+ [
+ "http://localhost:4444/", // check top-level directory listing
+ "http://localhost:4444/foo/" // check non-top-level, too
+ ];
+var currPathIndex = 0;
+
+/**
+ * Verifies data in bytes (an array of bytes) represents an index page for the
+ * given URI and path, which should be a page listing the given directory
+ * entries, in order.
+ *
+ * @param bytes
+ * array of bytes representing the index page's contents
+ * @param uri
+ * string which is the URI of the index page
+ * @param path
+ * the path portion of uri
+ * @param dirEntries
+ * sorted (in the manner the directory entries should be sorted) array of
+ * objects, each of which has a name property (whose value is the file's name,
+ * without / if it's a directory) and an isDirectory property (with expected
+ * value)
+ */
+function dataCheck(bytes, uri, path, dirEntries)
+{
+ var data = String.fromCharCode.apply(null, bytes);
+
+ var parser = Cc["@mozilla.org/xmlextras/domparser;1"]
+ .createInstance(Ci.nsIDOMParser);
+
+ // Note: the index format isn't XML -- it's actually HTML -- but we require
+ // the index format also be valid XML, albeit XML without namespaces,
+ // XML declarations, etc. Doing this simplifies output checking.
+ try
+ {
+ var doc = parser.parseFromString(data, "application/xml");
+ }
+ catch (e)
+ {
+ do_throw("document failed to parse as XML");
+ }
+
+ // See all the .QueryInterface()s and .item()s happening here? That's because
+ // xpcshell sucks and doesn't have classinfo, so no automatic interface
+ // flattening or array-style access to items in NodeLists. Suck.
+
+ var body = doc.documentElement.getElementsByTagName("body");
+ do_check_eq(body.length, 1);
+ body = body.item(0);
+
+ // header
+ var header = body.QueryInterface(Ci.nsIDOMElement)
+ .getElementsByTagName("h1");
+ do_check_eq(header.length, 1);
+
+ do_check_eq(header.item(0).QueryInterface(Ci.nsIDOM3Node).textContent, path);
+
+ // files
+ var lst = body.getElementsByTagName("ol");
+ do_check_eq(lst.length, 1);
+ var items = lst.item(0).QueryInterface(Ci.nsIDOMElement)
+ .getElementsByTagName("li");
+
+ var ios = Cc["@mozilla.org/network/io-service;1"]
+ .getService(Ci.nsIIOService);
+
+ var top = ios.newURI(uri, null, null);
+
+ for (var i = 0; i < items.length; i++)
+ {
+ var link = items.item(i)
+ .childNodes
+ .item(0)
+ .QueryInterface(Ci.nsIDOM3Node)
+ .QueryInterface(Ci.nsIDOMElement);
+ var f = dirEntries[i];
+
+ var sep = f.isDirectory ? "/" : "";
+
+ do_check_eq(link.textContent, f.name + sep);
+
+ var uri = ios.newURI(link.getAttribute("href"), null, top);
+ var fn = encodeURIComponent(f.name) + sep;
+ do_check_eq(uri.path, path + fn);
+ }
+}
+
+var listener =
+ {
+ // data from request
+ _data: [],
+
+ onStartRequest: function(request, cx)
+ {
+ var ch = request.QueryInterface(Ci.nsIHttpChannel);
+ do_check_eq(ch.getResponseHeader("Content-Type"), "text/html");
+
+ this._data.length = 0;
+ this._uri = paths[currPathIndex];
+ this._path = this._uri.substring(paths[0].length - 1);
+ this._dirEntries = dirEntries[currPathIndex];
+ },
+ onDataAvailable: function(request, cx, inputStream, offset, count)
+ {
+ var bytes = makeBIS(inputStream).readByteArray(count);
+ Array.prototype.push.apply(this._data, bytes);
+ },
+ onStopRequest: function(request, cx, status)
+ {
+ dataCheck(this._data, this._uri, this._path, this._dirEntries);
+
+ if (++currPathIndex == paths.length)
+ {
+ srv.stop();
+ destroyTestDirectory();
+ }
+ else
+ {
+ performNextTest();
+ }
+ do_test_finished();
+ },
+ QueryInterface: function(aIID)
+ {
+ if (aIID.equals(Ci.nsIStreamListener) ||
+ aIID.equals(Ci.nsIRequestObserver) ||
+ aIID.equals(Ci.nsISupports))
+ return this;
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ }
+ };
+
+
+var srv, dir, dirEntries;
+
+function run_test()
+{
+ createTestDirectory();
+
+ srv = createServer();
+ srv.registerDirectory("/", dir);
+ srv.start(4444);
+
+ performNextTest();
+}
+
+function performNextTest()
+{
+ do_test_pending();
+
+ var ch = makeChannel(paths[currPathIndex]);
+ ch.asyncOpen(listener, null);
+}
+
+function createTestDirectory()
+{
+ dir = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties)
+ .get("TmpD", Ci.nsIFile);
+ dir.append("index_handler_test_" + Math.random());
+ dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0744);
+
+ // populate with test directories, files, etc.
+ // Files must be in expected order of display on the index page!
+
+ files = [];
+
+ makeFile("aa_directory", true, dir, files);
+ makeFile("Ba_directory", true, dir, files);
+ makeFile("bb_directory", true, dir, files);
+ makeFile("foo", true, dir, files);
+ makeFile("a_file", false, dir, files);
+ makeFile("B_file", false, dir, files);
+ makeFile("za'z", false, dir, files);
+ makeFile("zb&z", false, dir, files);
+ makeFile("zcm", false, dir, files);
+
+ dirEntries = [files];
+
+ var subdir = dir.clone();
+ subdir.append("foo");
+
+ files = [];
+
+ makeFile("aa_dir", true, subdir, files);
+ makeFile("b_dir", true, subdir, files);
+ makeFile("AA_file.txt", false, subdir, files);
+ makeFile("test.txt", false, subdir, files);
+
+ dirEntries.push(files);
+}
+
+function destroyTestDirectory()
+{
+ dir.remove(true);
+}
+
+
+// utilities
+
+/**
+ * Create a file/directory with the given name underneath parentDir, and
+ * append an object with name/isDirectory properties to lst corresponding
+ * to it if the file/directory could be created.
+ */
+function makeFile(name, isDirectory, parentDir, lst)
+{
+ var type = isDirectory
+ ? Ci.nsIFile.DIRECTORY_TYPE
+ : Ci.nsIFile.NORMAL_FILE_TYPE;
+
+ var file = parentDir.clone();
+
+ try
+ {
+ file.append(name);
+ file.create(type, 0755);
+ lst.push({name: name, isDirectory: isDirectory});
+ }
+ catch (e) { /* OS probably doesn't like file name, skip */ }
+}
diff --git a/mozilla/netwerk/test/httpserver/test/test_setindexhandler.js b/mozilla/netwerk/test/httpserver/test/test_setindexhandler.js
index bb11e612c04..33185aa7268 100644
--- a/mozilla/netwerk/test/httpserver/test/test_setindexhandler.js
+++ b/mozilla/netwerk/test/httpserver/test/test_setindexhandler.js
@@ -66,7 +66,7 @@ var listener =
break;
case 1:
- do_check_eq(ch.responseStatus, 500);
+ do_check_eq(ch.responseStatus, 200); // default index handler
break;
}
},
@@ -99,13 +99,13 @@ function performNextTest()
ch.asyncOpen(listener, null);
}
-var srv;
+var srv, serverBasePath;
function run_test()
{
srv = createServer();
- dirServ = Cc["@mozilla.org/file/directory_service;1"]
- .getService(Ci.nsIProperties);
+ var dirServ = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties);
serverBasePath = dirServ.get("CurProcD", Ci.nsILocalFile);
serverBasePath.append("httpserver_tests");
srv.registerDirectory("/", serverBasePath);
@@ -119,5 +119,10 @@ function run_test()
function myIndexHandler(metadata, response)
{
+ var dir = metadata.getProperty("directory");
+ do_check_true(dir != null);
+ do_check_true(dir instanceof Ci.nsIFile);
+ do_check_true(dir.equals(serverBasePath));
+
response.write("directory!");
}