I've been asked to provide more information, so here is combination of 
the two messages I posted with some more commentary and attachments.

It pertains to Tomcat-3.2.1 and looks to be  the same in 3.2.2.b4. I'm 
running Apache 1.3.17 on Win 2K Professional. I'm also using mod_jk

I have some client code that sends a jar file to the servlet. The jar 
file was getting corrupted. After much digging, I found a CVS commit to 
Ajp13ConnectorRequest.java that mentioned a problem like this with the 
doRead() method. It turns out the the same applies to the doRead(byte[], 
int, int) method. The same problem exists in the Ajp12ConnectionHandler 
for that byte array read. Single byte reads for both protocols work just 
fine. I'm including the diffs for these classes to show what I'm talking 
about.


I finally got out from under some work and was able to make some test 
code. I'm attaching the client and servlet code.
The code transfers a couple parameters, then a binary file (I was using 
a .jar). If you call the client with
"BinTestClient localhost something.jar b", it uses byte-by-byte read on 
the server to spool the file to a temp file. If you call the client 
without the 'b', it uses the byte-array read that I was complaining 
about.  Transfer a file, then try "jar tvf testXXXX.jar" to see if it 
works. I uses a jar that contains .jpg images and when using the byte 
array read method, it creats a corrupt jar file. If I apply my fix to 
the Ajp13ConnectorRequest class, it works fine.
(I tried a jar that contained class files and it worked anyway...)
I'd like for someone else to try this out to make sure I didn't screw 
something up. The code seems pretty simple.
I discovered this when using JarIn/OutputStream to transfer data from  
client to servlet.I've seen this type of thing in Java before when 
writing code that talks to hardware (such as touchscreen driver and 
scanner drivers).

   David

Index: Ajp13ConnectorRequest.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Attic/Ajp13ConnectorRequest.java,v
retrieving revision 1.5.2.7
diff -r1.5.2.7 Ajp13ConnectorRequest.java
274c274,277
<           System.arraycopy(bodyBuff, pos, b, off, c);
---
>           //System.arraycopy(bodyBuff, pos, b, off, c);
>           for (int i=pos, j=off, d=c; d > 0; i++, j++, d--) {
>               b[j] = (byte)(((char)bodyBuff[i])&0xff);
>           }

What I've done here is to replace the array copy with a loop that does the appropriate 
data conversion.


Index: Ajp12ConnectionHandler.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Attic/Ajp12ConnectionHandler.java,v
retrieving revision 1.28.2.4
diff -r1.28.2.4 Ajp12ConnectionHandler.java
542a543,549
>     public  int read(byte b[], int off, int len) throws IOException {
>       int ret = super.read(b, off, len);
>       for (int i=0, j=off; i<len; i++, j++) {
>           b[j] = (byte)(((char)b[j])&0xff);
>       }
>       return ret;
>     }

In this case, I over-rode the read method to convert the data after calling the 
super.read 


import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;

//      args[0] = hostname
//      args[1] = jarfile
//      args[2] = 'b' for single byte read.
public class BinTestClient {

        public static void main(String [] args) {
                try {
                        URL url = new URL("http://"+args[0]+"/examples/BinTest";);
                        URLConnection connection = (URLConnection)url.openConnection();
                        connection.setDoOutput(true);
                        connection.setUseCaches(false);
                        DataOutputStream output = new 
DataOutputStream(connection.getOutputStream());
                        File jarFile = new File(args[1]);
                        if (jarFile.exists()) {
                                output.writeUTF(""+jarFile.length());
                        }
                        if (args.length > 2 && args[2] != null && 
args[2].trim().equals("b"))
                                output.writeChar('b');
                        else
                                output.writeChar(' ');

                        InputStream istr = new FileInputStream(jarFile);
                        byte [] buf = new byte[8192];
                        int count = istr.read(buf);
                        while (count != -1) {
                                if (count > 0)
                                        output.write(buf, 0, count);
                                count = istr.read(buf);
                        }
                        istr.close();
                        output.flush();
                        output.close();

                        istr = connection.getInputStream();
                        istr.read();
                } catch (Exception ex) {
                        ex.printStackTrace();
                }
        }
}

import java.io.DataInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class BinTestServlet extends HttpServlet{

        public void doPost (HttpServletRequest request, HttpServletResponse response) {
                try {
                        DataInputStream istr = new 
DataInputStream(request.getInputStream());
                        long fileLen = Long.parseLong(istr.readUTF());
                        char mode = istr.readChar();

                        File tmp = File.createTempFile("test", ".jar");
                        OutputStream fstr = new FileOutputStream(tmp);
                        if (mode == 'b') {
                                System.out.println("Using byte-by-byte read");
                                for (int i=0; i<fileLen; i++)
                                        fstr.write(istr.read());
                        }
                        else {
                                System.out.println("Using byte-array read");
                                byte [] buf = new byte[8192];
                                int count = istr.read(buf);
                                while (count != -1) {
                                        if (count > 0)
                                                fstr.write(buf, 0, count);
                                        count = istr.read(buf);
                                }
                        }
                        fstr.flush();
                        fstr.close();

                        OutputStream ostr = response.getOutputStream();
                        ostr.write(1);  // positive response
                } catch (Exception ex) {
                        ex.printStackTrace();
                }
        }
}

Reply via email to