【问题标题】:ASP.NET MVC UrlHelper.GenerateUrl exception: "Cannot use a leading .. to exit above the top directory"ASP.NET MVC UrlHelper.GenerateUrl 异常:“不能使用前导 .. 退出顶级目录”
【发布时间】:2011-04-19 02:02:13
【问题描述】:

我正在使用 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 位于 IIS 中的 UrlRouting 模块上方。

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

有什么想法吗?

【问题讨论】:

  • 我遇到了同样的问题,还没有找到解决方案。现在我只是对超链接进行硬编码,而不是使用 Html.ActionLink 我得到异常的地方。你找到解决办法了吗?
  • @Rob:我们没有找到解决方案。我能够追踪到请求中是否存在 X_ORIGINAL_URL 标头。 IIS 在重写 url 时将该标头放在那里。它使用该标头尝试撤消对 url 的重写,因为您可能不希望生成的 url 遵循重写的格式。当它考虑到原始网址时,它会为我们挂断。 总是 使用原始 url 没有多大意义 - 对我们来说,我们只希望它生成 url 并忽略原始 URL。我们发现无法覆盖此行为。
  • 我最终从重写切换到重定向,这解决了问题。我们的 URL 现在包含该区域,这并不理想,但更重要的是该站点可以正常工作,而不会过多地与 MVC 的路由混淆。
  • 不确定这是否有帮助,但我也遇到了这个问题,最后调用了重载的UrlHelper.GenerateUrl() method,它也将主机名作为参数。这确实意味着我必须将主机名保留在配置中并传递它,但它似乎有助于 url 重写...... :)
  • arg,我曾经处理过这个问题,但不记得了……我的大脑一片空白。无论如何,如果你愿意使用 rewrite 模块,为什么不使用 MVC 的路由呢?

标签: asp.net asp.net-mvc-2 url-rewriting


【解决方案1】:

工作解决方案是在 Url.Content/UrlHelper.GenerateContentUrl 之前插入一行(最好的位置是 Application_BeginRequest):

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

我的答案是上述 2 个答案(Rick Schott 和 Thom)的结果。两者都非常正确,但这并没有帮助。 我在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;
            }

如果我们使用“false”值将虚拟值写入 HttpContext.Items[UrlWasRewrittenServerVar],我们会跳过 httpWorkerRequest.GetServerVariable(UrlWasRewrittenServerVar) != null 检查。 所以 Url.Content 现在可以工作了。

【讨论】:

    【解决方案2】:

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

    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.
    

    【讨论】:

    • 你能告诉我应该在哪里运行这个吗?在我的情况下,实际上没有 IIS_WasUrlRewritten 服务器变量......但试图从应该与 Url Rewrite 做某事的标头和服务器变量中删除 X-Original-URL,但都没有从 Http 中删除模块(虽然值在那里,但调用 Remove() 对它没有任何作用)。
    • 很遗憾,这并没有为我们解决问题。
    • 你说的很对,但是你需要让 HttpContext.Items “脏”而不是 ServerVariables:System.Web.HttpContext.Current.Items.Add("IIS_WasUrlRewritten", "false");跨度>
    【解决方案3】:

    不确定是否有帮助,但这是引发异常的代码:

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

    【讨论】:

      猜你喜欢
      • 2014-04-28
      • 1970-01-01
      • 2010-09-16
      • 1970-01-01
      • 2012-01-14
      • 2011-01-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多