自定义ISAPI Filter中发现的一个与Keep-Alive相关的Bug

我曾经在IIS6和IIS7.5的Classic模式下实现了一个自定义ISAPI Filter,目的是实现我自己的Basic认证逻辑。这中间我遇到了ISAPI Filter中与Keep-Alive相关的一个bug。

我的自定义ISAPI Filter在重载的 CHttpFilter::OnPreprocHeaders方法中验证请求头中的用户信息 ( Authorization: Basic <Base64编码的name:password>). 如果验证没通过,我就会发送一个 401应答给客户端,并且在 CHttpFilter::OnPreprocHeaders方法中返回 SF_STATUS_REQ_FINISHED_KEEP_CONN

我遇到的bug是这样的:当我的自定义ISAPI Filter发送401应答时,IIS总是会关闭当前的TCP连接,即使Keep-Alive处于打开的状态。这样,我用.NET的HttpWebRequestHttpWebResponse写的客户端程序总是会抛出一个异常,说服务器端已经关闭了连接。这是为什么呢?

经过研究发现是ISAPI Filter本身的一个不正确的行为导致的这个bug。按照MSDN上的说法,当Keep-Alive打开并且CHttpFilter::OnPreprocHeaders返回SF_STATUS_REQ_FINISHED_KEEP_CONN时,IIS应该结束请求的处理过程,但它会保持当前TCP连接处于打开的状态来处理同一个客户端发过来的下一个请求。但事实上,微软并没有实现这个正确的逻辑!也就是说,返回SF_STATUS_REQ_FINISHED_KEEP_CONN其实跟返回SF_STATUS_REQ_FINISHED没有任何区别,当前TCP连接总是会被关闭。可以说,这一行为违反了HTTP keep-alive的协议,所以我的客户端程序会抛异常。

最后我采用的解决方法是:当需要发送401应答时,在应答头里加上“Connection: close”,这可以显式地通知客户端服务器会在这个应答发完之后关闭当前的TCP连接。这里不需要担心对性能的影响,因为大多数客户端应用都会把HttpWebRequest.PreAuthenticate设置为true。也就是说,只有第一个请求会导致401应答,后续的所有请求都会附带上正确的认证信息,从而使Keep-Alive发挥应有的作用。这里我抱怨一下微软,为啥不在第一个请求的头中就附带上认证信息呢?

最近,我用IIS7.5的Integrated模式下的HTTP Module替掉了ISAPI Filter来做我自己的Basic认证逻辑. 当然,这个bug没再出现。不过这只限于客户端直接连接web服务器。当使用方向代理设备(比如BigIP)的时候,这个bug又出现了。到目前为止,我还没发现根源,但至少“ Connection: close”这个解决方案还是能工作的.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值