Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4314224
Votes 0
Synopsis NT buffers *input* over URL connection
Category java:classes_net
Reported Against kestrel-rc1
Release Fixed
State 11-Closed, duplicate of 4333920, bug
Priority: 3-Medium
Related Bugs 4333920
Submit Date 20-FEB-2000
Description




2/6/2000   xxxxx@xxxxx   -- even with a 1.2.2 client, the messages arrive all at once.  Is this just a matter of flushing a buffer at the servlet end?
(please see Comments section)

java version "1.3.0rc1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0rc1-T)
Java HotSpot(TM) Client VM (build 1.3.0rc1-S, mixed mode)


This might be a java.io issue.

My app sends a request to a servlet, the servlet responds every few seconds
with a status message, and then sends the replay.  On 1.2.2 everything was
fine, but in 1.3 the whole output, including status messages, appears at once.

The following example has two parts, a server part and a client part.  The
server part is a servlet for JSDK2.0.  I run it on  customer , however, these seems
irrelevant since it works on all 1.2.2 clients.

The servlets sends 10 short message every two seconds after the connection has
been established.

The client piece (after the obvious adjustments) will contact the server and
should reads the messages when they are sent.  Instead, all messages are read
on once.

I have not done extensive impact studies yet, but my guess is that on
transactions that task a long time, the client will timeout.

Servlet code
============

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public final class TestServlet extends HttpServlet {
	
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
	}
	public void doPost (HttpServletRequest request, HttpServletResponse
response) throws ServletException {
		try {
			response.setContentType("text/html");
			
			InputStream is = request.getInputStream();
			byte[] buffer = new byte[5];
			is.read(buffer);
			System.out.println(new String(buffer));
			
			OutputStream os = response.getOutputStream();
			for (int i = 0; i < 10; i++) {
				String text = "Test " + i;
				os.write(text.getBytes());
				os.flush();
				Thread.sleep(2000);
			}
			is.close();
			os.close();
		}
		catch (Exception e) {
			e.printStackTrace(System.out);
		}
	}
}

client code
===========
import javax.swing.*;
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;

public final class ConnectDelay extends JFrame {
	JTextField field = new JTextField(20);
	JPanel panel;
	public static void main(String argv[]) {
		ConnectDelay app = new ConnectDelay();
	}
	public ConnectDelay() {
		super("Connection Test");
		panel = new JPanel();
		panel.add(new JLabel("Message:"));
		panel.add(field);
		getContentPane().add(panel);
		pack();
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		show();
		runTest();
	}
	public void runTest() {
		try {
			byte[] buffer = new byte[6];
			URL url = new URL
("http://idgiot.dev.donnell.com/servlets/TestServlet");
			HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
			connection.setUseCaches(false);
			connection.setRequestMethod("POST");
			connection.setAllowUserInteraction(true);
			connection.setDoOutput(true);
			OutputStream os = connection.getOutputStream();
			os.write("Hello".getBytes());
			os.close();
			InputStream is = connection.getInputStream();
			int length = is.read(buffer);
			while (length != -1) {
				String text = new String(buffer);
				field.setText(text);
				System.out.println(text);
				Rectangle rect = field.getBounds();
				panel.paintImmediately
(rect.x,rect.y,rect.width,rect.height);
				length = is.read(buffer,0,6);
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
}

-----------------------


(Review ID: 100647) 
======================================================================
Work Around
N/A
Evaluation
Using the given test case, tomcat server on NT 4.0 server JRE 1.3RC1-T the buffering behaviour seems perfectly normal. I tried this with W98/WNT and Solaris clients.

I suspect some other variable outside of the JRE is causing the problem.



  xxxxx@xxxxx   2000-02-29

As stated the customer is still experiencing this problem. Since we have been unable to reproduce this problem I suggest the customer try to narrow the focus to just the JRE. In other words would it be possible to create a test without the servlet code? 

  xxxxx@xxxxx   2000-03-29

  xxxxx@xxxxx   2000-07-18
To clarify my previos statement "the buffering behaviour seems perfectly normal" I did not mean to imply that there should be buffering but rather the lack of buffering is the expected behavior. 


According to the most recent comments there is a work around available by configuring Apache to use HTTP1.0 when communicating with a Java client.
This fact suggests that there is some strange interaction between Apache or the HttpServlet class and not necessarily the Java runtime. J2SE v1.3 supports 
HTTP 1.1  which may explain why the customer saw a change when moving from 1.2.2 to 1.3. In HTTP 1.1 there is support for the "chunked" transfer encoding which Apache may be using.  There is a an article on the Apache web site describe a similar problem which is available at

  http://www.apache.org/docs-1.2/misc/known_client_problems.html

which is where I suspect the customer found the work around. If the customer can 
verify "chunked" encoding is in use then we may be able to reproduce the problem. To prove that the problem does not exist in the absence of Apache or the Servlet classes I have modified the customer test to operate completely stand alone. The server source is attached (the client was unchanged). 

Please have the customer verify the test as well as whether chunked encoding is in use. If chunked encoding is in use I would be interested in see the snoop trace.

//=============== Servlet.java sans HttpServlet
import java.io.*;
import java.net.*;
import java.io.*;
import java.util.*;

public final class Servlet implements Runnable {
	
    private Socket client;
    private int    id;

    public Servlet (Socket client, int id) {
	this.client = client;
	this.id = id;
    }


    //
    // APPLICATION ENTRY POINT:
    //
    public static void main(String[] args) {

	int port = 8080;
	int errCount = 0;

        if (args.length == 1) {
	    try {
		port = Integer.parseInt(args[0]);
	    } catch (NumberFormatException nfe) {
		nfe.printStackTrace();
		System.exit(1);
	    }
	}


	ServerSocket ss = null;
	try {
	    ss = new ServerSocket(port);

	    ThreadGroup group = new ThreadGroup("Servlet");
	    Thread t = new Thread(group, new Servlet(ss.accept(), 1));
	    t.start();

	    //
	    // If we aren't looping forever, then we need to wait for the
	    // threads to finish.
	    //
	    while (group.activeCount() > 0) {
		try {
		    Thread.sleep(15000);		// wait for 15 seconds
		} catch (InterruptedException e) {
		    // ignore timer exception
		}
	    }
	} catch (BindException be) {
	    be.printStackTrace();
	} catch (Exception e) {
	    e.printStackTrace();
	} finally {
	    try {
		if (ss != null) ss.close();
	    } catch (IOException e) {
		// ignore close exception
	    }
	}
    }


    //
    // THREAD ENTRY POINT:
    //
    public void run() {
	doClient();
    }


    //
    // METHOD(S):
    //

    //
    // Do the client's work.
    //
    private void doClient() {
	try {
	    InputStream is = client.getInputStream();
	    byte[] buffer = new byte[5];
	    is.read(buffer);
	    System.out.println(new String(buffer));
			
	    PrintStream os = new PrintStream(client.getOutputStream());
	    sendHttpResponse("HTTP/1.1", 200, null, 0, os); // ct ignored

	    for (int i = 0; i < 10; i++) {
		String text = "Test " + i;
		os.write(text.getBytes());
		os.flush();
		Thread.sleep(2000);
	    }
	    is.close();
	    os.close();
	} catch (Exception e) {
	    e.printStackTrace(System.out);
	}
    }


    //
    // Send an HTTP response to the client.
    //
    private void sendHttpResponse(String version, int httpCode, String ct,
				  int length, PrintStream out) {
							// not HTTP/0.9 request
	if (version != null && version.startsWith("HTTP/")) {
	    out.print(version + " " + httpCode);
	    switch (httpCode) {
	    case HttpURLConnection.HTTP_NOT_FOUND:
		out.print(" Not Found");
		break;

	    case HttpURLConnection.HTTP_NOT_IMPLEMENTED:
		out.print(" Not Implemented");
		break;

	    case HttpURLConnection.HTTP_OK:
		out.print(" OK");
		break;
	    }
	    //
	    // While assembling the HTTP header line, we use print()
	    // instead of println() because we need to generate the
	    // specific <CR><NL> sequences. println() will generate
	    // <NL> on Unix and <CR><NL> on Win* so if we include <CR>
	    // in a println() call we are okay on Unix and wrong on
	    // Win*.
	    //
	    out.print("\r\n");
	    Date now = new Date();
	    out.print("Date: " + now + "\r\n");
	    out.print("Server: " + "Servlet" + " 1.0\r\n");
	    if (ct == null) {
		out.print("Content-type: text/html\r\n");
	    } else {
		//out.print("Content-length: " + length + "\r\n");
		out.print("Content-type: " + ct + "\r\n");
	    }
	    out.print("\r\n");
	}

	String bodyHead = "<BODY><H1>HTTP Error ";
	String bodyTail = "</H1></BODY><HTML>";
	String headerHead = "<HTML><HEAD><TITLE>";
	String headerTail = "</TITLE></HEAD>";

	switch (httpCode) {
	    case HttpURLConnection.HTTP_NOT_FOUND:
		out.println(headerHead + "File Not Found" + headerTail);
		out.println(bodyHead + httpCode + ": Not Found" + bodyTail);
		break;

	    case HttpURLConnection.HTTP_NOT_IMPLEMENTED:
		out.println(headerHead + "Not Implemented" + headerTail);
		out.println(bodyHead + httpCode + ": Not Implemented"
		    + bodyTail);
		break;

	    case HttpURLConnection.HTTP_OK:		// nothing more to send
		break;
	}
    }
}
//===============




On examination the issue is that Apache/Tomcat is buffering the 10 "Test x" messages
and when the HttpServletResponse output stream is closed it sends a single chunk
(60 bytes) to the http client -- ie: out.flush is not flushing the output to the
http client in a chunk.

However 1.3 is not without fault becuase it must read all chunks before it returns
the input stream to the application. This isn't the cause of the buffering issue
with this test case but it is something that must also be examined.

  xxxxx@xxxxx   2000-09-20
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang