зеркало из https://github.com/mozilla/pjs.git
bug 367537. enhancements to httpd.js. add an index handler and respose.write. r=jwalden
This commit is contained in:
Родитель
178fbd42c6
Коммит
23223c2562
|
@ -1,3 +1,5 @@
|
|||
/* -*- 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
|
||||
*
|
||||
|
@ -22,6 +24,7 @@
|
|||
* Darin Fisher (v1, netwerk/test/TestServ.js)
|
||||
* Christian Biesinger (v2, netwerk/test/unit/head_http_server.js)
|
||||
* Jeff Walden <jwalden+code@mit.edu> (v3, netwerk/test/httpserver/httpd.js)
|
||||
* Robert Sayre <sayrer@gmail.com>
|
||||
*
|
||||
* 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
|
||||
|
@ -396,6 +399,14 @@ nsHttpServer.prototype =
|
|||
this._handler.registerErrorHandler(code, handler);
|
||||
},
|
||||
|
||||
//
|
||||
// see nsIHttpServer.setIndexHandler
|
||||
//
|
||||
setIndexHandler: function(handler)
|
||||
{
|
||||
this._handler.setIndexHandler(handler);
|
||||
},
|
||||
|
||||
// NSISUPPORTS
|
||||
|
||||
//
|
||||
|
@ -538,6 +549,16 @@ function createHandlerFunc(handler)
|
|||
return function(metadata, response) { handler.handle(metadata, response); };
|
||||
}
|
||||
|
||||
/**
|
||||
* The default handler for directories.
|
||||
*/
|
||||
function defaultIndexHandler(metadata, response)
|
||||
{
|
||||
var file = metadata.getProperty("directory");
|
||||
NS_ASSERT(file);
|
||||
|
||||
throw HTTP_501; // need directory listings ftw!
|
||||
}
|
||||
|
||||
/**
|
||||
* An object which handles requests for a server, executing default and
|
||||
|
@ -592,6 +613,12 @@ function ServerHandler(srv)
|
|||
* @see also ServerHandler.prototype._defaultErrors
|
||||
*/
|
||||
this._overrideErrors = {};
|
||||
|
||||
/**
|
||||
* Init our default handler for directories. The handler used to
|
||||
* serve directories when no index file is present.
|
||||
*/
|
||||
this._indexHandler = defaultIndexHandler;
|
||||
}
|
||||
ServerHandler.prototype =
|
||||
{
|
||||
|
@ -711,13 +738,7 @@ ServerHandler.prototype =
|
|||
if (path.charAt(0) != "/")
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
|
||||
// for convenience, handler can be a function if this is run from xpcshell
|
||||
if (typeof(handler) == "function")
|
||||
this._overridePaths[path] = handler;
|
||||
else if (handler)
|
||||
this._overridePaths[path] = createHandlerFunc(handler);
|
||||
else
|
||||
delete this._overridePaths[path];
|
||||
this._handlerToField(handler, this._overridePaths, path);
|
||||
},
|
||||
|
||||
//
|
||||
|
@ -752,13 +773,41 @@ ServerHandler.prototype =
|
|||
dumpn("*** WARNING: registering non-HTTP/1.1 error code " +
|
||||
"(" + err + ") handler -- was this intentional?");
|
||||
|
||||
this._handlerToField(handler, this._overrideErrors, err);
|
||||
},
|
||||
|
||||
//
|
||||
// see nsIHttpServer.setIndexHandler
|
||||
//
|
||||
setIndexHandler: function(handler)
|
||||
{
|
||||
if (!handler)
|
||||
handler = defaultIndexHandler;
|
||||
else if (typeof(handler) != "function")
|
||||
handler = createHandlerFunc(handler);
|
||||
|
||||
this._indexHandler = handler;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set or remove a handler in an ojbect with a key.
|
||||
* If handler is null, the key will be deleted.
|
||||
*
|
||||
* @param handler
|
||||
* A function or an nsIHttpRequestHandler object.
|
||||
* @param dict
|
||||
* The object to attach the handler to.
|
||||
* @param key
|
||||
* The field name of the handler.
|
||||
*/
|
||||
_handlerToField: function(handler, dict, key) {
|
||||
// for convenience, handler can be a function if this is run from xpcshell
|
||||
if (typeof(handler) == "function")
|
||||
this._overrideErrors[err] = handler;
|
||||
dict[key] = handler;
|
||||
else if (handler)
|
||||
this._overrideErrors[err] = createHandlerFunc(handler);
|
||||
dict[key] = createHandlerFunc(handler);
|
||||
else
|
||||
delete this._overrideErrors[err];
|
||||
delete dict[key];
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -800,13 +849,17 @@ ServerHandler.prototype =
|
|||
// path-to-directory mapping in the requested URL
|
||||
var file = this._getFileForPath(path);
|
||||
|
||||
// the "file" might be a directory -- deal
|
||||
// the "file" might be a directory, in which case we either serve the
|
||||
// contained index.html or make the index handler write the response
|
||||
if (file.exists() && file.isDirectory())
|
||||
{
|
||||
file.append("index.html"); // make configurable?
|
||||
if (!file.exists() ||
|
||||
file.isDirectory())
|
||||
throw HTTP_501; // need directory listings ftw!
|
||||
file.append("index.html"); // make configurable?
|
||||
if (!file.exists() || file.isDirectory())
|
||||
{
|
||||
metadata._bag.setPropertyAsInterface("directory", file.parent);
|
||||
this._indexHandler(metadata, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// alternately, the file might not exist
|
||||
|
@ -1457,6 +1510,15 @@ Response.prototype =
|
|||
return this._bodyOutputStream;
|
||||
},
|
||||
|
||||
//
|
||||
// see nsIHttpResponse.write
|
||||
//
|
||||
write: function(data)
|
||||
{
|
||||
var dataAsString = String(data);
|
||||
this.bodyOutputStream.write(dataAsString, dataAsString.length);
|
||||
},
|
||||
|
||||
//
|
||||
// see nsIHttpResponse.setStatusLine
|
||||
//
|
||||
|
@ -2013,6 +2075,13 @@ function RequestMetadata(port)
|
|||
*/
|
||||
this._headers = new nsHttpHeaders();
|
||||
|
||||
/**
|
||||
* For the addition of ad-hoc properties and new functionality
|
||||
* without having to tweak nsIHttpRequestMetadata every time.
|
||||
*/
|
||||
this._bag = Cc["@mozilla.org/hash-property-bag;1"]
|
||||
.createInstance(Ci.nsIWritablePropertyBag2);
|
||||
|
||||
/**
|
||||
* The numeric HTTP error, if any, associated with this request. This value
|
||||
* may be set by the constructor but is usually only set by the handler after
|
||||
|
@ -2101,6 +2170,22 @@ RequestMetadata.prototype =
|
|||
return this._headers.enumerator;
|
||||
},
|
||||
|
||||
//
|
||||
// see nsIPropertyBag.enumerator
|
||||
//
|
||||
get enumerator()
|
||||
{
|
||||
return this._bag.enumerator;
|
||||
},
|
||||
|
||||
//
|
||||
// see nsIPropertyBag.getProperty
|
||||
//
|
||||
getProperty: function(name)
|
||||
{
|
||||
return this._bag.getProperty(name);
|
||||
},
|
||||
|
||||
// ENTITY
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Jeff Walden <jwalden+code@mit.edu> (original author)
|
||||
* Robert Sayre <sayrer@gmail.com>
|
||||
*
|
||||
* 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
|
||||
|
@ -36,6 +37,7 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsIServerSocket.idl"
|
||||
#include "nsIPropertyBag.idl"
|
||||
|
||||
interface nsILocalFile;
|
||||
interface nsISimpleEnumerator;
|
||||
|
@ -145,8 +147,22 @@ interface nsIHttpServer : nsIServerSocketListener
|
|||
* does not begin with and end with a forward slash
|
||||
*/
|
||||
void registerDirectory(in string path, in nsILocalFile dir);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the handler used to display the contents of a directory if
|
||||
* the directory contains no index page.
|
||||
*
|
||||
* @param handler
|
||||
* an object which will handle any requests for directories which
|
||||
* do not contain index pages, or null to reset to the default
|
||||
* index handler; if while the server is running the handler
|
||||
* throws an exception while responding to a request, an HTTP 500
|
||||
* response will be returned. An nsIFile corresponding to the
|
||||
* directory is available from the metadata object passed to the
|
||||
* handler, under the key "directory".
|
||||
*/
|
||||
void setIndexHandler(in nsIHttpRequestHandler handler);
|
||||
};
|
||||
|
||||
/**
|
||||
* A representation of a handler for HTTP requests. The handler is used by
|
||||
|
@ -183,8 +199,8 @@ interface nsIHttpRequestHandler : nsISupports
|
|||
/**
|
||||
* A representation of the data included in an HTTP request.
|
||||
*/
|
||||
[scriptable, uuid(acbb5ea6-58b3-4750-bcc7-618910ebca9d)]
|
||||
interface nsIHttpRequestMetadata : nsISupports
|
||||
[scriptable, uuid(3a899b17-b6eb-4333-8ef4-912df454a551)]
|
||||
interface nsIHttpRequestMetadata : nsIPropertyBag
|
||||
{
|
||||
/**
|
||||
* The request type for this request (see RFC 2616, section 5.1.1).
|
||||
|
@ -269,7 +285,7 @@ interface nsIHttpRequestMetadata : nsISupports
|
|||
/**
|
||||
* Represents an HTTP response, as described in RFC 2616, section 6.
|
||||
*/
|
||||
[scriptable, uuid(017f962b-137e-4911-887c-61808e89fa4f)]
|
||||
[scriptable, uuid(a2aaaff7-03bd-43b6-b460-94671e288093)]
|
||||
interface nsIHttpResponse : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -317,4 +333,12 @@ interface nsIHttpResponse : nsISupports
|
|||
* written.
|
||||
*/
|
||||
readonly attribute nsIOutputStream bodyOutputStream;
|
||||
|
||||
/**
|
||||
* Write a string to the response's output stream.
|
||||
*
|
||||
* @note
|
||||
* This method is only guaranteed to work with ASCII data.
|
||||
*/
|
||||
void write(in string data);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/* -*- 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 <jwalden+code@mit.edu>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* 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 ***** */
|
||||
|
||||
// make sure response.write works for strings, and coerces other args to strings
|
||||
|
||||
var paths =
|
||||
[
|
||||
"http://localhost:4444/writeString",
|
||||
"http://localhost:4444/writeInt"
|
||||
];
|
||||
var currPathIndex = 0;
|
||||
|
||||
var listener =
|
||||
{
|
||||
// NSISTREAMLISTENER
|
||||
onDataAvailable: function(request, cx, inputStream, offset, count)
|
||||
{
|
||||
makeBIS(inputStream).readByteArray(count); // required by API
|
||||
},
|
||||
// NSIREQUESTOBSERVER
|
||||
onStartRequest: function(request, cx)
|
||||
{
|
||||
var ch = request.QueryInterface(Ci.nsIHttpChannel)
|
||||
.QueryInterface(Ci.nsIHttpChannelInternal);
|
||||
|
||||
switch (currPathIndex)
|
||||
{
|
||||
case 0:
|
||||
do_check_eq(ch.getResponseHeader("Content-Length"), "4");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
do_check_eq(ch.getResponseHeader("Content-Length"), "4");
|
||||
break;
|
||||
}
|
||||
},
|
||||
onStopRequest: function(request, cx, status)
|
||||
{
|
||||
do_check_true(Components.isSuccessCode(status));
|
||||
if (++currPathIndex == paths.length)
|
||||
srv.stop();
|
||||
else
|
||||
performNextTest();
|
||||
do_test_finished();
|
||||
},
|
||||
// NSISUPPORTS
|
||||
QueryInterface: function(aIID)
|
||||
{
|
||||
if (aIID.equals(Ci.nsIStreamListener) ||
|
||||
aIID.equals(Ci.nsIRequestObserver) ||
|
||||
aIID.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
|
||||
function performNextTest()
|
||||
{
|
||||
do_test_pending();
|
||||
|
||||
var ch = makeChannel(paths[currPathIndex]);
|
||||
ch.asyncOpen(listener, null);
|
||||
}
|
||||
|
||||
var srv;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
srv = createServer();
|
||||
|
||||
srv.registerPathHandler("/writeString", writeString);
|
||||
srv.registerPathHandler("/writeInt", writeInt);
|
||||
srv.start(4444);
|
||||
|
||||
performNextTest();
|
||||
}
|
||||
|
||||
// PATH HANDLERS
|
||||
|
||||
function writeString(metadata, response)
|
||||
{
|
||||
response.write("1234");
|
||||
}
|
||||
|
||||
function writeInt(metadata, response)
|
||||
{
|
||||
response.write(1234);
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/* -*- 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 <jwalden+code@mit.edu>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* 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 ***** */
|
||||
|
||||
// Make sure setIndexHandler works as expected
|
||||
|
||||
var paths =
|
||||
[
|
||||
"http://localhost:4444/",
|
||||
"http://localhost:4444/"
|
||||
];
|
||||
var currPathIndex = 0;
|
||||
|
||||
var listener =
|
||||
{
|
||||
// NSISTREAMLISTENER
|
||||
onDataAvailable: function(request, cx, inputStream, offset, count)
|
||||
{
|
||||
makeBIS(inputStream).readByteArray(count); // required by API
|
||||
},
|
||||
// NSIREQUESTOBSERVER
|
||||
onStartRequest: function(request, cx)
|
||||
{
|
||||
var ch = request.QueryInterface(Ci.nsIHttpChannel)
|
||||
.QueryInterface(Ci.nsIHttpChannelInternal);
|
||||
|
||||
switch (currPathIndex)
|
||||
{
|
||||
case 0:
|
||||
do_check_eq(ch.getResponseHeader("Content-Length"), "10");
|
||||
srv.setIndexHandler(null);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
do_check_eq(ch.responseStatus, 500);
|
||||
break;
|
||||
}
|
||||
},
|
||||
onStopRequest: function(request, cx, status)
|
||||
{
|
||||
do_check_true(Components.isSuccessCode(status));
|
||||
if (++currPathIndex == paths.length)
|
||||
srv.stop();
|
||||
else
|
||||
performNextTest();
|
||||
do_test_finished();
|
||||
},
|
||||
// NSISUPPORTS
|
||||
QueryInterface: function(aIID)
|
||||
{
|
||||
if (aIID.equals(Ci.nsIStreamListener) ||
|
||||
aIID.equals(Ci.nsIRequestObserver) ||
|
||||
aIID.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
|
||||
function performNextTest()
|
||||
{
|
||||
do_test_pending();
|
||||
|
||||
var ch = makeChannel(paths[currPathIndex]);
|
||||
ch.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; // important!
|
||||
ch.asyncOpen(listener, null);
|
||||
}
|
||||
|
||||
var srv;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
srv = createServer();
|
||||
dirServ = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties);
|
||||
serverBasePath = dirServ.get("CurProcD", Ci.nsILocalFile);
|
||||
serverBasePath.append("httpserver_tests");
|
||||
srv.registerDirectory("/", serverBasePath);
|
||||
srv.setIndexHandler(myIndexHandler);
|
||||
srv.start(4444);
|
||||
|
||||
performNextTest();
|
||||
}
|
||||
|
||||
// PATH HANDLERS
|
||||
|
||||
function myIndexHandler(metadata, response)
|
||||
{
|
||||
response.write("directory!");
|
||||
}
|
Загрузка…
Ссылка в новой задаче