1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/devtools/netmonitor/test/browser_net_curl-utils.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,232 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +/** 1.8 + * Tests Curl Utils functionality. 1.9 + */ 1.10 + 1.11 +function test() { 1.12 + initNetMonitor(CURL_UTILS_URL).then(([aTab, aDebuggee, aMonitor]) => { 1.13 + info("Starting test... "); 1.14 + 1.15 + let { NetMonitorView, gNetwork } = aMonitor.panelWin; 1.16 + let { RequestsMenu } = NetMonitorView; 1.17 + 1.18 + RequestsMenu.lazyUpdate = false; 1.19 + 1.20 + waitForNetworkEvents(aMonitor, 1, 3).then(() => { 1.21 + let requests = { 1.22 + get: RequestsMenu.getItemAtIndex(0), 1.23 + post: RequestsMenu.getItemAtIndex(1), 1.24 + multipart: RequestsMenu.getItemAtIndex(2), 1.25 + multipartForm: RequestsMenu.getItemAtIndex(3) 1.26 + }; 1.27 + 1.28 + Task.spawn(function*() { 1.29 + yield createCurlData(requests.get.attachment, gNetwork).then((aData) => { 1.30 + test_findHeader(aData); 1.31 + }); 1.32 + 1.33 + yield createCurlData(requests.post.attachment, gNetwork).then((aData) => { 1.34 + test_isUrlEncodedRequest(aData); 1.35 + test_writePostDataTextParams(aData); 1.36 + }); 1.37 + 1.38 + yield createCurlData(requests.multipart.attachment, gNetwork).then((aData) => { 1.39 + test_isMultipartRequest(aData); 1.40 + test_getMultipartBoundary(aData); 1.41 + test_removeBinaryDataFromMultipartText(aData); 1.42 + }); 1.43 + 1.44 + yield createCurlData(requests.multipartForm.attachment, gNetwork).then((aData) => { 1.45 + test_getHeadersFromMultipartText(aData); 1.46 + }); 1.47 + 1.48 + if (Services.appinfo.OS != "WINNT") { 1.49 + test_escapeStringPosix(); 1.50 + } else { 1.51 + test_escapeStringWin(); 1.52 + } 1.53 + 1.54 + teardown(aMonitor).then(finish); 1.55 + }); 1.56 + }); 1.57 + 1.58 + aDebuggee.performRequests(SIMPLE_SJS); 1.59 + }); 1.60 +} 1.61 + 1.62 +function test_isUrlEncodedRequest(aData) { 1.63 + let isUrlEncoded = CurlUtils.isUrlEncodedRequest(aData); 1.64 + ok(isUrlEncoded, "Should return true for url encoded requests."); 1.65 +} 1.66 + 1.67 +function test_isMultipartRequest(aData) { 1.68 + let isMultipart = CurlUtils.isMultipartRequest(aData); 1.69 + ok(isMultipart, "Should return true for multipart/form-data requests."); 1.70 +} 1.71 + 1.72 +function test_findHeader(aData) { 1.73 + let headers = aData.headers; 1.74 + let hostName = CurlUtils.findHeader(headers, "Host"); 1.75 + let requestedWithLowerCased = CurlUtils.findHeader(headers, "x-requested-with"); 1.76 + let doesNotExist = CurlUtils.findHeader(headers, "X-Does-Not-Exist"); 1.77 + 1.78 + is(hostName, "example.com", 1.79 + "Header with name 'Host' should be found in the request array."); 1.80 + is(requestedWithLowerCased, "XMLHttpRequest", 1.81 + "The search should be case insensitive."); 1.82 + is(doesNotExist, null, 1.83 + "Should return null when a header is not found."); 1.84 +} 1.85 + 1.86 +function test_writePostDataTextParams(aData) { 1.87 + let params = CurlUtils.writePostDataTextParams(aData.postDataText); 1.88 + is(params, "param1=value1¶m2=value2¶m3=value3", 1.89 + "Should return a serialized representation of the request parameters"); 1.90 +} 1.91 + 1.92 +function test_getMultipartBoundary(aData) { 1.93 + let boundary = CurlUtils.getMultipartBoundary(aData); 1.94 + ok(/-{3,}\w+/.test(boundary), 1.95 + "A boundary string should be found in a multipart request."); 1.96 +} 1.97 + 1.98 +function test_removeBinaryDataFromMultipartText(aData) { 1.99 + let generatedBoundary = CurlUtils.getMultipartBoundary(aData); 1.100 + let text = aData.postDataText; 1.101 + let binaryRemoved = 1.102 + CurlUtils.removeBinaryDataFromMultipartText(text, generatedBoundary); 1.103 + let boundary = "--" + generatedBoundary; 1.104 + 1.105 + const EXPECTED_POSIX_RESULT = [ 1.106 + "$'", 1.107 + boundary, 1.108 + "\\r\\n\\r\\n", 1.109 + "Content-Disposition: form-data; name=\"param1\"", 1.110 + "\\r\\n\\r\\n", 1.111 + "value1", 1.112 + "\\r\\n", 1.113 + boundary, 1.114 + "\\r\\n\\r\\n", 1.115 + "Content-Disposition: form-data; name=\"file\"; filename=\"filename.png\"", 1.116 + "\\r\\n", 1.117 + "Content-Type: image/png", 1.118 + "\\r\\n\\r\\n", 1.119 + generatedBoundary, 1.120 + "--\\r\\n", 1.121 + "'" 1.122 + ].join(""); 1.123 + 1.124 + const EXPECTED_WIN_RESULT = [ 1.125 + '"' + boundary + '"^', 1.126 + '\u000d\u000A\u000d\u000A', 1.127 + '"Content-Disposition: form-data; name=""param1"""^', 1.128 + '\u000d\u000A\u000d\u000A', 1.129 + '"value1"^', 1.130 + '\u000d\u000A', 1.131 + '"' + boundary + '"^', 1.132 + '\u000d\u000A\u000d\u000A', 1.133 + '"Content-Disposition: form-data; name=""file""; filename=""filename.png"""^', 1.134 + '\u000d\u000A', 1.135 + '"Content-Type: image/png"^', 1.136 + '\u000d\u000A\u000d\u000A', 1.137 + '"' + generatedBoundary + '--"^', 1.138 + '\u000d\u000A', 1.139 + '""' 1.140 + ].join(""); 1.141 + 1.142 + if (Services.appinfo.OS != "WINNT") { 1.143 + is(CurlUtils.escapeStringPosix(binaryRemoved), EXPECTED_POSIX_RESULT, 1.144 + "The mulitpart request payload should not contain binary data."); 1.145 + } else { 1.146 + is(CurlUtils.escapeStringWin(binaryRemoved), EXPECTED_WIN_RESULT, 1.147 + "WinNT: The mulitpart request payload should not contain binary data."); 1.148 + } 1.149 +} 1.150 + 1.151 +function test_getHeadersFromMultipartText(aData) { 1.152 + let headers = CurlUtils.getHeadersFromMultipartText(aData.postDataText); 1.153 + 1.154 + ok(Array.isArray(headers), 1.155 + "Should return an array."); 1.156 + ok(headers.length > 0, 1.157 + "There should exist at least one request header."); 1.158 + is(headers[0].name, "Content-Type", 1.159 + "The first header name should be 'Content-Type'."); 1.160 +} 1.161 + 1.162 +function test_escapeStringPosix() { 1.163 + let surroundedWithQuotes = "A simple string"; 1.164 + is(CurlUtils.escapeStringPosix(surroundedWithQuotes), "'A simple string'", 1.165 + "The string should be surrounded with single quotes."); 1.166 + 1.167 + let singleQuotes = "It's unusual to put crickets in your coffee."; 1.168 + is(CurlUtils.escapeStringPosix(singleQuotes), 1.169 + "$'It\\'s unusual to put crickets in your coffee.'", 1.170 + "Single quotes should be escaped."); 1.171 + 1.172 + let newLines = "Line 1\r\nLine 2\u000d\u000ALine3"; 1.173 + is(CurlUtils.escapeStringPosix(newLines), "$'Line 1\\r\\nLine 2\\r\\nLine3'", 1.174 + "Newlines should be escaped."); 1.175 + 1.176 + let controlChars = "\u0007 \u0009 \u000C \u001B"; 1.177 + is(CurlUtils.escapeStringPosix(controlChars), "$'\\x07 \\x09 \\x0c \\x1b'", 1.178 + "Control characters should be escaped."); 1.179 + 1.180 + let extendedAsciiChars = "æ ø ü ß ö é"; 1.181 + is(CurlUtils.escapeStringPosix(extendedAsciiChars), 1.182 + "$'\\xc3\\xa6 \\xc3\\xb8 \\xc3\\xbc \\xc3\\x9f \\xc3\\xb6 \\xc3\\xa9'", 1.183 + "Character codes outside of the decimal range 32 - 126 should be escaped."); 1.184 +} 1.185 + 1.186 +function test_escapeStringWin() { 1.187 + let surroundedWithDoubleQuotes = "A simple string"; 1.188 + is(CurlUtils.escapeStringWin(surroundedWithDoubleQuotes), '"A simple string"', 1.189 + "The string should be surrounded with double quotes."); 1.190 + 1.191 + let doubleQuotes = "Quote: \"Time is an illusion. Lunchtime doubly so.\""; 1.192 + is(CurlUtils.escapeStringWin(doubleQuotes), 1.193 + '"Quote: ""Time is an illusion. Lunchtime doubly so."""', 1.194 + "Double quotes should be escaped."); 1.195 + 1.196 + let percentSigns = "%AppData%"; 1.197 + is(CurlUtils.escapeStringWin(percentSigns), '""%"AppData"%""', 1.198 + "Percent signs should be escaped."); 1.199 + 1.200 + let backslashes = "\\A simple string\\"; 1.201 + is(CurlUtils.escapeStringWin(backslashes), '"\\\\A simple string\\\\"', 1.202 + "Backslashes should be escaped."); 1.203 + 1.204 + let newLines = "line1\r\nline2\r\nline3"; 1.205 + is(CurlUtils.escapeStringWin(newLines), 1.206 + '"line1"^\u000d\u000A"line2"^\u000d\u000A"line3"', 1.207 + "Newlines should be escaped."); 1.208 +} 1.209 + 1.210 +function createCurlData(aSelected, aNetwork) { 1.211 + return Task.spawn(function*() { 1.212 + // Create a sanitized object for the Curl command generator. 1.213 + let data = { 1.214 + url: aSelected.url, 1.215 + method: aSelected.method, 1.216 + headers: [], 1.217 + httpVersion: aSelected.httpVersion, 1.218 + postDataText: null 1.219 + }; 1.220 + 1.221 + // Fetch header values. 1.222 + for (let { name, value } of aSelected.requestHeaders.headers) { 1.223 + let text = yield aNetwork.getString(value); 1.224 + data.headers.push({ name: name, value: text }); 1.225 + } 1.226 + 1.227 + // Fetch the request payload. 1.228 + if (aSelected.requestPostData) { 1.229 + let postData = aSelected.requestPostData.postData.text; 1.230 + data.postDataText = yield aNetwork.getString(postData); 1.231 + } 1.232 + 1.233 + return data; 1.234 + }); 1.235 +} 1.236 \ No newline at end of file