Avoid double escaping in PathString

This commit is contained in:
John Luo 2017-04-02 17:32:24 -07:00
parent f264659c95
commit 0da88e0dda
3 changed files with 39 additions and 6 deletions

View File

@ -28,5 +28,20 @@ namespace Microsoft.AspNetCore.Http.Internal
{ {
return c < ValidPathChars.Length && ValidPathChars[c]; return c < ValidPathChars.Length && ValidPathChars[c];
} }
public static bool IsPercentEncodedChar(string str, int index)
{
return index < str.Length - 2
&& str[index] == '%'
&& IsHexadecimalChar(str[index + 1])
&& IsHexadecimalChar(str[index + 2]);
}
public static bool IsHexadecimalChar(char c)
{
return ('0' <= c && c <= '9')
|| ('A' <= c && c <= 'F')
|| ('a' <= c && c <= 'f');
}
} }
} }

View File

@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Http
} }
/// <summary> /// <summary>
/// Provides the path string escaped in a way which is correct for combining into the URI representation. /// Provides the path string escaped in a way which is correct for combining into the URI representation.
/// </summary> /// </summary>
/// <returns>The escaped path value</returns> /// <returns>The escaped path value</returns>
public override string ToString() public override string ToString()
@ -77,9 +77,12 @@ namespace Microsoft.AspNetCore.Http
var start = 0; var start = 0;
var count = 0; var count = 0;
var requiresEscaping = false; var requiresEscaping = false;
for (int i = 0; i < _value.Length; ++i) var i = 0;
while (i < _value.Length)
{ {
if (PathStringHelper.IsValidPathChar(_value[i])) var isPercentEncodedChar = PathStringHelper.IsPercentEncodedChar(_value, i);
if (PathStringHelper.IsValidPathChar(_value[i]) || isPercentEncodedChar)
{ {
if (requiresEscaping) if (requiresEscaping)
{ {
@ -96,7 +99,16 @@ namespace Microsoft.AspNetCore.Http
count = 0; count = 0;
} }
count++; if (isPercentEncodedChar)
{
count += 3;
i += 3;
}
else
{
count++;
i++;
}
} }
else else
{ {
@ -116,6 +128,7 @@ namespace Microsoft.AspNetCore.Http
} }
count++; count++;
i++;
} }
} }
@ -146,6 +159,7 @@ namespace Microsoft.AspNetCore.Http
} }
} }
/// <summary> /// <summary>
/// Returns an PathString given the path as it is escaped in the URI format. The string MUST NOT contain any /// Returns an PathString given the path as it is escaped in the URI format. The string MUST NOT contain any
/// value that is not a path. /// value that is not a path.
@ -279,7 +293,7 @@ namespace Microsoft.AspNetCore.Http
} }
/// <summary> /// <summary>
/// Adds two PathString instances into a combined PathString value. /// Adds two PathString instances into a combined PathString value.
/// </summary> /// </summary>
/// <returns>The combined PathString value</returns> /// <returns>The combined PathString value</returns>
public PathString Add(PathString other) public PathString Add(PathString other)
@ -297,7 +311,7 @@ namespace Microsoft.AspNetCore.Http
} }
/// <summary> /// <summary>
/// Combines a PathString and QueryString into the joined URI formatted string value. /// Combines a PathString and QueryString into the joined URI formatted string value.
/// </summary> /// </summary>
/// <returns>The joined URI formatted string value</returns> /// <returns>The joined URI formatted string value</returns>
public string Add(QueryString other) public string Add(QueryString other)

View File

@ -195,6 +195,10 @@ namespace Microsoft.AspNetCore.Http
[InlineData("pct-encoding", "/单行道", "/%E5%8D%95%E8%A1%8C%E9%81%93")] [InlineData("pct-encoding", "/单行道", "/%E5%8D%95%E8%A1%8C%E9%81%93")]
[InlineData("mixed1", "/index/单行道=(x*y)[abc]", "/index/%E5%8D%95%E8%A1%8C%E9%81%93=(x*y)%5Babc%5D")] [InlineData("mixed1", "/index/单行道=(x*y)[abc]", "/index/%E5%8D%95%E8%A1%8C%E9%81%93=(x*y)%5Babc%5D")]
[InlineData("mixed2", "/index/单行道=(x*y)[abc]_", "/index/%E5%8D%95%E8%A1%8C%E9%81%93=(x*y)%5Babc%5D_")] [InlineData("mixed2", "/index/单行道=(x*y)[abc]_", "/index/%E5%8D%95%E8%A1%8C%E9%81%93=(x*y)%5Babc%5D_")]
[InlineData("encoded", "/http%3a%2f%2f[foo]%3A5000/", "/http%3a%2f%2f%5Bfoo%5D%3A5000/")]
[InlineData("encoded", "/http%3a%2f%2f[foo]%3A5000/%", "/http%3a%2f%2f%5Bfoo%5D%3A5000/%25")]
[InlineData("encoded", "/http%3a%2f%2f[foo]%3A5000/%2", "/http%3a%2f%2f%5Bfoo%5D%3A5000/%252")]
[InlineData("encoded", "/http%3a%2f%2f[foo]%3A5000/%2F", "/http%3a%2f%2f%5Bfoo%5D%3A5000/%2F")]
public void ToUriComponentEscapeCorrectly(string category, string input, string expected) public void ToUriComponentEscapeCorrectly(string category, string input, string expected)
{ {
var path = new PathString(input); var path = new PathString(input);