11 Replies Latest reply: Oct 12, 2007 11:32 AM by 807592 RSS

    Problem with JarURLConnection and JRE 1.5.0_02

    807587
      Hi,

      My application reads a RSA public key out of a file I have stored in my JAR file. When I upgraded to the new 1.5.0_02 JRE, my code no longer works correctly. The RSA public key is in a binary file.

      I read this file by determining the URL to the file, using the getResource() method. Then I call the URL.openStream() method.
      Under 1.5.0_01, this method returns a java.util.jar.JarVerifier$VerifierStream object.
      Under 1.5.0_02, this method returns a sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream object.

      When I get to the following line in my code:
      int len = in.read( bytefield, 0, 4 );   // bytefield is a byte[ 4 ]
      Under 1.5.0_01: this line returns 4, like I would expect.
      Under 1.5.0_02: this line returns 3, always.

      If I change that line of code, to the following:
      bytefield[ 0 ] = (byte) in.read();
      bytefield[ 1 ] = (byte) in.read();
      bytefield[ 2 ] = (byte) in.read();
      bytefield[ 3 ] = (byte) in.read();
      Then it works under both. But this "fix" makes me nervous, because I have no idea why I would have to do this, and because I see no reason why this would work where the other would fail. Am I doing something wrong here? Is this a problem with the JarURLInputStream class?

      Thanks for any help or ideas,
      -Ryan
        • 1. Re: Problem with JarURLConnection and JRE 1.5.0_02
          796447
          Too many times we at the forum see people such as yourselves blaming some bug of theirs on the VM or standard Java classes. I would suspect your case is no different, that you have erroneously diagnosed a problem. Do I know for sure? No. But I highly doubt that it is behaving as you described. By the way, why are you not just invoking in.read(bytefield), if bytefield is in fact a byte[4]? Passing 0, 4 to that method has no effect over the simpler one-argument method.
          • 2. Re: Problem with JarURLConnection and JRE 1.5.0_02
            DrClap
            You have an InputStream, right? And the API documentation for that method says

            "Reads up to len bytes of data from the input stream into an array of bytes. An attempt is made to read as many as len bytes, but a smaller number may be read, possibly zero. The number of bytes actually read is returned as an integer."

            In other words, both versions are operating correctly. You have just made the assumption that since something happened to work in one idiosyncratic way, then all future versions of the JRE must work that same way. But that isn't so. They just have to honour the documented contract.
            • 3. Re: Problem with JarURLConnection and JRE 1.5.0_02
              807587
              OK, dude,

              Thanks for taking the time to really look at my problem...

              It seems that I won't be given any respect without explaining the whole life story of this problem. So, here goes

              My WebStart application reads an RSA public key out of binary file that lives within my JAR file. Last week or so, when Sun came out with the 2nd update to 1.5, I noticed that my application no longer worked correctly. However, I did notice that when I configured Java WebStart to use the 1.5.0_01 JRE, my application worked great. When I switched it back to 1.5.0_02 JRE, it didn't work. This was a reliable way to break my application. This is the exact same code running against two different versions of the Windows JRE. I have tried it on 4 or 5 other PCs at my office, and it behaves exactly the same on each of these PCs. When they use 1.5.0_01 or 1.5.0, it works fine. When they use 1.5.0_02, it doesn't.

              This would tend to lead a person to draw one of two conclusions: 1) That my application was relying upon some "default value" that had changed from 1.5.0_01 to 1.5.0_02. OR 2) That something in the Window 1.5.0_02 JRE was not working correctly.

              For the past several days, I have suspected that the problem was with the SunJCE. I thought that they may have dropped support for PKCS#1 RSA padding or at least screwed something up with it. Since my application talks to a C++ server program that uses OpenSSL, I have been coordinateing with the developer of the server application. We have tried using different padding algorithms, all to no avail.

              Out of frustration, I started to sprinkly debug statements to System.out all throughout my code. Then I ran it under both JREs and would compare the output. This is how I finally found out that when my application runs under 1.5.0_02, it is not reading the public key file correctly.

              I have reduced the problem to one java file and my publickey file. When I run the application through the command line, with no jar file, it works fine in both _01 and _02. When I then put both the publickey and the class file into a JAR, it works under _01, but not _02. Thats when I dumped out the class of the InputStream object being returned by URL.openStream(). I noticed that the class of this object changed in 1.5.0_02. Thus, that one read() call only returns 3, when the InputStream returns a JarURLConnection$JarURLInputStream object. This is the same code and the same binary publickey file.

              This would lead me to beleave that this class is not working correctly.

              -Ryan
              • 4. Re: Problem with JarURLConnection and JRE 1.5.0_02
                807587
                Dr Clap,

                Sorry, I started writing my reply before I saw you had posted.

                I do have an InputStream. And it does say that in the JavaDocs. But it also says, right under that part, that " This method blocks until input data is available, end of file is detected, or an exception is thrown."

                I know that the end-of-file hasn't been reached because when I run the same code and the same binary file under 1.5.0_01, it reads 4 bytes. Furthermore, these 4 bytes are actually a binary integer, that tells my application how much more data to read from the file. When I run my application under 1.5.0_02, and this call returns 3, my application next calls read() again to read 2 more bytes from the file. This call returns successfully.

                Also, I know that no exception is being thrown.

                So, if it hasn't reached the end-of-file, and no exception is being thrown, then my understanding of this method is that it is supposed to block until it reads all the data.
                I can post my application code, if perhaps that would help. Although I'm not sure what would be a good way to give you my public key file...

                Thanks
                -Ryan
                • 5. Re: Problem with JarURLConnection and JRE 1.5.0_02
                  796447
                  OK, dude,

                  Thanks for taking the time to really look at my
                  problem...

                  It seems that I won't be given any respect without
                  explaining the whole life story of this problem. So,
                  here goes
                  Let me ask you this... If someone asks you a question, and you respond as I did (afterall, would I know whether you are really correct in your diagnosis, or just another "It's Java's fault - can't be mine" nitwit)... and then then that person comes back the way you did with a snotty attitude, would you continue the dialog with them, or just tell them to kiss off? You may guess what I'm electing to do now. You're the one needing the problem solved - I don't need you.
                  • 6. Re: Problem with JarURLConnection and JRE 1.5.0_02
                    807587
                    Maybe, I'm suggesting that you don't automattically assume that all the people who post questions to the forums are idiots. In case you didn't notice, there was a part of my original post that would seem to indicate that I was not a "It's Java's fault - can't be mine, nitwit". That would be the part where I said "Am I doing something wrong here?" Maybe you didn't even read my whole post...

                    Let me ask you this... If you've been banging your head into a wall for several days, trying to figure out why your code is working, and you decide to post your problem to the forums. And someone responds to you, without even reading your entire post, and immediately casts you in with a group of people who run to the forums as soon as something doesn't work right. Would you be pissed?
                    • 7. Re: Problem with JarURLConnection and JRE 1.5.0_02
                      796447
                      Maybe, I'm suggesting that you don't automattically
                      assume that all the people who post questions to the
                      forums are idiots.
                      Many, many, many are. Do I know you? Nope. Don't think I care to get to know you now either.
                      In case you didn't notice, there
                      was a part of my original post that would seem to
                      indicate that I was not a "It's Java's fault - can't
                      be mine, nitwit". That would be the part where I
                      said "Am I doing something wrong here?"
                      That doesn't tell me or anyone else that you might not be a "nitwit". (No, I'm not saying you are)
                      Maybe you didn't even read my whole post...
                      I did.
                      Let me ask you this... If you've been banging your
                      head into a wall for several days, trying to figure
                      out why your code is working, and you decide to post
                      your problem to the forums. And someone responds to
                      you, without even reading your entire
                      post, and immediately casts you in with a
                      group of people who run to the forums as soon as
                      something doesn't work right. Would you be
                      pissed?
                      No, because I'd realize that they don't know me or how much effort I've put into it. Being the one in need of help, I'd be sure to tread lightly and not bite the hand that might feed me.
                      • 8. Re: Problem with JarURLConnection and JRE 1.5.0_02
                        DrClap
                        I do have an InputStream. And it does say that in
                        the JavaDocs. But it also says, right under that
                        part, that " This method blocks until input data is
                        available, end of file is detected, or an exception
                        is thrown."
                        And what does "available" mean here? The docs don't say, so I suppose each subclass can decide what it means. Perhaps your assumption of what it means doesn't agree with the code's assumption. I wouldn't expect a JarURLInputStream to understand that those 4 bytes make up an integer, for example.
                        I know that the end-of-file hasn't been reached
                        because when I run the same code and the same binary
                        file under 1.5.0_01, it reads 4 bytes. Furthermore,
                        these 4 bytes are actually a binary integer, that
                        tells my application how much more data to read from
                        the file. When I run my application under 1.5.0_02,
                        and this call returns 3, my application next calls
                        read() again to read 2 more bytes from the file.
                        This call returns successfully.
                        Seems strange to me too. But I don't understand your question. That's how it works, no matter what anybody's opinions are about whether it's right or wrong. You have two options:

                        1. Report it as a bug.

                        2. Deal with it.

                        And since #1 isn't going to solve your problem in the short term, you're left with #2 anyway. Put a comment in your code to explain why you have to do it that way so that future maintainers aren't tempted to "improve" your code and introduce a bug.
                        • 9. Re: Problem with JarURLConnection and JRE 1.5.0_02
                          807587
                          I assume that "available" means "available to be read". But, you're right, perhaps that is an incorrect assumption. Although the docs don't explicitly state it, I would interpret them to mean that, for example, if you call read( 0, 500 ) and it returns a number less than 500, it means that you have reached the end of the file or stream. I interpret it that way because i don't know how else you would know that you reached the end of the file (at least without trying another read() which would then return -1).

                          I didn't mean to imply that the JarURLInputStream should know my four bytes were an integer. I just gave that as evidence that I wasn't really reaching the end of the file (since I was able to do a subsequent read successfully).

                          I agreee with the two options. I put a wrapper function around the InputStream.read() call. This function will block until it has read all the data, detect end-of-file and return false, or throw some IOException. But I thought it would be good to post this issue here, so that other people might find out about it. Especially since update 2 just came out, and I could see other people making the same assumptions.
                          In case anyone is curious, here is my wrapper function. Note, this function does an all or nothing approach (i.e. it either reads the whole buffer and returns true, or it returns false).
                          private static boolean readByteArray( InputStream in, byte[] array, int offset, int length ) throws IOException
                          {
                             int off = offset;
                             int left = length;
                          
                             while( left > 0 )
                             {
                                int read = in.read( array, off, left );
                          
                                // See if we hit the end-of-file
                                if( read == -1 )
                                   return false;
                          
                                off += read;
                                left -= read;
                             }
                          
                             // We have read the entire length, so return true
                             return true;
                          }
                          I think I will post a bug report as well. Since it really does seem to be a bug to me. At least, Sun could maybe explain a little better in the JavaDocs what available means, and what you can assume from the return code.

                          Thanks,
                          -Ryan
                          • 10. Re: Problem with JarURLConnection and JRE 1.5.0_02
                            DrClap
                            I didn't mean to imply that the JarURLInputStream
                            should know my four bytes were an integer. I just
                            gave that as evidence that I wasn't really reaching
                            the end of the file (since I was able to do a
                            subsequent read successfully).
                            Understood. Maybe it decompresses the jar file in small pieces and considers "available" to be the next small piece. Maybe it considers "having to decompress a few more bytes" to be blocking. But that's just a half-baked guess.
                            • 11. Re: Problem with JarURLConnection and JRE 1.5.0_02
                              807592
                              Thanks so much for posting this.

                              I ran into the same problem in 1.4.2_06 to 1.4.2_14 (or _08 or _12). I thought I was going crazy.

                              My application reads an ASE public key out of a file I have stored in my JAR file. When I upgraded to the new 1.4.2_14 JRE, my code no longer works correctly. The ASE public key is in a binary file.

                              I read this file by determining the URL to the file, using the getResourceAsStream() method.
                              Under *1.4.2_06*, this method returns a java.util.zip.ZipFile object.
                              Under *1.4.2_08, _12, _14*, this method returns a sun.net.www.protocol.jar.*JarURLConnection$JarURLInputStream* object.

                              Then the reading the file would read all but the last 2 bytes (under _08, _12, _14).

                              byte[] bytefield = new byte[16];
                              inputStream.read(bytefield);

                              The same code under _06 read all bytes.

                              I incorporated your workaround (under 1.4.2_14) and it now reads the last two bytes. (Yes, Still maintaining old app on 1.4.2 constrained to that version by vendor software).

                              Thanks again.

                              Did you ever report this to Sun as a bug?