diff options
Diffstat (limited to 'netwerk/test/httpserver/test/test_host.js')
-rw-r--r-- | netwerk/test/httpserver/test/test_host.js | 608 |
1 files changed, 608 insertions, 0 deletions
diff --git a/netwerk/test/httpserver/test/test_host.js b/netwerk/test/httpserver/test/test_host.js new file mode 100644 index 0000000000..2f5fadde92 --- /dev/null +++ b/netwerk/test/httpserver/test/test_host.js @@ -0,0 +1,608 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Tests that the scheme, host, and port of the server are correctly recorded + * and used in HTTP requests and responses. + */ + +"use strict"; + +const PORT = 4444; +const FAKE_PORT_ONE = 8888; +const FAKE_PORT_TWO = 8889; + +let srv, id; + +add_task(async function run_test1() { + dump("*** run_test1"); + + srv = createServer(); + + srv.registerPathHandler("/http/1.0-request", http10Request); + srv.registerPathHandler("/http/1.1-good-host", http11goodHost); + srv.registerPathHandler( + "/http/1.1-good-host-wacky-port", + http11goodHostWackyPort + ); + srv.registerPathHandler("/http/1.1-ip-host", http11ipHost); + + srv.start(FAKE_PORT_ONE); + + 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 + // of the default set of locations. + Assert.equal(id.primaryScheme, "http"); + Assert.equal(id.primaryHost, "localhost"); + Assert.equal(id.primaryPort, FAKE_PORT_ONE); + Assert.ok(id.has("http", "localhost", FAKE_PORT_ONE)); + Assert.ok(id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + + // This should be a nop. + id.add("http", "localhost", FAKE_PORT_ONE); + Assert.equal(id.primaryScheme, "http"); + Assert.equal(id.primaryHost, "localhost"); + Assert.equal(id.primaryPort, FAKE_PORT_ONE); + Assert.ok(id.has("http", "localhost", FAKE_PORT_ONE)); + Assert.ok(id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + + // Change the primary location and make sure all the getters work correctly. + id.setPrimary("http", "127.0.0.1", FAKE_PORT_ONE); + Assert.equal(id.primaryScheme, "http"); + Assert.equal(id.primaryHost, "127.0.0.1"); + Assert.equal(id.primaryPort, FAKE_PORT_ONE); + Assert.ok(id.has("http", "localhost", FAKE_PORT_ONE)); + Assert.ok(id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + + // Okay, now remove the primary location -- we fall back to the original + // location. + id.remove("http", "127.0.0.1", FAKE_PORT_ONE); + Assert.equal(id.primaryScheme, "http"); + Assert.equal(id.primaryHost, "localhost"); + Assert.equal(id.primaryPort, FAKE_PORT_ONE); + Assert.ok(id.has("http", "localhost", FAKE_PORT_ONE)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + + // You can't remove every location -- try this and the original default + // location will be silently readded. + id.remove("http", "localhost", FAKE_PORT_ONE); + Assert.equal(id.primaryScheme, "http"); + Assert.equal(id.primaryHost, "localhost"); + Assert.equal(id.primaryPort, FAKE_PORT_ONE); + Assert.ok(id.has("http", "localhost", FAKE_PORT_ONE)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + + // 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. + + await new Promise(resolve => srv.stop(resolve)); +}); + +add_task(async function run_test_2() { + dump("*** run_test_2"); + + // Our primary location is gone because it was dependent on the port on which + // the server was running. + checkPrimariesThrow(id); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_ONE)); + + srv.start(FAKE_PORT_TWO); + + // We should have picked up http://localhost:8889 as our primary location now + // that we've restarted. + Assert.equal(id.primaryScheme, "http"); + Assert.equal(id.primaryHost, "localhost"); + Assert.equal(id.primaryPort, FAKE_PORT_TWO); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_ONE)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + Assert.ok(id.has("http", "localhost", FAKE_PORT_TWO)); + Assert.ok(id.has("http", "127.0.0.1", FAKE_PORT_TWO)); + + // Now we're going to see what happens when we shut down with a primary + // location that wasn't a default. That location should persist, and the + // default we remove should still not be present. + id.setPrimary("http", "example.com", FAKE_PORT_TWO); + Assert.ok(id.has("http", "example.com", FAKE_PORT_TWO)); + Assert.ok(id.has("http", "127.0.0.1", FAKE_PORT_TWO)); + Assert.ok(id.has("http", "localhost", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_ONE)); + + id.remove("http", "localhost", FAKE_PORT_TWO); + Assert.ok(id.has("http", "example.com", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_TWO)); + Assert.ok(id.has("http", "127.0.0.1", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_ONE)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + + id.remove("http", "127.0.0.1", FAKE_PORT_TWO); + Assert.ok(id.has("http", "example.com", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_ONE)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + + await new Promise(resolve => srv.stop(resolve)); +}); + +add_task(async function run_test_3() { + dump("*** run_test_3"); + + // Only the default added location disappears; any others stay around, + // possibly as the primary location. We may have removed the default primary + // location, but the one we set manually should persist here. + Assert.equal(id.primaryScheme, "http"); + Assert.equal(id.primaryHost, "example.com"); + Assert.equal(id.primaryPort, FAKE_PORT_TWO); + Assert.ok(id.has("http", "example.com", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_ONE)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + + srv.start(PORT); + + // Starting always adds HTTP entries for 127.0.0.1:port and localhost:port. + Assert.ok(id.has("http", "example.com", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_ONE)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + Assert.ok(id.has("http", "localhost", PORT)); + Assert.ok(id.has("http", "127.0.0.1", PORT)); + + // Remove the primary location we'd left set from last time. + id.remove("http", "example.com", FAKE_PORT_TWO); + + // Default-port behavior testing requires the server responds to requests + // claiming to be on one such port. + id.add("http", "localhost", 80); + + // Make sure we don't have anything lying around from running on either the + // first or the second port -- all we should have is our generated default, + // plus the additional port to test "portless" hostport variants. + Assert.ok(id.has("http", "localhost", 80)); + Assert.equal(id.primaryScheme, "http"); + Assert.equal(id.primaryHost, "localhost"); + Assert.equal(id.primaryPort, PORT); + Assert.ok(id.has("http", "localhost", PORT)); + Assert.ok(id.has("http", "127.0.0.1", PORT)); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_ONE)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_ONE)); + Assert.ok(!id.has("http", "example.com", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "localhost", FAKE_PORT_TWO)); + Assert.ok(!id.has("http", "127.0.0.1", FAKE_PORT_TWO)); + + // Okay, finally done with identity testing. Our primary location is the one + // we want it to be, so we're off! + await new Promise(resolve => + runRawTests(tests, resolve, idx => dump(`running test no ${idx}`)) + ); + + // Finally shut down the server. + await new Promise(resolve => srv.stop(resolve)); +}); + +/** ******************* + * UTILITY FUNCTIONS * + *********************/ + +/** + * Verifies that all .primary* getters on a server identity correctly throw + * NS_ERROR_NOT_INITIALIZED. + * + * @param aId : nsIHttpServerIdentity + * the server identity to test + */ +function checkPrimariesThrow(aId) { + let threw = false; + try { + aId.primaryScheme; + } catch (e) { + threw = e.result === Cr.NS_ERROR_NOT_INITIALIZED; + } + Assert.ok(threw); + + threw = false; + try { + aId.primaryHost; + } catch (e) { + threw = e.result === Cr.NS_ERROR_NOT_INITIALIZED; + } + Assert.ok(threw); + + threw = false; + try { + aId.primaryPort; + } catch (e) { + threw = e.result === Cr.NS_ERROR_NOT_INITIALIZED; + } + Assert.ok(threw); +} + +/** + * Utility function to check for a 400 response. + */ +function check400(aData) { + let iter = LineIterator(aData); + + // Status-Line + let { value: firstLine } = iter.next(); + Assert.equal(firstLine.substring(0, HTTP_400_LEADER_LENGTH), HTTP_400_LEADER); +} + +/** ************* + * BEGIN TESTS * + ***************/ + +const HTTP_400_LEADER = "HTTP/1.1 400 "; +const HTTP_400_LEADER_LENGTH = HTTP_400_LEADER.length; + +var test, data; +var tests = []; + +// HTTP/1.0 request, to ensure we see our default scheme/host/port + +function http10Request(request, response) { + writeDetails(request, response); + response.setStatusLine("1.0", 200, "TEST PASSED"); +} +data = "GET /http/1.0-request HTTP/1.0\r\n\r\n"; +function check10(aData) { + let iter = LineIterator(aData); + + // Status-Line + Assert.equal(iter.next().value, "HTTP/1.0 200 TEST PASSED"); + + skipHeaders(iter); + + // Okay, next line must be the data we expected to be written + let body = [ + "Method: GET", + "Path: /http/1.0-request", + "Query: ", + "Version: 1.0", + "Scheme: http", + "Host: localhost", + "Port: 4444", + ]; + + expectLines(iter, body); +} +test = new RawTest("localhost", PORT, data, check10); +tests.push(test); + +// HTTP/1.1 request, no Host header, expect a 400 response + +// eslint-disable-next-line no-useless-concat +data = "GET /http/1.1-request HTTP/1.1\r\n" + "\r\n"; +test = new RawTest("localhost", PORT, data, check400); +tests.push(test); + +// HTTP/1.1 request, wrong host, expect a 400 response + +data = + // eslint-disable-next-line no-useless-concat + "GET /http/1.1-request HTTP/1.1\r\n" + "Host: not-localhost\r\n" + "\r\n"; +test = new RawTest("localhost", PORT, data, check400); +tests.push(test); + +// HTTP/1.1 request, wrong host/right port, expect a 400 response + +data = + "GET /http/1.1-request HTTP/1.1\r\n" + + "Host: not-localhost:4444\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check400); +tests.push(test); + +// HTTP/1.1 request, Host header has host but no port, expect a 400 response + +// eslint-disable-next-line no-useless-concat +data = "GET /http/1.1-request HTTP/1.1\r\n" + "Host: 127.0.0.1\r\n" + "\r\n"; +test = new RawTest("localhost", PORT, data, check400); +tests.push(test); + +// HTTP/1.1 request, Request-URI has wrong port, expect a 400 response + +data = + "GET http://127.0.0.1/http/1.1-request HTTP/1.1\r\n" + + "Host: 127.0.0.1\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check400); +tests.push(test); + +// HTTP/1.1 request, Request-URI has wrong port, expect a 400 response + +data = + "GET http://localhost:31337/http/1.1-request HTTP/1.1\r\n" + + "Host: localhost:31337\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check400); +tests.push(test); + +// HTTP/1.1 request, Request-URI has wrong scheme, expect a 400 response + +data = + "GET https://localhost:4444/http/1.1-request HTTP/1.1\r\n" + + "Host: localhost:4444\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check400); +tests.push(test); + +// HTTP/1.1 request, correct Host header, expect handler's response + +function http11goodHost(request, response) { + writeDetails(request, response); + response.setStatusLine("1.1", 200, "TEST PASSED"); +} +data = + // eslint-disable-next-line no-useless-concat + "GET /http/1.1-good-host HTTP/1.1\r\n" + "Host: localhost:4444\r\n" + "\r\n"; +function check11goodHost(aData) { + let iter = LineIterator(aData); + + // Status-Line + Assert.equal(iter.next().value, "HTTP/1.1 200 TEST PASSED"); + + skipHeaders(iter); + + // Okay, next line must be the data we expected to be written + let body = [ + "Method: GET", + "Path: /http/1.1-good-host", + "Query: ", + "Version: 1.1", + "Scheme: http", + "Host: localhost", + "Port: 4444", + ]; + + expectLines(iter, body); +} +test = new RawTest("localhost", PORT, data, check11goodHost); +tests.push(test); + +// HTTP/1.1 request, Host header is secondary identity + +function http11ipHost(request, response) { + writeDetails(request, response); + response.setStatusLine("1.1", 200, "TEST PASSED"); +} +data = + // eslint-disable-next-line no-useless-concat + "GET /http/1.1-ip-host HTTP/1.1\r\n" + "Host: 127.0.0.1:4444\r\n" + "\r\n"; +function check11ipHost(aData) { + let iter = LineIterator(aData); + + // Status-Line + Assert.equal(iter.next().value, "HTTP/1.1 200 TEST PASSED"); + + skipHeaders(iter); + + // Okay, next line must be the data we expected to be written + let body = [ + "Method: GET", + "Path: /http/1.1-ip-host", + "Query: ", + "Version: 1.1", + "Scheme: http", + "Host: 127.0.0.1", + "Port: 4444", + ]; + + expectLines(iter, body); +} +test = new RawTest("localhost", PORT, data, check11ipHost); +tests.push(test); + +// HTTP/1.1 request, absolute path, accurate Host header + +// reusing previous request handler so not defining a new one + +data = + "GET http://localhost:4444/http/1.1-good-host HTTP/1.1\r\n" + + "Host: localhost:4444\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check11goodHost); +tests.push(test); + +// HTTP/1.1 request, absolute path, inaccurate Host header + +// reusing previous request handler so not defining a new one + +data = + "GET http://localhost:4444/http/1.1-good-host HTTP/1.1\r\n" + + "Host: localhost:1234\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check11goodHost); +tests.push(test); + +// HTTP/1.1 request, absolute path, different inaccurate Host header + +// reusing previous request handler so not defining a new one + +data = + "GET http://localhost:4444/http/1.1-good-host HTTP/1.1\r\n" + + "Host: not-localhost:4444\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check11goodHost); +tests.push(test); + +// HTTP/1.1 request, absolute path, yet another inaccurate Host header + +// reusing previous request handler so not defining a new one + +data = + "GET http://localhost:4444/http/1.1-good-host HTTP/1.1\r\n" + + "Host: yippity-skippity\r\n" + + "\r\n"; +function checkInaccurate(aData) { + check11goodHost(aData); + + // dynamism setup + srv.identity.setPrimary("http", "127.0.0.1", 4444); +} +test = new RawTest("localhost", PORT, data, checkInaccurate); +tests.push(test); + +// HTTP/1.0 request, absolute path, different inaccurate Host header + +// reusing previous request handler so not defining a new one + +data = + "GET /http/1.0-request HTTP/1.0\r\n" + + "Host: not-localhost:4444\r\n" + + "\r\n"; +function check10ip(aData) { + let iter = LineIterator(aData); + + // Status-Line + Assert.equal(iter.next().value, "HTTP/1.0 200 TEST PASSED"); + + skipHeaders(iter); + + // Okay, next line must be the data we expected to be written + let body = [ + "Method: GET", + "Path: /http/1.0-request", + "Query: ", + "Version: 1.0", + "Scheme: http", + "Host: 127.0.0.1", + "Port: 4444", + ]; + + expectLines(iter, body); +} +test = new RawTest("localhost", PORT, data, check10ip); +tests.push(test); + +// HTTP/1.1 request, Host header with implied port + +function http11goodHostWackyPort(request, response) { + writeDetails(request, response); + response.setStatusLine("1.1", 200, "TEST PASSED"); +} +data = + "GET /http/1.1-good-host-wacky-port HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "\r\n"; +function check11goodHostWackyPort(aData) { + let iter = LineIterator(aData); + + // Status-Line + Assert.equal(iter.next().value, "HTTP/1.1 200 TEST PASSED"); + + skipHeaders(iter); + + // Okay, next line must be the data we expected to be written + let body = [ + "Method: GET", + "Path: /http/1.1-good-host-wacky-port", + "Query: ", + "Version: 1.1", + "Scheme: http", + "Host: localhost", + "Port: 80", + ]; + + expectLines(iter, body); +} +test = new RawTest("localhost", PORT, data, check11goodHostWackyPort); +tests.push(test); + +// HTTP/1.1 request, Host header with wacky implied port + +data = + "GET /http/1.1-good-host-wacky-port HTTP/1.1\r\n" + + "Host: localhost:\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check11goodHostWackyPort); +tests.push(test); + +// HTTP/1.1 request, absolute URI with implied port + +data = + "GET http://localhost/http/1.1-good-host-wacky-port HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check11goodHostWackyPort); +tests.push(test); + +// HTTP/1.1 request, absolute URI with wacky implied port + +data = + "GET http://localhost:/http/1.1-good-host-wacky-port HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check11goodHostWackyPort); +tests.push(test); + +// HTTP/1.1 request, absolute URI with explicit implied port, ignored Host + +data = + "GET http://localhost:80/http/1.1-good-host-wacky-port HTTP/1.1\r\n" + + "Host: who-cares\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check11goodHostWackyPort); +tests.push(test); + +// HTTP/1.1 request, a malformed Request-URI + +data = + "GET is-this-the-real-life-is-this-just-fantasy HTTP/1.1\r\n" + + "Host: localhost:4444\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check400); +tests.push(test); + +// HTTP/1.1 request, a malformed Host header + +// eslint-disable-next-line no-useless-concat +data = "GET /http/1.1-request HTTP/1.1\r\n" + "Host: la la la\r\n" + "\r\n"; +test = new RawTest("localhost", PORT, data, check400); +tests.push(test); + +// HTTP/1.1 request, a malformed Host header but absolute URI, 5.2 sez fine + +data = + "GET http://localhost:4444/http/1.1-good-host HTTP/1.1\r\n" + + "Host: la la la\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check11goodHost); +tests.push(test); + +// HTTP/1.0 request, absolute URI, but those aren't valid in HTTP/1.0 + +data = + "GET http://localhost:4444/http/1.1-request HTTP/1.0\r\n" + + "Host: localhost:4444\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check400); +tests.push(test); + +// HTTP/1.1 request, absolute URI with unrecognized host + +data = + "GET http://not-localhost:4444/http/1.1-request HTTP/1.1\r\n" + + "Host: not-localhost:4444\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check400); +tests.push(test); + +// HTTP/1.1 request, absolute URI with unrecognized host (but not in Host) + +data = + "GET http://not-localhost:4444/http/1.1-request HTTP/1.1\r\n" + + "Host: localhost:4444\r\n" + + "\r\n"; +test = new RawTest("localhost", PORT, data, check400); +tests.push(test); |