summaryrefslogtreecommitdiffstats
path: root/toolkit/components/url-classifier/content/moz/protocol4.js
blob: a75f6b531e1841f368db2c2d2bde9c649105d4fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.


// A helper class that knows how to parse from and serialize to
// protocol4. This is a simple, historical format used by some Google
// interfaces, for example the Toolbar (i.e., ancient services).
//
// Protocol4 consists of a newline-separated sequence of name/value
// pairs (strings). Each line consists of the name, the value length,
// and the value itself, all separated by colons. Example:
//
// foo:6:barbaz\n
// fritz:33:issickofdynamicallytypedlanguages\n


/**
 * This class knows how to serialize/deserialize maps to/from their
 * protocol4 representation.
 *
 * @constructor
 */
this.G_Protocol4Parser = function G_Protocol4Parser() {
  this.debugZone = "protocol4";

  this.protocol4RegExp_ = new RegExp("([^:]+):\\d+:(.*)$");
  this.newlineRegExp_ = new RegExp("(\\r)?\\n");
}

/**
 * Create a map from a protocol4 string. Silently skips invalid lines.
 *
 * @param text String holding the protocol4 representation
 * 
 * @returns Object as an associative array with keys and values 
 *          given in text. The empty object is returned if none
 *          are parsed.
 */
G_Protocol4Parser.prototype.parse = function(text) {

  var response = {};
  if (!text)
    return response;

  // Responses are protocol4: (repeated) name:numcontentbytes:content\n
  var lines = text.split(this.newlineRegExp_);
  for (var i = 0; i < lines.length; i++)
    if (this.protocol4RegExp_.exec(lines[i]))
      response[RegExp.$1] = RegExp.$2;

  return response;
}

/**
 * Create a protocol4 string from a map (object). Throws an error on 
 * an invalid input.
 *
 * @param map Object as an associative array with keys and values 
 *            given as strings.
 *
 * @returns text String holding the protocol4 representation
 */
G_Protocol4Parser.prototype.serialize = function(map) {
  if (typeof map != "object")
    throw new Error("map must be an object");

  var text = "";
  for (var key in map) {
    if (typeof map[key] != "string")
      throw new Error("Keys and values must be strings");
    
    text += key + ":" + map[key].length + ":" + map[key] + "\n";
  }
  
  return text;
}

#ifdef DEBUG
/**
 * Cheesey unittests
 */
this.TEST_G_Protocol4Parser = function TEST_G_Protocol4Parser() {
  if (G_GDEBUG) {
    var z = "protocol4 UNITTEST";
    G_debugService.enableZone(z);

    G_Debug(z, "Starting");

    var p = new G_Protocol4Parser();
    
    let isEmpty = function (map) {
      for (var key in map) 
        return false;
      return true;
    };

    G_Assert(z, isEmpty(p.parse(null)), "Parsing null broken");
    G_Assert(z, isEmpty(p.parse("")), "Parsing nothing broken");

    var t = "foo:3:bar";
    G_Assert(z, p.parse(t)["foo"] === "bar", "Parsing one line broken");

    t = "foo:3:bar\n";
    G_Assert(z, p.parse(t)["foo"] === "bar", "Parsing line with lf broken");

    t = "foo:3:bar\r\n";
    G_Assert(z, p.parse(t)["foo"] === "bar", "Parsing with crlf broken");


    t = "foo:3:bar\nbar:3:baz\r\nbom:3:yaz\n";
    G_Assert(z, p.parse(t)["foo"] === "bar", "First in multiline");
    G_Assert(z, p.parse(t)["bar"] === "baz", "Second in multiline");
    G_Assert(z, p.parse(t)["bom"] === "yaz", "Third in multiline");
    G_Assert(z, p.parse(t)[""] === undefined, "Nonexistent in multiline");
    
    // Test serialization

    var original = { 
      "1": "1", 
      "2": "2", 
      "foobar": "baz",
      "hello there": "how are you?" ,
    };
    var deserialized = p.parse(p.serialize(original));
    for (var key in original) 
      G_Assert(z, original[key] === deserialized[key], 
               "Trouble (de)serializing " + key);

    G_Debug(z, "PASSED");  
  }
}
#endif