Adding the ability to list LB protocols
diff --git a/rackspace/lb/v1/lbs/fixtures.go b/rackspace/lb/v1/lbs/fixtures.go
index 5178eee..007fa15 100644
--- a/rackspace/lb/v1/lbs/fixtures.go
+++ b/rackspace/lb/v1/lbs/fixtures.go
@@ -256,3 +256,96 @@
 		w.WriteHeader(http.StatusOK)
 	})
 }
+
+func mockListProtocolsResponse(t *testing.T) {
+	th.Mux.HandleFunc("/loadbalancers/protocols", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+
+		w.Header().Add("Content-Type", "application/json")
+		w.WriteHeader(http.StatusOK)
+
+		fmt.Fprintf(w, `
+{
+  "protocols": [
+    {
+      "name": "DNS_TCP",
+      "port": 53
+    },
+    {
+      "name": "DNS_UDP",
+      "port": 53
+    },
+    {
+      "name": "FTP",
+      "port": 21
+    },
+    {
+      "name": "HTTP",
+      "port": 80
+    },
+    {
+      "name": "HTTPS",
+      "port": 443
+    },
+    {
+      "name": "IMAPS",
+      "port": 993
+    },
+    {
+      "name": "IMAPv4",
+      "port": 143
+    },
+    {
+      "name": "LDAP",
+      "port": 389
+    },
+    {
+      "name": "LDAPS",
+      "port": 636
+    },
+    {
+      "name": "MYSQL",
+      "port": 3306
+    },
+    {
+      "name": "POP3",
+      "port": 110
+    },
+    {
+      "name": "POP3S",
+      "port": 995
+    },
+    {
+      "name": "SMTP",
+      "port": 25
+    },
+    {
+      "name": "TCP",
+      "port": 0
+    },
+    {
+      "name": "TCP_CLIENT_FIRST",
+      "port": 0
+    },
+    {
+      "name": "UDP",
+      "port": 0
+    },
+    {
+      "name": "UDP_STREAM",
+      "port": 0
+    },
+    {
+      "name": "SFTP",
+      "port": 22
+    },
+    {
+      "name": "TCP_STREAM",
+      "port": 0
+    }
+  ]
+}
+	`)
+	})
+}
diff --git a/rackspace/lb/v1/lbs/requests.go b/rackspace/lb/v1/lbs/requests.go
index 3a9fc25..7c5be06 100644
--- a/rackspace/lb/v1/lbs/requests.go
+++ b/rackspace/lb/v1/lbs/requests.go
@@ -84,7 +84,9 @@
 	Nodes []nodes.Node
 
 	// Required - protocol of the service that is being load balanced.
-	Protocol Protocol
+	// See http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/protocols.html
+	// for a full list of supported protocols.
+	Protocol string
 
 	// Optional - enables or disables Half-Closed support for the load balancer.
 	// Half-Closed support provides the ability for one end of the connection to
@@ -310,7 +312,9 @@
 	Name string
 
 	// Optional - the new protocol you want your load balancer to have.
-	Protocol Protocol
+	// See http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/protocols.html
+	// for a full list of supported protocols.
+	Protocol string
 
 	// Optional - see the HalfClosed field in CreateOpts for more information.
 	HalfClosed enabledState
@@ -380,3 +384,12 @@
 
 	return res
 }
+
+// ListProtocols is the operation responsible for returning a paginated
+// collection of load balancer protocols.
+func ListProtocols(client *gophercloud.ServiceClient) pagination.Pager {
+	url := protocolsURL(client)
+	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
+		return ProtocolPage{pagination.SinglePageBase(r)}
+	})
+}
diff --git a/rackspace/lb/v1/lbs/requests_test.go b/rackspace/lb/v1/lbs/requests_test.go
index add9d06..033cd7f 100644
--- a/rackspace/lb/v1/lbs/requests_test.go
+++ b/rackspace/lb/v1/lbs/requests_test.go
@@ -226,3 +226,35 @@
 	err := Update(client.ServiceClient(), id1, opts).ExtractErr()
 	th.AssertNoErr(t, err)
 }
+
+func TestListProtocols(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	mockListProtocolsResponse(t)
+
+	count := 0
+
+	err := ListProtocols(client.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
+		count++
+		actual, err := ExtractProtocols(page)
+		th.AssertNoErr(t, err)
+
+		expected := []Protocol{
+			Protocol{Name: "DNS_TCP", Port: 53},
+			Protocol{Name: "DNS_UDP", Port: 53},
+			Protocol{Name: "FTP", Port: 21},
+			Protocol{Name: "HTTP", Port: 80},
+			Protocol{Name: "HTTPS", Port: 443},
+			Protocol{Name: "IMAPS", Port: 993},
+			Protocol{Name: "IMAPv4", Port: 143},
+		}
+
+		th.CheckDeepEquals(t, expected[0:7], actual)
+
+		return true, nil
+	})
+
+	th.AssertNoErr(t, err)
+	th.AssertEquals(t, 1, count)
+}
diff --git a/rackspace/lb/v1/lbs/results.go b/rackspace/lb/v1/lbs/results.go
index 359d8e5..d73d823 100644
--- a/rackspace/lb/v1/lbs/results.go
+++ b/rackspace/lb/v1/lbs/results.go
@@ -10,36 +10,13 @@
 )
 
 // Protocol represents the network protocol which the load balancer accepts.
-type Protocol string
+type Protocol struct {
+	// The name of the protocol, e.g. HTTP, LDAP, FTP, etc.
+	Name string
 
-// The constants below represent all the compatible load balancer protocols.
-const (
-	// DNSTCP is a protocol that works with IPv6 and allows your DNS server to
-	// receive traffic using TCP port 53.
-	DNSTCP = "DNS_TCP"
-
-	// DNSUDP is a protocol that works with IPv6 and allows your DNS server to
-	// receive traffic using UDP port 53.
-	DNSUDP = "DNS_UDP"
-
-	// TCP is one of the core protocols of the Internet Protocol Suite. It
-	// provides a reliable, ordered delivery of a stream of bytes from one
-	// program on a computer to another program on another computer. Applications
-	// that require an ordered and reliable delivery of packets use this protocol.
-	TCP = "TCP"
-
-	// TCPCLIENTFIRST is a protocol similar to TCP, but is more efficient when a
-	// client is expected to write the data first.
-	TCPCLIENTFIRST = "TCP_CLIENT_FIRST"
-
-	// UDP provides a datagram service that emphasizes speed over reliability. It
-	// works well with applications that provide security through other measures.
-	UDP = "UDP"
-
-	// UDPSTREAM is a protocol designed to stream media over networks and is
-	// built on top of UDP.
-	UDPSTREAM = "UDP_STREAM"
-)
+	// The port number for the protocol.
+	Port int
+}
 
 // Algorithm defines how traffic should be directed between back-end nodes.
 type Algorithm string
@@ -112,7 +89,9 @@
 
 	// Represents the service protocol being load balanced. See Protocol type for
 	// a list of accepted values.
-	Protocol Protocol
+	// See http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/protocols.html
+	// for a full list of supported protocols.
+	Protocol string
 
 	// Defines how traffic should be directed between back-end nodes. The default
 	// algorithm is RANDOM. See Algorithm type for a list of accepted values.
@@ -264,3 +243,31 @@
 type GetResult struct {
 	commonResult
 }
+
+// ProtocolPage is the page returned by a pager when traversing over a
+// collection of LB protocols.
+type ProtocolPage struct {
+	pagination.SinglePageBase
+}
+
+// IsEmpty checks whether a ProtocolPage struct is empty.
+func (p ProtocolPage) IsEmpty() (bool, error) {
+	is, err := ExtractProtocols(p)
+	if err != nil {
+		return true, nil
+	}
+	return len(is) == 0, nil
+}
+
+// ExtractProtocols accepts a Page struct, specifically a ProtocolPage struct,
+// and extracts the elements into a slice of LoadBalancer structs. In other
+// words, a generic collection is mapped into a relevant slice.
+func ExtractProtocols(page pagination.Page) ([]Protocol, error) {
+	var resp struct {
+		Protocols []Protocol `mapstructure:"protocols" json:"protocols"`
+	}
+
+	err := mapstructure.Decode(page.(ProtocolPage).Body, &resp)
+
+	return resp.Protocols, err
+}
diff --git a/rackspace/lb/v1/lbs/urls.go b/rackspace/lb/v1/lbs/urls.go
index 3df99ab..1de038c 100644
--- a/rackspace/lb/v1/lbs/urls.go
+++ b/rackspace/lb/v1/lbs/urls.go
@@ -6,7 +6,10 @@
 	"github.com/rackspace/gophercloud"
 )
 
-const path = "loadbalancers"
+const (
+	path          = "loadbalancers"
+	protocolsPath = "protocols"
+)
 
 func resourceURL(c *gophercloud.ServiceClient, id int) string {
 	return c.ServiceURL(path, strconv.Itoa(id))
@@ -15,3 +18,7 @@
 func rootURL(c *gophercloud.ServiceClient) string {
 	return c.ServiceURL(path)
 }
+
+func protocolsURL(c *gophercloud.ServiceClient) string {
+	return c.ServiceURL(path, protocolsPath)
+}