156 lines
5.9 KiB
C#
156 lines
5.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace MontoyaTech.Rest.Net
|
|
{
|
|
/// <summary>
|
|
/// A class to help match route syntaxs against requests.
|
|
/// </summary>
|
|
public class RouteMatcher
|
|
{
|
|
/// <summary>
|
|
/// Check to see if a url matches a given route syntax.
|
|
/// * = any path segment will match
|
|
/// ** = anything from this point forward is accepted
|
|
/// {} = route parameter
|
|
/// ! = must not match
|
|
/// | = logical or
|
|
/// & = logical and
|
|
///
|
|
/// Note:
|
|
/// If route parameter doesn't end with /, then the parameter will be the rest of the url.
|
|
/// Example:
|
|
/// </summary>
|
|
/// <param name="url"></param>
|
|
/// <param name="syntax"></param>
|
|
/// <param name="parameters"></param>
|
|
/// <returns></returns>
|
|
public static bool Matches(string url, string syntax, out string[] arguments)
|
|
{
|
|
//Set the arguments to null, initially.
|
|
arguments = null;
|
|
|
|
//Trim the url and the syntax.
|
|
url = url.Trim();
|
|
syntax = syntax.Trim();
|
|
|
|
//If the url starts with http or https remove that so we just have the path left.
|
|
if (url.StartsWith("http://"))
|
|
{
|
|
url = url.Substring(7);
|
|
url = url.Substring(url.IndexOf('/'));
|
|
}
|
|
else if (url.StartsWith("https://"))
|
|
{
|
|
url = url.Substring(8);
|
|
url = url.Substring(url.IndexOf('/'));
|
|
}
|
|
|
|
//Split the url and the syntax into path segments
|
|
var urlSegments = url.Split('/').Where(segment => segment.Length > 0).Select(segment => segment.Trim()).ToArray();
|
|
var syntaxSegments = syntax.Split('/').Where(segment => segment.Length > 0).Select(segment => segment.Trim()).ToArray();
|
|
|
|
//If we have no url segments, and we have no syntax segments, this is a root match which is fine.
|
|
if (urlSegments.Length == 0 && syntaxSegments.Length == 0)
|
|
return true;
|
|
//If we have no syntax segments this is not a match.
|
|
else if (syntaxSegments.Length == 0)
|
|
return false;
|
|
//If the url has no segments but the syntax is a double wild card then this is a match.
|
|
else if (urlSegments.Length == 0 && syntaxSegments[0] == "**")
|
|
return true;
|
|
//If the url has no segments but the syntax is a wildcard then this is a match.
|
|
else if (urlSegments.Length == 0 && syntaxSegments.Length == 1 && syntaxSegments[0] == "*")
|
|
return true;
|
|
|
|
//Count the number of arguments in the syntax and set it.
|
|
arguments = new string[syntax.Count('{')];
|
|
int argumentIndex = 0;
|
|
|
|
//Check each segment against the url.
|
|
var max = Math.Min(urlSegments.Length, syntaxSegments.Length);
|
|
for (int i = 0; i < max; i++)
|
|
{
|
|
var syntaxSegment = syntaxSegments[i];
|
|
|
|
var urlSegment = urlSegments[i];
|
|
|
|
//If the segments syntax is a double wild card then everything after this is a match.
|
|
if (syntaxSegment == "**")
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
var conditions = new List<string>();
|
|
var builder = new StringBuilder();
|
|
for (int c = 0; c < syntaxSegment.Length; c++)
|
|
{
|
|
if (syntaxSegment[c] == '|' || syntaxSegment[c] == '&')
|
|
{
|
|
conditions.Add(builder.ToString());
|
|
conditions.Add(syntaxSegment[c].ToString());
|
|
builder.Clear();
|
|
}
|
|
else if (syntaxSegment[c] != ' ')
|
|
{
|
|
builder.Append(syntaxSegment[c]);
|
|
}
|
|
}
|
|
|
|
if (builder.Length > 0)
|
|
conditions.Add(builder.ToString());
|
|
|
|
bool match = false;
|
|
foreach (var condition in conditions)
|
|
{
|
|
if (condition == "*")
|
|
{
|
|
match = true;
|
|
}
|
|
else if (condition == "**")
|
|
{
|
|
match = true;
|
|
}
|
|
else if (condition.StartsWith("!") && condition.Substring(1) != urlSegment)
|
|
{
|
|
match = true;
|
|
}
|
|
else if (condition.StartsWith("{") && condition.EndsWith("}"))
|
|
{
|
|
arguments[argumentIndex++] = urlSegment;
|
|
|
|
match = true;
|
|
}
|
|
else if (condition == "&" && !match)
|
|
{
|
|
break;
|
|
}
|
|
else if (condition == "|" && match)
|
|
{
|
|
break;
|
|
}
|
|
else if (condition == urlSegment && condition != "&" && condition != "|")
|
|
{
|
|
match = true;
|
|
}
|
|
}
|
|
|
|
if (!match)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (urlSegments.Length > syntaxSegments.Length)
|
|
return false;
|
|
else if (syntaxSegments.Length > urlSegments.Length)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
}
|