'example.com' == 'example.com.' => false... is this intended?

Discussion in 'Ruby' started by Sam Roberts, Jan 31, 2005.

  1. Sam Roberts

    Sam Roberts Guest

    Hi Tanaka,

    I don't understand why DNS::Name#== requires both to be absolute if one
    is.

    Is this really necessary/useful? It surprises me.

    Also, I have a set of comparison operations for Resolv::DNS::Name.

    I copied the style (and docs) from Module/hierarchy comparisons, because
    I think there is some similarity.

    Comments?

    If you will accept, I will send patch and changelog.

    Thanks,
    Sam

    Below is implementation, followed by unit test so you can see behaviour.


    # DNS names are hierarchical in a similar sense to ruby classes/modules, and the
    # comparison operators are defined similarly to those of Module. A name is
    # +<+ another if it is a subdomain.
    # www.example.com < example.com # -> true
    # example.com < example.com # -> false
    # example.com <= example.com # -> true
    # com < example.com # -> false
    # bar.com < example.com # -> nil
    #
    # Note that #== does not consider two names equal if they differ in whether
    # they are #absolute?, but #equal? considers only the label when comparing
    # names.
    class Name
    def inspect
    n = to_s
    n << '.' if absolute?
    return n
    end

    def equal?(name)
    n = Name.create(name)

    @labels == n.to_a
    end

    def related?(name)
    n = Name.create(name)

    l = length < n.length ? length : n.length

    @labels[-l, l] == n.to_a[-l, l]
    end

    def lt?(name)
    n = Name.create(name)
    length > n.length && to_a[-n.length, n.length] == n.to_a
    end


    # Summary:
    # name < other => true, false, or nil
    #
    # Returns true if +name+ is a subdomain of +other+. Returns
    # <code>nil</code> if there's no relationship between the two.
    def <(name)
    n = Name.create(name)

    return nil unless self.related?(n)

    lt?(n)
    end

    # Summary:
    # name > other => true, false, or nil
    #
    # Same as +other < name+, see #<.
    def >(name)
    n = Name.create(name)

    n < self
    end

    # Summary:
    # name <= other => true, false, or nil
    #
    # Returns true if +name+ is a subdomain of +other+ or is the same as
    # +other+. Returns <code>nil</code> if there's no relationship between
    # the two.
    def <=(name)
    n = Name.create(name)
    self.equal?(n) || self < n
    end

    # Summary:
    # name >= other => true, false, or nil
    #
    # Returns true if +name+ is an ancestor of +other+, or the two DNS names
    # are the same. Returns <code>nil</code> if there's no relationship
    # between the two.
    def >=(name)
    n = Name.create(name)
    self.equal?(n) || self > n
    end

    # Summary:
    # name <=> other => -1, 0, +1, nil
    #
    # Returns -1 if +name+ is a subdomain of +other+, 0 if
    # +name+ is the same as +other+, and +1 if +other+ is a subdomain of
    # +name+, or nil if +name+ has no relationship with +other+.
    def <=>(name)
    n = Name.create(name)

    return nil unless self.related?(n)

    return -1 if self.lt?(n)
    return +1 if n.lt?(self)
    # must be #equal?
    return 0
    end

    end

    require 'test/unit'

    Name = Resolv::DNS::Name

    class TestDnsName < Test::Unit::TestCase

    def test_what_I_think_are_odd_behaviours
    # Why can't test against strings?
    assert_equal(false, Name.create("example.CoM") == "example.com")
    assert_equal(false, Name.create("example.CoM").eql?("example.com"))

    # Why does making it absolute mean they aren't equal?
    assert_equal(false, Name.create("example.CoM").eql?(Name.create("example.com.")))
    assert_equal(false, Name.create("example.CoM") == Name.create("example.com."))
    end

    def test_CoMparisons

    assert_equal(true, Name.create("example.CoM").eql?(Name.create("example.com")))
    assert_equal(true, Name.create("example.CoM") == Name.create("example.com"))

    assert_equal(true, Name.create("example.CoM").equal?("example.com."))
    assert_equal(true, Name.create("example.CoM").equal?("example.com"))

    assert_equal(true, Name.create("www.example.CoM") < "example.com")
    assert_equal(true, Name.create("www.example.CoM") <= "example.com")
    assert_equal(-1, Name.create("www.example.CoM") <=> "example.com")
    assert_equal(false, Name.create("www.example.CoM") >= "example.com")
    assert_equal(false, Name.create("www.example.CoM") > "example.com")

    assert_equal(false, Name.create("example.CoM") < "example.com")
    assert_equal(true, Name.create("example.CoM") <= "example.com")
    assert_equal(0, Name.create("example.CoM") <=> "example.com")
    assert_equal(true, Name.create("example.CoM") >= "example.com")
    assert_equal(false, Name.create("example.CoM") > "example.com")

    assert_equal(false, Name.create("CoM") < "example.com")
    assert_equal(false, Name.create("CoM") <= "example.com")
    assert_equal(+1, Name.create("CoM") <=> "example.com")
    assert_equal(true, Name.create("CoM") >= "example.com")
    assert_equal(true, Name.create("CoM") > "example.com")

    assert_equal(nil, Name.create("bar.CoM") < "example.com")
    assert_equal(nil, Name.create("bar.CoM") <= "example.com")
    assert_equal(nil, Name.create("bar.CoM") <=> "example.com")
    assert_equal(nil, Name.create("bar.CoM") >= "example.com")
    assert_equal(nil, Name.create("bar.CoM") > "example.com")

    assert_equal(nil, Name.create("net.") < "com")
    assert_equal(nil, Name.create("net.") <= "com")
    assert_equal(nil, Name.create("net.") <=> "com")
    assert_equal(nil, Name.create("net.") >= "com")
    assert_equal(nil, Name.create("net.") > "com")

    end
    end
    Sam Roberts, Jan 31, 2005
    #1
    1. Advertising

  2. Sam Roberts

    Tanaka Akira Guest

    In article <>,
    Sam Roberts <> writes:

    > I don't understand why DNS::Name#== requires both to be absolute if one
    > is.
    >
    > Is this really necessary/useful? It surprises me.


    I think it's right behavior.

    > Also, I have a set of comparison operations for Resolv::DNS::Name.
    >
    > I copied the style (and docs) from Module/hierarchy comparisons, because
    > I think there is some similarity.
    >
    > Comments?


    I'm not sure that they are used frequently enough to occupy comparison
    operators.
    --
    Tanaka Akira
    Tanaka Akira, Feb 4, 2005
    #2
    1. Advertising

  3. Sam Roberts

    Sam Roberts Guest

    Quoteing , on Fri, Feb 04, 2005 at 01:25:20PM +0900:
    > In article <>,
    > Sam Roberts <> writes:
    >
    > > I don't understand why DNS::Name#== requires both to be absolute if one
    > > is.
    > >
    > > Is this really necessary/useful? It surprises me.

    >
    > I think it's right behavior.


    Why? When are they not the same?

    They are equivalent in the DNS, Resolv::DNS#getaddress() would return
    the same A record for both.

    > > Also, I have a set of comparison operations for Resolv::DNS::Name.

    >
    > I'm not sure that they are used frequently enough to occupy comparison
    > operators.


    Name doesn't have any comparison operators, so they occupy empty space.

    Do you have another idea on what Name < Name could mean?

    I found it necessary to find whether a Name was a sub-domain of another.
    How would you recommend to do this, if there is no method?

    lhs.length > rhs.length && lhs.to_a[-rhs.length, rhs.length] == rhs.to_a

    is the best I came up with, and its not the kind of thing I would want
    to type regularly.

    Cheers,
    Sam
    Sam Roberts, Feb 4, 2005
    #3
  4. Sam Roberts

    Tanaka Akira Guest

    In article <>,
    Sam Roberts <> writes:

    > Why? When are they not the same?


    For example, if you have a machine named "museum", it is confusing with
    "museum." domain.

    > They are equivalent in the DNS, Resolv::DNS#getaddress() would return
    > the same A record for both.


    There are several top-domains which have A record: ac, museum, etc.
    If your local domain have a machine named "ac", it is important to
    distinguish a relative "ac" domain and the absolute "ac" domain.

    > Name doesn't have any comparison operators, so they occupy empty space.
    >
    > Do you have another idea on what Name < Name could mean?


    For example, lexical order.

    > I found it necessary to find whether a Name was a sub-domain of another.
    > How would you recommend to do this, if there is no method?
    >
    > lhs.length > rhs.length && lhs.to_a[-rhs.length, rhs.length] == rhs.to_a
    >
    > is the best I came up with, and its not the kind of thing I would want
    > to type regularly.


    Adding some method (not operator) is acceptable if it has a good name.
    --
    Tanaka Akira
    Tanaka Akira, Feb 4, 2005
    #4
  5. Sam Roberts <> wrote:
    > > > I don't understand why DNS::Name#== requires both to be absolute if one
    > > > is.
    > > >
    > > > Is this really necessary/useful? It surprises me.

    > >
    > > I think it's right behavior.

    >
    > Why? When are they not the same?
    >
    > They are equivalent in the DNS, Resolv::DNS#getaddress() would return
    > the same A record for both.


    "example.com" is a relative domain name. Depending on your
    resolver/nameserver's configuration, I believe it could resolve to
    "example.com.DEFAULTDOMAIN." which wouldn't be the same as
    "example.com."

    Cheers,
    Navin.
    Navindra Umanee, Feb 4, 2005
    #5
  6. Sam Roberts

    Sam Roberts Guest

    Quoteing , on Fri, Feb 04, 2005 at 05:02:45PM +0900:
    > In article <>,
    > Sam Roberts <> writes:
    >
    > > Why? When are they not the same?

    >
    > For example, if you have a machine named "museum", it is confusing with
    > "museum." domain.
    >
    > > They are equivalent in the DNS, Resolv::DNS#getaddress() would return
    > > the same A record for both.

    >
    > There are several top-domains which have A record: ac, museum, etc.
    > If your local domain have a machine named "ac", it is important to
    > distinguish a relative "ac" domain and the absolute "ac" domain.


    You only sometimes distinguish between the two, sometimes you convert
    them to each other:

    >> Name = Resolv::DNS::Name

    => Resolv::DNS::Name
    >> Name.create('museum') == Name.create('museum')

    => true
    # But, wouldn't this depend on the location? On my net, museum would
    # be museum.local.
    >> Name.create('museum') == Name.create('museum.')

    => false
    >> Name.create('museum').to_s == Name.create('museum.').to_s

    => true
    # Isn't it important to distinguish?

    n0=Resolv::DNS.new.getname("193.108.154.9")

    n1=Resolv.getname("193.108.154.9")
    => "a193-108-154-9.deploy.akamaitechnologies.com"
    # note it isn't absolute, though the DNS response was

    n0 == n1
    => in `==': undefined method `absolute?' for "com":String (NoMethodError)
    # I have to change my String to a Name to compare it? Irritating.

    n1 = Resolv::DNS::Name.create(n0)
    n0 == n1
    => false
    # DNS returns absolute names
    n2 = Resolv::DNS::Name.create(n0.to_s)
    n0 == n2
    => false
    n0.to_s == n2.to_s
    => true

    Maybe you haven't seen how unuseful the behaviour of == is because you
    use it inside resolv.rb, and all names you see are absolute?

    Outside of resolv.rb (including input/output values of the common Resolv
    class methods) names are non-absolute strings, and the DNS Name objects
    can't be compared to them.

    > > Name doesn't have any comparison operators, so they occupy empty space.
    > >
    > > Do you have another idea on what Name < Name could mean?

    >
    > For example, lexical order.
    >
    > > I found it necessary to find whether a Name was a sub-domain of another.
    > > How would you recommend to do this, if there is no method?
    > >
    > > lhs.length > rhs.length && lhs.to_a[-rhs.length, rhs.length] == rhs.to_a
    > >
    > > is the best I came up with, and its not the kind of thing I would want
    > > to type regularly.

    >
    > Adding some method (not operator) is acceptable if it has a good name.


    The code I posted included the method #lt?, you could include it as is,
    or change its name. For consistency with #eql?, you may want to make it
    NOT convert its argument from String to Name, or you may want to change
    both to allow comparison to String.

    def lt?(name)
    n = Name.create(name) # maybe remove?
    length > n.length && to_a[-n.length, n.length] == n.to_a
    end

    def ==(other)
    other = Name.create(other) # maybe add?
    return @labels == other.to_a && @absolute == other.absolute?
    end
    alias eql? ==


    Cheers,
    Sam
    Sam Roberts, Feb 4, 2005
    #6
  7. Sam Roberts

    Sam Roberts Guest

    bug - resolv.rb dies on TXT records with multiple strings

    The attached patch fixes this.

    Note well that it does it in such a way that it is backwards compatible, but
    also allows callers to see the strings as an array. I need this.

    RFC1035 says "semantics of the text depends on the domain where it is found",
    and the DNS-SD draft says mDNS TXT responses contain key/value pairs, where
    each key/value pair is a <character-string> from the TXT rdata.

    RFC1035:

    3.3.14. TXT RDATA format

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    / TXT-DATA /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

    where:

    TXT-DATA One or more <character-string>s.

    TXT RRs are used to hold descriptive text. The semantics of the text
    depends on the domain where it is found.

    Reproduce this with packet collected from wild:

    require 'resolv.rb'
    require 'pp'

    data = "\000\000\000\000\000\003\000\003\000\000\000\000\025Sam Roberts\342\200\231s Music\005_daap\004_tcp\005local\000\000!\000\001\300\f\000\020\000\001\300\"\000\f\000\001\300\f\000!\000\001\000\000\000;\000\021\000\000\000\000\016i\010ensemble\300-\300\f\000\020\000\001\000\000\000;\000\224\ttxtvers=1\016Version=196608\023iTSh Version=131073\027Machine ID=9C5AC2725708\034Database ID=681233690CC1C418\"Machine Name=Sam Roberts\342\200\231s Music\016Password=false\300\"\000\f\000\001\000\000\034\037\000\002\300\f"

    msg = Resolv::DNS::Message.decode(data)

    pp msg

    txtanswer = msg.answer[1]
    txtrr = txtanswer[2]

    pp txtrr.data
    pp txtrr.datas


    Changelog:

    resolv.rb dies on TXT records with multiple strings

    Patch:


    Index: resolv.rb
    ===================================================================
    RCS file: /src/ruby/lib/resolv.rb,v
    retrieving revision 1.17.2.8
    diff -u -r1.17.2.8 resolv.rb
    --- resolv.rb 29 Jan 2005 05:22:35 -0000 1.17.2.8
    +++ resolv.rb 5 Feb 2005 03:11:52 -0000
    @@ -1266,6 +1266,14 @@
    return d
    end

    + def get_strings
    + strings = []
    + until @index == @limit
    + strings << get_string
    + end
    + strings
    + end
    +
    def get_name
    return Name.new(self.get_labels)
    end
    @@ -1511,14 +1519,21 @@
    def initialize(data)
    @data = data
    end
    - attr_reader :data
    +
    + def data
    + @data.join
    + end
    +
    + def datas
    + @data
    + end

    def encode_rdata(msg)
    msg.put_string(@data)
    end

    def self.decode_rdata(msg)
    - data = msg.get_string
    + data = msg.get_strings
    return self.new(data)
    end
    end
    Sam Roberts, Feb 5, 2005
    #7
  8. Sam Roberts

    Tanaka Akira Guest

    In article <>,
    Sam Roberts <> writes:

    > Maybe you haven't seen how unuseful the behaviour of == is because you
    > use it inside resolv.rb, and all names you see are absolute?
    >
    > Outside of resolv.rb (including input/output values of the common Resolv
    > class methods) names are non-absolute strings, and the DNS Name objects
    > can't be compared to them.


    It is caused by the absolute/relative difference is not cared outside
    of a resolver. The unusefulness comes from you need supply omitted
    absoluteness information for conversion from string to name, and
    Resolv::DNS::Name#to_s omit the absoluteness information.

    I believe Resolv::DNS::Name's absoluteness sensitive behavior prevents
    a kind of bugs. So I don't want to introduce absoluteness insensitive
    behavour such as your comparison.

    Adding some conversion methods may be a solution. I don't have
    concrete idea, though.

    > The code I posted included the method #lt?, you could include it as is,
    > or change its name. For consistency with #eql?, you may want to make it
    > NOT convert its argument from String to Name, or you may want to change
    > both to allow comparison to String.


    I don't think lt? is a good name.
    Because it may mean comparison in lexical order and other orders.
    --
    Tanaka Akira
    Tanaka Akira, Feb 5, 2005
    #8
  9. Sam Roberts

    Sam Roberts Guest

    Quoteing , on Sat, Feb 05, 2005 at 01:27:35PM +0900:
    > > The code I posted included the method #lt?, you could include it as is,
    > > or change its name. For consistency with #eql?, you may want to make it
    > > NOT convert its argument from String to Name, or you may want to change
    > > both to allow comparison to String.

    >
    > I don't think lt? is a good name.
    > Because it may mean comparison in lexical order and other orders.


    Perhaps #subdomain?

    sam
    Sam Roberts, Feb 5, 2005
    #9
  10. Sam Roberts

    Tanaka Akira Guest

    Re: bug - resolv.rb dies on TXT records with multiple strings

    In article <>,
    Sam Roberts <> writes:

    > The attached patch fixes this.
    >
    > Note well that it does it in such a way that it is backwards compatible, but
    > also allows callers to see the strings as an array. I need this.
    >
    > RFC1035 says "semantics of the text depends on the domain where it is found",
    > and the DNS-SD draft says mDNS TXT responses contain key/value pairs, where
    > each key/value pair is a <character-string> from the TXT rdata.


    It is fixed based on your patch. Thank you.

    Note that I added TXT#strings to retrieve all strings, instead of
    TXT#datas.
    --
    Tanaka Akira
    Tanaka Akira, Feb 5, 2005
    #10
  11. Sam Roberts

    Tanaka Akira Guest

    In article <>,
    Sam Roberts <> writes:

    > Perhaps #subdomain?


    The term "subdomain" is good.

    But I feel two possibile meanings with A.subdomain?(B) :

    * A is a subdomain of B
    * B is a subdomain of A

    Is it clear for native speakers?
    --
    Tanaka Akira
    Tanaka Akira, Feb 5, 2005
    #11
  12. Sam Roberts

    Sam Roberts Guest

    Quoteing , on Sun, Feb 06, 2005 at 04:55:36AM +0900:
    > In article <>,
    > Sam Roberts <> writes:
    >
    > > Perhaps #subdomain?

    >
    > The term "subdomain" is good.
    >
    > But I feel two possibile meanings with A.subdomain?(B) :
    >
    > * A is a subdomain of B
    > * B is a subdomain of A
    >
    > Is it clear for native speakers?


    Native speakers are as confused by their language as everybody else.

    #subdomainof?

    would make it completely clear.

    Sam
    Sam Roberts, Feb 5, 2005
    #12
  13. Sam Roberts

    Sam Roberts Guest

    Re: bug - resolv.rb dies on TXT records with multiple strings

    Quoteing , on Sun, Feb 06, 2005 at 03:36:04AM +0900:
    > In article <>,
    > It is fixed based on your patch. Thank you.
    >
    > Note that I added TXT#strings to retrieve all strings, instead of
    > TXT#datas.


    I am happy with that.

    Thanks,
    Sam
    Sam Roberts, Feb 5, 2005
    #13
  14. On Sun, 6 Feb 2005 04:55:36 +0900, Tanaka Akira <> wrote:
    > In article < >,
    > Sam Roberts < > writes:
    > > Perhaps #subdomain?

    > The term "subdomain" is good.
    >
    > But I feel two possibile meanings with A.subdomain?(B) :
    >
    > * A is a subdomain of B
    > * B is a subdomain of A
    >
    > Is it clear for native speakers?


    Might I suggest #include? instead? Thus, (using <> strings to
    represent instances of the class under discussion):

    <.ca>.include?(<halostatue.ca>) # => true
    <halostatue.ca>.include?(<www.halostatue.ca>) # => true

    But, I don't use this functionality at all, so you can safely ignore
    my suggestion here.

    -austin
    --
    Austin Ziegler *
    * Alternate:
    Austin Ziegler, Feb 5, 2005
    #14
  15. Sam Roberts

    Tanaka Akira Guest

    In article <>,
    Sam Roberts <> writes:

    > #subdomainof?
    >
    > would make it completely clear.


    subdomain_of? and inspect is implemented.

    I inserted a underscore to consistent with kind_of?.
    --
    Tanaka Akira
    Tanaka Akira, Feb 7, 2005
    #15
  16. Sam Roberts

    Sam Roberts Guest

    Quoteing , on Tue, Feb 08, 2005 at 12:26:36AM +0900:
    > In article <>,
    > Sam Roberts <> writes:
    >
    > > #subdomainof?
    > >
    > > would make it completely clear.

    >
    > subdomain_of? and inspect is implemented.


    Thank you.

    Sam
    Sam Roberts, Feb 7, 2005
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. André
    Replies:
    3
    Views:
    1,574
  2. Rajarshi

    0 == False but [] != False?

    Rajarshi, May 24, 2007, in forum: Python
    Replies:
    20
    Views:
    703
    Erik Max Francis
    May 30, 2007
  3. DJ
    Replies:
    3
    Views:
    923
  4. trans.  (T. Onoma)
    Replies:
    0
    Views:
    150
    trans. (T. Onoma)
    Sep 25, 2004
  5. trans.  (T. Onoma)
    Replies:
    1
    Views:
    165
    David A. Black
    Sep 25, 2004
Loading...

Share This Page