在 C# 中模拟 HTTP 的不正确内容长度标头

发布于 2024-08-02 15:51:37 字数 328 浏览 6 评论 0原文

我们正在用 C# 为我们的应用程序构建一个全面的集成测试框架,该框架存在于 HTTP 之上,使用 IIS7 来托管我们的应用程序。

作为集成测试的一部分,我们希望测试传入的请求,当客户端发送一个 HTTP 标头(表明主体大小比实际传输的一部分更大)时,将导致 EndOfStreamExceptions(“无法读取超出流末尾”)。身体。我们想要测试这种情况下的错误恢复代码,因此我们需要模拟这些类型的请求。

我正在寻找基于 .NET Fx 的套接字库或自定义 HttpWebRequest 替代品,专门允许开发人员模拟此类条件以添加到我们的集成测试套件中。有谁知道有这样的图书馆吗?可编写脚本的解决方案也可以。

We are building a comprehensive integration test framework in C# for our application which exists on top of HTTP using IIS7 to host our applications.

As part of our integration tests we want to test incoming requests which will result in EndOfStreamExceptions ("Unable to read beyond end of stream") that occur when a client sends up a HTTP header indicating a larger body size than it actually transmits as part of the body. We want to test our error recovery code for this condition so we need to simulate these sorts of requests.

I am looking for a .NET Fx-based socket library or custom HttpWebRequest replacement that specifically allows developers to simulate such conditions to add to our integration test suite. Does anyone know of any such libraries? A scriptable solution would work as well.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

假情假意假温柔 2024-08-09 15:51:37

在调用 GetRequestStream(或 BeginGetRequestStream)之前设置 ContentLength 属性,然后向该流写入更少的字节。如果您在获取请求流后尝试设置 ContentLength,则会抛出异常。如果您不设置 ContentLength,HttpWebRequest 将缓冲标头直到流关闭,以便它可以适当地设置 ContentLength(或者,您可以使用 SendChunked,但这在这里不起作用)。如果您想对此进行最大程度的控制,请手动创建一两个错误的请求,然后打开服务器上端口 80 的套接字,并将请求写入 TCP 流,然后读取响应并检查连接以查看它是否已关闭。

但是:我认为这个测试不是一个好主意。问题是这样的:

客户端向服务器发送请求。它声称内容将为 100 字节。然后它发送 90 个字节,然后停止发送,使连接保持打开状态。服务器读取 90 个字节,然后等待其余部分,因为客户端表示将发送 100 个字节。现在,客户端发送第二个请求。服务器将如何处理新请求的前 10 个字节?

答案是,服务器会假设这些字节是前一个请求的一部分,并按原样对待它们,然后在“新”请求开始后 10 个字节开始读取“新”请求,这显然会导致标头格式错误。服务器不会喜欢这样,所以它会发送 4xx 错误,然后关闭连接。它关闭连接的原因是因为它现在无法知道发送给它的数据意味着什么,也无法恢复。此外,连接的关闭不会是优雅的,它会是突然的,另一端提交第二个请求(或者第三个或第四个,如果它们排队的话)的 HttpWebRequest 将抛出一个 WebException ,表示底层连接已关闭,让您猜测原因。

同样的行为导致连接通过 Expect 100-Continue 标头关闭,并且服务器返回 100-Continue 后跟 4xx,例如需要 Auth 时。即使它拒绝了请求,它仍然必须假设接下来的字节是同一请求的一部分,因为它已承诺通过发送 100-continue 来接收这些字节。如果它不服务该请求,或者客户端想要取消请求并提交新请求(可能带有身份验证凭据),则它必须关闭连接并打开一个新请求。

最后,使用 TCP 从网络流测试 EndOfStreamException 对我来说根本没有任何意义。 TCP 不标记流的“结束”,它只是在数据写入套接字时不断发送数据。它没有“EOF”,也没有办法检测数据是否全部传输,除非您知道预期有多少数据。除非连接关闭,否则 TCP 的流实际上并没有“结束”,在这种情况下,您将收到 WebException 或 SocketException,具体取决于您在堆栈中操作的位置。协议中的任何传输错误都在winsock 中处理。如果不再发送数据,连接的一端最终将向另一端发送保活消息,以确保连接实际上仍然打开,并且一台主机不会丢弃它。如果 keepalive 超时,连接将被关闭,并且下次尝试读取时可能会收到 WebException。考虑到所有这些是如何工作的,我只是不知道你将如何从这个测试中获得任何价值。最好只发送格式错误的请求,并确保相应地处理错误,并将适当的 4xx 消息发送回客户端,并正确关闭连接。

Set the ContentLength property prior to calling GetRequestStream (or BeginGetRequestStream) and then write fewer bytes to that stream. ContentLength will throw if you try to set it after you've gotten the request stream. If you don't set ContentLength, HttpWebRequest will buffer the headers until the stream is closed so that it can set ContentLength appropriately (alternately, you can use SendChunked but that won't work for you here). If you want maximum control over this, create a malormed request or two by hand and then open a socket to port 80 on the server and write the request to the TCP stream and then read the response and check the connection to see if it was closed.

HOWEVER: I don't think that this test is a good idea. Here's the problem:

Client sends a request to the server. It claims the content will be 100 bytes. It then sends 90 bytes and then just stops sending, leaving the connection open. The server reads 90 bytes, then waits for the rest since the client said that 100 bytes would be sent. Now, the Client sends a second request. What will the server do with the first 10 bytes of the new request?

The answer is that the server will assume that those bytes were part of the previous request and treat them as such, then start reading the "new" request 10 bytes after its start, which will obviously result in malformed headers. The server won't like that, so it'll send a 4xx error and then it will close the connection. The reason it closes the connection is because it now has no way to know what the data being sent to it means and no way to recover. Also, the closing of the connection will not be graceful, it'll be sudden and the HttpWebRequest on the other end that is submitting a second request (or a third or fourth if they're queued up) will throw a WebException saying that the underlying connection was closed and leave you guessing as to why.

This same behavior is what causes the connection to be closed with the Expect 100-continue header and the server returns a 100-continue followed by a 4xx such as when Auth is required. Even though it's rejected the request, it still MUST assume that the next bytes are part of the same request since it has committed to receiving those bytes by sending the 100-continue. If it won't service that request or if the client wants to cancel the request and submit a new one (presumably with auth credentials) then it has to close the connection and open a new one.

Finally, testing for an EndOfStreamException from a network stream using TCP doesn't make any sense to me at all. TCP doesn't mark the "end" of a stream, it just keeps sending data as it is written to the socket. There is no "EOF" for it and no way to detect if the data was all transmitted unless you know how much data to expect. TCP doesn't really have an "end" to its stream unless the connection is closed, in which case you'll get a WebException or a SocketException depending on where in the stack you're operating. Any transmission errors in the protocol are dealt with in winsock. If no more data is sent, one end of the connection will eventually send a keepalive to the other to ensure that the connection is still actually open and one host didn't just drop it. If the keepalive times out, the connection will be closed and you may get a WebException the next time you try to read from it. Given how all of this works, I just don't see how you're going to get any value out of this test. You're much better off just sending malformed requests and ensuring that the errors are processed accordingly and the appropriate 4xx message is being sent back to the client and the connection is being closed properly.

财迷小姐 2024-08-09 15:51:37

我不知道有任何这样的库,但在我看来,如果接收方是您编码的地方,那么它在接收方会非常简单。

只需检索整个 WebRequest,根据需要截断尽可能多或尽可能少的内容,然后转发即可。您可能需要在此过程中创建 WebRequest 的新副本,而不是就地截断,但它仍然应该是直接的。

I don't know of any such library, but it seems to me it would be very simple on the receiving-side, if that is where you are coding.

Simply retrieve the entire WebRequest, truncate as much or as little as you want, and then forward it on. You might need to make a new copy of the WebRequest in the process, rather than truncate in-place, but it should still be straight-forward.

小糖芽 2024-08-09 15:51:37

难道您不能将客户端上的 HttpWebRequest.ContentLength 属性设置为比数据实际大小更小或更大的值吗?

Can't you just set the HttpWebRequest.ContentLength property on the clients to a smaller or larger value than the actual size of the data?

囚你心 2024-08-09 15:51:37

如果你想模拟任何类似这样违反 HTTP 协议的事情,那么你必须编写自己的代码来完成它。 HttpWebRequest 不允许你做这样的事情。

If you want to simulate any things like this, where you are violating the HTTP protocol, then you will have to write your own code to do it. HttpWebRequest does not allow you to do things like this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文