HTTP server for unit tests

  • Revision slug: Httpd.js/HTTP_server_for_unit_tests
  • Revision title: HTTP server for unit tests
  • Revision id: 85542
  • Created:
  • Creator: Waldo
  • Is current revision? No
  • Comment update for HTTP headers

Revision Content

This page describes the JavaScript implementation of an HTTP server located in {{template.Source("netwerk/test/httpserver/")}}.

Functionality

Here are some of the things you can do with the server:

  • map a directory of files onto an HTTP path on the server, for an arbitrary number of such directories (including nested directories)
  • define custom error handlers for HTTP error codes
  • serve a given file for requests for a specific path, optionally with custom headers and status
  • define custom "CGI" handlers for specific paths using a JavaScript-based API to create the response (headers and actual content)
  • run multiple servers at once on different ports (8080, 8081, 8082, etc.)

This functionality should be more than enough for you to use it with any test which requires storage on an HTTP server but doesn't require a particular host.

Where you can use it

The server is written primarily for use from xpcshell-based tests, and it can be used as an inline script or as an XPCOM component (assuming you've compiled the server's IDL file and deployed the XPT correctly). The Mochitest framework also uses it to serve its tests.

Ways you might use it

  • application update testing
  • cross-"server" (but, alas, not cross-subdomain) security tests
  • tests where the behavior is dependent on the values of HTTP headers (e.g., Content-Type)
  • anything which requires use of files not stored locally
  •  ???

Functionality

The best and first place you should look for documentation is {{template.Source("netwerk/test/httpserver/nsIHttpServer.idl")}}. It's extremely comprehensive and detailed, and it should be enough to figure out how to make the server do what you want. I also suggest taking a look at the less-comprehensive server {{template.Source("netwerk/test/httpserver/README", "README")}}, although the IDL should usually be sufficient.

Running the server

To use the server in xpcshell-based tests, include the following line at the top of your test file:

do_import_script("netwerk/test/httpserver/httpd.js");

Once you've done that, you can create a new server as follows:

var server = new nsHttpServer();

server.registerDirectory("/", nsILocalFileForBasePath);

const SERVER_PORT = 8080; // or some suitably large number
server.start(SERVER_PORT);

// and when the tests are done, most likely from a callback...
server.stop();

Note that because the server only runs when the xpcshell event loop is spun, you'll have to use do_test_pending(); and doing your testing via callbacks, making sure to call do_test_finished(); when the tests finish. Doing so is a little hairy, but since such a test is unlikely to be synchronous anyway it shouldn't be too hard to handle server asynchronicity.

Header modification for files

The server supports modifying the headers of the files (not request handlers) it serves. To modify the headers for a file, create a sibling file with the first file's name followed by ^headers^. Here's an example of how such a file might look:

HTTP 404 I want a cool HTTP description!
Content-Type: text/plain

The status line is optional; all other lines specify HTTP headers in the standard HTTP format. Any line ending style is accepted, and the file may optionally end in a single blank line, to play nice with Unix text tools like diff and cvs.

Examples

Shorter examples (for tests which only do one test):

  • {{template.Source("netwerk/test/unit/test_bug331825.js")}}
  • {{template.Source("netwerk/test/unit/test_httpcancel.js")}}
  • {{template.Source("netwerk/test/unit/test_cookie_header.js")}}

Longer tests (where you'd need to do multiple async server requests):

  • {{template.Source("netwerk/test/httpserver/test/test_setstatusline.js")}}
  • {{template.Source("netwerk/test/unit/test_content_sniffer.js")}}
  • {{template.Source("netwerk/test/unit/test_authentication.js")}}
  • {{template.Source("netwerk/test/unit/test_event_sink.js")}}
  • {{template.Source("netwerk/test/httpserver/test/")}}

Examples of modifying HTTP headers in files may be found at {{template.Source("netwerk/test/httpserver/test/data/cern_meta/")}}.

Future directions

The server, while very functional, is not yet complete. There are a number of things to fix and features to add, among them support for sending requests as their data is generated (instead of batching it and sending all at once when the response is fully created -- no bug yet), POST method support (either {{template.Bug(370245)}} or {{template.Bug(366371)}}, depending on whether underlying platform issues can be solved), server-side JS scripts (no bug yet), and better conformance to the MUSTs and SHOULDs of HTTP/1.1. If you have suggestions for functionality or find bugs, file them in {{wiki.template('Enter-bug', [ "Core", "Testing" ])}} and CC jwalden+bmo.

Revision Source

<p>This page describes the JavaScript implementation of an HTTP server located in {{template.Source("netwerk/test/httpserver/")}}.
</p>
<h3 name="Functionality"> Functionality </h3>
<p>Here are some of the things you can do with the server:
</p>
<ul><li> map a directory of files onto an HTTP path on the server, for an arbitrary number of such directories (including nested directories)
</li><li> define custom error handlers for HTTP error codes
</li><li> serve a given file for requests for a specific path, optionally with custom headers and status
</li><li> define custom "CGI" handlers for specific paths using a JavaScript-based API to create the response (headers and actual content)
</li><li> run multiple servers at once on different ports (8080, 8081, 8082, etc.)
</li></ul>
<p>This functionality should be more than enough for you to use it with any test which requires storage on an HTTP server but doesn't require a particular host.
</p>
<h3 name="Where_you_can_use_it"> Where you can use it </h3>
<p>The server is written primarily for use from <a href="en/Writing_xpcshell-based_unit_tests">xpcshell-based tests</a>, and it can be used as an inline script or as an XPCOM component (assuming you've compiled the server's IDL file and deployed the XPT correctly).  The <a href="en/Mochitest">Mochitest</a> framework also uses it to serve its tests.
</p>
<h3 name="Ways_you_might_use_it"> Ways you might use it </h3>
<ul><li> application update testing
</li><li> cross-"server" (but, alas, not cross-subdomain) security tests
</li><li> tests where the behavior is dependent on the values of HTTP headers (e.g., Content-Type)
</li><li> anything which requires use of files not stored locally
</li><li> ???
</li></ul>
<h3 name="Functionality_2"> Functionality </h3>
<p>The best and first place you should look for documentation is {{template.Source("netwerk/test/httpserver/nsIHttpServer.idl")}}.  It's extremely comprehensive and detailed, and it should be enough to figure out how to make the server do what you want.  I also suggest taking a look at the less-comprehensive server {{template.Source("netwerk/test/httpserver/README", "README")}}, although the IDL should usually be sufficient.
</p>
<h4 name="Running_the_server"> Running the server </h4>
<p>To use the server in <a href="en/Writing_xpcshell-based_unit_tests">xpcshell-based tests</a>, include the following line at the top of your test file:
</p>
<pre class="eval">do_import_script("netwerk/test/httpserver/httpd.js");
</pre>
<p>Once you've done that, you can create a new server as follows:
</p>
<pre class="eval">var server = new nsHttpServer();

server.registerDirectory("/", nsILocalFileForBasePath);

const SERVER_PORT = 8080; // or some suitably large number
server.start(SERVER_PORT);

// and when the tests are done, most likely from a callback...
server.stop();
</pre>
<p>Note that because the server only runs when the xpcshell event loop is spun, you'll have to use <code>do_test_pending();</code> and doing your testing via callbacks, making sure to call <code>do_test_finished();</code> when the tests finish.  Doing so is a little hairy, but since such a test is unlikely to be synchronous anyway it shouldn't be too hard to handle server asynchronicity.
</p>
<h4 name="Header_modification_for_files"> Header modification for files </h4>
<p>The server supports modifying the headers of the files (not request handlers) it serves.  To modify the headers for a file, create a sibling file with the first file's name followed by <code>^headers^</code>.  Here's an example of how such a file might look:
</p>
<pre class="eval">HTTP 404 I want a cool HTTP description!
Content-Type: text/plain
</pre>
<p>The status line is optional; all other lines specify HTTP headers in the standard HTTP format.  Any line ending style is accepted, and the file may optionally end in a single blank line, to play nice with Unix text tools like diff and cvs.
</p>
<h3 name="Examples"> Examples </h3>
<p>Shorter examples (for tests which only do one test):
</p>
<ul><li> {{template.Source("netwerk/test/unit/test_bug331825.js")}}
</li><li> {{template.Source("netwerk/test/unit/test_httpcancel.js")}}
</li><li> {{template.Source("netwerk/test/unit/test_cookie_header.js")}}
</li></ul>
<p>Longer tests (where you'd need to do multiple async server requests):
</p>
<ul><li> {{template.Source("netwerk/test/httpserver/test/test_setstatusline.js")}}
</li><li> {{template.Source("netwerk/test/unit/test_content_sniffer.js")}}
</li><li> {{template.Source("netwerk/test/unit/test_authentication.js")}}
</li><li> {{template.Source("netwerk/test/unit/test_event_sink.js")}}
</li><li> {{template.Source("netwerk/test/httpserver/test/")}}
</li></ul>
<p>Examples of modifying HTTP headers in files may be found at {{template.Source("netwerk/test/httpserver/test/data/cern_meta/")}}.
</p>
<h3 name="Future_directions"> Future directions </h3>
<p>The server, while very functional, is not yet complete.  There are a number of things to fix and features to add, among them support for sending requests as their data is generated (instead of batching it and sending all at once when the response is fully created -- no bug yet), POST method support (either {{template.Bug(370245)}} or {{template.Bug(366371)}}, depending on whether underlying platform issues can be solved), server-side JS scripts (no bug yet), and better conformance to the MUSTs and SHOULDs of HTTP/1.1.  If you have suggestions for functionality or find bugs, file them in {{wiki.template('Enter-bug', [ "Core", "Testing" ])}} and CC jwalden+bmo.
</p>
Revert to this revision