为什么 Chrome 79 不接受我用 SslStream (C#) 发送的 HTTPS 响应? err_response_headers_truncated
Why won't Chrome 79 accept my HTTPS response sent with SslStream (C#)? err_response_headers_truncated
我正在尝试使用 C# 在本地主机上构建一个简单的 TLS Web 服务器 运行。在这种情况下,我希望服务器做的就是发出重定向。为此,我使用了 Microsoft 提供的 SslStream
class。从表面上看,它似乎很容易使用。我 运行 遇到的问题是 chrome 特别是似乎不喜欢我的 HTTPS。 (代码在底部)
响应非常简单:"HTTP/1.1 301 Moved Permanently\r\nCache-Control: no-store\r\nLocation: https://google.com/"
使用 HTTP 实现时,页面按预期重定向,客户端 (Chrome) 或服务器上没有出现错误或异常。
但是,在使用我的 HTTPS 实现时,我从 chrome:
得到了类似的东西
This site can't be reached
The webpage at.....
ERR_RESPONSE_HEADERS_TRUNCATED
我不确定它还想从我这里得到什么。我会说响应 header 几乎没有被截断,但我没有 chrome。我可以在调试时读取 chrome 的 GET 请求,但 chrome 显然不能或不会读取我的响应。
我已经成功地使用了完全相同的代码来重定向边缘(http 和 https),所以这似乎是 chrome 特定的
在服务器发送响应之前,快速的 wireshark 调查显示没有任何异常。举例说明:标准 tcp syn/ack 握手,tls 握手,然后是客户端应用程序。 data (the GET,) server app data (the 301.) 服务器发送 301 后,有 3 个 FIN/ACKs,一个 keep-alive,一个密码更改,然后是一堆 RST。鉴于此信息,chrome 似乎没有给我们任何东西,但同时也不希望我们抛弃它们并开始拼命请求重新连接。奇怪的是,如果我调试,它会重新连接。但是随后它抛出异常,因为服务器读取超时;我们给了 Chrome 第二次机会,但 Chrome 不愿意为这段已经破裂的关系重新投入任何东西,这留下了伤疤。
差不多,我在问我在做什么 Chrome 显然不希望我如何更正它以便它在 Chrome 上工作?我是否做了其他浏览器正在补偿的明显错误,或者这是 SslStream 的问题?
我的 TLS 代码基本上取自 Microsoft doc for SslStream
and the http design follows the same pattern: accept, read, write, flush, stream close, tcp close. If you wanted to reproduce, the certificate created was used with X509Certificate.CreateFromCertFile(string). The TcpListener
used IPAddress.Loopback
. To generate my certificate I followed this tutorial 并用 openssl pkcs12
导出了我的 localhost.crt
和 localhost.key
private string response = "HTTP/1.1 301 Moved Permanently\r\nCache-Control: no-store\r\nLocation: https://google.com/ \r\n";
private void listen() {
while (true) {
TcpClient client = listener.AcceptTcpClient();
NetworkStream stream = client.GetStream();
stream.Read(new Byte[1024], 0, 1024);
stream.Write(Encoding.UTF8.GetBytes(response), 0, response.Length);
stream.Flush();
stream.Close();
client.Close();
}
}
private void listenSSL() {
TcpClient client;
while (true) {
client = listener.AcceptTcpClient();
SslStream sslStream = new SslStream(client.GetStream(), false);
sslStream.AuthenticateAsServer(certificate, clientCertificateRequired: false, SslProtocols.Tls12, checkCertificateRevocation: true);
sslStream.ReadTimeout = timeout;
sslStream.WriteTimeout = timeout;
string message = readMessage(sslStream);
sslStream.Write(Encoding.UTF8.GetBytes(response), 0, response.Length);
sslStream.Flush();
sslStream.Close();
client.Close();
}
}
好的,问题原来是行尾问题。 Chrome 想要在响应末尾添加两个 \r\n。我在 support.google.com 上找到了关于它的 this 文章。
所以字符串应该看起来像
"HTTP/1.1 301 Moved Permanently\r\nCache-Control: no-store\r\nLocation: https://google.com/ \r\n\r\n";
而不是
"HTTP/1.1 301 Moved Permanently\r\nCache-Control: no-store\r\nLocation: https://google.com/ \r\n"
我正在尝试使用 C# 在本地主机上构建一个简单的 TLS Web 服务器 运行。在这种情况下,我希望服务器做的就是发出重定向。为此,我使用了 Microsoft 提供的 SslStream
class。从表面上看,它似乎很容易使用。我 运行 遇到的问题是 chrome 特别是似乎不喜欢我的 HTTPS。 (代码在底部)
响应非常简单:"HTTP/1.1 301 Moved Permanently\r\nCache-Control: no-store\r\nLocation: https://google.com/"
使用 HTTP 实现时,页面按预期重定向,客户端 (Chrome) 或服务器上没有出现错误或异常。
但是,在使用我的 HTTPS 实现时,我从 chrome:
得到了类似的东西This site can't be reached
The webpage at.....
ERR_RESPONSE_HEADERS_TRUNCATED
我不确定它还想从我这里得到什么。我会说响应 header 几乎没有被截断,但我没有 chrome。我可以在调试时读取 chrome 的 GET 请求,但 chrome 显然不能或不会读取我的响应。
我已经成功地使用了完全相同的代码来重定向边缘(http 和 https),所以这似乎是 chrome 特定的
在服务器发送响应之前,快速的 wireshark 调查显示没有任何异常。举例说明:标准 tcp syn/ack 握手,tls 握手,然后是客户端应用程序。 data (the GET,) server app data (the 301.) 服务器发送 301 后,有 3 个 FIN/ACKs,一个 keep-alive,一个密码更改,然后是一堆 RST。鉴于此信息,chrome 似乎没有给我们任何东西,但同时也不希望我们抛弃它们并开始拼命请求重新连接。奇怪的是,如果我调试,它会重新连接。但是随后它抛出异常,因为服务器读取超时;我们给了 Chrome 第二次机会,但 Chrome 不愿意为这段已经破裂的关系重新投入任何东西,这留下了伤疤。
差不多,我在问我在做什么 Chrome 显然不希望我如何更正它以便它在 Chrome 上工作?我是否做了其他浏览器正在补偿的明显错误,或者这是 SslStream 的问题?
我的 TLS 代码基本上取自 Microsoft doc for SslStream
and the http design follows the same pattern: accept, read, write, flush, stream close, tcp close. If you wanted to reproduce, the certificate created was used with X509Certificate.CreateFromCertFile(string). The TcpListener
used IPAddress.Loopback
. To generate my certificate I followed this tutorial 并用 openssl pkcs12
localhost.crt
和 localhost.key
private string response = "HTTP/1.1 301 Moved Permanently\r\nCache-Control: no-store\r\nLocation: https://google.com/ \r\n";
private void listen() {
while (true) {
TcpClient client = listener.AcceptTcpClient();
NetworkStream stream = client.GetStream();
stream.Read(new Byte[1024], 0, 1024);
stream.Write(Encoding.UTF8.GetBytes(response), 0, response.Length);
stream.Flush();
stream.Close();
client.Close();
}
}
private void listenSSL() {
TcpClient client;
while (true) {
client = listener.AcceptTcpClient();
SslStream sslStream = new SslStream(client.GetStream(), false);
sslStream.AuthenticateAsServer(certificate, clientCertificateRequired: false, SslProtocols.Tls12, checkCertificateRevocation: true);
sslStream.ReadTimeout = timeout;
sslStream.WriteTimeout = timeout;
string message = readMessage(sslStream);
sslStream.Write(Encoding.UTF8.GetBytes(response), 0, response.Length);
sslStream.Flush();
sslStream.Close();
client.Close();
}
}
好的,问题原来是行尾问题。 Chrome 想要在响应末尾添加两个 \r\n。我在 support.google.com 上找到了关于它的 this 文章。 所以字符串应该看起来像
"HTTP/1.1 301 Moved Permanently\r\nCache-Control: no-store\r\nLocation: https://google.com/ \r\n\r\n";
而不是
"HTTP/1.1 301 Moved Permanently\r\nCache-Control: no-store\r\nLocation: https://google.com/ \r\n"