Bug report #518 has just been filed. You can view the report at the following URL: <http://znutar.cortexity.com/BugRatViewer/ShowReport/518> REPORT #518 Details. Project: Tomcat Category: Bug Report SubCategory: New Bug Report Class: swbug State: received Priority: medium Severity: serious Confidence: public Environment: Release: 3.2 JVM Release: 1.3 Operating System: Win2000 Advanced OS Release: Win2000 Platform: 2-CPU Pentium Synopsis: JNI problem: bufferedreader.read fails in Tomcat/IIS/JNI set-up Description: There seems to be a bug that interferes with servlet-to-servlet communication, when Tomcat is running under IIS (Win 2000 Advanced), using JNI. I'm attaching source for a pair of simple servlets that demonstrate the bug. The first servlet (BadClient.java) opens a URLConnection to the second servlet (BadServer.java). BadClient uses the URLConnection to open an output stream, then uses the output stream to print some text, which will be read by BadServer. The BadServer servlet then calls request.getReader to get a reader object, to read the text that was sent by BadClient. This all works fine under Tomcat 3.2, when Tomcat is running stand-alone. But if Tomcat 3.2 is running inside IIS, using the JNI connector, there's a problem. BadServer is never able to read any of the text sent by BadClient. The whole process just seems to hang for exactly 1 minute... apparently, something times out after 1 minute, and BadClient stops trying to read the text. Under JNI, the read call returns -1. (Other servlets work fine under JNI.) The two servlets go on and perform other tasks after that, with BadServer reading a local .GIF file, then sending it back to BadClient, which send the image back to the browser. That part works; it's the first part that fails, as described above. I've tried various configurations of Tomcat -- using the JVM.DLL for classic, or hotspot, or server (Java 1.3). No difference. I've looked in the various log files for exceptions, and I don't see any. Here's the source for both servlets (around 100 lines each). If the formatting is messed up too badly, please let me know and I'll email a copy to anyone who wants to investigate the problem. // Here is all of BadClient.java (118 lines): // BadClient.java -- demonstrates behavior that works fine in Tomcat 3.2 // but does not work when Tomcat runs under IIS using JNI // Used in conjunction with BadServer.java import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; import java.net.URLConnection; import java.net.URL; public class BadClient extends HttpServlet { // TODO: Either modify the following string literal to represent // the URL of the BadServer servlet, or specify that URL // using an init parameter. String m_url = "http://localhost:8100/test/servlet/BadServer"; public void init(ServletConfig config) throws ServletException { super.init(config); try { String str = getInitParameter("url"); //URL to 2nd servlet if (str != null) { m_url = str; } } catch (Exception e) { e.printStackTrace(); } } public void service(HttpServletRequest request, HttpServletResponse res) throws ServletException, IOException { // Open an URLConnection to the BadServer servlet. URL url = new URL(m_url); URLConnection urlConnection = url.openConnection(); urlConnection.setDoOutput(true); urlConnection.setUseCaches(false); urlConnection.setRequestProperty("Connection", "close"); OutputStream os = null; try { os = urlConnection.getOutputStream(); // Only use one of the following two statements: //PrintWriter pw = new PrintWriter(os); OutputStreamWriter pw = new OutputStreamWriter(os); System.out.println("BadClient: About to print text. Time:" + new Date()); // Send some text to the second servlet. This is the part that // seems to fail when running on Tomcat 3.2 under IIS using JNI. // If using a PrintWriter, use the println method... /* if (pw.checkError()) { System.out.println("BadClient: will do println; checkError is true."); } pw.println("This is some text sent from BadClient to BadServer."); if (pw.checkError()) { System.out.println("BadClient: just did println; checkError is true."); } */ // ...OR, If using an OutputStreamWriter, use this statement: pw.write("This is some text sent from BadClient to BadServer...", 0, 50); System.out.println("BadClient: Sent text. Time:" + new Date()); String foo = request.getParameter("skipflush"); if (foo != null && foo.length() > 0) { System.out.println("BadClient: Will SKIP the pw.flush..."); } else { pw.flush(); } foo = request.getParameter("skipclose"); if (foo != null && foo.length() > 0 ) { System.out.println("Will SKIP the pw.close... "); } else { pw.close(); } System.out.println("BadClient:After flush & close. Time:" + new Date()); } catch (Exception e) { System.out.println(e.toString() ); e.printStackTrace(); } os.close(); // Fetch an image from the second servlet BufferedInputStream bin = new BufferedInputStream( urlConnection.getInputStream() ); DataInputStream dis = new DataInputStream(bin); // Read the text that precedes the image that we'll get back String s = dis.readUTF(); System.out.println("BadClient: Read header from BadServer: {" + s + "}"); byte[] buf = new byte[1024]; int count; // now pump the image data to the browser OutputStream outStream = res.getOutputStream(); while ((count = dis.read(buf)) != -1) { outStream.write(buf, 0, count); } outStream.flush(); dis.close(); outStream.close(); } public String getServletInfo() { return "ClientServlet Info"; } } // end of BadClient.java //Here is all of BadServer.java (101 lines): // BadServer.java -- demonstrates behavior that works fine in Tomcat 3.2 // but does not work if Tomcat is running under IIS with JNI. // Used in conjunction with BadClient.java import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class BadServer extends HttpServlet { public void init(ServletConfig config) throws ServletException { super.init(config); } public void doPost(HttpServletRequest request, HttpServletResponse res) throws ServletException, IOException { try { System.out.println("BadServer: will read text fromclient.:" + new Date()); // Read in the text sent by the client servlet. // Only make one of the following two calls: useBufferedReader(request); //useInputStreamReader(request); System.out.println("BadServer: read text from the client.:" + new Date()); } catch (Exception e) { System.out.println(e.toString() ); e.printStackTrace(); } // Send the client back some text, followed by a GIF image returnFile(res); } void useInputStreamReader(HttpServletRequest request) throws IOException { String buf = null; int i = 0; try { InputStream is = request.getInputStream(); InputStreamReader br = new InputStreamReader(is); char[] cbuf = new char[1024]; i = br.read(cbuf, 0, 50); buf = new String(cbuf); } catch (Exception e) { System.out.println(e.toString() ); e.printStackTrace(); } System.out.println("BadServer:read returned " + i + " chars:" + buf); } void useBufferedReader(HttpServletRequest request) throws IOException { //InputStream is = request.getInputStream(); //BufferedReader br = new BufferedReader(new InputStreamReader(is)); String buf = null; int i = 0; try { BufferedReader br = request.getReader(); char[] cbuf = new char[1024]; i = br.read(cbuf, 0, 50); buf = new String(cbuf); } catch (Exception e) { System.out.println(e.toString() ); e.printStackTrace(); } System.out.println("BadServer:readLine returned " + i + " chars:" + buf); } void returnFile(HttpServletResponse res) throws ServletException, IOException { // TODO: If necessary, modify the following to point to a local GIF file. File f = new File("D:\\test.gif"); BufferedInputStream bin = new BufferedInputStream(new FileInputStream(f)); BufferedOutputStream os = new BufferedOutputStream(res.getOutputStream()); DataOutputStream dos = new DataOutputStream(os); dos.writeUTF("Some text sent from BadServer!"); byte[] buf = new byte[1024]; int nRead; while( (nRead = bin.read(buf)) != -1 ) { os.write(buf, 0, nRead); } os.flush(); bin.close(); System.out.println("BadServer: Flushed OS."); } public String getServletInfo() { return "SecondServlet Information"; } } // end of BadServer.javaTitle: BugRat Report # 518
BugRat Report # 518
Project: Tomcat | Release: 3.2 |
Category: Bug Report | SubCategory: New Bug Report |
Class: swbug | State: received |
Priority: medium | Severity: serious |
Confidence:
public
|
Submitter:
Dave Smith ( [EMAIL PROTECTED] )
Date Submitted:
Dec 4 2000, 04:03:30 CST
Responsible:
Z_Tomcat Alias ( [EMAIL PROTECTED] )
- Synopsis:
- JNI problem: bufferedreader.read fails in Tomcat/IIS/JNI set-up
- Environment: (jvm, os, osrel, platform)
- 1.3, Win2000 Advanced, Win2000, 2-CPU Pentium
- Additional Environment Description:
- I haven't tried this on a single-CPU box. The test machine we used is a dual-CPU Pentium III with 512 MB of RAM.
- Report Description:
- There seems to be a bug that interferes with servlet-to-servlet communication, when Tomcat is running under IIS (Win 2000 Advanced), using JNI. I'm attaching source for a pair of simple servlets that demonstrate the bug. The first servlet (BadClient.java) opens a URLConnection to the second servlet (BadServer.java). BadClient uses the URLConnection to open an output stream, then uses the output stream to print some text, which will be read by BadServer. The BadServer servlet then calls request.getReader to get a reader object, to read the text that was sent by BadClient. This all works fine under Tomcat 3.2, when Tomcat is running stand-alone. But if Tomcat 3.2 is running inside IIS, using the JNI connector, there's a problem. BadServer is never able to read any of the text sent by BadClient. The whole process just seems to hang for exactly 1 minute... apparently, something times out after 1 minute, and BadClient stops trying to read the text. Under JNI, the read call returns -1. (Other servlets work fine under JNI.) The two servlets go on and perform other tasks after that, with BadServer reading a local .GIF file, then sending it back to BadClient, which send the image back to the browser. That part works; it's the first part that fails, as described above. I've tried various configurations of Tomcat -- using the JVM.DLL for classic, or hotspot, or server (Java 1.3). No difference. I've looked in the various log files for exceptions, and I don't see any. Here's the source for both servlets (around 100 lines each). If the formatting is messed up too badly, please let me know and I'll email a copy to anyone who wants to investigate the problem. // Here is all of BadClient.java (118 lines): // BadClient.java -- demonstrates behavior that works fine in Tomcat 3.2 // but does not work when Tomcat runs under IIS using JNI // Used in conjunction with BadServer.java import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; import java.net.URLConnection; import java.net.URL; public class BadClient extends HttpServlet { // TODO: Either modify the following string literal to represent // the URL of the BadServer servlet, or specify that URL // using an init parameter. String m_url = "http://localhost:8100/test/servlet/BadServer"; public void init(ServletConfig config) throws ServletException { super.init(config); try { String str = getInitParameter("url"); //URL to 2nd servlet if (str != null) { m_url = str; } } catch (Exception e) { e.printStackTrace(); } } public void service(HttpServletRequest request, HttpServletResponse res) throws ServletException, IOException { // Open an URLConnection to the BadServer servlet. URL url = new URL(m_url); URLConnection urlConnection = url.openConnection(); urlConnection.setDoOutput(true); urlConnection.setUseCaches(false); urlConnection.setRequestProperty("Connection", "close"); OutputStream os = null; try { os = urlConnection.getOutputStream(); // Only use one of the following two statements: //PrintWriter pw = new PrintWriter(os); OutputStreamWriter pw = new OutputStreamWriter(os); System.out.println("BadClient: About to print text. Time:" + new Date()); // Send some text to the second servlet. This is the part that // seems to fail when running on Tomcat 3.2 under IIS using JNI. // If using a PrintWriter, use the println method... /* if (pw.checkError()) { System.out.println("BadClient: will do println; checkError is true."); } pw.println("This is some text sent from BadClient to BadServer."); if (pw.checkError()) { System.out.println("BadClient: just did println; checkError is true."); } */ // ...OR, If using an OutputStreamWriter, use this statement: pw.write("This is some text sent from BadClient to BadServer...", 0, 50); System.out.println("BadClient: Sent text. Time:" + new Date()); String foo = request.getParameter("skipflush"); if (foo != null && foo.length() > 0) { System.out.println("BadClient: Will SKIP the pw.flush..."); } else { pw.flush(); } foo = request.getParameter("skipclose"); if (foo != null && foo.length() > 0 ) { System.out.println("Will SKIP the pw.close... "); } else { pw.close(); } System.out.println("BadClient:After flush & close. Time:" + new Date()); } catch (Exception e) { System.out.println(e.toString() ); e.printStackTrace(); } os.close(); // Fetch an image from the second servlet BufferedInputStream bin = new BufferedInputStream( urlConnection.getInputStream() ); DataInputStream dis = new DataInputStream(bin); // Read the text that precedes the image that we'll get back String s = dis.readUTF(); System.out.println("BadClient: Read header from BadServer: {" + s + "}"); byte[] buf = new byte[1024]; int count; // now pump the image data to the browser OutputStream outStream = res.getOutputStream(); while ((count = dis.read(buf)) != -1) { outStream.write(buf, 0, count); } outStream.flush(); dis.close(); outStream.close(); } public String getServletInfo() { return "ClientServlet Info"; } } // end of BadClient.java //Here is all of BadServer.java (101 lines): // BadServer.java -- demonstrates behavior that works fine in Tomcat 3.2 // but does not work if Tomcat is running under IIS with JNI. // Used in conjunction with BadClient.java import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class BadServer extends HttpServlet { public void init(ServletConfig config) throws ServletException { super.init(config); } public void doPost(HttpServletRequest request, HttpServletResponse res) throws ServletException, IOException { try { System.out.println("BadServer: will read text fromclient.:" + new Date()); // Read in the text sent by the client servlet. // Only make one of the following two calls: useBufferedReader(request); //useInputStreamReader(request); System.out.println("BadServer: read text from the client.:" + new Date()); } catch (Exception e) { System.out.println(e.toString() ); e.printStackTrace(); } // Send the client back some text, followed by a GIF image returnFile(res); } void useInputStreamReader(HttpServletRequest request) throws IOException { String buf = null; int i = 0; try { InputStream is = request.getInputStream(); InputStreamReader br = new InputStreamReader(is); char[] cbuf = new char[1024]; i = br.read(cbuf, 0, 50); buf = new String(cbuf); } catch (Exception e) { System.out.println(e.toString() ); e.printStackTrace(); } System.out.println("BadServer:read returned " + i + " chars:" + buf); } void useBufferedReader(HttpServletRequest request) throws IOException { //InputStream is = request.getInputStream(); //BufferedReader br = new BufferedReader(new InputStreamReader(is)); String buf = null; int i = 0; try { BufferedReader br = request.getReader(); char[] cbuf = new char[1024]; i = br.read(cbuf, 0, 50); buf = new String(cbuf); } catch (Exception e) { System.out.println(e.toString() ); e.printStackTrace(); } System.out.println("BadServer:readLine returned " + i + " chars:" + buf); } void returnFile(HttpServletResponse res) throws ServletException, IOException { // TODO: If necessary, modify the following to point to a local GIF file. File f = new File("D:\\test.gif"); BufferedInputStream bin = new BufferedInputStream(new FileInputStream(f)); BufferedOutputStream os = new BufferedOutputStream(res.getOutputStream()); DataOutputStream dos = new DataOutputStream(os); dos.writeUTF("Some text sent from BadServer!"); byte[] buf = new byte[1024]; int nRead; while( (nRead = bin.read(buf)) != -1 ) { os.write(buf, 0, nRead); } os.flush(); bin.close(); System.out.println("BadServer: Flushed OS."); } public String getServletInfo() { return "SecondServlet Information"; } } // end of BadServer.java
- How To Reproduce:
- null
- Workaround:
- null