Permission Issues With 1.7 and 1.8 and Medium Trust Support

Jul 11, 2009 at 9:49 PM
Edited Jul 11, 2009 at 10:36 PM

Hi, I am attempting to execute the following code using the DotNetZip Library versions v1.7 and v1.8:

Protected Sub CreateAlbumZipFile(ByVal Context As HttpContext)

        Try

            Context.Response.AddHeader("Content-Disposition", "attachment; filename=test.zip")
            
            ' Create the Album Zip File
            Dim AlbumZipFile As ZipFile = New ZipFile()

            ' Specify a temporary folder when creating the ZipFile if needed (must be a location that exists and is writable by the website)
            AlbumZipFile.TempFileFolder = HttpContext.Current.Server.MapPath(TempLocation)

            ' Add single item to zip file
            AlbumZipFile.AddFile(HttpContext.Current.Server.MapPath(AlbumLocation & "ContentID_1962.Orig.jpg"), "")

            ' Saves the Zip File (use the Response.OutputStream)
            AlbumZipFile.Save(Context.Response.OutputStream)
                
            Context.Response.End()

            AlbumZipFile.Dispose()

        Catch ex As Exception
            
        End Try

    End Sub

To simulate my shared hosting environment I have set my trust level to "Medium" in the Web.config.

If I use the DotNetZip Library v1.7 an exception is raised on the Context.Response.End() call:

    "System.Threading.ThreadAbortException"

But, the ZipFile is still successfully sent to the user.

If I use the DotNetZip Library v1.8 an exception is raised on the AlbumZipFile.Save(Context.Response.OutputStream) call:

    "Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed."

The only change I made was to remove version v1.7.2.26 and replace it with v1.8.4.5 of Ionic.Zip.dll in my WebSite's Bin folder.  I then restarted the web app and retested.

Other notes:

  • I am creating the zip file in memory and streaming it to the Response.OutputStream when having problems
  • v1.6 works fine (requires some minor code changes) but does not provide the FileName rename feature I would like to use for better performance when I have to create a ZipFile containing files with different names than the originals
  • v1.7 works fine if you create the zip first and save it to a file and later send that file via a Response.TransmitFile(pathname)
  • Using VS.NET 2005

So, I am wondering if we truely have "Medium Trust" support with v1.7 and v1.8 like we appear to have with v1.6.

Thanks for your help!

Coordinator
Jul 11, 2009 at 10:50 PM

I think you can avoid the thread abort Exception if you don't call Response.End(). 

You can call Context.ApplicationInstance.CompleteRequest() instead.  See this KB Article for info:  http://support.microsoft.com/kb/312629 

As for v1.8 - ... I don't know why it would fail like that.  It is marked APTC, which means it should work, and of course I test that case - saving a zip file directly to the ASP.NET Response output stream under medium trust - regularly. 

Are you running your website from a network share or a mapped drive?

Do you have a complete stack trace of the SecurityPermission error?  That would help me track it down very quickly.

Thanks

 

Jul 11, 2009 at 11:31 PM

Hi,

Thanks for the quick response and thanks for the information about CompleteRequest().  Good to know.

Here is the complete stack trace:

   at Ionic.Zip.SharedUtilities.ReadWithRetry(Stream s, Byte[] buffer, Int32 offset, Int32 count, String FileName)
   at Ionic.Zip.ZipEntry._WriteFileData(Stream s)
   at Ionic.Zip.ZipEntry._EmitOne(Stream outstream)
   at Ionic.Zip.ZipEntry.Write(Stream s)
   at Ionic.Zip.ZipFile.Save()
   at Ionic.Zip.ZipFile.Save(Stream outputStream)
   at VirtualZipFileFetch.CreateAlbumZipFile(HttpContext Context)

 Let me know if you need anything else!

Coordinator
Jul 12, 2009 at 4:21 AM

Ah, yes, that ReadWithRetry method is new for v1.8.     I will have to look at it further.

Coordinator
Jul 12, 2009 at 1:28 PM

The problem you're having with v1.8 - Is it easily reproducible?  Does it happen every time, with any set of files you try to zip?   Or are there particular files that cause the problem?

Can you run with the debug library (and the Ionic.Zip.PDB in the bin directory) so that your stacktrace includes line numbers?

It looks like what's happening is, your save is getting an exception while reading one of the files during compression.  That exception is caught, and in the handler, the code attempts to get the HRESULT that is embedded in the exception. This requires unmanaged code, which throws the SecurityPermission error. This is a guess on my part.

If you can repro the problem readily, and don't mind working through this with me, I could provide an updated v1.8 binary for you to test, to verify that I've fixed the problem.

Coordinator
Jul 12, 2009 at 1:52 PM

ps: Just a tip: in either v1.7 or v1.8, when saving to a stream, like Response.OutputStream, you don't need to set TempFileFolder. There is no temp file produced when saving to a stream.  Also in v1.8, you shouldn't need to set TempFileFolder ever.  As I said, it isn't used when saving to a stream, and when saving to a file, DotNetZip has been changed to create the temp file in the same folder as the final file.  So in v1.8, the TempFileFolder property becomes unnecessary.

Jul 12, 2009 at 2:42 PM
Edited Jul 12, 2009 at 10:08 PM

Hi,

Yes, the problem is consistantly reproducible.  I have switched the testcase to different jpgs and they all reproduce the problem.  I remember you saying that the TempFileFolder was not needed from another post but I just wanted to set it since I had been using it in v1.6 and earlier and wanted to make sure that the problem was not related in some way.  I have updated the testcase to the following and I am still able to reproduce the problem with the same stack:

        Try

            Context.Response.AddHeader("Content-Disposition", "attachment; filename=test.zip")
    
            ' Create the Album Zip File
            Dim AlbumZipFile As ZipFile = New ZipFile()

            ' Specify the temporary folder when creating the AlbumZipFile (must be a location that exists and is writable by the website)
            'AlbumZipFile.TempFileFolder = HttpContext.Current.Server.MapPath(TempLocation)

            ' Add single item to zip file
            AlbumZipFile.AddFile(HttpContext.Current.Server.MapPath(AlbumLocation & "ContentID_162.Orig.jpg"), "")

            ' Saves the Album Zip File (writes the Zip File to the Response.OutputStream)
            AlbumZipFile.Save(Context.Response.OutputStream)

            AlbumZipFile.Dispose()
        
            Context.Response.End()

        Catch ex As Exception
    
        End Try

The stack trace is still

   at Ionic.Zip.SharedUtilities.ReadWithRetry(Stream s, Byte[] buffer, Int32 offset, Int32 count, String FileName)
   at Ionic.Zip.ZipEntry._WriteFileData(Stream s)
   at Ionic.Zip.ZipEntry._EmitOne(Stream outstream)
   at Ionic.Zip.ZipEntry.Write(Stream s)
   at Ionic.Zip.ZipFile.Save()
   at Ionic.Zip.ZipFile.Save(Stream outputStream)
   at VirtualZipFileFetch.CreateAlbumZipFile(HttpContext Context)

But, I dont see any line numbers associated with the stack trace.  I have placed Ionic.Zip.dll and Ioniz.Zip.pdb from DotNetZipLib-DevKit-v1.8\DotNetZip-v1.8\Debug into my WebSite's Bin folder.  I left the Ionic.Zip.XML file alone.  Is that needed as well?

It did ask me to point to the source code file DotNetZip-src-v1.8.4.5\DotNetZip\Zip Partial DLL\ZipFile.cs if I put a break point on the call to AlbumZipFile.Save(Context.Response.OutputStream).  It steps into the code in ZipFile.cs at line 3928:

public void Save(Stream outputStream)

Following the stack of calls I then stepped through the code until it came to the call to ReadWithRetry.  I got to line 4184 of ZipEntry.cs but never saw the debugger step into the call to ReadWithRetry here:

4178      while ((n = SharedUtilities.ReadWithRetry(input1, buffer, 0, buffer.Length, FileName)) != 0)
                {
                    output2.Write(buffer, 0, n);
                    OnWriteBlock(input1.TotalBytesSlurped, fileLength);
                    if (_ioOperationCanceled)
                        break;
4184      }

The call stack window looked like this at this point:

>	Ionic.Zip.DLL!Ionic.Zip.ZipEntry._WriteFileData(System.IO.Stream s = {Ionic.Zip.CountingStream}) Line 4184 + 0x1 bytes	C#
 	Ionic.Zip.DLL!Ionic.Zip.ZipEntry._EmitOne(System.IO.Stream outstream = {Ionic.Zip.CountingStream}) Line 4531 + 0xb bytes	C#
 	Ionic.Zip.DLL!Ionic.Zip.ZipEntry.Write(System.IO.Stream s = {Ionic.Zip.CountingStream}) Line 4495 + 0xb bytes	C#
 	Ionic.Zip.DLL!Ionic.Zip.ZipFile.Save() Line 3678 + 0x2a bytes	C#
 	Ionic.Zip.DLL!Ionic.Zip.ZipFile.Save(System.IO.Stream outputStream = {System.Web.HttpResponseStream}) Line 3940 + 0x8 bytes	C#
 	App_Web_870ybjh0.dll!VirtualZipFileFetch.CreateAlbumZipFile(System.Web.HttpContext Context = {System.Web.HttpContext}) Line 327 + 0x2d bytes	Basic
 	App_Web_870ybjh0.dll!VirtualZipFileFetch.ProcessRequest(System.Web.HttpContext Context = {System.Web.HttpContext}) Line 33 + 0xe bytes	Basic

It then jumps into the finally block on 4203 as it appears the exception is raised at this point.  I am not sure why I cannot step into the call ReadWithRetry at this point.  If you have any ideas on what I may be doing wrong or how to get the call stack you are looking for, please let me know.

Thanks.

Coordinator
Jul 12, 2009 at 5:17 PM
Edited Jul 12, 2009 at 5:19 PM

yes, I think I have some insight into what's happening. and maybe how to avoid the problem.  I think you might be good-to-go with v1.7, assuming you are no longer calling Response.End().  But I would like you to keep trying v1.8 if you are willing.

In a while, I'll put up a temporary assembly and ask you to try it. 

Coordinator
Jul 12, 2009 at 5:20 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Jul 13, 2009 at 6:36 PM

Unfortunately the same problem occurred with the test build.  I think the pdb file no longer matches the source I am using so stepping through the source did not seem to match the correct line numbers.

Coordinator
Jul 13, 2009 at 10:02 PM

Thanks for trying it.  Yeah, the source has changed.

It would be easier if I could reproduce the problem here.  I don't know why I cannot.

I have to think about this some more, to figure out a good way to test and debug it.

Jul 14, 2009 at 3:56 AM

If you want, I think I could put together a VS.NET 2005 Web App that does nothing more than reproduce this problem with v1.8 and would run under the ASP.NET Development Server that comes with VS.NET.  Let me know if you think that would help.

Coordinator
Jul 14, 2009 at 12:45 PM

Ah, thank you for the offer.  I have exactly that right here, trust=medium, and so on, but it is not generating the problem.

I don't think it is a matter of the ASP.NET code. It is more likely something to do with the server configuration, the directory permissions, the security groups, and I'm not looking forward to getting all that just right. Too many different combinations to try. I have to think about it some more.

Coordinator
Jul 20, 2009 at 5:23 PM

I've reproduced the problem you reported and I believe I've fixed it. 

I'd like you to download v1.8.4.8 and verify that it's fixed for you.  It's available now.

Jul 20, 2009 at 11:17 PM

Hi Cheeso,

I just tested v1.8.4.8 and it appears to be working great!  Not sure what you had to change but whatever it was, it has made the difference.  I am going to perform some more thorough testing but it looks like its fixed.

Thanks!

Jul 21, 2009 at 4:30 AM

Hi Cheeso,

I performed some pretty thorough testing regarding my web applications functionality based on zip files and it passed with flying colors!

Wanted to let you know how much I appreciate the help and resolution of this issue.  Not only is this a great library that is easy to use with a rich set of functionality that gives my application another dimension via the DotNetZip Library, but most importantly, the support you provide is top notch!  Simply exceptional!

As a small token of my appreciation I will be making a donation.

Thanks again,

-DBall

Coordinator
Jul 21, 2009 at 12:27 PM

Super, glad to hear it's working,

and thanks for the donation!  Very generous of you.   It's much appreciated.