commit 143d3d99518f6e4ab970f8842e71e2133e68e44c Author: David Fifield david@bamsoftware.com Date: Fri Sep 7 12:23:10 2012 -0700
Add JavaScript build_url function. --- flashproxy-test.js | 47 ++++++++++++++++++++++++++++++++++++++++++++++ flashproxy.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 0 deletions(-)
diff --git a/flashproxy-test.js b/flashproxy-test.js index 1961740..3db15e0 100755 --- a/flashproxy-test.js +++ b/flashproxy-test.js @@ -60,6 +60,52 @@ function fail(test, expected, actual) print("FAIL " + repr(test) + " expected: " + repr(expected) + " actual: " + repr(actual)); }
+function test_build_url() +{ + var TESTS = [ + { args: ["http", "example.com"], + expected: "http://example.com" }, + { args: ["http", "example.com", 80], + expected: "http://example.com" }, + { args: ["http", "example.com", 81], + expected: "http://example.com:81" }, + { args: ["https", "example.com", 443], + expected: "https://example.com" }, + { args: ["https", "example.com", 444], + expected: "https://example.com:444" }, + { args: ["http", "example.com", 80, "/"], + expected: "http://example.com/" }, + { args: ["http", "example.com", 80, "/test?k=%#v"], + expected: "http://example.com/test%3Fk%3D%25%23v" }, + { args: ["http", "example.com", 80, "/test", []], + expected: "http://example.com/test?" }, + { args: ["http", "example.com", 80, "/test", [["k", "%#v"]]], + expected: "http://example.com/test?k=%25%23v" }, + { args: ["http", "example.com", 80, "/test", [["a", "b"], ["c", "d"]]], + expected: "http://example.com/test?a=b&c=d" }, + { args: ["http", "1.2.3.4"], + expected: "http://1.2.3.4" }, + { args: ["http", "1:2::3:4"], + expected: "http://%5B1:2::3:4]" }, + { args: ["http", "bog][us"], + expected: "http://bog%5D%5Bus" }, + { args: ["http", "bog:u]s"], + expected: "http://bog%3Au%5Ds" }, + ]; + + announce("test_build_url"); + for (var i = 0; i < TESTS.length; i++) { + var test = TESTS[i]; + var actual; + + actual = build_url.apply(undefined, test.args); + if (objects_equal(actual, test.expected)) + pass(test.args); + else + fail(test.args, test.expected, actual); + } +} + function test_parse_query_string() { var TESTS = [ @@ -170,6 +216,7 @@ function test_get_query_param_addr() } }
+test_build_url(); test_parse_query_string(); test_parse_addr_spec(); test_get_query_param_addr(); diff --git a/flashproxy.js b/flashproxy.js index 50526a4..d5b1c99 100644 --- a/flashproxy.js +++ b/flashproxy.js @@ -128,6 +128,59 @@ function parse_query_string(qs) { return result; }
+var DEFAULT_PORTS = { + http: 80, + https: 443 +} +/* Build an escaped URL string from unescaped components. Only scheme and host + are required. See RFC 3986, section 3. */ +function build_url(scheme, host, port, path, params) { + var parts = [] + + parts.push(encodeURIComponent(scheme)); + parts.push("://"); + + /* If it contains a colon but no square brackets, treat it like an IPv6 + address. */ + if (host.match(/:/) && !host.match(/[[]]/)) { + parts.push("["); + parts.push(host); + parts.push("]"); + } else { + parts.push(encodeURIComponent(host)); + } + if (port !== undefined && port !== DEFAULT_PORTS[scheme]) { + parts.push(":"); + parts.push(encodeURIComponent(port.toString())); + } + + if (path !== undefined && path !== "") { + if (!path.match(/^//)) + path = "/" + path; + /* Slash is significant so we must protect it from encodeURIComponent, + while still encoding question mark and number sign. RFC 3986, section + 3.3: "The path is terminated by the first question mark ('?') or + number sign ('#') character, or by the end of the URI. ... A path + consists of a sequence of path segments separated by a slash ('/') + character." */ + path = path.replace(/[^/]+/, function(m) { + return encodeURIComponent(m); + }); + parts.push(path); + } + + if (params !== undefined) { + parts.push("?"); + for (var i = 0; i < params.length; i++) { + if (i > 0) + parts.push("&"); + parts.push(encodeURIComponent(params[i][0]) + "=" + encodeURIComponent(params[i][1])); + } + } + + return parts.join(""); +} + /* Get a query string parameter and parse it as an address spec. Returns default_val if param is not defined in the query string. Returns null on a parsing error. */
tor-commits@lists.torproject.org