Bug 463254 - httpd.js fails on mac when running test_CrossSiteXHR.html. The problem was that exceptions were causing files not to be closed on OS X, and we were hitting the open-file limit; add some try-finally magic to close in a failsafe manner. r=honzab

This commit is contained in:
Jeff Walden 2008-11-06 12:44:27 -08:00
parent 159005ad48
commit 6ed4048793
5 changed files with 186 additions and 32 deletions

View File

@ -40,12 +40,6 @@ window.addEventListener("message", function(e) {
gen = runTest();
function runTest() {
if (navigator.platform == "MacIntel") {
todo(false, "httpd.js fails on Mac");
SimpleTest.finish();
yield;
}
var loader = document.getElementById('loader');
var loaderWindow = loader.contentWindow;
loader.onload = function () { gen.next() };

View File

@ -1805,11 +1805,11 @@ function maybeAddHeaders(file, metadata, response)
var fis = new FileInputStream(headerFile, PR_RDONLY, 0444,
Ci.nsIFileInputStream.CLOSE_ON_EOF);
var lis = new ConverterInputStream(fis, "UTF-8", 1024, 0x0);
lis.QueryInterface(Ci.nsIUnicharLineInputStream);
try
{
var lis = new ConverterInputStream(fis, "UTF-8", 1024, 0x0);
lis.QueryInterface(Ci.nsIUnicharLineInputStream);
var line = {value: ""};
var more = lis.readLine(line);
@ -1861,6 +1861,10 @@ function maybeAddHeaders(file, metadata, response)
dumpn("WARNING: error in headers for " + metadata.path + ": " + e);
throw HTTP_500;
}
finally
{
fis.close();
}
}
@ -2338,20 +2342,45 @@ ServerHandler.prototype =
var type = this._getTypeFromFile(file);
if (type == SJS_TYPE)
{
var fis = new FileInputStream(file, PR_RDONLY, 0444,
Ci.nsIFileInputStream.CLOSE_ON_EOF);
try
{
var fis = new FileInputStream(file, PR_RDONLY, 0444,
Ci.nsIFileInputStream.CLOSE_ON_EOF);
var sis = new ScriptableInputStream(fis);
var s = Cu.Sandbox(gGlobalObject);
s.importFunction(dump, "dump");
Cu.evalInSandbox(sis.read(file.fileSize), s);
s.handleRequest(metadata, response);
try
{
// Alas, the line number in errors dumped to console when calling the
// request handler is simply an offset from where we load the SJS file.
// Work around this in a reasonably non-fragile way by dynamically
// getting the line number where we evaluate the SJS file. Don't
// separate these two lines!
var line = new Error().lineNumber;
Cu.evalInSandbox(sis.read(file.fileSize), s);
}
catch (e)
{
dumpn("*** syntax error in SJS at " + file.path + ": " + e);
throw HTTP_500;
}
try
{
s.handleRequest(metadata, response);
}
catch (e)
{
dumpn("*** error running SJS at " + file.path + ": " +
e + " on line " + (e.lineNumber - line));
throw HTTP_500;
}
}
catch (e)
finally
{
dump("*** error running SJS: " + e + " on line " + (e.lineNumber-2192) + "\n");
throw HTTP_500;
fis.close();
}
}
else
@ -2368,21 +2397,28 @@ ServerHandler.prototype =
var fis = new FileInputStream(file, PR_RDONLY, 0444,
Ci.nsIFileInputStream.CLOSE_ON_EOF);
offset = offset || 0;
count = count || file.fileSize;
NS_ASSERT(offset == 0 || offset < file.fileSize, "bad offset");
NS_ASSERT(count >= 0, "bad count");
if (offset != 0)
try
{
// Read and discard data up to offset so the data sent to
// the client matches the requested range request.
var sis = new ScriptableInputStream(fis);
sis.read(offset);
offset = offset || 0;
count = count || file.fileSize;
NS_ASSERT(offset == 0 || offset < file.fileSize, "bad offset");
NS_ASSERT(count >= 0, "bad count");
if (offset != 0)
{
// Read and discard data up to offset so the data sent to
// the client matches the requested range request.
var sis = new ScriptableInputStream(fis);
sis.read(offset);
}
response.bodyOutputStream.writeFrom(fis, count);
}
finally
{
fis.close();
}
response.bodyOutputStream.writeFrom(fis, count);
fis.close();
maybeAddHeaders(file, metadata, response);
}

View File

@ -0,0 +1,6 @@
function handleRequest(request, response)
{
if (request.queryString == "throw")
undefined[5];
response.setHeader("X-Test-Status", "PASS", false);
}

View File

@ -249,11 +249,26 @@ function runHttpTests(testArray, done)
{
var ch = request.QueryInterface(Ci.nsIHttpChannel)
.QueryInterface(Ci.nsIHttpChannelInternal);
testArray[testIndex].onStopRequest(ch, cx, status, this._data);
performNextTest();
do_test_finished();
// NB: The onStopRequest callback must run before performNextTest here,
// because the latter runs the next test's initChannel callback, and
// we want one test to be sequentially processed before the next
// one.
try
{
testArray[testIndex].onStopRequest(ch, cx, status, this._data);
}
finally
{
try
{
performNextTest();
}
finally
{
do_test_finished();
}
}
},
QueryInterface: function(aIID)
{

View File

@ -0,0 +1,103 @@
/* -*- 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 httpd.js code.
*
* The Initial Developer of the Original Code is
* the Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jeff Walden <jwalden+code@mit.edu>
*
* 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 ***** */
/*
* Tests that running an SJS a whole lot of times doesn't have any ill effects
* (like exceeding open-file limits due to not closing the SJS file each time,
* then preventing any file from being opened).
*/
const PORT = 4444;
function run_test()
{
var srv = createServer();
var sjsDir = do_get_file("netwerk/test/httpserver/test/data/sjs/");
srv.registerDirectory("/", sjsDir);
srv.registerContentType("sjs", "sjs");
srv.start(PORT);
function done()
{
srv.stop();
do_check_eq(gStartCount, TEST_RUNS);
do_check_true(lastPassed);
}
runHttpTests(tests, done);
}
/***************
* BEGIN TESTS *
***************/
var gStartCount = 0;
var lastPassed = false;
// This hits the open-file limit for me on OS X; your mileage may vary.
const TEST_RUNS = 250;
var test = new Test("http://localhost:4444/thrower.sjs?throw",
null, start_thrower);
var tests = new Array(TEST_RUNS + 1);
for (var i = 0; i < TEST_RUNS; i++)
tests[i] = test;
// ...and don't forget to stop!
tests[TEST_RUNS] = new Test("http://localhost:4444/thrower.sjs",
null, start_last);
function start_thrower(ch, cx)
{
do_check_eq(ch.responseStatus, 500);
do_check_false(ch.requestSucceeded);
gStartCount++;
}
function start_last(ch, cx)
{
do_check_eq(ch.responseStatus, 200);
do_check_true(ch.requestSucceeded);
do_check_eq(ch.getResponseHeader("X-Test-Status"), "PASS");
lastPassed = true;
}