如何使用自定义IHttpModule和HttpRequest过滤器修改POST请求?

时间:2010-07-13 18:21:36

标签: c# asp.net iis iis-7 httpmodule

概述

我希望能够将请求参数和内容修改为第三方Web服务(ArcGIS Server)。这将用于创建任何客户端应用程序和服务器应用程序之间存在的安全层。

我认为我找到了解决方案,但我目前在实施方面遇到了一些困难。

潜在解决方案:使用自定义请求过滤器修改请求

对于解决方案,我基于sample shown on MSDN松散地实现了自定义请求过滤器。我已经“增强”了代码,以便我可以使用正则表达式搜索和替换必要的内容。这包括:

  1. 将内容(存储在字节数组中)转换为字符串。
  2. 搜索字符串并执行任何必要的修改。
  3. 将修改后的字符串转换为字节数组并将其写入缓冲区。
  4. 示例如下所示:

    public override int Read(byte[] buffer, int offset, int count)
    {
        int bytesRead = _stream.Read(buffer, offset, count);
    
        string orgContent = Encoding.UTF8.GetString(buffer, offset, bytesRead);
        string orgContentDecoded = HttpUtility.UrlDecode(orgContent);
    
        string layersPattern = @"&layers=(show|hide|include|exclude):([0-9]+,?)+";
        Regex layersRegex = new Regex(layersPattern, RegexOptions.IgnoreCase);
    
        string[] permittedLayers = new string[] { "0" , "1" };
        string replacementLayers = "&layers=show:" + String.Join(",", permittedLayers);
        string newContentDecoded = layersRegex.Replace(orgContentDecoded, replacementLayers);
    
        string newContent =  newContentDecoded.Replace(",", "%2C").Replace(":", "%3A");
    
        byte[] newBuffer = Encoding.UTF8.GetBytes(newContent);
        int newByteCountLength = Encoding.UTF8.GetByteCount(newContent);
    
        Encoding.UTF8.GetBytes(newContent, 0, Encoding.UTF8.GetByteCount(newContent), buffer, 0);
    
        return bytesRead;
    }
    

    只要修改后的内容长度原始内容长度不同,这似乎效果很好。例如,如果我用2替换1,一切正常。但是,如果我用10替换1(从而将消息大小增加1),那么我从ArcGIS Server收到错误,表明该格式不受支持。

    这引起了我的注意:

    1. 当前实现不处理分块请求。也就是说,如果请求sie足够大,则可以针对单个请求多次调用Read。 在这种情况下应该如何处理分块?
    2. 错误消息的根本原因是什么?与内容长度有关的问题是否与流长度不同? 如何正确修改内容以便更改其长度不是问题?
    3. 有什么想法吗?

3 个答案:

答案 0 :(得分:4)

这个问题的第二部分的答案是返回修改后的内容大小,而不是原始流的大小。看哪!

// return bytesRead;
return newByteCountLength;

答案 1 :(得分:2)

这个问题和你的答案对我来说真的很有用,但如果你试图在流中插入更多的数据,答案就不是全部:

仅当您插入流中的数据不会将读取到缓冲区中的字节数超过count值时,返回修改后的内容大小才有效。如果您尝试插入太多数据,您要么会发现buffer对象不足以容纳您正在插入的数据,要么写入超过count个字节的数据在缓冲区中,您将覆盖缓冲区末尾的一些数据,而这些数据本来就是一个人。

如果您需要插入的数据多于当前buffer对象可以容纳的数据,那么您必须在单独的字节数组中缓冲数据并将其复制到块中,因为对stream.read的调用是制成。

答案 2 :(得分:0)

正如Chris McKeown所说,除非你承诺不修改数据的大小,否则这并不是最好的过滤技术。为了完整地回答这个问题,我发布了一个示例项目,该项目演示了如果您感兴趣,如何使用缓冲技术处理请求和响应的过滤。

https://github.com/snives/HttpModuleRewrite

另外,对于有关排除HttpModules进行过滤的问题,过滤此帖也非常有用Is it possible to modify the content of HttpRequest POST in an IIS HttpModule?