| 1 | /* |
| 2 | Copyright 2018-2021 Intel Corporation |
| 3 | |
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | you may not use this file except in compliance with the License. |
| 6 | You may obtain a copy of the License at |
| 7 | |
| 8 | http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | |
| 10 | Unless required by applicable law or agreed to in writing, software |
| 11 | distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | See the License for the specific language governing permissions and |
| 14 | limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | /** |
| 18 | * @description WSMAN communication using duktape http |
| 19 | * @author Ylian Saint-Hilaire |
| 20 | * @version v0.2.0c |
| 21 | */ |
| 22 | |
| 23 | // Construct a WSMAN communication object |
| 24 | function CreateWsmanComm(/*host, port, user, pass, tls, extra*/) { |
| 25 | var obj = {}; |
| 26 | obj.PendingAjax = []; // List of pending AJAX calls. When one frees up, another will start. |
| 27 | obj.ActiveAjaxCount = 0; // Number of currently active AJAX calls |
| 28 | obj.MaxActiveAjaxCount = 1; // Maximum number of activate AJAX calls at the same time. |
| 29 | obj.FailAllError = 0; // Set this to non-zero to fail all AJAX calls with that error status, 999 causes responses to be silent. |
| 30 | obj.digest = null; |
| 31 | obj.RequestCount = 0; |
| 32 | |
| 33 | if (arguments.length == 1 && typeof (arguments[0] == 'object')) { |
| 34 | obj.host = arguments[0].host; |
| 35 | obj.port = arguments[0].port; |
| 36 | obj.authToken = arguments[0].authToken; |
| 37 | obj.tls = arguments[0].tls; |
| 38 | } |
| 39 | else { |
| 40 | obj.host = arguments[0]; |
| 41 | obj.port = arguments[1]; |
| 42 | obj.user = arguments[2]; |
| 43 | obj.pass = arguments[3]; |
| 44 | obj.tls = arguments[4]; |
| 45 | } |
| 46 | |
| 47 | |
| 48 | // Private method |
| 49 | // pri = priority, if set to 1, the call is high priority and put on top of the stack. |
| 50 | obj.PerformAjax = function (postdata, callback, tag, pri, url, action) { |
| 51 | if ((obj.ActiveAjaxCount == 0 || ((obj.ActiveAjaxCount < obj.MaxActiveAjaxCount) && (obj.challengeParams != null))) && obj.PendingAjax.length == 0) { |
| 52 | // There are no pending AJAX calls, perform the call now. |
| 53 | obj.PerformAjaxEx(postdata, callback, tag, url, action); |
| 54 | } else { |
| 55 | // If this is a high priority call, put this call in front of the array, otherwise put it in the back. |
| 56 | if (pri == 1) { obj.PendingAjax.unshift([postdata, callback, tag, url, action]); } else { obj.PendingAjax.push([postdata, callback, tag, url, action]); } |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | // Private method |
| 61 | obj.PerformNextAjax = function () { |
| 62 | if (obj.ActiveAjaxCount >= obj.MaxActiveAjaxCount || obj.PendingAjax.length == 0) return; |
| 63 | var x = obj.PendingAjax.shift(); |
| 64 | obj.PerformAjaxEx(x[0], x[1], x[2], x[3], x[4]); |
| 65 | obj.PerformNextAjax(); |
| 66 | } |
| 67 | |
| 68 | // Private method |
| 69 | obj.PerformAjaxEx = function (postdata, callback, tag, url, action) |
| 70 | { |
| 71 | if (obj.FailAllError != 0) { if (obj.FailAllError != 999) { obj.gotNextMessagesError({ status: obj.FailAllError }, 'error', null, [postdata, callback, tag]); } return; } |
| 72 | if (!postdata) postdata = ""; |
| 73 | if (globalDebugFlags & 1) { console.log("SEND: " + postdata + "\r\n\r\n"); } // DEBUG |
| 74 | |
| 75 | // We are in a DukTape environement |
| 76 | if (obj.digest == null) { |
| 77 | if (obj.authToken) { |
| 78 | obj.digest = require('http-digest').create({ authToken: obj.authToken }); |
| 79 | } else { |
| 80 | obj.digest = require('http-digest').create(obj.user, obj.pass); |
| 81 | } |
| 82 | obj.digest.http = require('http'); |
| 83 | } |
| 84 | var request = { delayWrite: true, protocol: (obj.tls == 1 ? 'https:' : 'http:'), method: 'POST', host: obj.host, path: '/wsman', port: obj.port, rejectUnauthorized: false, checkServerIdentity: function (cert) { /*console.log('checkServerIdentity', JSON.stringify(cert));*/ } }; |
| 85 | var req = obj.digest.request(request); |
| 86 | //console.log('Request ' + (obj.RequestCount++)); |
| 87 | if (globalDebugFlags & 1) { console.log('Request ' + (obj.RequestCount++)); } // DEBUG |
| 88 | |
| 89 | req.on('error', function (err) { obj.gotNextMessagesError({ status: 600, error: '' + err }, 'error', null, [postdata, callback, tag]); }); |
| 90 | req.on('response', function (response) { |
| 91 | //console.log(JSON.stringify(response, null, 2)); |
| 92 | if (globalDebugFlags & 1) { console.log('Response: ' + response.statusCode); } |
| 93 | if (response.statusCode != 200) { |
| 94 | if (globalDebugFlags & 1) { console.log('ERR:' + JSON.stringify(response)); } |
| 95 | obj.gotNextMessagesError({ status: response.statusCode }, 'error', null, [postdata, callback, tag]); |
| 96 | } else { |
| 97 | response.acc = ''; |
| 98 | response.on('data', function (data2) { this.acc += data2; }); |
| 99 | response.on('end', function () { obj.gotNextMessages(response.acc, 'success', { status: response.statusCode }, [postdata, callback, tag]); }); |
| 100 | } |
| 101 | }); |
| 102 | |
| 103 | // Send POST body, this work with binary. |
| 104 | req.end(postdata); |
| 105 | obj.ActiveAjaxCount++; |
| 106 | return req; |
| 107 | } |
| 108 | |
| 109 | // AJAX specific private method |
| 110 | obj.pendingAjaxCall = []; |
| 111 | |
| 112 | // Private method |
| 113 | obj.gotNextMessages = function (data, status, request, callArgs) { |
| 114 | obj.ActiveAjaxCount--; |
| 115 | if (obj.FailAllError == 999) return; |
| 116 | if (globalDebugFlags & 1) { console.log("RECV: " + data + "\r\n\r\n"); } // DEBUG |
| 117 | if (obj.FailAllError != 0) { callArgs[1](null, obj.FailAllError, callArgs[2]); return; } |
| 118 | if (request.status != 200) { callArgs[1](null, request.status, callArgs[2]); return; } |
| 119 | callArgs[1](data, 200, callArgs[2]); |
| 120 | obj.PerformNextAjax(); |
| 121 | } |
| 122 | |
| 123 | // Private method |
| 124 | obj.gotNextMessagesError = function (request, status, errorThrown, callArgs) { |
| 125 | obj.ActiveAjaxCount--; |
| 126 | if (obj.FailAllError == 999) return; |
| 127 | if (obj.FailAllError != 0) { callArgs[1](null, obj.FailAllError, callArgs[2]); return; } |
| 128 | //if (status != 200) { console.log("ERROR, status=" + status + "\r\n\r\nreq=" + callArgs[0]); } // Debug: Display the request & response if something did not work. |
| 129 | if (obj.FailAllError != 999) { callArgs[1]({ Header: { HttpError: request.status, error: request.error } }, request.status, callArgs[2]); } |
| 130 | obj.PerformNextAjax(); |
| 131 | } |
| 132 | |
| 133 | // Cancel all pending queries with given status |
| 134 | obj.CancelAllQueries = function (s) { |
| 135 | while (obj.PendingAjax.length > 0) { var x = obj.PendingAjax.shift(); x[1](null, s, x[2]); } |
| 136 | } |
| 137 | |
| 138 | return obj; |
| 139 | } |
| 140 | |
| 141 | module.exports = CreateWsmanComm; |