Fixing #17526: Escape "/" in content identities

--HG--
branch : 1.x
This commit is contained in:
Suha Can
2011-03-29 14:18:35 -07:00
parent f2586d06d2
commit fa44ab37fd
3 changed files with 133 additions and 7 deletions

View File

@@ -0,0 +1,35 @@
using System;
using NUnit.Framework;
using Orchard.ContentManagement;
namespace Orchard.Tests.ContentManagement {
[TestFixture]
public class ContentIdentityTests {
[Test]
public void ContentIdentityParsesIdentities() {
var identity1 = new ContentIdentity("/foo=bar");
Assert.That(identity1.Get("foo"), Is.EqualTo("bar"));
var identity2 = new ContentIdentity("/foo=");
Assert.That(identity2.Get("foo"), Is.EqualTo(String.Empty));
var identity3 = new ContentIdentity("foo");
Assert.That(identity3.Get("foo"), Is.Null);
}
[Test]
public void ContentIdentitiesAreEncodedWhenOutput() {
var identity1 = new ContentIdentity("/foo=bar");
Assert.That(identity1.ToString(), Is.EqualTo("/foo=bar"));
var identity2 = new ContentIdentity(@"/foo=bar/abaz=quux\/fr\\ed=foo/yarg=yiu=foo");
Assert.That(identity2.Get("foo"), Is.EqualTo("bar"));
Assert.That(identity2.Get("abaz"), Is.EqualTo(@"quux/fr\ed=foo"));
Assert.That(identity2.Get("yarg"), Is.EqualTo("yiu=foo"));
Assert.That(identity2.ToString(), Is.EqualTo(@"/foo=bar/abaz=quux\/fr\\ed=foo/yarg=yiu=foo"));
}
}
}

View File

@@ -165,9 +165,10 @@
<Compile Include="Commands\CommandHandlerDescriptorBuilderTests.cs" />
<Compile Include="Commands\CommandHandlerTests.cs" />
<Compile Include="Commands\CommandManagerTests.cs" />
<Compile Include="ContentManagement\ContentQueryTests.cs">
<Compile Include="ContentManagement\ContentIdentityTests.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ContentManagement\ContentQueryTests.cs" />
<Compile Include="ContentManagement\DefaultContentManagerTests.cs">
<SubType>Code</SubType>
</Compile>

View File

@@ -14,11 +14,11 @@ namespace Orchard.ContentManagement {
public ContentIdentity(string identity) {
_dictionary = new Dictionary<string, string>();
if (!String.IsNullOrEmpty(identity)) {
var identityEntries = identity.Split(new[] {"/"}, StringSplitOptions.RemoveEmptyEntries);
foreach (var token in identityEntries) {
var kv = token.Split(new[] {"="}, StringSplitOptions.None);
if (kv.Length == 2) {
_dictionary.Add(kv[0], kv[1]);
var identityEntries = GetIdentityEntries(identity);
foreach (var identityEntry in identityEntries) {
var keyValuePair = GetIdentityKeyValue(identityEntry);
if (keyValuePair != null) {
_dictionary.Add(keyValuePair.Value.Key, UnencodeIdentityValue(keyValuePair.Value.Value));
}
}
}
@@ -40,11 +40,101 @@ namespace Orchard.ContentManagement {
public override string ToString() {
var stringBuilder = new StringBuilder();
foreach (var key in _dictionary.Keys) {
stringBuilder.Append("/" + key + "=" + _dictionary[key]);
var escapedIdentity = EncodeIdentityValue(_dictionary[key]);
stringBuilder.Append("/" + key + "=" + escapedIdentity);
}
return stringBuilder.ToString();
}
private static string EncodeIdentityValue(string identityValue) {
var stringBuilder = new StringBuilder();
foreach (var ch in identityValue.ToCharArray()) {
switch (ch) {
case '\\':
stringBuilder.Append('\\');
stringBuilder.Append('\\');
break;
case '/':
stringBuilder.Append('\\');
stringBuilder.Append('/');
break;
default:
stringBuilder.Append(ch);
break;
}
}
return stringBuilder.ToString();
}
private static string UnencodeIdentityValue(string identityValue) {
var stringBuilder = new StringBuilder();
var identityChars = identityValue.ToCharArray();
var length = identityChars.Length;
for (int i = 0; i < length; i++) {
switch (identityChars[i]) {
case '\\':
if (i + 1 < length) {
if (identityChars[i + 1] == '\\') {
stringBuilder.Append('\\');
i++;
}
}
else {
stringBuilder.Append('\\');
}
break;
default:
stringBuilder.Append(identityChars[i]);
break;
}
}
return stringBuilder.ToString();
}
private static IEnumerable<string> GetIdentityEntries(string identity) {
var identityEntries = new List<string>();
var stringBuilder = new StringBuilder();
var escaping = false;
foreach (var ch in identity.ToCharArray()) {
if (escaping) {
stringBuilder.Append(ch);
escaping = false;
}
else {
if (ch == '/') {
if (stringBuilder.Length > 0) {
identityEntries.Add(stringBuilder.ToString());
stringBuilder.Clear();
}
stringBuilder.Append(ch);
}
else {
if (ch == '\\') {
escaping = true;
}
stringBuilder.Append(ch);
}
}
}
identityEntries.Add(stringBuilder.ToString());
return identityEntries;
}
private static KeyValuePair<string, string>? GetIdentityKeyValue(string identityEntry) {
if (String.IsNullOrWhiteSpace(identityEntry)) return null;
if (!identityEntry.StartsWith("/")) return null;
var indexOfEquals = identityEntry.IndexOf("=");
if (indexOfEquals < 0) return null;
var key = identityEntry.Substring(1, indexOfEquals - 1);
var value = identityEntry.Substring(indexOfEquals + 1);
return new KeyValuePair<string, string>(key, value);
}
public class ContentIdentityEqualityComparer : IEqualityComparer<ContentIdentity> {
public bool Equals(ContentIdentity contentIdentity1, ContentIdentity contentIdentity2) {
if (contentIdentity1._dictionary.Keys.Count != contentIdentity2._dictionary.Keys.Count)