Bug 1233253 - [GSS](6.4.z) DataSourceProvider produces FileNotFoundException upon second call of getInputStream()
Summary: [GSS](6.4.z) DataSourceProvider produces FileNotFoundException upon second ca...
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: JBoss Enterprise Application Platform 6
Classification: JBoss
Component: RESTEasy
Version: 6.4.0
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: CR2
: EAP 6.4.3
Assignee: Dmitrii Tikhomirov
QA Contact: Katerina Odabasi
URL:
Whiteboard:
Depends On:
Blocks: 1231259 1233546 1238542 1248917
TreeView+ depends on / blocked
 
Reported: 2015-06-18 14:31 UTC by William Antônio
Modified: 2019-07-11 09:25 UTC (History)
9 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2017-01-17 10:43:23 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Issue Tracker RESTEASY-1182 0 Major Closed DataSourceProvider produces FileNotFoundException upon second call of getInputStream() 2016-08-02 16:15:20 UTC

Description William Antônio 2015-06-18 14:31:14 UTC
Description of problem:

The fix for RESTEASY-1080 introduced another bug. If the DataSourceProvider uses a temporary file and the InputStream returned by getInputStream() is read until the end, any further call to getInputStream() results in a FileNotFoundException.

The SequenceDataSource used in the DataSourceProvider deletes the temporary file when it has been read until the end. When getInputStream() is called after the temporary file has been deleted new FileInputStream(tempFile) in getInputStream() results in a FileNotFoundException.

The javadoc of javax.activation.DataSource.getInputStream() however states:

    ... Note that a new InputStream object must be returned each time this method is called, and the stream must be positioned at the beginning of the data.

(http://docs.oracle.com/javase/7/docs/api/javax/activation/DataSource.html#getInputStream())

Version-Release number of selected component (if applicable):


How reproducible:
Always

Steps to Reproduce:
1. Create a JAX-RS resource that receives a DataSource as parameter
2. Read the input stream twice in the JAX-RS body.

Actual results:
FileNotFoundException is thrown.

Expected results:

No error since the documentation says it could be read twice.

Additional info:

Comment 2 JBoss JIRA Server 2015-06-19 06:59:43 UTC
Bartosz Baranowski <bbaranow> updated the status of jira RESTEASY-1182 to Coding In Progress

Comment 8 Rostislav Svoboda 2015-07-15 07:17:31 UTC
Ron, are you OK with finalize() block approach ?

Comment 9 baranowb 2015-07-15 07:28:48 UTC
if this is deemed a 'no good' I can probably hack that scanner, but it does not seem a good idea, it just adds configuration complexity.

Comment 10 Ron Sigal 2015-07-23 01:08:35 UTC
Hi Bartosz,

I'm sorry I forgot about this bz. I think I saw finalize() and had a Monty Python moment: "Run away, run away". 

There are two resources that should be eliminated:

 1. any system resources associated with the InputStream, handled by InputStream.close(), and

 2. the temporary file.

We leave the responsibility for calling close() to the user, and failing to call close() would be considered a bug. So why not do something like this:

     public InputStream getInputStream() throws IOException
      {
         InputStream bis = new ByteArrayInputStream(byteBuffer, byteBufferOffset, byteBufferLength);
         if (tempFile == null)
            return bis;
         InputStream fis = new FileInputStream(tempFile);
         return new SequenceInputStream(bis, fis) {
            @Override
            public void close() throws IOException
            {
               super.close();
               deleteTempFile();
            }
         };
      }

1. We are handing the responsibility for removing the temp file back to the user in a way that seems reasonable.

2. We could still have the finalize() method as a back up.

3. Having said all that, I think it's a good thing to clean up the temp file, but I'm not sure how terrible it is to not clean it up, given that it's going into a temporary file directory.

-Ron

Comment 11 baranowb 2015-07-23 04:42:04 UTC
Well, problem here is that getInputStream must return new instance of IS that is positioned at the beginning of the data:
{quote}
This method returns an InputStream representing the data and throws the appropriate exception if it can not do so. Note that a new InputStream object must be returned each time this method is called, and the stream must be positioned at the beginning of the data.
{quote}

So the trick with IS.close+deleteTMP file will work as long as users make sure:
 - they will call it eventually
 - call happens 


Trick with that is if:
 - call happens to soon, we violate specs
 - call does not happen, we have a leak


So with this one, its lesser evil. Either we violate specs or have leak which either we can:
 - leave
 - use deleteOnExit() and kill server/JVM

None of those is a good choice.

Comment 12 Ron Sigal 2015-07-23 16:35:59 UTC
Hi Bartosz,

You're right. Nothing I said made any sense.

I'm thinking a reasonable approach is to tie these temporary files to the servlet request lifecycle, i.e., solution 3) in the list given above. I'll have to look at the code to see just how to do it, but maybe it's not too complicated.

-Ron

Comment 13 Ron Sigal 2015-07-24 04:38:09 UTC
I'm playing with defining a Cleanable interface, a Cleanables class with a set of Cleanable's, adding Cleanables.class to the context map, defining an extension of SequenceInputStream that implements Cleanable, etc, etc. SynchronousDispatcher.pushContextObjects() puts Cleanables in the map and SynchronousDispacher.clearContextData() gets all the Cleanables and calls clean() on all of them. DataSourceProvider adds the CleanableSequenceInputStream to the Cleanables object in the context map. CleanableSequenceInputStream.clean() calls deleteTempFile().

So far, it's working, but I want to do more testing.

Comment 14 baranowb 2015-07-24 05:11:28 UTC
Ha, did not know this was possible here. Seems best choice so far.

Comment 26 JBoss JIRA Server 2015-08-03 20:33:15 UTC
Ron Sigal <ron.sigal> updated the status of jira RESTEASY-1182 to Resolved

Comment 27 JBoss JIRA Server 2015-08-03 20:33:22 UTC
Ron Sigal <ron.sigal> updated the status of jira RESTEASY-1182 to Closed

Comment 28 Katerina Odabasi 2015-08-07 13:01:36 UTC
Verified in EAP 6.4.3.CP.CR2.

Comment 29 JBoss JIRA Server 2015-11-12 16:40:38 UTC
Katerina Novotna <kanovotn> updated the status of jira RESTEASY-1182 to Reopened

Comment 32 JBoss JIRA Server 2015-12-16 10:39:42 UTC
Weinan Li <weli> updated the status of jira RESTEASY-1182 to Resolved

Comment 35 JBoss JIRA Server 2016-08-02 16:15:21 UTC
Alessio Soldano <asoldano> updated the status of jira RESTEASY-1182 to Closed

Comment 36 Petr Penicka 2017-01-17 10:40:55 UTC
Retroactively bulk-closing issues from released EAP 6.4 cummulative patches.

Comment 37 Petr Penicka 2017-01-17 10:41:12 UTC
Retroactively bulk-closing issues from released EAP 6.4 cumulative patches.

Comment 38 Petr Penicka 2017-01-17 10:43:23 UTC
Retroactively bulk-closing issues from released EAP 6.4 cumulative patches.


Note You need to log in before you can comment on or make changes to this bug.