diff --git a/src/mindtouch.dream/dream/XUri.cs b/src/mindtouch.dream/dream/XUri.cs
index cdb3877..924d8eb 100644
--- a/src/mindtouch.dream/dream/XUri.cs
+++ b/src/mindtouch.dream/dream/XUri.cs
@@ -976,6 +976,12 @@ public sealed class XUri : ISerializable {
/// Input uri.
public XUri(Uri uri) : this(uri.OriginalString) { }
+ ///
+ /// Create a new XUri from an existing XUri
+ ///
+ /// Input uri.
+ public XUri(XUri uri) : this(uri.Scheme, uri.User, uri.Password, uri.Host, uri.Port, uri.UsesDefaultPort, uri.Segments, uri.TrailingSlash, uri.Params, uri.Fragment, uri.UsesSegmentDoubleEncoding) { }
+
///
/// Create a new XUri from serialized form.
///
diff --git a/src/tests/DreamMisc/XUri-Test.cs b/src/tests/DreamMisc/XUri-Test.cs
index 2f56cbc..c3619d5 100644
--- a/src/tests/DreamMisc/XUri-Test.cs
+++ b/src/tests/DreamMisc/XUri-Test.cs
@@ -531,6 +531,23 @@ public class XUriTest {
}
}
+ [Test]
+ public void TestXUriFromUriConstruction2() {
+ string[] evilSegments = new string[] {
+
+ // Escaped version of "Iñtërnâtiônàlizætiøn" (should look similar to "Internationalization" but with extended characteres)
+ "I\u00f1t\u00ebrn\u00e2ti\u00f4n\u00e0liz\u00e6ti\u00f8n",
+ "A%4b"
+ };
+ foreach(string evil in evilSegments) {
+ XUri original = new XUri("http://" + evil);
+ XUri fromDecoded = new XUri(original.ToString());
+ XUri uri1 = new XUri(original);
+ XUri uri2 = new XUri(fromDecoded);
+ // just making sure they actually parse
+ }
+ }
+
[Test]
public void Decode_extended_chars1() {
const string before = "F\u00F4\u00F6";