[tor-commits] [torbutton/master] Bug 17568: Clean up tor-control-port.js

gk at torproject.org gk at torproject.org
Mon Dec 7 14:51:41 UTC 2015


commit 548c10907863257c636e9393babe707fe79a4f40
Author: Arthur Edelstein <arthuredelstein at gmail.com>
Date:   Thu Nov 12 16:09:43 2015 -0800

    Bug 17568: Clean up tor-control-port.js
---
 src/modules/tor-control-port.js |  113 ++++++++++++++-------------------------
 1 file changed, 41 insertions(+), 72 deletions(-)

diff --git a/src/modules/tor-control-port.js b/src/modules/tor-control-port.js
index 2b41897..c5010de 100644
--- a/src/modules/tor-control-port.js
+++ b/src/modules/tor-control-port.js
@@ -209,7 +209,7 @@ io.callbackDispatcher = function () {
 
 // __io.matchRepliesToCommands(asyncSend, dispatcher)__.
 // Takes asyncSend(message), an asynchronous send function, and the callback
-// displatcher, and returns a function Promise<response> sendCommand(command).
+// dispatcher, and returns a function Promise<response> sendCommand(command).
 io.matchRepliesToCommands = function (asyncSend, dispatcher) {
   let commandQueue = [],
       sendCommand = function (command, replyCallback, errorCallback) {
@@ -254,7 +254,7 @@ io.controlSocket = function (host, port, password, onError) {
                               io.onDataFromOnLine(
                                    io.onLineFromOnMessage(mainDispatcher.pushMessage)),
                               onError),
-      // Tor expects any commands to be terminated by CRLF.
+      // Controllers should send commands terminated by CRLF.
       writeLine = function (text) { socket.write(text + "\r\n"); },
       // Create a sendCommand method from writeLine.
       sendCommand = io.matchRepliesToCommands(writeLine, mainDispatcher),
@@ -371,6 +371,10 @@ utils.listMapData = function (parameterString, listNames) {
   return dataMap;
 };
 
+// __utils.rejectPromise(errorMessage)__.
+// Returns a rejected promise with the given error message.
+utils.rejectPromise = errorMessage => Promise.reject(new Error(errorMessage));
+
 // ## info
 // A namespace for functions related to tor's GETINFO and GETCONF command.
 let info = info || {};
@@ -387,7 +391,7 @@ let info = info || {};
 // or single-line (with a `250-` or `250 ` prefix):
 //
 //     250-version=0.2.6.0-alpha-dev (git-b408125288ad6943)
-info.keyValueStringsFromMessage = utils.extractor(/^(250\+[\s\S]+?^\.|250[-\ ].+?)$/gmi);
+info.keyValueStringsFromMessage = utils.extractor(/^(250\+[\s\S]+?^\.|250[- ].+?)$/gmi);
 
 // __info.applyPerLine(transformFunction)__.
 // Returns a function that splits text into lines,
@@ -400,7 +404,7 @@ info.applyPerLine = function (transformFunction) {
 
 // __info.routerStatusParser(valueString)__.
 // Parses a router status entry as, described in
-// https://gitweb.torproject.org/torspec.git/blob/HEAD:/dir-spec.txt
+// https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt
 // (search for "router status entry")
 info.routerStatusParser = function (valueString) {
   let lines = utils.splitLines(valueString),
@@ -418,7 +422,6 @@ info.routerStatusParser = function (valueString) {
           "v" : data => ({ "version" : data }),
           "w" : data => utils.listMapData(data, []),
           "p" : data => ({ "portList" : data.split(",") }),
-          "m" : data => utils.listMapData(data, [])
         }[line.charAt(0)];
     if (dataFun !== undefined) {
       objects.push(dataFun(myData));
@@ -448,21 +451,6 @@ info.streamStatusParser = function (text) {
                                   "CircuitID", "Target"]);
 };
 
-// __info.configTextParser(text)__.
-// Parse the output of a `getinfo config-text`.
-info.configTextParser = function(text) {
-  let result = {};
-  utils.splitLines(text).map(function(line) {
-    let [name, value] = utils.splitAtFirst(line, /\s/);
-    if (name) {
-      if (!result.hasOwnProperty(name)) result[name] = [];
-      result[name].push(value);
-    }
-  });
-  return result;
-};
-
-
 // __info.bridgeParser(bridgeLine)__.
 // Takes a single line from a `getconf bridge` result and returns
 // a map containing the bridge's type, address, and ID.
@@ -488,16 +476,15 @@ info.bridgeParser = function(bridgeLine) {
 // A map of GETINFO and GETCONF keys to parsing function, which convert
 // result strings to JavaScript data.
 info.parsers = {
-  "version" : utils.identity,
-  "config-file" : utils.identity,
-  "config-defaults-file" : utils.identity,
-  "config-text" : info.configTextParser,
   "ns/id/" : info.routerStatusParser,
-  "ns/name/" : info.routerStatusParser,
   "ip-to-country/" : utils.identity,
   "circuit-status" : info.applyPerLine(info.circuitStatusParser),
-  "stream-status" : info.applyPerLine(info.streamStatusParser),
-  "bridge" : info.bridgeParser
+  "bridge" : info.bridgeParser,
+  // Currently unused parsers:
+  //  "ns/name/" : info.routerStatusParser,
+  //  "stream-status" : info.applyPerLine(info.streamStatusParser),
+  //  "version" : utils.identity,
+  //  "config-file" : utils.identity,
 };
 
 // __info.getParser(key)__.
@@ -512,13 +499,14 @@ info.getParser = function(key) {
 // Converts a key-value string as from GETINFO or GETCONF to a value.
 info.stringToValue = function (string) {
   // key should look something like `250+circuit-status=` or `250-circuit-status=...`
-  // or `250 circuit-status...`
-  let matchForKey = string.match(/^250[ +-](.+?)=/mi),
+  // or `250 circuit-status=...`
+  let matchForKey = string.match(/^250[ +-](.+?)=/),
       key = matchForKey ? matchForKey[1] : null;
   if (key === null) return null;
-  // matchResult finds a single-line result for `250-` or a multi-line one for `250+`.
-  let matchResult = string.match(/^250[ -].+?=(.*?)$/mi) ||
-                    string.match(/^250\+.+?=([\s\S]*?)^\.$/mi),
+  // matchResult finds a single-line result for `250-` or `250 `,
+  // or a multi-line one for `250+`.
+  let matchResult = string.match(/^250[ -].+?=(.*)$/) ||
+                    string.match(/^250\+.+?=([\s\S]*?)^\.$/m),
       // Retrieve the captured group (the text of the value in the key-value pair)
       valueString = matchResult ? matchResult[1] : null,
       // Get the parser function for the key found.
@@ -538,48 +526,27 @@ info.getMultipleResponseValues = function (message) {
              .filter(utils.identity);
 };
 
-// __info.getInfoMultiple(aControlSocket, keys)__.
-// Sends GETINFO for an array of keys. Returns a promise with an array of results.
-info.getInfoMultiple = function (aControlSocket, keys) {
-  /*
-  if (!(keys instanceof Array)) {
-    throw new Error("keys argument should be an array");
-  }
-  if (!(onData instanceof Function)) {
-    throw new Error("onData argument should be a function");
-  }
-  let parsers = keys.map(info.getParser);
-  if (parsers.indexOf("unknown") !== -1) {
-    throw new Error("unknown key");
-  }
-  if (parsers.indexOf("not supported") !== -1) {
-    throw new Error("unsupported key");
-  }
-  */
-  return aControlSocket.sendCommand("getinfo " + keys.join(" "))
-                       .then(info.getMultipleResponseValues);
-};
-
 // __info.getInfo(controlSocket, key)__.
 // Sends GETINFO for a single key. Returns a promise with the result.
 info.getInfo = function (aControlSocket, key) {
-  /*
   if (!utils.isString(key)) {
-    throw new Error("key argument should be a string");
-  }
-  if (!(onValue instanceof Function)) {
-    throw new Error("onValue argument should be a function");
+    return utils.rejectPromise("key argument should be a string");
   }
-  */
-  return info.getInfoMultiple(aControlSocket, [key]).then(data => data[0]);
+  return aControlSocket
+    .sendCommand("getinfo " + key)
+    .then(response => info.getMultipleResponseValues(response)[0]);
 };
 
 // __info.getConf(aControlSocket, key)__.
 // Sends GETCONF for a single key. Returns a promise with the result.
 info.getConf = function (aControlSocket, key) {
-  // GETCONF with a single argument returns results that look like
-  // results from GETINFO with multiple arguments.
-  // So we can use the same kind of parsing for
+  // GETCONF with a single argument returns results with
+  // one or more lines that look like `250[- ]key=value`.
+  // Any GETCONF lines that contain a single keyword only are currently dropped.
+  // So we can use similar parsing to that for getInfo.
+  if (!utils.isString(key)) {
+    return utils.rejectPromise("key argument should be a string");
+  }
   return aControlSocket.sendCommand("getconf " + key)
                        .then(info.getMultipleResponseValues);
 };
@@ -594,22 +561,25 @@ let event = event || {};
 // data.
 event.parsers = {
   "stream" : info.streamStatusParser,
-  "circ" : info.circuitStatusParser
+  // Currently unused:
+  // "circ" : info.circuitStatusParser,
 };
 
 // __event.messageToData(type, message)__.
-// Extract the data from an event.
+// Extract the data from an event. Note, at present
+// we only extract streams that look like `"650" SP...`
 event.messageToData = function (type, message) {
-  let dataText = message.match(/^650 \S+?\s(.*?)$/mi)[1];
+  let dataText = message.match(/^650 \S+?\s(.*)/m)[1];
   return dataText ? event.parsers[type.toLowerCase()](dataText) : null;
 };
 
 // __event.watchEvent(controlSocket, type, filter, onData)__.
 // Watches for a particular type of event. If filter(data) returns true, the event's
 // data is passed to the onData callback. Returns a zero arg function that
-// stops watching the event.
+// stops watching the event. Note: we only observe `"650" SP...` events
+// currently (no `650+...` or `650-...` events).
 event.watchEvent = function (controlSocket, type, filter, onData) {
-  return controlSocket.addNotificationCallback(new RegExp("^650." + type, "i"),
+  return controlSocket.addNotificationCallback(new RegExp("^650 " + type),
     function (message) {
       let data = event.messageToData(type, message);
       if (filter === null || filter(data)) {
@@ -634,7 +604,6 @@ tor.controller = function (host, port, password, onError) {
   let socket = io.controlSocket(host, port, password, onError),
       isOpen = true;
   return { getInfo : key => info.getInfo(socket, key),
-           getInfoMultiple : keys => info.getInfoMultiple(socket, keys),
            getConf : key => info.getConf(socket, key),
            watchEvent : (type, filter, onData) =>
                           event.watchEvent(socket, type, filter, onData),
@@ -655,8 +624,8 @@ tor.controller = function (host, port, password, onError) {
 //     // Get the controller
 //     let c = controller("127.0.0.1", 9151, "MyPassw0rd",
 //                    function (error) { console.log(error.message || error); });
-//     // Send command and receive `250` reply or error message
-//     c.getInfo("ip-to-country/16.16.16.16", console.log);
+//     // Send command and receive `250` reply or error message in a promise:
+//     let replyPromise = c.getInfo("ip-to-country/16.16.16.16");
 //     // Close the controller permanently
 //     c.close();
 let controller = function (host, port, password, onError) {



More information about the tor-commits mailing list