Подтвердить что ты не робот

Как я могу надежно получить фактический URL-адрес, даже если в пути есть процентные части?

IIS и ASP.NET(MVC) имеют некоторые сбои при работе с URL-адресами с% -encoding в пути (а не в строке запроса; строка запроса Это хорошо). Как я могу обойти это? например, как я могу получить фактический URL-адрес, который был запрошен?

Например, если я перейду к /x%3Fa%3Db и (отдельно) к /x?a=b - оба из них сообщают .Request.Url как /x?a=b - потому что закодированные данные в пути сообщаются неправильно.

4b9b3361

Ответ 1

Как я это сделал, это посмотреть на основные серверные переменные; переменная URL содержит декодированное значение; переменная QUERY_STRING содержит запрограммированный запрос. Мы не можем просто вызывать кодировку в части URL, потому что она также содержит символ orignal / и т.д. В их исходной форме - если мы слепо кодируем всю вещь, мы получим ненужные значения %2f; однако, может разделить его и выявить проблемные случаи:

private static readonly Regex simpleUrlPath = new Regex("^[-a-zA-Z0-9_/]*$", RegexOptions.Compiled);
private static readonly char[] segmentsSplitChars = { '/' };
// ^^^ avoids lots of gen-0 arrays being created when calling .Split
public static Uri GetRealUrl(this HttpRequest request)
{
    if (request == null) throw new ArgumentNullException("request");
    var baseUri = request.Url; // use this primarily to avoid needing to process the protocol / authority
    try
    {
        var vars = request.ServerVariables;
        var url = vars["URL"];
        if (string.IsNullOrEmpty(url) || simpleUrlPath.IsMatch(url)) return baseUri; // nothing to do - looks simple enough even for IIS

        var query = vars["QUERY_STRING"];
        // here the thing: url contains *decoded* values; query contains *encoded* values

        // loop over the segments, encoding each separately
        var sb = new StringBuilder(url.Length * 2); // allow double to be pessimistic; we already expect trouble
        var segments = url.Split(segmentsSplitChars);
        foreach (var segment in segments)
        {
            if (segment.Length == 0)
            {
                if(sb.Length != 0) sb.Append('/');
            }
            else if (simpleUrlPath.IsMatch(segment))
            {
                sb.Append('/').Append(segment);
            }
            else
            {
                sb.Append('/').Append(HttpUtility.UrlEncode(segment));
            }
        }
        if (!string.IsNullOrEmpty(query)) sb.Append('?').Append(query); // query is fine; nothing needing
        return new Uri(baseUri, sb.ToString());
    }
    catch (Exception ex)
    { // if something unexpected happens, default to the broken ASP.NET handling
        GlobalApplication.LogException(ex);
        return baseUri;
    }
}