使用URL编码的斜杠获取URL

40

我想向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 over HTTP/GET 时,OCSP 协议规定必须发送 base-64 编码的 url-encoding ,因此需要发送实际的 %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协议中的一个错误(或者说是对其的误解)。 - Julian Reschke
我建议向微软报告这个错误。 - knocte
1
@knocte:已经有人报告并修复了。请参考Bradley Gaingers的回答。 - Rasmus Faber
哦,好的,抱歉打扰了。 - knocte
实际上,要么链接已经失效,要么错误报告是私有的 :( - knocte
https://dev59.com/sWnWa4cB1Zd3GeqPxiZV#18511985 — 适用于Power Shell中类似问题的解决方案 - Boo
5个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
52

这是一个可怕的黑客技巧,很可能与未来版本的框架不兼容等等。

但它能够工作!

(在我的机器上...)

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
确实有效。我想知道他们不允许“dontEscape”参数的原因是什么? - Patrick Klug
2
出于对Atwood的热爱,这个答案为我节省了数小时的时间。谢谢! - Matt Sherman
1
@user1473484:是的,你可以通过更改你的app.config来解决这个问题;在这里查看我对类似问题的回答:https://dev59.com/RmPVa4cB1Zd3GeqP5F44#10415482 - Bradley Grainger
Rasmus,我刚刚为.NET和Mono创建了一个库来解决这个问题。我使用了你的方法来制作.NET版本。它在这里:https://github.com/glennblock/PUrify/blob/master/README.md。如果你有任何疑虑,我已经在致谢中加入了你的名字,请告诉我。 - Glenn Block
1
要使其在 .Net Standard(以及可能的最近版本的 .Net Framework)下工作,您需要添加 flags &= ~((ulong)0xC30); 并将 m_Flags 更改为 _flags - Michael Brown
显示剩余5条评论

31
默认情况下,Uri类不允许在URI中使用转义的/字符(即使在我的阅读RFC 3986中似乎是合法的)。
Uri uri = new Uri("http://example.com/%2F");
Console.WriteLine(uri.AbsoluteUri); // prints: http://example.com//
(注意:不要使用Uri.ToString来打印URI。) 根据Microsoft Connect上关于此问题的错误报告,这种行为是设计上的,但您可以通过在您的app.config或web.config文件中添加以下内容来解决它:
<uri>
  <schemeSettings>
    <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
  </schemeSettings>
</uri>

(此内容转载自https://dev59.com/RmPVa4cB1Zd3GeqP5F44#10415482,因为这是避免使用反射修改私有字段的“官方”方法来避免此错误。)

编辑:Connect错误报告不再可见,但<schemeSettings>的文档建议使用此方法允许在URI中转义/字符。请注意(根据该文章),对于不能正确处理转义斜杠的组件可能会存在安全性问题。


4
如果你调用的URL是HTTPS,请务必使用name="https"。 - r590

13

关于这个问题的最新进展:看起来在.NET 4.5中Uri类的默认行为实际上已经更改,现在你可以使用转义斜杠并且它们不会被修改。

我在.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实际上已按预期未转义。

Fiddler trace

然而,在.NET 4.5/4.5.1中,您可以看到%2F未被解码(请注意GET /%2F)。

Fiddler trace

你现在甚至可以对Uri使用ToString(),你将得到相同的结果。 因此,总结一下,如果你使用的是.NET >= .NET 4.5,那么事情将会按照RFC的要求进行。 我刚刚尝试在Mono上实现相同的方法。我在这里发布了我的问题:在mono上获取带转义斜杠的Uri

我想补充一点,只有在Visual Studio中将“目标框架”更改为.NET 4.5时,更改才会生效。仅在计算机上安装.NET 4.5并不能改变行为。 - aKzenT

0

如我在Ramus的回答中所提到的,要使此黑科技生效,需要以下步骤(适用于.Net Standard和可能的后续版本的.Net Framework):

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);
}

-7

双重编码它:%252F

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

此外,如果WebClient接受URI,则可以创建一个新的URI并将其设置为不进行编码。


1
如果我尝试获取 http://example.com/%252F,实际上会发送 GET /%252F,所以这样不起作用。自2.0版本以来,URI 构造函数的 dontEscape 参数已被弃用,并且根据文档,dontEscape 参数将被忽略。你是指使用 HttpWebRequest 这一点吗? - Rasmus Faber
检查问题是在URI构造器中还是实际发送过程中?这可以帮助诊断确切的问题。 - dr. evil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,