Skip to content

Commit 006aaa7

Browse files
committed
added meaningful exceptions to IPAddr
Previously IPAddr would throw ArgumentError regardless of the cause of the exception. More meaningful exceptions were added (extending ArgumentError for backward compatibility). With new exceptions a developer can pragmatically determine the cause of the IPAddr failure in a more effective manor than checking the exception message.
1 parent e7ddd1f commit 006aaa7

File tree

1 file changed

+64
-42
lines changed

1 file changed

+64
-42
lines changed

lib/ipaddr.rb

Lines changed: 64 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,32 @@ class IPAddr
8282
\z
8383
}xi
8484

85+
# Raised when the provided IP address is an invalid address.
86+
class InvalidAddress < ArgumentError; end
87+
88+
# Raised when the provided IP address is of an unsupported address family.
89+
class UnsupportedAddressFamily < ArgumentError; end
90+
91+
# Raised when an octet contains a zero-filled number.
92+
# Example: 192.162.022.001
93+
class ZeroFilledNumber < ArgumentError; end
94+
95+
# Raised when an address is a mix of address families.
96+
class InconsistentAddressFamily < ArgumentError; end
97+
98+
# Raised when an address family is unspecified and cannot be reliability
99+
# determined (for example: if an Integer is provided instead of a string).
100+
class UnspecifiedAddressFamily < ArgumentError; end
101+
102+
# Raised when the address is an invalid IPv4 address.
103+
class InvalidIPv4 < ArgumentError; end
104+
105+
# Raised when the address is an invalid IPv6 address.
106+
class InvalidIPv6 < ArgumentError; end
107+
108+
# Raised when the address is an invalid length.
109+
class InvalidLength < ArgumentError; end
110+
85111
# Returns the address family of this IP address.
86112
attr_reader :family
87113

@@ -100,7 +126,7 @@ def IPAddr::ntop(addr)
100126
when 16
101127
s = IN6FORMAT % addr.unpack('n8')
102128
else
103-
raise ArgumentError, "unsupported address family"
129+
raise UnsupportedAddressFamily, "unsupported address family"
104130
end
105131
return s
106132
end
@@ -226,7 +252,7 @@ def hton
226252
(@addr >> (112 - 16 * i)) & 0xffff
227253
}.pack('n8')
228254
else
229-
raise "unsupported address family"
255+
raise UnsupportedAddressFamily, "unsupported address family"
230256
end
231257
end
232258

@@ -258,7 +284,7 @@ def ipv4_compat?
258284
# into an IPv4-mapped IPv6 address.
259285
def ipv4_mapped
260286
if !ipv4?
261-
raise ArgumentError, "not an IPv4 address"
287+
raise InvalidIPv4, "not an IPv4 address"
262288
end
263289
return self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6)
264290
end
@@ -267,7 +293,7 @@ def ipv4_mapped
267293
# into an IPv4-compatible IPv6 address.
268294
def ipv4_compat
269295
if !ipv4?
270-
raise ArgumentError, "not an IPv4 address"
296+
raise InvalidIPv4, "not an IPv4 address"
271297
end
272298
return self.clone.set(@addr, Socket::AF_INET6)
273299
end
@@ -291,22 +317,22 @@ def reverse
291317
when Socket::AF_INET6
292318
return ip6_arpa
293319
else
294-
raise "unsupported address family"
320+
raise UnsupportedAddressFamily, "unsupported address family"
295321
end
296322
end
297323

298324
# Returns a string for DNS reverse lookup compatible with RFC3172.
299325
def ip6_arpa
300326
if !ipv6?
301-
raise ArgumentError, "not an IPv6 address"
327+
raise InvalidIPv6, "not an IPv6 address"
302328
end
303329
return _reverse + ".ip6.arpa"
304330
end
305331

306332
# Returns a string for DNS reverse lookup compatible with RFC1886.
307333
def ip6_int
308334
if !ipv6?
309-
raise ArgumentError, "not an IPv6 address"
335+
raise InvalidIPv6, "not an IPv6 address"
310336
end
311337
return _reverse + ".ip6.int"
312338
end
@@ -346,7 +372,7 @@ def to_range
346372
when Socket::AF_INET6
347373
end_addr = (@addr | (IN6MASK ^ @mask_addr))
348374
else
349-
raise "unsupported address family"
375+
raise UnsupportedAddressFamily, "unsupported address family"
350376
end
351377

352378
return clone.set(begin_addr, @family)..clone.set(end_addr, @family)
@@ -361,29 +387,31 @@ def inspect
361387
when Socket::AF_INET6
362388
af = "IPv6"
363389
else
364-
raise "unsupported address family"
390+
raise UnsupportedAddressFamily, "unsupported address family"
365391
end
366392
return sprintf("#<%s: %s:%s/%s>", self.class.name,
367393
af, _to_string(@addr), _to_string(@mask_addr))
368394
end
369395

370396
protected
371397

398+
399+
372400
# Set +@addr+, the internal stored ip address, to given +addr+. The
373401
# parameter +addr+ is validated using the first +family+ member,
374402
# which is +Socket::AF_INET+ or +Socket::AF_INET6+.
375403
def set(addr, *family)
376404
case family[0] ? family[0] : @family
377405
when Socket::AF_INET
378406
if addr < 0 || addr > IN4MASK
379-
raise ArgumentError, "invalid address"
407+
raise InvalidAddress, "invalid address"
380408
end
381409
when Socket::AF_INET6
382410
if addr < 0 || addr > IN6MASK
383-
raise ArgumentError, "invalid address"
411+
raise InvalidAddress, "invalid address"
384412
end
385413
else
386-
raise ArgumentError, "unsupported address family"
414+
raise UnsupportedAddressFamily, "unsupported address family"
387415
end
388416
@addr = addr
389417
if family[0]
@@ -400,7 +428,7 @@ def mask!(mask)
400428
else
401429
m = IPAddr.new(mask)
402430
if m.family != @family
403-
raise ArgumentError, "address family is not same"
431+
raise InconsistentAddressFamily, "address family is not same"
404432
end
405433
@mask_addr = m.to_i
406434
@addr &= @mask_addr
@@ -412,18 +440,18 @@ def mask!(mask)
412440
case @family
413441
when Socket::AF_INET
414442
if prefixlen < 0 || prefixlen > 32
415-
raise ArgumentError, "invalid length"
443+
raise InvalidLength, "invalid length"
416444
end
417445
masklen = 32 - prefixlen
418446
@mask_addr = ((IN4MASK >> masklen) << masklen)
419447
when Socket::AF_INET6
420448
if prefixlen < 0 || prefixlen > 128
421-
raise ArgumentError, "invalid length"
449+
raise InvalidLength, "invalid length"
422450
end
423451
masklen = 128 - prefixlen
424452
@mask_addr = ((IN6MASK >> masklen) << masklen)
425453
else
426-
raise "unsupported address family"
454+
raise UnsupportedAddressFamily, "unsupported address family"
427455
end
428456
@addr = ((@addr >> masklen) << masklen)
429457
return self
@@ -457,9 +485,9 @@ def initialize(addr = '::', family = Socket::AF_UNSPEC)
457485
@mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
458486
return
459487
when Socket::AF_UNSPEC
460-
raise ArgumentError, "address family must be specified"
488+
raise UnspecifiedAddressFamily, "address family must be specified"
461489
else
462-
raise ArgumentError, "unsupported address family: #{family}"
490+
raise UnsupportedAddressFamily, "unsupported address family: #{family}"
463491
end
464492
end
465493
prefix, prefixlen = addr.split('/')
@@ -482,7 +510,7 @@ def initialize(addr = '::', family = Socket::AF_UNSPEC)
482510
@family = Socket::AF_INET6
483511
end
484512
if family != Socket::AF_UNSPEC && @family != family
485-
raise ArgumentError, "address family mismatch"
513+
raise InconsistentAddressFamily, "address family mismatch"
486514
end
487515
if prefixlen
488516
mask!(prefixlen)
@@ -511,8 +539,8 @@ def in_addr(addr)
511539
octets = m.captures
512540
end
513541
octets.inject(0) { |i, s|
514-
(n = s.to_i) < 256 or raise ArgumentError, "invalid address"
515-
s.match(/\A0./) and raise ArgumentError, "zero-filled number is ambiguous"
542+
(n = s.to_i) < 256 or raise InvalidAddress, "invalid address"
543+
s.match(/\A0./) and raise ZeroFilledNumber, "zero-filled number is ambiguous"
516544
i << 8 | n
517545
}
518546
end
@@ -529,18 +557,18 @@ def in6_addr(left)
529557
right = ''
530558
when RE_IPV6ADDRLIKE_COMPRESSED
531559
if $4
532-
left.count(':') <= 6 or raise ArgumentError, "invalid address"
560+
left.count(':') <= 6 or raise InvalidAddress, "invalid address"
533561
addr = in_addr($~[4,4])
534562
left = $1
535563
right = $3 + '0:0'
536564
else
537-
left.count(':') <= 7 or raise ArgumentError, "invalid address"
565+
left.count(':') <= 7 or raise InvalidAddress, "invalid address"
538566
left = $1
539567
right = $2
540568
addr = 0
541569
end
542570
else
543-
raise ArgumentError, "invalid address"
571+
raise InvalidAddress, "invalid address"
544572
end
545573
l = left.split(':')
546574
r = right.split(':')
@@ -560,7 +588,7 @@ def addr_mask(addr)
560588
when Socket::AF_INET6
561589
return addr & IN6MASK
562590
else
563-
raise "unsupported address family"
591+
raise UnsupportedAddressFamily, "unsupported address family"
564592
end
565593
end
566594

@@ -573,7 +601,7 @@ def _reverse
573601
when Socket::AF_INET6
574602
return ("%.32x" % @addr).reverse!.gsub!(/.(?!$)/, '\&.')
575603
else
576-
raise "unsupported address family"
604+
raise UnsupportedAddressFamily, "unsupported address family"
577605
end
578606
end
579607

@@ -586,7 +614,7 @@ def _to_string(addr)
586614
when Socket::AF_INET6
587615
return (("%.32x" % addr).gsub!(/.{4}(?!$)/, '\&:'))
588616
else
589-
raise "unsupported address family"
617+
raise UnsupportedAddressFamily, "unsupported address family"
590618
end
591619
end
592620

@@ -713,19 +741,13 @@ def test_s_new
713741

714742
assert_equal("2001:200:300::", IPAddr.new("[2001:200:300::]/48").to_s)
715743

716-
[
717-
["192.168.0.256"],
718-
["192.168.0.011"],
719-
["fe80::1%fxp0"],
720-
["::1/255.255.255.0"],
721-
[IPAddr.new("::1").to_i],
722-
["::ffff:192.168.1.2/120", Socket::AF_INET],
723-
["[192.168.1.2]/120"],
724-
].each { |args|
725-
assert_raises(ArgumentError) {
726-
IPAddr.new(*args)
727-
}
728-
}
744+
assert_raises(IPAddr::InvalidAddress) { IPAddr.new('192.168.0.256') }
745+
assert_raises(IPAddr::ZeroFilledNumber) { IPAddr.new('192.168.0.011') }
746+
assert_raises(IPAddr::InvalidAddress) { IPAddr.new("fe80::1%fxp0") }
747+
assert_raises(IPAddr::InconsistentAddressFamily) { IPAddr.new("::1/255.255.255.0") }
748+
assert_raises(IPAddr::UnspecifiedAddressFamily) { IPAddr.new(1) }
749+
assert_raises(IPAddr::InconsistentAddressFamily) { IPAddr.new("::ffff:192.168.1.2/120", Socket::AF_INET) }
750+
assert_raises(IPAddr::InvalidAddress) { IPAddr.new("[192.168.1.2]/120") }
729751
end
730752

731753
def test_s_new_ntoh
@@ -786,14 +808,14 @@ def test_reverse
786808

787809
def test_ip6_arpa
788810
assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").ip6_arpa)
789-
assert_raises(ArgumentError) {
811+
assert_raises(IPAddr::InvalidIPv6) {
790812
IPAddr.new("192.168.2.1").ip6_arpa
791813
}
792814
end
793815

794816
def test_ip6_int
795817
assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.int", IPAddr.new("3ffe:505:2::f").ip6_int)
796-
assert_raises(ArgumentError) {
818+
assert_raises(IPAddr::InvalidIPv6) {
797819
IPAddr.new("192.168.2.1").ip6_int
798820
}
799821
end

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy