代码之家  ›  专栏  ›  技术社区  ›  Paul Kearney - pk

ASP.NET MVC UrlHelper.GenerateUrl异常:“无法使用前导..退出顶部目录上方”

  •  17
  • Paul Kearney - pk  · 技术社区  · 14 年前

    我正在使用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)
    

    我还确保RewriteModule位于IIS中URL路由模块的上方。

    虽然我可以进入框架方法,但我不能检查任何局部变量(在VS或WinDbg中),因为它已经过编译器优化。

    3 回复  |  直到 14 年前
        1
  •  9
  •   Thom    12 年前

    这是一个涉及私有实现细节的奇怪的解决方法,但添加以下内容:

    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
  •  2
  •   Pavel Nazarov    6 年前

    工作溶液 是在Url.Content/UrlHelper.GenerateContentUrl之前插入一行(最佳位置在应用程序_BeginRequest中):

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

    我在大学里学过源代码 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;
                }
    

    所以Url.Content现在起作用了。

        3
  •  0
  •   rick schott    13 年前

    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 ".";
    }