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