简体   繁体   中英

Using a Filter in SharePoint HTTPModule to intercept binary data returns corrupt data

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:

  1. 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.

  2. 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.

  3. 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)

  4. When the custom filter is not enabled then the requested files are always returned successfully to the browser.

  5. 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.

  6. 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM