Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4361492

HTTPUrlConnection does not receive binary data correctly

XMLWordPrintable

    • 01
    • x86
    • windows_nt



        Name: stC104175 Date: 08/10/2000


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

        We use the java.net.URL class to manage a server request to a servlet.
        There is a transfer of binary data between the client and the servlet,
        where Objects are serialized via ByteArrayStreams and transfered as
        a byte[] like this:

        public byte[] requestBytes(byte[] rData)
        {
          byte[] lResult = null;
          URL lURL = new URL("http://servername/servlets/TestServlet");
          HttpURLConnection lCon = (HttpURLConnection) lURL.openConnection();
          lCon.setDoOutput(true);
          lCon.setDoInput(true);
          lCon.setUseCaches(false);
          lCon.setRequestMethod("POST");
          lCon.setRequestProperty("Content-Type", "application/octet-stream");
          OutputStream lOut = lCon.getOutputStream();
          lOut.write(rData);
          lOut.close(); // Does not change behaviour, if not present
          // until here anything works fine, servlet gets all data and responds
          // correct (could be checked with Internet Explorer download)
          System.out.println(lCon.getContentEncoding()); // is null whatever the
                                                         // servlet responds
          InputStream lIn = lCon.getInputStream(); // with -Dhttp.keepAlive=false
                                                   // this could takes about 5 Minutes
          int liSize = lCon.getContentLength(); // is -1, if data exceeds a certain
                                                // amount or data is transfered via
                                                // a proxy server
          System.out.println("RespCode: "+lCon.getResponseCode()); // is 200
          System.out.println("RespMsg: "+lCon.getResponseMessage()); // is 'OK'
          if (liSize > 0)
            lResult = StreamScan.blockread(lIn,liSize);
          else
            lResult = StreamScan.blockreadFully(lIn);
        // lIn.close(); // does not change behavior, if present
          return lResult;
        }


        StreamScan.blockread reads streamdata with respect to timeout values like this:


        public class StreamScan
        {
          private static final int giK_BlockSize = 8192;
          private static final long glK_TimeoutMillis = 800;
          private static final long glK_BlockTimeoutMillis = 5000;
          private static final long glK_SleepMillis = 200;
          private static final long glK_BlockSleepMillis = 500;

          private static int blockread(InputStream rInput,
            byte[] rbyBuffer, int viBufPos, int viLen)
          {
            int liBytesAvailable;
            int liByte;
            int liTotalBytesRead = 0;
            int liBufPos = viBufPos;
            if (rbyBuffer == null)
              return -1;
            int liLen = Math.min(viLen,rbyBuffer.length-viBufPos);
            try {
              do
              { // wait for data to become available or timeout is reached
                if ((liBytesAvailable = rInput.available()) == 0)
                {
                  long llTimerStart = System.currentTimeMillis();
                  do
                  {
                    try {Thread.currentThread().sleep(glK_BlockSleepMillis);}
                    catch (InterruptedException ex) {}
                  } while (((liBytesAvailable = rInput.available()) == 0) &&
               ((System.currentTimeMillis() - llTimerStart) < glK_BlockTimeoutMillis));
                }
                
                // cancel, if timed out
                if (liBytesAvailable == 0)
                  return liTotalBytesRead;
                
                // read available bytes
                while ((liTotalBytesRead < liLen) && (liBytesAvailable > 0))
                {
                  liByte = rInput.read();
                  if (liByte == -1) return -1; // should not really happen
                  rbyBuffer[liBufPos++] = (byte) liByte;
                  liTotalBytesRead++;
                  liBytesAvailable--;
                }
              } while (liTotalBytesRead < liLen);
              return liTotalBytesRead;
            }
            catch (Exception e) {return -1;}
          }

          public static byte[] blockread(InputStream rInput, int viLen)
          {
            byte[] lbyBuffer = new byte[viLen];
            if ((StreamScan.blockread(rInput,lbyBuffer,0,viLen)) < viLen)
              return null;
            else
              return lbyBuffer;
          }
        }


        The problem is, that this doesn't work stable. Often there is a content length
        of -1 reported from the HttpURLConnection and indeed there could be read no data
        from the stream. But the data IS sent from the servlet as we could prove with
        a download from a browser. Anythings well until we try to get the InputStream
        and read from it.

        We thought it to be related to the keepAlive problem and tried the
        -Dhttp.keepAlive=false parameter to java.exe, but things get even more curious
        with that. Now sometimes we didnt even get the InputStream from the
        HttpURLConnection (or it took until 10 Minutes!!! to get the stream and the
        content was cut after a few bytes). Switching off the keepAlive in the Internet
        Information Server didnt change anything by the way.

        Our environtment is an NT 4 Server (SR6) with IIS4 and the JRun Servlet Engine.
        Client and server are working with the JRE 1.3

        After weeks of testing we believe this to be a bug of the HttpURLConnection.
        It seems, as if the connection interprets a keepAlive message as the data packet
        with empty content or something alike. Very strange.

        Bye the way, here's the servlet code:

          ...
          byte[] lBuf = Meta.serialize(lTrans); // binary representation of an Object
          System.out.println("lBufSize: "+lBuf.length);
          response.setContentType("application/octet-stream");
          response.setContentLength(lBuf.length); // doesnt change anything, if missing
        // response.setHeader("Transfer-Encoding","chunked-data"); // doesnt any matter
        // response.setHeader("Content-Encoding","binary"); // doesnt matter either
          OutputStream lOut = response.getOutputStream();
          lOut.write(lBuf);
          ...

        very simple, isnt it?
        (Review ID: 108179)
        ======================================================================

              michaelm Michael McMahon
              stompkinsunw Sean Tompkins (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: