Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/net/ipaddress.js
2868 views
1
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview This file contains classes to handle IPv4 and IPv6 addresses.
17
* This implementation is mostly based on Google's project:
18
* http://code.google.com/p/ipaddr-py/.
19
*
20
*/
21
22
goog.provide('goog.net.IpAddress');
23
goog.provide('goog.net.Ipv4Address');
24
goog.provide('goog.net.Ipv6Address');
25
26
goog.require('goog.array');
27
goog.require('goog.math.Integer');
28
goog.require('goog.object');
29
goog.require('goog.string');
30
31
32
33
/**
34
* Abstract class defining an IP Address.
35
*
36
* Please use goog.net.IpAddress static methods or
37
* goog.net.Ipv4Address/Ipv6Address classes.
38
*
39
* @param {!goog.math.Integer} address The Ip Address.
40
* @param {number} version The version number (4, 6).
41
* @constructor
42
*/
43
goog.net.IpAddress = function(address, version) {
44
/**
45
* The IP Address.
46
* @type {!goog.math.Integer}
47
* @private
48
*/
49
this.ip_ = address;
50
51
/**
52
* The IP Address version.
53
* @type {number}
54
* @private
55
*/
56
this.version_ = version;
57
58
};
59
60
61
/**
62
* @return {number} The IP Address version.
63
*/
64
goog.net.IpAddress.prototype.getVersion = function() {
65
return this.version_;
66
};
67
68
69
/**
70
* @param {!goog.net.IpAddress} other The other IP Address.
71
* @return {boolean} true if the IP Addresses are equal.
72
*/
73
goog.net.IpAddress.prototype.equals = function(other) {
74
return (
75
this.version_ == other.getVersion() &&
76
this.ip_.equals(other.toInteger()));
77
};
78
79
80
/**
81
* @return {!goog.math.Integer} The IP Address, as an Integer.
82
*/
83
goog.net.IpAddress.prototype.toInteger = function() {
84
return /** @type {!goog.math.Integer} */ (goog.object.clone(this.ip_));
85
};
86
87
88
/**
89
* @return {string} The IP Address, as an URI string following RFC 3986.
90
*/
91
goog.net.IpAddress.prototype.toUriString = goog.abstractMethod;
92
93
94
/**
95
* @return {string} The IP Address, as a string.
96
* @override
97
*/
98
goog.net.IpAddress.prototype.toString = goog.abstractMethod;
99
100
101
/**
102
* @return {boolean} Whether or not the address is site-local.
103
*/
104
goog.net.IpAddress.prototype.isSiteLocal = goog.abstractMethod;
105
106
107
/**
108
* @return {boolean} Whether or not the address is link-local.
109
*/
110
goog.net.IpAddress.prototype.isLinkLocal = goog.abstractMethod;
111
112
113
/**
114
* Parses an IP Address in a string.
115
* If the string is malformed, the function will simply return null
116
* instead of raising an exception.
117
*
118
* @param {string} address The IP Address.
119
* @see {goog.net.Ipv4Address}
120
* @see {goog.net.Ipv6Address}
121
* @return {goog.net.IpAddress} The IP Address or null.
122
*/
123
goog.net.IpAddress.fromString = function(address) {
124
try {
125
if (address.indexOf(':') != -1) {
126
return new goog.net.Ipv6Address(address);
127
}
128
129
return new goog.net.Ipv4Address(address);
130
} catch (e) {
131
// Both constructors raise exception if the address is malformed (ie.
132
// invalid). The user of this function should not care about catching
133
// the exception, espcially if it's used to validate an user input.
134
return null;
135
}
136
};
137
138
139
/**
140
* Tries to parse a string represented as a host portion of an URI.
141
* See RFC 3986 for more details on IPv6 addresses inside URI.
142
* If the string is malformed, the function will simply return null
143
* instead of raising an exception.
144
*
145
* @param {string} address A RFC 3986 encoded IP address.
146
* @see {goog.net.Ipv4Address}
147
* @see {goog.net.Ipv6Address}
148
* @return {goog.net.IpAddress} The IP Address.
149
*/
150
goog.net.IpAddress.fromUriString = function(address) {
151
try {
152
if (goog.string.startsWith(address, '[') &&
153
goog.string.endsWith(address, ']')) {
154
return new goog.net.Ipv6Address(address.substring(1, address.length - 1));
155
}
156
157
return new goog.net.Ipv4Address(address);
158
} catch (e) {
159
// Both constructors raise exception if the address is malformed (ie.
160
// invalid). The user of this function should not care about catching
161
// the exception, espcially if it's used to validate an user input.
162
return null;
163
}
164
};
165
166
167
168
/**
169
* Takes a string or a number and returns a IPv4 Address.
170
*
171
* This constructor accepts strings and instance of goog.math.Integer.
172
* If you pass a goog.math.Integer, make sure that its sign is set to positive.
173
* @param {(string|!goog.math.Integer)} address The address to store.
174
* @extends {goog.net.IpAddress}
175
* @constructor
176
* @final
177
*/
178
goog.net.Ipv4Address = function(address) {
179
/**
180
* The cached string representation of the IP Address.
181
* @type {?string}
182
* @private
183
*/
184
this.ipStr_ = null;
185
186
var ip = goog.math.Integer.ZERO;
187
if (address instanceof goog.math.Integer) {
188
if (address.getSign() != 0 || address.lessThan(goog.math.Integer.ZERO) ||
189
address.greaterThan(goog.net.Ipv4Address.MAX_ADDRESS_)) {
190
throw Error('The address does not look like an IPv4.');
191
} else {
192
ip = goog.object.clone(address);
193
}
194
} else {
195
if (!goog.net.Ipv4Address.REGEX_.test(address)) {
196
throw Error(address + ' does not look like an IPv4 address.');
197
}
198
199
var octets = address.split('.');
200
if (octets.length != 4) {
201
throw Error(address + ' does not look like an IPv4 address.');
202
}
203
204
for (var i = 0; i < octets.length; i++) {
205
var parsedOctet = goog.string.toNumber(octets[i]);
206
if (isNaN(parsedOctet) || parsedOctet < 0 || parsedOctet > 255 ||
207
(octets[i].length != 1 && goog.string.startsWith(octets[i], '0'))) {
208
throw Error('In ' + address + ', octet ' + i + ' is not valid');
209
}
210
var intOctet = goog.math.Integer.fromNumber(parsedOctet);
211
ip = ip.shiftLeft(8).or(intOctet);
212
}
213
}
214
goog.net.Ipv4Address.base(
215
this, 'constructor', /** @type {!goog.math.Integer} */ (ip), 4);
216
};
217
goog.inherits(goog.net.Ipv4Address, goog.net.IpAddress);
218
219
220
/**
221
* Regular expression matching all the allowed chars for IPv4.
222
* @type {RegExp}
223
* @private
224
* @const
225
*/
226
goog.net.Ipv4Address.REGEX_ = /^[0-9.]*$/;
227
228
229
/**
230
* The Maximum length for a netmask (aka, the number of bits for IPv4).
231
* @type {number}
232
* @const
233
*/
234
goog.net.Ipv4Address.MAX_NETMASK_LENGTH = 32;
235
236
237
/**
238
* The Maximum address possible for IPv4.
239
* @type {goog.math.Integer}
240
* @private
241
* @const
242
*/
243
goog.net.Ipv4Address.MAX_ADDRESS_ =
244
goog.math.Integer.ONE.shiftLeft(goog.net.Ipv4Address.MAX_NETMASK_LENGTH)
245
.subtract(goog.math.Integer.ONE);
246
247
248
/**
249
* @override
250
*/
251
goog.net.Ipv4Address.prototype.toString = function() {
252
if (this.ipStr_) {
253
return this.ipStr_;
254
}
255
256
var ip = this.ip_.getBitsUnsigned(0);
257
var octets = [];
258
for (var i = 3; i >= 0; i--) {
259
octets[i] = String((ip & 0xff));
260
ip = ip >>> 8;
261
}
262
263
this.ipStr_ = octets.join('.');
264
265
return this.ipStr_;
266
};
267
268
269
/**
270
* @override
271
*/
272
goog.net.Ipv4Address.prototype.toUriString = function() {
273
return this.toString();
274
};
275
276
277
/**
278
* @override
279
*/
280
goog.net.Ipv4Address.prototype.isSiteLocal = function() {
281
// Check for prefix 10/8, 172.16/12, or 192.168/16.
282
var ipInt = this.ip_.toInt();
283
return (((ipInt >>> 24) & 0xff) == 10) ||
284
((((ipInt >>> 24) & 0xff) == 172) && (((ipInt >>> 16) & 0xf0) == 16)) ||
285
((((ipInt >>> 24) & 0xff) == 192) && (((ipInt >>> 16) & 0xff) == 168));
286
};
287
288
289
/**
290
* @override
291
*/
292
goog.net.Ipv4Address.prototype.isLinkLocal = function() {
293
// Check for prefix 169.254/16.
294
var ipInt = this.ip_.toInt();
295
return (((ipInt >>> 24) & 0xff) == 169) && (((ipInt >>> 16) & 0xff) == 254);
296
};
297
298
299
/**
300
* Takes a string or a number and returns an IPv6 Address.
301
*
302
* This constructor accepts strings and instance of goog.math.Integer.
303
* If you pass a goog.math.Integer, make sure that its sign is set to positive.
304
* @param {(string|!goog.math.Integer)} address The address to store.
305
* @constructor
306
* @extends {goog.net.IpAddress}
307
* @final
308
*/
309
goog.net.Ipv6Address = function(address) {
310
/**
311
* The cached string representation of the IP Address.
312
* @type {?string}
313
* @private
314
*/
315
this.ipStr_ = null;
316
317
var ip = goog.math.Integer.ZERO;
318
if (address instanceof goog.math.Integer) {
319
if (address.getSign() != 0 || address.lessThan(goog.math.Integer.ZERO) ||
320
address.greaterThan(goog.net.Ipv6Address.MAX_ADDRESS_)) {
321
throw Error('The address does not look like a valid IPv6.');
322
} else {
323
ip = goog.object.clone(address);
324
}
325
} else {
326
if (!goog.net.Ipv6Address.REGEX_.test(address)) {
327
throw Error(address + ' is not a valid IPv6 address.');
328
}
329
330
var splitColon = address.split(':');
331
if (splitColon[splitColon.length - 1].indexOf('.') != -1) {
332
var newHextets = goog.net.Ipv6Address.dottedQuadtoHextets_(
333
splitColon[splitColon.length - 1]);
334
goog.array.removeAt(splitColon, splitColon.length - 1);
335
goog.array.extend(splitColon, newHextets);
336
address = splitColon.join(':');
337
}
338
339
var splitDoubleColon = address.split('::');
340
if (splitDoubleColon.length > 2 ||
341
(splitDoubleColon.length == 1 && splitColon.length != 8)) {
342
throw Error(address + ' is not a valid IPv6 address.');
343
}
344
345
var ipArr;
346
if (splitDoubleColon.length > 1) {
347
ipArr = goog.net.Ipv6Address.explode_(splitDoubleColon);
348
} else {
349
ipArr = splitColon;
350
}
351
352
if (ipArr.length != 8) {
353
throw Error(address + ' is not a valid IPv6 address');
354
}
355
356
for (var i = 0; i < ipArr.length; i++) {
357
var parsedHextet = goog.math.Integer.fromString(ipArr[i], 16);
358
if (parsedHextet.lessThan(goog.math.Integer.ZERO) ||
359
parsedHextet.greaterThan(goog.net.Ipv6Address.MAX_HEXTET_VALUE_)) {
360
throw Error(ipArr[i] + ' in ' + address + ' is not a valid hextet.');
361
}
362
ip = ip.shiftLeft(16).or(parsedHextet);
363
}
364
}
365
goog.net.Ipv6Address.base(
366
this, 'constructor', /** @type {!goog.math.Integer} */ (ip), 6);
367
};
368
goog.inherits(goog.net.Ipv6Address, goog.net.IpAddress);
369
370
371
/**
372
* Regular expression matching all allowed chars for an IPv6.
373
* @type {RegExp}
374
* @private
375
* @const
376
*/
377
goog.net.Ipv6Address.REGEX_ = /^([a-fA-F0-9]*:){2}[a-fA-F0-9:.]*$/;
378
379
380
/**
381
* The Maximum length for a netmask (aka, the number of bits for IPv6).
382
* @type {number}
383
* @const
384
*/
385
goog.net.Ipv6Address.MAX_NETMASK_LENGTH = 128;
386
387
388
/**
389
* The maximum value of a hextet.
390
* @type {goog.math.Integer}
391
* @private
392
* @const
393
*/
394
goog.net.Ipv6Address.MAX_HEXTET_VALUE_ = goog.math.Integer.fromInt(65535);
395
396
397
/**
398
* The Maximum address possible for IPv6.
399
* @type {goog.math.Integer}
400
* @private
401
* @const
402
*/
403
goog.net.Ipv6Address.MAX_ADDRESS_ =
404
goog.math.Integer.ONE.shiftLeft(goog.net.Ipv6Address.MAX_NETMASK_LENGTH)
405
.subtract(goog.math.Integer.ONE);
406
407
408
/**
409
* @override
410
*/
411
goog.net.Ipv6Address.prototype.toString = function() {
412
if (this.ipStr_) {
413
return this.ipStr_;
414
}
415
416
var outputArr = [];
417
for (var i = 3; i >= 0; i--) {
418
var bits = this.ip_.getBitsUnsigned(i);
419
var firstHextet = bits >>> 16;
420
var secondHextet = bits & 0xffff;
421
outputArr.push(firstHextet.toString(16));
422
outputArr.push(secondHextet.toString(16));
423
}
424
425
outputArr = goog.net.Ipv6Address.compress_(outputArr);
426
this.ipStr_ = outputArr.join(':');
427
return this.ipStr_;
428
};
429
430
431
/**
432
* @override
433
*/
434
goog.net.Ipv6Address.prototype.toUriString = function() {
435
return '[' + this.toString() + ']';
436
};
437
438
439
/**
440
* @override
441
*/
442
goog.net.Ipv6Address.prototype.isSiteLocal = function() {
443
// Check for prefix fd00::/8.
444
var firstDWord = this.ip_.getBitsUnsigned(3);
445
var firstHextet = firstDWord >>> 16;
446
return (firstHextet & 0xff00) == 0xfd00;
447
};
448
449
450
/**
451
* @override
452
*/
453
goog.net.Ipv6Address.prototype.isLinkLocal = function() {
454
// Check for prefix fe80::/10.
455
var firstDWord = this.ip_.getBitsUnsigned(3);
456
var firstHextet = firstDWord >>> 16;
457
return (firstHextet & 0xffc0) == 0xfe80;
458
};
459
460
461
/**
462
* This method is in charge of expanding/exploding an IPv6 string from its
463
* compressed form.
464
* @private
465
* @param {!Array<string>} address An IPv6 address split around '::'.
466
* @return {!Array<string>} The expanded version of the IPv6.
467
*/
468
goog.net.Ipv6Address.explode_ = function(address) {
469
var basePart = address[0].split(':');
470
var secondPart = address[1].split(':');
471
472
if (basePart.length == 1 && basePart[0] == '') {
473
basePart = [];
474
}
475
if (secondPart.length == 1 && secondPart[0] == '') {
476
secondPart = [];
477
}
478
479
// Now we fill the gap with 0.
480
var gap = 8 - (basePart.length + secondPart.length);
481
482
if (gap < 1) {
483
return [];
484
}
485
486
return goog.array.join(basePart, goog.array.repeat('0', gap), secondPart);
487
};
488
489
490
/**
491
* This method is in charge of compressing an expanded IPv6 array of hextets.
492
* @private
493
* @param {!Array<string>} hextets The array of hextet.
494
* @return {!Array<string>} The compressed version of this array.
495
*/
496
goog.net.Ipv6Address.compress_ = function(hextets) {
497
var bestStart = -1;
498
var start = -1;
499
var bestSize = 0;
500
var size = 0;
501
for (var i = 0; i < hextets.length; i++) {
502
if (hextets[i] == '0') {
503
size++;
504
if (start == -1) {
505
start = i;
506
}
507
if (size > bestSize) {
508
bestSize = size;
509
bestStart = start;
510
}
511
} else {
512
start = -1;
513
size = 0;
514
}
515
}
516
517
if (bestSize > 0) {
518
if ((bestStart + bestSize) == hextets.length) {
519
hextets.push('');
520
}
521
hextets.splice(bestStart, bestSize, '');
522
523
if (bestStart == 0) {
524
hextets = [''].concat(hextets);
525
}
526
}
527
return hextets;
528
};
529
530
531
/**
532
* This method will convert an IPv4 to a list of 2 hextets.
533
*
534
* For instance, 1.2.3.4 will be converted to ['0102', '0304'].
535
* @private
536
* @param {string} quads An IPv4 as a string.
537
* @return {!Array<string>} A list of 2 hextets.
538
*/
539
goog.net.Ipv6Address.dottedQuadtoHextets_ = function(quads) {
540
var ip4 = new goog.net.Ipv4Address(quads).toInteger();
541
var bits = ip4.getBitsUnsigned(0);
542
var hextets = [];
543
544
hextets.push(((bits >>> 16) & 0xffff).toString(16));
545
hextets.push((bits & 0xffff).toString(16));
546
547
return hextets;
548
};
549
550
551
/**
552
* @return {boolean} true if the IPv6 contains a mapped IPv4.
553
*/
554
goog.net.Ipv6Address.prototype.isMappedIpv4Address = function() {
555
return (
556
this.ip_.getBitsUnsigned(3) == 0 && this.ip_.getBitsUnsigned(2) == 0 &&
557
this.ip_.getBitsUnsigned(1) == 0xffff);
558
};
559
560
561
/**
562
* Will return the mapped IPv4 address in this IPv6 address.
563
* @return {goog.net.Ipv4Address} an IPv4 or null.
564
*/
565
goog.net.Ipv6Address.prototype.getMappedIpv4Address = function() {
566
if (!this.isMappedIpv4Address()) {
567
return null;
568
}
569
570
var newIpv4 = new goog.math.Integer([this.ip_.getBitsUnsigned(0)], 0);
571
return new goog.net.Ipv4Address(newIpv4);
572
};
573
574