users@grizzly.java.net

Re: CometWriter assumes Transfer-Encoding: chunked

From: Oleksiy Stashok <Oleksiy.Stashok_at_Sun.COM>
Date: Thu, 28 Jan 2010 21:05:02 +0100

Hi Richard,

I've created an issue
https://grizzly.dev.java.net/issues/show_bug.cgi?id=791
to track the issue, will look at it ASAP.

WBR,
Alexey.

On Jan 28, 2010, at 1:55 , Richard Zschech wrote:

> Hi Alexey,
>
> Below is my code. It writes "BEFORE FLUSH" to the response then
> generates 10 notifications, one every three seconds. For each
> notification it registerAsyncWrite then uses the CometWriter to
> write 1024 bytes of data.
>
> Below the code is the first TCP capture with the request and chunked
> response. You can see that it writes the "BEFORE FLUSH" chunk fine
> then the after writing the first data chunk the CometWriter sends a
> zero sized chunk. This signals to the browser that the response is
> complete. I then send another chunk of data down the response and
> everything looks fine from my codes point of view, but the browser
> ignores it as the response is complete.
>
> The second TCP capture shows the request and non-chunked response.
> You can see that it writes the "BEFORE FLUSH" without the chunk
> length 'd' fine then the CometWriter sends a '400' chunk length and
> the data followed by a zero sized chunk. This means the browser
> thinks the chunk lengths are a part of the data.
>
> From Richard.
>
> Servlet code:
>
>
> import java.io.IOException;
>
> import javax.servlet.ServletConfig;
> import javax.servlet.ServletException;
> import javax.servlet.http.HttpServlet;
> import javax.servlet.http.HttpServletRequest;
> import javax.servlet.http.HttpServletResponse;
>
> import com.sun.grizzly.comet.CometContext;
> import com.sun.grizzly.comet.CometEngine;
> import com.sun.grizzly.comet.CometEvent;
> import com.sun.grizzly.comet.CometHandler;
> import com.sun.grizzly.comet.CometWriter;
>
> public class GrizzlyServlet extends HttpServlet {
>
> private String topic;
> private CometEngine cometEngine;
> private CometContext cometContext;
>
> @Override
> public void init(ServletConfig config) throws
> ServletException {
> topic = config.getServletContext().getContextPath();
> cometEngine = CometEngine.getEngine();
> cometContext = cometEngine.register(topic);
> cometContext.setExpirationDelay(-1);
> }
>
> @Override
> public void destroy() {
> cometEngine.unregister(topic);
> }
>
> protected void doGet(HttpServletRequest request,
> HttpServletResponse response) throws ServletException, IOException {
> response.getWriter().append("BEFORE FLUSH\n");
> response.getWriter().flush();
> final CometHandlerImpl handler = new
> CometHandlerImpl();
> handler.attach(response);
> cometContext.addCometHandler(handler);
> new Thread() {
> @Override
> public void run() {
> try {
> for (int i = 0; i < 10; i++) {
> Thread.sleep(1);
>
> System.out.println("Notifying");
>
> cometContext.notify(null, handler);
> Thread.sleep(3000);
> }
> }
> catch (InterruptedException e) {
> e.printStackTrace();
> }
> catch (IOException e) {
> e.printStackTrace();
> }
> }
> }.start();
> }
>
> private class CometHandlerImpl implements
> CometHandler<HttpServletResponse> {
> private HttpServletResponse response;
>
> volatile int index = 0;
> int size = 1 << 10;
> byte[] bytes = new byte[size];
>
> public CometHandlerImpl() {
> for (int i = 0; i < size - 1; i++) {
> bytes[i] = (byte) (i % 26 + 'A');
> }
> bytes[size - 1] = (byte)'\n';
> }
>
> public void attach(HttpServletResponse response) {
> this.response = response;
> }
>
> public void onInitialize(CometEvent event) throws
> IOException {
> System.out.println("onInitialize");
> }
>
> public void onInterrupt(CometEvent event) throws
> IOException {
> System.out.println("onInterrupt");
> }
>
> public void onTerminate(CometEvent event) throws
> IOException {
> System.out.println("onTerminate");
> }
>
> public void onEvent(CometEvent event) throws
> IOException {
> System.out.println("onEvent " +
> event.getType() + " " + event.attachment());
> if (event.getType() == CometEvent.NOTIFY) {
> System.out.println("Register " +
> index);
> index = 0;
> cometContext.registerAsyncWrite(this);
> }
> else if (event.getType() == CometEvent.WRITE) {
> CometWriter writer = (CometWriter)
> event.attachment();
>
> int write;
> while ((write = writer.write(bytes,
> index, bytes.length - index)) > 0) {
> System.out.println("Written "
> + write);
> index += write;
> if (index == bytes.length) {
> return;
> }
> }
> System.out.println("Register " +
> index);
> cometContext.registerAsyncWrite(this);
> }
> }
> }
> }
>
>
> TCP capture with chunked response:
>
>
> GET /grizzly HTTP/1.1
> Host: 10.66.5.53:8080
> User-Agent: Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.1.11)
> Gecko/20080118 Firefox/2.0.0.11
> Accept: text/xml,application/xml,application/xhtml+xml,text/
> html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
> Accept-Language: en-us,en;q=0.5
> Accept-Encoding: gzip,deflate
> Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
> Keep-Alive: 300
> Connection: keep-alive
> HTTP/1.1 200 OK
> X-Powered-By: Servlet/3.0
> Server: GlassFish v3
> Transfer-Encoding: chunked
> Date: Thu, 28 Jan 2010 00:37:19 GMT
> d
> BEFORE FLUSH
>
> 400
> ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR
> STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI
> 0
> 400
> ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR
> STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI
> 0
>
> 400
> ......
>
>
> TCP capture with non-chunked response:
>
>
> GET /grizzly HTTP/1.1
> Host: 10.66.5.53:8080
> HTTP/1.1 200 OK
> X-Powered-By: Servlet/3.0
> Server: GlassFish v3
> Date: Thu, 28 Jan 2010 00:49:32 GMT
> Connection: close
>
> BEFORE FLUSH
> 400
> ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR
> STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI
> 0
>
> 400
> ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR
> STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI
> 0
>
> 400
> ......
>
>
>
>
>
> Hi Richard,
>
> can you pls. attach the code you're using to send Comet response?
>
> Thank you.
>
> WBR,
> Alexey.
>
> On Jan 22, 2010, at 2:49 , Richard Zschech wrote:
>
> > Hi Alexey,
> >
> > If GlassFish decides to use "Connection: close" to signal the end of
> > the HTTP response with the socket disconnecting rather than with
> > chunks the CometWriter should not ouput the chunk length
> information.
> >
> > The example I have GlassFish responds with:
> >
> > HTTP/1.1 200 OK
> > X-Powered-By: Servlet/3.0
> > Server: GlassFish v3
> > Cache-Control: no-cache
> > Content-Type: text/plain;charset=UTF-8
> > Date: Fri, 22 Jan 2010 01:33:39 GMT
> > Connection: close
> >
> > 5
> > ABCDE
> > 0
> >
> > where I’ve written "ABCDE" to the CometWriter, 5 and 0 are the chunk
> > lengths, but because the Transfer-Encoding is not chunked then the 5
> > and 0 are interpreted as a part of the response data.
> >
> > It should be:
> >
> > HTTP/1.1 200 OK
> > X-Powered-By: Servlet/3.0
> > Server: GlassFish v3
> > Cache-Control: no-cache
> > Content-Type: text/plain;charset=UTF-8
> > Date: Fri, 22 Jan 2010 01:33:39 GMT
> > Connection: close
> >
> > ABCDE
> >
> >
> >
> > Another problem I’m having is the CometWriter assumes that you are
> > only going to write one chunk to the HTTP response. It writes the 0
> > length chunk to the response to terminate it. Can this be
> configured?
> >
> > From Richard.
> >
> >
> > > Hi Richard,
> > >
> > > > CometWriter assumes that the HTTP response is using "Transfer-
> > > > Encoding: chunked".
> > > >
> > > > In some cases Glassfish decides to respond with "Connection:
> > close"
> > > > where the user agent detects the end of the HTTP response from
> the
> > > > connection closing rather than using HTTP keep alive and
> > chunking .
> > > Can you pls. elaborate? Not sure I understand why "Connection:
> > close"
> > > causes issue?
> > >
> > > Thank you.
> > >
> > > WBR,
> > > Alexey.
> >
>