You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2017/11/22 15:16:08 UTC

qpid-proton git commit: PROTON-1693: Update Qpid::Proton#uri parser to allow "shortcut" URIs

Repository: qpid-proton
Updated Branches:
  refs/heads/master 235f0a8aa -> b2adecde3


PROTON-1693: Update Qpid::Proton#uri parser to allow "shortcut" URIs

See the comment for details - allows shortcuts like to the pn_url() parser.
The standard URI parser extensions provided by the module allow for a strict,
standard parse of AMQP URIs if desired. The Container connect/listen functions
will allow shortcut strings, but won't modify already-parsed URIs (except to
add an amqp scheme to scheme-less URIs)


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b2adecde
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b2adecde
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b2adecde

Branch: refs/heads/master
Commit: b2adecde31106361f2ad03a6ca84379e5bf3b2ed
Parents: 235f0a8
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Nov 22 10:03:17 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Nov 22 10:12:19 2017 -0500

----------------------------------------------------------------------
 proton-c/bindings/ruby/lib/core/container.rb |  6 +-
 proton-c/bindings/ruby/lib/core/uri.rb       | 44 ++++++++++----
 proton-c/bindings/ruby/lib/core/url.rb       |  3 +-
 proton-c/bindings/ruby/tests/test_uri.rb     | 70 ++++++++++++++++++-----
 4 files changed, 93 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b2adecde/proton-c/bindings/ruby/lib/core/container.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/core/container.rb b/proton-c/bindings/ruby/lib/core/container.rb
index 6fbdbb5..38dcd74 100644
--- a/proton-c/bindings/ruby/lib/core/container.rb
+++ b/proton-c/bindings/ruby/lib/core/container.rb
@@ -32,8 +32,6 @@ module Qpid::Proton
   class Container
     private
 
-    def amqp_uri(s) Qpid::Proton::amqp_uri s; end
-
     # Container driver applies options and adds container context to events
     class ConnectionTask < Qpid::Proton::HandlerDriver
       def initialize container, io, opts, server=false
@@ -162,7 +160,7 @@ module Qpid::Proton
     # @option (see Connection#open)
     # @return [Connection] The new AMQP connection
     def connect(url, opts = {})
-      url = amqp_uri(url)
+      url = Qpid::Proton::uri(url)
       opts[:user] ||= url.user
       opts[:password] ||= url.password
       # TODO aconway 2017-10-26: Use SSL for amqps URLs
@@ -187,7 +185,7 @@ module Qpid::Proton
     # @return [Listener] The AMQP listener.
     #
     def listen(url, handler=Listener::Handler.new)
-      url = amqp_uri(url)
+      url = Qpid::Proton::uri(url)
       # TODO aconway 2017-11-01: amqps
       listen_io(TCPServer.new(url.host, url.port), handler)
     end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b2adecde/proton-c/bindings/ruby/lib/core/uri.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/core/uri.rb b/proton-c/bindings/ruby/lib/core/uri.rb
index b29a719..aea1e6a 100644
--- a/proton-c/bindings/ruby/lib/core/uri.rb
+++ b/proton-c/bindings/ruby/lib/core/uri.rb
@@ -34,17 +34,37 @@ module URI
 end
 
 module Qpid::Proton
-  # Convert s to an {URI::AMQP} or {URI::AMQPS}
-  # @param s [String,URI] If s has no scheme, use the {URI::AMQP} scheme
-  # @return [URI::AMQP]
-  # @raise [BadURIError] If s has a scheme that is not "amqp" or "amqps"
-  def self.amqp_uri(s)
-    u = URI(s)
-    u.host ||= ""               # Behaves badly with nil host
-    return u if u.is_a? URI::AMQP
-    raise URI::BadURIError, "Not an AMQP URI: '#{u}'" if u.scheme
-    u.scheme = "amqp" unless u.scheme
-    u = URI::parse(u.to_s)      # Re-parse with amqp scheme
-    return u
+  # Returns +s+ converted to a {URI::AMQP} or {URI::AMQPS} object
+  #
+  # Shortcut strings are allowed: an "amqp://" prefix is added if +s+ does
+  # not already look like an 'amqp:', 'amqps:' URI.
+  #
+  # @note this does not give the same result as a standard URI parser in all cases.
+  #  For standard conversion to a URI use: {#URI}(s)
+  #
+  # @param s [String,URI] String to convert to a URI, or a URI object.
+  #  A URI object with no scheme will be converted to {URI::AMQP}
+  # @return [URI::AMQP] A valid {URI::AMQP} or {URI::AMQPS} object
+  # @raise [BadURIError] s is a URI object with a non-AMQP scheme
+  # @raise [InvalidURIError] s cannot be parsed as a URI or shortcut
+  # @raise [::ArgumentError] s is not a string or URI
+  #
+  def self.uri(s)
+    case s
+      when URI::AMQP then s     # Pass-thru
+    when URI::Generic
+      s.scheme ||= 'amqp'
+      u = URI.parse(s.to_s)      # Re-parse as amqp
+      raise URI::BadURIError, "Not an AMQP URI: '#{u}'" unless u.is_a? URI::AMQP
+      u
+    else
+      s = String.try_convert s
+      raise ::ArgumentError, "bad argument (expected URI object or URI string)" unless s
+      case s
+      when %r{^amqps?:} then URI.parse(s)      # Looks like an AMQP URI
+      when %r{^//} then URI.parse("amqp:#{s}") # Looks like a scheme-less URI
+      else URI.parse("amqp://#{s}")            # Treat as a bare host:port/path string
+      end
+    end
   end
 end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b2adecde/proton-c/bindings/ruby/lib/core/url.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/core/url.rb b/proton-c/bindings/ruby/lib/core/url.rb
index b54df66..ff49053 100644
--- a/proton-c/bindings/ruby/lib/core/url.rb
+++ b/proton-c/bindings/ruby/lib/core/url.rb
@@ -32,6 +32,7 @@ module Qpid::Proton
     # Parse a string, return a new URL
     # @param url [#to_s] the URL string
     def initialize(url = nil)
+      deprecated self.class, 'URI or String'
       if url
         @url = Cproton.pn_url_parse(url.to_s)
         if @url.nil?
@@ -72,7 +73,7 @@ module Qpid::Proton
     private
 
     def defaults
-      @scheme = @scheme || "ampq"
+      @scheme = @scheme || "amqp"
       @host = @host || "0.0.0.0"
       @port = @port || 5672
     end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b2adecde/proton-c/bindings/ruby/tests/test_uri.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/tests/test_uri.rb b/proton-c/bindings/ruby/tests/test_uri.rb
index e5279d8..2cfa3b7 100644
--- a/proton-c/bindings/ruby/tests/test_uri.rb
+++ b/proton-c/bindings/ruby/tests/test_uri.rb
@@ -22,19 +22,63 @@ require 'qpid_proton'
 
 class TestURI < Minitest::Test
 
-  def amqp_uri(u) Qpid::Proton::amqp_uri(u); end
-
-  def test_amqp_uri
-    assert_equal URI("amqp:").port, 5672
-    assert_equal URI("amqps:").port, 5671
-    assert_equal URI("amqp://user:pass@host:1234/path"), amqp_uri("//user:pass@host:1234/path")
-    assert_equal URI("amqp://user:pass@host:1234/path"), amqp_uri("amqp://user:pass@host:1234/path")
-    assert_equal URI("amqps://user:pass@host:1234/path"), amqp_uri("amqps://user:pass@host:1234/path")
-    assert_equal URI("amqp://host:1234/path"), amqp_uri("//host:1234/path")
-    assert_equal URI("amqp://host:1234"), amqp_uri("//host:1234")
-    assert_equal URI("amqp://host"), amqp_uri("//host")
-    assert_equal URI("amqp://:1234"), amqp_uri("//:1234")
-    assert_raises(URI::BadURIError) { amqp_uri("http://foo") }
+  def uri(u) Qpid::Proton::uri(u); end
+
+  # Extension to standard URI parser
+  def test_standard
+    u = URI("amqp://u:p@h/x")
+    assert_equal URI::AMQP, u.class
+    assert_equal ['amqp', 'u:p', 'h', 5672, '/x'], u.select(:scheme, :userinfo, :host, :port, :path)
+
+    u = URI("amqps://u:p@h/x")
+    assert_equal URI::AMQPS, u.class
+    assert_equal ['amqps', 'u:p', 'h', 5671, '/x'], u.select(:scheme, :userinfo, :host, :port, :path)
+
+    assert_equal ['amqp', '[::1:2:3]', 5672], URI('amqp://[::1:2:3]').select(:scheme, :host, :port)
+  end
+
+  # Proton::uri on valid URIs
+  def test_valid
+    u = uri("amqp://u:p@h:1/x")
+    assert_equal URI::AMQP, u.class
+    assert_equal u.select(:scheme, :userinfo, :host, :port, :path), ['amqp', 'u:p', 'h', 1, '/x']
+
+    u = uri("amqps://u:p@h:1/x")
+    assert_equal URI::AMQPS, u.class
+    assert_equal u.select(:scheme, :userinfo, :host, :port, :path), ['amqps', 'u:p', 'h', 1, '/x']
+
+    # Schemeless string -> amqp
+    assert_equal URI("amqp://h:1/x"), uri("//h:1/x")
+    assert_equal URI("amqp:/x"), uri("/x")
+    assert_equal URI("amqp:"), uri("//")
+    assert_equal URI("amqp:"), uri("")
+    assert_equal URI("amqp://[::1]"), uri("//[::1]")
+
+    # Schemeless URI -> amqp, no re-parse for ambiguous case of path only
+    assert_equal URI("amqp:x"), uri(URI("x"))
+    assert_equal URI("amqp:/x"), uri(URI("/x"))
+
+    # Pass-through
+    u = uri('')
+    assert_same u, uri(u)
+  end
+
+  # Proton::uri non-standard shortcuts
+  def test_shortcut
+    assert_equal URI("amqp://u:p@h:1/x"), uri("u:p@h:1/x")
+    assert_equal URI("amqp://h:1"), uri("h:1")
+    assert_equal URI("amqp://h"), uri("h")
+    assert_equal URI("amqp://h"), uri("h:")
+    assert_equal URI("amqp://:1"), uri(":1")
+    assert_equal URI("amqp://[::1:2]:1"), uri("[::1:2]:1")
+    assert_equal URI("amqp://[::1:2]"), uri("[::1:2]")
+  end
+
+  def test_error
+    assert_raises(::ArgumentError) { uri(nil) }
+    assert_raises(URI::BadURIError) { uri(URI("http:x")) } # Don't re-parse a URI with wrong scheme
+    assert_raises(URI::InvalidURIError) { uri("x:y:z") } # Nonsense
+    assert_raises(URI::InvalidURIError) { uri("amqp://[foobar]") } # Bad host
   end
 
 end


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org