tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Mel Martinez <melaqu...@yahoo.com>
Subject Re: TC3.2.1 - response commit on included JSPs
Date Fri, 23 Feb 2001 04:02:37 GMT

--- cmanolache@yahoo.com wrote:
> 
> > Second, while there is a flushBuffer() method in
> > JspWriterImpl, this method is NOT a part of the
> > javax.servlet.jsp.JspWriter interface nor is it
> public
> > (it is protected).
> 
> We can make it public - and the generated servlets
> already depends
> on jasper runtime.
> 
> The problem is that flush() must still be executed
> as expected,
> i.e. if an included JSP or servlet is actually
> calling flush(),
> it expects the response to be commited. 
> 

But does that necessarily mean to commit it to the
browser?  Or should it instead just commit it to the
buffer of the calling page (which is the actual
'client' here)?  I think it is the latter case that is
correct.

> It is possible to disable commit when a servlet/jsp
> is included,
> but then we disable a reasonable function (explicit
> flush() ).
> Or we can disable the commit just before the
> final/implicit out.flush()
> - but again we need an explicit API call.
> 
> 
> > Where trouble is probably being caused is that
> when
> > flush is being called it also calls
> > response.flushBuffer() both directly as well as
> > indirectly (through cascaded out.flush() calls). 
> If
> > we can prevent that from happening in the
> 'included'
> > case, perhaps that would be enough to fix the
> problem?
> 
> Then how do you distinguish explicit flush() calls ?
> And the spec for flush() is clear IMHO - it should
> propagate
> and commit the response. 
> 

This may be correct for streams in general, but if
adhered to in servlet-servlet communication, then we
have to re-think the way we use flush().

Aside from the question of what an explicit flush()
should do, one also has to worry about what should
happen when the buffer of the underlying stream simply
fills up, forcing an implicit flush.

> 
> I'll try to commit some changes tonight. I'm going
> to try
> with the flushBuffer() - it seems to me this is the
> right 
> way to do it ( and you can still do explicit flush()
> inside an 
> included jsp and get the expected behavior )
> 

I tried the change I suggested, which is to change
JspWriterImpl.flush() to (essentially):

 public void flush(){
   flushBuffer();
   if(out!=null && !isIncluded){
     out.flush();
     response.flushBuffer();
   }
 }

which effectively makes this equivalent to your
suggestion of replacing the use of out.flush() in the
finally{..} with out.flushBuffer().  I'll grant that
if we accept that flush() must always propagate then
the above solution is not 'elegant'.  However, it does
work just as well.  And it at least tries to adhere to
the principal that included servlets should not commit
the response.

Neither solution completely blocks an included servlet
from flushing the parent stream because as currently
written flushBuffer() can still end up flushing the
stream if it writes enough bytes to the underlying
stream to overfill it's buffer, causing an implicit
flush().

This could be prevented by rewriting flushBuffer(),
but I can't do that in my scheme because for some
reason it is declared 'final' in the current code.

Before I go, I want to cast a light on some other
misbehavior in this area.  From the JSP 1.1 spec,
section 2.13.4, paragraph 6, on dynamic includes:

"If the page output is buffered then the buffer is
flushed prior to the inclusion."

The current jasper code in tc3.2.1 implements
jsp:include using PageContextImpl.include() which
simply does:

 String path =
       getAbsPathRelativeToContext(relativeUrlPath);
 out.flush();
 context.getRequestDispatcher(path).include(
                          request, response);

As it stands, this will always commit the response
prior to the include.  This is not a problem for the
include, per se, but this is not what performing an
include should do because it alters the commit state
of the current page's response object.

In other words, the use of out.flush() (as currently
defined) just prior to the include means you can not
do something like so:

....
<jsp:include page="/somepage.jsp" flush="true" />
....
<%
  response.sendRedirect("http://somewhere");
%>

This breaks even if neither the current page or the
included page have actually written anything to the
stream simply because out.flush() is committing the
response prematurely.

So the core problem remains that flush() should NOT
commit the response.

As before, replacing the use of out.flush() in
PageContextImpl.include() with just the functionality
of out.flushBuffer() fixes the problem with the same
exception of the case where the amount of output
written to the underlying servletoutputstream causes
an implicit flush.

The solution you seem to favor is to make
JspWriterImpl.flushBuffer() public and then changing
the generated servlet code to have:

}finally{
  ((JspWriterImpl)out).flushBuffer();
  ...
}

and to similarly replace the out.flush() in
PageContextImpl.include().

This still would allow an explicit flush() or a buffer
overflow to commit the response.

I guess I'd be okay with that solution, but I'm not
sure I'm convinced that even an explicit flush() from
an included resource should commit the response.  It
just seems counter-intuitive for a 'child' page that
I'm including to be able to change the commit state of
my response object.  Technically, why shouldn't I be
able to call response.clearBuffer() after an include,
should I decide that the result of the include is not
what I wanted?

Note that the concept I'm getting at is already
expressed in the nested 'BodyContent' writers which
are not allowed to flush their parents.  I believe
that included resources need to somehow be treated the
same way.

I'm beginning to think that ultimately, the correct
way to do this is to have the underlying
ServletOutputStream not obey a flush() unless it is
delivered via response.flushBuffer() at the top-most
request level (i.e. not in an include).

Cheers,

Mel

Cheers,

Mel

__________________________________________________
Do You Yahoo!?
Yahoo! Auctions - Buy the things you want at great prices! http://auctions.yahoo.com/

Mime
View raw message