Why is CloseDelegate called twice?

Mar 21, 2010 at 6:41 PM

I'm trying to port Fiddler to DotNetZip from the Xceed library.  However, I'm having a problem with the AddEntry(string, OpenDelegate, CloseDelegate) method. Specifically, sometimes my close delegate is getting called twice (but Open is called only once), and that leads to an exception.  Any idea why this might happen?

thanks for any tips!

** LogString: Open response: raw/0032_s.txt
** LogString: Close response: raw/0032_s.txt
** LogString: Open response: raw/0033_s.txt
** LogString: Close response: raw/0033_s.txt
** LogString: Open response: raw/0034_s.txt
** LogString: Close response: raw/0034_s.txt
** LogString: Open response: raw/0035_s.txt
** LogString: Close response: raw/0035_s.txt
** LogString: Close response: raw/0035_s.txt
** LogString: WriteSessionArchive skipped writing raw/0035_s.txt to C:\Users\eri
claw\Desktop\11-36-47.saz because Cannot access a closed Stream.;
   at System.IO.MemoryStream.set_Position(Int64 value)
   at Ionic.Zip.ZipEntry.PrepSourceStream()
   at Ionic.Zip.ZipEntry.SetInputAndFigureFileLength(Stream& input)
   at Ionic.Zip.ZipEntry._WriteEntryData(Stream s)
   at Ionic.Zip.ZipEntry._EmitOne(Stream outstream)
   at Ionic.Zip.ZipEntry.Write(Stream s)...

My code is pretty simple:

oZip.AddEntry(sResponseFilename,
                        new OpenDelegate(delegate(string sn)
                        {
                            FiddlerApplication.Log.LogString("Open response: " + sn);
                            MemoryStream strmResponse = new MemoryStream();
                            if (!delegatesCopyOfSession.WriteResponseToStream(strmResponse, false))
                            {
                                FiddlerApplication.Log.LogString("Failed write!");
                            }
                            strmResponse.Position = 0;
                            return strmResponse;
                        }),
                        new CloseDelegate(delegate(string sn, Stream strmResponse)
                        {
                            FiddlerApplication.Log.LogString("Close response: " + sn);
                            if (null != strmResponse) strmResponse.Close();
                        })
                    ); 

Coordinator
Mar 23, 2010 at 5:46 PM

Hmmm, that's a surprise!

It's possible that the compression algorithm actually causes an increase in data size.  That can happen for a small file, where the compression dictionary is larger than the data to be compressed.  There's logic in DotNetZip that compares the size of the compressed stream with the size of the uncompressed stream, and if the former is larger, then DotNetZip will re-read the stream and store it uncompressed. 

I just looked at the code and saw the problem.  When a stream provided by an open delegate results in an expansion, and the re-read happens, DotNetZip fails to re-open the stream. (Fails to call the OpenDelegate again). 

Looks like a one-line fix.  I'll make a build ready for you to test in a few minutes.

 

Coordinator
Mar 23, 2010 at 5:47 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Coordinator
Mar 23, 2010 at 5:52 PM
Edited Mar 23, 2010 at 5:53 PM

ok, a patched version of the DLL is available on that workitem.  (http://dotnetzip.codeplex.com/WorkItem/View.aspx?WorkItemId=10489 )

Try it out and let me know.

ps; I love Fiddler.  Excellent tool.

 

Mar 23, 2010 at 11:44 PM

Thanks a bunch!  Turns out that the WriteDelegate version worked super-well for my needs, but I'll give your new bits a shot!

Coordinator
Mar 24, 2010 at 5:30 PM

Great, I'll be interested in what you find.

ps: I used fiddler today to work on a rewriting filter/proxy - IIRF - also on codeplex.  I needed to diagnose some problems with the proxy behavior. Fiddler is indispensable.