Bug 396226 - Provide an API to asynchronously generate HTTP responses in httpd.js, and implement a state-storage system which can store object references to provide greater contextual information in handlers. NB: this push enables httpd.js debug output just in case something goes wrong, to be disabled as soon as it's clear nothing has -- expect the first Windows builds to finish next century sometime. r=sayrer

This commit is contained in:
Jeff Walden 2009-04-15 13:19:35 -07:00
Родитель 19bfe8dc73
Коммит 98d4570c74
75 изменённых файлов: 2403 добавлений и 689 удалений

Просмотреть файл

@ -159,25 +159,39 @@ function OnRefTestLoad()
createInstance(CI.nsIHttpServer);
try {
if (gServer) {
gServer.registerContentType("sjs", "sjs");
// We want to try different ports in case the port we want
// is being used.
var tries = HTTP_SERVER_PORTS_TO_TRY;
var succeeded = false;
do {
try {
gServer.start(HTTP_SERVER_PORT);
succeeded = true;
} catch (ex) {
gServer.stop();
++HTTP_SERVER_PORT;
if (--tries == 0) {
throw ex;
}
}
} while (!succeeded);
if (gServer)
StartHTTPServer();
} catch (ex) {
//gBrowser.loadURI('data:text/plain,' + ex);
++gTestResults.Exception;
dump("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n");
DoneTests();
}
StartTests();
}
function StartHTTPServer()
{
gServer.registerContentType("sjs", "sjs");
// We want to try different ports in case the port we want
// is being used.
var tries = HTTP_SERVER_PORTS_TO_TRY;
do {
try {
gServer.start(HTTP_SERVER_PORT);
return;
} catch (ex) {
++HTTP_SERVER_PORT;
if (--tries == 0)
throw ex;
}
} while (true);
}
function StartTests()
{
try {
// Need to read the manifest once we have the final HTTP_SERVER_PORT.
ReadTopManifest(window.arguments[0]);
BuildUseCounts();
@ -525,9 +539,14 @@ function DoneTests()
dump("REFTEST INFO | Total canvas count = " + gRecycledCanvases.length + "\n");
function onStopped() {
dump("REFTEST INFO | Quitting...\n");
goQuitApplication();
}
if (gServer)
gServer.stop();
goQuitApplication();
gServer.stop(onStopped);
else
onStopped();
}
function setupZoom(contentRootElement) {

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -44,6 +44,7 @@ interface nsIOutputStream;
interface nsISimpleEnumerator;
interface nsIHttpServer;
interface nsIHttpServerStoppedCallback;
interface nsIHttpRequestHandler;
interface nsIHttpRequestMetadata;
interface nsIHttpResponse;
@ -52,33 +53,41 @@ interface nsIHttpServerIdentity;
/**
* An interface which represents an HTTP server.
*/
[scriptable, uuid(DEEDE3E3-B813-4F3F-9C70-948E5700C410)]
[scriptable, uuid(71ecfba5-15cf-457f-9642-4b33f6e9baf4)]
interface nsIHttpServer : nsISupports
{
/**
* Starts up this server, listening upon the given port. This method may
* throw if the process does not have sufficient privileges to open a socket
* for the given port, and it also throws when called upon a server which has
* already been started.
* Starts up this server, listening upon the given port.
*
* @param port
* the port upon which listening should happen, or -1 if no specific port is
* desired
* @throws NS_ERROR_ALREADY_INITIALIZED
* if this server is already started
* @throws NS_ERROR_NOT_AVAILABLE
* if the server is not started and cannot be started on the desired port
* (perhaps because the port is already in use or because the process does
* not have privileges to do so)
* @note
* Behavior is undefined if this method is called after stop() has been
* called on this but before the provided callback function has been
* called.
*/
void start(in long port);
/**
* Shuts down this server if it is running; if it is not, this method is a
* no-op.
* Shuts down this server if it is running (including the period of time after
* stop() has been called but before the provided callback has been called).
*
* This method will do its best to return after the socket in this
* server has been closed and all pending requests have completed being
* served, but this may or may not actually happen, since in some
* implementations this may not actually be possible. Implementations which
* can make this promise should make it explicit in implementation
* documentation.
* @param callback
* an asynchronous callback used to notify the user when this server is
* stopped and all pending requests have been fully served
* @throws NS_ERROR_NULL_POINTER
* if callback is null
* @throws NS_ERROR_UNEXPECTED
* if this server is not running
*/
void stop();
void stop(in nsIHttpServerStoppedCallback callback);
/**
* Associates the local file represented by the string file with all requests
@ -213,6 +222,30 @@ interface nsIHttpServer : nsISupports
* saved state.
*/
void setSharedState(in AString key, in AString value);
/**
* Retrieves the object associated with the given key in this in
* object-valued saved state. All keys are initially associated with null.
*/
nsISupports getObjectState(in AString key);
/**
* Sets the object associated with the given key in this in object-valued
* saved state. The value may be null.
*/
void setObjectState(in AString key, in nsISupports value);
};
/**
* An interface through which a notification of the complete stopping (socket
* closure, in-flight requests all fully served and responded to) of an HTTP
* server may be received.
*/
[scriptable, function, uuid(925a6d33-9937-4c63-abe1-a1c56a986455)]
interface nsIHttpServerStoppedCallback : nsISupports
{
/** Called when the corresponding server has been fully stopped. */
void onStopped();
};
/**
@ -450,7 +483,7 @@ interface nsIHttpRequestMetadata : nsIPropertyBag
/**
* Represents an HTTP response, as described in RFC 2616, section 6.
*/
[scriptable, uuid(a2aaaff7-03bd-43b6-b460-94671e288093)]
[scriptable, uuid(4b023876-274e-41e8-83fb-e51f7aba43a6)]
interface nsIHttpResponse : nsISupports
{
/**
@ -469,6 +502,9 @@ interface nsIHttpResponse : nsISupports
* @throws NS_ERROR_INVALID_ARG
* if httpVersion is not a valid HTTP version string, statusCode is greater
* than 999, or description contains invalid characters
* @throws NS_ERROR_NOT_AVAILABLE
* if this response is being processed asynchronously and data has been
* written to this response's body
*/
void setStatusLine(in string httpVersion,
in unsigned short statusCode,
@ -485,25 +521,73 @@ interface nsIHttpResponse : nsISupports
* @param merge
* when true, if the given header already exists in this, the values passed
* to this function will be merged into the existing header, per RFC 2616
* header semantics; when false, if the given header already exists in this,
* it is overwritten with the passed-in values; if the header doesn't exist
* in this, it is set regardless of the value of this parameter
* header semantics (except for the Set-Cookie, WWW-Authenticate, and
* Proxy-Authenticate headers, which will treat each such merged header as
* an additional instance of the header, for real-world compatibility
* reasons); when false, replaces any existing header of the given name (if
* any exists) with a new header with the specified value
* @throws NS_ERROR_INVALID_ARG
* if name or value is not a valid header component
* @throws NS_ERROR_NOT_AVAILABLE
* if this response is being processed asynchronously and data has been
* written to this response's body
*/
void setHeader(in string name, in string value, in boolean merge);
/**
* A stream to which data appearing in the body of this response should be
* written.
* written. After this response has been designated as being processed
* asynchronously, subsequent writes will be synchronously written to the
* underlying transport. However, immediate write-through visible to the HTTP
* client cannot be guaranteed, as intermediate buffers both in the server
* socket and in the client may delay written data; be prepared for potential
* delays.
*
* @note
* As writes to the underlying transport are synchronous, care must be taken
* not to block on these writes; it is even possible for deadlock to occur
* in the case that the server and the client reside in the same process.
* @throws NS_ERROR_NOT_AVAILABLE
* if accessed after this response is fully constructed
*/
readonly attribute nsIOutputStream bodyOutputStream;
/**
* Write a string to the response's output stream.
* Writes a string to the response's output stream. This method is merely a
* convenient shorthand for writing the same data to bodyOutputStream
* directly.
*
* @note
* This method is only guaranteed to work with ASCII data.
* @throws NS_ERROR_NOT_AVAILABLE
* if called after this response has been fully constructed
*/
void write(in string data);
/**
* Signals that this response is being constructed asynchronously. Requests
* are typically completely constructed during nsIHttpRequestHandler.handle;
* however, responses which require significant resources (time, memory,
* processing) to construct can be created and sent incrementally by calling
* this method during the call to nsIHttpRequestHandler.handle. This method
* only has this effect when called during nsIHttpRequestHandler.handle;
* behavior is undefined if it is called at a later time. It may be called
* multiple times with no ill effect, so long as each call occurs before
* finish() is called.
*
* @throws NS_ERROR_UNEXPECTED
* if not initially called within a nsIHttpRequestHandler.handle call or if
* called after this response has been finished
*/
void processAsync();
/**
* Signals that construction of this response is complete and that it may be
* sent over the network to the client. This method may only be called after
* processAsync() has been called. This method is idempotent.
*
* @throws NS_ERROR_UNEXPECTED
* if processAsync() has not already been properly called
*/
void finish();
};

Просмотреть файл

@ -0,0 +1,87 @@
function parseQueryString(str)
{
var paramArray = str.split("&");
var regex = /^([^=]+)=(.*)$/;
var params = {};
for (var i = 0, sz = paramArray.length; i < sz; i++)
{
var match = regex.exec(paramArray[i]);
if (!match)
throw "Bad parameter in queryString! '" + paramArray[i] + "'";
params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
}
return params;
}
/*
* We're relying somewhat dubiously on all data being sent as soon as it's
* available at numerous levels (in Necko in the server-side part of the
* connection, in the OS's outgoing socket buffer, in the OS's incoming socket
* buffer, and in Necko in the client-side part of the connection), but to the
* best of my knowledge there's no way to force data flow at all those levels,
* so this is the best we can do.
*/
function handleRequest(request, response)
{
response.setHeader("Cache-Control", "no-cache", false);
/*
* NB: A Content-Type header is *necessary* to avoid content-sniffing, which
* will delay onStartRequest past the the point where the entire head of
* the response has been received.
*/
response.setHeader("Content-Type", "text/plain", false);
var params = parseQueryString(request.queryString);
switch (params.state)
{
case "initial":
response.processAsync();
response.write("do");
var state =
{
QueryInterface: function(iid)
{
if (iid.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
end: function()
{
response.write("ne");
response.finish();
}
};
state.wrappedJSObject = state;
setObjectState("object-state-test", state);
getObjectState("object-state-test", function(obj)
{
if (obj !== state)
{
response.write("FAIL bad state save");
response.finish();
}
});
break;
case "intermediate":
response.write("intermediate");
break;
case "trigger":
response.write("trigger");
getObjectState("object-state-test", function(obj)
{
obj.wrappedJSObject.end();
setObjectState("object-state-test", null);
});
break;
default:
response.setStatusLine(request.httpVersion, 500, "Unexpected State");
response.write("Bad state: " + params.state);
break;
}
}

Просмотреть файл

@ -41,6 +41,8 @@ do_load_httpd_js();
// if these tests fail, we'll want the debug output
DEBUG = true;
const Timer = CC("@mozilla.org/timer;1", "nsITimer", "initWithCallback");
/**
* Constructs a new nsHttpServer instance. This function is intended to
@ -193,11 +195,109 @@ function skipHeaders(iter)
line = iter.next();
}
/**
* Checks that the exception e (which may be an XPConnect-created exception
* object or a raw nsresult number) is the given nsresult.
*
* @param e : Exception or nsresult
* the actual exception
* @param code : nsresult
* the expected exception
*/
function isException(e, code)
{
if (e !== code && e.result !== code)
do_throw("unexpected error: " + e);
}
/**
* Pending timers used by callLater, which must store them to avoid the timer
* being canceled and destroyed. Stupid API...
*/
var __pendingTimers = [];
/**
* Date.now() is not necessarily monotonically increasing (insert sob story
* about times not being the right tool to use for measuring intervals of time,
* robarnold can tell all), so be wary of error by erring by at least
* __timerFuzz ms.
*/
const __timerFuzz = 15;
/**
* Calls the given function at least the specified number of milliseconds later.
* The callback will not undershoot the given time, but it might overshoot --
* don't expect precision!
*
* @param milliseconds : uint
* the number of milliseconds to delay
* @param callback : function() : void
* the function to call
*/
function callLater(msecs, callback)
{
do_check_true(msecs >= 0);
var start = Date.now();
function checkTime()
{
var index = __pendingTimers.indexOf(timer);
do_check_true(index >= 0); // sanity
__pendingTimers.splice(index, 1);
do_check_eq(__pendingTimers.indexOf(timer), -1);
// The current nsITimer implementation can undershoot, but even if it
// couldn't, paranoia is probably a virtue here given the potential for
// random orange on tinderboxen.
var end = Date.now();
var elapsed = end - start;
if (elapsed >= msecs)
{
dumpn("*** TIMER FIRE " + elapsed + "ms (" + msecs + "ms requested)");
try
{
callback();
}
catch (e)
{
do_throw("exception thrown from callLater callback: " + e);
}
return;
}
// Timer undershot, retry with a little overshoot to try to avoid more
// undershoots.
var newDelay = msecs - elapsed;
dumpn("*** TIMER UNDERSHOOT " + newDelay + "ms " +
"(" + msecs + "ms requested, delaying)");
callLater(newDelay, callback);
}
var timer =
new Timer(checkTime, msecs + __timerFuzz, Ci.nsITimer.TYPE_ONE_SHOT);
__pendingTimers.push(timer);
}
/*******************************************************
* SIMPLE SUPPORT FOR LOADING/TESTING A SERIES OF URLS *
*******************************************************/
/**
* Create a completion callback which will stop the given server and end the
* test, assuming nothing else remains to be done at that point.
*/
function testComplete(srv)
{
return function complete()
{
do_test_pending();
srv.stop(function quit() { do_test_finished(); });
};
}
/**
* Represents a path to load from the tested HTTP server, along with actions to
* take before, during, and after loading the associated page.
@ -244,7 +344,14 @@ function runHttpTests(testArray, done)
{
if (++testIndex == testArray.length)
{
done();
try
{
done();
}
catch (e)
{
do_throw("error running test-completion callback: " + e);
}
return;
}
@ -397,7 +504,14 @@ function runRawTests(testArray, done)
if (++testIndex == testArray.length)
{
do_test_finished();
done();
try
{
done();
}
catch (e)
{
do_throw("error running test-completion callback: " + e);
}
return;
}

Просмотреть файл

@ -36,7 +36,9 @@
*
* ***** END LICENSE BLOCK ***** */
// basic functionality test, from the client programmer's POV
/*
* Basic functionality test, from the client programmer's POV.
*/
var tests =
[
@ -65,7 +67,7 @@ function run_test()
srv.start(4444);
runHttpTests(tests, function() { srv.stop(); });
runHttpTests(tests, testComplete(srv));
}

Просмотреть файл

@ -53,7 +53,7 @@ function run_test()
srv.registerPathHandler("/content-length", contentLength);
srv.start(PORT);
runHttpTests(tests, function() { srv.stop(); });
runHttpTests(tests, testComplete(srv));
}
const REQUEST_DATA = "12345678901234567";

Просмотреть файл

@ -77,7 +77,7 @@ function run_test()
srv.start(4444);
runHttpTests(tests, function() { srv.stop(); });
runHttpTests(tests, testComplete(srv));
}
function start_normal(ch, cx)

Просмотреть файл

@ -63,7 +63,7 @@ function run_test()
srv.start(4444);
runHttpTests(tests, function() { srv.stop(); });
runHttpTests(tests, testComplete(srv));
}

Просмотреть файл

@ -54,7 +54,14 @@ function run_test()
srv.start(4444);
runHttpTests(tests, function() { srv.stop(); destroyTestDirectory(); });
function done()
{
do_test_pending();
destroyTestDirectory();
srv.stop(function() { do_test_finished(); });
}
runHttpTests(tests, done);
}
function createTestDirectory()

Просмотреть файл

@ -57,7 +57,7 @@ function run_test()
srv.start(4444);
runHttpTests(tests, function() { srv.stop(); });
runHttpTests(tests, testComplete(srv));
}
// TEST DATA

Просмотреть файл

@ -60,7 +60,7 @@ function run_test()
srv.start(4444);
runHttpTests(tests, function() { srv.stop(); });
runHttpTests(tests, testComplete(srv));
}

Просмотреть файл

@ -49,12 +49,7 @@ function run_test()
srv.registerPathHandler("/path-handler", pathHandler);
srv.start(PORT);
function done()
{
srv.stop();
}
runHttpTests(tests, done);
runHttpTests(tests, testComplete(srv));
}

Просмотреть файл

@ -42,11 +42,15 @@
*/
const PORT = 4444;
const FAKE_PORT_ONE = 8888;
const FAKE_PORT_TWO = 8889;
var srv;
var srv, id;
function run_test()
{
dumpn("*** run_test");
srv = createServer();
srv.registerPathHandler("/http/1.0-request", http10Request);
@ -55,12 +59,9 @@ function run_test()
http11goodHostWackyPort);
srv.registerPathHandler("/http/1.1-ip-host", http11ipHost);
const FAKE_PORT_ONE = 8888;
const FAKE_PORT_TWO = 8889;
srv.start(FAKE_PORT_ONE);
var id = srv.identity;
id = srv.identity;
// The default location is http://localhost:PORT, where PORT is whatever you
// provided when you started the server. http://127.0.0.1:PORT is also part
@ -108,7 +109,26 @@ function run_test()
// Okay, now that we've exercised that behavior, shut down the server and
// restart it on the correct port, to exercise port-changing behaviors at
// server start and stop.
srv.stop();
do_test_pending();
srv.stop(function()
{
try
{
do_test_pending();
run_test_2();
}
finally
{
do_test_finished();
}
});
}
function run_test_2()
{
dumpn("*** run_test_2");
do_test_finished();
// Our primary location is gone because it was dependent on the port on which
// the server was running.
@ -152,7 +172,26 @@ function run_test()
do_check_false(id.has("http", "localhost", FAKE_PORT_ONE));
do_check_false(id.has("http", "127.0.0.1", FAKE_PORT_ONE));
srv.stop();
do_test_pending();
srv.stop(function()
{
try
{
do_test_pending();
run_test_3();
}
finally
{
do_test_finished();
}
});
}
function run_test_3()
{
dumpn("*** run_test_3");
do_test_finished();
// Only the default added location disappears; any others stay around,
// possibly as the primary location. We may have removed the default primary
@ -201,7 +240,7 @@ function run_test()
// Okay, finally done with identity testing. Our primary location is the one
// we want it to be, so we're off!
runRawTests(tests, function() { srv.stop(); });
runRawTests(tests, testComplete(srv));
}

Просмотреть файл

@ -86,7 +86,7 @@ function run_test()
srv.start(4444);
runHttpTests(tests, function() { srv.stop(); });
runHttpTests(tests, testComplete(srv));
}

Просмотреть файл

@ -0,0 +1,381 @@
/* -*- 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) 2009
* 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 for correct behavior of asynchronous responses.
*/
const PORT = 4444;
const PREPATH = "http://localhost:" + PORT;
function run_test()
{
var srv = createServer();
for (var path in handlers)
srv.registerPathHandler(path, handlers[path]);
srv.start(PORT);
runHttpTests(tests, testComplete(srv));
}
/***************
* BEGIN TESTS *
***************/
var test;
var tests = [];
var handlers = {};
function handleSync(request, response)
{
response.setStatusLine(request.httpVersion, 500, "handleSync fail");
try
{
response.finish();
do_throw("finish called on sync response");
}
catch (e)
{
isException(e, Cr.NS_ERROR_UNEXPECTED);
}
response.setStatusLine(request.httpVersion, 200, "handleSync pass");
}
handlers["/handleSync"] = handleSync;
function start_handleSync(ch, cx)
{
do_check_eq(ch.responseStatus, 200);
do_check_eq(ch.responseStatusText, "handleSync pass");
}
test = new Test(PREPATH + "/handleSync",
null, start_handleSync, null),
tests.push(test);
function handleAsync1(request, response)
{
response.setStatusLine(request.httpVersion, 500, "Old status line!");
response.setHeader("X-Foo", "old value", false);
response.processAsync();
response.setStatusLine(request.httpVersion, 200, "New status line!");
response.setHeader("X-Foo", "new value", false);
response.finish();
try
{
response.setStatusLine(request.httpVersion, 500, "Too late!");
do_throw("late setStatusLine didn't throw");
}
catch (e)
{
isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
}
try
{
response.setHeader("X-Foo", "late value", false);
do_throw("late setHeader didn't throw");
}
catch (e)
{
isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
}
try
{
response.bodyOutputStream;
do_throw("late bodyOutputStream get didn't throw");
}
catch (e)
{
isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
}
try
{
response.write("fugly");
do_throw("late write() didn't throw");
}
catch (e)
{
isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
}
}
handlers["/handleAsync1"] = handleAsync1;
function start_handleAsync1(ch, cx)
{
do_check_eq(ch.responseStatus, 200);
do_check_eq(ch.responseStatusText, "New status line!");
do_check_eq(ch.getResponseHeader("X-Foo"), "new value");
}
function stop_handleAsync1(ch, cx, status, data)
{
do_check_eq(data.length, 0);
}
test = new Test(PREPATH + "/handleAsync1",
null, start_handleAsync1, stop_handleAsync1),
tests.push(test);
const startToHeaderDelay = 500;
const startToFinishedDelay = 750;
function handleAsync2(request, response)
{
response.processAsync();
response.setStatusLine(request.httpVersion, 200, "Status line");
response.setHeader("X-Custom-Header", "value", false);
callLater(startToHeaderDelay, function()
{
var body = "BO";
response.bodyOutputStream.write(body, body.length);
try
{
response.setStatusLine(request.httpVersion, 500, "after body write");
do_throw("setStatusLine succeeded");
}
catch (e)
{
isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
}
try
{
response.setHeader("X-Custom-Header", "new 1", false);
}
catch (e)
{
isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
}
callLater(startToFinishedDelay - startToHeaderDelay, function()
{
var body = "DY";
response.bodyOutputStream.write(body, body.length);
response.finish();
response.finish(); // idempotency
try
{
response.setStatusLine(request.httpVersion, 500, "after finish");
}
catch (e)
{
isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
}
try
{
response.setHeader("X-Custom-Header", "new 2", false);
}
catch (e)
{
isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
}
try
{
response.write("EVIL");
}
catch (e)
{
isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
}
});
});
}
handlers["/handleAsync2"] = handleAsync2;
var startTime_handleAsync2;
function init_handleAsync2(ch)
{
var now = startTime_handleAsync2 = Date.now();
dumpn("*** init_HandleAsync2: start time " + now);
}
function start_handleAsync2(ch, cx)
{
var now = Date.now();
dumpn("*** start_handleAsync2: onStartRequest time " + now + ", " +
(now - startTime_handleAsync2) + "ms after start time");
do_check_true(now >= startTime_handleAsync2 + startToHeaderDelay);
do_check_eq(ch.responseStatus, 200);
do_check_eq(ch.responseStatusText, "Status line");
do_check_eq(ch.getResponseHeader("X-Custom-Header"), "value");
}
function stop_handleAsync2(ch, cx, status, data)
{
var now = Date.now();
dumpn("*** stop_handleAsync2: onStopRequest time " + now + ", " +
(now - startTime_handleAsync2) + "ms after header time");
do_check_true(now >= startTime_handleAsync2 + startToFinishedDelay);
do_check_eq(String.fromCharCode.apply(null, data), "BODY");
}
test = new Test(PREPATH + "/handleAsync2",
init_handleAsync2, start_handleAsync2, stop_handleAsync2);
tests.push(test);
const ASYNC_ERROR_BODY = "hi, I'm a body!";
function handleAsyncError(request, response)
{
response.setStatusLine(request.httpVersion, 200, "Async Error");
response.setHeader("X-Foo", "header value", false);
response.processAsync();
response.write(ASYNC_ERROR_BODY, ASYNC_ERROR_BODY.length);
// No turning back now -- except if there's an error!
throw "Monkey wrench!";
}
handlers["/handleAsyncError"] = handleAsyncError;
function start_handleAsyncError(ch, cx)
{
do_check_eq(ch.responseStatus, 200);
do_check_eq(ch.responseStatusText, "Async Error");
do_check_eq(ch.getResponseHeader("X-Foo"), "header value");
}
function stop_handleAsyncError(ch, cx, status, data)
{
// Lies! But not really!
do_check_true(ch.requestSucceeded);
// There's no way server APIs will ever guarantee exactly what data will show
// up here, but they will guarantee sending a (not necessarily strict) prefix
// of what was written.
do_check_true(data.length <= ASYNC_ERROR_BODY.length);
for (var i = 0, sz = data.length; i < sz; i++)
do_check_eq(data[i] == ASYNC_ERROR_BODY.charCodeAt(i));
}
test = new Test(PREPATH + "/handleAsyncError",
null, start_handleAsyncError, stop_handleAsyncError);
tests.push(test);
/*
* Tests that accessing output stream *before* calling processAsync() works
* correctly, sending written data immediately as it is written, not buffering
* until finish() is called -- which for this much data would mean we would all
* but certainly deadlock, since we're trying to read/write all this data in one
* process on a single thread.
*/
function handleAsyncOrdering(request, response)
{
var out = new BinaryOutputStream(response.bodyOutputStream);
var data = [];
for (var i = 0; i < 65536; i++)
data[i] = 0;
var count = 20;
var writeData =
{
run: function()
{
if (count-- === 0)
{
response.finish();
return;
}
try
{
out.writeByteArray(data, data.length);
step();
}
catch (e)
{
try
{
do_throw("error writing data: " + e);
}
finally
{
response.finish();
}
}
}
};
function step()
{
// Use gThreadManager here because it's expedient, *not* because it's
// intended for public use! If you do this in client code, expect me to
// knowingly break your code by changing the variable name. :-P
gThreadManager.currentThread
.dispatch(writeData, Ci.nsIThreadManager.DISPATCH_NORMAL);
}
step();
response.processAsync();
}
handlers["/handleAsyncOrdering"] = handleAsyncOrdering;
function stop_handleAsyncOrdering(ch, cx, status, data)
{
do_check_eq(data.length, 20 * 65536);
do_check_true(data.every(function(v) { return v === 0; }));
}
test = new Test(PREPATH + "/handleAsyncOrdering",
null, null, stop_handleAsyncOrdering);
tests.push(test);

Просмотреть файл

@ -69,7 +69,7 @@ function check200(ch)
do_check_eq(ch.responseStatusText, "OK");
}
function checkFile(ch)
function checkFile(ch, cx, status, data)
{
do_check_eq(ch.responseStatus, 200);
do_check_true(ch.requestSucceeded);
@ -78,6 +78,8 @@ function checkFile(ch)
actualFile.append("test_registerdirectory.js");
do_check_eq(ch.getResponseHeader("Content-Length"),
actualFile.fileSize.toString());
do_check_eq(data.map(function(v) String.fromCharCode(v)).join(""),
fileContents(actualFile));
}
@ -101,8 +103,8 @@ test = new Test(BASE + "/test_registerdirectory.js",
serverBasePath = testsDirectory.clone();
srv.registerDirectory("/", serverBasePath);
},
checkFile,
null);
null,
checkFile);
tests.push(test);
@ -166,8 +168,8 @@ test = new Test(BASE + "/test_registerdirectory.js",
serverBasePath = testsDirectory.clone();
srv.registerDirectory("/", serverBasePath);
},
checkFile,
null);
null,
checkFile);
tests.push(test);
@ -256,8 +258,8 @@ test = new Test(BASE + "/foo/test_registerdirectory.js/test_registerdirectory.js
srv.registerDirectory("/foo/test_registerdirectory.js/",
serverBasePath);
},
checkFile,
null);
null,
checkFile);
tests.push(test);
@ -266,7 +268,7 @@ tests.push(test);
************************************/
test = new Test(BASE + "/foo/test_registerdirectory.js",
nocache, checkFile, null);
nocache, null, checkFile);
tests.push(test);
@ -290,7 +292,7 @@ tests.push(test);
**************************************/
test = new Test(BASE + "/foo/test_registerdirectory.js/test_registerdirectory.js",
nocache, checkFile, null);
nocache, null, checkFile);
tests.push(test);
@ -321,7 +323,7 @@ function run_test()
srv = createServer();
srv.start(4444);
runHttpTests(tests, function() { srv.stop(); });
runHttpTests(tests, testComplete(srv));
}

Просмотреть файл

@ -40,12 +40,6 @@
const BASE = "http://localhost:4444";
function isException(e, code)
{
if (e !== code && e.result !== code)
do_throw("unexpected error: " + e);
}
var file = do_get_file("test_registerfile.js");
function onStart(ch, cx)
@ -78,5 +72,5 @@ function run_test()
srv.registerFile("/foo", file);
srv.start(4444);
runHttpTests([test], function() { srv.stop(); });
runHttpTests([test], testComplete(srv));
}

Просмотреть файл

@ -56,7 +56,7 @@ function run_test()
veryLongRequestLine);
srv.start(PORT);
runRawTests(tests, function() { srv.stop(); });
runRawTests(tests, testComplete(srv));
}

Просмотреть файл

@ -54,16 +54,16 @@ function run_test()
srv.registerPathHandler("/writeInt", writeInt);
srv.start(4444);
runHttpTests(tests, function() { srv.stop(); });
runHttpTests(tests, testComplete(srv));
}
// TEST DATA
function succeeded(ch, cx, status)
function succeeded(ch, cx, status, data)
{
do_check_true(Components.isSuccessCode(status));
do_check_eq(data.map(function(v) String.fromCharCode(v)).join(""), "1234");
}
function check_1234(ch, cx)
@ -71,7 +71,6 @@ function check_1234(ch, cx)
do_check_eq(ch.getResponseHeader("Content-Length"), "4");
}
// PATH HANDLERS
function writeString(metadata, response)

Просмотреть файл

@ -48,7 +48,7 @@ function run_test()
srv.setIndexHandler(myIndexHandler);
srv.start(4444);
runHttpTests(tests, function() { srv.stop(); });
runHttpTests(tests, testComplete(srv));
}

Просмотреть файл

@ -56,7 +56,7 @@ function run_test()
srv.start(4444);
runHttpTests(tests, function() { srv.stop() });
runHttpTests(tests, testComplete(srv));
}

Просмотреть файл

@ -50,12 +50,6 @@ var tests = [];
* UTILITY FUNCTIONS *
*********************/
function isException(e, code)
{
if (e !== code && e.result !== code)
do_throw("unexpected error: " + e);
}
function bytesToString(bytes)
{
return bytes.map(function(v) { return String.fromCharCode(v); }).join("");
@ -241,5 +235,5 @@ function run_test()
// test that doesn't care about throwing or not.
srv.start(4444);
runHttpTests(tests, function() { srv.stop(); });
runHttpTests(tests, testComplete(srv));
}

Просмотреть файл

@ -0,0 +1,322 @@
/* -*- 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 the object-state-preservation mechanism works correctly.
*/
const PORT = 4444;
const PATH = "http://localhost:" + PORT + "/object-state.sjs";
var srv;
function run_test()
{
srv = createServer();
var sjsDir = do_get_file("data/sjs/");
srv.registerDirectory("/", sjsDir);
srv.registerContentType("sjs", "sjs");
srv.start(PORT);
do_test_pending();
new HTTPTestLoader(PATH + "?state=initial", initialStart, initialStop);
}
/********************
* OBSERVER METHODS *
********************/
/*
* In practice the current implementation will guarantee an exact ordering of
* all start and stop callbacks. However, in the interests of robustness, this
* test will pass given any valid ordering of callbacks. Any ordering of calls
* which obeys the partial ordering shown by this directed acyclic graph will be
* handled correctly:
*
* initialStart
* |
* V
* intermediateStart
* |
* V
* intermediateStop
* | \
* | V
* | initialStop
* V
* triggerStart
* |
* V
* triggerStop
*
*/
var initialStarted = false;
function initialStart(ch, cx)
{
dumpn("*** initialStart");
if (initialStarted)
do_throw("initialStart: initialStarted is true?!?!");
initialStarted = true;
new HTTPTestLoader(PATH + "?state=intermediate",
intermediateStart, intermediateStop);
}
var initialStopped = false;
function initialStop(ch, cx, status, data)
{
dumpn("*** initialStop");
do_check_eq(data.map(function(v) { return String.fromCharCode(v); }).join(""),
"done");
do_check_eq(srv.getObjectState("object-state-test"), null);
if (!initialStarted)
do_throw("initialStop: initialStarted is false?!?!");
if (initialStopped)
do_throw("initialStop: initialStopped is true?!?!");
if (!intermediateStarted)
do_throw("initialStop: intermediateStarted is false?!?!");
if (!intermediateStopped)
do_throw("initialStop: intermediateStopped is false?!?!");
initialStopped = true;
checkForFinish();
}
var intermediateStarted = false;
function intermediateStart(ch, cx)
{
dumpn("*** intermediateStart");
do_check_neq(srv.getObjectState("object-state-test"), null);
if (!initialStarted)
do_throw("intermediateStart: initialStarted is false?!?!");
if (intermediateStarted)
do_throw("intermediateStart: intermediateStarted is true?!?!");
intermediateStarted = true;
}
var intermediateStopped = false;
function intermediateStop(ch, cx, status, data)
{
dumpn("*** intermediateStop");
do_check_eq(data.map(function(v) { return String.fromCharCode(v); }).join(""),
"intermediate");
do_check_neq(srv.getObjectState("object-state-test"), null);
if (!initialStarted)
do_throw("intermediateStop: initialStarted is false?!?!");
if (!intermediateStarted)
do_throw("intermediateStop: intermediateStarted is false?!?!");
if (intermediateStopped)
do_throw("intermediateStop: intermediateStopped is true?!?!");
intermediateStopped = true;
new HTTPTestLoader(PATH + "?state=trigger", triggerStart,
triggerStop);
}
var triggerStarted = false;
function triggerStart(ch, cx)
{
dumpn("*** triggerStart");
if (!initialStarted)
do_throw("triggerStart: initialStarted is false?!?!");
if (!intermediateStarted)
do_throw("triggerStart: intermediateStarted is false?!?!");
if (!intermediateStopped)
do_throw("triggerStart: intermediateStopped is false?!?!");
if (triggerStarted)
do_throw("triggerStart: triggerStarted is true?!?!");
triggerStarted = true;
}
var triggerStopped = false;
function triggerStop(ch, cx, status, data)
{
dumpn("*** triggerStop");
do_check_eq(data.map(function(v) { return String.fromCharCode(v); }).join(""),
"trigger");
if (!initialStarted)
do_throw("triggerStop: initialStarted is false?!?!");
if (!intermediateStarted)
do_throw("triggerStop: intermediateStarted is false?!?!");
if (!intermediateStopped)
do_throw("triggerStop: intermediateStopped is false?!?!");
if (!triggerStarted)
do_throw("triggerStop: triggerStarted is false?!?!");
if (triggerStopped)
do_throw("triggerStop: triggerStopped is false?!?!");
triggerStopped = true;
checkForFinish();
}
var finished = false;
function checkForFinish()
{
if (finished)
{
try
{
do_throw("uh-oh, how are we being finished twice?!?!");
}
finally
{
quit(1);
}
}
if (triggerStopped && initialStopped)
{
finished = true;
try
{
do_check_eq(srv.getObjectState("object-state-test"), null);
if (!initialStarted)
do_throw("checkForFinish: initialStarted is false?!?!");
if (!intermediateStarted)
do_throw("checkForFinish: intermediateStarted is false?!?!");
if (!intermediateStopped)
do_throw("checkForFinish: intermediateStopped is false?!?!");
if (!triggerStarted)
do_throw("checkForFinish: triggerStarted is false?!?!");
}
finally
{
srv.stop(do_test_finished);
}
}
}
/*********************************
* UTILITY OBSERVABLE URL LOADER *
*********************************/
/** Stream listener for the channels. */
function HTTPTestLoader(path, start, stop)
{
/** Path to load. */
this._path = path;
/** Array of bytes of data in body of response. */
this._data = [];
/** onStartRequest callback. */
this._start = start;
/** onStopRequest callback. */
this._stop = stop;
var channel = makeChannel(path);
channel.asyncOpen(this, null);
}
HTTPTestLoader.prototype =
{
onStartRequest: function(request, cx)
{
dumpn("*** HTTPTestLoader.onStartRequest for " + this._path);
var ch = request.QueryInterface(Ci.nsIHttpChannel)
.QueryInterface(Ci.nsIHttpChannelInternal);
try
{
try
{
this._start(ch, cx);
}
catch (e)
{
do_throw(this._path + ": error in onStartRequest: " + e);
}
}
catch (e)
{
dumpn("!!! swallowing onStartRequest exception so onStopRequest is " +
"called...");
}
},
onDataAvailable: function(request, cx, inputStream, offset, count)
{
dumpn("*** HTTPTestLoader.onDataAvailable for " + this._path);
Array.prototype.push.apply(this._data,
makeBIS(inputStream).readByteArray(count));
},
onStopRequest: function(request, cx, status)
{
dumpn("*** HTTPTestLoader.onStopRequest for " + this._path);
var ch = request.QueryInterface(Ci.nsIHttpChannel)
.QueryInterface(Ci.nsIHttpChannelInternal);
this._stop(ch, cx, status, this._data);
},
QueryInterface: function(aIID)
{
dumpn("*** QueryInterface: " + aIID);
if (aIID.equals(Ci.nsIStreamListener) ||
aIID.equals(Ci.nsIRequestObserver) ||
aIID.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}
};

Просмотреть файл

@ -61,7 +61,8 @@ function run_test()
"");
do_check_eq(srv.getState("/state2.sjs", "private-value"),
"newPrivate5");
srv.stop();
do_test_pending();
srv.stop(function() { do_test_finished(); });
}
runHttpTests(tests, done);

Просмотреть файл

@ -55,7 +55,8 @@ function run_test()
function done()
{
srv.stop();
do_test_pending();
srv.stop(function() { do_test_finished(); });
do_check_eq(gStartCount, TEST_RUNS);
do_check_true(lastPassed);
}

Просмотреть файл

@ -0,0 +1,210 @@
/* -*- 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) 2009
* 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 for correct behavior of the server start() and stop() methods.
*/
const PORT = 4444;
const PREPATH = "http://localhost:" + PORT;
var srv, srv2;
function run_test()
{
dumpn("*** run_test");
srv = createServer();
srv.start(PORT);
try
{
srv.start(PORT);
do_throw("starting a started server");
}
catch (e)
{
isException(e, Cr.NS_ERROR_ALREADY_INITIALIZED);
}
try
{
srv.stop();
do_throw("missing argument to stop");
}
catch (e)
{
isException(e, Cr.NS_ERROR_NULL_POINTER);
}
try
{
srv.stop(null);
do_throw("null argument to stop");
}
catch (e)
{
isException(e, Cr.NS_ERROR_NULL_POINTER);
}
do_test_pending();
srv.stop(function()
{
try
{
do_test_pending();
run_test_2();
}
finally
{
do_test_finished();
}
});
}
function run_test_2()
{
dumpn("*** run_test_2");
do_test_finished();
srv.start(PORT);
srv2 = createServer();
try
{
srv2.start(PORT);
do_throw("two servers on one port?");
}
catch (e)
{
isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
}
do_test_pending();
try
{
srv.stop({onStopped: function()
{
try
{
do_test_pending();
run_test_3();
}
finally
{
do_test_finished();
}
}
});
}
catch (e)
{
do_throw("error stopping with an object: " + e);
}
}
function run_test_3()
{
dumpn("*** run_test_3");
do_test_finished();
srv.registerPathHandler("/handle", handle);
srv.start(PORT);
// Don't rely on the exact (but implementation-constant) sequence of events
// as it currently exists by making either run_test_4 or serverStopped handle
// the final shutdown.
do_test_pending();
runHttpTests([new Test(PREPATH + "/handle")], run_test_4);
}
var testsComplete = false;
function run_test_4()
{
dumpn("*** run_test_4");
testsComplete = true;
if (stopped)
do_test_finished();
}
const INTERVAL = 500;
function handle(request, response)
{
response.processAsync();
dumpn("*** stopping server...");
srv.stop(serverStopped);
callLater(INTERVAL, function()
{
do_check_false(stopped);
callLater(INTERVAL, function()
{
do_check_false(stopped);
response.finish();
try
{
response.processAsync();
do_throw("late processAsync didn't throw?");
}
catch (e)
{
isException(e, Cr.NS_ERROR_UNEXPECTED);
}
});
});
}
var stopped = false;
function serverStopped()
{
dumpn("*** server really, fully shut down now");
stopped = true;
if (testsComplete)
do_test_finished();
}

Просмотреть файл

@ -236,8 +236,9 @@ var listener = {
current_test++;
tests[current_test]();
} else {
httpserv.stop();
} else {
do_test_pending();
httpserv.stop(do_test_finished);
}
do_test_finished();

Просмотреть файл

@ -13,7 +13,8 @@ var listener = {
},
onDownloadComplete: function(downloader, request, ctxt, status, file) {
server.stop();
do_test_pending();
server.stop(do_test_finished);
if (!file)
do_throw("Download failed");

Просмотреть файл

@ -11,8 +11,7 @@ TestListener.prototype.onStopRequest = function(request, context, status) {
var channel = request.QueryInterface(Components.interfaces.nsIHttpChannel);
do_check_eq(channel.responseStatus, 304);
server.stop();
do_test_finished();
server.stop(do_test_finished);
}
function run_test() {

Просмотреть файл

@ -28,8 +28,7 @@ function after_channel_closed() {
try {
change_content_type();
} finally {
server.stop();
do_test_finished();
server.stop(do_test_finished);
}
}

Просмотреть файл

@ -9,8 +9,7 @@ TestListener.prototype.onStartRequest = function(request, context) {
}
TestListener.prototype.onStopRequest = function(request, context, status) {
httpserv.stop();
do_test_finished();
httpserv.stop(do_test_finished);
}
function run_test() {

Просмотреть файл

@ -63,8 +63,7 @@ function do_test() {
}
else {
do_check_eq(handlers_called, "nocache,partial,cached");
httpserv.stop();
do_test_finished();
httpserv.stop(do_test_finished);
}
}

Просмотреть файл

@ -207,8 +207,7 @@ var gTests = [
function run_next_test()
{
if (gTests.length == 0) {
httpserver.stop();
do_test_finished();
httpserver.stop(do_test_finished);
return;
}

Просмотреть файл

@ -106,7 +106,8 @@ function run_test_iteration(index) {
sniffing_enabled = false;
index = listener._iteration = 1;
} else {
httpserv.stop();
do_test_pending();
httpserv.stop(do_test_finished);
return; // we're done
}
}

Просмотреть файл

@ -32,10 +32,12 @@ var listener = {
},
onStopRequest: function test_onStopR(request, ctx, status) {
if (this._iteration == 1)
if (this._iteration == 1) {
run_test_continued();
else
httpserv.stop();
} else {
do_test_pending();
httpserv.stop(do_test_finished);
}
do_test_finished();
},

Просмотреть файл

@ -81,10 +81,12 @@ var listener = {
},
onStopRequest: function test_onStopR(request, ctx, status) {
if (this._iteration <= 2)
if (this._iteration <= 2) {
run_test_continued();
else
httpserv.stop();
} else {
do_test_pending();
httpserv.stop(do_test_finished);
}
do_test_finished();
},

Просмотреть файл

@ -79,7 +79,8 @@ function continue_test() {
}
function finish_test(request, data, ctx) {
httpserver.stop();
do_test_pending();
httpserver.stop(do_test_finished);
do_check_eq(request.status, 0);
do_check_eq(data.length, responseBody.length);
for (var i = 0; i < data.length; ++i) {

Просмотреть файл

@ -33,8 +33,7 @@ var listener = {
},
onStopRequest: function test_onStopR(request, ctx, status) {
httpserv.stop();
do_test_finished();
httpserv.stop(do_test_finished);
}
};

Просмотреть файл

@ -131,7 +131,8 @@ function makeListener(headerIdx, bodyIdx) {
}
if (bodyIdx == bodyList.length) {
httpserv.stop();
do_test_pending();
httpserv.stop(do_test_finished);
} else {
doTest(headerIdx, bodyIdx);
}

Просмотреть файл

@ -36,9 +36,8 @@ function firstTimeThrough(request, buffer)
function finish_test(request, buffer)
{
httpserver.stop();
do_check_eq(buffer, responseBody);
do_test_finished();
httpserver.stop(do_test_finished);
}
function run_test()

Просмотреть файл

@ -132,8 +132,7 @@ function test_ftp_channel() {
}
function end() {
httpserv.stop();
do_test_finished();
httpserv.stop(do_test_finished);
}
function run_test() {

Просмотреть файл

@ -78,6 +78,7 @@ function run_test() {
var entityID;
function get_entity_id(request, data, ctx) {
dump("*** get_entity_id()\n");
do_check_true(request instanceof Ci.nsIResumableChannel,
"must be a resumable channel");
entityID = request.entityID;
@ -90,6 +91,7 @@ function run_test() {
}
function try_resume(request, data, ctx) {
dump("*** try_resume()\n");
do_check_eq(request.status, NS_ERROR_NOT_RESUMABLE);
// Try a successful resume
@ -99,6 +101,7 @@ function run_test() {
}
function try_resume_zero(request, data, ctx) {
dump("*** try_resume_zero()\n");
do_check_true(request.nsIHttpChannel.requestSucceeded);
do_check_eq(data, rangeBody.substring(1));
@ -110,6 +113,7 @@ function run_test() {
}
function try_no_range(request, data, ctx) {
dump("*** try_no_range()\n");
do_check_true(request.nsIHttpChannel.requestSucceeded);
do_check_eq(request.status, NS_ERROR_NOT_RESUMABLE);
@ -121,6 +125,7 @@ function run_test() {
}
function try_bytes_range(request, data, ctx) {
dump("*** try_bytes_range()\n");
do_check_true(request.nsIHttpChannel.requestSucceeded);
do_check_eq(data, rangeBody);
@ -132,6 +137,7 @@ function run_test() {
}
function try_foo_bar_range(request, data, ctx) {
dump("*** try_foo_bar_range()\n");
do_check_true(request.nsIHttpChannel.requestSucceeded);
do_check_eq(request.status, NS_ERROR_NOT_RESUMABLE);
@ -143,6 +149,7 @@ function run_test() {
}
function try_foobar_range(request, data, ctx) {
dump("*** try_foobar_range()\n");
do_check_true(request.nsIHttpChannel.requestSucceeded);
do_check_eq(request.status, NS_ERROR_NOT_RESUMABLE);
@ -154,6 +161,7 @@ function run_test() {
}
function try_bytes_foobar_range(request, data, ctx) {
dump("*** try_bytes_foobar_range()\n");
do_check_true(request.nsIHttpChannel.requestSucceeded);
do_check_eq(data, rangeBody);
@ -165,6 +173,7 @@ function run_test() {
}
function try_bytesfoo_bar_range(request, data, ctx) {
dump("*** try_bytesfoo_bar_range()\n");
do_check_true(request.nsIHttpChannel.requestSucceeded);
do_check_eq(request.status, NS_ERROR_NOT_RESUMABLE);
@ -175,6 +184,7 @@ function run_test() {
}
function try_no_accept_ranges(request, data, ctx) {
dump("*** try_no_accept_ranges()\n");
do_check_true(request.nsIHttpChannel.requestSucceeded);
do_check_eq(data, rangeBody);
@ -185,6 +195,7 @@ function run_test() {
}
function success(request, data, ctx) {
dump("*** success()\n");
do_check_true(request.nsIHttpChannel.requestSucceeded);
do_check_eq(data, rangeBody);
@ -197,6 +208,7 @@ function run_test() {
}
function test_auth_nopw(request, data, ctx) {
dump("*** test_auth_nopw()\n");
do_check_false(request.nsIHttpChannel.requestSucceeded);
do_check_eq(request.status, NS_ERROR_ENTITY_CHANGED);
@ -207,6 +219,7 @@ function run_test() {
chan.asyncOpen(new ChannelListener(test_auth, null, CL_EXPECT_FAILURE), null);
}
function test_auth(request, data, ctx) {
dump("*** test_auth()\n");
do_check_eq(request.status, NS_ERROR_NOT_RESUMABLE);
do_check_true(request.nsIHttpChannel.responseStatus < 300);
@ -219,6 +232,7 @@ function run_test() {
}
function test_auth_resume(request, data, ctx) {
dump("*** test_auth_resume()\n");
do_check_eq(data, rangeBody.substring(1));
do_check_true(request.nsIHttpChannel.requestSucceeded);
@ -230,6 +244,7 @@ function run_test() {
}
function test_404(request, data, ctx) {
dump("*** test_404()\n");
do_check_eq(request.status, NS_ERROR_ENTITY_CHANGED);
do_check_eq(request.nsIHttpChannel.responseStatus, 404);
@ -240,6 +255,7 @@ function run_test() {
}
function test_416(request, data, ctx) {
dump("*** test_416()\n");
do_check_eq(request.status, NS_ERROR_ENTITY_CHANGED);
do_check_eq(request.nsIHttpChannel.responseStatus, 416);
@ -251,6 +267,7 @@ function run_test() {
}
function test_redir_resume(request, data, ctx) {
dump("*** test_redir_resume()\n");
do_check_true(request.nsIHttpChannel.requestSucceeded);
do_check_eq(data, rangeBody.substring(1));
do_check_eq(request.nsIHttpChannel.responseStatus, 206);
@ -263,10 +280,10 @@ function run_test() {
}
function test_redir_noresume(request, data, ctx) {
dump("*** test_redir_noresume()\n");
do_check_eq(request.status, NS_ERROR_NOT_RESUMABLE);
httpserver.stop();
do_test_finished();
httpserver.stop(do_test_finished);
}
httpserver.start(4444);

Просмотреть файл

@ -67,8 +67,7 @@ Canceler.prototype = {
};
function finish_test() {
httpserver.stop();
do_test_finished();
httpserver.stop(do_test_finished);
}
function start_cache_read() {

Просмотреть файл

@ -57,8 +57,7 @@ TracingListener.prototype = {
onStopRequest: function(request, context, statusCode) {
this.listener.onStopRequest(request, context, statusCode);
httpserver.stop();
do_test_finished();
httpserver.stop(do_test_finished);
},
QueryInterface: function(iid) {

Просмотреть файл

@ -69,9 +69,9 @@ rdfLoadObserver.prototype =
gPending -= 1;
if (gPending == 0) {
server1.stop();
server2.stop();
do_test_finished();
do_test_pending();
server1.stop(do_test_finished);
server2.stop(do_test_finished);
}
},
onError : function() { }

Просмотреть файл

@ -114,6 +114,14 @@ function makeTags() {
}
}
var _quitting = false;
/** Quit when all activity has completed. */
function serverStopped()
{
_quitting = true;
}
// only run the "main" section if httpd.js was loaded ahead of us
if (this["nsHttpServer"]) {
//
@ -121,10 +129,16 @@ if (this["nsHttpServer"]) {
//
runServer();
// We can only have gotten here if the /server/shutdown path was requested,
// and we can shut down the xpcshell now that all testing requests have been
// served.
quit(0);
// We can only have gotten here if the /server/shutdown path was requested.
if (_quitting)
{
dumpn("HTTP server stopped, all pending requests complete");
quit(0);
}
// Impossible as the stop callback should have been called, but to be safe...
dumpn("TEST-UNEXPECTED-FAIL | failure to correctly shut down HTTP server");
quit(1);
}
var serverBasePath;
@ -276,8 +290,8 @@ function serverShutdown(metadata, response)
var body = "Server shut down.";
response.bodyOutputStream.write(body, body.length);
// Note: this doesn't disrupt the current request.
server.stop();
dumpn("Server shutting down now...");
server.stop(serverStopped);
}
//

Просмотреть файл

@ -195,8 +195,11 @@ function getDownloadListener()
do_test_finished();
}
if (gDownloadCount == 0)
httpserv.stop();
if (gDownloadCount == 0 && typeof httpserv != "undefined" && httpserv)
{
do_test_pending();
httpserv.stop(do_test_finished);
}
},
onStateChange: function(a, b, c, d, e) { },
onProgressChange: function(a, b, c, d, e, f, g) { },

Просмотреть файл

@ -78,10 +78,8 @@ function run_test()
timer.init(observer, 0, Ci.nsITimer.TYPE_ONE_SHOT);
}
if (Ci.nsIDownloadManager.DOWNLOAD_FINISHED == aDownload.state) {
httpserv.stop();
if (Ci.nsIDownloadManager.DOWNLOAD_FINISHED == aDownload.state)
do_test_finished();
}
},
onStateChange: function(a, b, c, d, e) { },
onProgressChange: function(a, b, c, d, e, f, g) { },

Просмотреть файл

@ -60,7 +60,9 @@ function run_test()
if (file.exists())
file.remove(false);
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
gDownloadCount++;
var dl = dm.addDownload(Ci.nsIDownloadManager.DOWNLOAD_TYPE_DOWNLOAD,
createURI("data:image/png;base64,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"),
createURI(file), null, null,
@ -95,7 +97,8 @@ function run_test()
do_test_finished();
break;
}
}
},
onStateChange: function(a, b, c, d, e) { }
};
dm.addListener(listener);

Просмотреть файл

@ -137,17 +137,13 @@ function run_test()
// extra real-resume check for the server
do_check_true(didResumeServer);
httpserv.stop();
httpserv.stop(do_test_finished);
aDl.targetFile.remove(false);
// we're done with the test!
do_test_finished();
}
else if (aDl.state == nsIDM.DOWNLOAD_FAILED) {
// this is only ok if we are not supposed to fail
do_check_true(doNotError);
httpserv.stop();
// we're done with the test!
do_test_finished();
httpserv.stop(do_test_finished);
}
},
onStateChange: function(a, b, aState, d, aDl) {

Просмотреть файл

@ -280,8 +280,7 @@ function run_test() {
// cleanup
prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
dm.removeListener(this);
httpserv.stop();
do_test_finished();
httpserv.stop(do_test_finished);
}
break;

Просмотреть файл

@ -123,9 +123,7 @@ function run_test()
do_check_eq(data.length, aDl.amountTransferred);
do_check_eq(data.length, aDl.size);
httpserv.stop();
// we're done with the test!
do_test_finished();
httpserv.stop(do_test_finished);
}
},
onStateChange: function(a, b, aState, d, aDl) {

Просмотреть файл

@ -136,17 +136,13 @@ function run_test()
// extra real-resume check for the server
do_check_true(didResumeServer);
httpserv.stop();
aDl.targetFile.remove(false);
// we're done with the test!
do_test_finished();
httpserv.stop(do_test_finished);
}
else if (aDl.state == nsIDM.DOWNLOAD_FAILED) {
// this is only ok if we are not supposed to fail
do_check_true(doNotError);
httpserv.stop();
// we're done with the test!
do_test_finished();
httpserv.stop(do_test_finished);
}
},
onStateChange: function(a, b, aState, d, aDl) {

Просмотреть файл

@ -451,7 +451,6 @@ function run_test_pt4() {
var item = gEM.getItemForID(ADDONS[i].id);
do_check_item(item, "0.2", ADDONS[i]);
}
do_test_finished();
testserver.stop();
testserver.stop(do_test_finished);
}

Просмотреть файл

@ -53,9 +53,7 @@ const checkListener = {
do_check_eq(item.minAppVersion, 1);
do_check_eq(item.maxAppVersion, 1);
do_test_finished();
testserver.stop();
testserver.stop(do_test_finished);
},
// nsIAddonUpdateCheckListener

Просмотреть файл

@ -183,6 +183,5 @@ function run_test() {
}
function test_complete() {
testserver.stop();
do_test_finished();
testserver.stop(do_test_finished);
}

Просмотреть файл

@ -88,8 +88,7 @@ var updateListener = {
onUpdateEnded: function()
{
server.stop();
do_test_finished();
server.stop(do_test_finished);
},
onAddonUpdateStarted: function(addon)

Просмотреть файл

@ -124,8 +124,7 @@ onUpdateStarted: function()
onUpdateEnded: function()
{
server.stop();
do_test_finished();
server.stop(do_test_finished);
},
onAddonUpdateStarted: function(addon)

Просмотреть файл

@ -52,9 +52,8 @@ var updateListener = {
onUpdateEnded: function onUpdateEnded()
{
server.stop();
do_test_finished();
do_check_eq(this._count, 2);
server.stop(do_test_finished);
},
onAddonUpdateStarted: function onAddonUpdateStarted(aAddon)

Просмотреть файл

@ -92,6 +92,5 @@ function run_test_pt2() {
dump("Checking onUpdateEnded\n");
do_check_true(checkListener._onUpdateEndedCalled);
do_check_eq(checkListener._onAddonUpdateStartedCount, checkListener._onAddonUpdateEndedCount);
testserver.stop();
do_test_finished();
testserver.stop(do_test_finished);
}

Просмотреть файл

@ -340,7 +340,6 @@ function downloaded_c() {
}
function test_complete() {
testserver.stop();
do_test_finished();
testserver.stop(do_test_finished);
}

Просмотреть файл

@ -124,8 +124,7 @@ var RecommendedCallback = {
},
searchFailed: function() {
do_test_finished();
server.stop();
server.stop(do_test_finished);
do_throw("Recommended results failed");
}
};
@ -135,27 +134,23 @@ var SearchCallback = {
do_check_false(addonRepo.isSearching);
checkResults(addons, length);
do_test_finished();
server.stop();
server.stop(do_test_finished);
},
searchFailed: function() {
do_test_finished();
server.stop();
server.stop(do_test_finished);
do_throw("Search results failed");
}
};
var FailCallback = {
searchSucceeded: function(addons, length, total) {
do_test_finished();
server.stop();
server.stop(do_test_finished);
do_throw("Should not be called");
},
searchFailed: function() {
do_test_finished();
server.stop();
server.stop(do_test_finished);
do_throw("Should not be called");
}
};

Просмотреть файл

@ -123,8 +123,7 @@ var RecommendedCallback = {
},
searchFailed: function() {
do_test_finished();
server.stop();
server.stop(do_test_finished);
do_throw("Recommended results failed");
}
};
@ -135,27 +134,23 @@ var SearchCallback = {
do_check_eq(total, 100);
checkResults(addons);
do_test_finished();
server.stop();
server.stop(do_test_finished);
},
searchFailed: function() {
do_test_finished();
server.stop();
server.stop(do_test_finished);
do_throw("Search results failed");
}
};
var FailCallback = {
searchSucceeded: function(addons, length, total) {
do_test_finished();
server.stop();
server.stop(do_test_finished);
do_throw("Should not be called");
},
searchFailed: function() {
do_test_finished();
server.stop();
server.stop(do_test_finished);
do_throw("Should not be called");
}
};

Просмотреть файл

@ -63,13 +63,11 @@ var RecommendedCallback = {
if (addons[i].rating != RESULTS[i])
do_throw("Rating for " + addons[i].id + " was " + addons[i].rating + ", should have been " + RESULTS[i]);
}
do_test_finished();
server.stop();
server.stop(do_test_finished);
},
searchFailed: function() {
do_test_finished();
server.stop();
server.stop(do_test_finished);
do_throw("Recommended results failed");
}
};

Просмотреть файл

@ -238,8 +238,7 @@ var installListener = {
function installNextAddon() {
if (gIndex >= ADDONS.length) {
testserver.stop();
do_test_finished();
testserver.stop(do_test_finished);
return;
}

Просмотреть файл

@ -98,8 +98,7 @@ function pathHandler(metadata, response) {
gOSVersion + "&1.9&distribution&distribution-version");
gBlocklist.observe(null, "quit-application", "");
gBlocklist.observe(null, "xpcom-shutdown", "");
testserver.stop();
do_test_finished();
testserver.stop(do_test_finished);
}
function run_test() {

Просмотреть файл

@ -597,6 +597,5 @@ function run_test_pt3() {
function check_test_pt3() {
dump("Checking pt 3\n");
check_state("appBlocks", "toolkitBlocks");
gTestserver.stop();
do_test_finished();
gTestserver.stop(do_test_finished);
}

Просмотреть файл

@ -526,6 +526,5 @@ function check_test_pt4() {
}
function finish() {
gTestserver.stop();
do_test_finished();
gTestserver.stop(do_test_finished);
}

Просмотреть файл

@ -257,6 +257,5 @@ function test_addon_9() {
}
function finish_test() {
testserver.stop();
do_test_finished();
testserver.stop(do_test_finished);
}

Просмотреть файл

@ -340,8 +340,9 @@ function start_httpserver(aRelativeDirName) {
}
/* Helper for stopping the http server used by the tests */
function stop_httpserver() {
gTestserver.stop();
function stop_httpserver(callback) {
do_check_true(!!callback);
gTestserver.stop(callback);
}
/**

Просмотреть файл

@ -58,8 +58,7 @@ function run_test() {
}
function end_test() {
stop_httpserver();
do_test_finished();
stop_httpserver(do_test_finished);
}
// Helper function for testing update counts returned from an update xml

Просмотреть файл

@ -58,8 +58,7 @@ function run_test() {
}
function end_test() {
stop_httpserver();
do_test_finished();
stop_httpserver(do_test_finished);
}
// Helper function for testing mar downloads that have the correct size

Просмотреть файл

@ -62,8 +62,7 @@ function run_test() {
}
function end_test() {
do_test_finished();
stop_httpserver();
stop_httpserver(do_test_finished);
}
// Helper function for parsing the result from the contructed url

Просмотреть файл

@ -64,8 +64,7 @@ function run_test() {
}
function end_test() {
stop_httpserver();
do_test_finished();
stop_httpserver(do_test_finished);
}
// Returns human readable status text from the updates.properties bundle