qpid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From acon...@apache.org
Subject [1/2] qpid-proton git commit: PROTON-827: go binding - use net/url.URL, error handling.
Date Tue, 03 Mar 2015 05:28:45 GMT
Repository: qpid-proton
Updated Branches:
  refs/heads/master a0edd8dff -> 84bea2403


PROTON-827: go binding - use net/url.URL, error handling.

Replaced the proton.Url with the standard net/url.URL.
We still use the proton URL parser because it is much more forgiving and allows abbreviations
that the Go URL parser does not. However the result is stored in a net/url.URL.


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

Branch: refs/heads/master
Commit: 5d8030faa2ecf87a2328c2aa572856cb64b626e3
Parents: a0edd8d
Author: Alan Conway <aconway@redhat.com>
Authored: Mon Mar 2 16:57:55 2015 -0500
Committer: Alan Conway <aconway@redhat.com>
Committed: Mon Mar 2 16:57:55 2015 -0500

----------------------------------------------------------------------
 .../bindings/go/src/apache.org/proton/error.go  |  82 +++++++++++
 .../bindings/go/src/apache.org/proton/url.go    | 146 +++++--------------
 .../go/src/apache.org/proton/url_test.go        | 125 +++-------------
 3 files changed, 138 insertions(+), 215 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5d8030fa/proton-c/bindings/go/src/apache.org/proton/error.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/apache.org/proton/error.go b/proton-c/bindings/go/src/apache.org/proton/error.go
new file mode 100644
index 0000000..178303e
--- /dev/null
+++ b/proton-c/bindings/go/src/apache.org/proton/error.go
@@ -0,0 +1,82 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+package proton
+
+// #include <proton/error.h>
+import "C"
+
+import (
+	"fmt"
+)
+
+// errorCode is an error code returned by proton C.
+type errorCode int
+
+const (
+	errEOS         errorCode = C.PN_EOS
+	errError                 = C.PN_ERR
+	errOverflow              = C.PN_OVERFLOW
+	errUnderflow             = C.PN_UNDERFLOW
+	errState                 = C.PN_STATE_ERR
+	errArgument              = C.PN_ARG_ERR
+	errTimeout               = C.PN_TIMEOUT
+	errInterrupted           = C.PN_INTR
+	errInProgress            = C.PN_INPROGRESS
+)
+
+// String gives a brief description of an errorCode.
+func (code errorCode) String() string {
+	switch code {
+	case errEOS:
+		return "end of data"
+	case errError:
+		return "error"
+	case errOverflow:
+		return "overflow"
+	case errUnderflow:
+		return "underflow"
+	case errState:
+		return "bad state"
+	case errArgument:
+		return "invalid argument"
+	case errTimeout:
+		return "timeout"
+	case errInterrupted:
+		return "interrupted"
+	case errInProgress:
+		return "in progress"
+	}
+	return fmt.Sprintf("invalid error code %d", code)
+}
+
+// An errorCode can be used as an error
+func (code errorCode) Error() string {
+	return fmt.Sprintf("proton: %v", code)
+}
+
+// errorf formats an error message with a proton: prefix.
+func errorf(format string, a ...interface{}) error {
+	return fmt.Errorf("proton: %v", fmt.Sprintf(format, a...))
+}
+
+// errorf2 formats an error message with a proton: prefix and an inner error message.
+func errorf2(err error, format string, a ...interface{}) error {
+	return fmt.Errorf("proton: %v: %v", fmt.Sprintf(format, a...), err)
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5d8030fa/proton-c/bindings/go/src/apache.org/proton/url.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/apache.org/proton/url.go b/proton-c/bindings/go/src/apache.org/proton/url.go
index 9c76b7d..44ef4ba 100644
--- a/proton-c/bindings/go/src/apache.org/proton/url.go
+++ b/proton-c/bindings/go/src/apache.org/proton/url.go
@@ -34,135 +34,63 @@ inline void	set(pn_url_t *url, setter_fn s, const char* value) {
 import "C"
 
 import (
-	"fmt"
 	"net"
+	"net/url"
 	"unsafe"
 )
 
-// Url holds the fields of a parsed AMQP URL.
-//
-// An AMQP URL contains information
-// to connect to a server (like any URL) and a path string that is interpreted
-// by the remote server to identify an AMQP node such as a queue or topic.
-//
-// The fields are:
-//
-//  Scheme: "amqp" or "amqps" for AMQP over SSL
-//  Username: user name for authentication
-//  Password: password for authentication
-//  Host: Host address, can be a DNS name or an IP address literal (v4 or v6)
-//  Port: Note this is a string, not a number. It an be a numeric value like "5672" or a
service name like "amqp"
-//  Path: Interpeted by the remote end as an AMQP node address.
-//  PortInt: int value of port, set after calling Validate()
-//
-// A URL string has the form "scheme://username:password@host:port/path".
-// Partial URLs such as "host", "host:port", ":port" or "host/path" are allowed.
-//
-type Url struct {
-	Scheme, Username, Password, Host, Port, Path string
-	PortInt                                      int
-}
-
-// urlFromC creates a Url and copies the fields from the C pn_url_t pnUrl
-func urlFromC(pnUrl *C.pn_url_t) Url {
-	return Url{
-		C.GoString(C.pn_url_get_scheme(pnUrl)),
-		C.GoString(C.pn_url_get_username(pnUrl)),
-		C.GoString(C.pn_url_get_password(pnUrl)),
-		C.GoString(C.pn_url_get_host(pnUrl)),
-		C.GoString(C.pn_url_get_port(pnUrl)),
-		C.GoString(C.pn_url_get_path(pnUrl)),
-		0,
-	}
-}
-
-// ParseUrl parses a URL string and returns a Url and an error if it is not valid.
-//
-// For a partial URL string, missing components will be filled in with default values.
-//
-func ParseUrl(s string) (u Url, err error) {
-	u, err = ParseUrlRaw(s)
-	if err == nil {
-		err = u.Validate()
-	}
-	if err != nil {
-		return Url{}, err
-	}
-	return
-}
+const (
+	AMQP  string = "amqp"
+	AMQPS        = "amqps"
+)
 
-// ParseUrlRaw parses a URL string and returns a Url and an error if it is not valid.
+// ParseUrl parses an AMQP URL string and returns a net/url.Url.
 //
-// For a partial URL string, missing components will be empty strings "" in the Url struct.
-// Error checking is limited, more errors are checked in Validate()
+// It is more forgiving than net/url.Parse and allows most of the parts of the
+// URL to be missing, assuming AMQP defaults.
 //
-func ParseUrlRaw(s string) (u Url, err error) {
+func ParseURL(s string) (u *url.URL, err error) {
 	cstr := C.CString(s)
 	defer C.free(unsafe.Pointer(cstr))
 	pnUrl := C.pn_url_parse(cstr)
 	if pnUrl == nil {
-		return Url{}, fmt.Errorf("proton: Invalid Url '%v'", s)
+		return nil, errorf("bad URL %#v", s)
 	}
 	defer C.pn_url_free(pnUrl)
-	u = urlFromC(pnUrl)
-	return
-}
 
-// newPnUrl creates a C pn_url_t and populate it with the fields from url.
-func newPnUrl(url Url) *C.pn_url_t {
-	pnUrl := C.pn_url()
-	set := func(setter unsafe.Pointer, value string) {
-		if value != "" {
-			cstr := C.CString(value)
-			defer C.free(unsafe.Pointer(cstr))
-			C.set(pnUrl, C.setter_fn(setter), cstr)
-		}
-	}
-	set(C.pn_url_set_scheme, url.Scheme)
-	set(C.pn_url_set_username, url.Username)
-	set(C.pn_url_set_password, url.Password)
-	set(C.pn_url_set_host, url.Host)
-	set(C.pn_url_set_port, url.Port)
-	set(C.pn_url_set_path, url.Path)
-	return pnUrl
-}
+	scheme := C.GoString(C.pn_url_get_scheme(pnUrl))
+	username := C.GoString(C.pn_url_get_username(pnUrl))
+	password := C.GoString(C.pn_url_get_password(pnUrl))
+	host := C.GoString(C.pn_url_get_host(pnUrl))
+	port := C.GoString(C.pn_url_get_port(pnUrl))
+	path := C.GoString(C.pn_url_get_path(pnUrl))
 
-// String generates a representation of the Url.
-func (u Url) String() string {
-	pnUrl := newPnUrl(u)
-	defer C.pn_url_free(pnUrl)
-	return C.GoString(C.pn_url_str(pnUrl))
-}
-
-// Validate supplies defaults for Scheme, Host and Port and does additional error checks.
-//
-// Fills in the value of PortInt from Port.
-//
-func (u *Url) Validate() error {
-	if u.Scheme == "" {
-		u.Scheme = "amqp"
+	if err != nil {
+		return nil, errorf2(err, "bad URL %#v", s)
 	}
-	if u.Host == "" {
-		u.Host = "127.0.0.1"
+	if scheme == "" {
+		scheme = AMQP
 	}
-	if u.Port == "" {
-		if u.Scheme == "amqps" {
-			u.Port = "amqps"
+	if port == "" {
+		if scheme == AMQPS {
+			port = AMQPS
 		} else {
-			u.Port = "amqp"
+			port = AMQP
 		}
 	}
-	port, err := net.LookupPort("", u.Port)
-	u.PortInt = port
-	if u.PortInt == 0 || err != nil {
-		return fmt.Errorf("proton: Invalid Url '%v' (bad port '%v')", u, u.Port)
+	var user *url.Userinfo
+	if password != "" {
+		user = url.UserPassword(username, password)
+	} else if username != "" {
+		user = url.User(username)
+	}
+
+	u = &url.URL{
+		Scheme: scheme,
+		User:   user,
+		Host:   net.JoinHostPort(host, port),
+		Path:   path,
 	}
-	return nil
-}
 
-// Equals tests for equality between two Urls.
-func (u Url) Equals(x Url) bool {
-	return (&u == &x) || (u.Scheme == x.Scheme &&
-		u.Username == x.Username && u.Password == x.Password &&
-		u.Host == x.Host && u.Port == x.Port && u.Path == x.Path)
+	return u, nil
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5d8030fa/proton-c/bindings/go/src/apache.org/proton/url_test.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/apache.org/proton/url_test.go b/proton-c/bindings/go/src/apache.org/proton/url_test.go
index 3174769..7315511 100644
--- a/proton-c/bindings/go/src/apache.org/proton/url_test.go
+++ b/proton-c/bindings/go/src/apache.org/proton/url_test.go
@@ -21,118 +21,31 @@ package proton
 
 import (
 	"fmt"
-	"reflect"
-	"testing"
 )
 
-func checkEqual(t *testing.T, a, b interface{}) string {
-	if !reflect.DeepEqual(a, b) {
-		return fmt.Sprintf("%#v != %#v", a, b)
-	}
-	return ""
-}
-
-// Verify URL matches fields, check round trip compose/parse
-func checkUrl(t *testing.T, u Url, scheme, username, password, host, port, path string) string
{
-	if msg := checkEqual(t, u.Scheme, scheme); msg != "" {
-		return msg
-	}
-	if msg := checkEqual(t, u.Username, username); msg != "" {
-		return msg
-	}
-	if msg := checkEqual(t, u.Password, password); msg != "" {
-		return msg
-	}
-	if msg := checkEqual(t, u.Host, host); msg != "" {
-		return msg
-	}
-	if msg := checkEqual(t, u.Port, port); msg != "" {
-		return msg
-	}
-	if msg := checkEqual(t, u.Path, path); msg != "" {
-		return msg
-	}
-	u2, _ := ParseUrlRaw(u.String()) // Round trip compose/parse
-	if msg := checkEqual(t, u.String(), u2.String()); msg != "" {
-		return msg
-	}
-	return ""
-}
-
-func TestParse(t *testing.T) {
-	s := "amqp://me:secret@myhost:1234/foobar"
-	u, _ := ParseUrl(s)
-	if msg := checkEqual(t, u.String(), s); msg != "" {
-		t.Error(msg)
-	}
-	if msg := checkUrl(t, u, "amqp", "me", "secret", "myhost", "1234", "foobar"); msg != ""
{
-		t.Error(msg)
-	}
-}
-
-// Test URL's with missing elements.
-func TestMissing(t *testing.T) {
-	u := Url{Username: "me", Password: "secret", Host: "myhost", Path: "foobar"}
-	if msg := checkUrl(t, u, "", "me", "secret", "myhost", "", "foobar"); msg != "" {
-		t.Error(msg)
-	}
-	if msg := checkEqual(t, "me:secret@myhost/foobar", u.String()); msg != "" {
-		t.Error(msg)
-	}
-	u, _ = ParseUrlRaw("myhost/")
-	if msg := checkUrl(t, u, "", "", "", "myhost", "", ""); msg != "" {
-		t.Error(msg)
-	}
-}
-
-func TestDefaults(t *testing.T) {
-	for pre, post := range map[string]string{
-		"foo":      "amqp://foo:amqp",
-		":1234":    "amqp://127.0.0.1:1234",
-		"/path":    "amqp://127.0.0.1:amqp/path",
-		"amqp://":  "amqp://127.0.0.1:amqp",
-		"amqps://": "amqps://127.0.0.1:amqps",
+func ExampleParseURL() {
+	for _, s := range []string{
+		"amqp://username:password@host:1234/path",
+		"host:1234",
+		"host",
+		":1234",
+		"host/path",
+		"amqps://host",
+		"",
 	} {
-		url, _ := ParseUrl(pre)
-		if msg := checkEqual(t, url.String(), post); msg != "" {
-			t.Error(msg)
+		u, err := ParseURL(s)
+		if err != nil {
+			fmt.Println(err)
+		} else {
+			fmt.Println(u)
 		}
 	}
-}
-
-func ExampleParseUrl_1parse() {
-	url, _ := ParseUrl("amqp://username:password@host:1234/path")
-	fmt.Printf("%#v\n", url) // Show the struct fields.
-	fmt.Println(url)         // url.String() shows the string form
 	// Output:
-	// proton.Url{Scheme:"amqp", Username:"username", Password:"password", Host:"host", Port:"1234",
Path:"path", PortInt:1234}
 	// amqp://username:password@host:1234/path
-}
-
-func ExampleParseUrl_2defaults() {
-	// Default settings for partial URLs
-	url, _ := ParseUrl(":5672")
-	fmt.Println(url)
-	url, _ = ParseUrl("host/path")
-	fmt.Println(url)
-	url, _ = ParseUrl("amqp://")
-	fmt.Printf("%v port=%v\n", url, url.PortInt)
-	url, _ = ParseUrl("amqps://")
-	fmt.Printf("%v port=%v\n", url, url.PortInt)
-	// Output:
-	// amqp://127.0.0.1:5672
+	// amqp://host:1234
+	// amqp://host:amqp
+	// amqp://:1234
 	// amqp://host:amqp/path
-	// amqp://127.0.0.1:amqp port=5672
-	// amqps://127.0.0.1:amqps port=5671
-}
-
-func ExampleParseUrl_3invalid() {
-	// Invalid URLs
-	_, err := ParseUrl("")
-	fmt.Println(err)
-	_, err = ParseUrl(":foobar")
-	fmt.Println(err)
-	// Output:
-	// proton: Invalid Url ''
-	// proton: Invalid Url 'amqp://127.0.0.1:foobar' (bad port 'foobar')
+	// amqps://host:amqps
+	// proton: bad URL ""
 }


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


Mime
View raw message