Skip to content

Commit 99d31e5

Browse files
author
Emile Joubert
committed
Merged bug24453 into default
2 parents 542e4f9 + 25de44d commit 99d31e5

File tree

16 files changed

+294
-52
lines changed

16 files changed

+294
-52
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ ensure-deliverables: rabbit-vsn
3434
file ${RELEASE_DIR}/${NAME_VSN}.msm
3535

3636
ensure-prerequisites: rabbit-vsn
37-
dpkg -L htmldoc plotutils transfig graphviz docbook-utils > /dev/null
37+
[ -f "/etc/debian_version" ] && dpkg -L htmldoc plotutils transfig graphviz docbook-utils || true > /dev/null
3838

3939
ensure-release-dir: rabbit-vsn
4040
touch ${RELEASE_DIR}/

docs/wikipages/data.ApiOverview.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ of the shell environment variable scanned.)
117117

118118
** Connecting to a broker
119119

120-
The following code connects to an AMQP broker:
120+
The following two code snippets connect to an AMQP broker:
121121

122122
@code java
123123
ConnectionFactory factory = new ConnectionFactory();
@@ -129,6 +129,16 @@ The following code connects to an AMQP broker:
129129
factory.Port = AmqpTcpEndpoint.UseDefaultPort;
130130
IConnection conn = factory.CreateConnection();
131131

132+
@code java
133+
ConnectionFactory factory = new ConnectionFactory();
134+
factory.Uri = "amqp://user:pass@hostName:port/vhost";
135+
IConnection conn = factory.CreateConnection();
136+
137+
Since the .NET client uses a stricter interpretation of the AMQP URI
138+
spec than the other clients, care must be taken when using URIs. In
139+
particular, the host part must not be omitted and virtual hosts with
140+
empty names are not addressable.
141+
132142
All factory properties have default values. The default value for a property will be used if the property remains unassigned prior to creating a connection:
133143
- username: [code "guest"]
134144
- password: [code "guest"]

projects/client/RabbitMQ.Client/src/client/api/ConnectionFactory.cs

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
using System;
4242
using System.IO;
4343
using System.Net;
44+
using System.Net.Security;
4445
using System.Net.Sockets;
4546
using System.Collections;
4647

@@ -76,17 +77,24 @@ namespace RabbitMQ.Client
7677
/// conn.Close(Constants.ReplySuccess, "Closing the connection");
7778
///</code></example>
7879
///<para>
79-
/// Please see also the API overview and tutorial in the User Guide.
80+
///The same example, written more compactly with AMQP URIs:
8081
///</para>
82+
///<example><code>
83+
/// ConnectionFactory factory = new ConnectionFactory();
84+
/// factory.Uri = "amqp://localhost";
85+
/// IConnection conn = factory.CreateConnection();
86+
/// ...
87+
///</code></example>
8188
///<para>
82-
/// Some of the static methods described below take, as a
83-
/// convenience, a System.Uri instance representing an AMQP server
84-
/// address. The use of Uri here is not standardised - Uri is
85-
/// simply a convenient container for internet-address-like
86-
/// components. In particular, the Uri "Scheme" property is
87-
/// ignored: only the "Host" and "Port" properties are extracted.
89+
/// Please see also the API overview and tutorial in the User Guide.
8890
///</para>
89-
///</remarks>
91+
///<para>
92+
///Note that the Uri property takes a string representation of an
93+
///AMQP URI. Omitted URI parts will take default values. The
94+
///host part of the URI cannot be omitted and URIs of the form
95+
///"amqp://foo/" (note the trailling slash) also represent the
96+
///default virtual host. The latter issue means that virtual
97+
///hosts with an empty name are not addressable. </para></remarks>
9098
public class ConnectionFactory
9199
{
92100
/// <summary>Default user name (value: "guest")</summary>
@@ -167,21 +175,14 @@ public AmqpTcpEndpoint Endpoint
167175
}
168176
}
169177

170-
public String Address
178+
public Uri uri
171179
{
172-
get
173-
{
174-
String result = HostName;
175-
if(Port != AmqpTcpEndpoint.UseDefaultPort)
176-
{
177-
result += (":" + Port);
178-
}
179-
return result;
180-
}
181-
set
182-
{
183-
Endpoint = AmqpTcpEndpoint.Parse(Protocol, value);
184-
}
180+
set { SetUri(value); }
181+
}
182+
183+
public String Uri
184+
{
185+
set { SetUri(new Uri(value, UriKind.Absolute)); }
185186
}
186187

187188
///<summary>Construct a fresh instance, with all fields set to
@@ -332,5 +333,61 @@ public AuthMechanismFactory AuthMechanismFactory(string[] mechs) {
332333

333334
return null;
334335
}
336+
337+
338+
private void SetUri(Uri uri)
339+
{
340+
Endpoint = new AmqpTcpEndpoint();
341+
342+
if ("amqp".CompareTo(uri.Scheme.ToLower()) == 0) {
343+
// nothing special to do
344+
} else if ("amqps".CompareTo(uri.Scheme.ToLower()) == 0) {
345+
Ssl.Enabled = true;
346+
Ssl.AcceptablePolicyErrors =
347+
SslPolicyErrors.RemoteCertificateNameMismatch;
348+
Port = AmqpTcpEndpoint.DefaultAmqpSslPort;
349+
} else {
350+
throw new ArgumentException("Wrong scheme in AMQP URI: " +
351+
uri.Scheme);
352+
}
353+
string host = uri.Host;
354+
if (!String.IsNullOrEmpty(host)) {
355+
HostName = host;
356+
}
357+
Ssl.ServerName = HostName;
358+
359+
int port = uri.Port;
360+
if (port != -1) {
361+
Port = port;
362+
}
363+
364+
string userInfo = uri.UserInfo;
365+
if (!String.IsNullOrEmpty(userInfo)) {
366+
string[] userPass = userInfo.Split(':');
367+
if (userPass.Length > 2) {
368+
throw new ArgumentException("Bad user info in AMQP " +
369+
"URI: " + userInfo);
370+
}
371+
UserName = UriDecode(userPass[0]);
372+
if (userPass.Length == 2) {
373+
Password = UriDecode(userPass[1]);
374+
}
375+
}
376+
377+
/* C# automatically changes URIs into a canonical form
378+
that has at least the path segment "/". */
379+
if (uri.Segments.Length > 2) {
380+
throw new ArgumentException("Multiple segments in " +
381+
"path of AMQP URI: " +
382+
String.Join(", ", uri.Segments));
383+
} else if (uri.Segments.Length == 2) {
384+
VirtualHost = UriDecode(uri.Segments[1]);
385+
}
386+
}
387+
388+
//<summary>Unescape a string, protecting '+'.</summary>
389+
private string UriDecode(string uri) {
390+
return System.Uri.UnescapeDataString(uri.Replace("+", "%2B"));
391+
}
335392
}
336393
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// This source code is dual-licensed under the Apache License, version
2+
// 2.0, and the Mozilla Public License, version 1.1.
3+
//
4+
// The APL v2.0:
5+
//
6+
//---------------------------------------------------------------------------
7+
// Copyright (C) 2011 VMware, Inc.
8+
//
9+
// Licensed under the Apache License, Version 2.0 (the "License");
10+
// you may not use this file except in compliance with the License.
11+
// You may obtain a copy of the License at
12+
//
13+
// http://www.apache.org/licenses/LICENSE-2.0
14+
//
15+
// Unless required by applicable law or agreed to in writing, software
16+
// distributed under the License is distributed on an "AS IS" BASIS,
17+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
// See the License for the specific language governing permissions and
19+
// limitations under the License.
20+
//---------------------------------------------------------------------------
21+
//
22+
// The MPL v1.1:
23+
//
24+
//---------------------------------------------------------------------------
25+
// The contents of this file are subject to the Mozilla Public License
26+
// Version 1.1 (the "License"); you may not use this file except in
27+
// compliance with the License. You may obtain a copy of the License
28+
// at http://www.mozilla.org/MPL/
29+
//
30+
// Software distributed under the License is distributed on an "AS IS"
31+
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
32+
// the License for the specific language governing rights and
33+
// limitations under the License.
34+
//
35+
// The Original Code is RabbitMQ.
36+
//
37+
// The Initial Developer of the Original Code is VMware, Inc.
38+
// Copyright (c) 2011 VMware, Inc. All rights reserved.
39+
//---------------------------------------------------------------------------
40+
41+
using NUnit.Framework;
42+
using System;
43+
using RabbitMQ.Client;
44+
45+
namespace RabbitMQ.Client.Unit
46+
{
47+
[TestFixture]
48+
public class TestAmqpUri
49+
{
50+
[Test]
51+
public void TestAmqpUriParse()
52+
{
53+
/* From the spec */
54+
ParseSuccess("amqp://user:pass@host:10000/vhost",
55+
"user", "pass", "host", 10000, "vhost");
56+
ParseSuccess("aMQps://user%61:%61pass@host:10000/v%2fhost",
57+
"usera", "apass", "host", 10000, "v/host");
58+
ParseSuccess("amqp://localhost", "guest", "guest", "localhost", 5672, "/");
59+
ParseSuccess("amqp://:@localhost/", "", "", "localhost", 5672, "/");
60+
ParseSuccess("amqp://user@localhost",
61+
"user", "guest", "localhost", 5672, "/");
62+
ParseSuccess("amqp://user:pass@localhost",
63+
"user", "pass", "localhost", 5672, "/");
64+
ParseSuccess("amqp://host", "guest", "guest", "host", 5672, "/");
65+
ParseSuccess("amqp://localhost:10000",
66+
"guest", "guest", "localhost", 10000, "/");
67+
ParseSuccess("amqp://localhost/vhost",
68+
"guest", "guest", "localhost", 5672, "vhost");
69+
ParseSuccess("amqp://host/", "guest", "guest", "host", 5672, "/");
70+
ParseSuccess("amqp://host/%2f",
71+
"guest", "guest", "host", 5672, "/");
72+
ParseSuccess("amqp://[::1]", "guest", "guest",
73+
"[0000:0000:0000:0000:0000:0000:0000:0001]",
74+
5672, "/");
75+
76+
/* Various other success cases */
77+
ParseSuccess("amqp://host:100",
78+
"guest", "guest", "host", 100, "/");
79+
ParseSuccess("amqp://[::1]:100",
80+
"guest", "guest",
81+
"[0000:0000:0000:0000:0000:0000:0000:0001]",
82+
100, "/");
83+
84+
ParseSuccess("amqp://host/blah",
85+
"guest", "guest", "host", 5672, "blah");
86+
ParseSuccess("amqp://host:100/blah",
87+
"guest", "guest", "host", 100, "blah");
88+
ParseSuccess("amqp://localhost:100/blah",
89+
"guest", "guest", "localhost", 100, "blah");
90+
ParseSuccess("amqp://[::1]/blah",
91+
"guest", "guest",
92+
"[0000:0000:0000:0000:0000:0000:0000:0001]",
93+
5672, "blah");
94+
ParseSuccess("amqp://[::1]:100/blah",
95+
"guest", "guest",
96+
"[0000:0000:0000:0000:0000:0000:0000:0001]",
97+
100, "blah");
98+
99+
ParseSuccess("amqp://user:pass@host",
100+
"user", "pass", "host", 5672, "/");
101+
ParseSuccess("amqp://user:pass@host:100",
102+
"user", "pass", "host", 100, "/");
103+
ParseSuccess("amqp://user:pass@localhost:100",
104+
"user", "pass", "localhost", 100, "/");
105+
ParseSuccess("amqp://user:pass@[::1]",
106+
"user", "pass",
107+
"[0000:0000:0000:0000:0000:0000:0000:0001]",
108+
5672, "/");
109+
ParseSuccess("amqp://user:pass@[::1]:100",
110+
"user", "pass",
111+
"[0000:0000:0000:0000:0000:0000:0000:0001]",
112+
100, "/");
113+
114+
/* Various failure cases */
115+
ParseFail("http://www.rabbitmq.com");
116+
ParseFail("amqp://foo:bar:baz");
117+
ParseFail("amqp://foo[::1]");
118+
ParseFail("amqp://foo:[::1]");
119+
ParseFail("amqp://[::1]foo");
120+
ParseFail("amqp://foo:1000xyz");
121+
ParseFail("amqp://foo:1000000");
122+
ParseFail("amqp://foo/bar/baz");
123+
124+
ParseFail("amqp://foo%1");
125+
ParseFail("amqp://foo%1x");
126+
ParseFail("amqp://foo%xy");
127+
}
128+
129+
private void ParseSuccess(string uri, string user, string password,
130+
string host, int port, string vhost)
131+
{
132+
ConnectionFactory cf = new ConnectionFactory();
133+
cf.Uri = uri;
134+
Assert.AreEqual(user, cf.UserName);
135+
Assert.AreEqual(password, cf.Password);
136+
Assert.AreEqual(host, cf.HostName);
137+
Assert.AreEqual(port, cf.Port);
138+
Assert.AreEqual(vhost, cf.VirtualHost);
139+
}
140+
141+
private void ParseFail(string uri)
142+
{
143+
Assert.Throws(
144+
Is.InstanceOf<Exception>(),
145+
delegate {
146+
ConnectionFactory cf = new ConnectionFactory();
147+
cf.Uri = uri;
148+
});
149+
}
150+
}
151+
}

projects/examples/client/AddClient/src/examples/AddClient.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,16 @@ namespace RabbitMQ.Client.Examples {
5050
public class AddClient {
5151
public static int Main(string[] args) {
5252
if (args.Length < 1) {
53-
Console.Error.WriteLine("Usage: AddClient <hostname>[:<portnumber>] [<number> ...]");
53+
Console.Error.WriteLine("Usage: AddClient <uri> [<number> ...]");
5454
Console.Error.WriteLine("RabbitMQ .NET client version "+typeof(IModel).Assembly.GetName().Version.ToString());
55+
Console.Error.WriteLine("Parameters:");
56+
Console.Error.WriteLine(" <uri> = \"amqp://user:pass@host:port/vhost\"");
5557
return 2;
5658
}
5759

5860
ConnectionFactory cf = new ConnectionFactory();
59-
cf.Address = args[0];
60-
61+
cf.Uri = args[0];
62+
6163
using (IConnection conn = cf.CreateConnection()) {
6264
using (IModel ch = conn.CreateModel()) {
6365

projects/examples/client/AddServer/src/examples/AddServer.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,15 @@ namespace RabbitMQ.Client.Examples {
5151
public class AddServer: SimpleRpcServer {
5252
public static int Main(string[] args) {
5353
if (args.Length < 1) {
54-
Console.Error.WriteLine("Usage: AddServer <hostname>[:<portnumber>]");
54+
Console.Error.WriteLine("Usage: AddServer <uri>");
5555
Console.Error.WriteLine("RabbitMQ .NET client version "+typeof(IModel).Assembly.GetName().Version.ToString());
56+
Console.Error.WriteLine("Parameters:");
57+
Console.Error.WriteLine(" <uri> = \"amqp://user:pass@host:port/vhost\"");
5658
return 2;
5759
}
5860

5961
ConnectionFactory cf = new ConnectionFactory();
60-
cf.Address = args[0];
62+
cf.Uri = args[0];
6163
using (IConnection conn = cf.CreateConnection()) {
6264
using (IModel ch = conn.CreateModel()) {
6365
ch.QueueDeclare("AddServer", false, false, false, null);

projects/examples/client/DeclareQueue/src/examples/DeclareQueue.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,10 @@ public static int Main(string[] args) {
7272
if (((args.Length - optionIndex) < 2) ||
7373
(((args.Length - optionIndex) % 2) != 0))
7474
{
75-
Console.Error.WriteLine("Usage: DeclareQueue [<option> ...] <hostname>[:<portnumber>] <queue> [<exchange> <routingkey>] ...");
75+
Console.Error.WriteLine("Usage: DeclareQueue [<option> ...] <uri> <queue> [<exchange> <routingkey>] ...");
7676
Console.Error.WriteLine("RabbitMQ .NET client version "+typeof(IModel).Assembly.GetName().Version.ToString());
77+
Console.Error.WriteLine("Parameters:");
78+
Console.Error.WriteLine(" <uri> = \"amqp://user:pass@host:port/vhost\"");
7779
Console.Error.WriteLine("Available options:");
7880
Console.Error.WriteLine(" /durable declare a durable queue");
7981
Console.Error.WriteLine(" /delete delete after declaring");
@@ -84,7 +86,7 @@ public static int Main(string[] args) {
8486
string serverAddress = args[optionIndex++];
8587
string inputQueueName = args[optionIndex++];
8688
ConnectionFactory cf = new ConnectionFactory();
87-
cf.Address = serverAddress;
89+
cf.Uri = serverAddress;
8890

8991
using (IConnection conn = cf.CreateConnection())
9092
{

projects/examples/client/ExceptionTest/src/examples/ExceptionTest.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,17 @@ public class ExceptionTest {
5252
public static int Main(string[] args) {
5353
try {
5454
if (args.Length < 1) {
55-
Console.Error.WriteLine("Usage: ExceptionTest <hostname>[:<portnumber>]");
55+
Console.Error.WriteLine("Usage: ExceptionTest <uri>");
5656
Console.Error.WriteLine("RabbitMQ .NET client version "+typeof(IModel).Assembly.GetName().Version.ToString());
57+
Console.Error.WriteLine("Parameters:");
58+
Console.Error.WriteLine(" <uri> = \"amqp://user:pass@host:port/vhost\"");
5759
return 2;
5860
}
5961

6062
string serverAddress = args[0];
6163
ConnectionFactory cf = new ConnectionFactory();
62-
cf.Address = serverAddress;
63-
64+
cf.Uri = serverAddress;
65+
6466
using (IConnection conn = cf.CreateConnection())
6567
{
6668
conn.ConnectionShutdown += new ConnectionShutdownEventHandler(First);

0 commit comments

Comments
 (0)