Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* Any copyright is dedicated to the Public Domain. |
michael@0 | 2 | http://creativecommons.org/publicdomain/zero/1.0/ */ |
michael@0 | 3 | |
michael@0 | 4 | /** |
michael@0 | 5 | * Tests Curl Utils functionality. |
michael@0 | 6 | */ |
michael@0 | 7 | |
michael@0 | 8 | function test() { |
michael@0 | 9 | initNetMonitor(CURL_UTILS_URL).then(([aTab, aDebuggee, aMonitor]) => { |
michael@0 | 10 | info("Starting test... "); |
michael@0 | 11 | |
michael@0 | 12 | let { NetMonitorView, gNetwork } = aMonitor.panelWin; |
michael@0 | 13 | let { RequestsMenu } = NetMonitorView; |
michael@0 | 14 | |
michael@0 | 15 | RequestsMenu.lazyUpdate = false; |
michael@0 | 16 | |
michael@0 | 17 | waitForNetworkEvents(aMonitor, 1, 3).then(() => { |
michael@0 | 18 | let requests = { |
michael@0 | 19 | get: RequestsMenu.getItemAtIndex(0), |
michael@0 | 20 | post: RequestsMenu.getItemAtIndex(1), |
michael@0 | 21 | multipart: RequestsMenu.getItemAtIndex(2), |
michael@0 | 22 | multipartForm: RequestsMenu.getItemAtIndex(3) |
michael@0 | 23 | }; |
michael@0 | 24 | |
michael@0 | 25 | Task.spawn(function*() { |
michael@0 | 26 | yield createCurlData(requests.get.attachment, gNetwork).then((aData) => { |
michael@0 | 27 | test_findHeader(aData); |
michael@0 | 28 | }); |
michael@0 | 29 | |
michael@0 | 30 | yield createCurlData(requests.post.attachment, gNetwork).then((aData) => { |
michael@0 | 31 | test_isUrlEncodedRequest(aData); |
michael@0 | 32 | test_writePostDataTextParams(aData); |
michael@0 | 33 | }); |
michael@0 | 34 | |
michael@0 | 35 | yield createCurlData(requests.multipart.attachment, gNetwork).then((aData) => { |
michael@0 | 36 | test_isMultipartRequest(aData); |
michael@0 | 37 | test_getMultipartBoundary(aData); |
michael@0 | 38 | test_removeBinaryDataFromMultipartText(aData); |
michael@0 | 39 | }); |
michael@0 | 40 | |
michael@0 | 41 | yield createCurlData(requests.multipartForm.attachment, gNetwork).then((aData) => { |
michael@0 | 42 | test_getHeadersFromMultipartText(aData); |
michael@0 | 43 | }); |
michael@0 | 44 | |
michael@0 | 45 | if (Services.appinfo.OS != "WINNT") { |
michael@0 | 46 | test_escapeStringPosix(); |
michael@0 | 47 | } else { |
michael@0 | 48 | test_escapeStringWin(); |
michael@0 | 49 | } |
michael@0 | 50 | |
michael@0 | 51 | teardown(aMonitor).then(finish); |
michael@0 | 52 | }); |
michael@0 | 53 | }); |
michael@0 | 54 | |
michael@0 | 55 | aDebuggee.performRequests(SIMPLE_SJS); |
michael@0 | 56 | }); |
michael@0 | 57 | } |
michael@0 | 58 | |
michael@0 | 59 | function test_isUrlEncodedRequest(aData) { |
michael@0 | 60 | let isUrlEncoded = CurlUtils.isUrlEncodedRequest(aData); |
michael@0 | 61 | ok(isUrlEncoded, "Should return true for url encoded requests."); |
michael@0 | 62 | } |
michael@0 | 63 | |
michael@0 | 64 | function test_isMultipartRequest(aData) { |
michael@0 | 65 | let isMultipart = CurlUtils.isMultipartRequest(aData); |
michael@0 | 66 | ok(isMultipart, "Should return true for multipart/form-data requests."); |
michael@0 | 67 | } |
michael@0 | 68 | |
michael@0 | 69 | function test_findHeader(aData) { |
michael@0 | 70 | let headers = aData.headers; |
michael@0 | 71 | let hostName = CurlUtils.findHeader(headers, "Host"); |
michael@0 | 72 | let requestedWithLowerCased = CurlUtils.findHeader(headers, "x-requested-with"); |
michael@0 | 73 | let doesNotExist = CurlUtils.findHeader(headers, "X-Does-Not-Exist"); |
michael@0 | 74 | |
michael@0 | 75 | is(hostName, "example.com", |
michael@0 | 76 | "Header with name 'Host' should be found in the request array."); |
michael@0 | 77 | is(requestedWithLowerCased, "XMLHttpRequest", |
michael@0 | 78 | "The search should be case insensitive."); |
michael@0 | 79 | is(doesNotExist, null, |
michael@0 | 80 | "Should return null when a header is not found."); |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | function test_writePostDataTextParams(aData) { |
michael@0 | 84 | let params = CurlUtils.writePostDataTextParams(aData.postDataText); |
michael@0 | 85 | is(params, "param1=value1¶m2=value2¶m3=value3", |
michael@0 | 86 | "Should return a serialized representation of the request parameters"); |
michael@0 | 87 | } |
michael@0 | 88 | |
michael@0 | 89 | function test_getMultipartBoundary(aData) { |
michael@0 | 90 | let boundary = CurlUtils.getMultipartBoundary(aData); |
michael@0 | 91 | ok(/-{3,}\w+/.test(boundary), |
michael@0 | 92 | "A boundary string should be found in a multipart request."); |
michael@0 | 93 | } |
michael@0 | 94 | |
michael@0 | 95 | function test_removeBinaryDataFromMultipartText(aData) { |
michael@0 | 96 | let generatedBoundary = CurlUtils.getMultipartBoundary(aData); |
michael@0 | 97 | let text = aData.postDataText; |
michael@0 | 98 | let binaryRemoved = |
michael@0 | 99 | CurlUtils.removeBinaryDataFromMultipartText(text, generatedBoundary); |
michael@0 | 100 | let boundary = "--" + generatedBoundary; |
michael@0 | 101 | |
michael@0 | 102 | const EXPECTED_POSIX_RESULT = [ |
michael@0 | 103 | "$'", |
michael@0 | 104 | boundary, |
michael@0 | 105 | "\\r\\n\\r\\n", |
michael@0 | 106 | "Content-Disposition: form-data; name=\"param1\"", |
michael@0 | 107 | "\\r\\n\\r\\n", |
michael@0 | 108 | "value1", |
michael@0 | 109 | "\\r\\n", |
michael@0 | 110 | boundary, |
michael@0 | 111 | "\\r\\n\\r\\n", |
michael@0 | 112 | "Content-Disposition: form-data; name=\"file\"; filename=\"filename.png\"", |
michael@0 | 113 | "\\r\\n", |
michael@0 | 114 | "Content-Type: image/png", |
michael@0 | 115 | "\\r\\n\\r\\n", |
michael@0 | 116 | generatedBoundary, |
michael@0 | 117 | "--\\r\\n", |
michael@0 | 118 | "'" |
michael@0 | 119 | ].join(""); |
michael@0 | 120 | |
michael@0 | 121 | const EXPECTED_WIN_RESULT = [ |
michael@0 | 122 | '"' + boundary + '"^', |
michael@0 | 123 | '\u000d\u000A\u000d\u000A', |
michael@0 | 124 | '"Content-Disposition: form-data; name=""param1"""^', |
michael@0 | 125 | '\u000d\u000A\u000d\u000A', |
michael@0 | 126 | '"value1"^', |
michael@0 | 127 | '\u000d\u000A', |
michael@0 | 128 | '"' + boundary + '"^', |
michael@0 | 129 | '\u000d\u000A\u000d\u000A', |
michael@0 | 130 | '"Content-Disposition: form-data; name=""file""; filename=""filename.png"""^', |
michael@0 | 131 | '\u000d\u000A', |
michael@0 | 132 | '"Content-Type: image/png"^', |
michael@0 | 133 | '\u000d\u000A\u000d\u000A', |
michael@0 | 134 | '"' + generatedBoundary + '--"^', |
michael@0 | 135 | '\u000d\u000A', |
michael@0 | 136 | '""' |
michael@0 | 137 | ].join(""); |
michael@0 | 138 | |
michael@0 | 139 | if (Services.appinfo.OS != "WINNT") { |
michael@0 | 140 | is(CurlUtils.escapeStringPosix(binaryRemoved), EXPECTED_POSIX_RESULT, |
michael@0 | 141 | "The mulitpart request payload should not contain binary data."); |
michael@0 | 142 | } else { |
michael@0 | 143 | is(CurlUtils.escapeStringWin(binaryRemoved), EXPECTED_WIN_RESULT, |
michael@0 | 144 | "WinNT: The mulitpart request payload should not contain binary data."); |
michael@0 | 145 | } |
michael@0 | 146 | } |
michael@0 | 147 | |
michael@0 | 148 | function test_getHeadersFromMultipartText(aData) { |
michael@0 | 149 | let headers = CurlUtils.getHeadersFromMultipartText(aData.postDataText); |
michael@0 | 150 | |
michael@0 | 151 | ok(Array.isArray(headers), |
michael@0 | 152 | "Should return an array."); |
michael@0 | 153 | ok(headers.length > 0, |
michael@0 | 154 | "There should exist at least one request header."); |
michael@0 | 155 | is(headers[0].name, "Content-Type", |
michael@0 | 156 | "The first header name should be 'Content-Type'."); |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | function test_escapeStringPosix() { |
michael@0 | 160 | let surroundedWithQuotes = "A simple string"; |
michael@0 | 161 | is(CurlUtils.escapeStringPosix(surroundedWithQuotes), "'A simple string'", |
michael@0 | 162 | "The string should be surrounded with single quotes."); |
michael@0 | 163 | |
michael@0 | 164 | let singleQuotes = "It's unusual to put crickets in your coffee."; |
michael@0 | 165 | is(CurlUtils.escapeStringPosix(singleQuotes), |
michael@0 | 166 | "$'It\\'s unusual to put crickets in your coffee.'", |
michael@0 | 167 | "Single quotes should be escaped."); |
michael@0 | 168 | |
michael@0 | 169 | let newLines = "Line 1\r\nLine 2\u000d\u000ALine3"; |
michael@0 | 170 | is(CurlUtils.escapeStringPosix(newLines), "$'Line 1\\r\\nLine 2\\r\\nLine3'", |
michael@0 | 171 | "Newlines should be escaped."); |
michael@0 | 172 | |
michael@0 | 173 | let controlChars = "\u0007 \u0009 \u000C \u001B"; |
michael@0 | 174 | is(CurlUtils.escapeStringPosix(controlChars), "$'\\x07 \\x09 \\x0c \\x1b'", |
michael@0 | 175 | "Control characters should be escaped."); |
michael@0 | 176 | |
michael@0 | 177 | let extendedAsciiChars = "æ ø ü ß ö é"; |
michael@0 | 178 | is(CurlUtils.escapeStringPosix(extendedAsciiChars), |
michael@0 | 179 | "$'\\xc3\\xa6 \\xc3\\xb8 \\xc3\\xbc \\xc3\\x9f \\xc3\\xb6 \\xc3\\xa9'", |
michael@0 | 180 | "Character codes outside of the decimal range 32 - 126 should be escaped."); |
michael@0 | 181 | } |
michael@0 | 182 | |
michael@0 | 183 | function test_escapeStringWin() { |
michael@0 | 184 | let surroundedWithDoubleQuotes = "A simple string"; |
michael@0 | 185 | is(CurlUtils.escapeStringWin(surroundedWithDoubleQuotes), '"A simple string"', |
michael@0 | 186 | "The string should be surrounded with double quotes."); |
michael@0 | 187 | |
michael@0 | 188 | let doubleQuotes = "Quote: \"Time is an illusion. Lunchtime doubly so.\""; |
michael@0 | 189 | is(CurlUtils.escapeStringWin(doubleQuotes), |
michael@0 | 190 | '"Quote: ""Time is an illusion. Lunchtime doubly so."""', |
michael@0 | 191 | "Double quotes should be escaped."); |
michael@0 | 192 | |
michael@0 | 193 | let percentSigns = "%AppData%"; |
michael@0 | 194 | is(CurlUtils.escapeStringWin(percentSigns), '""%"AppData"%""', |
michael@0 | 195 | "Percent signs should be escaped."); |
michael@0 | 196 | |
michael@0 | 197 | let backslashes = "\\A simple string\\"; |
michael@0 | 198 | is(CurlUtils.escapeStringWin(backslashes), '"\\\\A simple string\\\\"', |
michael@0 | 199 | "Backslashes should be escaped."); |
michael@0 | 200 | |
michael@0 | 201 | let newLines = "line1\r\nline2\r\nline3"; |
michael@0 | 202 | is(CurlUtils.escapeStringWin(newLines), |
michael@0 | 203 | '"line1"^\u000d\u000A"line2"^\u000d\u000A"line3"', |
michael@0 | 204 | "Newlines should be escaped."); |
michael@0 | 205 | } |
michael@0 | 206 | |
michael@0 | 207 | function createCurlData(aSelected, aNetwork) { |
michael@0 | 208 | return Task.spawn(function*() { |
michael@0 | 209 | // Create a sanitized object for the Curl command generator. |
michael@0 | 210 | let data = { |
michael@0 | 211 | url: aSelected.url, |
michael@0 | 212 | method: aSelected.method, |
michael@0 | 213 | headers: [], |
michael@0 | 214 | httpVersion: aSelected.httpVersion, |
michael@0 | 215 | postDataText: null |
michael@0 | 216 | }; |
michael@0 | 217 | |
michael@0 | 218 | // Fetch header values. |
michael@0 | 219 | for (let { name, value } of aSelected.requestHeaders.headers) { |
michael@0 | 220 | let text = yield aNetwork.getString(value); |
michael@0 | 221 | data.headers.push({ name: name, value: text }); |
michael@0 | 222 | } |
michael@0 | 223 | |
michael@0 | 224 | // Fetch the request payload. |
michael@0 | 225 | if (aSelected.requestPostData) { |
michael@0 | 226 | let postData = aSelected.requestPostData.postData.text; |
michael@0 | 227 | data.postDataText = yield aNetwork.getString(postData); |
michael@0 | 228 | } |
michael@0 | 229 | |
michael@0 | 230 | return data; |
michael@0 | 231 | }); |
michael@0 | 232 | } |