Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 package sun.net;
     26 
     27 import java.io.*;
     28 import java.net.Socket;
     29 import java.net.InetAddress;
     30 import java.net.InetSocketAddress;
     31 import java.net.UnknownHostException;
     32 import java.net.Proxy;
     33 import java.util.Arrays;
     34 import java.security.AccessController;
     35 import java.security.PrivilegedAction;
     36 
     37 /**
     38  * This is the base class for network clients.
     39  *
     40  * @author      Jonathan Payne
     41  */
     42 public class NetworkClient {
     43     /* Default value of read timeout, if not specified (infinity) */
     44     public static final int DEFAULT_READ_TIMEOUT = -1;
     45 
     46     /* Default value of connect timeout, if not specified (infinity) */
     47     public static final int DEFAULT_CONNECT_TIMEOUT = -1;
     48 
     49     protected Proxy     proxy = Proxy.NO_PROXY;
     50     /** Socket for communicating with server. */
     51     protected Socket    serverSocket = null;
     52 
     53     /** Stream for printing to the server. */
     54     public PrintStream  serverOutput;
     55 
     56     /** Buffered stream for reading replies from server. */
     57     public InputStream  serverInput;
     58 
     59     protected static int defaultSoTimeout;
     60     protected static int defaultConnectTimeout;
     61 
     62     protected int readTimeout = DEFAULT_READ_TIMEOUT;
     63     protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
     64     /* Name of encoding to use for output */
     65     protected static String encoding;
     66 
     67     static {
     68         final int vals[] = {0, 0};
     69         final String encs[] = { null };
     70 
     71         AccessController.doPrivileged(
     72                 new PrivilegedAction<Void>() {
     73                     public Void run() {
     74                         vals[0] = Integer.getInteger("sun.net.client.defaultReadTimeout", 0).intValue();
     75                         vals[1] = Integer.getInteger("sun.net.client.defaultConnectTimeout", 0).intValue();
     76                         encs[0] = System.getProperty("file.encoding", "ISO8859_1");
     77                         return null;
     78             }
     79         });
     80         if (vals[0] != 0) {
     81             defaultSoTimeout = vals[0];
     82         }
     83         if (vals[1] != 0) {
     84             defaultConnectTimeout = vals[1];
     85         }
     86 
     87         encoding = encs[0];
     88         try {
     89             if (!isASCIISuperset (encoding)) {
     90                 encoding = "ISO8859_1";
     91             }
     92         } catch (Exception e) {
     93             encoding = "ISO8859_1";
     94         }
     95     }
     96 
     97 
     98     /**
     99      * Test the named character encoding to verify that it converts ASCII
    100      * characters correctly. We have to use an ASCII based encoding, or else
    101      * the NetworkClients will not work correctly in EBCDIC based systems.
    102      * However, we cannot just use ASCII or ISO8859_1 universally, because in
    103      * Asian locales, non-ASCII characters may be embedded in otherwise
    104      * ASCII based protocols (eg. HTTP). The specifications (RFC2616, 2398)
    105      * are a little ambiguous in this matter. For instance, RFC2398 [part 2.1]
    106      * says that the HTTP request URI should be escaped using a defined
    107      * mechanism, but there is no way to specify in the escaped string what
    108      * the original character set is. It is not correct to assume that
    109      * UTF-8 is always used (as in URLs in HTML 4.0).  For this reason,
    110      * until the specifications are updated to deal with this issue more
    111      * comprehensively, and more importantly, HTTP servers are known to
    112      * support these mechanisms, we will maintain the current behavior
    113      * where it is possible to send non-ASCII characters in their original
    114      * unescaped form.
    115      */
    116     private static boolean isASCIISuperset (String encoding) throws Exception {
    117         String chkS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"+
    118                         "abcdefghijklmnopqrstuvwxyz-_.!~*'();/?:@&=+$,";
    119 
    120         // Expected byte sequence for string above
    121         byte[] chkB = { 48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,71,72,
    122                 73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,
    123                 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
    124                 115,116,117,118,119,120,121,122,45,95,46,33,126,42,39,40,41,59,
    125                 47,63,58,64,38,61,43,36,44};
    126 
    127         byte[] b = chkS.getBytes (encoding);
    128         return Arrays.equals (b, chkB);
    129     }
    130 
    131     /** Open a connection to the server. */
    132     public void openServer(String server, int port)
    133         throws IOException, UnknownHostException {
    134         if (serverSocket != null)
    135             closeServer();
    136         serverSocket = doConnect (server, port);
    137         try {
    138             serverOutput = new PrintStream(new BufferedOutputStream(
    139                                         serverSocket.getOutputStream()),
    140                                         true, encoding);
    141         } catch (UnsupportedEncodingException e) {
    142             throw new InternalError(encoding +"encoding not found");
    143         }
    144         serverInput = new BufferedInputStream(serverSocket.getInputStream());
    145     }
    146 
    147     /**
    148      * Return a socket connected to the server, with any
    149      * appropriate options pre-established
    150      */
    151     protected Socket doConnect (String server, int port)
    152     throws IOException, UnknownHostException {
    153         Socket s;
    154         if (proxy != null) {
    155             if (proxy.type() == Proxy.Type.SOCKS) {
    156                 s = AccessController.doPrivileged(
    157                     new PrivilegedAction<Socket>() {
    158                         public Socket run() {
    159                                        return new Socket(proxy);
    160                                    }});
    161             } else if (proxy.type() == Proxy.Type.DIRECT) {
    162                 s = createSocket();
    163             } else {
    164                 // Still connecting through a proxy
    165                 // server & port will be the proxy address and port
    166                 s = new Socket(Proxy.NO_PROXY);
    167             }
    168         } else
    169             s = createSocket();
    170         // Instance specific timeouts do have priority, that means
    171         // connectTimeout & readTimeout (-1 means not set)
    172         // Then global default timeouts
    173         // Then no timeout.
    174         if (connectTimeout >= 0) {
    175             s.connect(new InetSocketAddress(server, port), connectTimeout);
    176         } else {
    177             if (defaultConnectTimeout > 0) {
    178                 s.connect(new InetSocketAddress(server, port), defaultConnectTimeout);
    179             } else {
    180                 s.connect(new InetSocketAddress(server, port));
    181             }
    182         }
    183         if (readTimeout >= 0)
    184             s.setSoTimeout(readTimeout);
    185         else if (defaultSoTimeout > 0) {
    186             s.setSoTimeout(defaultSoTimeout);
    187         }
    188         return s;
    189     }
    190 
    191     /**
    192      * The following method, createSocket, is provided to allow the
    193      * https client to override it so that it may use its socket factory
    194      * to create the socket.
    195      */
    196     protected Socket createSocket() throws IOException {
    197         return new java.net.Socket();
    198     }
    199 
    200     protected InetAddress getLocalAddress() throws IOException {
    201         if (serverSocket == null)
    202             throw new IOException("not connected");
    203         return  AccessController.doPrivileged(
    204                         new PrivilegedAction<InetAddress>() {
    205                             public InetAddress run() {
    206                                 return serverSocket.getLocalAddress();
    207 
    208                             }
    209                         });
    210     }
    211 
    212     /** Close an open connection to the server. */
    213     public void closeServer() throws IOException {
    214         if (! serverIsOpen()) {
    215             return;
    216         }
    217         serverSocket.close();
    218         serverSocket = null;
    219         serverInput = null;
    220         serverOutput = null;
    221     }
    222 
    223     /** Return server connection status */
    224     public boolean serverIsOpen() {
    225         return serverSocket != null;
    226     }
    227 
    228     /** Create connection with host <i>host</i> on port <i>port</i> */
    229     public NetworkClient(String host, int port) throws IOException {
    230         openServer(host, port);
    231     }
    232 
    233     public NetworkClient() {}
    234 
    235     public void setConnectTimeout(int timeout) {
    236         connectTimeout = timeout;
    237     }
    238 
    239     public int getConnectTimeout() {
    240         return connectTimeout;
    241     }
    242 
    243     /**
    244      * Sets the read timeout.
    245      *
    246      * Note: Public URLConnection (and protocol specific implementations)
    247      * protect against negative timeout values being set. This implemenation,
    248      * and protocol specific implementations, use -1 to represent the default
    249      * read timeout.
    250      *
    251      * This method may be invoked with the default timeout value when the
    252      * protocol handler is trying to reset the timeout after doing a
    253      * potentially blocking internal operation, e.g. cleaning up unread
    254      * response data, buffering error stream response data, etc
    255      */
    256     public void setReadTimeout(int timeout) {
    257         if (timeout == DEFAULT_READ_TIMEOUT)
    258             timeout = defaultSoTimeout;
    259 
    260         if (serverSocket != null && timeout >= 0) {
    261             try {
    262                 serverSocket.setSoTimeout(timeout);
    263             } catch(IOException e) {
    264                 // We tried...
    265             }
    266         }
    267         readTimeout = timeout;
    268     }
    269 
    270     public int getReadTimeout() {
    271         return readTimeout;
    272     }
    273 }
    274