michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: /** michael@0: * Tests Curl Utils functionality. michael@0: */ michael@0: michael@0: function test() { michael@0: initNetMonitor(CURL_UTILS_URL).then(([aTab, aDebuggee, aMonitor]) => { michael@0: info("Starting test... "); michael@0: michael@0: let { NetMonitorView, gNetwork } = aMonitor.panelWin; michael@0: let { RequestsMenu } = NetMonitorView; michael@0: michael@0: RequestsMenu.lazyUpdate = false; michael@0: michael@0: waitForNetworkEvents(aMonitor, 1, 3).then(() => { michael@0: let requests = { michael@0: get: RequestsMenu.getItemAtIndex(0), michael@0: post: RequestsMenu.getItemAtIndex(1), michael@0: multipart: RequestsMenu.getItemAtIndex(2), michael@0: multipartForm: RequestsMenu.getItemAtIndex(3) michael@0: }; michael@0: michael@0: Task.spawn(function*() { michael@0: yield createCurlData(requests.get.attachment, gNetwork).then((aData) => { michael@0: test_findHeader(aData); michael@0: }); michael@0: michael@0: yield createCurlData(requests.post.attachment, gNetwork).then((aData) => { michael@0: test_isUrlEncodedRequest(aData); michael@0: test_writePostDataTextParams(aData); michael@0: }); michael@0: michael@0: yield createCurlData(requests.multipart.attachment, gNetwork).then((aData) => { michael@0: test_isMultipartRequest(aData); michael@0: test_getMultipartBoundary(aData); michael@0: test_removeBinaryDataFromMultipartText(aData); michael@0: }); michael@0: michael@0: yield createCurlData(requests.multipartForm.attachment, gNetwork).then((aData) => { michael@0: test_getHeadersFromMultipartText(aData); michael@0: }); michael@0: michael@0: if (Services.appinfo.OS != "WINNT") { michael@0: test_escapeStringPosix(); michael@0: } else { michael@0: test_escapeStringWin(); michael@0: } michael@0: michael@0: teardown(aMonitor).then(finish); michael@0: }); michael@0: }); michael@0: michael@0: aDebuggee.performRequests(SIMPLE_SJS); michael@0: }); michael@0: } michael@0: michael@0: function test_isUrlEncodedRequest(aData) { michael@0: let isUrlEncoded = CurlUtils.isUrlEncodedRequest(aData); michael@0: ok(isUrlEncoded, "Should return true for url encoded requests."); michael@0: } michael@0: michael@0: function test_isMultipartRequest(aData) { michael@0: let isMultipart = CurlUtils.isMultipartRequest(aData); michael@0: ok(isMultipart, "Should return true for multipart/form-data requests."); michael@0: } michael@0: michael@0: function test_findHeader(aData) { michael@0: let headers = aData.headers; michael@0: let hostName = CurlUtils.findHeader(headers, "Host"); michael@0: let requestedWithLowerCased = CurlUtils.findHeader(headers, "x-requested-with"); michael@0: let doesNotExist = CurlUtils.findHeader(headers, "X-Does-Not-Exist"); michael@0: michael@0: is(hostName, "example.com", michael@0: "Header with name 'Host' should be found in the request array."); michael@0: is(requestedWithLowerCased, "XMLHttpRequest", michael@0: "The search should be case insensitive."); michael@0: is(doesNotExist, null, michael@0: "Should return null when a header is not found."); michael@0: } michael@0: michael@0: function test_writePostDataTextParams(aData) { michael@0: let params = CurlUtils.writePostDataTextParams(aData.postDataText); michael@0: is(params, "param1=value1¶m2=value2¶m3=value3", michael@0: "Should return a serialized representation of the request parameters"); michael@0: } michael@0: michael@0: function test_getMultipartBoundary(aData) { michael@0: let boundary = CurlUtils.getMultipartBoundary(aData); michael@0: ok(/-{3,}\w+/.test(boundary), michael@0: "A boundary string should be found in a multipart request."); michael@0: } michael@0: michael@0: function test_removeBinaryDataFromMultipartText(aData) { michael@0: let generatedBoundary = CurlUtils.getMultipartBoundary(aData); michael@0: let text = aData.postDataText; michael@0: let binaryRemoved = michael@0: CurlUtils.removeBinaryDataFromMultipartText(text, generatedBoundary); michael@0: let boundary = "--" + generatedBoundary; michael@0: michael@0: const EXPECTED_POSIX_RESULT = [ michael@0: "$'", michael@0: boundary, michael@0: "\\r\\n\\r\\n", michael@0: "Content-Disposition: form-data; name=\"param1\"", michael@0: "\\r\\n\\r\\n", michael@0: "value1", michael@0: "\\r\\n", michael@0: boundary, michael@0: "\\r\\n\\r\\n", michael@0: "Content-Disposition: form-data; name=\"file\"; filename=\"filename.png\"", michael@0: "\\r\\n", michael@0: "Content-Type: image/png", michael@0: "\\r\\n\\r\\n", michael@0: generatedBoundary, michael@0: "--\\r\\n", michael@0: "'" michael@0: ].join(""); michael@0: michael@0: const EXPECTED_WIN_RESULT = [ michael@0: '"' + boundary + '"^', michael@0: '\u000d\u000A\u000d\u000A', michael@0: '"Content-Disposition: form-data; name=""param1"""^', michael@0: '\u000d\u000A\u000d\u000A', michael@0: '"value1"^', michael@0: '\u000d\u000A', michael@0: '"' + boundary + '"^', michael@0: '\u000d\u000A\u000d\u000A', michael@0: '"Content-Disposition: form-data; name=""file""; filename=""filename.png"""^', michael@0: '\u000d\u000A', michael@0: '"Content-Type: image/png"^', michael@0: '\u000d\u000A\u000d\u000A', michael@0: '"' + generatedBoundary + '--"^', michael@0: '\u000d\u000A', michael@0: '""' michael@0: ].join(""); michael@0: michael@0: if (Services.appinfo.OS != "WINNT") { michael@0: is(CurlUtils.escapeStringPosix(binaryRemoved), EXPECTED_POSIX_RESULT, michael@0: "The mulitpart request payload should not contain binary data."); michael@0: } else { michael@0: is(CurlUtils.escapeStringWin(binaryRemoved), EXPECTED_WIN_RESULT, michael@0: "WinNT: The mulitpart request payload should not contain binary data."); michael@0: } michael@0: } michael@0: michael@0: function test_getHeadersFromMultipartText(aData) { michael@0: let headers = CurlUtils.getHeadersFromMultipartText(aData.postDataText); michael@0: michael@0: ok(Array.isArray(headers), michael@0: "Should return an array."); michael@0: ok(headers.length > 0, michael@0: "There should exist at least one request header."); michael@0: is(headers[0].name, "Content-Type", michael@0: "The first header name should be 'Content-Type'."); michael@0: } michael@0: michael@0: function test_escapeStringPosix() { michael@0: let surroundedWithQuotes = "A simple string"; michael@0: is(CurlUtils.escapeStringPosix(surroundedWithQuotes), "'A simple string'", michael@0: "The string should be surrounded with single quotes."); michael@0: michael@0: let singleQuotes = "It's unusual to put crickets in your coffee."; michael@0: is(CurlUtils.escapeStringPosix(singleQuotes), michael@0: "$'It\\'s unusual to put crickets in your coffee.'", michael@0: "Single quotes should be escaped."); michael@0: michael@0: let newLines = "Line 1\r\nLine 2\u000d\u000ALine3"; michael@0: is(CurlUtils.escapeStringPosix(newLines), "$'Line 1\\r\\nLine 2\\r\\nLine3'", michael@0: "Newlines should be escaped."); michael@0: michael@0: let controlChars = "\u0007 \u0009 \u000C \u001B"; michael@0: is(CurlUtils.escapeStringPosix(controlChars), "$'\\x07 \\x09 \\x0c \\x1b'", michael@0: "Control characters should be escaped."); michael@0: michael@0: let extendedAsciiChars = "æ ø ü ß ö é"; michael@0: is(CurlUtils.escapeStringPosix(extendedAsciiChars), michael@0: "$'\\xc3\\xa6 \\xc3\\xb8 \\xc3\\xbc \\xc3\\x9f \\xc3\\xb6 \\xc3\\xa9'", michael@0: "Character codes outside of the decimal range 32 - 126 should be escaped."); michael@0: } michael@0: michael@0: function test_escapeStringWin() { michael@0: let surroundedWithDoubleQuotes = "A simple string"; michael@0: is(CurlUtils.escapeStringWin(surroundedWithDoubleQuotes), '"A simple string"', michael@0: "The string should be surrounded with double quotes."); michael@0: michael@0: let doubleQuotes = "Quote: \"Time is an illusion. Lunchtime doubly so.\""; michael@0: is(CurlUtils.escapeStringWin(doubleQuotes), michael@0: '"Quote: ""Time is an illusion. Lunchtime doubly so."""', michael@0: "Double quotes should be escaped."); michael@0: michael@0: let percentSigns = "%AppData%"; michael@0: is(CurlUtils.escapeStringWin(percentSigns), '""%"AppData"%""', michael@0: "Percent signs should be escaped."); michael@0: michael@0: let backslashes = "\\A simple string\\"; michael@0: is(CurlUtils.escapeStringWin(backslashes), '"\\\\A simple string\\\\"', michael@0: "Backslashes should be escaped."); michael@0: michael@0: let newLines = "line1\r\nline2\r\nline3"; michael@0: is(CurlUtils.escapeStringWin(newLines), michael@0: '"line1"^\u000d\u000A"line2"^\u000d\u000A"line3"', michael@0: "Newlines should be escaped."); michael@0: } michael@0: michael@0: function createCurlData(aSelected, aNetwork) { michael@0: return Task.spawn(function*() { michael@0: // Create a sanitized object for the Curl command generator. michael@0: let data = { michael@0: url: aSelected.url, michael@0: method: aSelected.method, michael@0: headers: [], michael@0: httpVersion: aSelected.httpVersion, michael@0: postDataText: null michael@0: }; michael@0: michael@0: // Fetch header values. michael@0: for (let { name, value } of aSelected.requestHeaders.headers) { michael@0: let text = yield aNetwork.getString(value); michael@0: data.headers.push({ name: name, value: text }); michael@0: } michael@0: michael@0: // Fetch the request payload. michael@0: if (aSelected.requestPostData) { michael@0: let postData = aSelected.requestPostData.postData.text; michael@0: data.postDataText = yield aNetwork.getString(postData); michael@0: } michael@0: michael@0: return data; michael@0: }); michael@0: }