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

FtpURLConnection connection leak on FileNotFoundException

    Details

    • Subcomponent:
    • Resolved In Build:
      b114
    • CPU:
      x86
    • OS:
      windows_7

      Backports

        Description

        FULL PRODUCT VERSION :
        java version "1.7.0_04"
        Java(TM) SE Runtime Environment (build 1.7.0_04-b22)
        Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode)

        java version "1.6.0_25"
        Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
        Java HotSpot(TM) 64-Bit Server VM (build 20.0-b11, mixed mode)


        java version "1.6.0_31"
        Java(TM) SE Runtime Environment (build 1.6.0_31-b04-415-11M3646)
        Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01-415, mixed mode)

        java version "1.6.0_20"
        OpenJDK Runtime Environment (IcedTea6 1.9.13) (6b20-1.9.13-0ubuntu1~10.04.1)
        OpenJDK Client VM (build 19.0-b09, mixed mode, sharing)

        ADDITIONAL OS VERSION INFORMATION :
        Microsoft Windows [Version 6.1.7600]

        Darwin Dimitris-Dimitropouloss-MacBook-Pro.local 11.3.0 Darwin Kernel Version 11.3.0: Thu Jan 12 18:47:41 PST 2012; root:xnu-1699.24.23~1/RELEASE_X86_64 x86_64

        Linux ubuntu 2.6.32-41-generic-pae #88-Ubuntu SMP Thu Mar 29 14:24:36 UTC 2012 i686 GNU/Linux





        EXTRA RELEVANT SYSTEM CONFIGURATION :
        This problem seems to be reproducible in both Oracle JDK 6 and 7 and OpenJDK 6 and 7 in any environment tested (mac, windows, linux)

        A DESCRIPTION OF THE PROBLEM :
        Using java.net.URL.openStream for an ftp resource that is not available on an ftp server throws an FileNotFoundException but leaves an underlying connection (an FTPClient) open.

        A common side-effect (apart from the socket leak) is that the firewall rules of a typical ftp server will eventually (after a few such exceptions) deny serving even valid resources, with a "too many connections open" error message.
         


        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        I am attaching a sample program.

        Just try to open a stream using a URL object for a resource like
        ftp://ftp.oracle.com/doesNotExist.txt

        using something as simple as
        new URL("ftp://ftp.oracle.com/doesNotExist.txt").openStream()

        This call will correctly return a FileNotFoundException since the specified path does not exist on that server.

        But the natural outcome of the exception is that the user does not have access to an InputStream or any other API method that he could use to close any internal connection in case of a FileNotFound (or any Runtime) exception.

        Repeat that for about 10-15 times and then try to open
         
        new URL("ftp://ftp.oracle.com/FAQ_README.htm")

        This will fail too (even though the resource exists) because most FTP servers have a limit on the number of open connections that allow from an individual client.

        So waiting for a "clean-up" during garbage collection is not a practical option.

        The implementation of (FtpURLConnection), seems to keep a connection open (an FTPClient), with no available API method to terminate it.

        The same is also true if the user uses directly the URLConnection API (URL.openConnection).

        Both URL and URLConnection are effectively immutable after the connection has been established and they do not provide an API method for changing the invalid URL path to a valid one or any way of cleanup in case of a FileNotFound (or any Runtime) exception.



        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        When methods FtpURLConnection.getInputStream or FtpURLConnection.getOutputStream throw any type of exception, they should clean up any allocated resources (FtpClient)
        ACTUAL -
        There are system socket connections to the FTP server that stay open after the exception is thrown without any means of closing them.

        In a typical situation, after a few exceptions, the FTP server will stop serving any resources to the client with a "too many open connections" error message

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        import java.io.FileNotFoundException;
        import java.io.IOException;
        import java.io.InputStream;
        import java.net.MalformedURLException;
        import java.net.URL;


        public class FtpURLConnectionLeak {
            
            public static void main(String []args) {

                URL url=null;
                
                try {
                    url = new URL("ftp://ftp.oracle.com/doesNotExist.txt");
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                    return;
                }
                
                for(int i=0;i<100;i++) {
                    
                    InputStream stream=null;
                    try {
                        stream=url.openStream();
                    } catch (FileNotFoundException e) {
                        // It should always reach this point since the path does not exist
                        System.err.println("Correct behaviour for attempt "+i+":"+e);
                    } catch (IOException e) {
                        System.err.println("Due to the ftp client connection leak, we have propably reached the firewall limit of the FTP server");
                        e.printStackTrace();
                        break;
                    }
                    
                    assert(stream==null) : "It will never reach here since the path is invalid";

                    if(stream!=null) {
                        // There is no other way to close the underlying connection
                        // but this code is unreachable
                        try {
                            stream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                            return;
                        }
                    }
                }
                
                // Due to the connection leak, its not possible now to download valid URLs from that ftp server
            }
        }


        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        There is no easy workaround from the API side.

        Resolving this would be easy by adding a try block that would include the full body of getInputStream() and getOutputStream() of FtpURLConnection.java with a catch statement (or a finally block) that would include a call to ftp.closeServer(); in case of a FileNotFoundException or any run time exception.

        (for example for the OpenJDK 6 version at)

        http://www.java2s.com/Open-Source/Java/6.0-JDK-Modules-sun/net/sun/net/www/protocol/ftp/FtpURLConnection.java.htm

          Activity

          Hide
          hgupdate HG Updates added a comment -
          URL: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/8f5f8f0f265e
          User: chegar
          Date: 2016-04-05 16:08:38 +0000
          Show
          hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/8f5f8f0f265e User: chegar Date: 2016-04-05 16:08:38 +0000
          Hide
          hgupdate HG Updates added a comment -
          URL: http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/8f5f8f0f265e
          User: lana
          Date: 2016-04-13 17:56:05 +0000
          Show
          hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/8f5f8f0f265e User: lana Date: 2016-04-13 17:56:05 +0000

            People

            • Assignee:
              vtewari Vyom Tewari
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Imported:
                Indexed: