ASP.NET MVC UrlHelper.GenerateUrl исключение: «Не удается использовать ведущий .. для выхода из верхнего каталога» - PullRequest
17 голосов
/ 30 сентября 2010

Я использую модуль перезаписи IIS 7 для перезаписи входящего URL, например:

http://server/year/all

до

http://server/application/controller/year/all

Всеработает нормально, за исключением случаев, когда при обработке переписанного запроса я использую метод MVC UrlHelper.GenerateUrl ():

UrlHelper.GenerateUrl(
   "Assets",
   "Css",
   "Asset",
   new RouteValueDictionary(new { site = site.Name, assetPath = assetPath }),
   RouteTable.Routes,
   controllerContext.RequestContext,
   false);

Вызов этого метода приводит к HttpException:

System.Web.HttpException: Cannot use a leading .. to exit above the top directory.
   at System.Web.Util.UrlPath.ReduceVirtualPath(String path)
   at System.Web.Util.UrlPath.Reduce(String path)
   at System.Web.VirtualPath.Combine(VirtualPath relativePath)
   at System.Web.VirtualPathUtility.Combine(String basePath, String relativePath)
   at System.Web.Mvc.PathHelpers.GenerateClientUrlInternal(HttpContextBase httpContext, String contentPath)
   at System.Web.Mvc.PathHelpers.GenerateClientUrl(HttpContextBase httpContext, String contentPath)
   at System.Web.Mvc.UrlHelper.GenerateUrl(String routeName, String actionName, String controllerName, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, Boolean includeImplicitMvcValues)

ПросмотрRequestContext, кажется, что все пути запроса являются правильными (то есть имеют переписанные значения).Кажется, я не могу понять, почему он пытается выйти из каталога верхнего уровня ... Мы нигде не используем .... в пути.

Я также убедился, что RewriteModuleвыше модуль UrlRouting в IIS.

Хотя я могу войти в методы инфраструктуры, я не могу исследовать ни одну из локальных переменных (в VS или WinDbg), потому что она оптимизирована компилятором.

Есть мысли?

Ответы [ 3 ]

8 голосов
/ 03 марта 2012

Это гротескный обходной путь, включающий частные детали реализации, но добавьте его:

HttpContext.Current.Request.ServerVariables.Remove("IIS_WasUrlRewritten");

Это позволяет избежать внутренней проверки, выполненной в PathHelper.GenerateClientUrlInternal для проверки того, был ли запрос переписан.Вполне вероятно, что это нарушит некоторые сценарии, на что намекает этот комментарий в справочных источниках:

// Since the rawUrl represents what the user sees in his browser, it is what we want to use as the base 
// of our absolute paths. For example, consider mysite.example.com/foo, which is internally 
// rewritten to content.example.com/mysite/foo. When we want to generate a link to ~/bar, we want to
// base it from / instead of /foo, otherwise the user ends up seeing mysite.example.com/foo/bar, 
// which is incorrect.
2 голосов
/ 19 декабря 2018

Рабочий раствор - вставить строку перед Url.Content / UrlHelper.GenerateContentUrl (лучшее место в Application_BeginRequest):

System.Web.HttpContext.Current.Items.Add("IIS_WasUrlRewritten", "false");

Мой ответ - результат 2 приведенных выше ответов(Рик Шотт и Том).Оба были совершенно правы, но это не помогло.Я узнал исходный код в https://github.com/aspnet/AspNetWebStack/blob/master/src/ двух классов (System.Web.WebPages.Utils.UrlRewriterHelper.cs и System.Web.WebPages.Utils.UrlUtil.cs), которые находятся в моей трассировке стека:

System.Web.HttpException (0x80004005): Cannot use a leading .. to exit above the top directory. 
at System.Web.Util.UrlPath.ReduceVirtualPath(String path) 
at System.Web.Util.UrlPath.Reduce(String path) 
at System.Web.VirtualPath.Combine(VirtualPath relativePath) 
at System.Web.VirtualPathUtility.Combine(String basePath, String relativePath) 
at System.Web.WebPages.UrlUtil.GenerateClientUrlInternal(HttpContextBase httpContext, String contentPath) 
at System.Web.WebPages.UrlUtil.GenerateClientUrlInternal(HttpContextBase httpContext, String contentPath) 
at System.Web.WebPages.UrlUtil.GenerateClientUrl(HttpContextBase httpContext, String basePath, String path, Object[] pathParts) 

В System.Web.WebPages.Utils.UrlUtil.cs есть код - метод GenerateClientUrlInternal:

if (!wasRequestRewritten)
            {
                return contentPath;
            }

            // Since the rawUrl represents what the user sees in his browser, it is what we want to use as the base
            // of our absolute paths. For example, consider mysite.example.com/foo, which is internally
            // rewritten to content.example.com/mysite/foo. When we want to generate a link to ~/bar, we want to
            // base it from / instead of /foo, otherwise the user ends up seeing mysite.example.com/foo/bar,
            // which is incorrect.
            string relativeUrlToDestination = MakeRelative(httpContext.Request.Path, contentPath);
            string absoluteUrlToDestination = MakeAbsolute(httpContext.Request.RawUrl, relativeUrlToDestination);
            return absoluteUrlToDestination;

Вы можете увидеть странные строки с комментариями автора для переписанных путей URL.Кроме того, исходный путь клиента находится в HttpContext.Request.RawUrl, но в URL он переписан.Посмотрите вперед на System.Web.WebPages.Utils.UrlRewriterHelper.cs:

 if (httpContext.Items.Contains(UrlWasRewrittenServerVar))
            {
                return Object.Equals(httpContext.Items[UrlWasRewrittenServerVar], UrlWasRequestRewrittenTrueValue);
            }
            else
            {
                HttpWorkerRequest httpWorkerRequest = (HttpWorkerRequest)httpContext.GetService(typeof(HttpWorkerRequest));
                bool requestWasRewritten = (httpWorkerRequest != null && httpWorkerRequest.GetServerVariable(UrlWasRewrittenServerVar) != null);

                if (requestWasRewritten)
                {
                    httpContext.Items.Add(UrlWasRewrittenServerVar, UrlWasRequestRewrittenTrueValue);
                }
                else
                {
                    httpContext.Items.Add(UrlWasRewrittenServerVar, UrlWasRequestRewrittenFalseValue);
                }

                return requestWasRewritten;
            }

Если мы записываем фиктивное значение в HttpContext.Items [UrlWasRewrittenServerVar] со значением «false», мы создаем пропущенный httpWorkerRequest.GetSertenRaviableRiable ()! = нулевая проверка.Итак, Url.Content сейчас работает.

0 голосов
/ 04 октября 2011

Не уверен, поможет ли это, но вот код, вызывающий исключение:

internal static string ReduceVirtualPath(string path)
{
    int length = path.Length;
    int startIndex = 0;
    while (true)
    {
        startIndex = path.IndexOf('.', startIndex);
        if (startIndex < 0)
        {
            return path;
        }
        if (((startIndex == 0) || (path[startIndex - 1] == '/')) && ((((startIndex + 1) == length) || (path[startIndex + 1] == '/')) || ((path[startIndex + 1] == '.') && (((startIndex + 2) == length) || (path[startIndex + 2] == '/')))))
        {
            break;
        }
        startIndex++;
    }
    ArrayList list = new ArrayList();
    StringBuilder builder = new StringBuilder();
    startIndex = 0;
    do
    {
        int num3 = startIndex;
        startIndex = path.IndexOf('/', num3 + 1);
        if (startIndex < 0)
        {
            startIndex = length;
        }
        if ((((startIndex - num3) <= 3) && ((startIndex < 1) || (path[startIndex - 1] == '.'))) && (((num3 + 1) >= length) || (path[num3 + 1] == '.')))
        {
            if ((startIndex - num3) == 3)
            {
                if (list.Count == 0)
                {
                    throw new HttpException(SR.GetString("Cannot_exit_up_top_directory"));
                }
                if ((list.Count == 1) && IsAppRelativePath(path))
                {
                    return ReduceVirtualPath(MakeVirtualPathAppAbsolute(path));
                }
                builder.Length = (int) list[list.Count - 1];
                list.RemoveRange(list.Count - 1, 1);
            }
        }
        else
        {
            list.Add(builder.Length);
            builder.Append(path, num3, startIndex - num3);
        }
    }
    while (startIndex != length);
    string str = builder.ToString();
    if (str.Length != 0)
    {
        return str;
    }
    if ((length > 0) && (path[0] == '/'))
    {
        return "/";
    }
    return ".";
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...