【问题标题】:GETting a URL with an url-encoded slash使用 url 编码的斜杠获取 URL
【发布时间】:2010-10-21 08:09:13
【问题描述】:

我想向http://example.com/%2F 发送一个HTTP GET。我的第一个猜测是这样的:

using (WebClient webClient = new WebClient())
{
  webClient.DownloadData("http://example.com/%2F");
}

不幸的是,我可以看到实际在网络上发送的是:

GET // HTTP/1.1
Host: example.com
Connection: Keep-Alive

所以http://example.com/%2F 在传输之前被翻译成http://example.com//。

有没有办法实际发送这个 GET 请求?

OCSP 协议要求在通过 HTTP/GET 使用 OCSP 时发送 base-64 编码的 url 编码,因此需要发送实际的 %2F 而不是“/”以符合要求。

编辑:

这里是OCSP协议标准的相关部分(RFC 2560附录A.1.1):

使用GET方法的OCSP请求构造如下:

GET {url}/{url-encoding of base-64 encoding of the DER encoding of the OCSPRequest}

我对这方面的其他解读持开放态度,但我看不出还有什么意思。

【问题讨论】:

  • 对我来说听起来像是 OCSP 协议中的一个错误(或者,对它的误解)。
  • 我建议向微软报告这个错误
  • @knocte:已报告并修复。请参阅 Bradley Gaingers 的回答。
  • 哦,对了,打扰了
  • 实际上,要么链接断开,要么错误报告是私有的:(

标签: c# .net http base64 url-encoding


【解决方案1】:

正如我在对 Ramus 发布的答案的评论中所提到的,.Net Standard(以及可能的 .Net Framework 的更高版本)需要以下内容才能使这个 hack 工作:

Uri uri = new Uri("http://example.com/%2F");
ForceCanonicalPathAndQuery(uri);
using (WebClient webClient = new WebClient())
{
  webClient.DownloadData(uri);
}

void ForceCanonicalPathAndQuery(Uri uri){
  string paq = uri.PathAndQuery; // need to access PathAndQuery
  FieldInfo flagsFieldInfo = typeof(Uri).GetField("_flags", BindingFlags.Instance | BindingFlags.NonPublic);
  ulong flags = (ulong) flagsFieldInfo.GetValue(uri);
  flags &= ~((ulong) 0xC30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
  flagsFieldInfo.SetValue(uri, flags);
}

【讨论】:

    【解决方案2】:

    默认情况下,Uri 类不允许在 URI 中使用转义的 / 字符 (%2f)(尽管在我阅读 RFC 3986 时这似乎是合法的)。

    Uri uri = new Uri("http://example.com/%2F");
    Console.WriteLine(uri.AbsoluteUri); // prints: http://example.com//
    

    (注意:don't use Uri.ToString 打印 URI。)

    根据 Microsoft Connect 上的 bug report for this issue,此行为是设计使然,但您可以通过将以下内容添加到 app.config 或 web.config 文件来解决此问题:

    <uri>
      <schemeSettings>
        <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
      </schemeSettings>
    </uri>
    

    (转自https://stackoverflow.com/a/10415482,因为这是在不使用反射修改私有字段的情况下避免此错误的“官方”方式。)

    编辑: Connect 错误报告不再可见,但 documentation for &lt;schemeSettings&gt; 建议使用此方法以允许在 URI 中转义 / 字符。请注意(根据那篇文章),未正确处理转义斜杠的组件可能存在安全隐患。

    【讨论】:

    • 如果您调用的 URL 是 HTTPS,请务必使用 name="https"。
    【解决方案3】:

    对此进行更新:看起来 Uri 类的默认行为实际上是 .NET 4.5 中的 changed,您现在可以使用转义的斜杠,并且不会触及它们。

    我在 .NET 3.5、.NET 4.0、.NET 4.5/4.5.1 中运行了以下代码

    static void Main(string[] args)
    {
        var uri = new Uri("http://www.yahooo.com/%2F");
        var client = new WebClient();
        client.DownloadString(uri);
    }
    

    在 .NET 3.5/4.0 中,跟踪显示 %2F 实际上未按预期进行转义。

    但是,在 .NET 4.5/4.5.1 中,您可以看到 %2F 没有被转义(注意 GET /%2F)

    您现在甚至可以在 Uri 上使用 ToString(),您将获得相同的结果。

    因此,总而言之,如果您使用的是 .NET >= .NET 4.5,那么事情的表现将与 RFC 内联。

    我刚刚进行了一次探索,试图在 Mono 上使用相同的方法。我在这里发布了关于该方法的问题:Getting a Uri with escaped slashes on mono

    【讨论】:

    • 我想补充一点,该更改仅在将 Visual Studio 中的“目标框架”更改为 .NET 4.5 时生效。仅在机器上安装 .NET 4.5 不会改变行为。
    【解决方案4】:

    这是一个可怕的 hack,必然与框架的未来版本不兼容等等。

    但它有效!

    (在我的机器上...)

    Uri uri = new Uri("http://example.com/%2F");
    ForceCanonicalPathAndQuery(uri);
    using (WebClient webClient = new WebClient())
    {
      webClient.DownloadData(uri);
    }
    
    void ForceCanonicalPathAndQuery(Uri uri){
      string paq = uri.PathAndQuery; // need to access PathAndQuery
      FieldInfo flagsFieldInfo = typeof(Uri).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
      ulong flags = (ulong) flagsFieldInfo.GetValue(uri);
      flags &= ~((ulong) 0x30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
      flagsFieldInfo.SetValue(uri, flags);
    }
    

    【讨论】:

    • +1。完美的!我需要这个来让 Google Webmaster Tools API 工作。
    • 确实有效。我想知道他们不允许“dontEscape”参数的原因是什么?
    • 看在 Atwood 的份上,这个答案为我节省了几个小时。谢谢!
    • @user1473484:是的,您可以通过更改 app.config 来解决此问题;在此处查看我对类似问题的回答:stackoverflow.com/a/10415482
    • 要使其在 .Net Standard(可能还有最新版本的 .Net Framework)下工作,您需要添加 flags &amp;= ~((ulong)0xC30); 并将 m_Flags 更改为 _flags
    【解决方案5】:

    双重编码:%252F

    但是,如果您使用 HttpWebRequest,您实际上可以告诉不要对 URL 进行编码,无论哪种方式都应该有效。

    此外,如果 WebClient 接受 URI,那么您可以创建一个新的 URI,您可以将其设置为不编码。

    【讨论】:

    • 如果我尝试获取example.com/%252F,它实际上会发送 GET /%252F,所以这不起作用。带有 dontEscape 的 URI 构造函数自 2.0 起已弃用,根据文档,dontEscape 参数被忽略。这就是您使用 HttpWebRequest 的意思吗?
    • 检查问题是否出在URI构造函数中?还是实际的发送过程?这可以帮助诊断确切的问题。
    猜你喜欢
    • 2010-10-10
    • 2012-07-13
    • 2016-10-29
    • 2011-11-24
    • 2013-12-26
    • 2016-03-30
    • 1970-01-01
    • 1970-01-01
    • 2014-12-05
    相关资源
    最近更新 更多