1 # ***** BEGIN LICENSE BLOCK *****
2 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 # The contents of this file are subject to the Mozilla Public License Version
5 # 1.1 (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
7 # http://www.mozilla.org/MPL/
9 # Software distributed under the License is distributed on an "AS IS" basis,
10 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 # for the specific language governing rights and limitations under the
14 # The Original Code is Google Safe Browsing.
16 # The Initial Developer of the Original Code is Google Inc.
17 # Portions created by the Initial Developer are Copyright (C) 2006
18 # the Initial Developer. All Rights Reserved.
21 # Niels Provos <niels@google.com> (original author)
22 # Fritz Schneider <fritz@google.com>
24 # Alternatively, the contents of this file may be used under the terms of
25 # either the GNU General Public License Version 2 or later (the "GPL"), or
26 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 # in which case the provisions of the GPL or the LGPL are applicable instead
28 # of those above. If you wish to allow use of your version of this file only
29 # under the terms of either the GPL or the LGPL, and not to allow others to
30 # use your version of this file under the terms of the MPL, indicate your
31 # decision by deleting the provisions above and replace them with the notice
32 # and other provisions required by the GPL or the LGPL. If you do not delete
33 # the provisions above, a recipient may use your version of this file under
34 # the terms of any one of the MPL, the GPL or the LGPL.
36 # ***** END LICENSE BLOCK *****
39 // A class that serializes and deserializes opaque key/value string to
40 // string maps to/from maps (trtables). It knows how to create
41 // trtables from the serialized format, so it also understands
42 // meta-information like the name of the table and the table's
43 // version. See docs for the protocol description.
45 // TODO: wireformatreader: if you have multiple updates for one table
46 // in a call to deserialize, the later ones will be merged
47 // (all but the last will be ignored). To fix, merge instead
48 // of replace when you have an existing table, and only do so once.
49 // TODO must have blank line between successive types -- problem?
50 // TODO doesn't tolerate blank lines very well
52 // Maybe: These classes could use a LOT more cleanup, but it's not a
53 // priority at the moment. For example, the tablesData/Known
54 // maps should be combined into a single object, the parser
55 // for a given type should be separate from the version info,
56 // and there should be synchronous interfaces for testing.
60 * A class that knows how to serialize and deserialize meta-information.
61 * This meta information is the table name and version number, and
62 * in its serialized form looks like the first line below:
64 * [name-of-table X.Y update?]
65 * ...key/value pairs to add or delete follow...
66 * <blank line ends the table>
68 * The X.Y is the version number and the optional "update" token means
69 * that the table is a differential from the curent table the extension
70 * has. Its absence means that this is a full, new table.
72 function PROT_VersionParser(type, opt_major, opt_minor, opt_requireMac) {
73 this.debugZone = "versionparser";
78 this.badHeader = false;
80 // Should the wireformatreader compute a mac?
83 this.macFailed = false;
84 this.requireMac = !!opt_requireMac;
87 this.needsUpdate = false; // used by ListManager to determine update policy
88 // Used by ListerManager to see if we have read data for this table from
89 // disk. Once we read a table from disk, we are not going to do so again
90 // but instead update remotely if necessary.
93 this.major = parseInt(opt_major);
95 this.minor = parseInt(opt_minor);
98 /** Import the version information from another VersionParser
99 * @params version a version parser object
101 PROT_VersionParser.prototype.ImportVersion = function(version) {
102 this.major = version.major;
103 this.minor = version.minor;
105 this.mac = version.mac;
106 this.macFailed = version.macFailed;
107 this.macval = version.macval;
108 // Don't set requireMac, since we create vparsers from scratch and doesn't
113 * Creates a string like [goog-white-black 1.1] from internal information
117 PROT_VersionParser.prototype.toString = function() {
118 var s = "[" + this.type + " " + this.major + "." + this.minor + "]";
123 * Creates a string like 1.123 with the version number. This is the
124 * format we store in prefs.
127 PROT_VersionParser.prototype.versionString = function() {
128 return this.major + "." + this.minor;
132 * Creates a string like 1:1 from internal information used for
133 * fetching updates from the server. Called by the listmanager.
137 PROT_VersionParser.prototype.toUrl = function() {
138 return this.major + ":" + this.minor;
142 * Process the old format, [type major.minor [update]]
144 * @returns true if the string could be parsed, false otherwise
146 PROT_VersionParser.prototype.processOldFormat_ = function(line) {
147 if (line[0] != '[' || line.slice(-1) != ']')
150 var description = line.slice(1, -1);
152 // Get the type name and version number of this table
153 var tokens = description.split(" ");
154 this.type = tokens[0];
155 var majorminor = tokens[1].split(".");
156 this.major = parseInt(majorminor[0]);
157 this.minor = parseInt(majorminor[1]);
158 if (isNaN(this.major) || isNaN(this.minor))
161 if (tokens.length >= 3) {
162 this.update = tokens[2] == "update";
169 * Takes a string like [name-of-table 1.1 [update]][mac=MAC] and figures out the
170 * type and corresponding version numbers.
171 * @returns true if the string could be parsed, false otherwise
173 PROT_VersionParser.prototype.fromString = function(line) {
174 G_Debug(this, "Calling fromString with line: " + line);
175 if (line[0] != '[' || line.slice(-1) != ']')
178 // There could be two [][], so take care of it
179 var secondBracket = line.indexOf('[', 1);
180 var firstPart = null;
181 var secondPart = null;
183 if (secondBracket != -1) {
184 firstPart = line.substring(0, secondBracket);
185 secondPart = line.substring(secondBracket);
186 G_Debug(this, "First part: " + firstPart + " Second part: " + secondPart);
189 G_Debug(this, "Old format: " + firstPart);
192 if (!this.processOldFormat_(firstPart))
195 if (secondPart && !this.processOptTokens_(secondPart))
202 * Process optional tokens
204 * @param line A string [token1=val1 token2=val2...]
205 * @returns true if the string could be parsed, false otherwise
207 PROT_VersionParser.prototype.processOptTokens_ = function(line) {
208 if (line[0] != '[' || line.slice(-1) != ']')
210 var description = line.slice(1, -1);
211 // Get the type name and version number of this table
212 var tokens = description.split(" ");
214 for (var i = 0; i < tokens.length; i++) {
215 G_Debug(this, "Processing optional token: " + tokens[i]);
216 var tokenparts = tokens[i].split("=");
217 switch(tokenparts[0]){
220 if (tokenparts.length < 2) {
221 G_Debug(this, "Found mac flag but not mac value!");
224 // The mac value may have "=" in it, so we can't just use tokenparts[1].
225 // Instead, just take the rest of tokens[i] after the first "="
226 this.macval = tokens[i].substr(tokens[i].indexOf("=")+1);
229 G_Debug(this, "Found unrecognized token: " + tokenparts[0]);
238 function TEST_PROT_WireFormat() {
240 var z = "versionparser UNITTEST";
241 G_Debug(z, "Starting");
243 var vp = new PROT_VersionParser("dummy");
244 G_Assert(z, vp.fromString("[foo-bar-url 1.234]"),
245 "failed to parse old format");
246 G_Assert(z, "foo-bar-url" == vp.type, "failed to parse type");
247 G_Assert(z, "1" == vp.major, "failed to parse major");
248 G_Assert(z, "234" == vp.minor, "failed to parse minor");
250 vp = new PROT_VersionParser("dummy");
251 G_Assert(z, vp.fromString("[foo-bar-url 1.234][mac=567]"),
252 "failed to parse new format");
253 G_Assert(z, "foo-bar-url" == vp.type, "failed to parse type");
254 G_Assert(z, "1" == vp.major, "failed to parse major");
255 G_Assert(z, "234" == vp.minor, "failed to parse minor");
256 G_Assert(z, true == vp.mac, "failed to parse mac");
257 G_Assert(z, "567" == vp.macval, "failed to parse macval");
259 G_Debug(z, "PASSED");