使用 SharePoint HTTPModule 中的筛选器拦截二进制数据会返回损坏的数据
我在 Stack Overflow 和 Google 上广泛研究了以下内容,但没有任何运气。请耐心等待我解释我想要实现的目标以及我遇到的问题。
我正在开发一个 SharePoint 2007 应用程序,该应用程序向浏览器请求的任何图像(jpg、gif、png)添加基本水印。图像是否作为“12 hive”的一部分驻留在文档库或服务器的文件系统中并不重要。 (这是正在构建的解决方案的简化,我不想让您厌倦不相关的细节)。
由于这需要与提供的任何图像一起工作,独立于可能在 SharePoint 上运行的第 3 方解决方案,我看到的唯一解决方案是编写 HTTPModule,挂钩模块的过滤器,从流中读取图像数据并替换它与图像的水印版本。无法为此使用 SharePoint 的事件接收器,并且 SharePoint 的“服务器端文件处理程序”不涵盖将此类文件传递到浏览器的所有场景。
尽管使用过滤器拦截和修改基于文本的内容效果很好,但当过滤器包含二进制数据时,自定义过滤器的 Write 方法会收到损坏的数据。在源文件中遇到 00 之前,byte[] 是正确的,所以听起来像是编码问题(二进制数据??)或者 HTTPModule 过滤器不允许二进制数据,我觉得很难相信。
奇怪的是,当 SharePoint 从服务器的文件系统读取二进制文件(图像)时,它会正确地通过我的过滤器。但是,当从 SharePoint 文档库读取二进制文件时,数据就会损坏。
为了确认这一点,我进行了以下测试:
从服务器的文件系统和 SharePoint 文档库请求 1.3MB TXT 文件工作正常。当从文件系统读取时,它会以一大块的形式到达。从文档库读取时,它以 32KB 大小的块形式到达。
过滤器可以很好地处理驻留在服务器文件系统上的 300KB 二进制映像的请求。但是,从文档库请求相同的文件会返回损坏的数据。
从文档库请求 3KB GIF 图像会返回损坏的数据。前 10 个字节没问题,之后数据就会损坏(源文件中的字节 10 是 0)
- 未启用自定义过滤器时,请求的文件始终会成功返回到浏览器。
我们的自定义过滤器的入口点是 Write 方法。传递给此方法的缓冲区中的数据已经损坏。
我知道多个 HTTPModule 是链接在一起的。我尝试将自定义模块放置在 web.config 文件中模块列表的开头和结尾,但没有任何运气
器的相关代码如下:
void context_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.Filter = new ResponseFilter(HttpContext.Current.Response.Filter);
}
HTTPModule 中用于连接过滤 ResponseFilter 类如下。请注意,除了将源数据写回输出流之外,它目前实际上没有执行任何操作。
public class ResponseFilter : Stream
{
private MemoryStream internalStream = new MemoryStream();
private Stream responseStream;
public ResponseFilter(Stream outputStream)
{
responseStream = outputStream;
}
public override void Flush()
{
responseStream.Flush();
}
public override void Write(byte[] buffer, int offset, int count)
{
internalStream.Write(buffer, offset, count);
responseStream.Write(buffer, offset, count);
}
public override void Close()
{
responseStream.Close();
}
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override long Length
{
get { return internalStream.Length; }
}
public override long Position
{
get { return internalStream.Position; }
set { internalStream.Position = value; }
}
public override int Read(byte[] buffer, int offset, int count)
{
return internalStream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin direction)
{
return internalStream.Seek(offset, direction);
}
public override void SetLength(long length)
{
internalStream.SetLength(length);
}
}
这个类远非完美,但问题是当调用 Write 方法时,缓冲区中的数据已经损坏。班上的其他人目前并不重要。
I have researched the following extensively on both Stack Overflow and Google without any luck. Bear with me while I explain what I am trying to achieve and the problem I am encountering.
I am developing a SharePoint 2007 application that adds a basic watermark to any image (jpg, gif, png) that is requested by the browser. It doesn't matter if the image resides in a document library or the server's file system as part of the '12 hive'. (This is a simplification of the solution that is being build, I don't want to bore you with the irrelevant details).
As this will need to work with any image served up, independent of the 3rd party solutions that may be running on SharePoint, the only solution I see is to write an HTTPModule, hook the Module's Filter, read the image data from the stream and replace it with the watermarked version of the image. It is not possible to use SharePoint's event receivers for this and SharePoint's 'Server side File handlers' do not cover all scenarios for delivering these kind of files to the browser.
Although intercepting and modifying text based content using a filter works just fine, when the filter contains binary data the custom filter's Write method receives corrupt data. The byte[] is correct until a 00 is encountered in the source file, so it sounds like either an encoding problem (of binary data??) or HTTPModule filters do not allow binary data, which I find hard to believe.
The weird thing is that when the binary file (image) is read by SharePoint from the server's file system then it is passed through my filter properly. However, the moment the binary file is read from a SharePoint Document Library the data is corrupted.
To confirm this I have carried out the following tests:
Requesting a 1.3MB TXT file from both the server's file system and SharePoint document library works fine. When read from the file system it arrives in one big chunk. When read from the Document library it arrives in 32KB sized chunks.
Requesting a 300KB Binary Image that resides on the server's file system is processed fine by the filter. However requesting the same file from a document library returns corrupt data.
Requesting a 3KB GIF Image from a document library returns corrupt data. The first 10 bytes are fine after which data becomes corrupt (byte 10 is a 0 in the source file)
When the custom filter is not enabled then the requested files are always returned successfully to the browser.
The entry point in our custom filter is the Write method. The data in the buffer that is passed to this method is already corrupt.
I understand that multiple HTTPModules are chained. I have tried placing my custom module both at the beginning as well as the end of the list of Modules in the web.config file, without any luck
The relevant code in the HTTPModule for hooking up the filter is as follows:
void context_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.Filter = new ResponseFilter(HttpContext.Current.Response.Filter);
}
The implementation of the ResponseFilter Class is as follows. Note that it doesn't actually do anything at the moment other than writing the source data back to the output stream.
public class ResponseFilter : Stream
{
private MemoryStream internalStream = new MemoryStream();
private Stream responseStream;
public ResponseFilter(Stream outputStream)
{
responseStream = outputStream;
}
public override void Flush()
{
responseStream.Flush();
}
public override void Write(byte[] buffer, int offset, int count)
{
internalStream.Write(buffer, offset, count);
responseStream.Write(buffer, offset, count);
}
public override void Close()
{
responseStream.Close();
}
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override long Length
{
get { return internalStream.Length; }
}
public override long Position
{
get { return internalStream.Position; }
set { internalStream.Position = value; }
}
public override int Read(byte[] buffer, int offset, int count)
{
return internalStream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin direction)
{
return internalStream.Seek(offset, direction);
}
public override void SetLength(long length)
{
internalStream.SetLength(length);
}
}
This class is far from perfect, but the problem is that the moment the Write
method is hit the data in the buffer is already corrupt. The rest of the class doesn't matter at the moment.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是一个老问题,您可能已经解决了这个问题。如果它仍然打开,您可以考虑进行测试,看看关闭缓存后替换是否可以解决损坏问题。请参阅 ASP.Net 响应筛选器与 SharePoint 2010 冲突发布站点默认值以获取更多详细信息。虽然可能性很小,但也许值得花时间进行测试。
This is an old question and you may have resolved this issue. If it's still open you might consider testing to see if turning off post-cache substitution resolves the corruption issue. See ASP.Net Response Filter Clashing with SharePoint 2010 Publishing Site Defaults for more details. It's a long shot but maybe worth the time to test.