tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
Subject Re: TC3.2.1 - response commit on included JSPs
Date Fri, 23 Feb 2001 05:13:57 GMT
> > 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.

The spec is not very clear ( IMHO ), but the comment on 
JspWriter.flush() says: 

"flush() invocation will flush all the buffers in a chain of 
Writers and OutputStreams."

The flush() on ServletOutputStream and flush() in the Writer 
are not redefined - and the

"Flushes this output stream and forces any buffered output bytes to be
written out. The general contract of flush is that calling it is an
indication that, if any bytes previously written have
been buffered by the implementation of the output stream,
such bytes should immediately be written to their intended
destination.  "

My expectation ( as a java user ) would be that if I call 
out.flush() the data will be written to the final destination.

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

The implicit flush() shouldn't be different ( unless
the special "throw exception" setting is in place ).

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

I tried flushBuffer() and it seems to work as well.

So the only question is how to interpret flush() on 

( for the flush() on OutputStream and Writer it seems 
pretty clear from the comments - and I haven't
found any mention in the servlet spec to alter the way
streams work )

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

That's easy to change. In any case - the 
ServletResponse.flushBuffer should go all the way - that's
specified in RD.include(). 

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

That's a flushBuffer() to me. 

> 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);

That should be a flushBuffer - if that's what we want,
or a flush() if we find a place where flush() is 
redefined for servlet streams 
( i.e. the Writer that is defined in the
servlet spec is not using the same definition for
flush() as )

The comment seems clear to me - all bytes should
go to their intended destination.

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


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

Or that flush() shouln't be used where the intentions 
is to not commit the response.

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

If we don't have a clear specification pointer where 
flush() is defined as "flush to the last OutputStream, but
don't flush the last stream" or "ServletOutputStream.flush()
shouldn't commit the answer, but be a noop " - I think 
we have to do that.

As I understand the spec, JspWriter.flush() will go down,
to the last writer/stream, and ServletOutputStream.flush()
is not re-defined - so OutputStream definition applys ( and 
that sounds clear ).

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

Based on the assumption that this is the correct behavior
of flush().

> 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

RequestDispatcher.include explicitely allows the included
page to commit. True - they mention ServletResponse.flush(),
but also "writing past the end of the buffer". 

I don't think changing the behavior of OutputStream.flush()
or Writer.flush() can be the correct behavior - it needs
to be explicitely done ( by overriding it in ServletOutputStream ).

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

Included resources are explicitely allowed to commit the response.


View raw message