feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.net.Proxy;
import java.net.SocketAddress;
/**
* Proxy wrapper class so that we can determine application set
* proxies by type.
*/
public final class ApplicationProxy extends Proxy {
private ApplicationProxy(Proxy proxy) {
super(proxy.type(), proxy.address());
}
public static ApplicationProxy create(Proxy proxy) {
return new ApplicationProxy(proxy);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.net.SocketException;
/**
* Thrown to indicate a connection reset.
*
* @since 1.4.1
*/
public
class ConnectionResetException extends SocketException {
private static final long serialVersionUID = -7633185991801851556L;
public ConnectionResetException(String msg) {
super(msg);
}
public ConnectionResetException() {
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2020, Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.net.SocketOption;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import static jdk.net.ExtendedSocketOptions.TCP_KEEPCOUNT;
import static jdk.net.ExtendedSocketOptions.TCP_KEEPIDLE;
import static jdk.net.ExtendedSocketOptions.TCP_KEEPINTERVAL;
public class ExtendedOptionsHelper {
private static final boolean keepAliveOptSupported =
ExtendedOptionsImpl.keepAliveOptionsSupported();
private static final Set<SocketOption<?>> extendedOptions = options();
private static Set<SocketOption<?>> options() {
Set<SocketOption<?>> options = new HashSet<>();
if (keepAliveOptSupported) {
options.add(TCP_KEEPCOUNT);
options.add(TCP_KEEPIDLE);
options.add(TCP_KEEPINTERVAL);
}
return Collections.unmodifiableSet(options);
}
public static Set<SocketOption<?>> keepAliveOptions() {
return extendedOptions;
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.net.*;
import jdk.net.*;
import java.io.IOException;
import java.io.FileDescriptor;
import java.security.PrivilegedAction;
import java.security.AccessController;
import java.lang.reflect.Field;
import java.util.Set;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Collections;
/**
* Contains the native implementation for extended socket options
* together with some other static utilities
*/
public class ExtendedOptionsImpl {
static {
AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
System.loadLibrary("net");
return null;
});
init();
}
private ExtendedOptionsImpl() {}
public static void checkSetOptionPermission(SocketOption<?> option) {
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
return;
}
String check = "setOption." + option.name();
sm.checkPermission(new NetworkPermission(check));
}
public static void checkGetOptionPermission(SocketOption<?> option) {
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
return;
}
String check = "getOption." + option.name();
sm.checkPermission(new NetworkPermission(check));
}
public static void checkValueType(Object value, Class<?> type) {
if (!type.isAssignableFrom(value.getClass())) {
String s = "Found: " + value.getClass().toString() + " Expected: "
+ type.toString();
throw new IllegalArgumentException(s);
}
}
private static native void init();
/*
* Extension native implementations
*
* SO_FLOW_SLA
*/
public static native void setFlowOption(FileDescriptor fd, SocketFlow f);
public static native void getFlowOption(FileDescriptor fd, SocketFlow f);
public static native boolean flowSupported();
public static native void setTcpKeepAliveProbes(FileDescriptor fd, int value) throws SocketException;
public static native void setTcpKeepAliveTime(FileDescriptor fd, int value) throws SocketException;
public static native void setTcpKeepAliveIntvl(FileDescriptor fd, int value) throws SocketException;
public static native int getTcpKeepAliveProbes(FileDescriptor fd) throws SocketException;
public static native int getTcpKeepAliveTime(FileDescriptor fd) throws SocketException;
public static native int getTcpKeepAliveIntvl(FileDescriptor fd) throws SocketException;
public static native boolean keepAliveOptionsSupported();
}

View File

@@ -0,0 +1,219 @@
/*
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.security.PrivilegedAction;
import java.security.Security;
public final class InetAddressCachePolicy {
// Controls the cache policy for successful lookups only
private static final String cachePolicyProp = "networkaddress.cache.ttl";
private static final String cachePolicyPropFallback =
"sun.net.inetaddr.ttl";
// Controls the cache policy for negative lookups only
private static final String negativeCachePolicyProp =
"networkaddress.cache.negative.ttl";
private static final String negativeCachePolicyPropFallback =
"sun.net.inetaddr.negative.ttl";
public static final int FOREVER = -1;
public static final int NEVER = 0;
/* default value for positive lookups */
public static final int DEFAULT_POSITIVE = 30;
/* The Java-level namelookup cache policy for successful lookups:
*
* -1: caching forever
* any positive value: the number of seconds to cache an address for
*
* default value is forever (FOREVER), as we let the platform do the
* caching. For security reasons, this caching is made forever when
* a security manager is set.
*/
private static volatile int cachePolicy = FOREVER;
/* The Java-level namelookup cache policy for negative lookups:
*
* -1: caching forever
* any positive value: the number of seconds to cache an address for
*
* default value is 0. It can be set to some other value for
* performance reasons.
*/
private static volatile int negativeCachePolicy = NEVER;
/*
* Whether or not the cache policy for successful lookups was set
* using a property (cmd line).
*/
private static boolean propertySet;
/*
* Whether or not the cache policy for negative lookups was set
* using a property (cmd line).
*/
private static boolean propertyNegativeSet;
/*
* Initialize
*/
static {
Integer tmp = java.security.AccessController.doPrivileged(
new PrivilegedAction<Integer>() {
public Integer run() {
try {
String tmpString = Security.getProperty(cachePolicyProp);
if (tmpString != null) {
return Integer.valueOf(tmpString);
}
} catch (NumberFormatException ignored) {
// Ignore
}
try {
String tmpString = System.getProperty(cachePolicyPropFallback);
if (tmpString != null) {
return Integer.decode(tmpString);
}
} catch (NumberFormatException ignored) {
// Ignore
}
return null;
}
});
if (tmp != null) {
cachePolicy = tmp < 0 ? FOREVER : tmp;
propertySet = true;
} else {
/* No properties defined for positive caching. If there is no
* security manager then use the default positive cache value.
*/
if (System.getSecurityManager() == null) {
cachePolicy = DEFAULT_POSITIVE;
}
}
tmp = java.security.AccessController.doPrivileged (
new PrivilegedAction<Integer>() {
public Integer run() {
try {
String tmpString = Security.getProperty(negativeCachePolicyProp);
if (tmpString != null) {
return Integer.valueOf(tmpString);
}
} catch (NumberFormatException ignored) {
// Ignore
}
try {
String tmpString = System.getProperty(negativeCachePolicyPropFallback);
if (tmpString != null) {
return Integer.decode(tmpString);
}
} catch (NumberFormatException ignored) {
// Ignore
}
return null;
}
});
if (tmp != null) {
negativeCachePolicy = tmp < 0 ? FOREVER : tmp;
propertyNegativeSet = true;
}
}
public static int get() {
return cachePolicy;
}
public static int getNegative() {
return negativeCachePolicy;
}
/**
* Sets the cache policy for successful lookups if the user has not
* already specified a cache policy for it using a
* command-property.
* @param newPolicy the value in seconds for how long the lookup
* should be cached
*/
public static synchronized void setIfNotSet(int newPolicy) {
/*
* When setting the new value we may want to signal that the
* cache should be flushed, though this doesn't seem strictly
* necessary.
*/
if (!propertySet) {
checkValue(newPolicy, cachePolicy);
cachePolicy = newPolicy;
}
}
/**
* Sets the cache policy for negative lookups if the user has not
* already specified a cache policy for it using a
* command-property.
* @param newPolicy the value in seconds for how long the lookup
* should be cached
*/
public static void setNegativeIfNotSet(int newPolicy) {
/*
* When setting the new value we may want to signal that the
* cache should be flushed, though this doesn't seem strictly
* necessary.
*/
if (!propertyNegativeSet) {
// Negative caching does not seem to have any security
// implications.
// checkValue(newPolicy, negativeCachePolicy);
// but we should normalize negative policy
negativeCachePolicy = newPolicy < 0 ? FOREVER : newPolicy;
}
}
private static void checkValue(int newPolicy, int oldPolicy) {
/*
* If malicious code gets a hold of this method, prevent
* setting the cache policy to something laxer or some
* invalid negative value.
*/
if (newPolicy == FOREVER)
return;
if ((oldPolicy == FOREVER) ||
(newPolicy < oldPolicy) ||
(newPolicy < FOREVER)) {
throw new
SecurityException("can't make InetAddress cache more lax");
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.net.InetAddress;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* Defines static methods to ensure that any installed net hooks are invoked
* prior to binding or connecting TCP sockets.
*/
public final class NetHooks {
/**
* Invoke prior to binding a TCP socket.
*/
public static void beforeTcpBind(FileDescriptor fdObj,
InetAddress address,
int port)
throws IOException
{
// nothing to do
}
/**
* Invoke prior to connecting an unbound TCP socket.
*/
public static void beforeTcpConnect(FileDescriptor fdObj,
InetAddress address,
int port)
throws IOException
{
// nothing to do
}
}

View File

@@ -0,0 +1,158 @@
/*
* Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.io.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Properties;
/*
* This class allows for centralized access to Networking properties.
* Default values are loaded from the file jre/lib/net.properties
*
*
* @author Jean-Christophe Collet
*
*/
public class NetProperties {
static private Properties props = new Properties();
static {
AccessController.doPrivileged(
new PrivilegedAction<Void>() {
public Void run() {
loadDefaultProperties();
return null;
}});
}
private NetProperties() { };
/*
* Loads the default networking system properties
* the file is in jre/lib/net.properties
*/
static private void loadDefaultProperties() {
String fname = System.getProperty("java.home");
if (fname == null) {
throw new Error("Can't find java.home ??");
}
try {
File f = new File(fname, "lib");
f = new File(f, "net.properties");
fname = f.getCanonicalPath();
InputStream in = new FileInputStream(fname);
BufferedInputStream bin = new BufferedInputStream(in);
props.load(bin);
bin.close();
} catch (Exception e) {
// Do nothing. We couldn't find or access the file
// so we won't have default properties...
}
}
/**
* Get a networking system property. If no system property was defined
* returns the default value, if it exists, otherwise returns
* <code>null</code>.
* @param key the property name.
* @throws SecurityException if a security manager exists and its
* <code>checkPropertiesAccess</code> method doesn't allow access
* to the system properties.
* @return the <code>String</code> value for the property,
* or <code>null</code>
*/
static public String get(String key) {
String def = props.getProperty(key);
try {
return System.getProperty(key, def);
} catch (IllegalArgumentException e) {
} catch (NullPointerException e) {
}
return null;
}
/**
* Get an Integer networking system property. If no system property was
* defined returns the default value, if it exists, otherwise returns
* <code>null</code>.
* @param key the property name.
* @param defval the default value to use if the property is not found
* @throws SecurityException if a security manager exists and its
* <code>checkPropertiesAccess</code> method doesn't allow access
* to the system properties.
* @return the <code>Integer</code> value for the property,
* or <code>null</code>
*/
static public Integer getInteger(String key, int defval) {
String val = null;
try {
val = System.getProperty(key, props.getProperty(key));
} catch (IllegalArgumentException e) {
} catch (NullPointerException e) {
}
if (val != null) {
try {
return Integer.decode(val);
} catch (NumberFormatException ex) {
}
}
return new Integer(defval);
}
/**
* Get a Boolean networking system property. If no system property was
* defined returns the default value, if it exists, otherwise returns
* <code>null</code>.
* @param key the property name.
* @throws SecurityException if a security manager exists and its
* <code>checkPropertiesAccess</code> method doesn't allow access
* to the system properties.
* @return the <code>Boolean</code> value for the property,
* or <code>null</code>
*/
static public Boolean getBoolean(String key) {
String val = null;
try {
val = System.getProperty(key, props.getProperty(key));
} catch (IllegalArgumentException e) {
} catch (NullPointerException e) {
}
if (val != null) {
try {
return Boolean.valueOf(val);
} catch (NumberFormatException ex) {
}
}
return null;
}
}

View File

@@ -0,0 +1,273 @@
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.io.*;
import java.net.Socket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.net.Proxy;
import java.util.Arrays;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* This is the base class for network clients.
*
* @author Jonathan Payne
*/
public class NetworkClient {
/* Default value of read timeout, if not specified (infinity) */
public static final int DEFAULT_READ_TIMEOUT = -1;
/* Default value of connect timeout, if not specified (infinity) */
public static final int DEFAULT_CONNECT_TIMEOUT = -1;
protected Proxy proxy = Proxy.NO_PROXY;
/** Socket for communicating with server. */
protected Socket serverSocket = null;
/** Stream for printing to the server. */
public PrintStream serverOutput;
/** Buffered stream for reading replies from server. */
public InputStream serverInput;
protected static int defaultSoTimeout;
protected static int defaultConnectTimeout;
protected int readTimeout = DEFAULT_READ_TIMEOUT;
protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
/* Name of encoding to use for output */
protected static String encoding;
static {
final int vals[] = {0, 0};
final String encs[] = { null };
AccessController.doPrivileged(
new PrivilegedAction<Void>() {
public Void run() {
vals[0] = Integer.getInteger("sun.net.client.defaultReadTimeout", 0).intValue();
vals[1] = Integer.getInteger("sun.net.client.defaultConnectTimeout", 0).intValue();
encs[0] = System.getProperty("file.encoding", "ISO8859_1");
return null;
}
});
if (vals[0] != 0) {
defaultSoTimeout = vals[0];
}
if (vals[1] != 0) {
defaultConnectTimeout = vals[1];
}
encoding = encs[0];
try {
if (!isASCIISuperset (encoding)) {
encoding = "ISO8859_1";
}
} catch (Exception e) {
encoding = "ISO8859_1";
}
}
/**
* Test the named character encoding to verify that it converts ASCII
* characters correctly. We have to use an ASCII based encoding, or else
* the NetworkClients will not work correctly in EBCDIC based systems.
* However, we cannot just use ASCII or ISO8859_1 universally, because in
* Asian locales, non-ASCII characters may be embedded in otherwise
* ASCII based protocols (eg. HTTP). The specifications (RFC2616, 2398)
* are a little ambiguous in this matter. For instance, RFC2398 [part 2.1]
* says that the HTTP request URI should be escaped using a defined
* mechanism, but there is no way to specify in the escaped string what
* the original character set is. It is not correct to assume that
* UTF-8 is always used (as in URLs in HTML 4.0). For this reason,
* until the specifications are updated to deal with this issue more
* comprehensively, and more importantly, HTTP servers are known to
* support these mechanisms, we will maintain the current behavior
* where it is possible to send non-ASCII characters in their original
* unescaped form.
*/
private static boolean isASCIISuperset (String encoding) throws Exception {
String chkS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"+
"abcdefghijklmnopqrstuvwxyz-_.!~*'();/?:@&=+$,";
// Expected byte sequence for string above
byte[] chkB = { 48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,71,72,
73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,
100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
115,116,117,118,119,120,121,122,45,95,46,33,126,42,39,40,41,59,
47,63,58,64,38,61,43,36,44};
byte[] b = chkS.getBytes (encoding);
return Arrays.equals (b, chkB);
}
/** Open a connection to the server. */
public void openServer(String server, int port)
throws IOException, UnknownHostException {
if (serverSocket != null)
closeServer();
serverSocket = doConnect (server, port);
try {
serverOutput = new PrintStream(new BufferedOutputStream(
serverSocket.getOutputStream()),
true, encoding);
} catch (UnsupportedEncodingException e) {
throw new InternalError(encoding +"encoding not found", e);
}
serverInput = new BufferedInputStream(serverSocket.getInputStream());
}
/**
* Return a socket connected to the server, with any
* appropriate options pre-established
*/
protected Socket doConnect (String server, int port)
throws IOException, UnknownHostException {
Socket s;
if (proxy != null) {
if (proxy.type() == Proxy.Type.SOCKS) {
s = AccessController.doPrivileged(
new PrivilegedAction<Socket>() {
public Socket run() {
return new Socket(proxy);
}});
} else if (proxy.type() == Proxy.Type.DIRECT) {
s = createSocket();
} else {
// Still connecting through a proxy
// server & port will be the proxy address and port
s = new Socket(Proxy.NO_PROXY);
}
} else
s = createSocket();
// Instance specific timeouts do have priority, that means
// connectTimeout & readTimeout (-1 means not set)
// Then global default timeouts
// Then no timeout.
if (connectTimeout >= 0) {
s.connect(new InetSocketAddress(server, port), connectTimeout);
} else {
if (defaultConnectTimeout > 0) {
s.connect(new InetSocketAddress(server, port), defaultConnectTimeout);
} else {
s.connect(new InetSocketAddress(server, port));
}
}
if (readTimeout >= 0)
s.setSoTimeout(readTimeout);
else if (defaultSoTimeout > 0) {
s.setSoTimeout(defaultSoTimeout);
}
return s;
}
/**
* The following method, createSocket, is provided to allow the
* https client to override it so that it may use its socket factory
* to create the socket.
*/
protected Socket createSocket() throws IOException {
return new java.net.Socket();
}
protected InetAddress getLocalAddress() throws IOException {
if (serverSocket == null)
throw new IOException("not connected");
return AccessController.doPrivileged(
new PrivilegedAction<InetAddress>() {
public InetAddress run() {
return serverSocket.getLocalAddress();
}
});
}
/** Close an open connection to the server. */
public void closeServer() throws IOException {
if (! serverIsOpen()) {
return;
}
serverSocket.close();
serverSocket = null;
serverInput = null;
serverOutput = null;
}
/** Return server connection status */
public boolean serverIsOpen() {
return serverSocket != null;
}
/** Create connection with host <i>host</i> on port <i>port</i> */
public NetworkClient(String host, int port) throws IOException {
openServer(host, port);
}
public NetworkClient() {}
public void setConnectTimeout(int timeout) {
connectTimeout = timeout;
}
public int getConnectTimeout() {
return connectTimeout;
}
/**
* Sets the read timeout.
*
* Note: Public URLConnection (and protocol specific implementations)
* protect against negative timeout values being set. This implementation,
* and protocol specific implementations, use -1 to represent the default
* read timeout.
*
* This method may be invoked with the default timeout value when the
* protocol handler is trying to reset the timeout after doing a
* potentially blocking internal operation, e.g. cleaning up unread
* response data, buffering error stream response data, etc
*/
public void setReadTimeout(int timeout) {
if (timeout == DEFAULT_READ_TIMEOUT)
timeout = defaultSoTimeout;
if (serverSocket != null && timeout >= 0) {
try {
serverSocket.setSoTimeout(timeout);
} catch(IOException e) {
// We tried...
}
}
readTimeout = timeout;
}
public int getReadTimeout() {
return readTimeout;
}
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.io.*;
import java.net.Socket;
import java.net.ServerSocket;
/**
* This is the base class for network servers. To define a new type
* of server define a new subclass of NetworkServer with a serviceRequest
* method that services one request. Start the server by executing:
* <pre>
* new MyServerClass().startServer(port);
* </pre>
*/
public class NetworkServer implements Runnable, Cloneable {
/** Socket for communicating with client. */
public Socket clientSocket = null;
private Thread serverInstance;
private ServerSocket serverSocket;
/** Stream for printing to the client. */
public PrintStream clientOutput;
/** Buffered stream for reading replies from client. */
public InputStream clientInput;
/** Close an open connection to the client. */
public void close() throws IOException {
clientSocket.close();
clientSocket = null;
clientInput = null;
clientOutput = null;
}
/** Return client connection status */
public boolean clientIsOpen() {
return clientSocket != null;
}
final public void run() {
if (serverSocket != null) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
// System.out.print("Server starts " + serverSocket + "\n");
while (true) {
try {
Socket ns = serverSocket.accept();
// System.out.print("New connection " + ns + "\n");
NetworkServer n = (NetworkServer)clone();
n.serverSocket = null;
n.clientSocket = ns;
new Thread(n).start();
} catch(Exception e) {
System.out.print("Server failure\n");
e.printStackTrace();
try {
serverSocket.close();
} catch(IOException e2) {}
System.out.print("cs="+serverSocket+"\n");
break;
}
}
// close();
} else {
try {
clientOutput = new PrintStream(
new BufferedOutputStream(clientSocket.getOutputStream()),
false, "ISO8859_1");
clientInput = new BufferedInputStream(clientSocket.getInputStream());
serviceRequest();
// System.out.print("Service handler exits
// "+clientSocket+"\n");
} catch(Exception e) {
// System.out.print("Service handler failure\n");
// e.printStackTrace();
}
try {
close();
} catch(IOException e2) {}
}
}
/** Start a server on port <i>port</i>. It will call serviceRequest()
for each new connection. */
final public void startServer(int port) throws IOException {
serverSocket = new ServerSocket(port, 50);
serverInstance = new Thread(this);
serverInstance.start();
}
/** Service one request. It is invoked with the clientInput and
clientOutput streams initialized. This method handles one client
connection. When it is done, it can simply exit. The default
server just echoes it's input. It is invoked in it's own private
thread. */
public void serviceRequest() throws IOException {
byte buf[] = new byte[300];
int n;
clientOutput.print("Echo server " + getClass().getName() + "\n");
clientOutput.flush();
while ((n = clientInput.read(buf, 0, buf.length)) >= 0) {
clientOutput.write(buf, 0, n);
}
}
public static void main(String argv[]) {
try {
new NetworkServer ().startServer(8888);
} catch (IOException e) {
System.out.print("Server failed: "+e+"\n");
}
}
/**
* Clone this object;
*/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
public NetworkServer () {
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.security.AccessController;
/**
* Determines the ephemeral port range in use on this system.
* If this cannot be determined, then the default settings
* of the OS are returned.
*/
public final class PortConfig {
private static int defaultUpper, defaultLower;
private final static int upper, lower;
static {
AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("net");
return null;
}
});
int v = getLower0();
if (v == -1) {
v = defaultLower;
}
lower = v;
v = getUpper0();
if (v == -1) {
v = defaultUpper;
}
upper = v;
}
static native int getLower0();
static native int getUpper0();
public static int getLower() {
return lower;
}
public static int getUpper() {
return upper;
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.util.EventObject;
import java.net.URL;
/**
* ProgressEvent represents an progress event in monitering network input stream.
*
* @author Stanley Man-Kit Ho
*/
@SuppressWarnings("serial") // never serialized
public class ProgressEvent extends EventObject {
// URL of the stream
private URL url;
// content type of the stream
private String contentType;
// method associated with URL
private String method;
// bytes read
private long progress;
// bytes expected
private long expected;
// the last thing to happen
private ProgressSource.State state;
/**
* Construct a ProgressEvent object.
*/
public ProgressEvent(ProgressSource source, URL url, String method, String contentType, ProgressSource.State state, long progress, long expected) {
super(source);
this.url = url;
this.method = method;
this.contentType = contentType;
this.progress = progress;
this.expected = expected;
this.state = state;
}
/**
* Return URL related to the progress.
*/
public URL getURL()
{
return url;
}
/**
* Return method associated with URL.
*/
public String getMethod()
{
return method;
}
/**
* Return content type of the URL.
*/
public String getContentType()
{
return contentType;
}
/**
* Return current progress value.
*/
public long getProgress()
{
return progress;
}
/**
* Return expected maximum progress value; -1 if expected is unknown.
*/
public long getExpected() {
return expected;
}
/**
* Return state.
*/
public ProgressSource.State getState() {
return state;
}
public String toString() {
return getClass().getName() + "[url=" + url + ", method=" + method + ", state=" + state
+ ", content-type=" + contentType + ", progress=" + progress + ", expected=" + expected + "]";
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.util.EventListener;
/**
* ProgressListener is an interface to be implemented by parties
* interested to be notified of progress in network input stream.
*
* @author Stanley Man-Kit Ho
*/
public interface ProgressListener extends EventListener
{
/**
* Start progress.
*/
public void progressStart(ProgressEvent evt);
/**
* Update progress.
*/
public void progressUpdate(ProgressEvent evt);
/**
* Finish progress.
*/
public void progressFinish(ProgressEvent evt);
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.net.URL;
/**
* ProgressMeteringPolicy is an interface for determining progress metering policy.
*
* @author Stanley Man-Kit Ho
*/
public interface ProgressMeteringPolicy
{
/**
* Return true if metering should be turned on for a particular network input stream.
*/
public boolean shouldMeterInput(URL url, String method);
/**
* Return update notification threshold.
*/
public int getProgressUpdateThreshold();
}

View File

@@ -0,0 +1,257 @@
/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.util.ArrayList;
import java.util.Iterator;
import java.net.URL;
/**
* ProgressMonitor is a class for monitoring progress in network input stream.
*
* @author Stanley Man-Kit Ho
*/
public class ProgressMonitor
{
/**
* Return default ProgressMonitor.
*/
public static synchronized ProgressMonitor getDefault() {
return pm;
}
/**
* Change default ProgressMonitor implementation.
*/
public static synchronized void setDefault(ProgressMonitor m) {
if (m != null)
pm = m;
}
/**
* Change progress metering policy.
*/
public static synchronized void setMeteringPolicy(ProgressMeteringPolicy policy) {
if (policy != null)
meteringPolicy = policy;
}
/**
* Return a snapshot of the ProgressSource list
*/
public ArrayList<ProgressSource> getProgressSources() {
ArrayList<ProgressSource> snapshot = new ArrayList<ProgressSource>();
try {
synchronized(progressSourceList) {
for (Iterator<ProgressSource> iter = progressSourceList.iterator(); iter.hasNext();) {
ProgressSource pi = iter.next();
// Clone ProgressSource and add to snapshot
snapshot.add((ProgressSource)pi.clone());
}
}
}
catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return snapshot;
}
/**
* Return update notification threshold
*/
public synchronized int getProgressUpdateThreshold() {
return meteringPolicy.getProgressUpdateThreshold();
}
/**
* Return true if metering should be turned on
* for a particular URL input stream.
*/
public boolean shouldMeterInput(URL url, String method) {
return meteringPolicy.shouldMeterInput(url, method);
}
/**
* Register progress source when progress is began.
*/
public void registerSource(ProgressSource pi) {
synchronized(progressSourceList) {
if (progressSourceList.contains(pi))
return;
progressSourceList.add(pi);
}
// Notify only if there is at least one listener
if (progressListenerList.size() > 0)
{
// Notify progress listener if there is progress change
ArrayList<ProgressListener> listeners = new ArrayList<ProgressListener>();
// Copy progress listeners to another list to avoid holding locks
synchronized(progressListenerList) {
for (Iterator<ProgressListener> iter = progressListenerList.iterator(); iter.hasNext();) {
listeners.add(iter.next());
}
}
// Fire event on each progress listener
for (Iterator<ProgressListener> iter = listeners.iterator(); iter.hasNext();) {
ProgressListener pl = iter.next();
ProgressEvent pe = new ProgressEvent(pi, pi.getURL(), pi.getMethod(), pi.getContentType(), pi.getState(), pi.getProgress(), pi.getExpected());
pl.progressStart(pe);
}
}
}
/**
* Unregister progress source when progress is finished.
*/
public void unregisterSource(ProgressSource pi) {
synchronized(progressSourceList) {
// Return if ProgressEvent does not exist
if (progressSourceList.contains(pi) == false)
return;
// Close entry and remove from map
pi.close();
progressSourceList.remove(pi);
}
// Notify only if there is at least one listener
if (progressListenerList.size() > 0)
{
// Notify progress listener if there is progress change
ArrayList<ProgressListener> listeners = new ArrayList<ProgressListener>();
// Copy progress listeners to another list to avoid holding locks
synchronized(progressListenerList) {
for (Iterator<ProgressListener> iter = progressListenerList.iterator(); iter.hasNext();) {
listeners.add(iter.next());
}
}
// Fire event on each progress listener
for (Iterator<ProgressListener> iter = listeners.iterator(); iter.hasNext();) {
ProgressListener pl = iter.next();
ProgressEvent pe = new ProgressEvent(pi, pi.getURL(), pi.getMethod(), pi.getContentType(), pi.getState(), pi.getProgress(), pi.getExpected());
pl.progressFinish(pe);
}
}
}
/**
* Progress source is updated.
*/
public void updateProgress(ProgressSource pi) {
synchronized (progressSourceList) {
if (progressSourceList.contains(pi) == false)
return;
}
// Notify only if there is at least one listener
if (progressListenerList.size() > 0)
{
// Notify progress listener if there is progress change
ArrayList<ProgressListener> listeners = new ArrayList<ProgressListener>();
// Copy progress listeners to another list to avoid holding locks
synchronized(progressListenerList) {
for (Iterator<ProgressListener> iter = progressListenerList.iterator(); iter.hasNext();) {
listeners.add(iter.next());
}
}
// Fire event on each progress listener
for (Iterator<ProgressListener> iter = listeners.iterator(); iter.hasNext();) {
ProgressListener pl = iter.next();
ProgressEvent pe = new ProgressEvent(pi, pi.getURL(), pi.getMethod(), pi.getContentType(), pi.getState(), pi.getProgress(), pi.getExpected());
pl.progressUpdate(pe);
}
}
}
/**
* Add progress listener in progress monitor.
*/
public void addProgressListener(ProgressListener l) {
synchronized(progressListenerList) {
progressListenerList.add(l);
}
}
/**
* Remove progress listener from progress monitor.
*/
public void removeProgressListener(ProgressListener l) {
synchronized(progressListenerList) {
progressListenerList.remove(l);
}
}
// Metering policy
private static ProgressMeteringPolicy meteringPolicy = new DefaultProgressMeteringPolicy();
// Default implementation
private static ProgressMonitor pm = new ProgressMonitor();
// ArrayList for outstanding progress sources
private ArrayList<ProgressSource> progressSourceList = new ArrayList<ProgressSource>();
// ArrayList for progress listeners
private ArrayList<ProgressListener> progressListenerList = new ArrayList<ProgressListener>();
}
/**
* Default progress metering policy.
*/
class DefaultProgressMeteringPolicy implements ProgressMeteringPolicy {
/**
* Return true if metering should be turned on for a particular network input stream.
*/
public boolean shouldMeterInput(URL url, String method)
{
// By default, no URL input stream is metered for
// performance reason.
return false;
}
/**
* Return update notification threshold.
*/
public int getProgressUpdateThreshold() {
// 8K - same as default I/O buffer size
return 8192;
}
}

View File

@@ -0,0 +1,210 @@
/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.net.URL;
/**
* ProgressSource represents the source of progress changes.
*
* @author Stanley Man-Kit Ho
*/
public class ProgressSource
{
public enum State { NEW, CONNECTED, UPDATE, DELETE };
// URL
private URL url;
// URL method
private String method;
// Content type
private String contentType;
// bytes read
private long progress = 0;
// last bytes read
private long lastProgress = 0;
//bytes expected
private long expected = -1;
// the last thing to happen with this source
private State state;
// connect flag
private boolean connected = false;
// threshold for notification
private int threshold = 8192;
// progress monitor
private ProgressMonitor progressMonitor;
/**
* Construct progress source object.
*/
public ProgressSource(URL url, String method) {
this(url, method, -1);
}
/**
* Construct progress source object.
*/
public ProgressSource(URL url, String method, long expected) {
this.url = url;
this.method = method;
this.contentType = "content/unknown";
this.progress = 0;
this.lastProgress = 0;
this.expected = expected;
this.state = State.NEW;
this.progressMonitor = ProgressMonitor.getDefault();
this.threshold = progressMonitor.getProgressUpdateThreshold();
}
public boolean connected() {
if (!connected) {
connected = true;
state = State.CONNECTED;
return false;
}
return true;
}
/**
* Close progress source.
*/
public void close() {
state = State.DELETE;
}
/**
* Return URL of progress source.
*/
public URL getURL() {
return url;
}
/**
* Return method of URL.
*/
public String getMethod() {
return method;
}
/**
* Return content type of URL.
*/
public String getContentType() {
return contentType;
}
// Change content type
public void setContentType(String ct) {
contentType = ct;
}
/**
* Return current progress.
*/
public long getProgress() {
return progress;
}
/**
* Return expected maximum progress; -1 if expected is unknown.
*/
public long getExpected() {
return expected;
}
/**
* Return state.
*/
public State getState() {
return state;
}
/**
* Begin progress tracking.
*/
public void beginTracking() {
progressMonitor.registerSource(this);
}
/**
* Finish progress tracking.
*/
public void finishTracking() {
progressMonitor.unregisterSource(this);
}
/**
* Update progress.
*/
public void updateProgress(long latestProgress, long expectedProgress) {
lastProgress = progress;
progress = latestProgress;
expected = expectedProgress;
if (connected() == false)
state = State.CONNECTED;
else
state = State.UPDATE;
// The threshold effectively divides the progress into
// different set of ranges:
//
// Range 0: 0..threshold-1,
// Range 1: threshold .. 2*threshold-1
// ....
// Range n: n*threshold .. (n+1)*threshold-1
//
// To determine which range the progress belongs to, it
// would be calculated as follow:
//
// range number = progress / threshold
//
// Notification should only be triggered when the current
// progress and the last progress are in different ranges,
// i.e. they have different range numbers.
//
// Using this range scheme, notification will be generated
// only once when the progress reaches each range.
//
if (lastProgress / threshold != progress / threshold) {
progressMonitor.updateProgress(this);
}
// Detect read overrun
if (expected != -1) {
if (progress >= expected && progress != 0)
close();
}
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String toString() {
return getClass().getName() + "[url=" + url + ", method=" + method + ", state=" + state
+ ", content-type=" + contentType + ", progress=" + progress + ", expected=" + expected + "]";
}
}

View File

@@ -0,0 +1,913 @@
/*
* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/*
* WARNING: This class may contain out-of-date information. It should be
* updated or replaced with an appropriate implementation. See
* sun.security.util.RegisteredDomain for more information.
*
* The naming tables listed below were gathered from publicly available data such as
* the subdomain registration websites listed for each top-level domain by the Internet
* Assigned Numbers Authority and the website of the Internet Corporation for Assigned Names
* and Numbers as well as Wikipedia.
*/
public class RegisteredDomain {
// XX.AA
private static Set<String> top1Set = new HashSet<String>(Arrays.asList("asia", "biz", "cat", "coop",
"edu", "info", "gov", "jobs", "travel", "am", "aq", "ax", "cc", "cf", "cg", "ch", "cv", "cz",
"de", "dj", "dk", "fm", "fo", "ga", "gd", "gf", "gl", "gm", "gq", "gs", "gw", "hm",
"li", "lu", "md", "mh", "mil", "mobi", "mq", "ms", "ms", "ne", "nl", "nu", "si",
"sm", "sr", "su", "tc", "td", "tf", "tg", "tk", "tm", "tv", "va", "vg",
/* ae */ "xn--mgbaam7a8h", /* cn s */ "xn--fiqs8s", /* cn t */ "xn--fiqz9s",
/* eg */ "xn--wgbh1c", /* hk */ "xn--j6w193g", /* jo */ "xn--mgbayh7gpa",
/* lk */ "xn--fzc2c9e2c", /* ps */ "xn--ygbi2ammx", /* ru */ "xn--p1ai",
/* qa */ "xn--wgbl6a", /* sa */ "xn--mgberp4a5d4ar", /* sg */ "xn--yfro4i67o",
/* th */ "xn--o3cw4h", /* tn */ "xn--pgbs0dh", /* tw s */ "xn--kpry57d",
/* tw */ "xn--kprw13d", /* sg tamil */ "xn--clchc0ea0b2g2a9gcd"));
// common pattern: XX.AA or XX.GOV.AA
private static Set<String> top2Set = new HashSet<String>(Arrays.asList("as", "bf", "cd", "cx",
"ie", "lt", "mr", "tl"));
// common pattern: XX.AA or XX.COM.AA or XX.EDU.AA or XX.NET.AA or XX.ORG.AA or XX.GOV.AA
private static Set<String> top4Set = new HashSet<String>(Arrays.asList("af", "bm", "bs", "bt",
"bz", "dm", "ky", "lb", "lr", "mo", "sc", "sl", "ws"));
// AA or less than 3 other XX.BB.AA possible matches
private static Set<String> top3Set = new HashSet<String>(Arrays.asList("ad", "aw", "be", "bw",
"cl", "fi", "int", "io", "mc"));
// AA.UK exceptions
private static Set<String> ukSet = new HashSet<String>(Arrays.asList( "bl", "british-library",
"jet", "nhs", "nls", "parliament", "mod", "police"));
// AA.AR exceptions
private static Set<String> arSet = new HashSet<String>(Arrays.asList( "argentina", "educ",
"gobiernoelectronico", "nic", "promocion", "retina", "uba"));
// AA.OM exceptions
private static Set<String> omSet = new HashSet<String>(Arrays.asList("mediaphone", "nawrastelecom",
"nawras", "omanmobile", "omanpost", "omantel", "rakpetroleum", "siemens", "songfest",
"statecouncil", "shura", "peie", "omran", "omnic", "omanet", "oman", "muriya", "kom"));
// any XX.BB.AA
private static Set<String> top5Set = new HashSet<String>(Arrays.asList("au", "arpa", "bd", "bn", "ck",
"cy", "er", "et", "fj", "fk", "gt", "gu", "il", "jm", "ke", "kh", "kw",
"mm", "mt", "mz", "ni", "np", "nz", "pg", "sb", "sv", "tz", "uy", "ve", "ye",
"za", "zm", "zw"));
// XX.CC.BB.JP
private static Set<String> jpSet = new HashSet<String>(Arrays.asList("aichi", "akita", "aomori",
"chiba", "ehime", "fukui", "fukuoka", "fukushima", "gifu", "gunma", "hiroshima", "hokkaido",
"hyogo", "ibaraki", "ishikawa", "iwate", "kagawa", "kagoshima", "kanagawa", "kawasaki",
"kitakyushu", "kobe", "kochi", "kumamoto", "kyoto", "mie", "miyagi", "miyazaki", "nagano",
"nagasaki", "nagoya", "nara", "niigata", "oita", "okayama", "okinawa", "osaka", "saga",
"saitama", "sapporo", "sendai", "shiga", "shimane", "shizuoka", "tochigi", "tokushima",
"tokyo", "tottori", "toyama", "wakayama", "yamagata", "yamaguchi", "yamanashi", "yokohama"));
// CC.BB.JP exceptions
private static Set<String> jp2Set = new HashSet<String>(Arrays.asList("metro.tokyo.jp",
"pref.aichi.jp", "pref.akita.jp", "pref.aomori.jp", "pref.chiba.jp", "pref.ehime.jp",
"pref.fukui.jp", "pref.fukuoka.jp", "pref.fukushima.jp", "pref.gifu.jp", "pref.gunma.jp",
"pref.hiroshima.jp", "pref.hokkaido.jp", "pref.hyogo.jp", "pref.ibaraki.jp", "pref.ishikawa.jp",
"pref.iwate.jp", "pref.kagawa.jp", "pref.kagoshima.jp", "pref.kanagawa.jp", "pref.kochi.jp",
"pref.kumamoto.jp", "pref.kyoto.jp", "pref.mie.jp", "pref.miyagi.jp", "pref.miyazaki.jp",
"pref.nagano.jp", "pref.nagasaki.jp", "pref.nara.jp", "pref.niigata.jp", "pref.oita.jp",
"pref.okayama.jp", "pref.okinawa.jp", "pref.osaka.jp", "pref.saga.jp", "pref.saitama.jp",
"pref.shiga.jp", "pref.shimane.jp", "pref.shizuoka.jp", "pref.tochigi.jp", "pref.tokushima.jp",
"pref.tottori.jp", "pref.toyama.jp", "pref.wakayama.jp", "pref.yamagata.jp", "pref.yamaguchi.jp",
"pref.yamanashi.jp", "city.chiba.jp", "city.fukuoka.jp", "city.hamamatsu.jp", "city.hiroshima.jp", "city.kawasaki.jp",
"city.kitakyushu.jp", "city.kobe.jp", "city.kyoto.jp", "city.nagoya.jp", "city.niigata.jp",
"city.okayama.jp", "city.osaka.jp", "city.sagamihara.jp", "city.saitama.jp", "city.sapporo.jp", "city.sendai.jp",
"city.shizuoka.jp", "city.yokohama.jp"));
private static Set<String> usStateSet = new HashSet<String>(Arrays.asList("ak",
"al", "ar", "as", "az", "ca", "co", "ct", "dc", "de", "fl", "ga", "gu", "hi", "ia",
"id", "il", "in", "ks", "ky", "la", "ma", "md", "me", "mi", "mn", "mo", "ms", "mt",
"nc", "nd", "ne", "nh", "nj", "nm", "nv", "ny", "oh", "ok", "or", "pa", "pr", "ri",
"sc", "sd", "tn", "tx", "ut", "vi", "vt", "va", "wa", "wi", "wv", "wy"));
private static Set<String> usSubStateSet = new HashSet<String>(Arrays.asList("state",
"lib", "k12", "cc", "tec", "gen", "cog", "mus", "dst"));
private static Map<String,Set<String>> topMap = new HashMap<>();
private static Map<String,Set<String>> top3Map = new HashMap<>();
static {
/*
* XX.AA or XX.BB.AA
*/
topMap.put("ac", new HashSet<String>(Arrays.asList("com", "co", "edu", "gov", "net", "mil", "org")));
topMap.put("ae", new HashSet<String>(Arrays.asList("co", "net", "org", "sch", "ac", "gov", "mil")));
topMap.put("aero", new HashSet<String>(Arrays.asList("accident-investigation",
"accident-prevention", "aerobatic", "aeroclub", "aerodrome", "agents", "aircraft",
"airline", "airport", "air-surveillance", "airtraffic", "air-traffic-control",
"ambulance", "amusement", "association", "author", "ballooning", "broker", "caa",
"cargo", "catering", "certification", "championship", "charter", "civilaviation",
"club", "conference", "consultant", "consulting", "control", "council", "crew",
"design", "dgca", "educator", "emergency", "engine", "engineer", "entertainment",
"equipment", "exchange", "express", "federation", "flight", "freight", "fuel",
"gliding", "government", "groundhandling", "group", "hanggliding", "homebuilt",
"insurance", "journal", "journalist", "leasing", "logistics", "magazine",
"maintenance", "marketplace", "media", "microlight", "modelling", "navigation",
"parachuting", "paragliding", "passenger-association", "pilot", "press", "production",
"recreation", "repbody", "res", "research", "rotorcraft", "safety", "scientist",
"services", "show", "skydiving", "software", "student", "taxi", "trader", "trading",
"trainer", "union", "workinggroup", "works" )));
topMap.put( "ag", new HashSet<String>(Arrays.asList("com", "org", "net", "co", "nom")));
topMap.put( "ai", new HashSet<String>(Arrays.asList("off", "com", "net", "org")));
topMap.put( "al", new HashSet<String>(Arrays.asList("com", "edu", "gov", "mil", "net", "org")));
topMap.put( "an", new HashSet<String>(Arrays.asList("com")));
topMap.put( "ao", new HashSet<String>(Arrays.asList("ed", "gv", "og", "co", "pb", "it")));
topMap.put( "at", new HashSet<String>(Arrays.asList("ac", "co", "gv", "or", "biz", "info", "priv")));
topMap.put( "az", new HashSet<String>(Arrays.asList("com", "net", "int", "gov", "org", "edu", "info",
"pp", "mil", "name", "biz")));
topMap.put( "ba", new HashSet<String>(Arrays.asList("org", "net", "edu", "gov", "mil", "unbi",
"unmo", "unsa", "untz", "unze", "co", "com", "rs")));
topMap.put( "bb", new HashSet<String>(Arrays.asList("biz", "com", "edu", "gov", "info", "net", "org",
"store")));
topMap.put( "bg", new HashSet<String>(Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
"k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1",
"2", "3", "4", "5", "6", "7", "8", "9")));
topMap.put( "bh", new HashSet<String>(Arrays.asList("com", "info", "cc", "edu", "biz", "net",
"org", "gov")));
topMap.put( "bi", new HashSet<String>(Arrays.asList("co", "com", "edu", "gov", "info", "or", "org")));
topMap.put( "bj", new HashSet<String>(Arrays.asList("asso", "barreau", "com", "edu", "gouv", "gov", "mil")));
topMap.put( "bo", new HashSet<String>(Arrays.asList("com", "edu", "gov", "gob", "int", "org", "net",
"mil", "tv")));
topMap.put( "br", new HashSet<String>(Arrays.asList("adm", "adv", "agr", "am", "arq", "art", "ato",
"b", "bio", "blog", "bmd", "cim", "cng", "cnt", "com", "coop", "ecn", "edu", "emp", "eng",
"esp", "etc", "eti", "far", "flog", "fm", "fnd", "fot", "fst", "g12", "ggf", "gov",
"imb", "ind", "inf", "jor", "jus", "lel", "mat", "med", "mil", "mus", "net", "nom",
"not", "ntr", "odo", "org", "ppg", "pro", "psc", "psi", "qsl", "radio", "rec", "slg",
"srv", "taxi", "teo", "tmp", "trd", "tur", "tv", "vet", "vlog", "wiki", "zlg")));
topMap.put( "bw", new HashSet<String>(Arrays.asList("co", "gov", "org")));
topMap.put( "by", new HashSet<String>(Arrays.asList("gov", "mil", "com", "of")));
topMap.put( "ca", new HashSet<String>(Arrays.asList("ab", "bc", "mb", "nb", "nf",
"nl", "ns", "nt", "nu", "on", "pe", "qc", "sk", "yk", "gc")));
topMap.put( "ci", new HashSet<String>(Arrays.asList("org", "or", "com", "co", "edu",
"ed", "ac", "net", "go", "asso", "xn--aroport-bya", "int",
"presse", "md", "gouv")));
topMap.put( "com", new HashSet<String>(Arrays.asList("ad", "ar", "br", "cn", "de", "eu", "gb",
"gr", "hu", "jpn", "kr", "no", "qc", "ru", "sa", "se", "uk", "us", "uy", "za")));
topMap.put( "cm", new HashSet<String>(Arrays.asList("co", "com", "gov", "net")));
topMap.put( "cn", new HashSet<String>(Arrays.asList("ac", "com", "edu", "gov", "net",
"org", "mil", "xn--55qx5d", "xn--io0a7i",
"ah", "bj", "cq", "fj", "gd", "gs", "gz", "gx",
"ha", "hb", "he", "hi", "hl", "hn", "jl", "js", "jx", "ln", "nm", "nx", "qh",
"sc", "sd", "sh", "sn", "sx", "tj", "xj", "xz", "yn", "zj", "hk", "mo", "tw")));
topMap.put( "co", new HashSet<String>(Arrays.asList("arts", "com", "edu", "firm", "gov", "info",
"int", "mil", "net", "nom", "org", "rec", "web")));
topMap.put( "cr", new HashSet<String>(Arrays.asList("ac", "co", "ed", "fi", "go", "or", "sa")));
topMap.put( "cu", new HashSet<String>(Arrays.asList("com", "edu", "org", "net", "gov", "inf")));
topMap.put( "do", new HashSet<String>(Arrays.asList("com", "edu", "org", "net", "gov", "gob",
"web", "art", "sld", "mil")));
topMap.put( "dz", new HashSet<String>(Arrays.asList("com", "org", "net", "gov", "edu", "asso",
"pol", "art")));
topMap.put( "ec", new HashSet<String>(Arrays.asList("com", "info", "net", "fin", "k12", "med",
"pro", "org", "edu", "gov", "gob", "mil")));
topMap.put( "ee", new HashSet<String>(Arrays.asList("edu", "gov", "riik", "lib", "med", "com",
"pri", "aip", "org", "fie")));
topMap.put( "eg", new HashSet<String>(Arrays.asList("com", "edu", "eun", "gov", "mil", "name",
"net", "org", "sci")));
topMap.put( "es", new HashSet<String>(Arrays.asList("com", "nom", "org", "gob", "edu")));
topMap.put( "eu", new HashSet<String>(Arrays.asList("europa")));
topMap.put( "fr", new HashSet<String>(Arrays.asList("com", "asso", "nom", "prd", "presse",
"tm", "aeroport", "assedic", "avocat", "avoues", "cci", "chambagri",
"chirurgiens-dentistes", "experts-comptables", "geometre-expert", "gouv", "greta",
"huissier-justice", "medecin", "notaires", "pharmacien", "port", "veterinaire")));
topMap.put( "ge", new HashSet<String>(Arrays.asList("com", "edu", "gov", "org", "mil", "net", "pvt")));
topMap.put( "gg", new HashSet<String>(Arrays.asList("co", "org", "net", "sch", "gov")));
topMap.put( "gh", new HashSet<String>(Arrays.asList("com", "edu", "gov", "org", "mil")));
topMap.put( "gi", new HashSet<String>(Arrays.asList("com", "ltd", "gov", "mod", "edu", "org")));
topMap.put( "gn", new HashSet<String>(Arrays.asList("ac", "com", "edu", "gov", "org", "net")));
topMap.put( "gp", new HashSet<String>(Arrays.asList("com", "net", "mobi", "edu", "org", "asso")));
topMap.put( "gr", new HashSet<String>(Arrays.asList("com", "co", "net", "edu", "org", "gov",
"mil", "mod", "sch")));
topMap.put( "gy", new HashSet<String>(Arrays.asList("co", "com", "net", "org", "edu", "gov")));
topMap.put( "hk", new HashSet<String>(Arrays.asList("com", "edu", "gov", "idv", "net", "org",
/* com */ "xn--55qx5d", /* edu */ "xn--wcvs22d", /* gov */"xn--mxtq1m",
/* idv */ "xn--gmqw5a", /* net */ "xn--od0alg", /*org*/ "xn--uc0atv")));
topMap.put( /* hk */ "xn--j6w193g", new HashSet<String>(Arrays.asList(
/* com */ "xn--55qx5d", /* edu */ "xn--wcvs22d", /* gov */"xn--mxtq1m",
/* idv */ "xn--gmqw5a", /* net */ "xn--od0alg", /*org*/ "xn--uc0atv")));
topMap.put( "hn", new HashSet<String>(Arrays.asList("com", "edu", "org", "net", "mil", "gob")));
topMap.put( "hr", new HashSet<String>(Arrays.asList("iz.hr", "from.hr", "name.hr", "com.hr")));
topMap.put( "ht", new HashSet<String>(Arrays.asList("com", "shop", "firm", "info", "adult",
"net", "pro", "org", "med", "art", "coop", "pol", "asso", "edu", "rel", "gouv", "perso")));
topMap.put( "hu", new HashSet<String>(Arrays.asList("co", "info", "org", "priv", "sport", "tm",
"2000", "agrar", "bolt", "casino", "city", "erotica", "erotika", "film", "forum",
"games", "hotel", "ingatlan", "jogasz", "konyvelo", "lakas", "media", "news", "reklam",
"sex", "shop", "suli", "szex", "tozsde", "utazas", "video")));
topMap.put( "id", new HashSet<String>(Arrays.asList("ac", "co", "go", "mil", "net", "or", "sch",
"web")));
topMap.put( "im", new HashSet<String>(Arrays.asList("co.im", "com", "net.im", "gov.im", "org.im",
"ac.im")));
topMap.put( "in", new HashSet<String>(Arrays.asList("co", "firm", "ernet", "net", "org", "gen", "ind",
"nic", "ac", "edu", "res", "gov", "mil")));
topMap.put( "iq", new HashSet<String>(Arrays.asList("gov", "edu", "mil", "com", "org", "net" )));
topMap.put( "ir", new HashSet<String>(Arrays.asList("ac", "co", "gov", "id", "net", "org", "sch"
)));
topMap.put( "is", new HashSet<String>(Arrays.asList("net", "com", "edu", "gov", "org", "int")));
topMap.put( "it", new HashSet<String>(Arrays.asList("gov", "edu", "agrigento", "ag", "alessandria",
"al", "ancona", "an", "aosta", "aoste", "ao", "arezzo", "ar", "ascoli-piceno",
"ascolipiceno", "ap", "asti", "at", "avellino", "av", "bari", "ba",
"andria-barletta-trani", "andriabarlettatrani", "trani-barletta-andria",
"tranibarlettaandria", "barletta-trani-andria", "barlettatraniandria",
"andria-trani-barletta", "andriatranibarletta", "trani-andria-barletta",
"traniandriabarletta", "bt", "belluno", "bl", "benevento", "bn", "bergamo", "bg",
"biella", "bi", "bologna", "bo", "bolzano", "bozen", "balsan", "alto-adige",
"altoadige", "suedtirol", "bz", "brescia", "bs", "brindisi", "br", "cagliari",
"ca", "caltanissetta", "cl", "campobasso", "cb", "carboniaiglesias", "carbonia-iglesias",
"iglesias-carbonia", "iglesiascarbonia", "ci", "caserta", "ce", "catania", "ct",
"catanzaro", "cz", "chieti", "ch", "como", "co", "cosenza", "cs", "cremona", "cr",
"crotone", "kr", "cuneo", "cn", "dell-ogliastra", "dellogliastra", "ogliastra", "og",
"enna", "en", "ferrara", "fe", "fermo", "fm", "firenze", "florence", "fi", "foggia",
"fg", "forli-cesena", "forlicesena", "cesena-forli", "cesenaforli", "fc", "frosinone",
"fr", "genova", "genoa", "ge", "gorizia", "go", "grosseto", "gr", "imperia", "im",
"isernia", "is", "laquila", "aquila", "aq", "la-spezia", "laspezia", "sp", "latina",
"lt", "lecce", "le", "lecco", "lc", "livorno", "li", "lodi", "lo", "lucca", "lu",
"macerata", "mc", "mantova", "mn", "massa-carrara", "massacarrara", "carrara-massa",
"carraramassa", "ms", "matera", "mt", "medio-campidano", "mediocampidano",
"campidano-medio", "campidanomedio", "vs", "messina", "me", "milano", "milan",
"mi", "modena", "mo", "monza", "monza-brianza", "monzabrianza", "monzaebrianza",
"monzaedellabrianza", "monza-e-della-brianza", "mb", "napoli", "naples", "na",
"novara", "no", "nuoro", "nu", "oristano", "or", "padova", "padua", "pd", "palermo",
"pa", "parma", "pr", "pavia", "pv", "perugia", "pg", "pescara", "pe", "pesaro-urbino",
"pesarourbino", "urbino-pesaro", "urbinopesaro", "pu", "piacenza", "pc", "pisa",
"pi", "pistoia", "pt", "pordenone", "pn", "potenza", "pz", "prato", "po", "ragusa",
"rg", "ravenna", "ra", "reggio-calabria", "reggiocalabria", "rc", "reggio-emilia",
"reggioemilia", "re", "rieti", "ri", "rimini", "rn", "roma", "rome", "rm", "rovigo",
"ro", "salerno", "sa", "sassari", "ss", "savona", "sv", "siena", "si", "siracusa",
"sr", "sondrio", "so", "taranto", "ta", "tempio-olbia", "tempioolbia", "olbia-tempio",
"olbiatempio", "ot", "teramo", "te", "terni", "tr", "torino", "turin", "to",
"trapani", "tp", "trento", "trentino", "tn", "treviso", "tv", "trieste", "ts",
"udine", "ud", "varese", "va", "venezia", "venice", "ve", "verbania", "vb",
"vercelli", "vc", "verona", "vr", "vibo-valentia", "vibovalentia", "vv", "vicenza",
"vi", "viterbo", "vt")));
topMap.put( "je", new HashSet<String>(Arrays.asList("co", "org", "net", "sch", "gov")));
topMap.put( "jo", new HashSet<String>(Arrays.asList("com", "org", "net", "edu", "sch",
"gov", "mil", "name")));
topMap.put( "jp", new HashSet<String>(Arrays.asList("ac", "ad", "co", "ed", "go", "gr", "lg",
"ne", "or")));
topMap.put( "kg", new HashSet<String>(Arrays.asList("org", "net", "com", "edu", "gov", "mil")));
topMap.put( "ki", new HashSet<String>(Arrays.asList("edu", "biz", "net", "org", "gov",
"info", "com")));
topMap.put( "km", new HashSet<String>(Arrays.asList("org", "nom", "gov", "prd", "tm", "edu",
"mil", "ass", "com", "coop", "asso", "presse", "medecin", "notaires", "pharmaciens",
"veterinaire", "gouv")));
topMap.put( "kn", new HashSet<String>(Arrays.asList("net", "org", "edu", "gov")));
topMap.put( "kp", new HashSet<String>(Arrays.asList("com", "edu", "gov", "org", "rep", "tra")));
topMap.put( "kr", new HashSet<String>(Arrays.asList("ac", "co", "es", "go", "hs", "kg", "mil",
"ms", "ne", "or", "pe", "re", "sc", "busan", "chungbuk", "chungnam", "daegu",
"daejeon", "gangwon", "gwangju", "gyeongbuk", "gyeonggi", "gyeongnam", "incheon",
"jeju", "jeonbuk", "jeonnam", "seoul", "ulsan")));
topMap.put( "kz", new HashSet<String>(Arrays.asList("org", "edu", "net", "gov", "mil", "com")));
topMap.put( "la", new HashSet<String>(Arrays.asList("int", "net", "info", "edu", "gov", "per",
"com", "org", "c")));
topMap.put( "lc", new HashSet<String>(Arrays.asList("com", "net", "co", "org", "edu", "gov",
"l.lc", "p.lc")));
topMap.put( "lk", new HashSet<String>(Arrays.asList("gov", "sch", "net", "int", "com", "org",
"edu", "ngo", "soc", "web", "ltd", "assn", "grp", "hotel")));
topMap.put( "ls", new HashSet<String>(Arrays.asList("co", "gov", "ac", "org")));
topMap.put( "lv", new HashSet<String>(Arrays.asList("com", "edu", "gov", "org", "mil",
"id", "net", "asn", "conf")));
topMap.put( "ly", new HashSet<String>(Arrays.asList("com", "net", "gov", "plc", "edu", "sch",
"med", "org", "id")));
topMap.put( "ma", new HashSet<String>(Arrays.asList("co", "net", "gov", "org", "ac", "press")));
topMap.put( "me", new HashSet<String>(Arrays.asList("co", "net", "org", "edu", "ac", "gov",
"its", "priv")));
topMap.put( "mg", new HashSet<String>(Arrays.asList("org", "nom", "gov", "prd", "tm",
"edu", "mil", "com")));
topMap.put( "mk", new HashSet<String>(Arrays.asList("com", "org", "net", "edu", "gov", "inf",
"name", "pro")));
topMap.put( "ml", new HashSet<String>(Arrays.asList("com", "edu", "gouv", "gov", "net",
"org", "presse")));
topMap.put( "mn", new HashSet<String>(Arrays.asList("gov", "edu", "org")));
topMap.put( "mp", new HashSet<String>(Arrays.asList("gov", "co", "org")));
topMap.put( "mu", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "ac",
"co", "or")));
topMap.put( "museum", new HashSet<String>(Arrays.asList("academy", "agriculture", "air",
"airguard", "alabama", "alaska", "amber", "ambulance", "american", "americana",
"americanantiques", "americanart", "amsterdam", "and", "annefrank", "anthro",
"anthropology", "antiques", "aquarium", "arboretum", "archaeological", "archaeology",
"architecture", "art", "artanddesign", "artcenter", "artdeco", "arteducation",
"artgallery", "arts", "artsandcrafts", "asmatart", "assassination", "assisi",
"association", "astronomy", "atlanta", "austin", "australia", "automotive", "aviation",
"axis", "badajoz", "baghdad", "bahn", "bale", "baltimore", "barcelona", "baseball",
"basel", "baths", "bauern", "beauxarts", "beeldengeluid", "bellevue", "bergbau",
"berkeley", "berlin", "bern", "bible", "bilbao", "bill", "birdart", "birthplace",
"bonn", "boston", "botanical", "botanicalgarden", "botanicgarden", "botany",
"brandywinevalley", "brasil", "bristol", "british", "britishcolumbia", "broadcast",
"brunel", "brussel", "brussels", "bruxelles", "building", "burghof", "bus", "bushey",
"cadaques", "california", "cambridge", "can", "canada", "capebreton", "carrier",
"cartoonart", "casadelamoneda", "castle", "castres", "celtic", "center", "chattanooga",
"cheltenham", "chesapeakebay", "chicago", "children", "childrens", "childrensgarden",
"chiropractic", "chocolate", "christiansburg", "cincinnati", "cinema", "circus",
"civilisation", "civilization", "civilwar", "clinton", "clock", "coal", "coastaldefence",
"cody", "coldwar", "collection", "colonialwilliamsburg", "coloradoplateau", "columbia",
"columbus", "communication", "communications", "community", "computer",
"computerhistory", "xn--comunicaes-v6a2o", "contemporary", "contemporaryart",
"convent", "copenhagen", "corporation", "xn--correios-e-telecomunicaes-ghc29a",
"corvette", "costume", "countryestate", "county", "crafts", "cranbrook", "creation",
"cultural", "culturalcenter", "culture", "cyber", "cymru", "dali", "dallas", "database",
"ddr", "decorativearts", "delaware", "delmenhorst", "denmark", "depot", "design",
"detroit", "dinosaur", "discovery", "dolls", "donostia", "durham", "eastafrica",
"eastcoast", "education", "educational", "egyptian", "eisenbahn", "elburg",
"elvendrell", "embroidery", "encyclopedic", "england", "entomology", "environment",
"environmentalconservation", "epilepsy", "essex", "estate", "ethnology", "exeter",
"exhibition", "family", "farm", "farmequipment", "farmers", "farmstead", "field",
"figueres", "filatelia", "film", "fineart", "finearts", "finland", "flanders", "florida",
"force", "fortmissoula", "fortworth", "foundation", "francaise", "frankfurt",
"franziskaner", "freemasonry", "freiburg", "fribourg", "frog", "fundacio", "furniture",
"gallery", "garden", "gateway", "geelvinck", "gemological", "geology", "georgia",
"giessen", "glas", "glass", "gorge", "grandrapids", "graz", "guernsey", "halloffame",
"hamburg", "handson", "harvestcelebration", "hawaii", "health", "heimatunduhren",
"hellas", "helsinki", "hembygdsforbund", "heritage", "histoire", "historical",
"historicalsociety", "historichouses", "historisch", "historisches", "history",
"historyofscience", "horology", "house", "humanities", "illustration", "imageandsound",
"indian", "indiana", "indianapolis", "indianmarket", "intelligence", "interactive",
"iraq", "iron", "isleofman", "jamison", "jefferson", "jerusalem", "jewelry",
"jewish", "jewishart", "jfk", "journalism", "judaica", "judygarland", "juedisches",
"juif", "karate", "karikatur", "kids", "koebenhavn", "koeln", "kunst", "kunstsammlung",
"kunstunddesign", "labor", "labour", "lajolla", "lancashire", "landes", "lans",
"xn--lns-qla", "larsson", "lewismiller", "lincoln", "linz", "living", "livinghistory",
"localhistory", "london", "losangeles", "louvre", "loyalist", "lucerne", "luxembourg",
"luzern", "mad", "madrid", "mallorca", "manchester", "mansion", "mansions", "manx",
"marburg", "maritime", "maritimo", "maryland", "marylhurst", "media", "medical",
"medizinhistorisches", "meeres", "memorial", "mesaverde", "michigan", "midatlantic",
"military", "mill", "miners", "mining", "minnesota", "missile", "missoula", "modern",
"moma", "money", "monmouth", "monticello", "montreal", "moscow", "motorcycle", "muenchen",
"muenster", "mulhouse", "muncie", "museet", "museumcenter", "museumvereniging", "music",
"national", "nationalfirearms", "nationalheritage", "nativeamerican", "naturalhistory",
"naturalhistorymuseum", "naturalsciences", "nature", "naturhistorisches",
"natuurwetenschappen", "naumburg", "naval", "nebraska", "neues", "newhampshire",
"newjersey", "newmexico", "newport", "newspaper", "newyork", "niepce", "norfolk",
"north", "nrw", "nuernberg", "nuremberg", "nyc", "nyny", "oceanographic",
"oceanographique", "omaha", "online", "ontario", "openair", "oregon", "oregontrail",
"otago", "oxford", "pacific", "paderborn", "palace", "paleo", "palmsprings", "panama",
"paris", "pasadena", "pharmacy", "philadelphia", "philadelphiaarea", "philately",
"phoenix", "photography", "pilots", "pittsburgh", "planetarium", "plantation",
"plants", "plaza", "portal", "portland", "portlligat", "posts-and-telecommunications",
"preservation", "presidio", "press", "project", "public", "pubol", "quebec",
"railroad", "railway", "research", "resistance", "riodejaneiro", "rochester", "rockart",
"roma", "russia", "saintlouis", "salem", "salvadordali", "salzburg", "sandiego",
"sanfrancisco", "santabarbara", "santacruz", "santafe", "saskatchewan", "satx",
"savannahga", "schlesisches", "schoenbrunn", "schokoladen", "school", "schweiz",
"science", "scienceandhistory", "scienceandindustry", "sciencecenter", "sciencecenters",
"science-fiction", "sciencehistory", "sciences", "sciencesnaturelles", "scotland",
"seaport", "settlement", "settlers", "shell", "sherbrooke", "sibenik", "silk", "ski",
"skole", "society", "sologne", "soundandvision", "southcarolina", "southwest", "space",
"spy", "square", "stadt", "stalbans", "starnberg", "state", "stateofdelaware",
"station", "steam", "steiermark", "stjohn", "stockholm", "stpetersburg", "stuttgart",
"suisse", "surgeonshall", "surrey", "svizzera", "sweden", "sydney", "tank", "tcm",
"technology", "telekommunikation", "television", "texas", "textile", "theater",
"time", "timekeeping", "topology", "torino", "touch", "town", "transport", "tree",
"trolley", "trust", "trustee", "uhren", "ulm", "undersea", "university", "usa",
"usantiques", "usarts", "uscountryestate", "usculture", "usdecorativearts", "usgarden",
"ushistory", "ushuaia", "uslivinghistory", "utah", "uvic", "valley", "vantaa",
"versailles", "viking", "village", "virginia", "virtual", "virtuel", "vlaanderen",
"volkenkunde", "wales", "wallonie", "war", "washingtondc", "watchandclock",
"watch-and-clock", "western", "westfalen", "whaling", "wildlife", "williamsburg",
"windmill", "workshop", "york", "yorkshire", "yosemite", "youth", "zoological",
"zoology", "xn--9dbhblg6di", "xn--h1aegh")));
topMap.put( "mv", new HashSet<String>(Arrays.asList("aero", "biz", "com", "coop", "edu", "gov",
"info", "int", "mil", "museum", "name", "net", "org", "pro")));
topMap.put( "mw", new HashSet<String>(Arrays.asList("ac", "biz", "co", "com", "coop", "edu",
"gov", "int", "museum", "net", "org")));
topMap.put( "mx", new HashSet<String>(Arrays.asList("com", "org", "gob", "edu", "net")));
topMap.put( "my", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "edu",
"mil", "name", "sch")));
topMap.put( "na", new HashSet<String>(Arrays.asList("co", "com", "org", "edu", "edunet", "net",
"alt", "biz", "info")));
topMap.put( "nc", new HashSet<String>(Arrays.asList("asso", "nom")));
topMap.put( "net", new HashSet<String>(Arrays.asList("gb", "se", "uk", "za")));
topMap.put( "ng", new HashSet<String>(Arrays.asList("name", "sch", "mil", "mobi", "com",
"edu", "gov", "net", "org")));
topMap.put( "nf", new HashSet<String>(Arrays.asList("com", "net", "per", "rec", "web",
"arts", "firm", "info", "other", "store")));
topMap.put( "no", new HashSet<String>(Arrays.asList("fhs", "vgs", "fylkesbibl", "folkebibl",
"museum", "idrett", "priv", "mil", "stat", "dep", "kommune", "herad", "aa",
"ah", "bu", "fm", "hl", "hm", "jan-mayen", "mr", "nl", "nt", "of", "ol", "oslo",
"rl", "sf", "st", "svalbard", "tm", "tr", "va", "vf", "akrehamn",
"xn--krehamn-dxa", "algard", "xn--lgrd-poac", "arna", "brumunddal",
"bryne", "bronnoysund", "xn--brnnysund-m8ac", "drobak",
"xn--drbak-wua", "egersund", "fetsund", "floro", "xn--flor-jra",
"fredrikstad", "hokksund", "honefoss", "xn--hnefoss-q1a",
"jessheim", "jorpeland", "xn--jrpeland-54a", "kirkenes", "kopervik",
"krokstadelva", "langevag", "xn--langevg-jxa", "leirvik", "mjondalen",
"xn--mjndalen-64a", "mo-i-rana", "mosjoen", "xn--mosjen-eya",
"nesoddtangen", "orkanger", "osoyro", "xn--osyro-wua",
"raholt", "xn--rholt-mra", "sandnessjoen", "xn--sandnessjen-ogb",
"skedsmokorset", "slattum", "spjelkavik", "stathelle", "stavern", "stjordalshalsen",
"xn--stjrdalshalsen-sqb", "tananger", "tranby", "vossevangen", "tranby",
"vossevangen", "afjord", "xn--fjord-lra", "agdenes", "al",
"xn--l-1fa", "alesund", "xn--lesund-hua",
"alstahaug", "alta", "xn--lt-liac", "alaheadju",
"xn--laheadju-7ya", "alvdal", "amli", "xn--mli-tla",
"amot", "xn--mot-tla", "andebu", "andoy", "xn--andy-ira",
"andasuolo", "ardal", "xn--rdal-poa", "aremark", "arendal",
"xn--s-1fa", "aseral", "xn--seral-lra",
"asker", "askim", "askvoll", "askoy", "xn--asky-ira",
"asnes", "xn--snes-poa", "audnedaln", "aukra", "aure", "aurland",
"aurskog-holand", "xn--aurskog-hland-jnb",
"austevoll", "austrheim", "averoy", "xn--avery-yua",
"balestrand", "ballangen", "balat", "xn--blt-elab",
"balsfjord", "bahccavuotna", "xn--bhccavuotna-k7a",
"bamble", "bardu", "beardu", "beiarn", "bajddar", "xn--bjddar-pta",
"baidar", "xn--bidr-5nac", "berg", "bergen", "berlevag", "xn--berlevg-jxa",
"bearalvahki", "xn--bearalvhki-y4a", "bindal", "birkenes", "bjarkoy",
"xn--bjarky-fya", "bjerkreim", "bjugn", "bodo", "xn--bod-2na",
"badaddja", "xn--bdddj-mrabd", "budejju", "bokn",
"bremanger", "bronnoy", "xn--brnny-wuac", "bygland",
"bykle", "barum", "xn--brum-voa", "bievat", "xn--bievt-0qa",
"bomlo", "xn--bmlo-gra", "batsfjord", "xn--btsfjord-9za", "bahcavuotna",
"xn--bhcavuotna-s4a", "dovre", "drammen", "drangedal", "dyroy",
"xn--dyry-ira", "donna", "xn--dnna-gra",
"eid", "eidfjord", "eidsberg", "eidskog", "eidsvoll", "eigersund", "elverum",
"enebakk", "engerdal", "etne", "etnedal", "evenes", "evenassi",
"xn--eveni-0qa01ga", "evje-og-hornnes", "farsund", "fauske",
"fuossko", "fuoisku", "fedje", "fet", "finnoy", "xn--finny-yua",
"fitjar", "fjaler", "fjell", "flakstad", "flatanger", "flekkefjord", "flesberg",
"flora", "fla", "xn--fl-zia", "folldal", "forsand", "fosnes", "frei",
"frogn", "froland", "frosta", "frana", "xn--frna-woa",
"froya", "xn--frya-hra", "fusa", "fyresdal", "forde",
"xn--frde-gra", "gamvik", "gangaviika", "xn--ggaviika-8ya47h",
"gaular", "gausdal", "gildeskal", "xn--gildeskl-g0a",
"giske", "gjemnes", "gjerdrum", "gjerstad", "gjesdal", "gjovik",
"xn--gjvik-wua", "gloppen", "gol", "gran", "grane", "granvin",
"gratangen", "grimstad", "grong", "kraanghke", "xn--kranghke-b0a",
"grue", "gulen", "hadsel", "halden", "halsa", "hamar", "hamaroy", "habmer",
"xn--hbmer-xqa", "hapmir", "xn--hpmir-xqa",
"hammerfest", "hammarfeasta", "xn--hmmrfeasta-s4ac",
"haram", "hareid", "harstad", "hasvik", "aknoluokta", "xn--koluokta-7ya57h",
"hattfjelldal", "aarborte", "haugesund", "hemne", "hemnes", "hemsedal",
"hitra", "hjartdal", "hjelmeland",
"hobol", "xn--hobl-ira", "hof", "hol", "hole", "holmestrand", "holtalen",
"xn--holtlen-hxa", "hornindal", "horten", "hurdal", "hurum", "hvaler",
"hyllestad", "hagebostad", "xn--hgebostad-g3a", "hoyanger",
"xn--hyanger-q1a", "hoylandet", "xn--hylandet-54a",
"ha", "xn--h-2fa", "ibestad", "inderoy", "xn--indery-fya",
"iveland", "jevnaker", "jondal", "jolster", "xn--jlster-bya",
"karasjok", "karasjohka", "xn--krjohka-hwab49j",
"karlsoy", "galsa", "xn--gls-elac", "karmoy",
"xn--karmy-yua", "kautokeino", "guovdageaidnu", "klepp", "klabu",
"xn--klbu-woa", "kongsberg", "kongsvinger", "kragero", "xn--krager-gya",
"kristiansand", "kristiansund", "krodsherad", "xn--krdsherad-m8a",
"kvalsund", "rahkkeravju", "xn--rhkkervju-01af",
"kvam", "kvinesdal", "kvinnherad", "kviteseid", "kvitsoy", "xn--kvitsy-fya",
"kvafjord", "xn--kvfjord-nxa", "giehtavuoatna", "kvanangen",
"xn--kvnangen-k0a", "navuotna", "xn--nvuotna-hwa",
"kafjord", "xn--kfjord-iua", "gaivuotna", "xn--givuotna-8ya",
"larvik", "lavangen", "lavagis", "loabat", "xn--loabt-0qa",
"lebesby", "davvesiida", "leikanger", "leirfjord", "leka", "leksvik", "lenvik",
"leangaviika", "xn--leagaviika-52b", "lesja", "levanger", "lier", "lierne",
"lillehammer", "lillesand", "lindesnes", "lindas", "xn--linds-pra",
"lom", "loppa", "lahppi", "xn--lhppi-xqa", "lund", "lunner", "luroy",
"xn--lury-ira", "luster", "lyngdal", "lyngen", "ivgu", "lardal", "lerdal",
"xn--lrdal-sra", "lodingen", "xn--ldingen-q1a", "lorenskog",
"xn--lrenskog-54a", "loten", "xn--lten-gra", "malvik",
"masoy", "xn--msy-ula0h", "muosat", "xn--muost-0qa",
"mandal", "marker", "marnardal", "masfjorden", "meland", "meldal", "melhus",
"meloy", "xn--mely-ira", "meraker", "xn--merker-kua", "moareke",
"xn--moreke-jua", "midsund", "midtre-gauldal", "modalen", "modum",
"molde", "moskenes", "moss", "mosvik", "malselv", "xn--mlselv-iua",
"malatvuopmi", "xn--mlatvuopmi-s4a", "namdalseid", "aejrie", "namsos",
"namsskogan", "naamesjevuemie", "xn--nmesjevuemie-tcba",
"laakesvuemie", "nannestad", "narvik", "narviika", "naustdal", "nedre-eiker",
"nesna", "nesodden", "nesseby", "unjarga", "xn--unjrga-rta", "nesset",
"nissedal", "nittedal", "nord-aurdal", "nord-fron", "nord-odal", "norddal",
"nordkapp", "davvenjarga", "xn--davvenjrga-y4a", "nordre-land",
"nordreisa", "raisa", "xn--risa-5na", "nore-og-uvdal", "notodden", "naroy",
"xn--nry-yla5g", "notteroy", "xn--nttery-byae",
"odda", "oksnes", "xn--ksnes-uua", "oppdal", "oppegard",
"xn--oppegrd-ixa", "orkdal", "orland", "xn--rland-uua",
"orskog", "xn--rskog-uua", "orsta", "xn--rsta-fra",
"os.hedmark", "os.hordaland", "osen", "osteroy", "xn--ostery-fya",
"ostre-toten", "xn--stre-toten-zcb", "overhalla", "ovre-eiker",
"xn--vre-eiker-k8a", "oyer", "xn--yer-zna",
"oygarden", "xn--ygarden-p1a", "oystre-slidre", "xn--ystre-slidre-ujb",
"porsanger", "porsangu", "xn--porsgu-sta26f", "porsgrunn",
"radoy", "xn--rady-ira", "rakkestad", "rana", "ruovat", "randaberg",
"rauma", "rendalen", "rennebu", "rennesoy", "xn--rennesy-v1a",
"rindal", "ringebu", "ringerike", "ringsaker", "rissa", "risor",
"xn--risr-ira", "roan", "rollag", "rygge", "ralingen", "xn--rlingen-mxa",
"rodoy", "xn--rdy-0nab", "romskog", "xn--rmskog-bya",
"roros", "xn--rros-gra", "rost", "xn--rst-0na",
"royken", "xn--ryken-vua", "royrvik", "xn--ryrvik-bya",
"rade", "xn--rde-ula", "salangen", "siellak", "saltdal", "salat",
"xn--slt-elab", "xn--slat-5na", "samnanger",
"sandefjord", "sandnes", "sandoy", "xn--sandy-yua", "sarpsborg",
"sauda", "sauherad", "sel", "selbu", "selje", "seljord", "sigdal", "siljan",
"sirdal", "skaun", "skedsmo", "ski", "skien", "skiptvet", "skjervoy",
"xn--skjervy-v1a", "skierva", "xn--skierv-uta",
"skjak", "xn--skjk-soa", "skodje", "skanland", "xn--sknland-fxa",
"skanit", "xn--sknit-yqa", "smola", "xn--smla-hra",
"snillfjord", "snasa", "xn--snsa-roa", "snoasa", "snaase",
"xn--snase-nra", "sogndal", "sokndal", "sola", "solund", "songdalen",
"sortland", "spydeberg", "stange", "stavanger", "steigen", "steinkjer",
"stjordal", "xn--stjrdal-s1a", "stokke", "stor-elvdal", "stord", "stordal",
"storfjord", "omasvuotna", "strand", "stranda", "stryn", "sula", "suldal",
"sund", "sunndal", "surnadal", "sveio", "svelvik", "sykkylven", "sogne",
"xn--sgne-gra", "somna", "xn--smna-gra", "sondre-land",
"xn--sndre-land-0cb", "sor-aurdal", "xn--sr-aurdal-l8a",
"sor-fron", "xn--sr-fron-q1a", "sor-odal", "xn--sr-odal-q1a",
"sor-varanger", "xn--sr-varanger-ggb", "matta-varjjat",
"xn--mtta-vrjjat-k7af", "sorfold", "xn--srfold-bya",
"sorreisa", "xn--srreisa-q1a", "sorum", "xn--srum-gra",
"tana", "deatnu", "time", "tingvoll", "tinn", "tjeldsund", "dielddanuorri",
"tjome", "xn--tjme-hra", "tokke", "tolga", "torsken", "tranoy",
"xn--trany-yua", "tromso", "xn--troms-zua", "tromsa", "romsa",
"trondheim", "troandin", "trysil", "trana", "xn--trna-woa",
"trogstad", "xn--trgstad-r1a", "tvedestrand", "tydal", "tynset",
"tysfjord", "divtasvuodna", "divttasvuotna", "tysnes", "tysvar",
"xn--tysvr-vra", "tonsberg", "xn--tnsberg-q1a",
"ullensaker", "ullensvang", "ulvik", "utsira", "vadso", "xn--vads-jra",
"cahcesuolo", "xn--hcesuolo-7ya35b", "vaksdal", "valle", "vang",
"vanylven", "vardo", "xn--vard-jra", "varggat", "xn--vrggt-xqad",
"vefsn", "vaapste", "vega", "vegarshei", "xn--vegrshei-c0a", "vennesla",
"verdal", "verran", "vestby", "vestnes", "vestre-slidre", "vestre-toten",
"vestvagoy", "xn--vestvgy-ixa6o", "vevelstad", "vik", "vikna",
"vindafjord", "volda", "voss", "varoy", "xn--vry-yla5g",
"vagan", "xn--vgan-qoa", "voagat", "vagsoy", "xn--vgsy-qoa0j",
"vaga", "xn--vg-yiab")));
topMap.put( "nr", new HashSet<String>(Arrays.asList("biz", "info", "gov", "edu", "org",
"net", "com", "co")));
topMap.put( "pa", new HashSet<String>(Arrays.asList("ac", "gob", "com", "org",
"sld", "edu", "net", "ing", "abo", "med", "nom")));
topMap.put( "pe", new HashSet<String>(Arrays.asList("edu", "gob", "nom", "mil", "org", "com",
"net", "sld")));
topMap.put( "pf", new HashSet<String>(Arrays.asList( "com")));
topMap.put( "ph", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "edu", "ngo", "mil")));
topMap.put( "pk", new HashSet<String>(Arrays.asList("com", "net", "edu", "org", "fam", "biz",
"web", "gov", "gob", "gok", "gon", "gop", "gos", "gog", "gkp", "info")));
topMap.put( "pl", new HashSet<String>(Arrays.asList("aid", "agro", "atm", "auto", "biz", "com",
"edu", "gmina", "gsm", "info", "mail", "miasta", "media", "mil", "net", "nieruchomosci",
"nom", "org", "pc", "powiat", "priv", "realestate", "rel", "sex", "shop", "sklep",
"sos", "szkola", "targi", "tm", "tourism", "travel", "turystyka", "art",
"gov", "ngo", "augustow", "babia-gora", "bedzin", "beskidy",
"bialowieza", "bialystok", "bielawa", "bieszczady", "boleslawiec", "bydgoszcz",
"bytom", "cieszyn", "czeladz", "czest", "dlugoleka", "elblag", "elk", "glogow",
"gniezno", "gorlice", "grajewo", "ilawa", "jaworzno", "jelenia-gora", "jgora",
"kalisz", "kazimierz-dolny", "karpacz", "kartuzy", "kaszuby", "katowice", "kepno",
"ketrzyn", "klodzko", "kobierzyce", "kolobrzeg", "konin", "konskowola", "kutno",
"lapy", "lebork", "legnica", "lezajsk", "limanowa", "lomza", "lowicz", "lubin",
"lukow", "malbork", "malopolska", "mazowsze", "mazury", "mielec", "mielno", "mragowo",
"naklo", "nowaruda", "nysa", "olawa", "olecko", "olkusz", "olsztyn", "opoczno",
"opole", "ostroda", "ostroleka", "ostrowiec", "ostrowwlkp", "pila", "pisz", "podhale",
"podlasie", "polkowice", "pomorze", "pomorskie", "prochowice", "pruszkow", "przeworsk",
"pulawy", "radom", "rawa-maz", "rybnik", "rzeszow", "sanok", "sejny", "siedlce",
"slask", "slupsk", "sosnowiec", "stalowa-wola", "skoczow", "starachowice", "stargard",
"suwalki", "swidnica", "swiebodzin", "swinoujscie", "szczecin", "szczytno", "tarnobrzeg",
"tgory", "turek", "tychy", "ustka", "walbrzych", "warmia", "warszawa", "waw",
"wegrow", "wielun", "wlocl", "wloclawek", "wodzislaw", "wolomin", "wroclaw",
"zachpomor", "zagan", "zarow", "zgora", "zgorzelec", "gda", "gdansk",
"krakow", "poznan", "wroc", "co",
"lodz", "lublin", "torun")));
topMap.put( "pn", new HashSet<String>(Arrays.asList("gov", "co", "org", "edu", "net")));
topMap.put( "pr", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "edu", "isla",
"pro", "biz", "info", "name", "est", "prof", "ac", "gobierno")));
topMap.put( "pro", new HashSet<String>(Arrays.asList("aca", "bar", "cpa", "jur", "law",
"med", "eng")));
topMap.put( "ps", new HashSet<String>(Arrays.asList("edu", "gov", "sec", "plo", "com", "org", "net")));
topMap.put( "pt", new HashSet<String>(Arrays.asList("net", "gov", "org", "edu", "int", "publ",
"com", "nome")));
topMap.put( "pw", new HashSet<String>(Arrays.asList("co", "ne", "or", "ed", "go", "belau")));
topMap.put( "qa", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "edu", "mil")));
topMap.put( "re", new HashSet<String>(Arrays.asList("com", "asso", "nom")));
topMap.put( "ro", new HashSet<String>(Arrays.asList("com", "org", "tm", "nt", "nom", "info",
"rec", "arts", "firm", "store", "www")));
topMap.put( "rs", new HashSet<String>(Arrays.asList("co", "org", "edu", "ac", "gov", "in")));
topMap.put( "ru", new HashSet<String>(Arrays.asList("ac", "com", "edu", "int", "net", "org",
"pp", "adygeya", "altai", "amur", "arkhangelsk", "astrakhan", "bashkiria",
"belgorod", "bir", "bryansk", "buryatia", "cap", "cbg", "chel", "chelyabinsk", "chita",
"chukotka", "dagestan", "e-burg", "grozny", "irkutsk",
"ivanovo", "izhevsk", "jar", "joshkar-ola", "kalmykia", "kaluga", "kamchatka",
"karelia", "kazan", "kchr", "kemerovo", "khabarovsk", "khakassia", "khv", "kirov",
"koenig", "komi", "kostroma", "krasnoyarsk", "kuban", "kurgan", "kursk", "lipetsk",
"magadan", "mari", "mari-el", "marine", "mordovia", "mosreg", "msk", "murmansk",
"nalchik", "nnov", "nov", "novosibirsk", "nsk", "omsk", "orenburg", "oryol",
"palana", "penza", "perm", "pskov", "ptz", "rnd", "ryazan", "sakhalin", "samara",
"saratov", "simbirsk", "smolensk", "spb", "stavropol", "stv", "surgut", "tambov",
"tatarstan", "tom", "tomsk", "tsaritsyn", "tsk", "tula", "tuva", "tver", "tyumen",
"udm", "udmurtia", "ulan-ude", "vladikavkaz", "vladimir", "vladivostok", "volgograd",
"vologda", "voronezh", "vrn", "vyatka", "yakutia", "yamal", "yaroslavl",
"yekaterinburg", "yuzhno-sakhalinsk", "amursk", "baikal", "cmw", "fareast",
"jamal", "kms", "k-uralsk", "kustanai", "kuzbass", "magnitka", "mytis",
"nakhodka", "nkz", "norilsk", "oskol", "pyatigorsk", "rubtsovsk", "snz", "syzran",
"vdonsk", "zgrad", "gov", "mil", "test")));
topMap.put( "rw", new HashSet<String>(Arrays.asList("gov", "net", "edu", "ac", "com", "co",
"int", "mil", "gouv")));
topMap.put( "sa", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "med", "pub",
"edu", "sch")));
topMap.put( "sd", new HashSet<String>(Arrays.asList("com", "net", "org", "edu", "med", "gov",
"info", "tv")));
topMap.put( "se", new HashSet<String>(Arrays.asList("a", "ac", "b", "bd", "brand", "c", "d",
"e", "f", "fh", "fhsk", "fhv", "g", "h", "i", "k", "komforb", "kommunalforbund",
"komvux", "l", "lanarb", "lanbib", "m", "n", "naturbruksgymn", "o", "org", "p", "parti",
"pp", "press", "r", "s", "sshn", "t", "tm", "u", "w", "x", "y", "z")));
topMap.put( "sg", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "edu", "per")));
topMap.put( "sh", new HashSet<String>(Arrays.asList("co", "com", "net", "org", "gov", "edu", "nom")));
topMap.put( "sk", new HashSet<String>(Arrays.asList("gov", "edu")));
topMap.put( "sn", new HashSet<String>(Arrays.asList("art", "com", "edu", "gouv", "org", "perso",
"univ")));
topMap.put( "so", new HashSet<String>(Arrays.asList("com", "net", "org")));
topMap.put( "sr", new HashSet<String>(Arrays.asList("co", "com", "consulado", "edu", "embaixada",
"gov", "mil", "net", "org", "principe", "saotome", "store")));
topMap.put( "sy", new HashSet<String>(Arrays.asList("edu", "gov", "net", "mil", "com", "org", "news")));
topMap.put( "sz", new HashSet<String>(Arrays.asList("co", "ac", "org")));
topMap.put( "th", new HashSet<String>(Arrays.asList("ac", "co", "go", "in", "mi", "net", "or")));
topMap.put( "tj", new HashSet<String>(Arrays.asList("ac", "biz", "co", "com", "edu", "go", "gov",
"int", "mil", "name", "net", "nic", "org", "test", "web")));
topMap.put( "tn", new HashSet<String>(Arrays.asList("com", "ens", "fin", "gov", "ind", "intl",
"nat", "net", "org", "info", "perso", "tourism", "edunet", "rnrt", "rns", "rnu",
"mincom", "agrinet", "defense", "turen")));
topMap.put( "to", new HashSet<String>(Arrays.asList("gov")));
topMap.put( "tt", new HashSet<String>(Arrays.asList("co", "com", "org", "net", "biz", "info",
"pro", "int", "coop", "jobs", "mobi", "travel", "museum", "aero", "name", "gov",
"edu", "cat", "tel", "mil")));
topMap.put( "tw", new HashSet<String>(Arrays.asList("edu", "gov", "mil", "com", "net", "org",
"idv", "game", "ebiz", "club", "xn--zf0ao64a", "xn--uc0atv", "xn--czrw28b")));
topMap.put( "ua", new HashSet<String>(Arrays.asList("com", "edu", "gov", "in", "net", "org",
"cherkassy", "chernigov", "chernovtsy", "ck", "cn", "crimea", "cv", "dn",
"dnepropetrovsk", "donetsk", "dp", "if", "ivano-frankivsk", "kh", "kharkov",
"kherson", "kiev", "kirovograd", "km", "kr", "ks", "lg",
"lugansk", "lutsk", "lviv", "mk", "nikolaev", "od", "odessa", "pl", "poltava",
"rovno", "rv", "sebastopol", "sumy", "te", "ternopil", "uzhgorod", "vinnica", "vn",
"zaporizhzhe", "zp", "zhitomir", "zt", "cr", "lt", "lv", "sb", "sm", "tr",
"co", "biz", "in", "ne", "pp", "uz", "dominic")));
topMap.put( "ug", new HashSet<String>(Arrays.asList("co", "ac", "sc", "go", "ne", "or", "org", "com")));
topMap.put( "us", new HashSet<String>(Arrays.asList("dni", "fed", "isa", "kids", "nsn", "kyschools")));
topMap.put( "uz", new HashSet<String>(Arrays.asList("co", "com", "org", "gov", "ac", "edu", "int", "pp", "net")));
topMap.put( "vc", new HashSet<String>(Arrays.asList("com", "net", "org", "gov")));
topMap.put( "vi", new HashSet<String>(Arrays.asList("co", "com", "k12", "net", "org")));
topMap.put( "vn", new HashSet<String>(Arrays.asList( "com", "net", "org", "edu", "gov", "int",
"ac", "biz", "info", "name", "pro", "health")));
topMap.put( "vu", new HashSet<String>(Arrays.asList("co", "com", "net", "org", "edu", "gov", "de")));
topMap.put("org", new HashSet<String>(Arrays.asList("ae", "za")));
topMap.put("pro", new HashSet<String>(Arrays.asList("aca", "bar", "cpa", "jur", "law", "med", "eng")));
top3Map.put("au", new HashSet<String>(Arrays.asList("act.edu.au", "eq.edu.au",
"nsw.edu.au", "nt.edu.au", "qld.edu.au", "sa.edu.au", "tas.edu.au", "vic.edu.au",
"wa.edu.au", "act.gov.au", "nsw.gov.au", "nt.gov.au", "qld.gov.au", "sa.gov.au",
"tas.gov.au", "vic.gov.au", "wa.gov.au")));
top3Map.put("im", new HashSet<String>(Arrays.asList("ltd.co.im", "plc.co.im")));
top3Map.put("no", new HashSet<String>(Arrays.asList("gs.aa.no", "gs.ah.no", "gs.bu.no",
"gs.fm.no", "gs.hl.no", "gs.hm.no", "gs.jan-mayen.no", "gs.mr.no", "gs.nl.no",
"gs.nt.no", "gs.of.no", "gs.ol.no", "gs.oslo.no", "gs.rl.no", "gs.sf.no",
"gs.st.no", "gs.svalbard.no", "gs.tm.no", "gs.tr.no", "gs.va.no", "gs.vf.no",
"bo.telemark.no", "xn--b-5ga.telemark.no", "bo.nordland.no",
"xn--b-5ga.nordland.no", "heroy.more-og-romsdal.no",
"xn--hery-ira.xn--mre-og-romsdal-qqb.no", "heroy.nordland.no",
"xn--hery-ira.nordland.no", "nes.akershus.no", "nes.buskerud.no",
"os.hedmark.no", "os.hordaland.no",
"sande.more-og-romsdal.no", "sande.xn--mre-og-romsdal-qqb.no",
"sande.vestfold.no", "valer.ostfold.no", "xn--vler-qoa.xn--stfold-9xa.no",
"valer.hedmark.no", "xn--vler-qoa.hedmark.no")));
top3Map.put("tr", new HashSet<String>(Arrays.asList("gov.nc.tr")));
}
/**
* Returns a {@code sun.security.util.RegisteredDomain} representing the
* registered part of the specified domain.
*
* @param domain the domain name
* @return a {@code sun.security.util.RegisteredDomain} or null
* if the domain is unknown or not registerable
* @throws NullPointerException if domain is null
*/
public static sun.security.util.RegisteredDomain registeredDomain(String domain) {
String name = getRegisteredDomain(domain);
if (name.equals(domain)) {
return null;
}
return new sun.security.util.RegisteredDomain() {
private String rname = name;
@Override
public String name() {
return rname;
}
@Override
public sun.security.util.RegisteredDomain.Type type() {
return sun.security.util.RegisteredDomain.Type.ICANN;
}
@Override
public String publicSuffix() {
return rname.substring(rname.indexOf(".") + 1);
}
};
}
/*
* Return the registered part of a qualified domain
* name or the original if no match is found.
*/
public static String getRegisteredDomain(String cname) {
int dot;
/*
* If one dot or less than just return.
*/
dot = cname.lastIndexOf('.');
if (dot == -1)
return cname;
if (dot == 0)
return "";
if (dot == cname.length() - 1) {
cname = cname.substring(0, cname.length() -1);
dot = cname.lastIndexOf('.');
if (dot == -1)
return cname;
if (dot == 0)
return "";
}
if (dot == cname.length() - 1)
return "";
/*
* Break it up into seperate labels.
*/
int second = cname.lastIndexOf('.', dot - 1);
if (second == -1)
return cname;
if (second == 0)
return "";
int third = cname.lastIndexOf('.', second - 1);
int fourth = -1;
if (third > 0) {
fourth = cname.lastIndexOf('.', third - 1);
}
int fifth = -1;
if (fourth > 0) {
fifth = cname.lastIndexOf('.', fourth - 1);
}
String s = cname.substring(dot + 1);
String s2 = cname.substring(second + 1, dot);
/*
* Look for longest matches first.
* XX.PVT.K12.MA.US etc.
*/
if (fourth != -1 && s.equals("us") && usStateSet.contains(s2)) {
String s3 = cname.substring(third + 1, second);
String s4 = cname.substring(fourth + 1, third);
if (s3.equals("k12")) {
if (s2.equals("ma") && (s4.equals("chtr") || s4.equals("paroch"))) {
return cname.substring(fifth + 1);
} else if (s4.equals("pvt")) {
return cname.substring(fifth + 1);
}
}
}
/*
* XX.K12.MA.US.
*/
String str = cname.substring(third + 1);
if (third != -1) {
Set<String> set = top3Map.get(s);
if (set != null) {
if (set.contains(str)) {
return cname.substring(fourth + 1);
}
} else if (s.equals("us") && usStateSet.contains(s2)) {
// check for known third level labels
String s3 = cname.substring(third + 1, second);
if (usSubStateSet.contains(s3)) {
return fourth != -1? cname.substring(fourth + 1): cname;
} else {
return cname.substring(third + 1);
}
} else if (s.equals("uk")) {
if (s2.equals("sch")) {
return cname.substring(fourth + 1);
}
} else if (s.equals("jp")) {
if (jpSet.contains(s2)) {
if (jp2Set.contains(str)) {
return cname.substring(third + 1);
}
return cname.substring(fourth + 1);
}
}
}
/*
* PREF.AKITA.JP etc.
*/
if (jp2Set.contains(str)) {
return cname.substring(third + 1);
}
/*
* XX.MA.US.
*/
Set<String> topSet = topMap.get(s);
if (topSet != null) {
if (topSet.contains(s2)) {
return cname.substring(third + 1);
}
if (!((s.equals("us") && usStateSet.contains(s2)) || (s.equals("jp") && jpSet.contains(s2)))) {
return cname.substring(second + 1);
}
} else if (top2Set.contains(s)) {
if (s2.equals("gov")) {
return cname.substring(third + 1);
}
return cname.substring(second + 1);
} else if (top3Set.contains(s)) {
if (s.equals("ad") && s2.equals("nom") ||
s.equals("aw") && s2.equals("com") ||
s.equals("be") && s2.equals("ac") ||
s.equals("cl") && s2.equals("gov") ||
s.equals("cl") && s2.equals("gob") ||
s.equals("fi") && s2.equals("aland") ||
s.equals("int") && s2.equals("eu") ||
s.equals("io") && s2.equals("com") ||
s.equals("mc") && s2.equals("tm") ||
s.equals("mc") && s2.equals("asso") ||
s.equals("vc") && s2.equals("com")) {
return cname.substring(third + 1);
}
return cname.substring(second + 1);
} else if (top4Set.contains(s)) {
if (s2.equals("com") || s2.equals("edu") || s2.equals("gov") ||
s2.equals("net") || s2.equals("org")) {
return cname.substring(third + 1);
}
return cname.substring(second + 1);
} else if (top5Set.contains(s)) {
return cname.substring(third + 1);
}
/*
* BB.AA exception cases.
*/
if (s.equals("tr")) {
if (!s2.equals("nic") && !s2.equals("tsk")) {
return cname.substring(third + 1);
}
return cname.substring(second + 1);
} else if (s.equals("uk")) {
if (!ukSet.contains(s2)) {
return cname.substring(third + 1);
}
return cname.substring(second + 1);
} else if (s.equals("ar")) {
if (!arSet.contains(s2)) {
return cname.substring(third + 1);
}
return cname.substring(second + 1);
} else if (s.equals("om")) {
if (!omSet.contains(s2)) {
return cname.substring(third + 1);
}
return cname.substring(second + 1);
}
/*
* XX.AA
*/
if (top1Set.contains(s)) {
return cname.substring(second + 1);
}
/*
* Nothing matched so we can't shorten the string.
*/
return cname;
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.net.SocketException;
import java.util.concurrent.atomic.AtomicInteger;
import sun.security.action.GetPropertyAction;
/**
* Manages count of total number of UDP sockets and ensures
* that exception is thrown if we try to create more than the
* configured limit.
*
* This functionality could be put in NetHooks some time in future.
*/
public class ResourceManager {
/* default maximum number of udp sockets per VM
* when a security manager is enabled.
* The default is 25 which is high enough to be useful
* but low enough to be well below the maximum number
* of port numbers actually available on all OSes
* when multiplied by the maximum feasible number of VM processes
* that could practically be spawned.
*/
private static final int DEFAULT_MAX_SOCKETS = 25;
private static final int maxSockets;
private static final AtomicInteger numSockets;
static {
String prop = java.security.AccessController.doPrivileged(
new GetPropertyAction("sun.net.maxDatagramSockets")
);
int defmax = DEFAULT_MAX_SOCKETS;
try {
if (prop != null) {
defmax = Integer.parseInt(prop);
}
} catch (NumberFormatException e) {}
maxSockets = defmax;
numSockets = new AtomicInteger(0);
}
public static void beforeUdpCreate() throws SocketException {
if (System.getSecurityManager() != null) {
if (numSockets.incrementAndGet() > maxSockets) {
numSockets.decrementAndGet();
throw new SocketException("maximum number of DatagramSockets reached");
}
}
}
public static void afterUdpClose() {
if (System.getSecurityManager() != null) {
numSockets.decrementAndGet();
}
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.net.Proxy;
import java.net.SocketAddress;
/**
* Proxy wrapper class so we can determine the socks protocol version.
*/
public final class SocksProxy extends Proxy {
private final int version;
private SocksProxy(SocketAddress addr, int version) {
super(Proxy.Type.SOCKS, addr);
this.version = version;
}
public static SocksProxy create(SocketAddress addr, int version) {
return new SocksProxy(addr, version);
}
public int protocolVersion() {
return version;
}
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright (c) 1994, 1995, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.io.*;
/**
* This class provides input and output streams for telnet clients.
* This class overrides read to do CRLF processing as specified in
* RFC 854. The class assumes it is running on a system where lines
* are terminated with a single newline <LF> character.
*
* This is the relevant section of RFC 824 regarding CRLF processing:
*
* <pre>
* The sequence "CR LF", as defined, will cause the NVT to be
* positioned at the left margin of the next print line (as would,
* for example, the sequence "LF CR"). However, many systems and
* terminals do not treat CR and LF independently, and will have to
* go to some effort to simulate their effect. (For example, some
* terminals do not have a CR independent of the LF, but on such
* terminals it may be possible to simulate a CR by backspacing.)
* Therefore, the sequence "CR LF" must be treated as a single "new
* line" character and used whenever their combined action is
* intended; the sequence "CR NUL" must be used where a carriage
* return alone is actually desired; and the CR character must be
* avoided in other contexts. This rule gives assurance to systems
* which must decide whether to perform a "new line" function or a
* multiple-backspace that the TELNET stream contains a character
* following a CR that will allow a rational decision.
*
* Note that "CR LF" or "CR NUL" is required in both directions
* (in the default ASCII mode), to preserve the symmetry of the
* NVT model. Even though it may be known in some situations
* (e.g., with remote echo and suppress go ahead options in
* effect) that characters are not being sent to an actual
* printer, nonetheless, for the sake of consistency, the protocol
* requires that a NUL be inserted following a CR not followed by
* a LF in the data stream. The converse of this is that a NUL
* received in the data stream after a CR (in the absence of
* options negotiations which explicitly specify otherwise) should
* be stripped out prior to applying the NVT to local character
* set mapping.
* </pre>
*
* @author Jonathan Payne
*/
public class TelnetInputStream extends FilterInputStream {
/** If stickyCRLF is true, then we're a machine, like an IBM PC,
where a Newline is a CR followed by LF. On UNIX, this is false
because Newline is represented with just a LF character. */
boolean stickyCRLF = false;
boolean seenCR = false;
public boolean binaryMode = false;
public TelnetInputStream(InputStream fd, boolean binary) {
super(fd);
binaryMode = binary;
}
public void setStickyCRLF(boolean on) {
stickyCRLF = on;
}
public int read() throws IOException {
if (binaryMode)
return super.read();
int c;
/* If last time we determined we saw a CRLF pair, and we're
not turning that into just a Newline (that is, we're
stickyCRLF), then return the LF part of that sticky
pair now. */
if (seenCR) {
seenCR = false;
return '\n';
}
if ((c = super.read()) == '\r') { /* CR */
switch (c = super.read()) {
default:
case -1: /* this is an error */
throw new TelnetProtocolException("misplaced CR in input");
case 0: /* NUL - treat CR as CR */
return '\r';
case '\n': /* CRLF - treat as NL */
if (stickyCRLF) {
seenCR = true;
return '\r';
} else {
return '\n';
}
}
}
return c;
}
/** read into a byte array */
public int read(byte bytes[]) throws IOException {
return read(bytes, 0, bytes.length);
}
/**
* Read into a byte array at offset <i>off</i> for length <i>length</i>
* bytes.
*/
public int read(byte bytes[], int off, int length) throws IOException {
if (binaryMode)
return super.read(bytes, off, length);
int c;
int offStart = off;
while (--length >= 0) {
c = read();
if (c == -1)
break;
bytes[off++] = (byte)c;
}
return (off > offStart) ? off - offStart : -1;
}
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.io.*;
/**
* This class provides input and output streams for telnet clients.
* This class overrides write to do CRLF processing as specified in
* RFC 854. The class assumes it is running on a system where lines
* are terminated with a single newline <LF> character.
*
* This is the relevant section of RFC 824 regarding CRLF processing:
*
* <pre>
* The sequence "CR LF", as defined, will cause the NVT to be
* positioned at the left margin of the next print line (as would,
* for example, the sequence "LF CR"). However, many systems and
* terminals do not treat CR and LF independently, and will have to
* go to some effort to simulate their effect. (For example, some
* terminals do not have a CR independent of the LF, but on such
* terminals it may be possible to simulate a CR by backspacing.)
* Therefore, the sequence "CR LF" must be treated as a single "new
* line" character and used whenever their combined action is
* intended; the sequence "CR NUL" must be used where a carriage
* return alone is actually desired; and the CR character must be
* avoided in other contexts. This rule gives assurance to systems
* which must decide whether to perform a "new line" function or a
* multiple-backspace that the TELNET stream contains a character
* following a CR that will allow a rational decision.
*
* Note that "CR LF" or "CR NUL" is required in both directions
* (in the default ASCII mode), to preserve the symmetry of the
* NVT model. Even though it may be known in some situations
* (e.g., with remote echo and suppress go ahead options in
* effect) that characters are not being sent to an actual
* printer, nonetheless, for the sake of consistency, the protocol
* requires that a NUL be inserted following a CR not followed by
* a LF in the data stream. The converse of this is that a NUL
* received in the data stream after a CR (in the absence of
* options negotiations which explicitly specify otherwise) should
* be stripped out prior to applying the NVT to local character
* set mapping.
* </pre>
*
* @author Jonathan Payne
*/
public class TelnetOutputStream extends BufferedOutputStream {
boolean stickyCRLF = false;
boolean seenCR = false;
public boolean binaryMode = false;
public TelnetOutputStream(OutputStream fd, boolean binary) {
super(fd);
binaryMode = binary;
}
/**
* set the stickyCRLF flag. Tells whether the terminal considers CRLF as a single
* char.
*
* @param on the <code>boolean</code> to set the flag to.
*/
public void setStickyCRLF(boolean on) {
stickyCRLF = on;
}
/**
* Writes the int to the stream and does CR LF processing if necessary.
*/
public void write(int c) throws IOException {
if (binaryMode) {
super.write(c);
return;
}
if (seenCR) {
if (c != '\n')
super.write(0);
super.write(c);
if (c != '\r')
seenCR = false;
} else { // !seenCR
if (c == '\n') {
super.write('\r');
super.write('\n');
return;
}
if (c == '\r') {
if (stickyCRLF)
seenCR = true;
else {
super.write('\r');
c = 0;
}
}
super.write(c);
}
}
/**
* Write the bytes at offset <i>off</i> in buffer <i>bytes</i> for
* <i>length</i> bytes.
*/
public void write(byte bytes[], int off, int length) throws IOException {
if (binaryMode) {
super.write(bytes, off, length);
return;
}
while (--length >= 0) {
write(bytes[off++]);
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.io.*;
/**
* An unexpected result was received by the client when talking to the
* telnet server.
*
* @author Jonathan Payne
*/
public class TelnetProtocolException extends IOException {
private static final long serialVersionUID = 8509127047257111343L;
public TelnetProtocolException(String s) {
super(s);
}
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
import java.io.*;
import java.util.Vector;
/**
* This class implements that basic intefaces of transfer protocols.
* It is used by subclasses implementing specific protocols.
*
* @author Jonathan Payne
* @see sun.net.ftp.FtpClient
* @see sun.net.nntp.NntpClient
*/
public class TransferProtocolClient extends NetworkClient {
static final boolean debug = false;
/** Array of strings (usually 1 entry) for the last reply
from the server. */
protected Vector<String> serverResponse = new Vector<>(1);
/** code for last reply */
protected int lastReplyCode;
/**
* Pulls the response from the server and returns the code as a
* number. Returns -1 on failure.
*/
public int readServerResponse() throws IOException {
StringBuffer replyBuf = new StringBuffer(32);
int c;
int continuingCode = -1;
int code;
String response;
serverResponse.setSize(0);
while (true) {
while ((c = serverInput.read()) != -1) {
if (c == '\r') {
if ((c = serverInput.read()) != '\n')
replyBuf.append('\r');
}
replyBuf.append((char)c);
if (c == '\n')
break;
}
response = replyBuf.toString();
replyBuf.setLength(0);
if (debug) {
System.out.print(response);
}
if (response.length() == 0) {
code = -1;
} else {
try {
code = Integer.parseInt(response.substring(0, 3));
} catch (NumberFormatException e) {
code = -1;
} catch (StringIndexOutOfBoundsException e) {
/* this line doesn't contain a response code, so
we just completely ignore it */
continue;
}
}
serverResponse.addElement(response);
if (continuingCode != -1) {
/* we've seen a XXX- sequence */
if (code != continuingCode ||
(response.length() >= 4 && response.charAt(3) == '-')) {
continue;
} else {
/* seen the end of code sequence */
continuingCode = -1;
break;
}
} else if (response.length() >= 4 && response.charAt(3) == '-') {
continuingCode = code;
continue;
} else {
break;
}
}
return lastReplyCode = code;
}
/** Sends command <i>cmd</i> to the server. */
public void sendServer(String cmd) {
serverOutput.print(cmd);
if (debug) {
System.out.print("Sending: " + cmd);
}
}
/** converts the server response into a string. */
public String getResponseString() {
return serverResponse.elementAt(0);
}
/** Returns all server response strings. */
public Vector<String> getResponseStrings() {
return serverResponse;
}
/** standard constructor to host <i>host</i>, port <i>port</i>. */
public TransferProtocolClient(String host, int port) throws IOException {
super(host, port);
}
/** creates an uninitialized instance of this class. */
public TransferProtocolClient() {}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net;
/**
* Helper class to map URL "abbreviations" to real URLs.
* The default implementation supports the following mappings:
* ftp.mumble.bar/... => ftp://ftp.mumble.bar/...
* gopher.mumble.bar/... => gopher://gopher.mumble.bar/...
* other.name.dom/... => http://other.name.dom/...
* /foo/... => file:/foo/...
*
* Full URLs (those including a protocol name) are passed through unchanged.
*
* Subclassers can override or extend this behavior to support different
* or additional canonicalization policies.
*
* @author Steve Byrne
*/
public class URLCanonicalizer {
/**
* Creates the default canonicalizer instance.
*/
public URLCanonicalizer() { }
/**
* Given a possibly abbreviated URL (missing a protocol name, typically),
* this method's job is to transform that URL into a canonical form,
* by including a protocol name and additional syntax, if necessary.
*
* For a correctly formed URL, this method should just return its argument.
*/
public String canonicalize(String simpleURL) {
String resultURL = simpleURL;
if (simpleURL.startsWith("ftp.")) {
resultURL = "ftp://" + simpleURL;
} else if (simpleURL.startsWith("gopher.")) {
resultURL = "gopher://" + simpleURL;
} else if (simpleURL.startsWith("/")) {
resultURL = "file:" + simpleURL;
} else if (!hasProtocolName(simpleURL)) {
if (isSimpleHostName(simpleURL)) {
simpleURL = "www." + simpleURL + ".com";
}
resultURL = "http://" + simpleURL;
}
return resultURL;
}
/**
* Given a possibly abbreviated URL, this predicate function returns
* true if it appears that the URL contains a protocol name
*/
public boolean hasProtocolName(String url) {
int index = url.indexOf(':');
if (index <= 0) { // treat ":foo" as not having a protocol spec
return false;
}
for (int i = 0; i < index; i++) {
char c = url.charAt(i);
// REMIND: this is a guess at legal characters in a protocol --
// need to be verified
if ((c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c == '-')) {
continue;
}
// found an illegal character
return false;
}
return true;
}
/**
* Returns true if the URL is just a single name, no periods or
* slashes, false otherwise
**/
protected boolean isSimpleHostName(String url) {
for (int i = 0; i < url.length(); i++) {
char c = url.charAt(i);
// REMIND: this is a guess at legal characters in a protocol --
// need to be verified
if ((c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9')
|| (c == '-')) {
continue;
}
// found an illegal character
return false;
}
return true;
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.dns;
import java.util.List;
/**
* The configuration of the client resolver.
*
* <p>A ResolverConfiguration is a singleton that represents the
* configuration of the client resolver. The ResolverConfiguration
* is opened by invoking the {@link #open() open} method.
*
* @since 1.4
*/
public abstract class ResolverConfiguration {
private static final Object lock = new Object();
private static ResolverConfiguration provider;
protected ResolverConfiguration() { }
/**
* Opens the resolver configuration.
*
* @return the resolver configuration
*/
public static ResolverConfiguration open() {
synchronized (lock) {
if (provider == null) {
provider = new sun.net.dns.ResolverConfigurationImpl();
}
return provider;
}
}
/**
* Returns a list corresponding to the domain search path. The
* list is ordered by the search order used for host name lookup.
* Each element in the list returns a {@link java.lang.String}
* containing a domain name or suffix.
*
* @return list of domain names
*/
public abstract List<String> searchlist();
/**
* Returns a list of name servers used for host name lookup.
* Each element in the list returns a {@link java.lang.String}
* containing the textual representation of the IP address of
* the name server.
*
* @return list of the name servers
*/
public abstract List<String> nameservers();
/**
* Options representing certain resolver variables of
* a {@link ResolverConfiguration}.
*/
public static abstract class Options {
/**
* Returns the maximum number of attempts the resolver
* will connect to each name server before giving up
* and returning an error.
*
* @return the resolver attempts value or -1 is unknown
*/
public int attempts() {
return -1;
}
/**
* Returns the basic retransmit timeout, in milliseconds,
* used by the resolver. The resolver will typically use
* an exponential backoff algorithm where the timeout is
* doubled for every retransmit attempt. The basic
* retransmit timeout, returned here, is the initial
* timeout for the exponential backoff algorithm.
*
* @return the basic retransmit timeout value or -1
* if unknown
*/
public int retrans() {
return -1;
}
}
/**
* Returns the {@link #Options} for the resolver.
*
* @return options for the resolver
*/
public abstract Options options();
}

View File

@@ -0,0 +1,183 @@
/*
* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.dns;
import java.util.List;
import java.util.LinkedList;
import java.util.StringTokenizer;
/*
* An implementation of sun.net.ResolverConfiguration for Windows.
*/
public class ResolverConfigurationImpl
extends ResolverConfiguration
{
// Lock helds whilst loading configuration or checking
private static Object lock = new Object();
// Resolver options
private final Options opts;
// Addreses have changed
private static boolean changed = false;
// Time of last refresh.
private static long lastRefresh = -1;
// Cache timeout (120 seconds) - should be converted into property
// or configured as preference in the future.
private static final int TIMEOUT = 120000;
// DNS suffix list and name servers populated by native method
private static String os_searchlist;
private static String os_nameservers;
// Cached lists
private static LinkedList<String> searchlist;
private static LinkedList<String> nameservers;
// Parse string that consists of token delimited by space or commas
// and return LinkedHashMap
private LinkedList<String> stringToList(String str) {
LinkedList<String> ll = new LinkedList<>();
// comma and space are valid delimites
StringTokenizer st = new StringTokenizer(str, ", ");
while (st.hasMoreTokens()) {
String s = st.nextToken();
if (!ll.contains(s)) {
ll.add(s);
}
}
return ll;
}
// Load DNS configuration from OS
private void loadConfig() {
assert Thread.holdsLock(lock);
// if address have changed then DNS probably changed aswell;
// otherwise check if cached settings have expired.
//
if (changed) {
changed = false;
} else {
if (lastRefresh >= 0) {
long currTime = System.currentTimeMillis();
if ((currTime - lastRefresh) < TIMEOUT) {
return;
}
}
}
// load DNS configuration, update timestamp, create
// new HashMaps from the loaded configuration
//
loadDNSconfig0();
lastRefresh = System.currentTimeMillis();
searchlist = stringToList(os_searchlist);
nameservers = stringToList(os_nameservers);
os_searchlist = null; // can be GC'ed
os_nameservers = null;
}
ResolverConfigurationImpl() {
opts = new OptionsImpl();
}
@SuppressWarnings("unchecked") // clone()
public List<String> searchlist() {
synchronized (lock) {
loadConfig();
// List is mutable so return a shallow copy
return (List<String>)searchlist.clone();
}
}
@SuppressWarnings("unchecked") // clone()
public List<String> nameservers() {
synchronized (lock) {
loadConfig();
// List is mutable so return a shallow copy
return (List<String>)nameservers.clone();
}
}
public Options options() {
return opts;
}
// --- Address Change Listener
static class AddressChangeListener extends Thread {
public void run() {
for (;;) {
// wait for configuration to change
if (notifyAddrChange0() != 0)
return;
synchronized (lock) {
changed = true;
}
}
}
}
// --- Native methods --
static native void init0();
static native void loadDNSconfig0();
static native int notifyAddrChange0();
static {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("net");
return null;
}
});
init0();
// start the address listener thread
AddressChangeListener thr = new AddressChangeListener();
thr.setDaemon(true);
thr.start();
}
}
/**
* Implementation of {@link ResolverConfiguration.Options}
*/
class OptionsImpl extends ResolverConfiguration.Options {
}

View File

@@ -0,0 +1,943 @@
/*
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.ftp;
import java.net.*;
import java.io.*;
import java.util.Date;
import java.util.List;
import java.util.Iterator;
/**
* A class that implements the FTP protocol according to
* RFCs <A href="http://www.ietf.org/rfc/rfc0959.txt">959</A>,
* <A href="http://www.ietf.org/rfc/rfc2228.txt">2228</A>,
* <A href="http://www.ietf.org/rfc/rfc2389.txt">2389</A>,
* <A href="http://www.ietf.org/rfc/rfc2428.txt">2428</A>,
* <A href="http://www.ietf.org/rfc/rfc3659.txt">3659</A>,
* <A href="http://www.ietf.org/rfc/rfc4217.txt">4217</A>.
* Which includes support for FTP over SSL/TLS (aka ftps).
*
* {@code FtpClient} provides all the functionalities of a typical FTP
* client, like storing or retrieving files, listing or creating directories.
* A typical usage would consist of connecting the client to the server,
* log in, issue a few commands then logout.
* Here is a code example:
* <pre>
* FtpClient cl = FtpClient.create();
* cl.connect("ftp.gnu.org").login("anonymous", "john.doe@mydomain.com".toCharArray())).changeDirectory("pub/gnu");
* Iterator&lt;FtpDirEntry&gt; dir = cl.listFiles();
* while (dir.hasNext()) {
* FtpDirEntry f = dir.next();
* System.err.println(f.getName());
* }
* cl.close();
* }
* </pre>
* <p><b>Error reporting:</b> There are, mostly, two families of errors that
* can occur during an FTP session. The first kind are the network related issues
* like a connection reset, and they are usually fatal to the session, meaning,
* in all likelyhood the connection to the server has been lost and the session
* should be restarted from scratch. These errors are reported by throwing an
* {@link IOException}. The second kind are the errors reported by the FTP server,
* like when trying to download a non-existing file for example. These errors
* are usually non fatal to the session, meaning more commands can be sent to the
* server. In these cases, a {@link FtpProtocolException} is thrown.</p>
* <p>
* It should be noted that this is not a thread-safe API, as it wouldn't make
* too much sense, due to the very sequential nature of FTP, to provide a
* client able to be manipulated from multiple threads.
*
* @since 1.7
*/
public abstract class FtpClient implements java.io.Closeable {
private static final int FTP_PORT = 21;
public static enum TransferType {
ASCII, BINARY, EBCDIC
};
/**
* Returns the default FTP port number.
*
* @return the port number.
*/
public static final int defaultPort() {
return FTP_PORT;
}
/**
* Creates an instance of FtpClient. The client is not connected to any
* server yet.
*
*/
protected FtpClient() {
}
/**
* Creates an instance of {@code FtpClient}. The client is not connected to any
* server yet.
*
* @return the created {@code FtpClient}
*/
public static FtpClient create() {
FtpClientProvider provider = FtpClientProvider.provider();
return provider.createFtpClient();
}
/**
* Creates an instance of FtpClient and connects it to the specified
* address.
*
* @param dest the {@code InetSocketAddress} to connect to.
* @return The created {@code FtpClient}
* @throws IOException if the connection fails
* @see #connect(java.net.SocketAddress)
*/
public static FtpClient create(InetSocketAddress dest) throws FtpProtocolException, IOException {
FtpClient client = create();
if (dest != null) {
client.connect(dest);
}
return client;
}
/**
* Creates an instance of {@code FtpClient} and connects it to the
* specified host on the default FTP port.
*
* @param dest the {@code String} containing the name of the host
* to connect to.
* @return The created {@code FtpClient}
* @throws IOException if the connection fails.
* @throws FtpProtocolException if the server rejected the connection
*/
public static FtpClient create(String dest) throws FtpProtocolException, IOException {
return create(new InetSocketAddress(dest, FTP_PORT));
}
/**
* Enables, or disables, the use of the <I>passive</I> mode. In that mode,
* data connections are established by having the client connect to the server.
* This is the recommended default mode as it will work best through
* firewalls and NATs. If set to {@code false} the mode is said to be
* <I>active</I> which means the server will connect back to the client
* after a PORT command to establish a data connection.
*
* <p><b>Note:</b> Since the passive mode might not be supported by all
* FTP servers, enabling it means the client will try to use it. If the
* server rejects it, then the client will attempt to fall back to using
* the <I>active</I> mode by issuing a {@code PORT} command instead.</p>
*
* @param passive {@code true} to force passive mode.
* @return This FtpClient
* @see #isPassiveModeEnabled()
*/
public abstract FtpClient enablePassiveMode(boolean passive);
/**
* Tests whether passive mode is enabled.
*
* @return {@code true} if the passive mode has been enabled.
* @see #enablePassiveMode(boolean)
*/
public abstract boolean isPassiveModeEnabled();
/**
* Sets the default timeout value to use when connecting to the server,
*
* @param timeout the timeout value, in milliseconds, to use for the connect
* operation. A value of zero or less, means use the default timeout.
*
* @return This FtpClient
*/
public abstract FtpClient setConnectTimeout(int timeout);
/**
* Returns the current default connection timeout value.
*
* @return the value, in milliseconds, of the current connect timeout.
* @see #setConnectTimeout(int)
*/
public abstract int getConnectTimeout();
/**
* Sets the timeout value to use when reading from the server,
*
* @param timeout the timeout value, in milliseconds, to use for the read
* operation. A value of zero or less, means use the default timeout.
* @return This FtpClient
*/
public abstract FtpClient setReadTimeout(int timeout);
/**
* Returns the current read timeout value.
*
* @return the value, in milliseconds, of the current read timeout.
* @see #setReadTimeout(int)
*/
public abstract int getReadTimeout();
/**
* Set the {@code Proxy} to be used for the next connection.
* If the client is already connected, it doesn't affect the current
* connection. However it is not recommended to change this during a session.
*
* @param p the {@code Proxy} to use, or {@code null} for no proxy.
* @return This FtpClient
*/
public abstract FtpClient setProxy(Proxy p);
/**
* Get the proxy of this FtpClient
*
* @return the {@code Proxy}, this client is using, or {@code null}
* if none is used.
* @see #setProxy(Proxy)
*/
public abstract Proxy getProxy();
/**
* Tests whether this client is connected or not to a server.
*
* @return {@code true} if the client is connected.
*/
public abstract boolean isConnected();
/**
* Connects the {@code FtpClient} to the specified destination server.
*
* @param dest the address of the destination server
* @return this FtpClient
* @throws IOException if connection failed.
* @throws SecurityException if there is a SecurityManager installed and it
* denied the authorization to connect to the destination.
* @throws FtpProtocolException
*/
public abstract FtpClient connect(SocketAddress dest) throws FtpProtocolException, IOException;
/**
* Connects the FtpClient to the specified destination server.
*
* @param dest the address of the destination server
* @param timeout the value, in milliseconds, to use as a connection timeout
* @return this FtpClient
* @throws IOException if connection failed.
* @throws SecurityException if there is a SecurityManager installed and it
* denied the authorization to connect to the destination.
* @throws FtpProtocolException
*/
public abstract FtpClient connect(SocketAddress dest, int timeout) throws FtpProtocolException, IOException;
/**
* Retrieves the address of the FTP server this client is connected to.
*
* @return the {@link SocketAddress} of the server, or {@code null} if this
* client is not connected yet.
*/
public abstract SocketAddress getServerAddress();
/**
* Attempts to log on the server with the specified user name and password.
*
* @param user The user name
* @param password The password for that user
* @return this FtpClient
* @throws IOException if an error occurred during the transmission
* @throws FtpProtocolException if the login was refused by the server
*/
public abstract FtpClient login(String user, char[] password) throws FtpProtocolException, IOException;
/**
* Attempts to log on the server with the specified user name, password and
* account name.
*
* @param user The user name
* @param password The password for that user.
* @param account The account name for that user.
* @return this FtpClient
* @throws IOException if an error occurs during the transmission.
* @throws FtpProtocolException if the login was refused by the server
*/
public abstract FtpClient login(String user, char[] password, String account) throws FtpProtocolException, IOException;
/**
* Closes the current connection. Logs out the current user, if any, by
* issuing the QUIT command to the server.
* This is in effect terminates the current
* session and the connection to the server will be closed.
* <p>After a close, the client can then be connected to another server
* to start an entirely different session.</P>
*
* @throws IOException if an error occurs during transmission
*/
public abstract void close() throws IOException;
/**
* Checks whether the client is logged in to the server or not.
*
* @return {@code true} if the client has already completed a login.
*/
public abstract boolean isLoggedIn();
/**
* Changes to a specific directory on a remote FTP server
*
* @param remoteDirectory path of the directory to CD to.
* @return this FtpClient
* @throws IOException if an error occurs during the transmission.
* @throws FtpProtocolException if the command was refused by the server
*/
public abstract FtpClient changeDirectory(String remoteDirectory) throws FtpProtocolException, IOException;
/**
* Changes to the parent directory, sending the CDUP command to the server.
*
* @return this FtpClient
* @throws IOException if an error occurs during the transmission.
* @throws FtpProtocolException if the command was refused by the server
*/
public abstract FtpClient changeToParentDirectory() throws FtpProtocolException, IOException;
/**
* Retrieve the server current working directory using the PWD command.
*
* @return a {@code String} containing the current working directory
* @throws IOException if an error occurs during transmission
* @throws FtpProtocolException if the command was refused by the server,
*/
public abstract String getWorkingDirectory() throws FtpProtocolException, IOException;
/**
* Sets the restart offset to the specified value. That value will be
* sent through a {@code REST} command to server before the next file
* transfer and has the effect of resuming a file transfer from the
* specified point. After the transfer the restart offset is set back to
* zero.
*
* @param offset the offset in the remote file at which to start the next
* transfer. This must be a value greater than or equal to zero.
* @return this FtpClient
* @throws IllegalArgumentException if the offset is negative.
*/
public abstract FtpClient setRestartOffset(long offset);
/**
* Retrieves a file from the ftp server and writes its content to the specified
* {@code OutputStream}.
* <p>If the restart offset was set, then a {@code REST} command will be
* sent before the {@code RETR} in order to restart the tranfer from the specified
* offset.</p>
* <p>The {@code OutputStream} is not closed by this method at the end
* of the transfer. </p>
* <p>This method will block until the transfer is complete or an exception
* is thrown.</p>
*
* @param name a {@code String} containing the name of the file to
* retreive from the server.
* @param local the {@code OutputStream} the file should be written to.
* @return this FtpClient
* @throws IOException if the transfer fails.
* @throws FtpProtocolException if the command was refused by the server
* @see #setRestartOffset(long)
*/
public abstract FtpClient getFile(String name, OutputStream local) throws FtpProtocolException, IOException;
/**
* Retrieves a file from the ftp server, using the {@code RETR} command, and
* returns the InputStream from the established data connection.
* {@link #completePending()} <b>has</b> to be called once the application
* is done reading from the returned stream.
* <p>If the restart offset was set, then a {@code REST} command will be
* sent before the {@code RETR} in order to restart the tranfer from the specified
* offset.</p>
*
* @param name the name of the remote file
* @return the {@link java.io.InputStream} from the data connection
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was refused by the server
* @see #setRestartOffset(long)
*/
public abstract InputStream getFileStream(String name) throws FtpProtocolException, IOException;
/**
* Transfers a file from the client to the server (aka a <I>put</I>)
* by sending the STOR command, and returns the {@code OutputStream}
* from the established data connection.
*
* A new file is created at the server site if the file specified does
* not already exist.
*
* {@link #completePending()} <b>has</b> to be called once the application
* is finished writing to the returned stream.
*
* @param name the name of the remote file to write.
* @return the {@link java.io.OutputStream} from the data connection or
* {@code null} if the command was unsuccessful.
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public OutputStream putFileStream(String name) throws FtpProtocolException, IOException {
return putFileStream(name, false);
}
/**
* Transfers a file from the client to the server (aka a <I>put</I>)
* by sending the STOR or STOU command, depending on the
* {@code unique} argument, and returns the {@code OutputStream}
* from the established data connection.
* {@link #completePending()} <b>has</b> to be called once the application
* is finished writing to the stream.
*
* A new file is created at the server site if the file specified does
* not already exist.
*
* If {@code unique} is set to {@code true}, the resultant file
* is to be created under a name unique to that directory, meaning
* it will not overwrite an existing file, instead the server will
* generate a new, unique, file name.
* The name of the remote file can be retrieved, after completion of the
* transfer, by calling {@link #getLastFileName()}.
*
* @param name the name of the remote file to write.
* @param unique {@code true} if the remote files should be unique,
* in which case the STOU command will be used.
* @return the {@link java.io.OutputStream} from the data connection.
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract OutputStream putFileStream(String name, boolean unique) throws FtpProtocolException, IOException;
/**
* Transfers a file from the client to the server (aka a <I>put</I>)
* by sending the STOR or STOU command, depending on the
* {@code unique} argument. The content of the {@code InputStream}
* passed in argument is written into the remote file, overwriting any
* existing data.
*
* A new file is created at the server site if the file specified does
* not already exist.
*
* If {@code unique} is set to {@code true}, the resultant file
* is to be created under a name unique to that directory, meaning
* it will not overwrite an existing file, instead the server will
* generate a new, unique, file name.
* The name of the remote file can be retrieved, after completion of the
* transfer, by calling {@link #getLastFileName()}.
*
* <p>This method will block until the transfer is complete or an exception
* is thrown.</p>
*
* @param name the name of the remote file to write.
* @param local the {@code InputStream} that points to the data to
* transfer.
* @return this FtpClient
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public FtpClient putFile(String name, InputStream local) throws FtpProtocolException, IOException {
return putFile(name, local, false);
}
/**
* Transfers a file from the client to the server (aka a <I>put</I>)
* by sending the STOR command. The content of the {@code InputStream}
* passed in argument is written into the remote file, overwriting any
* existing data.
*
* A new file is created at the server site if the file specified does
* not already exist.
*
* <p>This method will block until the transfer is complete or an exception
* is thrown.</p>
*
* @param name the name of the remote file to write.
* @param local the {@code InputStream} that points to the data to
* transfer.
* @param unique {@code true} if the remote file should be unique
* (i.e. not already existing), {@code false} otherwise.
* @return this FtpClient
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
* @see #getLastFileName()
*/
public abstract FtpClient putFile(String name, InputStream local, boolean unique) throws FtpProtocolException, IOException;
/**
* Sends the APPE command to the server in order to transfer a data stream
* passed in argument and append it to the content of the specified remote
* file.
*
* <p>This method will block until the transfer is complete or an exception
* is thrown.</p>
*
* @param name A {@code String} containing the name of the remote file
* to append to.
* @param local The {@code InputStream} providing access to the data
* to be appended.
* @return this FtpClient
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract FtpClient appendFile(String name, InputStream local) throws FtpProtocolException, IOException;
/**
* Renames a file on the server.
*
* @param from the name of the file being renamed
* @param to the new name for the file
* @return this FtpClient
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract FtpClient rename(String from, String to) throws FtpProtocolException, IOException;
/**
* Deletes a file on the server.
*
* @param name a {@code String} containing the name of the file
* to delete.
* @return this FtpClient
* @throws IOException if an error occurred during the exchange
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract FtpClient deleteFile(String name) throws FtpProtocolException, IOException;
/**
* Creates a new directory on the server.
*
* @param name a {@code String} containing the name of the directory
* to create.
* @return this FtpClient
* @throws IOException if an error occurred during the exchange
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract FtpClient makeDirectory(String name) throws FtpProtocolException, IOException;
/**
* Removes a directory on the server.
*
* @param name a {@code String} containing the name of the directory
* to remove.
*
* @return this FtpClient
* @throws IOException if an error occurred during the exchange.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract FtpClient removeDirectory(String name) throws FtpProtocolException, IOException;
/**
* Sends a No-operation command. It's useful for testing the connection
* status or as a <I>keep alive</I> mechanism.
*
* @return this FtpClient
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract FtpClient noop() throws FtpProtocolException, IOException;
/**
* Sends the {@code STAT} command to the server.
* This can be used while a data connection is open to get a status
* on the current transfer, in that case the parameter should be
* {@code null}.
* If used between file transfers, it may have a pathname as argument
* in which case it will work as the LIST command except no data
* connection will be created.
*
* @param name an optional {@code String} containing the pathname
* the STAT command should apply to.
* @return the response from the server
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract String getStatus(String name) throws FtpProtocolException, IOException;
/**
* Sends the {@code FEAT} command to the server and returns the list of supported
* features in the form of strings.
*
* The features are the supported commands, like AUTH TLS, PROT or PASV.
* See the RFCs for a complete list.
*
* Note that not all FTP servers support that command, in which case
* a {@link FtpProtocolException} will be thrown.
*
* @return a {@code List} of {@code Strings} describing the
* supported additional features
* @throws IOException if an error occurs during the transmission.
* @throws FtpProtocolException if the command is rejected by the server
*/
public abstract List<String> getFeatures() throws FtpProtocolException, IOException;
/**
* Sends the {@code ABOR} command to the server.
* <p>It tells the server to stop the previous command or transfer. No action
* will be taken if the previous command has already been completed.</p>
* <p>This doesn't abort the current session, more commands can be issued
* after an abort.</p>
*
* @return this FtpClient
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract FtpClient abort() throws FtpProtocolException, IOException;
/**
* Some methods do not wait until completion before returning, so this
* method can be called to wait until completion. This is typically the case
* with commands that trigger a transfer like {@link #getFileStream(String)}.
* So this method should be called before accessing information related to
* such a command.
* <p>This method will actually block reading on the command channel for a
* notification from the server that the command is finished. Such a
* notification often carries extra information concerning the completion
* of the pending action (e.g. number of bytes transfered).</p>
* <p>Note that this will return immediately if no command or action
* is pending</p>
* <p>It should be also noted that most methods issuing commands to the ftp
* server will call this method if a previous command is pending.
* <p>Example of use:
* <pre>
* InputStream in = cl.getFileStream("file");
* ...
* cl.completePending();
* long size = cl.getLastTransferSize();
* </pre>
* On the other hand, it's not necessary in a case like:
* <pre>
* InputStream in = cl.getFileStream("file");
* // read content
* ...
* cl.close();
* </pre>
* <p>Since {@link #close()} will call completePending() if necessary.</p>
* @return this FtpClient
* @throws IOException if an error occurred during the transfer
* @throws FtpProtocolException if the command didn't complete successfully
*/
public abstract FtpClient completePending() throws FtpProtocolException, IOException;
/**
* Reinitializes the USER parameters on the FTP server
*
* @return this FtpClient
* @throws IOException if an error occurs during transmission
* @throws FtpProtocolException if the command fails
*/
public abstract FtpClient reInit() throws FtpProtocolException, IOException;
/**
* Changes the transfer type (binary, ascii, ebcdic) and issue the
* proper command (e.g. TYPE A) to the server.
*
* @param type the {@code TransferType} to use.
* @return This FtpClient
* @throws IOException if an error occurs during transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract FtpClient setType(TransferType type) throws FtpProtocolException, IOException;
/**
* Changes the current transfer type to binary.
* This is a convenience method that is equivalent to
* {@code setType(TransferType.BINARY)}
*
* @return This FtpClient
* @throws IOException if an error occurs during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
* @see #setType(TransferType)
*/
public FtpClient setBinaryType() throws FtpProtocolException, IOException {
setType(TransferType.BINARY);
return this;
}
/**
* Changes the current transfer type to ascii.
* This is a convenience method that is equivalent to
* {@code setType(TransferType.ASCII)}
*
* @return This FtpClient
* @throws IOException if an error occurs during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
* @see #setType(TransferType)
*/
public FtpClient setAsciiType() throws FtpProtocolException, IOException {
setType(TransferType.ASCII);
return this;
}
/**
* Issues a {@code LIST} command to the server to get the current directory
* listing, and returns the InputStream from the data connection.
*
* <p>{@link #completePending()} <b>has</b> to be called once the application
* is finished reading from the stream.</p>
*
* @param path the pathname of the directory to list, or {@code null}
* for the current working directory.
* @return the {@code InputStream} from the resulting data connection
* @throws IOException if an error occurs during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
* @see #changeDirectory(String)
* @see #listFiles(String)
*/
public abstract InputStream list(String path) throws FtpProtocolException, IOException;
/**
* Issues a {@code NLST path} command to server to get the specified directory
* content. It differs from {@link #list(String)} method by the fact that
* it will only list the file names which would make the parsing of the
* somewhat easier.
*
* <p>{@link #completePending()} <b>has</b> to be called once the application
* is finished reading from the stream.</p>
*
* @param path a {@code String} containing the pathname of the
* directory to list or {@code null} for the current working directory.
* @return the {@code InputStream} from the resulting data connection
* @throws IOException if an error occurs during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract InputStream nameList(String path) throws FtpProtocolException, IOException;
/**
* Issues the {@code SIZE [path]} command to the server to get the size of a
* specific file on the server.
* Note that this command may not be supported by the server. In which
* case -1 will be returned.
*
* @param path a {@code String} containing the pathname of the
* file.
* @return a {@code long} containing the size of the file or -1 if
* the server returned an error, which can be checked with
* {@link #getLastReplyCode()}.
* @throws IOException if an error occurs during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract long getSize(String path) throws FtpProtocolException, IOException;
/**
* Issues the {@code MDTM [path]} command to the server to get the modification
* time of a specific file on the server.
* Note that this command may not be supported by the server, in which
* case {@code null} will be returned.
*
* @param path a {@code String} containing the pathname of the file.
* @return a {@code Date} representing the last modification time
* or {@code null} if the server returned an error, which
* can be checked with {@link #getLastReplyCode()}.
* @throws IOException if an error occurs during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract Date getLastModified(String path) throws FtpProtocolException, IOException;
/**
* Sets the parser used to handle the directory output to the specified
* one. By default the parser is set to one that can handle most FTP
* servers output (Unix base mostly). However it may be necessary for
* and application to provide its own parser due to some uncommon
* output format.
*
* @param p The {@code FtpDirParser} to use.
* @return this FtpClient
* @see #listFiles(String)
*/
public abstract FtpClient setDirParser(FtpDirParser p);
/**
* Issues a {@code MLSD} command to the server to get the specified directory
* listing and applies the internal parser to create an Iterator of
* {@link java.net.FtpDirEntry}. Note that the Iterator returned is also a
* {@link java.io.Closeable}.
* <p>If the server doesn't support the MLSD command, the LIST command is used
* instead and the parser set by {@link #setDirParser(java.net.FtpDirParser) }
* is used instead.</p>
*
* {@link #completePending()} <b>has</b> to be called once the application
* is finished iterating through the files.
*
* @param path the pathname of the directory to list or {@code null}
* for the current working directoty.
* @return a {@code Iterator} of files or {@code null} if the
* command failed.
* @throws IOException if an error occurred during the transmission
* @see #setDirParser(FtpDirParser)
* @see #changeDirectory(String)
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract Iterator<FtpDirEntry> listFiles(String path) throws FtpProtocolException, IOException;
/**
* Attempts to use Kerberos GSSAPI as an authentication mechanism with the
* ftp server. This will issue an {@code AUTH GSSAPI} command, and if
* it is accepted by the server, will followup with {@code ADAT}
* command to exchange the various tokens until authentication is
* successful. This conforms to Appendix I of RFC 2228.
*
* @return this FtpClient
* @throws IOException if an error occurs during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract FtpClient useKerberos() throws FtpProtocolException, IOException;
/**
* Returns the Welcome string the server sent during initial connection.
*
* @return a {@code String} containing the message the server
* returned during connection or {@code null}.
*/
public abstract String getWelcomeMsg();
/**
* Returns the last reply code sent by the server.
*
* @return the lastReplyCode or {@code null} if none were received yet.
*/
public abstract FtpReplyCode getLastReplyCode();
/**
* Returns the last response string sent by the server.
*
* @return the message string, which can be quite long, last returned
* by the server, or {@code null} if no response were received yet.
*/
public abstract String getLastResponseString();
/**
* Returns, when available, the size of the latest started transfer.
* This is retreived by parsing the response string received as an initial
* response to a {@code RETR} or similar request.
*
* @return the size of the latest transfer or -1 if either there was no
* transfer or the information was unavailable.
*/
public abstract long getLastTransferSize();
/**
* Returns, when available, the remote name of the last transfered file.
* This is mainly useful for "put" operation when the unique flag was
* set since it allows to recover the unique file name created on the
* server which may be different from the one submitted with the command.
*
* @return the name the latest transfered file remote name, or
* {@code null} if that information is unavailable.
*/
public abstract String getLastFileName();
/**
* Attempts to switch to a secure, encrypted connection. This is done by
* sending the {@code AUTH TLS} command.
* <p>See <a href="http://www.ietf.org/rfc/rfc4217.txt">RFC 4217</a></p>
* If successful this will establish a secure command channel with the
* server, it will also make it so that all other transfers (e.g. a RETR
* command) will be done over an encrypted channel as well unless a
* {@link #reInit()} command or a {@link #endSecureSession()} command is issued.
* <p>This method should be called after a successful {@link #connect(java.net.InetSocketAddress) }
* but before calling {@link #login(java.lang.String, char[]) }.</p>
*
* @return this FtpCLient
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
* @see #endSecureSession()
*/
public abstract FtpClient startSecureSession() throws FtpProtocolException, IOException;
/**
* Sends a {@code CCC} command followed by a {@code PROT C}
* command to the server terminating an encrypted session and reverting
* back to a non encrypted transmission.
*
* @return this FtpClient
* @throws IOException if an error occurred during transmission.
* @throws FtpProtocolException if the command was rejected by the server
* @see #startSecureSession()
*/
public abstract FtpClient endSecureSession() throws FtpProtocolException, IOException;
/**
* Sends the "Allocate" ({@code ALLO}) command to the server telling it to
* pre-allocate the specified number of bytes for the next transfer.
*
* @param size The number of bytes to allocate.
* @return this FtpClient
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract FtpClient allocate(long size) throws FtpProtocolException, IOException;
/**
* Sends the "Structure Mount" ({@code SMNT}) command to the server. This let the
* user mount a different file system data structure without altering his
* login or accounting information.
*
* @param struct a {@code String} containing the name of the
* structure to mount.
* @return this FtpClient
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract FtpClient structureMount(String struct) throws FtpProtocolException, IOException;
/**
* Sends a System ({@code SYST}) command to the server and returns the String
* sent back by the server describing the operating system at the
* server.
*
* @return a {@code String} describing the OS, or {@code null}
* if the operation was not successful.
* @throws IOException if an error occurred during the transmission.
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract String getSystem() throws FtpProtocolException, IOException;
/**
* Sends the {@code HELP} command to the server, with an optional command, like
* SITE, and returns the text sent back by the server.
*
* @param cmd the command for which the help is requested or
* {@code null} for the general help
* @return a {@code String} containing the text sent back by the
* server, or {@code null} if the command failed.
* @throws IOException if an error occurred during transmission
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract String getHelp(String cmd) throws FtpProtocolException, IOException;
/**
* Sends the {@code SITE} command to the server. This is used by the server
* to provide services specific to his system that are essential
* to file transfer.
*
* @param cmd the command to be sent.
* @return this FtpClient
* @throws IOException if an error occurred during transmission
* @throws FtpProtocolException if the command was rejected by the server
*/
public abstract FtpClient siteCmd(String cmd) throws FtpProtocolException, IOException;
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.ftp;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ServiceConfigurationError;
//import java.util.ServiceLoader;
/**
* Service provider class for FtpClient.
* Sub-classes of FtpClientProvider provide an implementation of {@link FtpClient}
* and associated classes. Applications do not normally use this class directly.
* See {@link #provider() } for how providers are found and loaded.
*
* @since 1.7
*/
public abstract class FtpClientProvider {
/**
* Creates a FtpClient from this provider.
*
* @return The created {@link FtpClient}.
*/
public abstract FtpClient createFtpClient();
private static final Object lock = new Object();
private static FtpClientProvider provider = null;
/**
* Initializes a new instance of this class.
*
* @throws SecurityException if a security manager is installed and it denies
* {@link RuntimePermission}<tt>("ftpClientProvider")</tt>
*/
protected FtpClientProvider() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("ftpClientProvider"));
}
}
private static boolean loadProviderFromProperty() {
String cm = System.getProperty("sun.net.ftpClientProvider");
if (cm == null) {
return false;
}
try {
Class<?> c = Class.forName(cm, true, null);
provider = (FtpClientProvider) c.newInstance();
return true;
} catch (ClassNotFoundException |
IllegalAccessException |
InstantiationException |
SecurityException x) {
throw new ServiceConfigurationError(x.toString());
}
}
private static boolean loadProviderAsService() {
// Iterator<FtpClientProvider> i =
// ServiceLoader.load(FtpClientProvider.class,
// ClassLoader.getSystemClassLoader()).iterator();
//
// while (i.hasNext()) {
// try {
// provider = i.next();
// return true;
// } catch (ServiceConfigurationError sce) {
// if (sce.getCause() instanceof SecurityException) {
// // Ignore, try next provider, if any
// continue;
// }
// throw sce;
// }
// }
return false;
}
/**
* Returns the system wide default FtpClientProvider for this invocation of
* the Java virtual machine.
*
* <p> The first invocation of this method locates the default provider
* object as follows: </p>
*
* <ol>
*
* <li><p> If the system property
* <tt>java.net.FtpClientProvider</tt> is defined then it is
* taken to be the fully-qualified name of a concrete provider class.
* The class is loaded and instantiated; if this process fails then an
* unspecified unchecked error or exception is thrown. </p></li>
*
* <li><p> If a provider class has been installed in a jar file that is
* visible to the system class loader, and that jar file contains a
* provider-configuration file named
* <tt>java.net.FtpClientProvider</tt> in the resource
* directory <tt>META-INF/services</tt>, then the first class name
* specified in that file is taken. The class is loaded and
* instantiated; if this process fails then an unspecified unchecked error or exception is
* thrown. </p></li>
*
* <li><p> Finally, if no provider has been specified by any of the above
* means then the system-default provider class is instantiated and the
* result is returned. </p></li>
*
* </ol>
*
* <p> Subsequent invocations of this method return the provider that was
* returned by the first invocation. </p>
*
* @return The system-wide default FtpClientProvider
*/
public static FtpClientProvider provider() {
synchronized (lock) {
if (provider != null) {
return provider;
}
return (FtpClientProvider) AccessController.doPrivileged(
new PrivilegedAction<Object>() {
public Object run() {
if (loadProviderFromProperty()) {
return provider;
}
if (loadProviderAsService()) {
return provider;
}
provider = new sun.net.ftp.impl.DefaultFtpClientProvider();
return provider;
}
});
}
}
}

View File

@@ -0,0 +1,331 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.ftp;
import java.util.Date;
import java.util.HashMap;
/**
* A {@code FtpDirEntry} is a class agregating all the information that the FTP client
* can gather from the server by doing a {@code LST} (or {@code NLST}) command and
* parsing the output. It will typically contain the name, type, size, last modification
* time, owner and group of the file, although some of these could be unavailable
* due to specific FTP server limitations.
*
* @see sun.net.ftp.FtpDirParser
* @since 1.7
*/
public class FtpDirEntry {
public enum Type {
FILE, DIR, PDIR, CDIR, LINK
};
public enum Permission {
USER(0), GROUP(1), OTHERS(2);
int value;
Permission(int v) {
value = v;
}
};
private final String name;
private String user = null;
private String group = null;
private long size = -1;
private java.util.Date created = null;
private java.util.Date lastModified = null;
private Type type = Type.FILE;
private boolean[][] permissions = null;
private HashMap<String, String> facts = new HashMap<String, String>();
private FtpDirEntry() {
name = null;
}
/**
* Creates an FtpDirEntry instance with only the name being set.
*
* @param name The name of the file
*/
public FtpDirEntry(String name) {
this.name = name;
}
/**
* Returns the name of the remote file.
*
* @return a {@code String} containing the name of the remote file.
*/
public String getName() {
return name;
}
/**
* Returns the user name of the owner of the file as returned by the FTP
* server, if provided. This could be a name or a user id (number).
*
* @return a {@code String} containing the user name or
* {@code null} if that information is not available.
*/
public String getUser() {
return user;
}
/**
* Sets the user name of the owner of the file. Intended mostly to be
* used from inside a {@link java.net.FtpDirParser} implementation.
*
* @param user The user name of the owner of the file, or {@code null}
* if that information is not available.
* @return this FtpDirEntry
*/
public FtpDirEntry setUser(String user) {
this.user = user;
return this;
}
/**
* Returns the group name of the file as returned by the FTP
* server, if provided. This could be a name or a group id (number).
*
* @return a {@code String} containing the group name or
* {@code null} if that information is not available.
*/
public String getGroup() {
return group;
}
/**
* Sets the name of the group to which the file belong. Intended mostly to be
* used from inside a {@link java.net.FtpDirParser} implementation.
*
* @param group The name of the group to which the file belong, or {@code null}
* if that information is not available.
* @return this FtpDirEntry
*/
public FtpDirEntry setGroup(String group) {
this.group = group;
return this;
}
/**
* Returns the size of the remote file as it was returned by the FTP
* server, if provided.
*
* @return the size of the file or -1 if that information is not available.
*/
public long getSize() {
return size;
}
/**
* Sets the size of that file. Intended mostly to be used from inside an
* {@link java.net.FtpDirParser} implementation.
*
* @param size The size, in bytes, of that file. or -1 if unknown.
* @return this FtpDirEntry
*/
public FtpDirEntry setSize(long size) {
this.size = size;
return this;
}
/**
* Returns the type of the remote file as it was returned by the FTP
* server, if provided.
* It returns a FtpDirEntry.Type enum and the values can be:
* - FtpDirEntry.Type.FILE for a normal file
* - FtpDirEntry.Type.DIR for a directory
* - FtpDirEntry.Type.LINK for a symbolic link
*
* @return a {@code FtpDirEntry.Type} describing the type of the file
* or {@code null} if that information is not available.
*/
public Type getType() {
return type;
}
/**
* Sets the type of the file. Intended mostly to be used from inside an
* {@link java.net.FtpDirParser} implementation.
*
* @param type the type of this file or {@code null} if that information
* is not available.
* @return this FtpDirEntry
*/
public FtpDirEntry setType(Type type) {
this.type = type;
return this;
}
/**
* Returns the last modification time of the remote file as it was returned
* by the FTP server, if provided, {@code null} otherwise.
*
* @return a <code>Date</code> representing the last time the file was
* modified on the server, or {@code null} if that
* information is not available.
*/
public java.util.Date getLastModified() {
return this.lastModified;
}
/**
* Sets the last modification time of the file. Intended mostly to be used
* from inside an {@link java.net.FtpDirParser} implementation.
*
* @param lastModified The Date representing the last modification time, or
* {@code null} if that information is not available.
* @return this FtpDirEntry
*/
public FtpDirEntry setLastModified(Date lastModified) {
this.lastModified = lastModified;
return this;
}
/**
* Returns whether read access is granted for a specific permission.
*
* @param p the Permission (user, group, others) to check.
* @return {@code true} if read access is granted.
*/
public boolean canRead(Permission p) {
if (permissions != null) {
return permissions[p.value][0];
}
return false;
}
/**
* Returns whether write access is granted for a specific permission.
*
* @param p the Permission (user, group, others) to check.
* @return {@code true} if write access is granted.
*/
public boolean canWrite(Permission p) {
if (permissions != null) {
return permissions[p.value][1];
}
return false;
}
/**
* Returns whether execute access is granted for a specific permission.
*
* @param p the Permission (user, group, others) to check.
* @return {@code true} if execute access is granted.
*/
public boolean canExexcute(Permission p) {
if (permissions != null) {
return permissions[p.value][2];
}
return false;
}
/**
* Sets the permissions for that file. Intended mostly to be used
* from inside an {@link java.net.FtpDirParser} implementation.
* The permissions array is a 3x3 {@code boolean} array, the first index being
* the User, group or owner (0, 1 and 2 respectively) while the second
* index is read, write or execute (0, 1 and 2 respectively again).
* <p>E.G.: {@code permissions[1][2]} is the group/execute permission.</p>
*
* @param permissions a 3x3 {@code boolean} array
* @return this {@code FtpDirEntry}
*/
public FtpDirEntry setPermissions(boolean[][] permissions) {
this.permissions = permissions;
return this;
}
/**
* Adds a 'fact', as defined in RFC 3659, to the list of facts of this file.
* Intended mostly to be used from inside a {@link java.net.FtpDirParser}
* implementation.
*
* @param fact the name of the fact (e.g. "Media-Type"). It is not case-sensitive.
* @param value the value associated with this fact.
* @return this {@code FtpDirEntry}
*/
public FtpDirEntry addFact(String fact, String value) {
facts.put(fact.toLowerCase(), value);
return this;
}
/**
* Returns the requested 'fact', as defined in RFC 3659, if available.
*
* @param fact The name of the fact *e.g. "Media-Type"). It is not case sensitive.
* @return The value of the fact or, {@code null} if that fact wasn't
* provided by the server.
*/
public String getFact(String fact) {
return facts.get(fact.toLowerCase());
}
/**
* Returns the creation time of the file, when provided by the server.
*
* @return The Date representing the creation time, or {@code null}
* if the server didn't provide that information.
*/
public Date getCreated() {
return created;
}
/**
* Sets the creation time for that file. Intended mostly to be used from
* inside a {@link java.net.FtpDirParser} implementation.
*
* @param created the Date representing the creation time for that file, or
* {@code null} if that information is not available.
* @return this FtpDirEntry
*/
public FtpDirEntry setCreated(Date created) {
this.created = created;
return this;
}
/**
* Returns a string representation of the object.
* The {@code toString} method for class {@code FtpDirEntry}
* returns a string consisting of the name of the file, followed by its
* type between brackets, followed by the user and group between
* parenthesis, then size between '{', and, finally, the lastModified of last
* modification if it's available.
*
* @return a string representation of the object.
*/
@Override
public String toString() {
if (lastModified == null) {
return name + " [" + type + "] (" + user + " / " + group + ") " + size;
}
return name + " [" + type + "] (" + user + " / " + group + ") {" + size + "} " + java.text.DateFormat.getDateInstance().format(lastModified);
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.ftp;
/**
* This interface describes a parser for the FtpClient class. Such a parser is
* used when listing a remote directory to transform text lines like:
* drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog
* into FtpDirEntry instances.
*
* @see java.net.FtpClient#setFileParser(FtpDirParser)
* @since 1.7
*/
public interface FtpDirParser {
/**
* Takes one line from a directory listing and returns an FtpDirEntry instance
* based on the information contained.
*
* @param line a <code>String</code>, a line sent by the FTP server as a
* result of the LST command.
* @return an <code>FtpDirEntry</code> instance.
* @see java.net.FtpDirEntry
*/
public FtpDirEntry parseLine(String line);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 1994, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.ftp;
import java.io.IOException;
/**
* This exception is thrown when an error is encountered during an
* FTP login operation.
*
* @author Jonathan Payne
*/
public class FtpLoginException extends IOException {
private static final long serialVersionUID = 2218162403237941536L;
public FtpLoginException(String s) {
super(s);
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 1994, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.ftp;
/**
* Thrown to indicate that the FTP server reported an error.
* For instance that the requested file doesn't exist or
* that a command isn't supported.
* <p>The specific error code can be retreived with {@link #getReplyCode() }.</p>
* @author Jonathan Payne
*/
public class FtpProtocolException extends Exception {
private static final long serialVersionUID = 5978077070276545054L;
private final FtpReplyCode code;
/**
* Constructs a new {@code FtpProtocolException} from the
* specified detail message. The reply code is set to unknow error.
*
* @param detail the detail message.
*/
public FtpProtocolException(String detail) {
super(detail);
code = FtpReplyCode.UNKNOWN_ERROR;
}
/**
* Constructs a new {@code FtpProtocolException} from the
* specified response code and exception detail message
*
* @param detail the detail message.
* @param code The {@code FtpRelyCode} received from server.
*/
public FtpProtocolException(String detail, FtpReplyCode code) {
super(detail);
this.code = code;
}
/**
* Gets the reply code sent by the server that led to this exception
* being thrown.
*
* @return The {@link FtpReplyCode} associated with that exception.
*/
public FtpReplyCode getReplyCode() {
return code;
}
}

View File

@@ -0,0 +1,248 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.ftp;
/**
* This class describes a FTP protocol reply code and associates a meaning
* to the numerical value according to the various RFCs (RFC 959 in
* particular).
*
*/
public enum FtpReplyCode {
RESTART_MARKER(110),
SERVICE_READY_IN(120),
DATA_CONNECTION_ALREADY_OPEN(125),
FILE_STATUS_OK(150),
COMMAND_OK(200),
NOT_IMPLEMENTED(202),
SYSTEM_STATUS(211),
DIRECTORY_STATUS(212),
FILE_STATUS(213),
HELP_MESSAGE(214),
NAME_SYSTEM_TYPE(215),
SERVICE_READY(220),
SERVICE_CLOSING(221),
DATA_CONNECTION_OPEN(225),
CLOSING_DATA_CONNECTION(226),
ENTERING_PASSIVE_MODE(227),
ENTERING_EXT_PASSIVE_MODE(229),
LOGGED_IN(230),
SECURELY_LOGGED_IN(232),
SECURITY_EXCHANGE_OK(234),
SECURITY_EXCHANGE_COMPLETE(235),
FILE_ACTION_OK(250),
PATHNAME_CREATED(257),
NEED_PASSWORD(331),
NEED_ACCOUNT(332),
NEED_ADAT(334),
NEED_MORE_ADAT(335),
FILE_ACTION_PENDING(350),
SERVICE_NOT_AVAILABLE(421),
CANT_OPEN_DATA_CONNECTION(425),
CONNECTION_CLOSED(426),
NEED_SECURITY_RESOURCE(431),
FILE_ACTION_NOT_TAKEN(450),
ACTION_ABORTED(451),
INSUFFICIENT_STORAGE(452),
COMMAND_UNRECOGNIZED(500),
INVALID_PARAMETER(501),
BAD_SEQUENCE(503),
NOT_IMPLEMENTED_FOR_PARAMETER(504),
NOT_LOGGED_IN(530),
NEED_ACCOUNT_FOR_STORING(532),
PROT_LEVEL_DENIED(533),
REQUEST_DENIED(534),
FAILED_SECURITY_CHECK(535),
UNSUPPORTED_PROT_LEVEL(536),
PROT_LEVEL_NOT_SUPPORTED_BY_SECURITY(537),
FILE_UNAVAILABLE(550),
PAGE_TYPE_UNKNOWN(551),
EXCEEDED_STORAGE(552),
FILE_NAME_NOT_ALLOWED(553),
PROTECTED_REPLY(631),
UNKNOWN_ERROR(999);
private final int value;
FtpReplyCode(int val) {
this.value = val;
}
/**
* Returns the numerical value of the code.
*
* @return the numerical value.
*/
public int getValue() {
return value;
}
/**
* Determines if the code is a Positive Preliminary response.
* This means beginning with a 1 (which means a value between 100 and 199)
*
* @return <code>true</code> if the reply code is a positive preliminary
* response.
*/
public boolean isPositivePreliminary() {
return value >= 100 && value < 200;
}
/**
* Determines if the code is a Positive Completion response.
* This means beginning with a 2 (which means a value between 200 and 299)
*
* @return <code>true</code> if the reply code is a positive completion
* response.
*/
public boolean isPositiveCompletion() {
return value >= 200 && value < 300;
}
/**
* Determines if the code is a positive internediate response.
* This means beginning with a 3 (which means a value between 300 and 399)
*
* @return <code>true</code> if the reply code is a positive intermediate
* response.
*/
public boolean isPositiveIntermediate() {
return value >= 300 && value < 400;
}
/**
* Determines if the code is a transient negative response.
* This means beginning with a 4 (which means a value between 400 and 499)
*
* @return <code>true</code> if the reply code is a transient negative
* response.
*/
public boolean isTransientNegative() {
return value >= 400 && value < 500;
}
/**
* Determines if the code is a permanent negative response.
* This means beginning with a 5 (which means a value between 500 and 599)
*
* @return <code>true</code> if the reply code is a permanent negative
* response.
*/
public boolean isPermanentNegative() {
return value >= 500 && value < 600;
}
/**
* Determines if the code is a protected reply response.
* This means beginning with a 6 (which means a value between 600 and 699)
*
* @return <code>true</code> if the reply code is a protected reply
* response.
*/
public boolean isProtectedReply() {
return value >= 600 && value < 700;
}
/**
* Determines if the code is a syntax related response.
* This means the second digit is a 0.
*
* @return <code>true</code> if the reply code is a syntax related
* response.
*/
public boolean isSyntax() {
return ((value / 10) - ((value / 100) * 10)) == 0;
}
/**
* Determines if the code is an information related response.
* This means the second digit is a 1.
*
* @return <code>true</code> if the reply code is an information related
* response.
*/
public boolean isInformation() {
return ((value / 10) - ((value / 100) * 10)) == 1;
}
/**
* Determines if the code is a connection related response.
* This means the second digit is a 2.
*
* @return <code>true</code> if the reply code is a connection related
* response.
*/
public boolean isConnection() {
return ((value / 10) - ((value / 100) * 10)) == 2;
}
/**
* Determines if the code is an authentication related response.
* This means the second digit is a 3.
*
* @return <code>true</code> if the reply code is an authentication related
* response.
*/
public boolean isAuthentication() {
return ((value / 10) - ((value / 100) * 10)) == 3;
}
/**
* Determines if the code is an unspecified type of response.
* This means the second digit is a 4.
*
* @return <code>true</code> if the reply code is an unspecified type of
* response.
*/
public boolean isUnspecified() {
return ((value / 10) - ((value / 100) * 10)) == 4;
}
/**
* Determines if the code is a file system related response.
* This means the second digit is a 5.
*
* @return <code>true</code> if the reply code is a file system related
* response.
*/
public boolean isFileSystem() {
return ((value / 10) - ((value / 100) * 10)) == 5;
}
/**
* Static utility method to convert a value into a FtpReplyCode.
*
* @param v the value to convert
* @return the <code>FtpReplyCode</code> associated with the value.
*/
public static FtpReplyCode find(int v) {
for (FtpReplyCode code : FtpReplyCode.values()) {
if (code.getValue() == v) {
return code;
}
}
return UNKNOWN_ERROR;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.ftp.impl;
/**
* Default FtpClientProvider.
* Uses sun.net.ftp.FtpCLient.
*/
public class DefaultFtpClientProvider extends sun.net.ftp.FtpClientProvider {
@Override
public sun.net.ftp.FtpClient createFtpClient() {
return sun.net.ftp.impl.FtpClient.create();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import com.sun.net.httpserver.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import sun.net.www.MessageHeader;
import java.util.*;
import javax.security.auth.*;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
public class AuthFilter extends Filter {
private Authenticator authenticator;
public AuthFilter (Authenticator authenticator) {
this.authenticator = authenticator;
}
public String description () {
return "Authentication filter";
}
public void setAuthenticator (Authenticator a) {
authenticator = a;
}
public void consumeInput (HttpExchange t) throws IOException {
InputStream i = t.getRequestBody();
byte[] b = new byte [4096];
while (i.read (b) != -1);
i.close ();
}
/**
* The filter's implementation, which is invoked by the server
*/
public void doFilter (HttpExchange t, Filter.Chain chain) throws IOException
{
if (authenticator != null) {
Authenticator.Result r = authenticator.authenticate (t);
if (r instanceof Authenticator.Success) {
Authenticator.Success s = (Authenticator.Success)r;
ExchangeImpl e = ExchangeImpl.get (t);
e.setPrincipal (s.getPrincipal());
chain.doFilter (t);
} else if (r instanceof Authenticator.Retry) {
Authenticator.Retry ry = (Authenticator.Retry)r;
consumeInput (t);
t.sendResponseHeaders (ry.getResponseCode(), -1);
} else if (r instanceof Authenticator.Failure) {
Authenticator.Failure f = (Authenticator.Failure)r;
consumeInput (t);
t.sendResponseHeaders (f.getResponseCode(), -1);
}
} else {
chain.doFilter (t);
}
}
}

View File

@@ -0,0 +1,186 @@
/*
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.io.*;
import java.net.*;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
class ChunkedInputStream extends LeftOverInputStream {
ChunkedInputStream (ExchangeImpl t, InputStream src) {
super (t, src);
}
private int remaining;
/* true when a chunk header needs to be read */
private boolean needToReadHeader = true;
final static char CR = '\r';
final static char LF = '\n';
/*
* Maximum chunk header size of 2KB + 2 bytes for CRLF
*/
private final static int MAX_CHUNK_HEADER_SIZE = 2050;
private int numeric (char[] arr, int nchars) throws IOException {
assert arr.length >= nchars;
int len = 0;
for (int i=0; i<nchars; i++) {
char c = arr[i];
int val=0;
if (c>='0' && c <='9') {
val = c - '0';
} else if (c>='a' && c<= 'f') {
val = c - 'a' + 10;
} else if (c>='A' && c<= 'F') {
val = c - 'A' + 10;
} else {
throw new IOException ("invalid chunk length");
}
len = len * 16 + val;
}
return len;
}
/* read the chunk header line and return the chunk length
* any chunk extensions are ignored
*/
private int readChunkHeader () throws IOException {
boolean gotCR = false;
int c;
char[] len_arr = new char [16];
int len_size = 0;
boolean end_of_len = false;
int read = 0;
while ((c=in.read())!= -1) {
char ch = (char) c;
read++;
if ((len_size == len_arr.length -1) ||
(read > MAX_CHUNK_HEADER_SIZE))
{
throw new IOException ("invalid chunk header");
}
if (gotCR) {
if (ch == LF) {
int l = numeric (len_arr, len_size);
return l;
} else {
gotCR = false;
}
if (!end_of_len) {
len_arr[len_size++] = ch;
}
} else {
if (ch == CR) {
gotCR = true;
} else if (ch == ';') {
end_of_len = true;
} else if (!end_of_len) {
len_arr[len_size++] = ch;
}
}
}
throw new IOException ("end of stream reading chunk header");
}
protected int readImpl (byte[]b, int off, int len) throws IOException {
if (eof) {
return -1;
}
if (needToReadHeader) {
remaining = readChunkHeader();
if (remaining == 0) {
eof = true;
consumeCRLF();
t.getServerImpl().requestCompleted (t.getConnection());
return -1;
}
needToReadHeader = false;
}
if (len > remaining) {
len = remaining;
}
int n = in.read(b, off, len);
if (n > -1) {
remaining -= n;
}
if (remaining == 0) {
needToReadHeader = true;
consumeCRLF();
}
if (n < 0 && !eof)
throw new IOException("connection closed before all data received");
return n;
}
private void consumeCRLF () throws IOException {
char c;
c = (char)in.read(); /* CR */
if (c != CR) {
throw new IOException ("invalid chunk end");
}
c = (char)in.read(); /* LF */
if (c != LF) {
throw new IOException ("invalid chunk end");
}
}
/**
* returns the number of bytes available to read in the current chunk
* which may be less than the real amount, but we'll live with that
* limitation for the moment. It only affects potential efficiency
* rather than correctness.
*/
public int available () throws IOException {
if (eof || closed) {
return 0;
}
int n = in.available();
return n > remaining? remaining: n;
}
/* called after the stream is closed to see if bytes
* have been read from the underlying channel
* and buffered internally
*/
public boolean isDataBuffered () throws IOException {
assert eof;
return in.available() > 0;
}
public boolean markSupported () {return false;}
public void mark (int l) {
}
public void reset () throws IOException {
throw new IOException ("mark/reset not supported");
}
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.io.*;
import java.net.*;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
/**
* a class which allows the caller to write an arbitrary
* number of bytes to an underlying stream.
* normal close() does not close the underlying stream
*
* This class is buffered.
*
* Each chunk is written in one go as :-
* abcd\r\nxxxxxxxxxxxxxx\r\n
*
* abcd is the chunk-size, and xxx is the chunk data
* If the length is less than 4 chars (in size) then the buffer
* is written with an offset.
* Final chunk is:
* 0\r\n\r\n
*/
class ChunkedOutputStream extends FilterOutputStream
{
private boolean closed = false;
/* max. amount of user data per chunk */
final static int CHUNK_SIZE = 4096;
/* allow 4 bytes for chunk-size plus 4 for CRLFs */
final static int OFFSET = 6; /* initial <=4 bytes for len + CRLF */
private int pos = OFFSET;
private int count = 0;
private byte[] buf = new byte [CHUNK_SIZE+OFFSET+2];
ExchangeImpl t;
ChunkedOutputStream (ExchangeImpl t, OutputStream src) {
super (src);
this.t = t;
}
public void write (int b) throws IOException {
if (closed) {
throw new StreamClosedException ();
}
buf [pos++] = (byte)b;
count ++;
if (count == CHUNK_SIZE) {
writeChunk();
}
assert count < CHUNK_SIZE;
}
public void write (byte[]b, int off, int len) throws IOException {
if (closed) {
throw new StreamClosedException ();
}
int remain = CHUNK_SIZE - count;
if (len > remain) {
System.arraycopy (b,off,buf,pos,remain);
count = CHUNK_SIZE;
writeChunk();
len -= remain;
off += remain;
while (len >= CHUNK_SIZE) {
System.arraycopy (b,off,buf,OFFSET,CHUNK_SIZE);
len -= CHUNK_SIZE;
off += CHUNK_SIZE;
count = CHUNK_SIZE;
writeChunk();
}
}
if (len > 0) {
System.arraycopy (b,off,buf,pos,len);
count += len;
pos += len;
}
if (count == CHUNK_SIZE) {
writeChunk();
}
}
/**
* write out a chunk , and reset the pointers
* chunk does not have to be CHUNK_SIZE bytes
* count must == number of user bytes (<= CHUNK_SIZE)
*/
private void writeChunk () throws IOException {
char[] c = Integer.toHexString (count).toCharArray();
int clen = c.length;
int startByte = 4 - clen;
int i;
for (i=0; i<clen; i++) {
buf[startByte+i] = (byte)c[i];
}
buf[startByte + (i++)] = '\r';
buf[startByte + (i++)] = '\n';
buf[startByte + (i++) + count] = '\r';
buf[startByte + (i++) + count] = '\n';
out.write (buf, startByte, i+count);
count = 0;
pos = OFFSET;
}
public void close () throws IOException {
if (closed) {
return;
}
flush();
try {
/* write an empty chunk */
writeChunk();
out.flush();
LeftOverInputStream is = t.getOriginalInputStream();
if (!is.isClosed()) {
is.close();
}
/* some clients close the connection before empty chunk is sent */
} catch (IOException e) {
} finally {
closed = true;
}
WriteFinishedEvent e = new WriteFinishedEvent (t);
t.getHttpContext().getServerImpl().addEvent (e);
}
public void flush () throws IOException {
if (closed) {
throw new StreamClosedException ();
}
if (count > 0) {
writeChunk();
}
out.flush();
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
class Code {
public static final int HTTP_CONTINUE = 100;
public static final int HTTP_OK = 200;
public static final int HTTP_CREATED = 201;
public static final int HTTP_ACCEPTED = 202;
public static final int HTTP_NOT_AUTHORITATIVE = 203;
public static final int HTTP_NO_CONTENT = 204;
public static final int HTTP_RESET = 205;
public static final int HTTP_PARTIAL = 206;
public static final int HTTP_MULT_CHOICE = 300;
public static final int HTTP_MOVED_PERM = 301;
public static final int HTTP_MOVED_TEMP = 302;
public static final int HTTP_SEE_OTHER = 303;
public static final int HTTP_NOT_MODIFIED = 304;
public static final int HTTP_USE_PROXY = 305;
public static final int HTTP_BAD_REQUEST = 400;
public static final int HTTP_UNAUTHORIZED = 401;
public static final int HTTP_PAYMENT_REQUIRED = 402;
public static final int HTTP_FORBIDDEN = 403;
public static final int HTTP_NOT_FOUND = 404;
public static final int HTTP_BAD_METHOD = 405;
public static final int HTTP_NOT_ACCEPTABLE = 406;
public static final int HTTP_PROXY_AUTH = 407;
public static final int HTTP_CLIENT_TIMEOUT = 408;
public static final int HTTP_CONFLICT = 409;
public static final int HTTP_GONE = 410;
public static final int HTTP_LENGTH_REQUIRED = 411;
public static final int HTTP_PRECON_FAILED = 412;
public static final int HTTP_ENTITY_TOO_LARGE = 413;
public static final int HTTP_REQ_TOO_LONG = 414;
public static final int HTTP_UNSUPPORTED_TYPE = 415;
public static final int HTTP_INTERNAL_ERROR = 500;
public static final int HTTP_NOT_IMPLEMENTED = 501;
public static final int HTTP_BAD_GATEWAY = 502;
public static final int HTTP_UNAVAILABLE = 503;
public static final int HTTP_GATEWAY_TIMEOUT = 504;
public static final int HTTP_VERSION = 505;
static String msg (int code) {
switch (code) {
case HTTP_OK: return " OK";
case HTTP_CONTINUE: return " Continue";
case HTTP_CREATED: return " Created";
case HTTP_ACCEPTED: return " Accepted";
case HTTP_NOT_AUTHORITATIVE: return " Non-Authoritative Information";
case HTTP_NO_CONTENT: return " No Content";
case HTTP_RESET: return " Reset Content";
case HTTP_PARTIAL: return " Partial Content";
case HTTP_MULT_CHOICE: return " Multiple Choices";
case HTTP_MOVED_PERM: return " Moved Permanently";
case HTTP_MOVED_TEMP: return " Temporary Redirect";
case HTTP_SEE_OTHER: return " See Other";
case HTTP_NOT_MODIFIED: return " Not Modified";
case HTTP_USE_PROXY: return " Use Proxy";
case HTTP_BAD_REQUEST: return " Bad Request";
case HTTP_UNAUTHORIZED: return " Unauthorized" ;
case HTTP_PAYMENT_REQUIRED: return " Payment Required";
case HTTP_FORBIDDEN: return " Forbidden";
case HTTP_NOT_FOUND: return " Not Found";
case HTTP_BAD_METHOD: return " Method Not Allowed";
case HTTP_NOT_ACCEPTABLE: return " Not Acceptable";
case HTTP_PROXY_AUTH: return " Proxy Authentication Required";
case HTTP_CLIENT_TIMEOUT: return " Request Time-Out";
case HTTP_CONFLICT: return " Conflict";
case HTTP_GONE: return " Gone";
case HTTP_LENGTH_REQUIRED: return " Length Required";
case HTTP_PRECON_FAILED: return " Precondition Failed";
case HTTP_ENTITY_TOO_LARGE: return " Request Entity Too Large";
case HTTP_REQ_TOO_LONG: return " Request-URI Too Large";
case HTTP_UNSUPPORTED_TYPE: return " Unsupported Media Type";
case HTTP_INTERNAL_ERROR: return " Internal Server Error";
case HTTP_NOT_IMPLEMENTED: return " Not Implemented";
case HTTP_BAD_GATEWAY: return " Bad Gateway";
case HTTP_UNAVAILABLE: return " Service Unavailable";
case HTTP_GATEWAY_TIMEOUT: return " Gateway Timeout";
case HTTP_VERSION: return " HTTP Version Not Supported";
default: return " ";
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.util.*;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
class ContextList {
final static int MAX_CONTEXTS = 50;
LinkedList<HttpContextImpl> list = new LinkedList<HttpContextImpl>();
public synchronized void add (HttpContextImpl ctx) {
assert ctx.getPath() != null;
list.add (ctx);
}
public synchronized int size () {
return list.size();
}
/* initially contexts are located only by protocol:path.
* Context with longest prefix matches (currently case-sensitive)
*/
synchronized HttpContextImpl findContext (String protocol, String path) {
return findContext (protocol, path, false);
}
synchronized HttpContextImpl findContext (String protocol, String path, boolean exact) {
protocol = protocol.toLowerCase();
String longest = "";
HttpContextImpl lc = null;
for (HttpContextImpl ctx: list) {
if (!ctx.getProtocol().equals(protocol)) {
continue;
}
String cpath = ctx.getPath();
if (exact && !cpath.equals (path)) {
continue;
} else if (!exact && !path.startsWith(cpath)) {
continue;
}
if (cpath.length() > longest.length()) {
longest = cpath;
lc = ctx;
}
}
return lc;
}
public synchronized void remove (String protocol, String path)
throws IllegalArgumentException
{
HttpContextImpl ctx = findContext (protocol, path, true);
if (ctx == null) {
throw new IllegalArgumentException ("cannot remove element from list");
}
list.remove (ctx);
}
public synchronized void remove (HttpContextImpl context)
throws IllegalArgumentException
{
for (HttpContextImpl ctx: list) {
if (ctx.equals (context)) {
list.remove (ctx);
return;
}
}
throw new IllegalArgumentException ("no such context in list");
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.net.*;
import java.io.*;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
public class DefaultHttpServerProvider extends HttpServerProvider {
public HttpServer createHttpServer (InetSocketAddress addr, int backlog) throws IOException {
return new HttpServerImpl (addr, backlog);
}
public HttpsServer createHttpsServer (InetSocketAddress addr, int backlog) throws IOException {
return new HttpsServerImpl (addr, backlog);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
class Event {
ExchangeImpl exchange;
protected Event (ExchangeImpl t) {
this.exchange = t;
}
}

View File

@@ -0,0 +1,456 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
import java.util.*;
import java.util.logging.Logger;
import java.text.*;
import com.sun.net.httpserver.*;
class ExchangeImpl {
Headers reqHdrs, rspHdrs;
Request req;
String method;
boolean writefinished;
URI uri;
HttpConnection connection;
long reqContentLen;
long rspContentLen;
/* raw streams which access the socket directly */
InputStream ris;
OutputStream ros;
Thread thread;
/* close the underlying connection when this exchange finished */
boolean close;
boolean closed;
boolean http10 = false;
/* for formatting the Date: header */
private static final String pattern = "EEE, dd MMM yyyy HH:mm:ss zzz";
private static final TimeZone gmtTZ = TimeZone.getTimeZone("GMT");
private static final ThreadLocal<DateFormat> dateFormat =
new ThreadLocal<DateFormat>() {
@Override protected DateFormat initialValue() {
DateFormat df = new SimpleDateFormat(pattern, Locale.US);
df.setTimeZone(gmtTZ);
return df;
}
};
private static final String HEAD = "HEAD";
/* streams which take care of the HTTP protocol framing
* and are passed up to higher layers
*/
InputStream uis;
OutputStream uos;
LeftOverInputStream uis_orig; // uis may have be a user supplied wrapper
PlaceholderOutputStream uos_orig;
boolean sentHeaders; /* true after response headers sent */
Map<String,Object> attributes;
int rcode = -1;
HttpPrincipal principal;
ServerImpl server;
ExchangeImpl (
String m, URI u, Request req, long len, HttpConnection connection
) throws IOException {
this.req = req;
this.reqHdrs = req.headers();
this.rspHdrs = new Headers();
this.method = m;
this.uri = u;
this.connection = connection;
this.reqContentLen = len;
/* ros only used for headers, body written directly to stream */
this.ros = req.outputStream();
this.ris = req.inputStream();
server = getServerImpl();
server.startExchange();
}
public Headers getRequestHeaders () {
return new UnmodifiableHeaders (reqHdrs);
}
public Headers getResponseHeaders () {
return rspHdrs;
}
public URI getRequestURI () {
return uri;
}
public String getRequestMethod (){
return method;
}
public HttpContextImpl getHttpContext (){
return connection.getHttpContext();
}
private boolean isHeadRequest() {
return HEAD.equals(getRequestMethod());
}
public void close () {
if (closed) {
return;
}
closed = true;
/* close the underlying connection if,
* a) the streams not set up yet, no response can be sent, or
* b) if the wrapper output stream is not set up, or
* c) if the close of the input/outpu stream fails
*/
try {
if (uis_orig == null || uos == null) {
connection.close();
return;
}
if (!uos_orig.isWrapped()) {
connection.close();
return;
}
if (!uis_orig.isClosed()) {
uis_orig.close();
}
uos.close();
} catch (IOException e) {
connection.close();
}
}
public InputStream getRequestBody () {
if (uis != null) {
return uis;
}
if (reqContentLen == -1L) {
uis_orig = new ChunkedInputStream (this, ris);
uis = uis_orig;
} else {
uis_orig = new FixedLengthInputStream (this, ris, reqContentLen);
uis = uis_orig;
}
return uis;
}
LeftOverInputStream getOriginalInputStream () {
return uis_orig;
}
public int getResponseCode () {
return rcode;
}
public OutputStream getResponseBody () {
/* TODO. Change spec to remove restriction below. Filters
* cannot work with this restriction
*
* if (!sentHeaders) {
* throw new IllegalStateException ("headers not sent");
* }
*/
if (uos == null) {
uos_orig = new PlaceholderOutputStream (null);
uos = uos_orig;
}
return uos;
}
/* returns the place holder stream, which is the stream
* returned from the 1st call to getResponseBody()
* The "real" ouputstream is then placed inside this
*/
PlaceholderOutputStream getPlaceholderResponseBody () {
getResponseBody();
return uos_orig;
}
public void sendResponseHeaders (int rCode, long contentLen)
throws IOException
{
if (sentHeaders) {
throw new IOException ("headers already sent");
}
this.rcode = rCode;
String statusLine = "HTTP/1.1 "+rCode+Code.msg(rCode)+"\r\n";
OutputStream tmpout = new BufferedOutputStream (ros);
PlaceholderOutputStream o = getPlaceholderResponseBody();
tmpout.write (bytes(statusLine, 0), 0, statusLine.length());
boolean noContentToSend = false; // assume there is content
rspHdrs.set ("Date", dateFormat.get().format (new Date()));
/* check for response type that is not allowed to send a body */
if ((rCode>=100 && rCode <200) /* informational */
||(rCode == 204) /* no content */
||(rCode == 304)) /* not modified */
{
if (contentLen != -1) {
Logger logger = server.getLogger();
String msg = "sendResponseHeaders: rCode = "+ rCode
+ ": forcing contentLen = -1";
logger.warning (msg);
}
contentLen = -1;
}
if (isHeadRequest()) {
/* HEAD requests should not set a content length by passing it
* through this API, but should instead manually set the required
* headers.*/
if (contentLen >= 0) {
final Logger logger = server.getLogger();
String msg =
"sendResponseHeaders: being invoked with a content length for a HEAD request";
logger.warning (msg);
}
noContentToSend = true;
contentLen = 0;
} else { /* not a HEAD request */
if (contentLen == 0) {
if (http10) {
o.setWrappedStream (new UndefLengthOutputStream (this, ros));
close = true;
} else {
rspHdrs.set ("Transfer-encoding", "chunked");
o.setWrappedStream (new ChunkedOutputStream (this, ros));
}
} else {
if (contentLen == -1) {
noContentToSend = true;
contentLen = 0;
}
rspHdrs.set("Content-length", Long.toString(contentLen));
o.setWrappedStream (new FixedLengthOutputStream (this, ros, contentLen));
}
}
write (rspHdrs, tmpout);
this.rspContentLen = contentLen;
tmpout.flush() ;
tmpout = null;
sentHeaders = true;
if (noContentToSend) {
WriteFinishedEvent e = new WriteFinishedEvent (this);
server.addEvent (e);
closed = true;
}
server.logReply (rCode, req.requestLine(), null);
}
void write (Headers map, OutputStream os) throws IOException {
Set<Map.Entry<String,List<String>>> entries = map.entrySet();
for (Map.Entry<String,List<String>> entry : entries) {
String key = entry.getKey();
byte[] buf;
List<String> values = entry.getValue();
for (String val : values) {
int i = key.length();
buf = bytes (key, 2);
buf[i++] = ':';
buf[i++] = ' ';
os.write (buf, 0, i);
buf = bytes (val, 2);
i = val.length();
buf[i++] = '\r';
buf[i++] = '\n';
os.write (buf, 0, i);
}
}
os.write ('\r');
os.write ('\n');
}
private byte[] rspbuf = new byte [128]; // used by bytes()
/**
* convert string to byte[], using rspbuf
* Make sure that at least "extra" bytes are free at end
* of rspbuf. Reallocate rspbuf if not big enough.
* caller must check return value to see if rspbuf moved
*/
private byte[] bytes (String s, int extra) {
int slen = s.length();
if (slen+extra > rspbuf.length) {
int diff = slen + extra - rspbuf.length;
rspbuf = new byte [2* (rspbuf.length + diff)];
}
char c[] = s.toCharArray();
for (int i=0; i<c.length; i++) {
rspbuf[i] = (byte)c[i];
}
return rspbuf;
}
public InetSocketAddress getRemoteAddress (){
Socket s = connection.getChannel().socket();
InetAddress ia = s.getInetAddress();
int port = s.getPort();
return new InetSocketAddress (ia, port);
}
public InetSocketAddress getLocalAddress (){
Socket s = connection.getChannel().socket();
InetAddress ia = s.getLocalAddress();
int port = s.getLocalPort();
return new InetSocketAddress (ia, port);
}
public String getProtocol (){
String reqline = req.requestLine();
int index = reqline.lastIndexOf (' ');
return reqline.substring (index+1);
}
public SSLSession getSSLSession () {
SSLEngine e = connection.getSSLEngine();
if (e == null) {
return null;
}
return e.getSession();
}
public Object getAttribute (String name) {
if (name == null) {
throw new NullPointerException ("null name parameter");
}
if (attributes == null) {
attributes = getHttpContext().getAttributes();
}
return attributes.get (name);
}
public void setAttribute (String name, Object value) {
if (name == null) {
throw new NullPointerException ("null name parameter");
}
if (attributes == null) {
attributes = getHttpContext().getAttributes();
}
attributes.put (name, value);
}
public void setStreams (InputStream i, OutputStream o) {
assert uis != null;
if (i != null) {
uis = i;
}
if (o != null) {
uos = o;
}
}
/**
* PP
*/
HttpConnection getConnection () {
return connection;
}
ServerImpl getServerImpl () {
return getHttpContext().getServerImpl();
}
public HttpPrincipal getPrincipal () {
return principal;
}
void setPrincipal (HttpPrincipal principal) {
this.principal = principal;
}
static ExchangeImpl get (HttpExchange t) {
if (t instanceof HttpExchangeImpl) {
return ((HttpExchangeImpl)t).getExchangeImpl();
} else {
assert t instanceof HttpsExchangeImpl;
return ((HttpsExchangeImpl)t).getExchangeImpl();
}
}
}
/**
* An OutputStream which wraps another stream
* which is supplied either at creation time, or sometime later.
* If a caller/user tries to write to this stream before
* the wrapped stream has been provided, then an IOException will
* be thrown.
*/
class PlaceholderOutputStream extends java.io.OutputStream {
OutputStream wrapped;
PlaceholderOutputStream (OutputStream os) {
wrapped = os;
}
void setWrappedStream (OutputStream os) {
wrapped = os;
}
boolean isWrapped () {
return wrapped != null;
}
private void checkWrap () throws IOException {
if (wrapped == null) {
throw new IOException ("response headers not sent yet");
}
}
public void write(int b) throws IOException {
checkWrap();
wrapped.write (b);
}
public void write(byte b[]) throws IOException {
checkWrap();
wrapped.write (b);
}
public void write(byte b[], int off, int len) throws IOException {
checkWrap();
wrapped.write (b, off, len);
}
public void flush() throws IOException {
checkWrap();
wrapped.flush();
}
public void close() throws IOException {
checkWrap();
wrapped.close();
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.io.*;
import java.net.*;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
/**
* a class which allows the caller to read up to a defined
* number of bytes off an underlying stream
* close() does not close the underlying stream
*/
class FixedLengthInputStream extends LeftOverInputStream {
private long remaining;
FixedLengthInputStream (ExchangeImpl t, InputStream src, long len) {
super (t, src);
if (len < 0) {
throw new IllegalArgumentException("Content-Length: " + len);
}
this.remaining = len;
}
protected int readImpl (byte[]b, int off, int len) throws IOException {
eof = (remaining == 0L);
if (eof) {
return -1;
}
if (len > remaining) {
len = (int)remaining;
}
int n = in.read(b, off, len);
if (n > -1) {
remaining -= n;
if (remaining == 0) {
t.getServerImpl().requestCompleted (t.getConnection());
}
}
if (n < 0 && !eof)
throw new IOException("connection closed before all data received");
return n;
}
public int available () throws IOException {
if (eof) {
return 0;
}
int n = in.available();
return n < remaining? n: (int)remaining;
}
public boolean markSupported () {return false;}
public void mark (int l) {
}
public void reset () throws IOException {
throw new IOException ("mark/reset not supported");
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.io.*;
import java.net.*;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
/**
* a class which allows the caller to write up to a defined
* number of bytes to an underlying stream. The caller *must*
* write the pre-defined number or else an exception will be thrown
* and the whole request aborted.
* normal close() does not close the underlying stream
*/
class FixedLengthOutputStream extends FilterOutputStream
{
private long remaining;
private boolean eof = false;
private boolean closed = false;
ExchangeImpl t;
FixedLengthOutputStream (ExchangeImpl t, OutputStream src, long len) {
super (src);
if (len < 0) {
throw new IllegalArgumentException("Content-Length: " + len);
}
this.t = t;
this.remaining = len;
}
public void write (int b) throws IOException {
if (closed) {
throw new IOException ("stream closed");
}
eof = (remaining == 0);
if (eof) {
throw new StreamClosedException();
}
out.write(b);
remaining --;
}
public void write (byte[]b, int off, int len) throws IOException {
if (closed) {
throw new IOException ("stream closed");
}
eof = (remaining == 0);
if (eof) {
throw new StreamClosedException();
}
if (len > remaining) {
// stream is still open, caller can retry
throw new IOException ("too many bytes to write to stream");
}
out.write(b, off, len);
remaining -= len;
}
public void close () throws IOException {
if (closed) {
return;
}
closed = true;
if (remaining > 0) {
t.close();
throw new IOException ("insufficient bytes written to stream");
}
flush();
eof = true;
LeftOverInputStream is = t.getOriginalInputStream();
if (!is.isClosed()) {
try {
is.close();
} catch (IOException e) {}
}
WriteFinishedEvent e = new WriteFinishedEvent (t);
t.getHttpContext().getServerImpl().addEvent (e);
}
// flush is a pass-through
}

View File

@@ -0,0 +1,194 @@
/*
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.io.*;
import javax.net.ssl.*;
import java.nio.channels.*;
import java.util.logging.Logger;
/**
* encapsulates all the connection specific state for a HTTP/S connection
* one of these is hung from the selector attachment and is used to locate
* everything from that.
*/
class HttpConnection {
HttpContextImpl context;
SSLEngine engine;
SSLContext sslContext;
SSLStreams sslStreams;
/* high level streams returned to application */
InputStream i;
/* low level stream that sits directly over channel */
InputStream raw;
OutputStream rawout;
SocketChannel chan;
SelectionKey selectionKey;
String protocol;
long idleStartTime; // absolute time in milli seconds, starting when the connection was marked idle
volatile long reqStartedTime; // time when the request was initiated
volatile long rspStartedTime; // time we started writing the response
int remaining;
boolean closed = false;
Logger logger;
public enum State {IDLE, REQUEST, RESPONSE, NEWLY_ACCEPTED};
volatile State state;
public String toString() {
String s = null;
if (chan != null) {
s = chan.toString();
}
return s;
}
HttpConnection () {
}
void setChannel (SocketChannel c) {
chan = c;
}
void setContext (HttpContextImpl ctx) {
context = ctx;
}
State getState() {
return state;
}
void setState (State s) {
state = s;
}
void setParameters (
InputStream in, OutputStream rawout, SocketChannel chan,
SSLEngine engine, SSLStreams sslStreams, SSLContext sslContext, String protocol,
HttpContextImpl context, InputStream raw
)
{
this.context = context;
this.i = in;
this.rawout = rawout;
this.raw = raw;
this.protocol = protocol;
this.engine = engine;
this.chan = chan;
this.sslContext = sslContext;
this.sslStreams = sslStreams;
this.logger = context.getLogger();
}
SocketChannel getChannel () {
return chan;
}
synchronized void close () {
if (closed) {
return;
}
closed = true;
if (logger != null && chan != null) {
logger.finest ("Closing connection: " + chan.toString());
}
if (!chan.isOpen()) {
ServerImpl.dprint ("Channel already closed");
return;
}
try {
/* need to ensure temporary selectors are closed */
if (raw != null) {
raw.close();
}
} catch (IOException e) {
ServerImpl.dprint (e);
}
try {
if (rawout != null) {
rawout.close();
}
} catch (IOException e) {
ServerImpl.dprint (e);
}
try {
if (sslStreams != null) {
sslStreams.close();
}
} catch (IOException e) {
ServerImpl.dprint (e);
}
try {
chan.close();
} catch (IOException e) {
ServerImpl.dprint (e);
}
}
/* remaining is the number of bytes left on the lowest level inputstream
* after the exchange is finished
*/
void setRemaining (int r) {
remaining = r;
}
int getRemaining () {
return remaining;
}
SelectionKey getSelectionKey () {
return selectionKey;
}
InputStream getInputStream () {
return i;
}
OutputStream getRawOutputStream () {
return rawout;
}
String getProtocol () {
return protocol;
}
SSLEngine getSSLEngine () {
return engine;
}
SSLContext getSSLContext () {
return sslContext;
}
HttpContextImpl getHttpContext () {
return context;
}
}

View File

@@ -0,0 +1,152 @@
/*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.io.*;
import java.util.*;
import java.util.logging.Logger;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
/**
* HttpContext represents a mapping between a protocol (http or https) together with a root URI path
* to a {@link HttpHandler} which is invoked to handle requests destined
* for the protocol/path on the associated HttpServer.
* <p>
* HttpContext instances are created by {@link HttpServer#createContext(String,String,HttpHandler,Object)}
* <p>
*/
class HttpContextImpl extends HttpContext {
private String path;
private String protocol;
private HttpHandler handler;
private Map<String,Object> attributes = new HashMap<String,Object>();
private ServerImpl server;
/* system filters, not visible to applications */
private LinkedList<Filter> sfilters = new LinkedList<Filter>();
/* user filters, set by applications */
private LinkedList<Filter> ufilters = new LinkedList<Filter>();
private Authenticator authenticator;
private AuthFilter authfilter;
/**
* constructor is package private.
*/
HttpContextImpl (String protocol, String path, HttpHandler cb, ServerImpl server) {
if (path == null || protocol == null || path.length() < 1 || path.charAt(0) != '/') {
throw new IllegalArgumentException ("Illegal value for path or protocol");
}
this.protocol = protocol.toLowerCase();
this.path = path;
if (!this.protocol.equals ("http") && !this.protocol.equals ("https")) {
throw new IllegalArgumentException ("Illegal value for protocol");
}
this.handler = cb;
this.server = server;
authfilter = new AuthFilter(null);
sfilters.add (authfilter);
}
/**
* returns the handler for this context
* @return the HttpHandler for this context
*/
public HttpHandler getHandler () {
return handler;
}
public void setHandler (HttpHandler h) {
if (h == null) {
throw new NullPointerException ("Null handler parameter");
}
if (handler != null) {
throw new IllegalArgumentException ("handler already set");
}
handler = h;
}
/**
* returns the path this context was created with
* @return this context's path
*/
public String getPath() {
return path;
}
/**
* returns the server this context was created with
* @return this context's server
*/
public HttpServer getServer () {
return server.getWrapper();
}
ServerImpl getServerImpl () {
return server;
}
/**
* returns the protocol this context was created with
* @return this context's path
*/
public String getProtocol() {
return protocol;
}
/**
* returns a mutable Map, which can be used to pass
* configuration and other data to Filter modules
* and to the context's exchange handler.
* <p>
* Every attribute stored in this Map will be visible to
* every HttpExchange processed by this context
*/
public Map<String,Object> getAttributes() {
return attributes;
}
public List<Filter> getFilters () {
return ufilters;
}
List<Filter> getSystemFilters () {
return sfilters;
}
public Authenticator setAuthenticator (Authenticator auth) {
Authenticator old = authenticator;
authenticator = auth;
authfilter.setAuthenticator (auth);
return old;
}
public Authenticator getAuthenticator () {
return authenticator;
}
Logger getLogger () {
return server.getLogger();
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
/**
* A Http error
*/
class HttpError extends RuntimeException {
private static final long serialVersionUID = 8769596371344178179L;
public HttpError (String msg) {
super (msg);
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import javax.net.ssl.*;
import java.util.*;
import sun.net.www.MessageHeader;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
class HttpExchangeImpl extends HttpExchange {
ExchangeImpl impl;
HttpExchangeImpl (ExchangeImpl impl) {
this.impl = impl;
}
public Headers getRequestHeaders () {
return impl.getRequestHeaders();
}
public Headers getResponseHeaders () {
return impl.getResponseHeaders();
}
public URI getRequestURI () {
return impl.getRequestURI();
}
public String getRequestMethod (){
return impl.getRequestMethod();
}
public HttpContextImpl getHttpContext (){
return impl.getHttpContext();
}
public void close () {
impl.close();
}
public InputStream getRequestBody () {
return impl.getRequestBody();
}
public int getResponseCode () {
return impl.getResponseCode();
}
public OutputStream getResponseBody () {
return impl.getResponseBody();
}
public void sendResponseHeaders (int rCode, long contentLen)
throws IOException
{
impl.sendResponseHeaders (rCode, contentLen);
}
public InetSocketAddress getRemoteAddress (){
return impl.getRemoteAddress();
}
public InetSocketAddress getLocalAddress (){
return impl.getLocalAddress();
}
public String getProtocol (){
return impl.getProtocol();
}
public Object getAttribute (String name) {
return impl.getAttribute (name);
}
public void setAttribute (String name, Object value) {
impl.setAttribute (name, value);
}
public void setStreams (InputStream i, OutputStream o) {
impl.setStreams (i, o);
}
public HttpPrincipal getPrincipal () {
return impl.getPrincipal();
}
ExchangeImpl getExchangeImpl () {
return impl;
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.net.*;
import java.io.*;
import java.nio.*;
import java.security.*;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
import javax.net.ssl.*;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
public class HttpServerImpl extends HttpServer {
ServerImpl server;
HttpServerImpl () throws IOException {
this (new InetSocketAddress(80), 0);
}
HttpServerImpl (
InetSocketAddress addr, int backlog
) throws IOException {
server = new ServerImpl (this, "http", addr, backlog);
}
public void bind (InetSocketAddress addr, int backlog) throws IOException {
server.bind (addr, backlog);
}
public void start () {
server.start();
}
public void setExecutor (Executor executor) {
server.setExecutor(executor);
}
public Executor getExecutor () {
return server.getExecutor();
}
public void stop (int delay) {
server.stop (delay);
}
public HttpContextImpl createContext (String path, HttpHandler handler) {
return server.createContext (path, handler);
}
public HttpContextImpl createContext (String path) {
return server.createContext (path);
}
public void removeContext (String path) throws IllegalArgumentException {
server.removeContext (path);
}
public void removeContext (HttpContext context) throws IllegalArgumentException {
server.removeContext (context);
}
public InetSocketAddress getAddress() {
return server.getAddress();
}
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import javax.net.ssl.*;
import java.util.*;
import sun.net.www.MessageHeader;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
class HttpsExchangeImpl extends HttpsExchange {
ExchangeImpl impl;
HttpsExchangeImpl (ExchangeImpl impl) throws IOException {
this.impl = impl;
}
public Headers getRequestHeaders () {
return impl.getRequestHeaders();
}
public Headers getResponseHeaders () {
return impl.getResponseHeaders();
}
public URI getRequestURI () {
return impl.getRequestURI();
}
public String getRequestMethod (){
return impl.getRequestMethod();
}
public HttpContextImpl getHttpContext (){
return impl.getHttpContext();
}
public void close () {
impl.close();
}
public InputStream getRequestBody () {
return impl.getRequestBody();
}
public int getResponseCode () {
return impl.getResponseCode();
}
public OutputStream getResponseBody () {
return impl.getResponseBody();
}
public void sendResponseHeaders (int rCode, long contentLen)
throws IOException
{
impl.sendResponseHeaders (rCode, contentLen);
}
public InetSocketAddress getRemoteAddress (){
return impl.getRemoteAddress();
}
public InetSocketAddress getLocalAddress (){
return impl.getLocalAddress();
}
public String getProtocol (){
return impl.getProtocol();
}
public SSLSession getSSLSession () {
return impl.getSSLSession ();
}
public Object getAttribute (String name) {
return impl.getAttribute (name);
}
public void setAttribute (String name, Object value) {
impl.setAttribute (name, value);
}
public void setStreams (InputStream i, OutputStream o) {
impl.setStreams (i, o);
}
public HttpPrincipal getPrincipal () {
return impl.getPrincipal();
}
ExchangeImpl getExchangeImpl () {
return impl;
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.net.*;
import java.io.*;
import java.nio.*;
import java.security.*;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
import javax.net.ssl.*;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
public class HttpsServerImpl extends HttpsServer {
ServerImpl server;
HttpsServerImpl () throws IOException {
this (new InetSocketAddress(443), 0);
}
HttpsServerImpl (
InetSocketAddress addr, int backlog
) throws IOException {
server = new ServerImpl (this, "https", addr, backlog);
}
public void setHttpsConfigurator (HttpsConfigurator config) {
server.setHttpsConfigurator (config);
}
public HttpsConfigurator getHttpsConfigurator () {
return server.getHttpsConfigurator();
}
public void bind (InetSocketAddress addr, int backlog) throws IOException {
server.bind (addr, backlog);
}
public void start () {
server.start();
}
public void setExecutor (Executor executor) {
server.setExecutor(executor);
}
public Executor getExecutor () {
return server.getExecutor();
}
public void stop (int delay) {
server.stop (delay);
}
public HttpContextImpl createContext (String path, HttpHandler handler) {
return server.createContext (path, handler);
}
public HttpContextImpl createContext (String path) {
return server.createContext (path);
}
public void removeContext (String path) throws IllegalArgumentException {
server.removeContext (path);
}
public void removeContext (HttpContext context) throws IllegalArgumentException {
server.removeContext (context);
}
public InetSocketAddress getAddress() {
return server.getAddress();
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.io.*;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
/**
* a (filter) input stream which can tell us if bytes are "left over"
* on the underlying stream which can be read (without blocking)
* on another instance of this class.
*
* The class can also report if all bytes "expected" to be read
* were read, by the time close() was called. In that case,
* bytes may be drained to consume them (by calling drain() ).
*
* isEOF() returns true, when all expected bytes have been read
*/
abstract class LeftOverInputStream extends FilterInputStream {
ExchangeImpl t;
ServerImpl server;
protected boolean closed = false;
protected boolean eof = false;
byte[] one = new byte [1];
public LeftOverInputStream (ExchangeImpl t, InputStream src) {
super (src);
this.t = t;
this.server = t.getServerImpl();
}
/**
* if bytes are left over buffered on *the UNDERLYING* stream
*/
public boolean isDataBuffered () throws IOException {
assert eof;
return super.available() > 0;
}
public void close () throws IOException {
if (closed) {
return;
}
closed = true;
if (!eof) {
eof = drain (ServerConfig.getDrainAmount());
}
}
public boolean isClosed () {
return closed;
}
public boolean isEOF () {
return eof;
}
protected abstract int readImpl (byte[]b, int off, int len) throws IOException;
public synchronized int read () throws IOException {
if (closed) {
throw new IOException ("Stream is closed");
}
int c = readImpl (one, 0, 1);
if (c == -1 || c == 0) {
return c;
} else {
return one[0] & 0xFF;
}
}
public synchronized int read (byte[]b, int off, int len) throws IOException {
if (closed) {
throw new IOException ("Stream is closed");
}
return readImpl (b, off, len);
}
/**
* read and discard up to l bytes or "eof" occurs,
* (whichever is first). Then return true if the stream
* is at eof (ie. all bytes were read) or false if not
* (still bytes to be read)
*/
public boolean drain (long l) throws IOException {
int bufSize = 2048;
byte[] db = new byte [bufSize];
while (l > 0) {
long len = readImpl (db, 0, bufSize);
if (len == -1) {
eof = true;
return true;
} else {
l = l - len;
}
}
return false;
}
}

View File

@@ -0,0 +1,408 @@
/*
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.nio.*;
import java.io.*;
import java.nio.channels.*;
import com.sun.net.httpserver.*;
/**
*/
class Request {
final static int BUF_LEN = 2048;
final static byte CR = 13;
final static byte LF = 10;
private String startLine;
private SocketChannel chan;
private InputStream is;
private OutputStream os;
Request (InputStream rawInputStream, OutputStream rawout) throws IOException {
is = rawInputStream;
os = rawout;
do {
startLine = readLine();
if (startLine == null) {
return;
}
/* skip blank lines */
} while (startLine == null ? false : startLine.equals (""));
}
char[] buf = new char [BUF_LEN];
int pos;
StringBuffer lineBuf;
public InputStream inputStream () {
return is;
}
public OutputStream outputStream () {
return os;
}
/**
* read a line from the stream returning as a String.
* Not used for reading headers.
*/
public String readLine () throws IOException {
boolean gotCR = false, gotLF = false;
pos = 0; lineBuf = new StringBuffer();
while (!gotLF) {
int c = is.read();
if (c == -1) {
return null;
}
if (gotCR) {
if (c == LF) {
gotLF = true;
} else {
gotCR = false;
consume (CR);
consume (c);
}
} else {
if (c == CR) {
gotCR = true;
} else {
consume (c);
}
}
}
lineBuf.append (buf, 0, pos);
return new String (lineBuf);
}
private void consume (int c) {
if (pos == BUF_LEN) {
lineBuf.append (buf);
pos = 0;
}
buf[pos++] = (char)c;
}
/**
* returns the request line (first line of a request)
*/
public String requestLine () {
return startLine;
}
Headers hdrs = null;
@SuppressWarnings("fallthrough")
Headers headers () throws IOException {
if (hdrs != null) {
return hdrs;
}
hdrs = new Headers();
char s[] = new char[10];
int len = 0;
int firstc = is.read();
// check for empty headers
if (firstc == CR || firstc == LF) {
int c = is.read();
if (c == CR || c == LF) {
return hdrs;
}
s[0] = (char)firstc;
len = 1;
firstc = c;
}
while (firstc != LF && firstc != CR && firstc >= 0) {
int keyend = -1;
int c;
boolean inKey = firstc > ' ';
s[len++] = (char) firstc;
parseloop:{
while ((c = is.read()) >= 0) {
switch (c) {
/*fallthrough*/
case ':':
if (inKey && len > 0)
keyend = len;
inKey = false;
break;
case '\t':
c = ' ';
case ' ':
inKey = false;
break;
case CR:
case LF:
firstc = is.read();
if (c == CR && firstc == LF) {
firstc = is.read();
if (firstc == CR)
firstc = is.read();
}
if (firstc == LF || firstc == CR || firstc > ' ')
break parseloop;
/* continuation */
c = ' ';
break;
}
if (len >= s.length) {
char ns[] = new char[s.length * 2];
System.arraycopy(s, 0, ns, 0, len);
s = ns;
}
s[len++] = (char) c;
}
firstc = -1;
}
while (len > 0 && s[len - 1] <= ' ')
len--;
String k;
if (keyend <= 0) {
k = null;
keyend = 0;
} else {
k = String.copyValueOf(s, 0, keyend);
if (keyend < len && s[keyend] == ':')
keyend++;
while (keyend < len && s[keyend] <= ' ')
keyend++;
}
String v;
if (keyend >= len)
v = new String();
else
v = String.copyValueOf(s, keyend, len - keyend);
if (hdrs.size() >= ServerConfig.getMaxReqHeaders()) {
throw new IOException("Maximum number of request headers (" +
"sun.net.httpserver.maxReqHeaders) exceeded, " +
ServerConfig.getMaxReqHeaders() + ".");
}
if (k == null) { // Headers disallows null keys, use empty string
k = ""; // instead to represent invalid key
}
hdrs.add (k,v);
len = 0;
}
return hdrs;
}
/**
* Implements blocking reading semantics on top of a non-blocking channel
*/
static class ReadStream extends InputStream {
SocketChannel channel;
ByteBuffer chanbuf;
byte[] one;
private boolean closed = false, eof = false;
ByteBuffer markBuf; /* reads may be satisfied from this buffer */
boolean marked;
boolean reset;
int readlimit;
static long readTimeout;
ServerImpl server;
final static int BUFSIZE = 8 * 1024;
public ReadStream (ServerImpl server, SocketChannel chan) throws IOException {
this.channel = chan;
this.server = server;
chanbuf = ByteBuffer.allocate (BUFSIZE);
chanbuf.clear();
one = new byte[1];
closed = marked = reset = false;
}
public synchronized int read (byte[] b) throws IOException {
return read (b, 0, b.length);
}
public synchronized int read () throws IOException {
int result = read (one, 0, 1);
if (result == 1) {
return one[0] & 0xFF;
} else {
return -1;
}
}
public synchronized int read (byte[] b, int off, int srclen) throws IOException {
int canreturn, willreturn;
if (closed)
throw new IOException ("Stream closed");
if (eof) {
return -1;
}
assert channel.isBlocking();
if (off < 0 || srclen < 0|| srclen > (b.length-off)) {
throw new IndexOutOfBoundsException ();
}
if (reset) { /* satisfy from markBuf */
canreturn = markBuf.remaining ();
willreturn = canreturn>srclen ? srclen : canreturn;
markBuf.get(b, off, willreturn);
if (canreturn == willreturn) {
reset = false;
}
} else { /* satisfy from channel */
chanbuf.clear ();
if (srclen < BUFSIZE) {
chanbuf.limit (srclen);
}
do {
willreturn = channel.read (chanbuf);
} while (willreturn == 0);
if (willreturn == -1) {
eof = true;
return -1;
}
chanbuf.flip ();
chanbuf.get(b, off, willreturn);
if (marked) { /* copy into markBuf */
try {
markBuf.put (b, off, willreturn);
} catch (BufferOverflowException e) {
marked = false;
}
}
}
return willreturn;
}
public boolean markSupported () {
return true;
}
/* Does not query the OS socket */
public synchronized int available () throws IOException {
if (closed)
throw new IOException ("Stream is closed");
if (eof)
return -1;
if (reset)
return markBuf.remaining();
return chanbuf.remaining();
}
public void close () throws IOException {
if (closed) {
return;
}
channel.close ();
closed = true;
}
public synchronized void mark (int readlimit) {
if (closed)
return;
this.readlimit = readlimit;
markBuf = ByteBuffer.allocate (readlimit);
marked = true;
reset = false;
}
public synchronized void reset () throws IOException {
if (closed )
return;
if (!marked)
throw new IOException ("Stream not marked");
marked = false;
reset = true;
markBuf.flip ();
}
}
static class WriteStream extends java.io.OutputStream {
SocketChannel channel;
ByteBuffer buf;
SelectionKey key;
boolean closed;
byte[] one;
ServerImpl server;
public WriteStream (ServerImpl server, SocketChannel channel) throws IOException {
this.channel = channel;
this.server = server;
assert channel.isBlocking();
closed = false;
one = new byte [1];
buf = ByteBuffer.allocate (4096);
}
public synchronized void write (int b) throws IOException {
one[0] = (byte)b;
write (one, 0, 1);
}
public synchronized void write (byte[] b) throws IOException {
write (b, 0, b.length);
}
public synchronized void write (byte[] b, int off, int len) throws IOException {
int l = len;
if (closed)
throw new IOException ("stream is closed");
int cap = buf.capacity();
if (cap < len) {
int diff = len - cap;
buf = ByteBuffer.allocate (2*(cap+diff));
}
buf.clear();
buf.put (b, off, len);
buf.flip ();
int n;
while ((n = channel.write (buf)) < l) {
l -= n;
if (l == 0)
return;
}
}
public void close () throws IOException {
if (closed)
return;
//server.logStackTrace ("Request.OS.close: isOpen="+channel.isOpen());
channel.close ();
closed = true;
}
}
}

View File

@@ -0,0 +1,666 @@
/*
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.net.*;
import java.nio.*;
import java.io.*;
import java.nio.channels.*;
import java.util.concurrent.locks.*;
import javax.net.ssl.*;
import javax.net.ssl.SSLEngineResult.*;
import com.sun.net.httpserver.*;
/**
* given a non-blocking SocketChannel, it produces
* (blocking) streams which encrypt/decrypt the SSL content
* and handle the SSL handshaking automatically.
*/
class SSLStreams {
SSLContext sslctx;
SocketChannel chan;
ServerImpl server;
SSLEngine engine;
EngineWrapper wrapper;
OutputStream os;
InputStream is;
/* held by thread doing the hand-shake on this connection */
Lock handshaking = new ReentrantLock();
SSLStreams (ServerImpl server, SSLContext sslctx, SocketChannel chan) throws IOException {
this.server = server;
this.sslctx= sslctx;
this.chan= chan;
InetSocketAddress addr =
(InetSocketAddress)chan.socket().getRemoteSocketAddress();
engine = sslctx.createSSLEngine (addr.getHostName(), addr.getPort());
engine.setUseClientMode (false);
HttpsConfigurator cfg = server.getHttpsConfigurator();
configureEngine (cfg, addr);
wrapper = new EngineWrapper (chan, engine);
}
private void configureEngine(HttpsConfigurator cfg, InetSocketAddress addr){
if (cfg != null) {
Parameters params = new Parameters (cfg, addr);
//BEGIN_TIGER_EXCLUDE
cfg.configure (params);
SSLParameters sslParams = params.getSSLParameters();
if (sslParams != null) {
engine.setSSLParameters (sslParams);
} else
//END_TIGER_EXCLUDE
{
/* tiger compatibility */
if (params.getCipherSuites() != null) {
try {
engine.setEnabledCipherSuites (
params.getCipherSuites()
);
} catch (IllegalArgumentException e) { /* LOG */}
}
engine.setNeedClientAuth (params.getNeedClientAuth());
engine.setWantClientAuth (params.getWantClientAuth());
if (params.getProtocols() != null) {
try {
engine.setEnabledProtocols (
params.getProtocols()
);
} catch (IllegalArgumentException e) { /* LOG */}
}
}
}
}
class Parameters extends HttpsParameters {
InetSocketAddress addr;
HttpsConfigurator cfg;
Parameters (HttpsConfigurator cfg, InetSocketAddress addr) {
this.addr = addr;
this.cfg = cfg;
}
public InetSocketAddress getClientAddress () {
return addr;
}
public HttpsConfigurator getHttpsConfigurator() {
return cfg;
}
//BEGIN_TIGER_EXCLUDE
SSLParameters params;
public void setSSLParameters (SSLParameters p) {
params = p;
}
SSLParameters getSSLParameters () {
return params;
}
//END_TIGER_EXCLUDE
}
/**
* cleanup resources allocated inside this object
*/
void close () throws IOException {
wrapper.close();
}
/**
* return the SSL InputStream
*/
InputStream getInputStream () throws IOException {
if (is == null) {
is = new InputStream();
}
return is;
}
/**
* return the SSL OutputStream
*/
OutputStream getOutputStream () throws IOException {
if (os == null) {
os = new OutputStream();
}
return os;
}
SSLEngine getSSLEngine () {
return engine;
}
/**
* request the engine to repeat the handshake on this session
* the handshake must be driven by reads/writes on the streams
* Normally, not necessary to call this.
*/
void beginHandshake() throws SSLException {
engine.beginHandshake();
}
class WrapperResult {
SSLEngineResult result;
/* if passed in buffer was not big enough then the
* a reallocated buffer is returned here
*/
ByteBuffer buf;
}
int app_buf_size;
int packet_buf_size;
enum BufType {
PACKET, APPLICATION
};
private ByteBuffer allocate (BufType type) {
return allocate (type, -1);
}
private ByteBuffer allocate (BufType type, int len) {
assert engine != null;
synchronized (this) {
int size;
if (type == BufType.PACKET) {
if (packet_buf_size == 0) {
SSLSession sess = engine.getSession();
packet_buf_size = sess.getPacketBufferSize();
}
if (len > packet_buf_size) {
packet_buf_size = len;
}
size = packet_buf_size;
} else {
if (app_buf_size == 0) {
SSLSession sess = engine.getSession();
app_buf_size = sess.getApplicationBufferSize();
}
if (len > app_buf_size) {
app_buf_size = len;
}
size = app_buf_size;
}
return ByteBuffer.allocate (size);
}
}
/* reallocates the buffer by :-
* 1. creating a new buffer double the size of the old one
* 2. putting the contents of the old buffer into the new one
* 3. set xx_buf_size to the new size if it was smaller than new size
*
* flip is set to true if the old buffer needs to be flipped
* before it is copied.
*/
private ByteBuffer realloc (ByteBuffer b, boolean flip, BufType type) {
synchronized (this) {
int nsize = 2 * b.capacity();
ByteBuffer n = allocate (type, nsize);
if (flip) {
b.flip();
}
n.put(b);
b = n;
}
return b;
}
/**
* This is a thin wrapper over SSLEngine and the SocketChannel,
* which guarantees the ordering of wraps/unwraps with respect to the underlying
* channel read/writes. It handles the UNDER/OVERFLOW status codes
* It does not handle the handshaking status codes, or the CLOSED status code
* though once the engine is closed, any attempt to read/write to it
* will get an exception. The overall result is returned.
* It functions synchronously/blocking
*/
class EngineWrapper {
SocketChannel chan;
SSLEngine engine;
Object wrapLock, unwrapLock;
ByteBuffer unwrap_src, wrap_dst;
boolean closed = false;
int u_remaining; // the number of bytes left in unwrap_src after an unwrap()
EngineWrapper (SocketChannel chan, SSLEngine engine) throws IOException {
this.chan = chan;
this.engine = engine;
wrapLock = new Object();
unwrapLock = new Object();
unwrap_src = allocate(BufType.PACKET);
wrap_dst = allocate(BufType.PACKET);
}
void close () throws IOException {
}
/* try to wrap and send the data in src. Handles OVERFLOW.
* Might block if there is an outbound blockage or if another
* thread is calling wrap(). Also, might not send any data
* if an unwrap is needed.
*/
WrapperResult wrapAndSend(ByteBuffer src) throws IOException {
return wrapAndSendX(src, false);
}
WrapperResult wrapAndSendX(ByteBuffer src, boolean ignoreClose) throws IOException {
if (closed && !ignoreClose) {
throw new IOException ("Engine is closed");
}
Status status;
WrapperResult r = new WrapperResult();
synchronized (wrapLock) {
wrap_dst.clear();
do {
r.result = engine.wrap (src, wrap_dst);
status = r.result.getStatus();
if (status == Status.BUFFER_OVERFLOW) {
wrap_dst = realloc (wrap_dst, true, BufType.PACKET);
}
} while (status == Status.BUFFER_OVERFLOW);
if (status == Status.CLOSED && !ignoreClose) {
closed = true;
return r;
}
if (r.result.bytesProduced() > 0) {
wrap_dst.flip();
int l = wrap_dst.remaining();
assert l == r.result.bytesProduced();
while (l>0) {
l -= chan.write (wrap_dst);
}
}
}
return r;
}
/* block until a complete message is available and return it
* in dst, together with the Result. dst may have been re-allocated
* so caller should check the returned value in Result
* If handshaking is in progress then, possibly no data is returned
*/
WrapperResult recvAndUnwrap(ByteBuffer dst) throws IOException {
Status status = Status.OK;
WrapperResult r = new WrapperResult();
r.buf = dst;
if (closed) {
throw new IOException ("Engine is closed");
}
boolean needData;
if (u_remaining > 0) {
unwrap_src.compact();
unwrap_src.flip();
needData = false;
} else {
unwrap_src.clear();
needData = true;
}
synchronized (unwrapLock) {
int x;
do {
if (needData) {
do {
x = chan.read (unwrap_src);
} while (x == 0);
if (x == -1) {
throw new IOException ("connection closed for reading");
}
unwrap_src.flip();
}
r.result = engine.unwrap (unwrap_src, r.buf);
status = r.result.getStatus();
if (status == Status.BUFFER_UNDERFLOW) {
if (unwrap_src.limit() == unwrap_src.capacity()) {
/* buffer not big enough */
unwrap_src = realloc (
unwrap_src, false, BufType.PACKET
);
} else {
/* Buffer not full, just need to read more
* data off the channel. Reset pointers
* for reading off SocketChannel
*/
unwrap_src.position (unwrap_src.limit());
unwrap_src.limit (unwrap_src.capacity());
}
needData = true;
} else if (status == Status.BUFFER_OVERFLOW) {
r.buf = realloc (r.buf, true, BufType.APPLICATION);
needData = false;
} else if (status == Status.CLOSED) {
closed = true;
r.buf.flip();
return r;
}
} while (status != Status.OK);
}
u_remaining = unwrap_src.remaining();
return r;
}
}
/**
* send the data in the given ByteBuffer. If a handshake is needed
* then this is handled within this method. When this call returns,
* all of the given user data has been sent and any handshake has been
* completed. Caller should check if engine has been closed.
*/
public WrapperResult sendData (ByteBuffer src) throws IOException {
WrapperResult r=null;
while (src.remaining() > 0) {
r = wrapper.wrapAndSend(src);
Status status = r.result.getStatus();
if (status == Status.CLOSED) {
doClosure ();
return r;
}
HandshakeStatus hs_status = r.result.getHandshakeStatus();
if (hs_status != HandshakeStatus.FINISHED &&
hs_status != HandshakeStatus.NOT_HANDSHAKING)
{
doHandshake(hs_status);
}
}
return r;
}
/**
* read data thru the engine into the given ByteBuffer. If the
* given buffer was not large enough, a new one is allocated
* and returned. This call handles handshaking automatically.
* Caller should check if engine has been closed.
*/
public WrapperResult recvData (ByteBuffer dst) throws IOException {
/* we wait until some user data arrives */
WrapperResult r = null;
assert dst.position() == 0;
while (dst.position() == 0) {
r = wrapper.recvAndUnwrap (dst);
dst = (r.buf != dst) ? r.buf: dst;
Status status = r.result.getStatus();
if (status == Status.CLOSED) {
doClosure ();
return r;
}
HandshakeStatus hs_status = r.result.getHandshakeStatus();
if (hs_status != HandshakeStatus.FINISHED &&
hs_status != HandshakeStatus.NOT_HANDSHAKING)
{
doHandshake (hs_status);
}
}
dst.flip();
return r;
}
/* we've received a close notify. Need to call wrap to send
* the response
*/
void doClosure () throws IOException {
try {
handshaking.lock();
ByteBuffer tmp = allocate(BufType.APPLICATION);
WrapperResult r;
Status st;
HandshakeStatus hs;
do {
tmp.clear();
tmp.flip ();
r = wrapper.wrapAndSendX (tmp, true);
hs = r.result.getHandshakeStatus();
st = r.result.getStatus();
} while (st != Status.CLOSED &&
!(st == Status.OK && hs == HandshakeStatus.NOT_HANDSHAKING));
} finally {
handshaking.unlock();
}
}
/* do the (complete) handshake after acquiring the handshake lock.
* If two threads call this at the same time, then we depend
* on the wrapper methods being idempotent. eg. if wrapAndSend()
* is called with no data to send then there must be no problem
*/
@SuppressWarnings("fallthrough")
void doHandshake (HandshakeStatus hs_status) throws IOException {
try {
handshaking.lock();
ByteBuffer tmp = allocate(BufType.APPLICATION);
while (hs_status != HandshakeStatus.FINISHED &&
hs_status != HandshakeStatus.NOT_HANDSHAKING)
{
WrapperResult r = null;
switch (hs_status) {
case NEED_TASK:
Runnable task;
while ((task = engine.getDelegatedTask()) != null) {
/* run in current thread, because we are already
* running an external Executor
*/
task.run();
}
/* fall thru - call wrap again */
case NEED_WRAP:
tmp.clear();
tmp.flip();
r = wrapper.wrapAndSend(tmp);
break;
case NEED_UNWRAP:
tmp.clear();
r = wrapper.recvAndUnwrap (tmp);
if (r.buf != tmp) {
tmp = r.buf;
}
assert tmp.position() == 0;
break;
}
hs_status = r.result.getHandshakeStatus();
}
} finally {
handshaking.unlock();
}
}
/**
* represents an SSL input stream. Multiple https requests can
* be sent over one stream. closing this stream causes an SSL close
* input.
*/
class InputStream extends java.io.InputStream {
ByteBuffer bbuf;
boolean closed = false;
/* this stream eof */
boolean eof = false;
boolean needData = true;
InputStream () {
bbuf = allocate (BufType.APPLICATION);
}
public int read (byte[] buf, int off, int len) throws IOException {
if (closed) {
throw new IOException ("SSL stream is closed");
}
if (eof) {
return -1;
}
int available=0;
if (!needData) {
available = bbuf.remaining();
needData = (available==0);
}
if (needData) {
bbuf.clear();
WrapperResult r = recvData (bbuf);
bbuf = r.buf== bbuf? bbuf: r.buf;
if ((available=bbuf.remaining()) == 0) {
eof = true;
return -1;
} else {
needData = false;
}
}
/* copy as much as possible from buf into users buf */
if (len > available) {
len = available;
}
bbuf.get (buf, off, len);
return len;
}
public int available () throws IOException {
return bbuf.remaining();
}
public boolean markSupported () {
return false; /* not possible with SSLEngine */
}
public void reset () throws IOException {
throw new IOException ("mark/reset not supported");
}
public long skip (long s) throws IOException {
int n = (int)s;
if (closed) {
throw new IOException ("SSL stream is closed");
}
if (eof) {
return 0;
}
int ret = n;
while (n > 0) {
if (bbuf.remaining() >= n) {
bbuf.position (bbuf.position()+n);
return ret;
} else {
n -= bbuf.remaining();
bbuf.clear();
WrapperResult r = recvData (bbuf);
bbuf = r.buf==bbuf? bbuf: r.buf;
}
}
return ret; /* not reached */
}
/**
* close the SSL connection. All data must have been consumed
* before this is called. Otherwise an exception will be thrown.
* [Note. May need to revisit this. not quite the normal close() semantics
*/
public void close () throws IOException {
eof = true;
engine.closeInbound ();
}
public int read (byte[] buf) throws IOException {
return read (buf, 0, buf.length);
}
byte single[] = new byte [1];
public int read () throws IOException {
if (eof) {
return -1;
}
int n = read (single, 0, 1);
if (n <= 0) {
return -1;
} else {
return single[0] & 0xFF;
}
}
}
/**
* represents an SSL output stream. plain text data written to this stream
* is encrypted by the stream. Multiple HTTPS responses can be sent on
* one stream. closing this stream initiates an SSL closure
*/
class OutputStream extends java.io.OutputStream {
ByteBuffer buf;
boolean closed = false;
byte single[] = new byte[1];
OutputStream() {
buf = allocate(BufType.APPLICATION);
}
public void write(int b) throws IOException {
single[0] = (byte)b;
write (single, 0, 1);
}
public void write(byte b[]) throws IOException {
write (b, 0, b.length);
}
public void write(byte b[], int off, int len) throws IOException {
if (closed) {
throw new IOException ("output stream is closed");
}
while (len > 0) {
int l = len > buf.capacity() ? buf.capacity() : len;
buf.clear();
buf.put (b, off, l);
len -= l;
off += l;
buf.flip();
WrapperResult r = sendData (buf);
if (r.result.getStatus() == Status.CLOSED) {
closed = true;
if (len > 0) {
throw new IOException ("output stream is closed");
}
}
}
}
public void flush() throws IOException {
/* no-op */
}
public void close() throws IOException {
WrapperResult r=null;
engine.closeOutbound();
closed = true;
HandshakeStatus stat = HandshakeStatus.NEED_WRAP;
buf.clear();
while (stat == HandshakeStatus.NEED_WRAP) {
r = wrapper.wrapAndSend (buf);
stat = r.result.getHandshakeStatus();
}
assert r.result.getStatus() == Status.CLOSED;
}
}
}

View File

@@ -0,0 +1,239 @@
/*
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.util.logging.Logger;
import java.security.PrivilegedAction;
/**
* Parameters that users will not likely need to set
* but are useful for debugging
*/
class ServerConfig {
private static final int DEFAULT_IDLE_TIMER_SCHEDULE_MILLIS = 10000 ; // 10 sec.
private static final long DEFAULT_IDLE_INTERVAL_IN_SECS = 30;
private static final int DEFAULT_MAX_CONNECTIONS = -1 ; // no limit on maximum connections
private static final int DEFAULT_MAX_IDLE_CONNECTIONS = 200 ;
private static final long DEFAULT_MAX_REQ_TIME = -1; // default: forever
private static final long DEFAULT_MAX_RSP_TIME = -1; // default: forever
// default timer schedule, in milli seconds, for the timer task that's responsible for
// timing out request/response if max request/response time is configured
private static final long DEFAULT_REQ_RSP_TIMER_TASK_SCHEDULE_MILLIS = 1000;
private static final int DEFAULT_MAX_REQ_HEADERS = 200;
private static final long DEFAULT_DRAIN_AMOUNT = 64 * 1024;
private static long idleTimerScheduleMillis;
private static long idleIntervalMillis;
// The maximum number of bytes to drain from an inputstream
private static long drainAmount;
// the maximum number of connections that the server will allow to be open
// after which it will no longer "accept()" any new connections, till the
// current connection count goes down due to completion of processing the requests
private static int maxConnections;
private static int maxIdleConnections;
// The maximum number of request headers allowable
private static int maxReqHeaders;
// max time a request or response is allowed to take
private static long maxReqTime;
private static long maxRspTime;
private static long reqRspTimerScheduleMillis;
private static boolean debug;
// the value of the TCP_NODELAY socket-level option
private static boolean noDelay;
static {
java.security.AccessController.doPrivileged(
new PrivilegedAction<Void>() {
@Override
public Void run () {
idleIntervalMillis = Long.getLong("sun.net.httpserver.idleInterval",
DEFAULT_IDLE_INTERVAL_IN_SECS) * 1000;
if (idleIntervalMillis <= 0) {
idleIntervalMillis = DEFAULT_IDLE_INTERVAL_IN_SECS * 1000;
}
idleTimerScheduleMillis = Long.getLong("sun.net.httpserver.clockTick",
DEFAULT_IDLE_TIMER_SCHEDULE_MILLIS);
if (idleTimerScheduleMillis <= 0) {
// ignore zero or negative value and use the default schedule
idleTimerScheduleMillis = DEFAULT_IDLE_TIMER_SCHEDULE_MILLIS;
}
maxConnections = Integer.getInteger(
"jdk.httpserver.maxConnections",
DEFAULT_MAX_CONNECTIONS);
maxIdleConnections = Integer.getInteger(
"sun.net.httpserver.maxIdleConnections",
DEFAULT_MAX_IDLE_CONNECTIONS);
drainAmount = Long.getLong("sun.net.httpserver.drainAmount",
DEFAULT_DRAIN_AMOUNT);
maxReqHeaders = Integer.getInteger(
"sun.net.httpserver.maxReqHeaders",
DEFAULT_MAX_REQ_HEADERS);
maxReqTime = Long.getLong("sun.net.httpserver.maxReqTime",
DEFAULT_MAX_REQ_TIME);
maxRspTime = Long.getLong("sun.net.httpserver.maxRspTime",
DEFAULT_MAX_RSP_TIME);
reqRspTimerScheduleMillis = Long.getLong("sun.net.httpserver.timerMillis",
DEFAULT_REQ_RSP_TIMER_TASK_SCHEDULE_MILLIS);
if (reqRspTimerScheduleMillis <= 0) {
// ignore any negative or zero value for this configuration and reset
// to default schedule
reqRspTimerScheduleMillis = DEFAULT_REQ_RSP_TIMER_TASK_SCHEDULE_MILLIS;
}
debug = Boolean.getBoolean("sun.net.httpserver.debug");
noDelay = Boolean.getBoolean("sun.net.httpserver.nodelay");
return null;
}
});
}
static void checkLegacyProperties(final Logger logger) {
// legacy properties that are no longer used
// print a warning to logger if they are set.
java.security.AccessController.doPrivileged(
new PrivilegedAction<Void>() {
public Void run () {
if (System.getProperty("sun.net.httpserver.readTimeout")
!=null)
{
logger.warning ("sun.net.httpserver.readTimeout "+
"property is no longer used. "+
"Use sun.net.httpserver.maxReqTime instead."
);
}
if (System.getProperty("sun.net.httpserver.writeTimeout")
!=null)
{
logger.warning ("sun.net.httpserver.writeTimeout "+
"property is no longer used. Use "+
"sun.net.httpserver.maxRspTime instead."
);
}
if (System.getProperty("sun.net.httpserver.selCacheTimeout")
!=null)
{
logger.warning ("sun.net.httpserver.selCacheTimeout "+
"property is no longer used."
);
}
return null;
}
}
);
}
static boolean debugEnabled() {
return debug;
}
/**
* {@return Returns the maximum duration, in milli seconds, a connection can be idle}
*/
static long getIdleIntervalMillis() {
return idleIntervalMillis;
}
/**
* {@return Returns the schedule, in milli seconds, for the timer task that is responsible
* for managing the idle connections}
*/
static long getIdleTimerScheduleMillis() {
return idleTimerScheduleMillis;
}
/**
* @return Returns the maximum number of connections that can be open at any given time.
* This method can return a value of 0 or negative to represent that the limit hasn't
* been configured.
*/
static int getMaxConnections() {
return maxConnections;
}
/**
* @return Returns the maximum number of connections that can be idle. This method
* can return a value of 0 or negative.
*/
static int getMaxIdleConnections() {
return maxIdleConnections;
}
static long getDrainAmount() {
return drainAmount;
}
static int getMaxReqHeaders() {
return maxReqHeaders;
}
/**
* @return Returns the maximum amount of time the server will wait for the request to be read
* completely. This method can return a value of 0 or negative to imply no maximum limit has
* been configured.
*/
static long getMaxReqTime() {
return maxReqTime;
}
/**
* @return Returns the maximum amount of time the server will wait for the response to be generated
* for a request that is being processed. This method can return a value of 0 or negative to
* imply no maximum limit has been configured.
*/
static long getMaxRspTime() {
return maxRspTime;
}
/**
* {@return Returns the timer schedule of the task that's responsible for timing out
* request/response that have been running longer than any configured timeout}
*/
static long getReqRspTimerScheduleMillis() {
return reqRspTimerScheduleMillis;
}
static boolean noDelay() {
return noDelay;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.io.*;
class StreamClosedException extends IOException {
private static final long serialVersionUID = -4485921499356327937L;
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.io.*;
import java.net.*;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.*;
/**
* a class which allows the caller to write an indefinite
* number of bytes to an underlying stream , but without using
* chunked encoding. Used for http/1.0 clients only
* The underlying connection needs to be closed afterwards.
*/
class UndefLengthOutputStream extends FilterOutputStream
{
private boolean closed = false;
ExchangeImpl t;
UndefLengthOutputStream (ExchangeImpl t, OutputStream src) {
super (src);
this.t = t;
}
public void write (int b) throws IOException {
if (closed) {
throw new IOException ("stream closed");
}
out.write(b);
}
public void write (byte[]b, int off, int len) throws IOException {
if (closed) {
throw new IOException ("stream closed");
}
out.write(b, off, len);
}
public void close () throws IOException {
if (closed) {
return;
}
closed = true;
flush();
LeftOverInputStream is = t.getOriginalInputStream();
if (!is.isClosed()) {
try {
is.close();
} catch (IOException e) {}
}
WriteFinishedEvent e = new WriteFinishedEvent (t);
t.getHttpContext().getServerImpl().addEvent (e);
}
// flush is a pass-through
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import java.util.*;
import com.sun.net.httpserver.*;
class UnmodifiableHeaders extends Headers {
Headers map;
UnmodifiableHeaders(Headers map) {
this.map = map;
}
public int size() {return map.size();}
public boolean isEmpty() {return map.isEmpty();}
public boolean containsKey(Object key) {
return map.containsKey (key);
}
public boolean containsValue(Object value) {
return map.containsValue(value);
}
public List<String> get(Object key) {
return map.get(key);
}
public String getFirst (String key) {
return map.getFirst(key);
}
public List<String> put(String key, List<String> value) {
return map.put (key, value);
}
public void add (String key, String value) {
throw new UnsupportedOperationException ("unsupported operation");
}
public void set (String key, String value) {
throw new UnsupportedOperationException ("unsupported operation");
}
public List<String> remove(Object key) {
throw new UnsupportedOperationException ("unsupported operation");
}
public void putAll(Map<? extends String,? extends List<String>> t) {
throw new UnsupportedOperationException ("unsupported operation");
}
public void clear() {
throw new UnsupportedOperationException ("unsupported operation");
}
public Set<String> keySet() {
return Collections.unmodifiableSet (map.keySet());
}
public Collection<List<String>> values() {
return Collections.unmodifiableCollection(map.values());
}
/* TODO check that contents of set are not modifable : security */
public Set<Map.Entry<String, List<String>>> entrySet() {
return Collections.unmodifiableSet (map.entrySet());
}
public boolean equals(Object o) {return map.equals(o);}
public int hashCode() {return map.hashCode();}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
class WriteFinishedEvent extends Event {
WriteFinishedEvent (ExchangeImpl t) {
super (t);
assert !t.writefinished;
t.writefinished = true;
}
}

View File

@@ -0,0 +1,511 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*******************************************************************************
* Copyright (C) 2003-2004, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
//
// CHANGELOG
// 2005-05-19 Edward Wang
// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/text/Punycode.java
// - move from package com.ibm.icu.text to package sun.net.idn
// - use ParseException instead of StringPrepParseException
// 2007-08-14 Martin Buchholz
// - remove redundant casts
//
package sun.net.idn;
import java.text.ParseException;
import sun.text.normalizer.UCharacter;
import sun.text.normalizer.UTF16;
/**
* Ported code from ICU punycode.c
* @author ram
*/
/* Package Private class */
public final class Punycode {
/* Punycode parameters for Bootstring */
private static final int BASE = 36;
private static final int TMIN = 1;
private static final int TMAX = 26;
private static final int SKEW = 38;
private static final int DAMP = 700;
private static final int INITIAL_BIAS = 72;
private static final int INITIAL_N = 0x80;
/* "Basic" Unicode/ASCII code points */
private static final int HYPHEN = 0x2d;
private static final int DELIMITER = HYPHEN;
private static final int ZERO = 0x30;
private static final int NINE = 0x39;
private static final int SMALL_A = 0x61;
private static final int SMALL_Z = 0x7a;
private static final int CAPITAL_A = 0x41;
private static final int CAPITAL_Z = 0x5a;
// TODO: eliminate the 256 limitation
private static final int MAX_CP_COUNT = 256;
private static final int UINT_MAGIC = 0x80000000;
private static final long ULONG_MAGIC = 0x8000000000000000L;
private static int adaptBias(int delta, int length, boolean firstTime){
if(firstTime){
delta /=DAMP;
}else{
delta /= 2;
}
delta += delta/length;
int count=0;
for(; delta>((BASE-TMIN)*TMAX)/2; count+=BASE) {
delta/=(BASE-TMIN);
}
return count+(((BASE-TMIN+1)*delta)/(delta+SKEW));
}
/**
* basicToDigit[] contains the numeric value of a basic code
* point (for use in representing integers) in the range 0 to
* BASE-1, or -1 if b is does not represent a value.
*/
static final int[] basicToDigit= new int[]{
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
private static char asciiCaseMap(char b, boolean uppercase) {
if(uppercase) {
if(SMALL_A<=b && b<=SMALL_Z) {
b-=(SMALL_A-CAPITAL_A);
}
} else {
if(CAPITAL_A<=b && b<=CAPITAL_Z) {
b+=(SMALL_A-CAPITAL_A);
}
}
return b;
}
/**
* digitToBasic() returns the basic code point whose value
* (when used for representing integers) is d, which must be in the
* range 0 to BASE-1. The lowercase form is used unless the uppercase flag is
* nonzero, in which case the uppercase form is used.
*/
private static char digitToBasic(int digit, boolean uppercase) {
/* 0..25 map to ASCII a..z or A..Z */
/* 26..35 map to ASCII 0..9 */
if(digit<26) {
if(uppercase) {
return (char)(CAPITAL_A+digit);
} else {
return (char)(SMALL_A+digit);
}
} else {
return (char)((ZERO-26)+digit);
}
}
/**
* Converts Unicode to Punycode.
* The input string must not contain single, unpaired surrogates.
* The output will be represented as an array of ASCII code points.
*
* @param src
* @param caseFlags
* @return
* @throws ParseException
*/
public static StringBuffer encode(StringBuffer src, boolean[] caseFlags) throws ParseException{
int[] cpBuffer = new int[MAX_CP_COUNT];
int n, delta, handledCPCount, basicLength, destLength, bias, j, m, q, k, t, srcCPCount;
char c, c2;
int srcLength = src.length();
int destCapacity = MAX_CP_COUNT;
char[] dest = new char[destCapacity];
StringBuffer result = new StringBuffer();
/*
* Handle the basic code points and
* convert extended ones to UTF-32 in cpBuffer (caseFlag in sign bit):
*/
srcCPCount=destLength=0;
for(j=0; j<srcLength; ++j) {
if(srcCPCount==MAX_CP_COUNT) {
/* too many input code points */
throw new ParseException("Too many input code points", -1);
}
c=src.charAt(j);
if(isBasic(c)) {
if(destLength<destCapacity) {
cpBuffer[srcCPCount++]=0;
dest[destLength]=
caseFlags!=null ?
asciiCaseMap(c, caseFlags[j]) :
c;
}
++destLength;
} else {
n=((caseFlags!=null && caseFlags[j])? 1 : 0)<<31L;
if(!UTF16.isSurrogate(c)) {
n|=c;
} else if(UTF16.isLeadSurrogate(c) && (j+1)<srcLength && UTF16.isTrailSurrogate(c2=src.charAt(j+1))) {
++j;
n|=UCharacter.getCodePoint(c, c2);
} else {
/* error: unmatched surrogate */
throw new ParseException("Illegal char found", -1);
}
cpBuffer[srcCPCount++]=n;
}
}
/* Finish the basic string - if it is not empty - with a delimiter. */
basicLength=destLength;
if(basicLength>0) {
if(destLength<destCapacity) {
dest[destLength]=DELIMITER;
}
++destLength;
}
/*
* handledCPCount is the number of code points that have been handled
* basicLength is the number of basic code points
* destLength is the number of chars that have been output
*/
/* Initialize the state: */
n=INITIAL_N;
delta=0;
bias=INITIAL_BIAS;
/* Main encoding loop: */
for(handledCPCount=basicLength; handledCPCount<srcCPCount; /* no op */) {
/*
* All non-basic code points < n have been handled already.
* Find the next larger one:
*/
for(m=0x7fffffff, j=0; j<srcCPCount; ++j) {
q=cpBuffer[j]&0x7fffffff; /* remove case flag from the sign bit */
if(n<=q && q<m) {
m=q;
}
}
/*
* Increase delta enough to advance the decoder's
* <n,i> state to <m,0>, but guard against overflow:
*/
if(m-n>(0x7fffffff-MAX_CP_COUNT-delta)/(handledCPCount+1)) {
throw new RuntimeException("Internal program error");
}
delta+=(m-n)*(handledCPCount+1);
n=m;
/* Encode a sequence of same code points n */
for(j=0; j<srcCPCount; ++j) {
q=cpBuffer[j]&0x7fffffff; /* remove case flag from the sign bit */
if(q<n) {
++delta;
} else if(q==n) {
/* Represent delta as a generalized variable-length integer: */
for(q=delta, k=BASE; /* no condition */; k+=BASE) {
/** RAM: comment out the old code for conformance with draft-ietf-idn-punycode-03.txt
t=k-bias;
if(t<TMIN) {
t=TMIN;
} else if(t>TMAX) {
t=TMAX;
}
*/
t=k-bias;
if(t<TMIN) {
t=TMIN;
} else if(k>=(bias+TMAX)) {
t=TMAX;
}
if(q<t) {
break;
}
if(destLength<destCapacity) {
dest[destLength++]=digitToBasic(t+(q-t)%(BASE-t), false);
}
q=(q-t)/(BASE-t);
}
if(destLength<destCapacity) {
dest[destLength++]=digitToBasic(q, (cpBuffer[j]<0));
}
bias=adaptBias(delta, handledCPCount+1,(handledCPCount==basicLength));
delta=0;
++handledCPCount;
}
}
++delta;
++n;
}
return result.append(dest, 0, destLength);
}
private static boolean isBasic(int ch){
return (ch < INITIAL_N);
}
private static boolean isBasicUpperCase(int ch){
return( CAPITAL_A <= ch && ch <= CAPITAL_Z);
}
private static boolean isSurrogate(int ch){
return (((ch)&0xfffff800)==0xd800);
}
/**
* Converts Punycode to Unicode.
* The Unicode string will be at most as long as the Punycode string.
*
* @param src
* @param caseFlags
* @return
* @throws ParseException
*/
public static StringBuffer decode(StringBuffer src, boolean[] caseFlags)
throws ParseException{
int srcLength = src.length();
StringBuffer result = new StringBuffer();
int n, destLength, i, bias, basicLength, j, in, oldi, w, k, digit, t,
destCPCount, firstSupplementaryIndex, cpLength;
char b;
int destCapacity = MAX_CP_COUNT;
char[] dest = new char[destCapacity];
/*
* Handle the basic code points:
* Let basicLength be the number of input code points
* before the last delimiter, or 0 if there is none,
* then copy the first basicLength code points to the output.
*
* The two following loops iterate backward.
*/
for(j=srcLength; j>0;) {
if(src.charAt(--j)==DELIMITER) {
break;
}
}
destLength=basicLength=destCPCount=j;
while(j>0) {
b=src.charAt(--j);
if(!isBasic(b)) {
throw new ParseException("Illegal char found", -1);
}
if(j<destCapacity) {
dest[j]= b;
if(caseFlags!=null) {
caseFlags[j]=isBasicUpperCase(b);
}
}
}
/* Initialize the state: */
n=INITIAL_N;
i=0;
bias=INITIAL_BIAS;
firstSupplementaryIndex=1000000000;
/*
* Main decoding loop:
* Start just after the last delimiter if any
* basic code points were copied; start at the beginning otherwise.
*/
for(in=basicLength>0 ? basicLength+1 : 0; in<srcLength; /* no op */) {
/*
* in is the index of the next character to be consumed, and
* destCPCount is the number of code points in the output array.
*
* Decode a generalized variable-length integer into delta,
* which gets added to i. The overflow checking is easier
* if we increase i as we go, then subtract off its starting
* value at the end to obtain delta.
*/
for(oldi=i, w=1, k=BASE; /* no condition */; k+=BASE) {
if(in>=srcLength) {
throw new ParseException("Illegal char found", -1);
}
digit=basicToDigit[(byte)src.charAt(in++)];
if(digit<0) {
throw new ParseException("Invalid char found", -1);
}
if(digit>(0x7fffffff-i)/w) {
/* integer overflow */
throw new ParseException("Illegal char found", -1);
}
i+=digit*w;
t=k-bias;
if(t<TMIN) {
t=TMIN;
} else if(k>=(bias+TMAX)) {
t=TMAX;
}
if(digit<t) {
break;
}
if(w>0x7fffffff/(BASE-t)) {
/* integer overflow */
throw new ParseException("Illegal char found", -1);
}
w*=BASE-t;
}
/*
* Modification from sample code:
* Increments destCPCount here,
* where needed instead of in for() loop tail.
*/
++destCPCount;
bias=adaptBias(i-oldi, destCPCount, (oldi==0));
/*
* i was supposed to wrap around from (incremented) destCPCount to 0,
* incrementing n each time, so we'll fix that now:
*/
if(i/destCPCount>(0x7fffffff-n)) {
/* integer overflow */
throw new ParseException("Illegal char found", -1);
}
n+=i/destCPCount;
i%=destCPCount;
/* not needed for Punycode: */
/* if (decode_digit(n) <= BASE) return punycode_invalid_input; */
if(n>0x10ffff || isSurrogate(n)) {
/* Unicode code point overflow */
throw new ParseException("Illegal char found", -1);
}
/* Insert n at position i of the output: */
cpLength=UTF16.getCharCount(n);
if((destLength+cpLength)<destCapacity) {
int codeUnitIndex;
/*
* Handle indexes when supplementary code points are present.
*
* In almost all cases, there will be only BMP code points before i
* and even in the entire string.
* This is handled with the same efficiency as with UTF-32.
*
* Only the rare cases with supplementary code points are handled
* more slowly - but not too bad since this is an insertion anyway.
*/
if(i<=firstSupplementaryIndex) {
codeUnitIndex=i;
if(cpLength>1) {
firstSupplementaryIndex=codeUnitIndex;
} else {
++firstSupplementaryIndex;
}
} else {
codeUnitIndex=firstSupplementaryIndex;
codeUnitIndex=UTF16.moveCodePointOffset(dest, 0, destLength, codeUnitIndex, i-codeUnitIndex);
}
/* use the UChar index codeUnitIndex instead of the code point index i */
if(codeUnitIndex<destLength) {
System.arraycopy(dest, codeUnitIndex,
dest, codeUnitIndex+cpLength,
(destLength-codeUnitIndex));
if(caseFlags!=null) {
System.arraycopy(caseFlags, codeUnitIndex,
caseFlags, codeUnitIndex+cpLength,
destLength-codeUnitIndex);
}
}
if(cpLength==1) {
/* BMP, insert one code unit */
dest[codeUnitIndex]=(char)n;
} else {
/* supplementary character, insert two code units */
dest[codeUnitIndex]=UTF16.getLeadSurrogate(n);
dest[codeUnitIndex+1]=UTF16.getTrailSurrogate(n);
}
if(caseFlags!=null) {
/* Case of last character determines uppercase flag: */
caseFlags[codeUnitIndex]=isBasicUpperCase(src.charAt(in-1));
if(cpLength==2) {
caseFlags[codeUnitIndex+1]=false;
}
}
}
destLength+=cpLength;
++i;
}
result.append(dest, 0, destLength);
return result;
}
}

View File

@@ -0,0 +1,487 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
/*
*******************************************************************************
* Copyright (C) 2003-2004, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
//
// CHANGELOG
// 2005-05-19 Edward Wang
// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/text/StringPrep.java
// - move from package com.ibm.icu.text to package sun.net.idn
// - use ParseException instead of StringPrepParseException
// - change 'Normalizer.getUnicodeVersion()' to 'NormalizerImpl.getUnicodeVersion()'
// - remove all @deprecated tag to make compiler happy
// 2007-08-14 Martin Buchholz
// - remove redundant casts
//
package sun.net.idn;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import sun.text.Normalizer;
import sun.text.normalizer.CharTrie;
import sun.text.normalizer.Trie;
import sun.text.normalizer.NormalizerImpl;
import sun.text.normalizer.VersionInfo;
import sun.text.normalizer.UCharacter;
import sun.text.normalizer.UCharacterIterator;
import sun.text.normalizer.UTF16;
import sun.net.idn.UCharacterDirection;
import sun.net.idn.StringPrepDataReader;
/**
* StringPrep API implements the StingPrep framework as described by
* <a href="http://www.ietf.org/rfc/rfc3454.txt">RFC 3454</a>.
* StringPrep prepares Unicode strings for use in network protocols.
* Profiles of StingPrep are set of rules and data according to which the
* Unicode Strings are prepared. Each profiles contains tables which describe
* how a code point should be treated. The tables are broadly classied into
* <ul>
* <li> Unassigned Table: Contains code points that are unassigned
* in the Unicode Version supported by StringPrep. Currently
* RFC 3454 supports Unicode 3.2. </li>
* <li> Prohibited Table: Contains code points that are prohibted from
* the output of the StringPrep processing function. </li>
* <li> Mapping Table: Contains code ponts that are deleted from the output or case mapped. </li>
* </ul>
*
* The procedure for preparing Unicode strings:
* <ol>
* <li> Map: For each character in the input, check if it has a mapping
* and, if so, replace it with its mapping. </li>
* <li> Normalize: Possibly normalize the result of step 1 using Unicode
* normalization. </li>
* <li> Prohibit: Check for any characters that are not allowed in the
* output. If any are found, return an error.</li>
* <li> Check bidi: Possibly check for right-to-left characters, and if
* any are found, make sure that the whole string satisfies the
* requirements for bidirectional strings. If the string does not
* satisfy the requirements for bidirectional strings, return an
* error. </li>
* </ol>
* @author Ram Viswanadha
* @draft ICU 2.8
*/
public final class StringPrep {
/**
* Option to prohibit processing of unassigned code points in the input
*
* @see #prepare
* @draft ICU 2.8
*/
public static final int DEFAULT = 0x0000;
/**
* Option to allow processing of unassigned code points in the input
*
* @see #prepare
* @draft ICU 2.8
*/
public static final int ALLOW_UNASSIGNED = 0x0001;
private static final int UNASSIGNED = 0x0000;
private static final int MAP = 0x0001;
private static final int PROHIBITED = 0x0002;
private static final int DELETE = 0x0003;
private static final int TYPE_LIMIT = 0x0004;
private static final int NORMALIZATION_ON = 0x0001;
private static final int CHECK_BIDI_ON = 0x0002;
private static final int TYPE_THRESHOLD = 0xFFF0;
private static final int MAX_INDEX_VALUE = 0x3FBF; /*16139*/
private static final int MAX_INDEX_TOP_LENGTH = 0x0003;
/* indexes[] value names */
private static final int INDEX_TRIE_SIZE = 0; /* number of bytes in normalization trie */
private static final int INDEX_MAPPING_DATA_SIZE = 1; /* The array that contains the mapping */
private static final int NORM_CORRECTNS_LAST_UNI_VERSION = 2; /* The index of Unicode version of last entry in NormalizationCorrections.txt */
private static final int ONE_UCHAR_MAPPING_INDEX_START = 3; /* The starting index of 1 UChar mapping index in the mapping data array */
private static final int TWO_UCHARS_MAPPING_INDEX_START = 4; /* The starting index of 2 UChars mapping index in the mapping data array */
private static final int THREE_UCHARS_MAPPING_INDEX_START = 5;
private static final int FOUR_UCHARS_MAPPING_INDEX_START = 6;
private static final int OPTIONS = 7; /* Bit set of options to turn on in the profile */
private static final int INDEX_TOP = 16; /* changing this requires a new formatVersion */
/**
* Default buffer size of datafile
*/
private static final int DATA_BUFFER_SIZE = 25000;
/* Wrappers for Trie implementations */
private static final class StringPrepTrieImpl implements Trie.DataManipulate{
private CharTrie sprepTrie = null;
/**
* Called by com.ibm.icu.util.Trie to extract from a lead surrogate's
* data the index array offset of the indexes for that lead surrogate.
* @param property data value for a surrogate from the trie, including
* the folding offset
* @return data offset or 0 if there is no data for the lead surrogate
*/
public int getFoldingOffset(int value){
return value;
}
}
// CharTrie implementation for reading the trie data
private StringPrepTrieImpl sprepTrieImpl;
// Indexes read from the data file
private int[] indexes;
// mapping data read from the data file
private char[] mappingData;
// format version of the data file
private byte[] formatVersion;
// the version of Unicode supported by the data file
private VersionInfo sprepUniVer;
// the Unicode version of last entry in the
// NormalizationCorrections.txt file if normalization
// is turned on
private VersionInfo normCorrVer;
// Option to turn on Normalization
private boolean doNFKC;
// Option to turn on checking for BiDi rules
private boolean checkBiDi;
private char getCodePointValue(int ch){
return sprepTrieImpl.sprepTrie.getCodePointValue(ch);
}
private static VersionInfo getVersionInfo(int comp){
int micro = comp & 0xFF;
int milli =(comp >> 8) & 0xFF;
int minor =(comp >> 16) & 0xFF;
int major =(comp >> 24) & 0xFF;
return VersionInfo.getInstance(major,minor,milli,micro);
}
private static VersionInfo getVersionInfo(byte[] version){
if(version.length != 4){
return null;
}
return VersionInfo.getInstance((int)version[0],(int) version[1],(int) version[2],(int) version[3]);
}
/**
* Creates an StringPrep object after reading the input stream.
* The object does not hold a reference to the input steam, so the stream can be
* closed after the method returns.
*
* @param inputStream The stream for reading the StringPrep profile binarySun
* @throws IOException
* @draft ICU 2.8
*/
public StringPrep(InputStream inputStream) throws IOException{
BufferedInputStream b = new BufferedInputStream(inputStream,DATA_BUFFER_SIZE);
StringPrepDataReader reader = new StringPrepDataReader(b);
// read the indexes
indexes = reader.readIndexes(INDEX_TOP);
byte[] sprepBytes = new byte[indexes[INDEX_TRIE_SIZE]];
//indexes[INDEX_MAPPING_DATA_SIZE] store the size of mappingData in bytes
mappingData = new char[indexes[INDEX_MAPPING_DATA_SIZE]/2];
// load the rest of the data data and initialize the data members
reader.read(sprepBytes,mappingData);
sprepTrieImpl = new StringPrepTrieImpl();
sprepTrieImpl.sprepTrie = new CharTrie( new ByteArrayInputStream(sprepBytes),sprepTrieImpl );
// get the data format version
formatVersion = reader.getDataFormatVersion();
// get the options
doNFKC = ((indexes[OPTIONS] & NORMALIZATION_ON) > 0);
checkBiDi = ((indexes[OPTIONS] & CHECK_BIDI_ON) > 0);
sprepUniVer = getVersionInfo(reader.getUnicodeVersion());
normCorrVer = getVersionInfo(indexes[NORM_CORRECTNS_LAST_UNI_VERSION]);
VersionInfo normUniVer = NormalizerImpl.getUnicodeVersion();
if(normUniVer.compareTo(sprepUniVer) < 0 && /* the Unicode version of SPREP file must be less than the Unicode Vesion of the normalization data */
normUniVer.compareTo(normCorrVer) < 0 && /* the Unicode version of the NormalizationCorrections.txt file should be less than the Unicode Vesion of the normalization data */
((indexes[OPTIONS] & NORMALIZATION_ON) > 0) /* normalization turned on*/
){
throw new IOException("Normalization Correction version not supported");
}
b.close();
}
private static final class Values{
boolean isIndex;
int value;
int type;
public void reset(){
isIndex = false;
value = 0;
type = -1;
}
}
private static final void getValues(char trieWord,Values values){
values.reset();
if(trieWord == 0){
/*
* Initial value stored in the mapping table
* just return TYPE_LIMIT .. so that
* the source codepoint is copied to the destination
*/
values.type = TYPE_LIMIT;
}else if(trieWord >= TYPE_THRESHOLD){
values.type = (trieWord - TYPE_THRESHOLD);
}else{
/* get the type */
values.type = MAP;
/* ascertain if the value is index or delta */
if((trieWord & 0x02)>0){
values.isIndex = true;
values.value = trieWord >> 2; //mask off the lower 2 bits and shift
}else{
values.isIndex = false;
values.value = (trieWord<<16)>>16;
values.value = (values.value >> 2);
}
if((trieWord>>2) == MAX_INDEX_VALUE){
values.type = DELETE;
values.isIndex = false;
values.value = 0;
}
}
}
private StringBuffer map( UCharacterIterator iter, int options)
throws ParseException {
Values val = new Values();
char result = 0;
int ch = UCharacterIterator.DONE;
StringBuffer dest = new StringBuffer();
boolean allowUnassigned = ((options & ALLOW_UNASSIGNED)>0);
while((ch=iter.nextCodePoint())!= UCharacterIterator.DONE){
result = getCodePointValue(ch);
getValues(result,val);
// check if the source codepoint is unassigned
if(val.type == UNASSIGNED && allowUnassigned == false){
throw new ParseException("An unassigned code point was found in the input " +
iter.getText(), iter.getIndex());
}else if((val.type == MAP)){
int index, length;
if(val.isIndex){
index = val.value;
if(index >= indexes[ONE_UCHAR_MAPPING_INDEX_START] &&
index < indexes[TWO_UCHARS_MAPPING_INDEX_START]){
length = 1;
}else if(index >= indexes[TWO_UCHARS_MAPPING_INDEX_START] &&
index < indexes[THREE_UCHARS_MAPPING_INDEX_START]){
length = 2;
}else if(index >= indexes[THREE_UCHARS_MAPPING_INDEX_START] &&
index < indexes[FOUR_UCHARS_MAPPING_INDEX_START]){
length = 3;
}else{
length = mappingData[index++];
}
/* copy mapping to destination */
dest.append(mappingData,index,length);
continue;
}else{
ch -= val.value;
}
}else if(val.type == DELETE){
// just consume the codepoint and contine
continue;
}
//copy the source into destination
UTF16.append(dest,ch);
}
return dest;
}
private StringBuffer normalize(StringBuffer src){
/*
* Option UNORM_BEFORE_PRI_29:
*
* IDNA as interpreted by IETF members (see unicode mailing list 2004H1)
* requires strict adherence to Unicode 3.2 normalization,
* including buggy composition from before fixing Public Review Issue #29.
* Note that this results in some valid but nonsensical text to be
* either corrupted or rejected, depending on the text.
* See http://www.unicode.org/review/resolved-pri.html#pri29
* See unorm.cpp and cnormtst.c
*/
return new StringBuffer(
Normalizer.normalize(
src.toString(),
java.text.Normalizer.Form.NFKC,
Normalizer.UNICODE_3_2|NormalizerImpl.BEFORE_PRI_29));
}
/*
boolean isLabelSeparator(int ch){
int result = getCodePointValue(ch);
if( (result & 0x07) == LABEL_SEPARATOR){
return true;
}
return false;
}
*/
/*
1) Map -- For each character in the input, check if it has a mapping
and, if so, replace it with its mapping.
2) Normalize -- Possibly normalize the result of step 1 using Unicode
normalization.
3) Prohibit -- Check for any characters that are not allowed in the
output. If any are found, return an error.
4) Check bidi -- Possibly check for right-to-left characters, and if
any are found, make sure that the whole string satisfies the
requirements for bidirectional strings. If the string does not
satisfy the requirements for bidirectional strings, return an
error.
[Unicode3.2] defines several bidirectional categories; each character
has one bidirectional category assigned to it. For the purposes of
the requirements below, an "RandALCat character" is a character that
has Unicode bidirectional categories "R" or "AL"; an "LCat character"
is a character that has Unicode bidirectional category "L". Note
that there are many characters which fall in neither of the above
definitions; Latin digits (<U+0030> through <U+0039>) are examples of
this because they have bidirectional category "EN".
In any profile that specifies bidirectional character handling, all
three of the following requirements MUST be met:
1) The characters in section 5.8 MUST be prohibited.
2) If a string contains any RandALCat character, the string MUST NOT
contain any LCat character.
3) If a string contains any RandALCat character, a RandALCat
character MUST be the first character of the string, and a
RandALCat character MUST be the last character of the string.
*/
/**
* Prepare the input buffer for use in applications with the given profile. This operation maps, normalizes(NFKC),
* checks for prohited and BiDi characters in the order defined by RFC 3454
* depending on the options specified in the profile.
*
* @param src A UCharacterIterator object containing the source string
* @param options A bit set of options:
*
* - StringPrep.NONE Prohibit processing of unassigned code points in the input
*
* - StringPrep.ALLOW_UNASSIGNED Treat the unassigned code points are in the input
* as normal Unicode code points.
*
* @return StringBuffer A StringBuffer containing the output
* @throws ParseException
* @draft ICU 2.8
*/
public StringBuffer prepare(UCharacterIterator src, int options)
throws ParseException{
// map
StringBuffer mapOut = map(src,options);
StringBuffer normOut = mapOut;// initialize
if(doNFKC){
// normalize
normOut = normalize(mapOut);
}
int ch;
char result;
UCharacterIterator iter = UCharacterIterator.getInstance(normOut);
Values val = new Values();
int direction=UCharacterDirection.CHAR_DIRECTION_COUNT,
firstCharDir=UCharacterDirection.CHAR_DIRECTION_COUNT;
int rtlPos=-1, ltrPos=-1;
boolean rightToLeft=false, leftToRight=false;
while((ch=iter.nextCodePoint())!= UCharacterIterator.DONE){
result = getCodePointValue(ch);
getValues(result,val);
if(val.type == PROHIBITED ){
throw new ParseException("A prohibited code point was found in the input" +
iter.getText(), val.value);
}
direction = UCharacter.getDirection(ch);
if(firstCharDir == UCharacterDirection.CHAR_DIRECTION_COUNT){
firstCharDir = direction;
}
if(direction == UCharacterDirection.LEFT_TO_RIGHT){
leftToRight = true;
ltrPos = iter.getIndex()-1;
}
if(direction == UCharacterDirection.RIGHT_TO_LEFT || direction == UCharacterDirection.RIGHT_TO_LEFT_ARABIC){
rightToLeft = true;
rtlPos = iter.getIndex()-1;
}
}
if(checkBiDi == true){
// satisfy 2
if( leftToRight == true && rightToLeft == true){
throw new ParseException("The input does not conform to the rules for BiDi code points." +
iter.getText(),
(rtlPos>ltrPos) ? rtlPos : ltrPos);
}
//satisfy 3
if( rightToLeft == true &&
!((firstCharDir == UCharacterDirection.RIGHT_TO_LEFT || firstCharDir == UCharacterDirection.RIGHT_TO_LEFT_ARABIC) &&
(direction == UCharacterDirection.RIGHT_TO_LEFT || direction == UCharacterDirection.RIGHT_TO_LEFT_ARABIC))
){
throw new ParseException("The input does not conform to the rules for BiDi code points." +
iter.getText(),
(rtlPos>ltrPos) ? rtlPos : ltrPos);
}
}
return normOut;
}
}

View File

@@ -0,0 +1,127 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
/*
******************************************************************************
* Copyright (C) 2003, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*
* Created on May 2, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
// CHANGELOG
// 2005-05-19 Edward Wang
// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/impl/StringPrepDataReader.java
// - move from package com.ibm.icu.impl to package sun.net.idn
//
package sun.net.idn;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import sun.text.normalizer.ICUBinary;
/**
* @author ram
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
final class StringPrepDataReader implements ICUBinary.Authenticate {
/**
* <p>private constructor.</p>
* @param inputStream ICU uprop.dat file input stream
* @exception IOException throw if data file fails authentication
* @draft 2.1
*/
public StringPrepDataReader(InputStream inputStream)
throws IOException{
unicodeVersion = ICUBinary.readHeader(inputStream, DATA_FORMAT_ID, this);
dataInputStream = new DataInputStream(inputStream);
}
public void read(byte[] idnaBytes,
char[] mappingTable)
throws IOException{
//Read the bytes that make up the idnaTrie
dataInputStream.read(idnaBytes);
//Read the extra data
for(int i=0;i<mappingTable.length;i++){
mappingTable[i]=dataInputStream.readChar();
}
}
public byte[] getDataFormatVersion(){
return DATA_FORMAT_VERSION;
}
public boolean isDataVersionAcceptable(byte version[]){
return version[0] == DATA_FORMAT_VERSION[0]
&& version[2] == DATA_FORMAT_VERSION[2]
&& version[3] == DATA_FORMAT_VERSION[3];
}
public int[] readIndexes(int length)throws IOException{
int[] indexes = new int[length];
//Read the indexes
for (int i = 0; i <length ; i++) {
indexes[i] = dataInputStream.readInt();
}
return indexes;
}
public byte[] getUnicodeVersion(){
return unicodeVersion;
}
// private data members -------------------------------------------------
/**
* ICU data file input stream
*/
private DataInputStream dataInputStream;
private byte[] unicodeVersion;
/**
* File format version that this class understands.
* No guarantees are made if a older version is used
* see store.c of gennorm for more information and values
*/
///* dataFormat="SPRP" 0x53, 0x50, 0x52, 0x50 */
private static final byte DATA_FORMAT_ID[] = {(byte)0x53, (byte)0x50,
(byte)0x52, (byte)0x50};
private static final byte DATA_FORMAT_VERSION[] = {(byte)0x3, (byte)0x2,
(byte)0x5, (byte)0x2};
}

View File

@@ -0,0 +1,111 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
/**
*******************************************************************************
* Copyright (C) 1996-2004, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
// CHANGELOG
// 2005-05-19 Edward Wang
// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/lang/UCharacterDirection.java
// - move from package com.ibm.icu.lang to package sun.net.idn
//
package sun.net.idn;
/**
* Enumerated Unicode character linguistic direction constants.
* Used as return results from <a href=UCharacter.html>UCharacter</a>
* <p>
* This class is not subclassable
* </p>
* @author Syn Wee Quek
* @stable ICU 2.1
*/
final class UCharacterDirection implements UCharacterEnums.ECharacterDirection {
// private constructor =========================================
///CLOVER:OFF
/**
* Private constructor to prevent initialisation
*/
private UCharacterDirection()
{
}
///CLOVER:ON
/**
* Gets the name of the argument direction
* @param dir direction type to retrieve name
* @return directional name
* @stable ICU 2.1
*/
public static String toString(int dir) {
switch(dir)
{
case LEFT_TO_RIGHT :
return "Left-to-Right";
case RIGHT_TO_LEFT :
return "Right-to-Left";
case EUROPEAN_NUMBER :
return "European Number";
case EUROPEAN_NUMBER_SEPARATOR :
return "European Number Separator";
case EUROPEAN_NUMBER_TERMINATOR :
return "European Number Terminator";
case ARABIC_NUMBER :
return "Arabic Number";
case COMMON_NUMBER_SEPARATOR :
return "Common Number Separator";
case BLOCK_SEPARATOR :
return "Paragraph Separator";
case SEGMENT_SEPARATOR :
return "Segment Separator";
case WHITE_SPACE_NEUTRAL :
return "Whitespace";
case OTHER_NEUTRAL :
return "Other Neutrals";
case LEFT_TO_RIGHT_EMBEDDING :
return "Left-to-Right Embedding";
case LEFT_TO_RIGHT_OVERRIDE :
return "Left-to-Right Override";
case RIGHT_TO_LEFT_ARABIC :
return "Right-to-Left Arabic";
case RIGHT_TO_LEFT_EMBEDDING :
return "Right-to-Left Embedding";
case RIGHT_TO_LEFT_OVERRIDE :
return "Right-to-Left Override";
case POP_DIRECTIONAL_FORMAT :
return "Pop Directional Format";
case DIR_NON_SPACING_MARK :
return "Non-Spacing Mark";
case BOUNDARY_NEUTRAL :
return "Boundary Neutral";
}
return "Unassigned";
}
}

View File

@@ -0,0 +1,587 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
/**
*******************************************************************************
* Copyright (C) 2004, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
// CHANGELOG
// 2005-05-19 Edward Wang
// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/lang/UCharacterEnums.java
// - move from package com.ibm.icu.lang to package sun.net.idn
//
// 2011-09-06 Kurchi Subhra Hazra
// - Added @Deprecated tag to the following:
// - class UCharacterEnums
// - interfaces ECharacterCategory, ECharacterDirection
// - fields INITIAL_QUOTE_PUNCTUATION, FINAL_QUOTE_PUNCTUATION,
// DIRECTIONALITY_LEFT_TO_RIGHT, DIRECTIONALITY_RIGHT_TO_LEFT,
// DIRECTIONALITY_EUROPEAN_NUMBER, DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR
// DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR, DIRECTIONALITY_ARABIC_NUMBER,
// DIRECTIONALITY_COMMON_NUMBER_SEPARATOR, DIRECTIONALITY_PARAGRAPH_SEPARATOR,
// DIRECTIONALITY_SEGMENT_SEPARATOR, DIRECTIONALITY_WHITESPACE,
// DIRECTIONALITY_OTHER_NEUTRALS, DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING,
// DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE, DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC,
// DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING, DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE,
// DIRECTIONALITY_POP_DIRECTIONAL_FORMAT, DIRECTIONALITY_NON_SPACING_MARK,
// DIRECTIONALITY_BOUNDARY_NEUTRAL, DIRECTIONALITY_UNDEFINED
//
package sun.net.idn;
/**
* A container for the different 'enumerated types' used by UCharacter.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
class UCharacterEnums {
/** This is just a namespace, it is not instantiatable. */
private UCharacterEnums() {};
/**
* 'Enum' for the CharacterCategory constants. These constants are
* compatible in name <b>but not in value</b> with those defined in
* <code>java.lang.Character</code>.
* @see UCharacterCategory
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static interface ECharacterCategory {
/**
* Unassigned character type
* @stable ICU 2.1
*/
public static final int UNASSIGNED = 0;
/**
* Character type Cn
* Not Assigned (no characters in [UnicodeData.txt] have this property)
* @stable ICU 2.6
*/
public static final int GENERAL_OTHER_TYPES = 0;
/**
* Character type Lu
* @stable ICU 2.1
*/
public static final int UPPERCASE_LETTER = 1;
/**
* Character type Ll
* @stable ICU 2.1
*/
public static final int LOWERCASE_LETTER = 2;
/**
* Character type Lt
* @stable ICU 2.1
*/
public static final int TITLECASE_LETTER = 3;
/**
* Character type Lm
* @stable ICU 2.1
*/
public static final int MODIFIER_LETTER = 4;
/**
* Character type Lo
* @stable ICU 2.1
*/
public static final int OTHER_LETTER = 5;
/**
* Character type Mn
* @stable ICU 2.1
*/
public static final int NON_SPACING_MARK = 6;
/**
* Character type Me
* @stable ICU 2.1
*/
public static final int ENCLOSING_MARK = 7;
/**
* Character type Mc
* @stable ICU 2.1
*/
public static final int COMBINING_SPACING_MARK = 8;
/**
* Character type Nd
* @stable ICU 2.1
*/
public static final int DECIMAL_DIGIT_NUMBER = 9;
/**
* Character type Nl
* @stable ICU 2.1
*/
public static final int LETTER_NUMBER = 10;
/**
* Character type No
* @stable ICU 2.1
*/
public static final int OTHER_NUMBER = 11;
/**
* Character type Zs
* @stable ICU 2.1
*/
public static final int SPACE_SEPARATOR = 12;
/**
* Character type Zl
* @stable ICU 2.1
*/
public static final int LINE_SEPARATOR = 13;
/**
* Character type Zp
* @stable ICU 2.1
*/
public static final int PARAGRAPH_SEPARATOR = 14;
/**
* Character type Cc
* @stable ICU 2.1
*/
public static final int CONTROL = 15;
/**
* Character type Cf
* @stable ICU 2.1
*/
public static final int FORMAT = 16;
/**
* Character type Co
* @stable ICU 2.1
*/
public static final int PRIVATE_USE = 17;
/**
* Character type Cs
* @stable ICU 2.1
*/
public static final int SURROGATE = 18;
/**
* Character type Pd
* @stable ICU 2.1
*/
public static final int DASH_PUNCTUATION = 19;
/**
* Character type Ps
* @stable ICU 2.1
*/
public static final int START_PUNCTUATION = 20;
/**
* Character type Pe
* @stable ICU 2.1
*/
public static final int END_PUNCTUATION = 21;
/**
* Character type Pc
* @stable ICU 2.1
*/
public static final int CONNECTOR_PUNCTUATION = 22;
/**
* Character type Po
* @stable ICU 2.1
*/
public static final int OTHER_PUNCTUATION = 23;
/**
* Character type Sm
* @stable ICU 2.1
*/
public static final int MATH_SYMBOL = 24;
/**
* Character type Sc
* @stable ICU 2.1
*/
public static final int CURRENCY_SYMBOL = 25;
/**
* Character type Sk
* @stable ICU 2.1
*/
public static final int MODIFIER_SYMBOL = 26;
/**
* Character type So
* @stable ICU 2.1
*/
public static final int OTHER_SYMBOL = 27;
/**
* Character type Pi
* @see #INITIAL_QUOTE_PUNCTUATION
* @stable ICU 2.1
*/
public static final int INITIAL_PUNCTUATION = 28;
/**
* Character type Pi
* This name is compatible with java.lang.Character's name for this type.
* @see #INITIAL_PUNCTUATION
* @draft ICU 2.8
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final int INITIAL_QUOTE_PUNCTUATION = 28;
/**
* Character type Pf
* @see #FINAL_QUOTE_PUNCTUATION
* @stable ICU 2.1
*/
public static final int FINAL_PUNCTUATION = 29;
/**
* Character type Pf
* This name is compatible with java.lang.Character's name for this type.
* @see #FINAL_PUNCTUATION
* @draft ICU 2.8
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final int FINAL_QUOTE_PUNCTUATION = 29;
/**
* Character type count
* @stable ICU 2.1
*/
public static final int CHAR_CATEGORY_COUNT = 30;
}
/**
* 'Enum' for the CharacterDirection constants. There are two sets
* of names, those used in ICU, and those used in the JDK. The
* JDK constants are compatible in name <b>but not in value</b>
* with those defined in <code>java.lang.Character</code>.
* @see UCharacterDirection
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static interface ECharacterDirection {
/**
* Directional type L
* @stable ICU 2.1
*/
public static final int LEFT_TO_RIGHT = 0;
/**
* JDK-compatible synonum for LEFT_TO_RIGHT.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_LEFT_TO_RIGHT = (byte)LEFT_TO_RIGHT;
/**
* Directional type R
* @stable ICU 2.1
*/
public static final int RIGHT_TO_LEFT = 1;
/**
* JDK-compatible synonum for RIGHT_TO_LEFT.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_RIGHT_TO_LEFT = (byte)RIGHT_TO_LEFT;
/**
* Directional type EN
* @stable ICU 2.1
*/
public static final int EUROPEAN_NUMBER = 2;
/**
* JDK-compatible synonum for EUROPEAN_NUMBER.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_EUROPEAN_NUMBER = (byte)EUROPEAN_NUMBER;
/**
* Directional type ES
* @stable ICU 2.1
*/
public static final int EUROPEAN_NUMBER_SEPARATOR = 3;
/**
* JDK-compatible synonum for EUROPEAN_NUMBER_SEPARATOR.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = (byte)EUROPEAN_NUMBER_SEPARATOR;
/**
* Directional type ET
* @stable ICU 2.1
*/
public static final int EUROPEAN_NUMBER_TERMINATOR = 4;
/**
* JDK-compatible synonum for EUROPEAN_NUMBER_TERMINATOR.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = (byte)EUROPEAN_NUMBER_TERMINATOR;
/**
* Directional type AN
* @stable ICU 2.1
*/
public static final int ARABIC_NUMBER = 5;
/**
* JDK-compatible synonum for ARABIC_NUMBER.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_ARABIC_NUMBER = (byte)ARABIC_NUMBER;
/**
* Directional type CS
* @stable ICU 2.1
*/
public static final int COMMON_NUMBER_SEPARATOR = 6;
/**
* JDK-compatible synonum for COMMON_NUMBER_SEPARATOR.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = (byte)COMMON_NUMBER_SEPARATOR;
/**
* Directional type B
* @stable ICU 2.1
*/
public static final int BLOCK_SEPARATOR = 7;
/**
* JDK-compatible synonum for BLOCK_SEPARATOR.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_PARAGRAPH_SEPARATOR = (byte)BLOCK_SEPARATOR;
/**
* Directional type S
* @stable ICU 2.1
*/
public static final int SEGMENT_SEPARATOR = 8;
/**
* JDK-compatible synonum for SEGMENT_SEPARATOR.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_SEGMENT_SEPARATOR = (byte)SEGMENT_SEPARATOR;
/**
* Directional type WS
* @stable ICU 2.1
*/
public static final int WHITE_SPACE_NEUTRAL = 9;
/**
* JDK-compatible synonum for WHITE_SPACE_NEUTRAL.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_WHITESPACE = (byte)WHITE_SPACE_NEUTRAL;
/**
* Directional type ON
* @stable ICU 2.1
*/
public static final int OTHER_NEUTRAL = 10;
/**
* JDK-compatible synonum for OTHER_NEUTRAL.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_OTHER_NEUTRALS = (byte)OTHER_NEUTRAL;
/**
* Directional type LRE
* @stable ICU 2.1
*/
public static final int LEFT_TO_RIGHT_EMBEDDING = 11;
/**
* JDK-compatible synonum for LEFT_TO_RIGHT_EMBEDDING.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = (byte)LEFT_TO_RIGHT_EMBEDDING;
/**
* Directional type LRO
* @stable ICU 2.1
*/
public static final int LEFT_TO_RIGHT_OVERRIDE = 12;
/**
* JDK-compatible synonum for LEFT_TO_RIGHT_OVERRIDE.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = (byte)LEFT_TO_RIGHT_OVERRIDE;
/**
* Directional type AL
* @stable ICU 2.1
*/
public static final int RIGHT_TO_LEFT_ARABIC = 13;
/**
* JDK-compatible synonum for RIGHT_TO_LEFT_ARABIC.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = (byte)RIGHT_TO_LEFT_ARABIC;
/**
* Directional type RLE
* @stable ICU 2.1
*/
public static final int RIGHT_TO_LEFT_EMBEDDING = 14;
/**
* JDK-compatible synonum for RIGHT_TO_LEFT_EMBEDDING.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = (byte)RIGHT_TO_LEFT_EMBEDDING;
/**
* Directional type RLO
* @stable ICU 2.1
*/
public static final int RIGHT_TO_LEFT_OVERRIDE = 15;
/**
* JDK-compatible synonum for RIGHT_TO_LEFT_OVERRIDE.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = (byte)RIGHT_TO_LEFT_OVERRIDE;
/**
* Directional type PDF
* @stable ICU 2.1
*/
public static final int POP_DIRECTIONAL_FORMAT = 16;
/**
* JDK-compatible synonum for POP_DIRECTIONAL_FORMAT.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = (byte)POP_DIRECTIONAL_FORMAT;
/**
* Directional type NSM
* @stable ICU 2.1
*/
public static final int DIR_NON_SPACING_MARK = 17;
/**
* JDK-compatible synonum for DIR_NON_SPACING_MARK.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_NON_SPACING_MARK = (byte)DIR_NON_SPACING_MARK;
/**
* Directional type BN
* @stable ICU 2.1
*/
public static final int BOUNDARY_NEUTRAL = 18;
/**
* JDK-compatible synonum for BOUNDARY_NEUTRAL.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = (byte)BOUNDARY_NEUTRAL;
/**
* Number of directional types
* @stable ICU 2.1
*/
public static final int CHAR_DIRECTION_COUNT = 19;
/**
* Undefined bidirectional character type. Undefined <code>char</code>
* values have undefined directionality in the Unicode specification.
* @draft ICU 3.0
* @deprecated This is a draft API and might change in a future release of ICU.
*/
@Deprecated
public static final byte DIRECTIONALITY_UNDEFINED = -1;
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.sdp;
import java.io.IOException;
import java.io.FileDescriptor;
import java.security.AccessController;
import sun.misc.SharedSecrets;
import sun.misc.JavaIOFileDescriptorAccess;
/**
* This class defines methods for creating SDP sockets or "converting" existing
* file descriptors, referencing (unbound) TCP sockets, to SDP.
*/
public final class SdpSupport {
private static final String os = AccessController
.doPrivileged(new sun.security.action.GetPropertyAction("os.name"));
private static final boolean isSupported = (os.equals("SunOS") || (os.equals("Linux")));
private static final JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess();
private SdpSupport() { }
/**
* Creates a SDP socket, returning file descriptor referencing the socket.
*/
public static FileDescriptor createSocket() throws IOException {
if (!isSupported)
throw new UnsupportedOperationException("SDP not supported on this platform");
int fdVal = create0();
FileDescriptor fd = new FileDescriptor();
fdAccess.set(fd, fdVal);
return fd;
}
/**
* Converts an existing file descriptor, that references an unbound TCP socket,
* to SDP.
*/
public static void convertSocket(FileDescriptor fd) throws IOException {
if (!isSupported)
throw new UnsupportedOperationException("SDP not supported on this platform");
int fdVal = fdAccess.get(fd);
convert0(fdVal);
}
private static native int create0() throws IOException;
private static native void convert0(int fd) throws IOException;
static {
AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("net");
return null;
}
});
}
}

View File

@@ -0,0 +1,291 @@
/*
* Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.smtp;
import java.util.StringTokenizer;
import java.io.*;
import java.net.*;
import sun.net.TransferProtocolClient;
/**
* This class implements the SMTP client.
* You can send a piece of mail by creating a new SmtpClient, calling
* the "to" method to add destinations, calling "from" to name the
* sender, calling startMessage to return a stream to which you write
* the message (with RFC733 headers) and then you finally close the Smtp
* Client.
*
* @author James Gosling
*/
public class SmtpClient extends TransferProtocolClient {
private static int DEFAULT_SMTP_PORT = 25;
String mailhost;
SmtpPrintStream message;
/**
* issue the QUIT command to the SMTP server and close the connection.
*/
public void closeServer() throws IOException {
if (serverIsOpen()) {
closeMessage();
issueCommand("QUIT\r\n", 221);
super.closeServer();
}
}
void issueCommand(String cmd, int expect) throws IOException {
sendServer(cmd);
int reply;
while ((reply = readServerResponse()) != expect)
if (reply != 220) {
throw new SmtpProtocolException(getResponseString());
}
}
private void toCanonical(String s) throws IOException {
if (s.startsWith("<"))
issueCommand("rcpt to: " + s + "\r\n", 250);
else
issueCommand("rcpt to: <" + s + ">\r\n", 250);
}
public void to(String s) throws IOException {
if (s.indexOf('\n') != -1) {
throw new IOException("Illegal SMTP command",
new IllegalArgumentException("Illegal carriage return"));
}
int st = 0;
int limit = s.length();
int pos = 0;
int lastnonsp = 0;
int parendepth = 0;
boolean ignore = false;
while (pos < limit) {
int c = s.charAt(pos);
if (parendepth > 0) {
if (c == '(')
parendepth++;
else if (c == ')')
parendepth--;
if (parendepth == 0)
if (lastnonsp > st)
ignore = true;
else
st = pos + 1;
} else if (c == '(')
parendepth++;
else if (c == '<')
st = lastnonsp = pos + 1;
else if (c == '>')
ignore = true;
else if (c == ',') {
if (lastnonsp > st)
toCanonical(s.substring(st, lastnonsp));
st = pos + 1;
ignore = false;
} else {
if (c > ' ' && !ignore)
lastnonsp = pos + 1;
else if (st == pos)
st++;
}
pos++;
}
if (lastnonsp > st)
toCanonical(s.substring(st, lastnonsp));
}
public void from(String s) throws IOException {
if (s.indexOf('\n') != -1) {
throw new IOException("Illegal SMTP command",
new IllegalArgumentException("Illegal carriage return"));
}
if (s.startsWith("<")) {
issueCommand("mail from: " + s + "\r\n", 250);
} else {
issueCommand("mail from: <" + s + ">\r\n", 250);
}
}
/** open a SMTP connection to host <i>host</i>. */
private void openServer(String host) throws IOException {
mailhost = host;
openServer(mailhost, DEFAULT_SMTP_PORT);
issueCommand("helo "+InetAddress.getLocalHost().getHostName()+"\r\n", 250);
}
public PrintStream startMessage() throws IOException {
issueCommand("data\r\n", 354);
try {
message = new SmtpPrintStream(serverOutput, this);
} catch (UnsupportedEncodingException e) {
throw new InternalError(encoding+" encoding not found", e);
}
return message;
}
void closeMessage() throws IOException {
if (message != null)
message.close();
}
/** New SMTP client connected to host <i>host</i>. */
public SmtpClient (String host) throws IOException {
super();
if (host != null) {
try {
openServer(host);
mailhost = host;
return;
} catch(Exception e) {
}
}
try {
String s;
mailhost = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("mail.host"));
if (mailhost != null) {
openServer(mailhost);
return;
}
} catch(Exception e) {
}
try {
mailhost = "localhost";
openServer(mailhost);
} catch(Exception e) {
mailhost = "mailhost";
openServer(mailhost);
}
}
/** Create an uninitialized SMTP client. */
public SmtpClient () throws IOException {
this(null);
}
public SmtpClient(int to) throws IOException {
super();
setConnectTimeout(to);
try {
String s;
mailhost = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("mail.host"));
if (mailhost != null) {
openServer(mailhost);
return;
}
} catch(Exception e) {
}
try {
mailhost = "localhost";
openServer(mailhost);
} catch(Exception e) {
mailhost = "mailhost";
openServer(mailhost);
}
}
public String getMailHost() {
return mailhost;
}
String getEncoding () {
return encoding;
}
}
class SmtpPrintStream extends java.io.PrintStream {
private SmtpClient target;
private int lastc = '\n';
SmtpPrintStream (OutputStream fos, SmtpClient cl) throws UnsupportedEncodingException {
super(fos, false, cl.getEncoding());
target = cl;
}
public void close() {
if (target == null)
return;
if (lastc != '\n') {
write('\n');
}
try {
target.issueCommand(".\r\n", 250);
target.message = null;
out = null;
target = null;
} catch (IOException e) {
}
}
public void write(int b) {
try {
// quote a dot at the beginning of a line
if (lastc == '\n' && b == '.') {
out.write('.');
}
// translate NL to CRLF
if (b == '\n' && lastc != '\r') {
out.write('\r');
}
out.write(b);
lastc = b;
} catch (IOException e) {
}
}
public void write(byte b[], int off, int len) {
try {
int lc = lastc;
while (--len >= 0) {
int c = b[off++];
// quote a dot at the beginning of a line
if (lc == '\n' && c == '.')
out.write('.');
// translate NL to CRLF
if (c == '\n' && lc != '\r') {
out.write('\r');
}
out.write(c);
lc = c;
}
lastc = lc;
} catch (IOException e) {
}
}
public void print(String s) {
int len = s.length();
for (int i = 0; i < len; i++) {
write(s.charAt(i));
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.smtp;
import java.io.IOException;
/**
* This exception is thrown when unexpected results are returned during
* an SMTP session.
*/
public class SmtpProtocolException extends IOException {
private static final long serialVersionUID = -7547136771133814908L;
SmtpProtocolException(String s) {
super(s);
}
}

View File

@@ -0,0 +1,395 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.spi;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.StringJoiner;
import java.util.regex.Pattern;
import sun.net.NetProperties;
import sun.net.SocksProxy;
import static java.util.regex.Pattern.quote;
/**
* Supports proxy settings using system properties This proxy selector
* provides backward compatibility with the old http protocol handler
* as far as how proxy is set
*
* Most of the implementation copied from the old http protocol handler
*
* Supports http/https/ftp.proxyHost, http/https/ftp.proxyPort,
* proxyHost, proxyPort, and http/https/ftp.nonProxyHost, and socks.
* NOTE: need to do gopher as well
*/
public class DefaultProxySelector extends ProxySelector {
/**
* This is where we define all the valid System Properties we have to
* support for each given protocol.
* The format of this 2 dimensional array is :
* - 1 row per protocol (http, ftp, ...)
* - 1st element of each row is the protocol name
* - subsequent elements are prefixes for Host & Port properties
* listed in order of priority.
* Example:
* {"ftp", "ftp.proxy", "ftpProxy", "proxy", "socksProxy"},
* means for FTP we try in that oder:
* + ftp.proxyHost & ftp.proxyPort
* + ftpProxyHost & ftpProxyPort
* + proxyHost & proxyPort
* + socksProxyHost & socksProxyPort
*
* Note that the socksProxy should *always* be the last on the list
*/
final static String[][] props = {
/*
* protocol, Property prefix 1, Property prefix 2, ...
*/
{"http", "http.proxy", "proxy", "socksProxy"},
{"https", "https.proxy", "proxy", "socksProxy"},
{"ftp", "ftp.proxy", "ftpProxy", "proxy", "socksProxy"},
{"gopher", "gopherProxy", "socksProxy"},
{"socket", "socksProxy"}
};
private static final String SOCKS_PROXY_VERSION = "socksProxyVersion";
private static boolean hasSystemProxies = false;
static {
final String key = "java.net.useSystemProxies";
Boolean b = AccessController.doPrivileged(
new PrivilegedAction<Boolean>() {
public Boolean run() {
return NetProperties.getBoolean(key);
}});
if (b != null && b.booleanValue()) {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("net");
return null;
}
});
hasSystemProxies = init();
}
}
/**
* How to deal with "non proxy hosts":
* since we do have to generate a pattern we don't want to do that if
* it's not necessary. Therefore we do cache the result, on a per-protocol
* basis, and change it only when the "source", i.e. the system property,
* did change.
*/
static class NonProxyInfo {
// Default value for nonProxyHosts, this provides backward compatibility
// by excluding localhost and its litteral notations.
static final String defStringVal = "localhost|127.*|[::1]|0.0.0.0|[::0]";
String hostsSource;
Pattern pattern;
final String property;
final String defaultVal;
static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null, defStringVal);
static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null, defStringVal);
static NonProxyInfo socksNonProxyInfo = new NonProxyInfo("socksNonProxyHosts", null, null, defStringVal);
NonProxyInfo(String p, String s, Pattern pattern, String d) {
property = p;
hostsSource = s;
this.pattern = pattern;
defaultVal = d;
}
}
/**
* select() method. Where all the hard work is done.
* Build a list of proxies depending on URI.
* Since we're only providing compatibility with the system properties
* from previous releases (see list above), that list will always
* contain 1 single proxy, default being NO_PROXY.
*/
public java.util.List<Proxy> select(URI uri) {
if (uri == null) {
throw new IllegalArgumentException("URI can't be null.");
}
String protocol = uri.getScheme();
String host = uri.getHost();
if (host == null) {
// This is a hack to ensure backward compatibility in two
// cases: 1. hostnames contain non-ascii characters,
// internationalized domain names. in which case, URI will
// return null, see BugID 4957669; 2. Some hostnames can
// contain '_' chars even though it's not supposed to be
// legal, in which case URI will return null for getHost,
// but not for getAuthority() See BugID 4913253
String auth = uri.getAuthority();
if (auth != null) {
int i;
i = auth.indexOf('@');
if (i >= 0) {
auth = auth.substring(i+1);
}
i = auth.lastIndexOf(':');
if (i >= 0) {
auth = auth.substring(0,i);
}
host = auth;
}
}
if (protocol == null || host == null) {
throw new IllegalArgumentException("protocol = "+protocol+" host = "+host);
}
List<Proxy> proxyl = new ArrayList<Proxy>(1);
NonProxyInfo pinfo = null;
if ("http".equalsIgnoreCase(protocol)) {
pinfo = NonProxyInfo.httpNonProxyInfo;
} else if ("https".equalsIgnoreCase(protocol)) {
// HTTPS uses the same property as HTTP, for backward
// compatibility
pinfo = NonProxyInfo.httpNonProxyInfo;
} else if ("ftp".equalsIgnoreCase(protocol)) {
pinfo = NonProxyInfo.ftpNonProxyInfo;
} else if ("socket".equalsIgnoreCase(protocol)) {
pinfo = NonProxyInfo.socksNonProxyInfo;
}
/**
* Let's check the System properties for that protocol
*/
final String proto = protocol;
final NonProxyInfo nprop = pinfo;
final String urlhost = host.toLowerCase();
/**
* This is one big doPrivileged call, but we're trying to optimize
* the code as much as possible. Since we're checking quite a few
* System properties it does help having only 1 call to doPrivileged.
* Be mindful what you do in here though!
*/
Proxy p = AccessController.doPrivileged(
new PrivilegedAction<Proxy>() {
public Proxy run() {
int i, j;
String phost = null;
int pport = 0;
String nphosts = null;
InetSocketAddress saddr = null;
// Then let's walk the list of protocols in our array
for (i=0; i<props.length; i++) {
if (props[i][0].equalsIgnoreCase(proto)) {
for (j = 1; j < props[i].length; j++) {
/* System.getProp() will give us an empty
* String, "" for a defined but "empty"
* property.
*/
phost = NetProperties.get(props[i][j]+"Host");
if (phost != null && phost.length() != 0)
break;
}
if (phost == null || phost.length() == 0) {
/**
* No system property defined for that
* protocol. Let's check System Proxy
* settings (Gnome & Windows) if we were
* instructed to.
*/
if (hasSystemProxies) {
String sproto;
if (proto.equalsIgnoreCase("socket"))
sproto = "socks";
else
sproto = proto;
Proxy sproxy = getSystemProxy(sproto, urlhost);
if (sproxy != null) {
return sproxy;
}
}
return Proxy.NO_PROXY;
}
// If a Proxy Host is defined for that protocol
// Let's get the NonProxyHosts property
if (nprop != null) {
nphosts = NetProperties.get(nprop.property);
synchronized (nprop) {
if (nphosts == null) {
if (nprop.defaultVal != null) {
nphosts = nprop.defaultVal;
} else {
nprop.hostsSource = null;
nprop.pattern = null;
}
} else if (nphosts.length() != 0) {
// add the required default patterns
// but only if property no set. If it
// is empty, leave empty.
nphosts += "|" + NonProxyInfo
.defStringVal;
}
if (nphosts != null) {
if (!nphosts.equals(nprop.hostsSource)) {
nprop.pattern = toPattern(nphosts);
nprop.hostsSource = nphosts;
}
}
if (shouldNotUseProxyFor(nprop.pattern, urlhost)) {
return Proxy.NO_PROXY;
}
}
}
// We got a host, let's check for port
pport = NetProperties.getInteger(props[i][j]+"Port", 0).intValue();
if (pport == 0 && j < (props[i].length - 1)) {
// Can't find a port with same prefix as Host
// AND it's not a SOCKS proxy
// Let's try the other prefixes for that proto
for (int k = 1; k < (props[i].length - 1); k++) {
if ((k != j) && (pport == 0))
pport = NetProperties.getInteger(props[i][k]+"Port", 0).intValue();
}
}
// Still couldn't find a port, let's use default
if (pport == 0) {
if (j == (props[i].length - 1)) // SOCKS
pport = defaultPort("socket");
else
pport = defaultPort(proto);
}
// We did find a proxy definition.
// Let's create the address, but don't resolve it
// as this will be done at connection time
saddr = InetSocketAddress.createUnresolved(phost, pport);
// Socks is *always* the last on the list.
if (j == (props[i].length - 1)) {
int version = NetProperties.getInteger(SOCKS_PROXY_VERSION, 5).intValue();
return SocksProxy.create(saddr, version);
} else {
return new Proxy(Proxy.Type.HTTP, saddr);
}
}
}
return Proxy.NO_PROXY;
}});
proxyl.add(p);
/*
* If no specific property was set for that URI, we should be
* returning an iterator to an empty List.
*/
return proxyl;
}
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
if (uri == null || sa == null || ioe == null) {
throw new IllegalArgumentException("Arguments can't be null.");
}
// ignored
}
private int defaultPort(String protocol) {
if ("http".equalsIgnoreCase(protocol)) {
return 80;
} else if ("https".equalsIgnoreCase(protocol)) {
return 443;
} else if ("ftp".equalsIgnoreCase(protocol)) {
return 80;
} else if ("socket".equalsIgnoreCase(protocol)) {
return 1080;
} else if ("gopher".equalsIgnoreCase(protocol)) {
return 80;
} else {
return -1;
}
}
private native static boolean init();
private synchronized native Proxy getSystemProxy(String protocol, String host);
/**
* @return {@code true} if given this pattern for non-proxy hosts and this
* urlhost the proxy should NOT be used to access this urlhost
*/
static boolean shouldNotUseProxyFor(Pattern pattern, String urlhost) {
if (pattern == null || urlhost.isEmpty())
return false;
boolean matches = pattern.matcher(urlhost).matches();
return matches;
}
/**
* @param mask non-null mask
* @return {@link java.util.regex.Pattern} corresponding to this mask
* or {@code null} in case mask should not match anything
*/
static Pattern toPattern(String mask) {
boolean disjunctionEmpty = true;
StringJoiner joiner = new StringJoiner("|");
for (String disjunct : mask.split("\\|")) {
if (disjunct.isEmpty())
continue;
disjunctionEmpty = false;
String regex = disjunctToRegex(disjunct.toLowerCase());
joiner.add(regex);
}
return disjunctionEmpty ? null : Pattern.compile(joiner.toString());
}
/**
* @param disjunct non-null mask disjunct
* @return java regex string corresponding to this mask
*/
static String disjunctToRegex(String disjunct) {
String regex;
if (disjunct.startsWith("*")) {
regex = ".*" + quote(disjunct.substring(1));
} else if (disjunct.endsWith("*")) {
regex = quote(disjunct.substring(0, disjunct.length() - 1)) + ".*";
} else {
regex = quote(disjunct);
}
return regex;
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.spi.nameservice;
import java.net.UnknownHostException;
public interface NameService {
public java.net.InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException;
public String getHostByAddr(byte[] addr) throws UnknownHostException;
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.spi.nameservice;
public interface NameServiceDescriptor {
/**
* Create a new instance of the corresponding name service.
*/
public NameService createNameService () throws Exception ;
/**
* Returns this service provider's name
*
*/
public String getProviderName();
/**
* Returns this name service type
* "dns" "nis" etc
*/
public String getType();
}

View File

@@ -0,0 +1,505 @@
/*
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.spi.nameservice.dns;
import java.lang.ref.SoftReference;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.spi.NamingManager;
import java.util.*;
import sun.net.util.IPAddressUtil;
import sun.net.dns.ResolverConfiguration;
import sun.net.spi.nameservice.*;
import java.security.AccessController;
import sun.security.action.*;
/*
* A name service provider based on JNDI-DNS.
*/
public final class DNSNameService implements NameService {
// List of domains specified by property
private LinkedList<String> domainList = null;
// JNDI-DNS URL for name servers specified via property
private String nameProviderUrl = null;
// Per-thread soft cache of the last temporary context
private static ThreadLocal<SoftReference<ThreadContext>> contextRef =
new ThreadLocal<>();
// Simple class to encapsulate the temporary context
private static class ThreadContext {
private DirContext dirCtxt;
private List<String> nsList;
public ThreadContext(DirContext dirCtxt, List<String> nsList) {
this.dirCtxt = dirCtxt;
this.nsList = nsList;
}
public DirContext dirContext() {
return dirCtxt;
}
public List<String> nameservers() {
return nsList;
}
}
// Returns a per-thread DirContext
private DirContext getTemporaryContext() throws NamingException {
SoftReference<ThreadContext> ref = contextRef.get();
ThreadContext thrCtxt = null;
List<String> nsList = null;
// if no property specified we need to obtain the list of servers
//
if (nameProviderUrl == null)
nsList = ResolverConfiguration.open().nameservers();
// if soft reference hasn't been gc'ed no property has been
// specified then we need to check if the DNS configuration
// has changed.
//
if ((ref != null) && ((thrCtxt = ref.get()) != null)) {
if (nameProviderUrl == null) {
if (!thrCtxt.nameservers().equals(nsList)) {
// DNS configuration has changed
thrCtxt = null;
}
}
}
// new thread context needs to be created
if (thrCtxt == null) {
final Hashtable<String,Object> env = new Hashtable<>();
env.put("java.naming.factory.initial",
"com.sun.jndi.dns.DnsContextFactory");
// If no nameservers property specified we create provider URL
// based on system configured name servers
//
String provUrl = nameProviderUrl;
if (provUrl == null) {
provUrl = createProviderURL(nsList);
if (provUrl.length() == 0) {
throw new RuntimeException("bad nameserver configuration");
}
}
env.put("java.naming.provider.url", provUrl);
// Need to create directory context in privileged block
// as JNDI-DNS needs to resolve the name servers.
//
DirContext dirCtxt;
try {
dirCtxt = java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<DirContext>() {
public DirContext run() throws NamingException {
// Create the DNS context using NamingManager rather than using
// the initial context constructor. This avoids having the initial
// context constructor call itself.
Context ctx = NamingManager.getInitialContext(env);
if (!(ctx instanceof DirContext)) {
return null; // cannot create a DNS context
}
return (DirContext)ctx;
}
});
} catch (java.security.PrivilegedActionException pae) {
throw (NamingException)pae.getException();
}
// create new soft reference to our thread context
//
thrCtxt = new ThreadContext(dirCtxt, nsList);
contextRef.set(new SoftReference<ThreadContext>(thrCtxt));
}
return thrCtxt.dirContext();
}
/**
* Resolves the specified entry in DNS.
*
* Canonical name records are recursively resolved (to a maximum
* of 5 to avoid performance hit and potential CNAME loops).
*
* @param ctx JNDI directory context
* @param name name to resolve
* @param ids record types to search
* @param depth call depth - pass as 0.
*
* @return array list with results (will have at least on entry)
*
* @throws UnknownHostException if lookup fails or other error.
*/
private ArrayList<String> resolve(final DirContext ctx, final String name,
final String[] ids, int depth)
throws UnknownHostException
{
ArrayList<String> results = new ArrayList<>();
Attributes attrs;
// do the query
try {
attrs = java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<Attributes>() {
public Attributes run() throws NamingException {
return ctx.getAttributes(name, ids);
}
});
} catch (java.security.PrivilegedActionException pae) {
throw new UnknownHostException(pae.getException().getMessage());
}
// non-requested type returned so enumeration is empty
NamingEnumeration<? extends Attribute> ne = attrs.getAll();
if (!ne.hasMoreElements()) {
throw new UnknownHostException("DNS record not found");
}
// iterate through the returned attributes
UnknownHostException uhe = null;
try {
while (ne.hasMoreElements()) {
Attribute attr = ne.next();
String attrID = attr.getID();
for (NamingEnumeration<?> e = attr.getAll(); e.hasMoreElements();) {
String addr = (String)e.next();
// for canoncical name records do recursive lookup
// - also check for CNAME loops to avoid stack overflow
if (attrID.equals("CNAME")) {
if (depth > 4) {
throw new UnknownHostException(name + ": possible CNAME loop");
}
try {
results.addAll(resolve(ctx, addr, ids, depth+1));
} catch (UnknownHostException x) {
// canonical name can't be resolved.
if (uhe == null)
uhe = x;
}
} else {
results.add(addr);
}
}
}
} catch (NamingException nx) {
throw new UnknownHostException(nx.getMessage());
}
// pending exception as canonical name could not be resolved.
if (results.isEmpty() && uhe != null) {
throw uhe;
}
return results;
}
public DNSNameService() throws Exception {
// default domain
String domain = AccessController.doPrivileged(
new GetPropertyAction("sun.net.spi.nameservice.domain"));
if (domain != null && domain.length() > 0) {
domainList = new LinkedList<String>();
domainList.add(domain);
}
// name servers
String nameservers = AccessController.doPrivileged(
new GetPropertyAction("sun.net.spi.nameservice.nameservers"));
if (nameservers != null && nameservers.length() > 0) {
nameProviderUrl = createProviderURL(nameservers);
if (nameProviderUrl.length() == 0) {
throw new RuntimeException("malformed nameservers property");
}
} else {
// no property specified so check host DNS resolver configured
// with at least one nameserver in dotted notation.
//
List<String> nsList = ResolverConfiguration.open().nameservers();
if (nsList.isEmpty()) {
throw new RuntimeException("no nameservers provided");
}
boolean found = false;
for (String addr: nsList) {
if (IPAddressUtil.isIPv4LiteralAddress(addr) ||
IPAddressUtil.isIPv6LiteralAddress(addr)) {
found = true;
break;
}
}
if (!found) {
throw new RuntimeException("bad nameserver configuration");
}
}
}
public InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException {
// DNS records that we search for
String[] ids = {"A", "AAAA", "CNAME"};
// first get directory context
DirContext ctx;
try {
ctx = getTemporaryContext();
} catch (NamingException nx) {
throw new Error(nx);
}
ArrayList<String> results = null;
UnknownHostException uhe = null;
// If host already contains a domain name then just look it up
if (host.indexOf('.') >= 0) {
try {
results = resolve(ctx, host, ids, 0);
} catch (UnknownHostException x) {
uhe = x;
}
}
// Here we try to resolve the host using the domain suffix or
// the domain suffix search list. If the host cannot be resolved
// using the domain suffix then we attempt devolution of
// the suffix - eg: if we are searching for "foo" and our
// domain suffix is "eng.sun.com" we will try to resolve
// "foo.eng.sun.com" and "foo.sun.com".
// It's not normal to attempt devolation with domains on the
// domain suffix search list - however as ResolverConfiguration
// doesn't distinguish domain or search list in the list it
// returns we approximate by doing devolution on the domain
// suffix if the list has one entry.
if (results == null) {
List<String> searchList = null;
Iterator<String> i;
boolean usingSearchList = false;
if (domainList != null) {
i = domainList.iterator();
} else {
searchList = ResolverConfiguration.open().searchlist();
if (searchList.size() > 1) {
usingSearchList = true;
}
i = searchList.iterator();
}
// iterator through each domain suffix
while (i.hasNext()) {
String parentDomain = i.next();
int start = 0;
while ((start = parentDomain.indexOf(".")) != -1
&& start < parentDomain.length() -1) {
try {
results = resolve(ctx, host+"."+parentDomain, ids, 0);
break;
} catch (UnknownHostException x) {
uhe = x;
if (usingSearchList) {
break;
}
// devolve
parentDomain = parentDomain.substring(start+1);
}
}
if (results != null) {
break;
}
}
}
// finally try the host if it doesn't have a domain name
if (results == null && (host.indexOf('.') < 0)) {
results = resolve(ctx, host, ids, 0);
}
// if not found then throw the (last) exception thrown.
if (results == null) {
assert uhe != null;
throw uhe;
}
/**
* Convert the array list into a byte aray list - this
* filters out any invalid IPv4/IPv6 addresses.
*/
assert results.size() > 0;
InetAddress[] addrs = new InetAddress[results.size()];
int count = 0;
for (int i=0; i<results.size(); i++) {
String addrString = results.get(i);
byte[] addr = null;
try {
addr = IPAddressUtil.validateNumericFormatV4(addrString);
} catch (IllegalArgumentException ignored) {
}
if (addr == null) {
addr = IPAddressUtil.textToNumericFormatV6(addrString);
}
if (addr != null) {
addrs[count++] = InetAddress.getByAddress(host, addr);
}
}
/**
* If addresses are filtered then we need to resize the
* array. Additionally if all addresses are filtered then
* we throw an exception.
*/
if (count == 0) {
throw new UnknownHostException(host + ": no valid DNS records");
}
if (count < results.size()) {
InetAddress[] tmp = new InetAddress[count];
for (int i=0; i<count; i++) {
tmp[i] = addrs[i];
}
addrs = tmp;
}
return addrs;
}
/**
* Reverse lookup code. I.E: find a host name from an IP address.
* IPv4 addresses are mapped in the IN-ADDR.ARPA. top domain, while
* IPv6 addresses can be in IP6.ARPA or IP6.INT.
* In both cases the address has to be converted into a dotted form.
*/
public String getHostByAddr(byte[] addr) throws UnknownHostException {
String host = null;
try {
String literalip = "";
String[] ids = { "PTR" };
DirContext ctx;
ArrayList<String> results = null;
try {
ctx = getTemporaryContext();
} catch (NamingException nx) {
throw new Error(nx);
}
if (addr.length == 4) { // IPv4 Address
for (int i = addr.length-1; i >= 0; i--) {
literalip += (addr[i] & 0xff) +".";
}
literalip += "IN-ADDR.ARPA.";
results = resolve(ctx, literalip, ids, 0);
host = results.get(0);
} else if (addr.length == 16) { // IPv6 Address
/**
* Because RFC 3152 changed the root domain name for reverse
* lookups from IP6.INT. to IP6.ARPA., we need to check
* both. I.E. first the new one, IP6.ARPA, then if it fails
* the older one, IP6.INT
*/
for (int i = addr.length-1; i >= 0; i--) {
literalip += Integer.toHexString((addr[i] & 0x0f)) +"."
+Integer.toHexString((addr[i] & 0xf0) >> 4) +".";
}
String ip6lit = literalip + "IP6.ARPA.";
try {
results = resolve(ctx, ip6lit, ids, 0);
host = results.get(0);
} catch (UnknownHostException e) {
host = null;
}
if (host == null) {
// IP6.ARPA lookup failed, let's try the older IP6.INT
ip6lit = literalip + "IP6.INT.";
results = resolve(ctx, ip6lit, ids, 0);
host = results.get(0);
}
}
} catch (Exception e) {
throw new UnknownHostException(e.getMessage());
}
// Either we couldn't find it or the address was neither IPv4 or IPv6
if (host == null)
throw new UnknownHostException();
// remove trailing dot
if (host.endsWith(".")) {
host = host.substring(0, host.length() - 1);
}
return host;
}
// ---------
private static void appendIfLiteralAddress(String addr, StringBuffer sb) {
if (IPAddressUtil.isIPv4LiteralAddress(addr)) {
sb.append("dns://" + addr + " ");
} else {
if (IPAddressUtil.isIPv6LiteralAddress(addr)) {
sb.append("dns://[" + addr + "] ");
}
}
}
/*
* @return String containing the JNDI-DNS provider URL
* corresponding to the supplied List of nameservers.
*/
private static String createProviderURL(List<String> nsList) {
StringBuffer sb = new StringBuffer();
for (String s: nsList) {
appendIfLiteralAddress(s, sb);
}
return sb.toString();
}
/*
* @return String containing the JNDI-DNS provider URL
* corresponding to the list of nameservers
* contained in the provided str.
*/
private static String createProviderURL(String str) {
StringBuffer sb = new StringBuffer();
StringTokenizer st = new StringTokenizer(str, ",");
while (st.hasMoreTokens()) {
appendIfLiteralAddress(st.nextToken(), sb);
}
return sb.toString();
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.spi.nameservice.dns;
import sun.net.spi.nameservice.*;
public final class DNSNameServiceDescriptor implements NameServiceDescriptor {
/**
* Create a new instance of the corresponding name service.
*/
public NameService createNameService() throws Exception {
return new DNSNameService();
}
/**
* Returns this service provider's name
*
*/
public String getProviderName() {
return "sun";
}
/**
* Returns this name service type
* "dns" "nis" etc
*/
public String getType() {
return "dns";
}
}

View File

@@ -0,0 +1,741 @@
/*
* Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.util;
import java.net.URL;
import java.nio.CharBuffer;
import java.util.Arrays;
import sun.security.action.GetPropertyAction;
public class IPAddressUtil {
private final static int INADDR4SZ = 4;
private final static int INADDR16SZ = 16;
private final static int INT16SZ = 2;
/*
* Converts IPv4 address in its textual presentation form
* into its numeric binary form.
*
* @param src a String representing an IPv4 address in standard format
* @return a byte array representing the IPv4 numeric address
*/
@SuppressWarnings("fallthrough")
public static byte[] textToNumericFormatV4(String src)
{
byte[] res = new byte[INADDR4SZ];
long tmpValue = 0;
int currByte = 0;
boolean newOctet = true;
int len = src.length();
if (len == 0 || len > 15) {
return null;
}
/*
* When only one part is given, the value is stored directly in
* the network address without any byte rearrangement.
*
* When a two part address is supplied, the last part is
* interpreted as a 24-bit quantity and placed in the right
* most three bytes of the network address. This makes the
* two part address format convenient for specifying Class A
* network addresses as net.host.
*
* When a three part address is specified, the last part is
* interpreted as a 16-bit quantity and placed in the right
* most two bytes of the network address. This makes the
* three part address format convenient for specifying
* Class B net- work addresses as 128.net.host.
*
* When four parts are specified, each is interpreted as a
* byte of data and assigned, from left to right, to the
* four bytes of an IPv4 address.
*
* We determine and parse the leading parts, if any, as single
* byte values in one pass directly into the resulting byte[],
* then the remainder is treated as a 8-to-32-bit entity and
* translated into the remaining bytes in the array.
*/
for (int i = 0; i < len; i++) {
char c = src.charAt(i);
if (c == '.') {
if (newOctet || tmpValue < 0 || tmpValue > 0xff || currByte == 3) {
return null;
}
res[currByte++] = (byte) (tmpValue & 0xff);
tmpValue = 0;
newOctet = true;
} else {
int digit = digit(c, 10);
if (digit < 0) {
return null;
}
tmpValue *= 10;
tmpValue += digit;
newOctet = false;
}
}
if (newOctet || tmpValue < 0 || tmpValue >= (1L << ((4 - currByte) * 8))) {
return null;
}
switch (currByte) {
case 0:
res[0] = (byte) ((tmpValue >> 24) & 0xff);
case 1:
res[1] = (byte) ((tmpValue >> 16) & 0xff);
case 2:
res[2] = (byte) ((tmpValue >> 8) & 0xff);
case 3:
res[3] = (byte) ((tmpValue >> 0) & 0xff);
}
return res;
}
/**
* Validates if input string is a valid IPv4 address literal.
* If the "jdk.net.allowAmbiguousIPAddressLiterals" system property is set
* to {@code false}, or is not set then validation of the address string is performed as follows:
* If string can't be parsed by following IETF IPv4 address string literals
* formatting style rules (default one), but can be parsed by following BSD formatting
* style rules, the IPv4 address string content is treated as ambiguous and
* {@code IllegalArgumentException} is thrown.
*
* @param src input string
* @return bytes array if string is a valid IPv4 address string
* @throws IllegalArgumentException if "jdk.net.allowAmbiguousIPAddressLiterals" SP is set to
* "false" and IPv4 address string {@code "src"} is ambiguous
*/
public static byte[] validateNumericFormatV4(String src) {
byte[] parsedBytes = textToNumericFormatV4(src);
if (!ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE
&& parsedBytes == null && isBsdParsableV4(src)) {
throw new IllegalArgumentException("Invalid IP address literal: " + src);
}
return parsedBytes;
}
/*
* Convert IPv6 presentation level address to network order binary form.
* credit:
* Converted from C code from Solaris 8 (inet_pton)
*
* Any component of the string following a per-cent % is ignored.
*
* @param src a String representing an IPv6 address in textual format
* @return a byte array representing the IPv6 numeric address
*/
public static byte[] textToNumericFormatV6(String src)
{
// Shortest valid string is "::", hence at least 2 chars
if (src.length() < 2) {
return null;
}
int colonp;
char ch;
boolean saw_xdigit;
int val;
char[] srcb = src.toCharArray();
byte[] dst = new byte[INADDR16SZ];
int srcb_length = srcb.length;
int pc = src.indexOf ("%");
if (pc == srcb_length -1) {
return null;
}
if (pc != -1) {
srcb_length = pc;
}
colonp = -1;
int i = 0, j = 0;
/* Leading :: requires some special handling. */
if (srcb[i] == ':')
if (srcb[++i] != ':')
return null;
int curtok = i;
saw_xdigit = false;
val = 0;
while (i < srcb_length) {
ch = srcb[i++];
int chval = digit(ch, 16);
if (chval != -1) {
val <<= 4;
val |= chval;
if (val > 0xffff)
return null;
saw_xdigit = true;
continue;
}
if (ch == ':') {
curtok = i;
if (!saw_xdigit) {
if (colonp != -1)
return null;
colonp = j;
continue;
} else if (i == srcb_length) {
return null;
}
if (j + INT16SZ > INADDR16SZ)
return null;
dst[j++] = (byte) ((val >> 8) & 0xff);
dst[j++] = (byte) (val & 0xff);
saw_xdigit = false;
val = 0;
continue;
}
if (ch == '.' && ((j + INADDR4SZ) <= INADDR16SZ)) {
String ia4 = src.substring(curtok, srcb_length);
/* check this IPv4 address has 3 dots, ie. A.B.C.D */
int dot_count = 0, index=0;
while ((index = ia4.indexOf ('.', index)) != -1) {
dot_count ++;
index ++;
}
if (dot_count != 3) {
return null;
}
byte[] v4addr = textToNumericFormatV4(ia4);
if (v4addr == null) {
return null;
}
for (int k = 0; k < INADDR4SZ; k++) {
dst[j++] = v4addr[k];
}
saw_xdigit = false;
break; /* '\0' was seen by inet_pton4(). */
}
return null;
}
if (saw_xdigit) {
if (j + INT16SZ > INADDR16SZ)
return null;
dst[j++] = (byte) ((val >> 8) & 0xff);
dst[j++] = (byte) (val & 0xff);
}
if (colonp != -1) {
int n = j - colonp;
if (j == INADDR16SZ)
return null;
for (i = 1; i <= n; i++) {
dst[INADDR16SZ - i] = dst[colonp + n - i];
dst[colonp + n - i] = 0;
}
j = INADDR16SZ;
}
if (j != INADDR16SZ)
return null;
byte[] newdst = convertFromIPv4MappedAddress(dst);
if (newdst != null) {
return newdst;
} else {
return dst;
}
}
/**
* @param src a String representing an IPv4 address in textual format
* @return a boolean indicating whether src is an IPv4 literal address
*/
public static boolean isIPv4LiteralAddress(String src) {
return textToNumericFormatV4(src) != null;
}
/**
* @param src a String representing an IPv6 address in textual format
* @return a boolean indicating whether src is an IPv6 literal address
*/
public static boolean isIPv6LiteralAddress(String src) {
return textToNumericFormatV6(src) != null;
}
/*
* Convert IPv4-Mapped address to IPv4 address. Both input and
* returned value are in network order binary form.
*
* @param src a String representing an IPv4-Mapped address in textual format
* @return a byte array representing the IPv4 numeric address
*/
public static byte[] convertFromIPv4MappedAddress(byte[] addr) {
if (isIPv4MappedAddress(addr)) {
byte[] newAddr = new byte[INADDR4SZ];
System.arraycopy(addr, 12, newAddr, 0, INADDR4SZ);
return newAddr;
}
return null;
}
/**
* Utility routine to check if the InetAddress is an
* IPv4 mapped IPv6 address.
*
* @return a <code>boolean</code> indicating if the InetAddress is
* an IPv4 mapped IPv6 address; or false if address is IPv4 address.
*/
private static boolean isIPv4MappedAddress(byte[] addr) {
if (addr.length < INADDR16SZ) {
return false;
}
if ((addr[0] == 0x00) && (addr[1] == 0x00) &&
(addr[2] == 0x00) && (addr[3] == 0x00) &&
(addr[4] == 0x00) && (addr[5] == 0x00) &&
(addr[6] == 0x00) && (addr[7] == 0x00) &&
(addr[8] == 0x00) && (addr[9] == 0x00) &&
(addr[10] == (byte)0xff) &&
(addr[11] == (byte)0xff)) {
return true;
}
return false;
}
// See java.net.URI for more details on how to generate these
// masks.
//
// square brackets
private static final long L_IPV6_DELIMS = 0x0L; // "[]"
private static final long H_IPV6_DELIMS = 0x28000000L; // "[]"
// RFC 3986 gen-delims
private static final long L_GEN_DELIMS = 0x8400800800000000L; // ":/?#[]@"
private static final long H_GEN_DELIMS = 0x28000001L; // ":/?#[]@"
// These gen-delims can appear in authority
private static final long L_AUTH_DELIMS = 0x400000000000000L; // "@[]:"
private static final long H_AUTH_DELIMS = 0x28000001L; // "@[]:"
// colon is allowed in userinfo
private static final long L_COLON = 0x400000000000000L; // ":"
private static final long H_COLON = 0x0L; // ":"
// slash should be encoded in authority
private static final long L_SLASH = 0x800000000000L; // "/"
private static final long H_SLASH = 0x0L; // "/"
// backslash should always be encoded
private static final long L_BACKSLASH = 0x0L; // "\"
private static final long H_BACKSLASH = 0x10000000L; // "\"
// ASCII chars 0-31 + 127 - various controls + CRLF + TAB
private static final long L_NON_PRINTABLE = 0xffffffffL;
private static final long H_NON_PRINTABLE = 0x8000000000000000L;
// All of the above
private static final long L_EXCLUDE = 0x84008008ffffffffL;
private static final long H_EXCLUDE = 0x8000000038000001L;
private static final char[] OTHERS = {
8263,8264,8265,8448,8449,8453,8454,10868,
65109,65110,65119,65131,65283,65295,65306,65311,65312
};
// Tell whether the given character is found by the given mask pair
public static boolean match(char c, long lowMask, long highMask) {
if (c < 64)
return ((1L << c) & lowMask) != 0;
if (c < 128)
return ((1L << (c - 64)) & highMask) != 0;
return false; // other non ASCII characters are not filtered
}
// returns -1 if the string doesn't contain any characters
// from the mask, the index of the first such character found
// otherwise.
public static int scan(String s, long lowMask, long highMask) {
int i = -1, len;
if (s == null || (len = s.length()) == 0) return -1;
boolean match = false;
while (++i < len && !(match = match(s.charAt(i), lowMask, highMask)));
if (match) return i;
return -1;
}
public static int scan(String s, long lowMask, long highMask, char[] others) {
int i = -1, len;
if (s == null || (len = s.length()) == 0) return -1;
boolean match = false;
char c, c0 = others[0];
while (++i < len && !(match = match((c=s.charAt(i)), lowMask, highMask))) {
if (c >= c0 && (Arrays.binarySearch(others, c) > -1)) {
match = true; break;
}
}
if (match) return i;
return -1;
}
private static String describeChar(char c) {
if (c < 32 || c == 127) {
if (c == '\n') return "LF";
if (c == '\r') return "CR";
return "control char (code=" + (int)c + ")";
}
if (c == '\\') return "'\\'";
return "'" + c + "'";
}
private static String checkUserInfo(String str) {
// colon is permitted in user info
int index = scan(str, L_EXCLUDE & ~L_COLON,
H_EXCLUDE & ~H_COLON);
if (index >= 0) {
return "Illegal character found in user-info: "
+ describeChar(str.charAt(index));
}
return null;
}
private static String checkHost(String str) {
int index;
if (str.startsWith("[") && str.endsWith("]")) {
str = str.substring(1, str.length() - 1);
if (isIPv6LiteralAddress(str)) {
index = str.indexOf('%');
if (index >= 0) {
index = scan(str = str.substring(index),
L_NON_PRINTABLE | L_IPV6_DELIMS,
H_NON_PRINTABLE | H_IPV6_DELIMS);
if (index >= 0) {
return "Illegal character found in IPv6 scoped address: "
+ describeChar(str.charAt(index));
}
}
return null;
}
return "Unrecognized IPv6 address format";
} else {
index = scan(str, L_EXCLUDE, H_EXCLUDE);
if (index >= 0) {
return "Illegal character found in host: "
+ describeChar(str.charAt(index));
}
}
return null;
}
private static String checkAuth(String str) {
int index = scan(str,
L_EXCLUDE & ~L_AUTH_DELIMS,
H_EXCLUDE & ~H_AUTH_DELIMS);
if (index >= 0) {
return "Illegal character found in authority: "
+ describeChar(str.charAt(index));
}
return null;
}
// check authority of hierarchical URL. Appropriate for
// HTTP-like protocol handlers
public static String checkAuthority(URL url) {
String s, u, h;
if (url == null) return null;
if ((s = checkUserInfo(u = url.getUserInfo())) != null) {
return s;
}
if ((s = checkHost(h = url.getHost())) != null) {
return s;
}
if (h == null && u == null) {
return checkAuth(url.getAuthority());
}
return null;
}
// minimal syntax checks - deeper check may be performed
// by the appropriate protocol handler
public static String checkExternalForm(URL url) {
String s;
if (url == null) return null;
int index = scan(s = url.getUserInfo(),
L_NON_PRINTABLE | L_SLASH,
H_NON_PRINTABLE | H_SLASH);
if (index >= 0) {
return "Illegal character found in authority: "
+ describeChar(s.charAt(index));
}
if ((s = checkHostString(url.getHost())) != null) {
return s;
}
return null;
}
public static String checkHostString(String host) {
if (host == null) return null;
int index = scan(host,
L_NON_PRINTABLE | L_SLASH,
H_NON_PRINTABLE | H_SLASH,
OTHERS);
if (index >= 0) {
return "Illegal character found in host: "
+ describeChar(host.charAt(index));
}
return null;
}
/**
* Returns the numeric value of the character {@code ch} in the
* specified radix.
*
* @param ch the character to be converted.
* @param radix the radix.
* @return the numeric value represented by the character in the
* specified radix.
*/
public static int digit(char ch, int radix) {
if (ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE) {
return Character.digit(ch, radix);
} else {
return parseAsciiDigit(ch, radix);
}
}
/**
* Try to parse String as IPv4 address literal by following
* BSD-style formatting rules.
*
* @param input input string
* @return {@code true} if input string is parsable as IPv4 address literal,
* {@code false} otherwise.
*/
public static boolean isBsdParsableV4(String input) {
char firstSymbol = input.charAt(0);
// Check if first digit is not a decimal digit
if (parseAsciiDigit(firstSymbol, DECIMAL) == -1) {
return false;
}
// Last character is dot OR is not a supported digit: [0-9,A-F,a-f]
char lastSymbol = input.charAt(input.length() - 1);
if (lastSymbol == '.' || parseAsciiHexDigit(lastSymbol) == -1) {
return false;
}
// Parse IP address fields
CharBuffer charBuffer = CharBuffer.wrap(input);
int fieldNumber = 0;
while (charBuffer.hasRemaining()) {
long fieldValue = -1L;
// Try to parse fields in all supported radixes
for (int radix : SUPPORTED_RADIXES) {
fieldValue = parseV4FieldBsd(radix, charBuffer, fieldNumber);
if (fieldValue >= 0) {
fieldNumber++;
break;
} else if (fieldValue == TERMINAL_PARSE_ERROR) {
return false;
}
}
// If field can't be parsed as one of supported radixes stop
// parsing
if (fieldValue < 0) {
return false;
}
}
return true;
}
/**
* Method tries to parse IP address field that starts from {@linkplain CharBuffer#position()
* current position} of the provided character buffer.
* <p>
* This method supports three {@code "radix"} values to decode field values in
* {@code "HEXADECIMAL (radix=16)"}, {@code "DECIMAL (radix=10)"} and
* {@code "OCTAL (radix=8)"} radixes.
* <p>
* If {@code -1} value is returned the char buffer position is reset to the value
* it was before it was called.
* <p>
* Method returns {@code -2} if formatting illegal for all supported {@code radix}
* values is observed, and there is no point in checking other radix values.
* That includes the following cases:<ul>
* <li>Two subsequent dots are observer
* <li>Number of dots more than 3
* <li>Field value exceeds max allowed
* <li>Character is not a valid digit for the requested {@code radix} value, given
* that a field has the radix specific prefix
* </ul>
*
* @param radix digits encoding radix to use for parsing. Valid values: 8, 10, 16.
* @param buffer {@code CharBuffer} with position set to the field's fist character
* @param fieldNumber parsed field number
* @return {@code CANT_PARSE_IN_RADIX} if field can not be parsed in requested {@code radix}.
* {@code TERMINAL_PARSE_ERROR} if field can't be parsed and the whole parse process should be terminated.
* Parsed field value otherwise.
*/
private static long parseV4FieldBsd(int radix, CharBuffer buffer, int fieldNumber) {
int initialPos = buffer.position();
long val = 0;
int digitsCount = 0;
if (!checkPrefix(buffer, radix)) {
val = CANT_PARSE_IN_RADIX;
}
boolean dotSeen = false;
while (buffer.hasRemaining() && val != CANT_PARSE_IN_RADIX && !dotSeen) {
char c = buffer.get();
if (c == '.') {
dotSeen = true;
// Fail if 4 dots in IP address string.
// fieldNumber counter starts from 0, therefore 3
if (fieldNumber == 3) {
// Terminal state, can stop parsing: too many fields
return TERMINAL_PARSE_ERROR;
}
// Check for literals with two dots, like '1.2..3', '1.2.3..'
if (digitsCount == 0) {
// Terminal state, can stop parsing: dot with no digits
return TERMINAL_PARSE_ERROR;
}
if (val > 255) {
// Terminal state, can stop parsing: too big value for an octet
return TERMINAL_PARSE_ERROR;
}
} else {
int dv = parseAsciiDigit(c, radix);
if (dv >= 0) {
digitsCount++;
val *= radix;
val += dv;
} else {
// Spotted digit can't be parsed in the requested 'radix'.
// The order in which radixes are checked - hex, octal, decimal:
// - if symbol is not a valid digit in hex radix - terminal
// - if symbol is not a valid digit in octal radix, and given
// that octal prefix was observed before - terminal
// - if symbol is not a valid digit in decimal radix - terminal
return TERMINAL_PARSE_ERROR;
}
}
}
if (val == CANT_PARSE_IN_RADIX) {
buffer.position(initialPos);
} else if (!dotSeen) {
// It is the last field - check its value
// This check will ensure that address strings with less
// than 4 fields, i.e. A, A.B and A.B.C address types
// contain value less then the allowed maximum for the last field.
long maxValue = (1L << ((4 - fieldNumber) * 8)) - 1;
if (val > maxValue) {
// Terminal state, can stop parsing: last field value exceeds its
// allowed value
return TERMINAL_PARSE_ERROR;
}
}
return val;
}
// This method moves the position of the supplied CharBuffer by analysing the digit prefix
// symbols if any.
// The caller should reset the position when method returns false.
private static boolean checkPrefix(CharBuffer buffer, int radix) {
switch (radix) {
case OCTAL:
return isOctalFieldStart(buffer);
case DECIMAL:
return isDecimalFieldStart(buffer);
case HEXADECIMAL:
return isHexFieldStart(buffer);
default:
throw new AssertionError("Not supported radix");
}
}
// This method always moves the position of the supplied CharBuffer
// removing the octal prefix symbols '0'.
// The caller should reset the position when method returns false.
private static boolean isOctalFieldStart(CharBuffer cb) {
// .0<EOS> is not treated as octal field
if (cb.remaining() < 2) {
return false;
}
// Fetch two first characters
int position = cb.position();
char first = cb.get();
char second = cb.get();
// Return false if the first char is not octal prefix '0' or second is a
// field separator - parseV4FieldBsd will reset position to start of the field.
// '.0.' fields will be successfully parsed in decimal radix.
boolean isOctalPrefix = first == '0' && second != '.';
// If the prefix looks like octal - consume '0', otherwise 'false' is returned
// and caller will reset the buffer position.
if (isOctalPrefix) {
cb.position(position + 1);
}
return isOctalPrefix;
}
// This method doesn't move the position of the supplied CharBuffer
private static boolean isDecimalFieldStart(CharBuffer cb) {
return cb.hasRemaining();
}
// This method always moves the position of the supplied CharBuffer
// removing the hexadecimal prefix symbols '0x'.
// The caller should reset the position when method returns false.
private static boolean isHexFieldStart(CharBuffer cb) {
if (cb.remaining() < 2) {
return false;
}
char first = cb.get();
char second = cb.get();
return first == '0' && (second == 'x' || second == 'X');
}
// Parse ASCII digit in given radix
public static int parseAsciiDigit(char c, int radix) {
assert radix == OCTAL || radix == DECIMAL || radix == HEXADECIMAL;
if (radix == HEXADECIMAL) {
return parseAsciiHexDigit(c);
}
int val = c - '0';
return (val < 0 || val >= radix) ? -1 : val;
}
// Parse ASCII digit in hexadecimal radix
private static int parseAsciiHexDigit(char digit) {
char c = Character.toLowerCase(digit);
if (c >= 'a' && c <= 'f') {
return c - 'a' + 10;
}
return parseAsciiDigit(c, DECIMAL);
}
// Supported radixes
private static final int HEXADECIMAL = 16;
private static final int DECIMAL = 10;
private static final int OCTAL = 8;
// Order in which field formats are exercised to parse one IP address textual field
private static final int[] SUPPORTED_RADIXES = new int[]{HEXADECIMAL, OCTAL, DECIMAL};
// BSD parser's return values
private final static long CANT_PARSE_IN_RADIX = -1L;
private final static long TERMINAL_PARSE_ERROR = -2L;
private static final String ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP = "jdk.net.allowAmbiguousIPAddressLiterals";
private static final boolean ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE = Boolean.valueOf(
GetPropertyAction.privilegedGetProperty(ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP, "false"));
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.util;
import sun.net.ApplicationProxy;
import java.net.Proxy;
public final class ProxyUtil {
private ProxyUtil() {}
/**
* Creates a new {@link Proxy} instance for the given proxy iff it is
* neither null, {@link Proxy#NO_PROXY Proxy.NO_PROXY}, an
* {@link ApplicationProxy} instance, nor already a {@code Proxy} instance.
*/
public static Proxy copyProxy(Proxy proxy) {
return proxy == null
|| proxy.getClass() == Proxy.class
|| proxy instanceof ApplicationProxy
? proxy
: new Proxy(proxy.type(), proxy.address());
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.util;
import java.io.IOException;
import java.net.URL;
import java.net.URLPermission;
import java.security.Permission;
/**
* URL Utility class.
*/
public class URLUtil {
/**
* Returns a string form of the url suitable for use as a key in HashMap/Sets.
*
* The string form should be behave in the same manner as the URL when
* compared for equality in a HashMap/Set, except that no nameservice
* lookup is done on the hostname (only string comparison), and the fragment
* is not considered.
*
* @see java.net.URLStreamHandler.sameFile(java.net.URL)
*/
public static String urlNoFragString(URL url) {
StringBuilder strForm = new StringBuilder();
String protocol = url.getProtocol();
if (protocol != null) {
/* protocol is compared case-insensitive, so convert to lowercase */
protocol = protocol.toLowerCase();
strForm.append(protocol);
strForm.append("://");
}
String host = url.getHost();
if (host != null) {
/* host is compared case-insensitive, so convert to lowercase */
host = host.toLowerCase();
strForm.append(host);
int port = url.getPort();
if (port == -1) {
/* if no port is specificed then use the protocols
* default, if there is one */
port = url.getDefaultPort();
}
if (port != -1) {
strForm.append(":").append(port);
}
}
String file = url.getFile();
if (file != null) {
strForm.append(file);
}
return strForm.toString();
}
public static Permission getConnectPermission(URL url) throws IOException {
String urlStringLowerCase = url.toString().toLowerCase();
if (urlStringLowerCase.startsWith("http:") || urlStringLowerCase.startsWith("https:")) {
return getURLConnectPermission(url);
} else if (urlStringLowerCase.startsWith("jar:http:") || urlStringLowerCase.startsWith("jar:https:")) {
String urlString = url.toString();
int bangPos = urlString.indexOf("!/");
urlString = urlString.substring(4, bangPos > -1 ? bangPos : urlString.length());
URL u = new URL(urlString);
return getURLConnectPermission(u);
// If protocol is HTTP or HTTPS than use URLPermission object
} else {
return url.openConnection().getPermission();
}
}
private static Permission getURLConnectPermission(URL url) {
String urlString = url.getProtocol() + "://" + url.getAuthority() + url.getPath();
return new URLPermission(urlString);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www;
/**
* An exception thrown by the MimeLauncher when it is unable to launch
* an external content viewer.
*
* @author Sunita Mani
*/
public class ApplicationLaunchException extends Exception {
private static final long serialVersionUID = -4782286141289536883L;
public ApplicationLaunchException(String reason) {
super(reason);
}
}

View File

@@ -0,0 +1,277 @@
/*
* Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www;
import java.util.Iterator;
import java.util.OptionalInt;
/* This is useful for the nightmare of parsing multi-part HTTP/RFC822 headers
* sensibly:
* From a String like: 'timeout=15, max=5'
* create an array of Strings:
* { {"timeout", "15"},
* {"max", "5"}
* }
* From one like: 'Basic Realm="FuzzFace" Foo="Biz Bar Baz"'
* create one like (no quotes in literal):
* { {"basic", null},
* {"realm", "FuzzFace"}
* {"foo", "Biz Bar Baz"}
* }
* keys are converted to lower case, vals are left as is....
*
* @author Dave Brown
*/
public class HeaderParser {
/* table of key/val pairs */
String raw;
String[][] tab;
int nkeys;
int asize = 10; // initial size of array is 10
public HeaderParser(String raw) {
this.raw = raw;
tab = new String[asize][2];
parse();
}
private HeaderParser () {
}
/**
* create a new HeaderParser from this, whose keys (and corresponding values)
* range from "start" to "end-1"
*/
public HeaderParser subsequence (int start, int end) {
if (start == 0 && end == nkeys) {
return this;
}
if (start < 0 || start >= end || end > nkeys)
throw new IllegalArgumentException ("invalid start or end");
HeaderParser n = new HeaderParser ();
n.tab = new String [asize][2];
n.asize = asize;
System.arraycopy (tab, start, n.tab, 0, (end-start));
n.nkeys= (end-start);
return n;
}
private void parse() {
if (raw != null) {
raw = raw.trim();
char[] ca = raw.toCharArray();
int beg = 0, end = 0, i = 0;
boolean inKey = true;
boolean inQuote = false;
int len = ca.length;
while (end < len) {
char c = ca[end];
if ((c == '=') && !inQuote) { // end of a key
tab[i][0] = new String(ca, beg, end-beg).toLowerCase();
inKey = false;
end++;
beg = end;
} else if (c == '\"') {
if (inQuote) {
tab[i++][1]= new String(ca, beg, end-beg);
inQuote=false;
do {
end++;
} while (end < len && (ca[end] == ' ' || ca[end] == ','));
inKey=true;
beg=end;
} else {
inQuote=true;
end++;
beg=end;
}
} else if (c == ' ' || c == ',') { // end key/val, of whatever we're in
if (inQuote) {
end++;
continue;
} else if (inKey) {
tab[i++][0] = (new String(ca, beg, end-beg)).toLowerCase();
} else {
tab[i++][1] = (new String(ca, beg, end-beg));
}
while (end < len && (ca[end] == ' ' || ca[end] == ',')) {
end++;
}
inKey = true;
beg = end;
} else {
end++;
}
if (i == asize) {
asize = asize * 2;
String[][] ntab = new String[asize][2];
System.arraycopy (tab, 0, ntab, 0, tab.length);
tab = ntab;
}
}
// get last key/val, if any
if (--end > beg) {
if (!inKey) {
if (ca[end] == '\"') {
tab[i++][1] = (new String(ca, beg, end-beg));
} else {
tab[i++][1] = (new String(ca, beg, end-beg+1));
}
} else {
tab[i++][0] = (new String(ca, beg, end-beg+1)).toLowerCase();
}
} else if (end == beg) {
if (!inKey) {
if (ca[end] == '\"') {
tab[i++][1] = String.valueOf(ca[end-1]);
} else {
tab[i++][1] = String.valueOf(ca[end]);
}
} else {
tab[i++][0] = String.valueOf(ca[end]).toLowerCase();
}
}
nkeys=i;
}
}
public String findKey(int i) {
if (i < 0 || i > asize)
return null;
return tab[i][0];
}
public String findValue(int i) {
if (i < 0 || i > asize)
return null;
return tab[i][1];
}
public String findValue(String key) {
return findValue(key, null);
}
public String findValue(String k, String Default) {
if (k == null)
return Default;
k = k.toLowerCase();
for (int i = 0; i < asize; ++i) {
if (tab[i][0] == null) {
return Default;
} else if (k.equals(tab[i][0])) {
return tab[i][1];
}
}
return Default;
}
class ParserIterator implements Iterator<String> {
int index;
boolean returnsValue; // or key
ParserIterator (boolean returnValue) {
returnsValue = returnValue;
}
public boolean hasNext () {
return index<nkeys;
}
public String next () {
return tab[index++][returnsValue?1:0];
}
public void remove () {
throw new UnsupportedOperationException ("remove not supported");
}
}
public Iterator<String> keys () {
return new ParserIterator (false);
}
public Iterator<String> values () {
return new ParserIterator (true);
}
public String toString () {
Iterator<String> k = keys();
StringBuffer sbuf = new StringBuffer();
sbuf.append ("{size="+asize+" nkeys="+nkeys+" ");
for (int i=0; k.hasNext(); i++) {
String key = k.next();
String val = findValue (i);
if (val != null && "".equals (val)) {
val = null;
}
sbuf.append (" {"+key+(val==null?"":","+val)+"}");
if (k.hasNext()) {
sbuf.append (",");
}
}
sbuf.append (" }");
return new String (sbuf);
}
public int findInt(String k, int Default) {
try {
return Integer.parseInt(findValue(k, String.valueOf(Default)));
} catch (Throwable t) {
return Default;
}
}
public OptionalInt findInt(String k) {
try {
String s = findValue(k);
if (s == null) {
return OptionalInt.empty();
}
return OptionalInt.of(Integer.parseInt(s));
} catch (Throwable t) {
return OptionalInt.empty();
}
}
/*
public static void main(String[] a) throws Exception {
System.out.print("enter line to parse> ");
System.out.flush();
DataInputStream dis = new DataInputStream(System.in);
String line = dis.readLine();
HeaderParser p = new HeaderParser(line);
for (int i = 0; i < asize; ++i) {
if (p.findKey(i) == null) break;
String v = p.findValue(i);
System.out.println(i + ") " +p.findKey(i) + "="+v);
}
System.out.println("Done!");
}
*/
}

View File

@@ -0,0 +1,607 @@
/*
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*-
* news stream opener
*/
package sun.net.www;
import java.io.*;
import java.lang.reflect.Array;
import java.net.ProtocolException;
import java.util.Collections;
import java.util.*;
/** An RFC 844 or MIME message header. Includes methods
for parsing headers from incoming streams, fetching
values, setting values, and printing headers.
Key values of null are legal: they indicate lines in
the header that don't have a valid key, but do have
a value (this isn't legal according to the standard,
but lines like this are everywhere). */
public
class MessageHeader {
private String keys[];
private String values[];
private int nkeys;
// max number of bytes for headers, <=0 means unlimited;
// this corresponds to the length of the names, plus the length
// of the values, plus an overhead of 32 bytes per name: value
// pair.
// Note: we use the same definition as HTTP/2 SETTINGS_MAX_HEADER_LIST_SIZE
// see RFC 9113, section 6.5.2.
// https://www.rfc-editor.org/rfc/rfc9113.html#SETTINGS_MAX_HEADER_LIST_SIZE
private final int maxHeaderSize;
// Aggregate size of the field lines (name + value + 32) x N
// that have been parsed and accepted so far.
// This is defined as a long to force promotion to long
// and avoid overflows; see checkNewSize;
private long size;
public MessageHeader () {
this(0);
}
public MessageHeader (int maxHeaderSize) {
this.maxHeaderSize = maxHeaderSize;
grow();
}
public MessageHeader (InputStream is) throws java.io.IOException {
maxHeaderSize = 0;
parseHeader(is);
}
/**
* Returns list of header names in a comma separated list
*/
public synchronized String getHeaderNamesInList() {
StringJoiner joiner = new StringJoiner(",");
for (int i=0; i<nkeys; i++) {
joiner.add(keys[i]);
}
return joiner.toString();
}
/**
* Reset a message header (all key/values removed)
*/
public synchronized void reset() {
keys = null;
values = null;
nkeys = 0;
grow();
}
/**
* Find the value that corresponds to this key.
* It finds only the first occurrence of the key.
* @param k the key to find.
* @return null if not found.
*/
public synchronized String findValue(String k) {
if (k == null) {
for (int i = nkeys; --i >= 0;)
if (keys[i] == null)
return values[i];
} else
for (int i = nkeys; --i >= 0;) {
if (k.equalsIgnoreCase(keys[i]))
return values[i];
}
return null;
}
// return the location of the key
public synchronized int getKey(String k) {
for (int i = nkeys; --i >= 0;)
if ((keys[i] == k) ||
(k != null && k.equalsIgnoreCase(keys[i])))
return i;
return -1;
}
public synchronized String getKey(int n) {
if (n < 0 || n >= nkeys) return null;
return keys[n];
}
public synchronized String getValue(int n) {
if (n < 0 || n >= nkeys) return null;
return values[n];
}
/** Deprecated: Use multiValueIterator() instead.
*
* Find the next value that corresponds to this key.
* It finds the first value that follows v. To iterate
* over all the values of a key use:
* <pre>
* for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) {
* ...
* }
* </pre>
*/
public synchronized String findNextValue(String k, String v) {
boolean foundV = false;
if (k == null) {
for (int i = nkeys; --i >= 0;)
if (keys[i] == null)
if (foundV)
return values[i];
else if (values[i] == v)
foundV = true;
} else
for (int i = nkeys; --i >= 0;)
if (k.equalsIgnoreCase(keys[i]))
if (foundV)
return values[i];
else if (values[i] == v)
foundV = true;
return null;
}
/**
* Removes bare Negotiate and Kerberos headers when an "NTLM ..."
* appears. All Performed on headers with key being k.
* @return true if there is a change
*/
public boolean filterNTLMResponses(String k) {
boolean found = false;
for (int i=0; i<nkeys; i++) {
if (k.equalsIgnoreCase(keys[i])
&& values[i] != null && values[i].length() > 5
&& values[i].substring(0, 5).equalsIgnoreCase("NTLM ")) {
found = true;
break;
}
}
if (found) {
int j = 0;
for (int i=0; i<nkeys; i++) {
if (k.equalsIgnoreCase(keys[i]) && (
"Negotiate".equalsIgnoreCase(values[i]) ||
"Kerberos".equalsIgnoreCase(values[i]))) {
continue;
}
if (i != j) {
keys[j] = keys[i];
values[j] = values[i];
}
j++;
}
if (j != nkeys) {
nkeys = j;
return true;
}
}
return false;
}
class HeaderIterator implements Iterator<String> {
int index = 0;
int next = -1;
String key;
boolean haveNext = false;
Object lock;
public HeaderIterator (String k, Object lock) {
key = k;
this.lock = lock;
}
public boolean hasNext () {
synchronized (lock) {
if (haveNext) {
return true;
}
while (index < nkeys) {
if (key.equalsIgnoreCase (keys[index])) {
haveNext = true;
next = index++;
return true;
}
index ++;
}
return false;
}
}
public String next() {
synchronized (lock) {
if (haveNext) {
haveNext = false;
return values [next];
}
if (hasNext()) {
return next();
} else {
throw new NoSuchElementException ("No more elements");
}
}
}
public void remove () {
throw new UnsupportedOperationException ("remove not allowed");
}
}
/**
* return an Iterator that returns all values of a particular
* key in sequence
*/
public Iterator<String> multiValueIterator (String k) {
return new HeaderIterator (k, this);
}
public synchronized Map<String, List<String>> getHeaders() {
return getHeaders(null);
}
public synchronized Map<String, List<String>> getHeaders(String[] excludeList) {
return filterAndAddHeaders(excludeList, null);
}
public synchronized Map<String, List<String>> filterAndAddHeaders(
String[] excludeList, Map<String, List<String>> include) {
boolean skipIt = false;
Map<String, List<String>> m = new HashMap<String, List<String>>();
for (int i = nkeys; --i >= 0;) {
if (excludeList != null) {
// check if the key is in the excludeList.
// if so, don't include it in the Map.
for (int j = 0; j < excludeList.length; j++) {
if ((excludeList[j] != null) &&
(excludeList[j].equalsIgnoreCase(keys[i]))) {
skipIt = true;
break;
}
}
}
if (!skipIt) {
List<String> l = m.get(keys[i]);
if (l == null) {
l = new ArrayList<String>();
m.put(keys[i], l);
}
l.add(values[i]);
} else {
// reset the flag
skipIt = false;
}
}
if (include != null) {
for (Map.Entry<String,List<String>> entry: include.entrySet()) {
List<String> l = m.get(entry.getKey());
if (l == null) {
l = new ArrayList<String>();
m.put(entry.getKey(), l);
}
l.addAll(entry.getValue());
}
}
for (String key : m.keySet()) {
m.put(key, Collections.unmodifiableList(m.get(key)));
}
return Collections.unmodifiableMap(m);
}
/** Check if a line of message header looks like a request line.
* This method does not perform a full validation but simply
* returns false if the line does not end with 'HTTP/[1-9].[0-9]'
* @param line the line to check.
* @return true if the line might be a request line.
*/
private boolean isRequestline(String line) {
String k = line.trim();
int i = k.lastIndexOf(' ');
if (i <= 0) return false;
int len = k.length();
if (len - i < 9) return false;
char c1 = k.charAt(len-3);
char c2 = k.charAt(len-2);
char c3 = k.charAt(len-1);
if (c1 < '1' || c1 > '9') return false;
if (c2 != '.') return false;
if (c3 < '0' || c3 > '9') return false;
return (k.substring(i+1, len-3).equalsIgnoreCase("HTTP/"));
}
/** Prints the key-value pairs represented by this
header. Also prints the RFC required blank line
at the end. Omits pairs with a null key. Omits
colon if key-value pair is the requestline. */
public synchronized void print(PrintStream p) {
for (int i = 0; i < nkeys; i++)
if (keys[i] != null) {
StringBuilder sb = new StringBuilder(keys[i]);
if (values[i] != null) {
sb.append(": " + values[i]);
} else if (i != 0 || !isRequestline(keys[i])) {
sb.append(":");
}
p.print(sb.append("\r\n"));
}
p.print("\r\n");
p.flush();
}
/** Adds a key value pair to the end of the
header. Duplicates are allowed */
public synchronized void add(String k, String v) {
grow();
keys[nkeys] = k;
values[nkeys] = v;
nkeys++;
}
/** Prepends a key value pair to the beginning of the
header. Duplicates are allowed */
public synchronized void prepend(String k, String v) {
grow();
for (int i = nkeys; i > 0; i--) {
keys[i] = keys[i-1];
values[i] = values[i-1];
}
keys[0] = k;
values[0] = v;
nkeys++;
}
/** Overwrite the previous key/val pair at location 'i'
* with the new k/v. If the index didn't exist before
* the key/val is simply tacked onto the end.
*/
public synchronized void set(int i, String k, String v) {
grow();
if (i < 0) {
return;
} else if (i >= nkeys) {
add(k, v);
} else {
keys[i] = k;
values[i] = v;
}
}
/** grow the key/value arrays as needed */
private void grow() {
if (keys == null || nkeys >= keys.length) {
String[] nk = new String[nkeys + 4];
String[] nv = new String[nkeys + 4];
if (keys != null)
System.arraycopy(keys, 0, nk, 0, nkeys);
if (values != null)
System.arraycopy(values, 0, nv, 0, nkeys);
keys = nk;
values = nv;
}
}
/**
* Remove the key from the header. If there are multiple values under
* the same key, they are all removed.
* Nothing is done if the key doesn't exist.
* After a remove, the other pairs' order are not changed.
* @param k the key to remove
*/
public synchronized void remove(String k) {
if(k == null) {
for (int i = 0; i < nkeys; i++) {
while (keys[i] == null && i < nkeys) {
for(int j=i; j<nkeys-1; j++) {
keys[j] = keys[j+1];
values[j] = values[j+1];
}
nkeys--;
}
}
} else {
for (int i = 0; i < nkeys; i++) {
while (k.equalsIgnoreCase(keys[i]) && i < nkeys) {
for(int j=i; j<nkeys-1; j++) {
keys[j] = keys[j+1];
values[j] = values[j+1];
}
nkeys--;
}
}
}
}
/** Sets the value of a key. If the key already
exists in the header, it's value will be
changed. Otherwise a new key/value pair will
be added to the end of the header. */
public synchronized void set(String k, String v) {
for (int i = nkeys; --i >= 0;)
if (k.equalsIgnoreCase(keys[i])) {
values[i] = v;
return;
}
add(k, v);
}
/** Set's the value of a key only if there is no
* key with that value already.
*/
public synchronized void setIfNotSet(String k, String v) {
if (findValue(k) == null) {
add(k, v);
}
}
/** Convert a message-id string to canonical form (strips off
leading and trailing <>s) */
public static String canonicalID(String id) {
if (id == null)
return "";
int st = 0;
int len = id.length();
boolean substr = false;
int c;
while (st < len && ((c = id.charAt(st)) == '<' ||
c <= ' ')) {
st++;
substr = true;
}
while (st < len && ((c = id.charAt(len - 1)) == '>' ||
c <= ' ')) {
len--;
substr = true;
}
return substr ? id.substring(st, len) : id;
}
/** Parse a MIME header from an input stream. */
public void parseHeader(InputStream is) throws java.io.IOException {
synchronized (this) {
nkeys = 0;
size = 0;
}
mergeHeader(is);
}
private void checkMaxHeaderSize(int sz) throws ProtocolException {
if (maxHeaderSize > 0) checkNewSize(size, sz, 0);
}
private long checkNewSize(long size, int name, int value) throws ProtocolException {
// See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2.
long newSize = size + name + value + 32;
if (maxHeaderSize > 0 && newSize > maxHeaderSize) {
Arrays.fill(keys, 0, nkeys, null);
Arrays.fill(values,0, nkeys, null);
nkeys = 0;
throw new ProtocolException(String.format("Header size too big: %s > %s",
newSize, maxHeaderSize));
}
return newSize;
}
/** Parse and merge a MIME header from an input stream. */
@SuppressWarnings("fallthrough")
public void mergeHeader(InputStream is) throws java.io.IOException {
if (is == null)
return;
char s[] = new char[10];
int firstc = is.read();
while (firstc != '\n' && firstc != '\r' && firstc >= 0) {
int len = 0;
int keyend = -1;
int c;
boolean inKey = firstc > ' ';
s[len++] = (char) firstc;
checkMaxHeaderSize(len);
parseloop:{
// We start parsing for a new name value pair here.
// The max header size includes an overhead of 32 bytes per
// name value pair.
// See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2.
long maxRemaining = maxHeaderSize > 0
? maxHeaderSize - size - 32
: Long.MAX_VALUE;
while ((c = is.read()) >= 0) {
switch (c) {
case ':':
if (inKey && len > 0)
keyend = len;
inKey = false;
break;
case '\t':
c = ' ';
/*fall through*/
case ' ':
inKey = false;
break;
case '\r':
case '\n':
firstc = is.read();
if (c == '\r' && firstc == '\n') {
firstc = is.read();
if (firstc == '\r')
firstc = is.read();
}
if (firstc == '\n' || firstc == '\r' || firstc > ' ')
break parseloop;
/* continuation */
c = ' ';
break;
}
if (len >= s.length) {
char ns[] = new char[s.length * 2];
System.arraycopy(s, 0, ns, 0, len);
s = ns;
}
s[len++] = (char) c;
if (maxHeaderSize > 0 && len > maxRemaining) {
checkMaxHeaderSize(len);
}
}
firstc = -1;
}
while (len > 0 && s[len - 1] <= ' ')
len--;
String k;
if (keyend <= 0) {
k = null;
keyend = 0;
} else {
k = String.copyValueOf(s, 0, keyend);
if (keyend < len && s[keyend] == ':')
keyend++;
while (keyend < len && s[keyend] <= ' ')
keyend++;
}
String v;
if (keyend >= len)
v = new String();
else
v = String.copyValueOf(s, keyend, len - keyend);
int klen = k == null ? 0 : k.length();
size = checkNewSize(size, klen, v.length());
add(k, v);
}
}
public synchronized String toString() {
String result = super.toString() + nkeys + " pairs: ";
for (int i = 0; i < keys.length && i < nkeys; i++) {
result += "{"+keys[i]+": "+values[i]+"}";
}
return result;
}
}

View File

@@ -0,0 +1,217 @@
/*
* Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www;
import java.net.URL;
import java.util.*;
import java.io.*;
import sun.net.ProgressSource;
import sun.net.www.http.ChunkedInputStream;
public class MeteredStream extends FilterInputStream {
// Instance variables.
/* if expected != -1, after we've read >= expected, we're "closed" and return -1
* from subsequest read() 's
*/
protected boolean closed = false;
protected long expected;
protected long count = 0;
protected long markedCount = 0;
protected int markLimit = -1;
protected ProgressSource pi;
public MeteredStream(InputStream is, ProgressSource pi, long expected)
{
super(is);
this.pi = pi;
this.expected = expected;
if (pi != null) {
pi.updateProgress(0, expected);
}
}
private final void justRead(long n) throws IOException {
if (n == -1) {
/*
* don't close automatically when mark is set and is valid;
* cannot reset() after close()
*/
if (!isMarked()) {
close();
}
return;
}
count += n;
/**
* If read beyond the markLimit, invalidate the mark
*/
if (count - markedCount > markLimit) {
markLimit = -1;
}
if (pi != null)
pi.updateProgress(count, expected);
if (isMarked()) {
return;
}
// if expected length is known, we could determine if
// read overrun.
if (expected > 0) {
if (count >= expected) {
close();
}
}
}
/**
* Returns true if the mark is valid, false otherwise
*/
private boolean isMarked() {
if (markLimit < 0) {
return false;
}
// mark is set, but is not valid anymore
if (count - markedCount > markLimit) {
return false;
}
// mark still holds
return true;
}
public synchronized int read() throws java.io.IOException {
if (closed) {
return -1;
}
int c = in.read();
if (c != -1) {
justRead(1);
} else {
justRead(c);
}
return c;
}
public synchronized int read(byte b[], int off, int len)
throws java.io.IOException {
if (closed) {
return -1;
}
int n = in.read(b, off, len);
justRead(n);
return n;
}
public synchronized long skip(long n) throws IOException {
// REMIND: what does skip do on EOF????
if (closed) {
return 0;
}
if (in instanceof ChunkedInputStream) {
n = in.skip(n);
}
else {
// just skip min(n, num_bytes_left)
long min = (n > expected - count) ? expected - count: n;
n = in.skip(min);
}
justRead(n);
return n;
}
public void close() throws IOException {
if (closed) {
return;
}
if (pi != null)
pi.finishTracking();
closed = true;
in.close();
}
public synchronized int available() throws IOException {
return closed ? 0: in.available();
}
public synchronized void mark(int readLimit) {
if (closed) {
return;
}
super.mark(readLimit);
/*
* mark the count to restore upon reset
*/
markedCount = count;
markLimit = readLimit;
}
public synchronized void reset() throws IOException {
if (closed) {
return;
}
if (!isMarked()) {
throw new IOException ("Resetting to an invalid mark");
}
count = markedCount;
super.reset();
}
public boolean markSupported() {
if (closed) {
return false;
}
return super.markSupported();
}
protected void finalize() throws Throwable {
try {
close();
if (pi != null)
pi.close();
}
finally {
// Call super class
super.finalize();
}
}
}

View File

@@ -0,0 +1,340 @@
/*
* Copyright (c) 1994, 2002, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www;
import java.net.URL;
import java.io.*;
import java.util.StringTokenizer;
public class MimeEntry implements Cloneable {
private String typeName; // of the form: "type/subtype"
private String tempFileNameTemplate;
private int action;
private String command;
private String description;
private String imageFileName;
private String fileExtensions[];
boolean starred;
// Actions
public static final int UNKNOWN = 0;
public static final int LOAD_INTO_BROWSER = 1;
public static final int SAVE_TO_FILE = 2;
public static final int LAUNCH_APPLICATION = 3;
static final String[] actionKeywords = {
"unknown",
"browser",
"save",
"application",
};
/**
* Construct an empty entry of the given type and subtype.
*/
public MimeEntry(String type) {
// Default action is UNKNOWN so clients can decide what the default
// should be, typically save to file or ask user.
this(type, UNKNOWN, null, null, null);
}
//
// The next two constructors are used only by the deprecated
// PlatformMimeTable classes or, in last case, is called by the public
// constructor. They are kept here anticipating putting support for
// mailcap formatted config files back in (so BOTH the properties format
// and the mailcap formats are supported).
//
MimeEntry(String type, String imageFileName, String extensionString) {
typeName = type.toLowerCase();
action = UNKNOWN;
command = null;
this.imageFileName = imageFileName;
setExtensions(extensionString);
starred = isStarred(typeName);
}
// For use with MimeTable::parseMailCap
MimeEntry(String typeName, int action, String command,
String tempFileNameTemplate) {
this.typeName = typeName.toLowerCase();
this.action = action;
this.command = command;
this.imageFileName = null;
this.fileExtensions = null;
this.tempFileNameTemplate = tempFileNameTemplate;
}
// This is the one called by the public constructor.
MimeEntry(String typeName, int action, String command,
String imageFileName, String fileExtensions[]) {
this.typeName = typeName.toLowerCase();
this.action = action;
this.command = command;
this.imageFileName = imageFileName;
this.fileExtensions = fileExtensions;
starred = isStarred(typeName);
}
public synchronized String getType() {
return typeName;
}
public synchronized void setType(String type) {
typeName = type.toLowerCase();
}
public synchronized int getAction() {
return action;
}
public synchronized void setAction(int action, String command) {
this.action = action;
this.command = command;
}
public synchronized void setAction(int action) {
this.action = action;
}
public synchronized String getLaunchString() {
return command;
}
public synchronized void setCommand(String command) {
this.command = command;
}
public synchronized String getDescription() {
return (description != null ? description : typeName);
}
public synchronized void setDescription(String description) {
this.description = description;
}
// ??? what to return for the image -- the file name or should this return
// something more advanced like an image source or something?
// returning the name has the least policy associated with it.
// pro tempore, we'll use the name
public String getImageFileName() {
return imageFileName;
}
public synchronized void setImageFileName(String filename) {
File file = new File(filename);
if (file.getParent() == null) {
imageFileName = System.getProperty(
"java.net.ftp.imagepath."+filename);
}
else {
imageFileName = filename;
}
if (filename.lastIndexOf('.') < 0) {
imageFileName = imageFileName + ".gif";
}
}
public String getTempFileTemplate() {
return tempFileNameTemplate;
}
public synchronized String[] getExtensions() {
return fileExtensions;
}
public synchronized String getExtensionsAsList() {
String extensionsAsString = "";
if (fileExtensions != null) {
for (int i = 0; i < fileExtensions.length; i++) {
extensionsAsString += fileExtensions[i];
if (i < (fileExtensions.length - 1)) {
extensionsAsString += ",";
}
}
}
return extensionsAsString;
}
public synchronized void setExtensions(String extensionString) {
StringTokenizer extTokens = new StringTokenizer(extensionString, ",");
int numExts = extTokens.countTokens();
String extensionStrings[] = new String[numExts];
for (int i = 0; i < numExts; i++) {
String ext = (String)extTokens.nextElement();
extensionStrings[i] = ext.trim();
}
fileExtensions = extensionStrings;
}
private boolean isStarred(String typeName) {
return (typeName != null)
&& (typeName.length() > 0)
&& (typeName.endsWith("/*"));
}
/**
* Invoke the MIME type specific behavior for this MIME type.
* Returned value can be one of several types:
* <ol>
* <li>A thread -- the caller can choose when to launch this thread.
* <li>A string -- the string is loaded into the browser directly.
* <li>An input stream -- the caller can read from this byte stream and
* will typically store the results in a file.
* <li>A document (?) --
* </ol>
*/
public Object launch(java.net.URLConnection urlc, InputStream is, MimeTable mt) throws ApplicationLaunchException {
switch (action) {
case SAVE_TO_FILE:
// REMIND: is this really the right thing to do?
try {
return is;
} catch(Exception e) {
// I18N
return "Load to file failed:\n" + e;
}
case LOAD_INTO_BROWSER:
// REMIND: invoke the content handler?
// may be the right thing to do, may not be -- short term
// where docs are not loaded asynch, loading and returning
// the content is the right thing to do.
try {
return urlc.getContent();
} catch (Exception e) {
return null;
}
case LAUNCH_APPLICATION:
{
String threadName = command;
int fst = threadName.indexOf(' ');
if (fst > 0) {
threadName = threadName.substring(0, fst);
}
return new MimeLauncher(this, urlc, is,
mt.getTempFileTemplate(), threadName);
}
case UNKNOWN:
// REMIND: What do do here?
return null;
}
return null;
}
public boolean matches(String type) {
if (starred) {
// REMIND: is this the right thing or not?
return type.startsWith(typeName);
} else {
return type.equals(typeName);
}
}
public Object clone() {
// return a shallow copy of this.
MimeEntry theClone = new MimeEntry(typeName);
theClone.action = action;
theClone.command = command;
theClone.description = description;
theClone.imageFileName = imageFileName;
theClone.tempFileNameTemplate = tempFileNameTemplate;
theClone.fileExtensions = fileExtensions;
return theClone;
}
public synchronized String toProperty() {
StringBuffer buf = new StringBuffer();
String separator = "; ";
boolean needSeparator = false;
int action = getAction();
if (action != MimeEntry.UNKNOWN) {
buf.append("action=" + actionKeywords[action]);
needSeparator = true;
}
String command = getLaunchString();
if (command != null && command.length() > 0) {
if (needSeparator) {
buf.append(separator);
}
buf.append("application=" + command);
needSeparator = true;
}
if (getImageFileName() != null) {
if (needSeparator) {
buf.append(separator);
}
buf.append("icon=" + getImageFileName());
needSeparator = true;
}
String extensions = getExtensionsAsList();
if (extensions.length() > 0) {
if (needSeparator) {
buf.append(separator);
}
buf.append("file_extensions=" + extensions);
needSeparator = true;
}
String description = getDescription();
if (description != null && !description.equals(getType())) {
if (needSeparator) {
buf.append(separator);
}
buf.append("description=" + description);
}
return buf.toString();
}
public String toString() {
return "MimeEntry[contentType=" + typeName
+ ", image=" + imageFileName
+ ", action=" + action
+ ", command=" + command
+ ", extensions=" + getExtensionsAsList()
+ "]";
}
}

View File

@@ -0,0 +1,205 @@
/*
* Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www;
import java.net.URL;
import java.io.*;
import java.util.StringTokenizer;
class MimeLauncher extends Thread {
java.net.URLConnection uc;
MimeEntry m;
String genericTempFileTemplate;
InputStream is;
String execPath;
MimeLauncher (MimeEntry M, java.net.URLConnection uc,
InputStream is, String tempFileTemplate, String threadName) throws ApplicationLaunchException {
super(threadName);
m = M;
this.uc = uc;
this.is = is;
genericTempFileTemplate = tempFileTemplate;
/* get the application to launch */
String launchString = m.getLaunchString();
/* get a valid path to launch application - sets
the execPath instance variable with the correct path.
*/
if (!findExecutablePath(launchString)) {
/* strip off parameters i.e %s */
String appName;
int index = launchString.indexOf(' ');
if (index != -1) {
appName = launchString.substring(0, index);
}
else {
appName = launchString;
}
throw new ApplicationLaunchException(appName);
}
}
protected String getTempFileName(URL url, String template) {
String tempFilename = template;
// Replace all but last occurrance of "%s" with timestamp to insure
// uniqueness. There's a subtle behavior here: if there is anything
// _after_ the last "%s" we need to append it so that unusual launch
// strings that have the datafile in the middle can still be used.
int wildcard = tempFilename.lastIndexOf("%s");
String prefix = tempFilename.substring(0, wildcard);
String suffix = "";
if (wildcard < tempFilename.length() - 2) {
suffix = tempFilename.substring(wildcard + 2);
}
long timestamp = System.currentTimeMillis()/1000;
int argIndex = 0;
while ((argIndex = prefix.indexOf("%s")) >= 0) {
prefix = prefix.substring(0, argIndex)
+ timestamp
+ prefix.substring(argIndex + 2);
}
// Add a file name and file-extension if known
String filename = url.getFile();
String extension = "";
int dot = filename.lastIndexOf('.');
// BugId 4084826: Temp MIME file names not always valid.
// Fix: don't allow slashes in the file name or extension.
if (dot >= 0 && dot > filename.lastIndexOf('/')) {
extension = filename.substring(dot);
}
filename = "HJ" + url.hashCode();
tempFilename = prefix + filename + timestamp + extension + suffix;
return tempFilename;
}
public void run() {
try {
String ofn = m.getTempFileTemplate();
if (ofn == null) {
ofn = genericTempFileTemplate;
}
ofn = getTempFileName(uc.getURL(), ofn);
try {
OutputStream os = new FileOutputStream(ofn);
byte buf[] = new byte[2048];
int i = 0;
try {
while ((i = is.read(buf)) >= 0) {
os.write(buf, 0, i);
}
} catch(IOException e) {
//System.err.println("Exception in write loop " + i);
//e.printStackTrace();
} finally {
os.close();
is.close();
}
} catch(IOException e) {
//System.err.println("Exception in input or output stream");
//e.printStackTrace();
}
int inx = 0;
String c = execPath;
while ((inx = c.indexOf("%t")) >= 0) {
c = c.substring(0, inx) + uc.getContentType()
+ c.substring(inx + 2);
}
boolean substituted = false;
while ((inx = c.indexOf("%s")) >= 0) {
c = c.substring(0, inx) + ofn + c.substring(inx + 2);
substituted = true;
}
if (!substituted)
c = c + " <" + ofn;
// System.out.println("Execing " +c);
Runtime.getRuntime().exec(c);
} catch(IOException e) {
}
}
/* This method determines the path for the launcher application
and sets the execPath instance variable. It uses the exec.path
property to obtain a list of paths that is in turn used to
location the application. If a valid path is not found, it
returns false else true. */
private boolean findExecutablePath(String str) {
if (str == null || str.length() == 0) {
return false;
}
String command;
int index = str.indexOf(' ');
if (index != -1) {
command = str.substring(0, index);
}
else {
command = str;
}
File f = new File(command);
if (f.isFile()) {
// Already executable as it is
execPath = str;
return true;
}
String execPathList;
execPathList = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("exec.path"));
if (execPathList == null) {
// exec.path property not set
return false;
}
StringTokenizer iter = new StringTokenizer(execPathList, "|");
while (iter.hasMoreElements()) {
String prefix = (String)iter.nextElement();
String fullCmd = prefix + File.separator + command;
f = new File(fullCmd);
if (f.isFile()) {
execPath = prefix + File.separator + str;
return true;
}
}
return false; // application not found in exec.path
}
}

View File

@@ -0,0 +1,459 @@
/*
* Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www;
import java.io.*;
import java.net.FileNameMap;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Properties;
import java.util.StringTokenizer;
public class MimeTable implements FileNameMap {
/** Keyed by content type, returns MimeEntries */
private Hashtable<String, MimeEntry> entries
= new Hashtable<String, MimeEntry>();
/** Keyed by file extension (with the .), returns MimeEntries */
private Hashtable<String, MimeEntry> extensionMap
= new Hashtable<String, MimeEntry>();
// Will be reset if in the platform-specific data file
private static String tempFileTemplate;
static {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
tempFileTemplate =
System.getProperty("content.types.temp.file.template",
"/tmp/%s");
mailcapLocations = new String[] {
System.getProperty("user.mailcap"),
System.getProperty("user.home") + "/.mailcap",
"/etc/mailcap",
"/usr/etc/mailcap",
"/usr/local/etc/mailcap",
System.getProperty("hotjava.home",
"/usr/local/hotjava")
+ "/lib/mailcap",
};
return null;
}
});
}
private static final String filePreamble = "sun.net.www MIME content-types table";
private static final String fileMagic = "#" + filePreamble;
MimeTable() {
load();
}
private static class DefaultInstanceHolder {
static final MimeTable defaultInstance = getDefaultInstance();
static MimeTable getDefaultInstance() {
return java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<MimeTable>() {
public MimeTable run() {
MimeTable instance = new MimeTable();
URLConnection.setFileNameMap(instance);
return instance;
}
});
}
}
/**
* Get the single instance of this class. First use will load the
* table from a data file.
*/
public static MimeTable getDefaultTable() {
return DefaultInstanceHolder.defaultInstance;
}
/**
*
*/
public static FileNameMap loadTable() {
MimeTable mt = getDefaultTable();
return (FileNameMap)mt;
}
public synchronized int getSize() {
return entries.size();
}
public synchronized String getContentTypeFor(String fileName) {
MimeEntry entry = findByFileName(fileName);
if (entry != null) {
return entry.getType();
} else {
return null;
}
}
public synchronized void add(MimeEntry m) {
entries.put(m.getType(), m);
String exts[] = m.getExtensions();
if (exts == null) {
return;
}
for (int i = 0; i < exts.length; i++) {
extensionMap.put(exts[i], m);
}
}
public synchronized MimeEntry remove(String type) {
MimeEntry entry = entries.get(type);
return remove(entry);
}
public synchronized MimeEntry remove(MimeEntry entry) {
String[] extensionKeys = entry.getExtensions();
if (extensionKeys != null) {
for (int i = 0; i < extensionKeys.length; i++) {
extensionMap.remove(extensionKeys[i]);
}
}
return entries.remove(entry.getType());
}
public synchronized MimeEntry find(String type) {
MimeEntry entry = entries.get(type);
if (entry == null) {
// try a wildcard lookup
Enumeration<MimeEntry> e = entries.elements();
while (e.hasMoreElements()) {
MimeEntry wild = e.nextElement();
if (wild.matches(type)) {
return wild;
}
}
}
return entry;
}
/**
* Locate a MimeEntry by the file extension that has been associated
* with it. Parses general file names, and URLs.
*/
public MimeEntry findByFileName(String fname) {
String ext = "";
int i = fname.lastIndexOf('#');
if (i > 0) {
fname = fname.substring(0, i - 1);
}
i = fname.lastIndexOf('.');
// REMIND: OS specific delimters appear here
i = Math.max(i, fname.lastIndexOf('/'));
i = Math.max(i, fname.lastIndexOf('?'));
if (i != -1 && fname.charAt(i) == '.') {
ext = fname.substring(i).toLowerCase();
}
return findByExt(ext);
}
/**
* Locate a MimeEntry by the file extension that has been associated
* with it.
*/
public synchronized MimeEntry findByExt(String fileExtension) {
return extensionMap.get(fileExtension);
}
public synchronized MimeEntry findByDescription(String description) {
Enumeration<MimeEntry> e = elements();
while (e.hasMoreElements()) {
MimeEntry entry = e.nextElement();
if (description.equals(entry.getDescription())) {
return entry;
}
}
// We failed, now try treating description as type
return find(description);
}
String getTempFileTemplate() {
return tempFileTemplate;
}
public synchronized Enumeration<MimeEntry> elements() {
return entries.elements();
}
// For backward compatibility -- mailcap format files
// This is not currently used, but may in the future when we add ability
// to read BOTH the properties format and the mailcap format.
protected static String[] mailcapLocations;
public synchronized void load() {
Properties entries = new Properties();
File file = null;
try {
InputStream is;
// First try to load the user-specific table, if it exists
String userTablePath =
System.getProperty("content.types.user.table");
if (userTablePath != null) {
file = new File(userTablePath);
if (!file.exists()) {
// No user-table, try to load the default built-in table.
file = new File(System.getProperty("java.home") +
File.separator +
"lib" +
File.separator +
"content-types.properties");
}
}
else {
// No user table, try to load the default built-in table.
file = new File(System.getProperty("java.home") +
File.separator +
"lib" +
File.separator +
"content-types.properties");
}
is = new BufferedInputStream(new FileInputStream(file));
entries.load(is);
is.close();
}
catch (IOException e) {
System.err.println("Warning: default mime table not found: " +
file.getPath());
return;
}
parse(entries);
}
void parse(Properties entries) {
// first, strip out the platform-specific temp file template
String tempFileTemplate = (String)entries.get("temp.file.template");
if (tempFileTemplate != null) {
entries.remove("temp.file.template");
MimeTable.tempFileTemplate = tempFileTemplate;
}
// now, parse the mime-type spec's
Enumeration<?> types = entries.propertyNames();
while (types.hasMoreElements()) {
String type = (String)types.nextElement();
String attrs = entries.getProperty(type);
parse(type, attrs);
}
}
//
// Table format:
//
// <entry> ::= <table_tag> | <type_entry>
//
// <table_tag> ::= <table_format_version> | <temp_file_template>
//
// <type_entry> ::= <type_subtype_pair> '=' <type_attrs_list>
//
// <type_subtype_pair> ::= <type> '/' <subtype>
//
// <type_attrs_list> ::= <attr_value_pair> [ ';' <attr_value_pair> ]*
// | [ <attr_value_pair> ]+
//
// <attr_value_pair> ::= <attr_name> '=' <attr_value>
//
// <attr_name> ::= 'description' | 'action' | 'application'
// | 'file_extensions' | 'icon'
//
// <attr_value> ::= <legal_char>*
//
// Embedded ';' in an <attr_value> are quoted with leading '\' .
//
// Interpretation of <attr_value> depends on the <attr_name> it is
// associated with.
//
void parse(String type, String attrs) {
MimeEntry newEntry = new MimeEntry(type);
// REMIND handle embedded ';' and '|' and literal '"'
StringTokenizer tokenizer = new StringTokenizer(attrs, ";");
while (tokenizer.hasMoreTokens()) {
String pair = tokenizer.nextToken();
parse(pair, newEntry);
}
add(newEntry);
}
void parse(String pair, MimeEntry entry) {
// REMIND add exception handling...
String name = null;
String value = null;
boolean gotName = false;
StringTokenizer tokenizer = new StringTokenizer(pair, "=");
while (tokenizer.hasMoreTokens()) {
if (gotName) {
value = tokenizer.nextToken().trim();
}
else {
name = tokenizer.nextToken().trim();
gotName = true;
}
}
fill(entry, name, value);
}
void fill(MimeEntry entry, String name, String value) {
if ("description".equalsIgnoreCase(name)) {
entry.setDescription(value);
}
else if ("action".equalsIgnoreCase(name)) {
entry.setAction(getActionCode(value));
}
else if ("application".equalsIgnoreCase(name)) {
entry.setCommand(value);
}
else if ("icon".equalsIgnoreCase(name)) {
entry.setImageFileName(value);
}
else if ("file_extensions".equalsIgnoreCase(name)) {
entry.setExtensions(value);
}
// else illegal name exception
}
String[] getExtensions(String list) {
StringTokenizer tokenizer = new StringTokenizer(list, ",");
int n = tokenizer.countTokens();
String[] extensions = new String[n];
for (int i = 0; i < n; i++) {
extensions[i] = tokenizer.nextToken();
}
return extensions;
}
int getActionCode(String action) {
for (int i = 0; i < MimeEntry.actionKeywords.length; i++) {
if (action.equalsIgnoreCase(MimeEntry.actionKeywords[i])) {
return i;
}
}
return MimeEntry.UNKNOWN;
}
public synchronized boolean save(String filename) {
if (filename == null) {
filename = System.getProperty("user.home" +
File.separator +
"lib" +
File.separator +
"content-types.properties");
}
return saveAsProperties(new File(filename));
}
public Properties getAsProperties() {
Properties properties = new Properties();
Enumeration<MimeEntry> e = elements();
while (e.hasMoreElements()) {
MimeEntry entry = e.nextElement();
properties.put(entry.getType(), entry.toProperty());
}
return properties;
}
protected boolean saveAsProperties(File file) {
FileOutputStream os = null;
try {
os = new FileOutputStream(file);
Properties properties = getAsProperties();
properties.put("temp.file.template", tempFileTemplate);
String tag;
String user = System.getProperty("user.name");
if (user != null) {
tag = "; customized for " + user;
properties.store(os, filePreamble + tag);
}
else {
properties.store(os, filePreamble);
}
}
catch (IOException e) {
e.printStackTrace();
return false;
}
finally {
if (os != null) {
try { os.close(); } catch (IOException e) {}
}
}
return true;
}
/*
* Debugging utilities
*
public void list(PrintStream out) {
Enumeration keys = entries.keys();
while (keys.hasMoreElements()) {
String key = (String)keys.nextElement();
MimeEntry entry = (MimeEntry)entries.get(key);
out.println(key + ": " + entry);
}
}
public static void main(String[] args) {
MimeTable testTable = MimeTable.getDefaultTable();
Enumeration e = testTable.elements();
while (e.hasMoreElements()) {
MimeEntry entry = (MimeEntry)e.nextElement();
System.out.println(entry);
}
testTable.save(File.separator + "tmp" +
File.separator + "mime_table.save");
}
*/
}

View File

@@ -0,0 +1,680 @@
/*
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www;
import java.util.BitSet;
import java.io.UnsupportedEncodingException;
import java.io.File;
import java.net.URL;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import sun.nio.cs.ThreadLocalCoders;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
/**
* A class that contains useful routines common to sun.net.www
* @author Mike McCloskey
*/
public class ParseUtil {
static BitSet encodedInPath;
static {
encodedInPath = new BitSet(256);
// Set the bits corresponding to characters that are encoded in the
// path component of a URI.
// These characters are reserved in the path segment as described in
// RFC2396 section 3.3.
encodedInPath.set('=');
encodedInPath.set(';');
encodedInPath.set('?');
encodedInPath.set('/');
// These characters are defined as excluded in RFC2396 section 2.4.3
// and must be escaped if they occur in the data part of a URI.
encodedInPath.set('#');
encodedInPath.set(' ');
encodedInPath.set('<');
encodedInPath.set('>');
encodedInPath.set('%');
encodedInPath.set('"');
encodedInPath.set('{');
encodedInPath.set('}');
encodedInPath.set('|');
encodedInPath.set('\\');
encodedInPath.set('^');
encodedInPath.set('[');
encodedInPath.set(']');
encodedInPath.set('`');
// US ASCII control characters 00-1F and 7F.
for (int i=0; i<32; i++)
encodedInPath.set(i);
encodedInPath.set(127);
}
/**
* Constructs an encoded version of the specified path string suitable
* for use in the construction of a URL.
*
* A path separator is replaced by a forward slash. The string is UTF8
* encoded. The % escape sequence is used for characters that are above
* 0x7F or those defined in RFC2396 as reserved or excluded in the path
* component of a URL.
*/
public static String encodePath(String path) {
return encodePath(path, true);
}
/*
* flag indicates whether path uses platform dependent
* File.separatorChar or not. True indicates path uses platform
* dependent File.separatorChar.
*/
public static String encodePath(String path, boolean flag) {
char[] retCC = new char[path.length() * 2 + 16];
int retLen = 0;
char[] pathCC = path.toCharArray();
int n = path.length();
for (int i=0; i<n; i++) {
char c = pathCC[i];
if ((!flag && c == '/') || (flag && c == File.separatorChar))
retCC[retLen++] = '/';
else {
if (c <= 0x007F) {
if (c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9') {
retCC[retLen++] = c;
} else
if (encodedInPath.get(c))
retLen = escape(retCC, c, retLen);
else
retCC[retLen++] = c;
} else if (c > 0x07FF) {
retLen = escape(retCC, (char)(0xE0 | ((c >> 12) & 0x0F)), retLen);
retLen = escape(retCC, (char)(0x80 | ((c >> 6) & 0x3F)), retLen);
retLen = escape(retCC, (char)(0x80 | ((c >> 0) & 0x3F)), retLen);
} else {
retLen = escape(retCC, (char)(0xC0 | ((c >> 6) & 0x1F)), retLen);
retLen = escape(retCC, (char)(0x80 | ((c >> 0) & 0x3F)), retLen);
}
}
//worst case scenario for character [0x7ff-] every single
//character will be encoded into 9 characters.
if (retLen + 9 > retCC.length) {
int newLen = retCC.length * 2 + 16;
if (newLen < 0) {
newLen = Integer.MAX_VALUE;
}
char[] buf = new char[newLen];
System.arraycopy(retCC, 0, buf, 0, retLen);
retCC = buf;
}
}
return new String(retCC, 0, retLen);
}
/**
* Appends the URL escape sequence for the specified char to the
* specified StringBuffer.
*/
private static int escape(char[] cc, char c, int index) {
cc[index++] = '%';
cc[index++] = Character.forDigit((c >> 4) & 0xF, 16);
cc[index++] = Character.forDigit(c & 0xF, 16);
return index;
}
/**
* Un-escape and return the character at position i in string s.
*/
private static byte unescape(String s, int i) {
return (byte) Integer.parseInt(s.substring(i+1,i+3),16);
}
/**
* Returns a new String constructed from the specified String by replacing
* the URL escape sequences and UTF8 encoding with the characters they
* represent.
*/
public static String decode(String s) {
int n = s.length();
if ((n == 0) || (s.indexOf('%') < 0))
return s;
StringBuilder sb = new StringBuilder(n);
ByteBuffer bb = ByteBuffer.allocate(n);
CharBuffer cb = CharBuffer.allocate(n);
CharsetDecoder dec = ThreadLocalCoders.decoderFor("UTF-8")
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT);
char c = s.charAt(0);
for (int i = 0; i < n;) {
assert c == s.charAt(i);
if (c != '%') {
sb.append(c);
if (++i >= n)
break;
c = s.charAt(i);
continue;
}
bb.clear();
int ui = i;
for (;;) {
assert (n - i >= 2);
try {
bb.put(unescape(s, i));
} catch (NumberFormatException e) {
throw new IllegalArgumentException();
}
i += 3;
if (i >= n)
break;
c = s.charAt(i);
if (c != '%')
break;
}
bb.flip();
cb.clear();
dec.reset();
CoderResult cr = dec.decode(bb, cb, true);
if (cr.isError())
throw new IllegalArgumentException("Error decoding percent encoded characters");
cr = dec.flush(cb);
if (cr.isError())
throw new IllegalArgumentException("Error decoding percent encoded characters");
sb.append(cb.flip().toString());
}
return sb.toString();
}
/**
* Returns a canonical version of the specified string.
*/
public String canonizeString(String file) {
int i = 0;
int lim = file.length();
// Remove embedded /../
while ((i = file.indexOf("/../")) >= 0) {
if ((lim = file.lastIndexOf('/', i - 1)) >= 0) {
file = file.substring(0, lim) + file.substring(i + 3);
} else {
file = file.substring(i + 3);
}
}
// Remove embedded /./
while ((i = file.indexOf("/./")) >= 0) {
file = file.substring(0, i) + file.substring(i + 2);
}
// Remove trailing ..
while (file.endsWith("/..")) {
i = file.indexOf("/..");
if ((lim = file.lastIndexOf('/', i - 1)) >= 0) {
file = file.substring(0, lim+1);
} else {
file = file.substring(0, i);
}
}
// Remove trailing .
if (file.endsWith("/."))
file = file.substring(0, file.length() -1);
return file;
}
public static URL fileToEncodedURL(File file)
throws MalformedURLException
{
String path = file.getAbsolutePath();
path = ParseUtil.encodePath(path);
if (!path.startsWith("/")) {
path = "/" + path;
}
if (!path.endsWith("/") && file.isDirectory()) {
path = path + "/";
}
return new URL("file", "", path);
}
public static java.net.URI toURI(URL url) {
String protocol = url.getProtocol();
String auth = url.getAuthority();
String path = url.getPath();
String query = url.getQuery();
String ref = url.getRef();
if (path != null && !(path.startsWith("/")))
path = "/" + path;
//
// In java.net.URI class, a port number of -1 implies the default
// port number. So get it stripped off before creating URI instance.
//
if (auth != null && auth.endsWith(":-1"))
auth = auth.substring(0, auth.length() - 3);
java.net.URI uri;
try {
uri = createURI(protocol, auth, path, query, ref);
} catch (java.net.URISyntaxException e) {
uri = null;
}
return uri;
}
//
// createURI() and its auxiliary code are cloned from java.net.URI.
// Most of the code are just copy and paste, except that quote()
// has been modified to avoid double-escape.
//
// Usually it is unacceptable, but we're forced to do it because
// otherwise we need to change public API, namely java.net.URI's
// multi-argument constructors. It turns out that the changes cause
// incompatibilities so can't be done.
//
private static URI createURI(String scheme,
String authority,
String path,
String query,
String fragment) throws URISyntaxException
{
String s = toString(scheme, null,
authority, null, null, -1,
path, query, fragment);
checkPath(s, scheme, path);
return new URI(s);
}
private static String toString(String scheme,
String opaquePart,
String authority,
String userInfo,
String host,
int port,
String path,
String query,
String fragment)
{
StringBuffer sb = new StringBuffer();
if (scheme != null) {
sb.append(scheme);
sb.append(':');
}
appendSchemeSpecificPart(sb, opaquePart,
authority, userInfo, host, port,
path, query);
appendFragment(sb, fragment);
return sb.toString();
}
private static void appendSchemeSpecificPart(StringBuffer sb,
String opaquePart,
String authority,
String userInfo,
String host,
int port,
String path,
String query)
{
if (opaquePart != null) {
/* check if SSP begins with an IPv6 address
* because we must not quote a literal IPv6 address
*/
if (opaquePart.startsWith("//[")) {
int end = opaquePart.indexOf("]");
if (end != -1 && opaquePart.indexOf(":")!=-1) {
String doquote, dontquote;
if (end == opaquePart.length()) {
dontquote = opaquePart;
doquote = "";
} else {
dontquote = opaquePart.substring(0,end+1);
doquote = opaquePart.substring(end+1);
}
sb.append (dontquote);
sb.append(quote(doquote, L_URIC, H_URIC));
}
} else {
sb.append(quote(opaquePart, L_URIC, H_URIC));
}
} else {
appendAuthority(sb, authority, userInfo, host, port);
if (path != null)
sb.append(quote(path, L_PATH, H_PATH));
if (query != null) {
sb.append('?');
sb.append(quote(query, L_URIC, H_URIC));
}
}
}
private static void appendAuthority(StringBuffer sb,
String authority,
String userInfo,
String host,
int port)
{
if (host != null) {
sb.append("//");
if (userInfo != null) {
sb.append(quote(userInfo, L_USERINFO, H_USERINFO));
sb.append('@');
}
boolean needBrackets = ((host.indexOf(':') >= 0)
&& !host.startsWith("[")
&& !host.endsWith("]"));
if (needBrackets) sb.append('[');
sb.append(host);
if (needBrackets) sb.append(']');
if (port != -1) {
sb.append(':');
sb.append(port);
}
} else if (authority != null) {
sb.append("//");
if (authority.startsWith("[")) {
int end = authority.indexOf("]");
if (end != -1 && authority.indexOf(":")!=-1) {
String doquote, dontquote;
if (end == authority.length()) {
dontquote = authority;
doquote = "";
} else {
dontquote = authority.substring(0,end+1);
doquote = authority.substring(end+1);
}
sb.append (dontquote);
sb.append(quote(doquote,
L_REG_NAME | L_SERVER,
H_REG_NAME | H_SERVER));
}
} else {
sb.append(quote(authority,
L_REG_NAME | L_SERVER,
H_REG_NAME | H_SERVER));
}
}
}
private static void appendFragment(StringBuffer sb, String fragment) {
if (fragment != null) {
sb.append('#');
sb.append(quote(fragment, L_URIC, H_URIC));
}
}
// Quote any characters in s that are not permitted
// by the given mask pair
//
private static String quote(String s, long lowMask, long highMask) {
int n = s.length();
StringBuffer sb = null;
boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c < '\u0080') {
if (!match(c, lowMask, highMask) && !isEscaped(s, i)) {
if (sb == null) {
sb = new StringBuffer();
sb.append(s.substring(0, i));
}
appendEscape(sb, (byte)c);
} else {
if (sb != null)
sb.append(c);
}
} else if (allowNonASCII
&& (Character.isSpaceChar(c)
|| Character.isISOControl(c))) {
if (sb == null) {
sb = new StringBuffer();
sb.append(s.substring(0, i));
}
appendEncoded(sb, c);
} else {
if (sb != null)
sb.append(c);
}
}
return (sb == null) ? s : sb.toString();
}
//
// To check if the given string has an escaped triplet
// at the given position
//
private static boolean isEscaped(String s, int pos) {
if (s == null || (s.length() <= (pos + 2)))
return false;
return s.charAt(pos) == '%'
&& match(s.charAt(pos + 1), L_HEX, H_HEX)
&& match(s.charAt(pos + 2), L_HEX, H_HEX);
}
private static void appendEncoded(StringBuffer sb, char c) {
ByteBuffer bb = null;
try {
bb = ThreadLocalCoders.encoderFor("UTF-8")
.encode(CharBuffer.wrap("" + c));
} catch (CharacterCodingException x) {
assert false;
}
while (bb.hasRemaining()) {
int b = bb.get() & 0xff;
if (b >= 0x80)
appendEscape(sb, (byte)b);
else
sb.append((char)b);
}
}
private final static char[] hexDigits = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
private static void appendEscape(StringBuffer sb, byte b) {
sb.append('%');
sb.append(hexDigits[(b >> 4) & 0x0f]);
sb.append(hexDigits[(b >> 0) & 0x0f]);
}
// Tell whether the given character is permitted by the given mask pair
private static boolean match(char c, long lowMask, long highMask) {
if (c < 64)
return ((1L << c) & lowMask) != 0;
if (c < 128)
return ((1L << (c - 64)) & highMask) != 0;
return false;
}
// If a scheme is given then the path, if given, must be absolute
//
private static void checkPath(String s, String scheme, String path)
throws URISyntaxException
{
if (scheme != null) {
if ((path != null)
&& ((path.length() > 0) && (path.charAt(0) != '/')))
throw new URISyntaxException(s,
"Relative path in absolute URI");
}
}
// -- Character classes for parsing --
// Compute a low-order mask for the characters
// between first and last, inclusive
private static long lowMask(char first, char last) {
long m = 0;
int f = Math.max(Math.min(first, 63), 0);
int l = Math.max(Math.min(last, 63), 0);
for (int i = f; i <= l; i++)
m |= 1L << i;
return m;
}
// Compute the low-order mask for the characters in the given string
private static long lowMask(String chars) {
int n = chars.length();
long m = 0;
for (int i = 0; i < n; i++) {
char c = chars.charAt(i);
if (c < 64)
m |= (1L << c);
}
return m;
}
// Compute a high-order mask for the characters
// between first and last, inclusive
private static long highMask(char first, char last) {
long m = 0;
int f = Math.max(Math.min(first, 127), 64) - 64;
int l = Math.max(Math.min(last, 127), 64) - 64;
for (int i = f; i <= l; i++)
m |= 1L << i;
return m;
}
// Compute the high-order mask for the characters in the given string
private static long highMask(String chars) {
int n = chars.length();
long m = 0;
for (int i = 0; i < n; i++) {
char c = chars.charAt(i);
if ((c >= 64) && (c < 128))
m |= (1L << (c - 64));
}
return m;
}
// Character-class masks
// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
// "8" | "9"
private static final long L_DIGIT = lowMask('0', '9');
private static final long H_DIGIT = 0L;
// hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
// "a" | "b" | "c" | "d" | "e" | "f"
private static final long L_HEX = L_DIGIT;
private static final long H_HEX = highMask('A', 'F') | highMask('a', 'f');
// upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
// "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
// "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
private static final long L_UPALPHA = 0L;
private static final long H_UPALPHA = highMask('A', 'Z');
// lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
// "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
// "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
private static final long L_LOWALPHA = 0L;
private static final long H_LOWALPHA = highMask('a', 'z');
// alpha = lowalpha | upalpha
private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA;
private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA;
// alphanum = alpha | digit
private static final long L_ALPHANUM = L_DIGIT | L_ALPHA;
private static final long H_ALPHANUM = H_DIGIT | H_ALPHA;
// mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
// "(" | ")"
private static final long L_MARK = lowMask("-_.!~*'()");
private static final long H_MARK = highMask("-_.!~*'()");
// unreserved = alphanum | mark
private static final long L_UNRESERVED = L_ALPHANUM | L_MARK;
private static final long H_UNRESERVED = H_ALPHANUM | H_MARK;
// reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
// "$" | "," | "[" | "]"
// Added per RFC2732: "[", "]"
private static final long L_RESERVED = lowMask(";/?:@&=+$,[]");
private static final long H_RESERVED = highMask(";/?:@&=+$,[]");
// The zero'th bit is used to indicate that escape pairs and non-US-ASCII
// characters are allowed; this is handled by the scanEscape method below.
private static final long L_ESCAPED = 1L;
private static final long H_ESCAPED = 0L;
// Dash, for use in domainlabel and toplabel
private static final long L_DASH = lowMask("-");
private static final long H_DASH = highMask("-");
// uric = reserved | unreserved | escaped
private static final long L_URIC = L_RESERVED | L_UNRESERVED | L_ESCAPED;
private static final long H_URIC = H_RESERVED | H_UNRESERVED | H_ESCAPED;
// pchar = unreserved | escaped |
// ":" | "@" | "&" | "=" | "+" | "$" | ","
private static final long L_PCHAR
= L_UNRESERVED | L_ESCAPED | lowMask(":@&=+$,");
private static final long H_PCHAR
= H_UNRESERVED | H_ESCAPED | highMask(":@&=+$,");
// All valid path characters
private static final long L_PATH = L_PCHAR | lowMask(";/");
private static final long H_PATH = H_PCHAR | highMask(";/");
// userinfo = *( unreserved | escaped |
// ";" | ":" | "&" | "=" | "+" | "$" | "," )
private static final long L_USERINFO
= L_UNRESERVED | L_ESCAPED | lowMask(";:&=+$,");
private static final long H_USERINFO
= H_UNRESERVED | H_ESCAPED | highMask(";:&=+$,");
// reg_name = 1*( unreserved | escaped | "$" | "," |
// ";" | ":" | "@" | "&" | "=" | "+" )
private static final long L_REG_NAME
= L_UNRESERVED | L_ESCAPED | lowMask("$,;:@&=+");
private static final long H_REG_NAME
= H_UNRESERVED | H_ESCAPED | highMask("$,;:@&=+");
// All valid characters for server-based authorities
private static final long L_SERVER
= L_USERINFO | L_ALPHANUM | L_DASH | lowMask(".:@[]");
private static final long H_SERVER
= H_USERINFO | H_ALPHANUM | H_DASH | highMask(".:@[]");
}

View File

@@ -0,0 +1,246 @@
/*
* Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www;
import java.net.URL;
import java.util.*;
/**
* A class to represent an active connection to an object
* represented by a URL.
* @author James Gosling
*/
abstract public class URLConnection extends java.net.URLConnection {
/** The URL that it is connected to */
private String contentType;
private int contentLength = -1;
protected MessageHeader properties;
/** Create a URLConnection object. These should not be created directly:
instead they should be created by protocol handers in response to
URL.openConnection.
@param u The URL that this connects to.
*/
public URLConnection (URL u) {
super(u);
properties = new MessageHeader();
}
/** Call this routine to get the property list for this object.
* Properties (like content-type) that have explicit getXX() methods
* associated with them should be accessed using those methods. */
public MessageHeader getProperties() {
return properties;
}
/** Call this routine to set the property list for this object. */
public void setProperties(MessageHeader properties) {
this.properties = properties;
}
public void setRequestProperty(String key, String value) {
if(connected)
throw new IllegalAccessError("Already connected");
if (key == null)
throw new NullPointerException ("key cannot be null");
properties.set(key, value);
}
/**
* The following three methods addRequestProperty, getRequestProperty,
* and getRequestProperties were copied from the superclass implementation
* before it was changed by CR:6230836, to maintain backward compatibility.
*/
public void addRequestProperty(String key, String value) {
if (connected)
throw new IllegalStateException("Already connected");
if (key == null)
throw new NullPointerException ("key is null");
}
public String getRequestProperty(String key) {
if (connected)
throw new IllegalStateException("Already connected");
return null;
}
public Map<String,List<String>> getRequestProperties() {
if (connected)
throw new IllegalStateException("Already connected");
return Collections.emptyMap();
}
public String getHeaderField(String name) {
try {
getInputStream();
} catch (Exception e) {
return null;
}
return properties == null ? null : properties.findValue(name);
}
/**
* Return the key for the nth header field. Returns null if
* there are fewer than n fields. This can be used to iterate
* through all the headers in the message.
*/
public String getHeaderFieldKey(int n) {
try {
getInputStream();
} catch (Exception e) {
return null;
}
MessageHeader props = properties;
return props == null ? null : props.getKey(n);
}
/**
* Return the value for the nth header field. Returns null if
* there are fewer than n fields. This can be used in conjunction
* with getHeaderFieldKey to iterate through all the headers in the message.
*/
public String getHeaderField(int n) {
try {
getInputStream();
} catch (Exception e) {
return null;
}
MessageHeader props = properties;
return props == null ? null : props.getValue(n);
}
/** Call this routine to get the content-type associated with this
* object.
*/
public String getContentType() {
if (contentType == null)
contentType = getHeaderField("content-type");
if (contentType == null) {
String ct = null;
try {
ct = guessContentTypeFromStream(getInputStream());
} catch(java.io.IOException e) {
}
String ce = properties.findValue("content-encoding");
if (ct == null) {
ct = properties.findValue("content-type");
if (ct == null)
if (url.getFile().endsWith("/"))
ct = "text/html";
else
ct = guessContentTypeFromName(url.getFile());
}
/*
* If the Mime header had a Content-encoding field and its value
* was not one of the values that essentially indicate no
* encoding, we force the content type to be unknown. This will
* cause a save dialog to be presented to the user. It is not
* ideal but is better than what we were previously doing, namely
* bringing up an image tool for compressed tar files.
*/
if (ct == null || ce != null &&
!(ce.equalsIgnoreCase("7bit")
|| ce.equalsIgnoreCase("8bit")
|| ce.equalsIgnoreCase("binary")))
ct = "content/unknown";
setContentType(ct);
}
return contentType;
}
/**
* Set the content type of this URL to a specific value.
* @param type The content type to use. One of the
* content_* static variables in this
* class should be used.
* eg. setType(URL.content_html);
*/
public void setContentType(String type) {
contentType = type;
properties.set("content-type", type);
}
/** Call this routine to get the content-length associated with this
* object.
*/
public int getContentLength() {
try {
getInputStream();
} catch (Exception e) {
return -1;
}
int l = contentLength;
if (l < 0) {
try {
l = Integer.parseInt(properties.findValue("content-length"));
setContentLength(l);
} catch(Exception e) {
}
}
return l;
}
/** Call this routine to set the content-length associated with this
* object.
*/
protected void setContentLength(int length) {
contentLength = length;
properties.set("content-length", String.valueOf(length));
}
/**
* Returns true if the data associated with this URL can be cached.
*/
public boolean canCache() {
return url.getFile().indexOf('?') < 0 /* && url.postData == null
REMIND */ ;
}
/**
* Call this to close the connection and flush any remaining data.
* Overriders must remember to call super.close()
*/
public void close() {
url = null;
}
private static HashMap<String,Void> proxiedHosts = new HashMap<>();
public synchronized static void setProxiedHost(String host) {
proxiedHosts.put(host.toLowerCase(), null);
}
public synchronized static boolean isProxiedHost(String host) {
return proxiedHosts.containsKey(host.toLowerCase());
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Basic .aiff audio handler.
* @author Jeff Nisewanger
*/
package sun.net.www.content.audio;
import java.net.*;
import java.io.IOException;
import sun.applet.AppletAudioClip;
/**
* Returns an AppletAudioClip object.
*/
public class aiff extends ContentHandler {
public Object getContent(URLConnection uc) throws IOException {
return new AppletAudioClip(uc);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Basic .au and .snd audio handler.
* @author Jeff Nisewanger
*/
package sun.net.www.content.audio;
import java.net.*;
import java.io.IOException;
import sun.applet.AppletAudioClip;
/**
* Returns an AppletAudioClip object.
* This provides backwards compatibility with the behavior
* of ClassLoader.getResource().getContent() on JDK1.1.
*/
public class basic extends ContentHandler {
public Object getContent(URLConnection uc) throws IOException {
return new AppletAudioClip(uc);
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Basic .wav audio handler.
* @author Jeff Nisewanger
*/
package sun.net.www.content.audio;
import java.net.*;
import java.io.IOException;
import sun.applet.AppletAudioClip;
/**
* Returns an AppletAudioClip object.
*/
public class wav extends ContentHandler {
public Object getContent(URLConnection uc) throws IOException {
return new AppletAudioClip(uc);
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Basic .aiff audio handler.
* @author Jeff Nisewanger
*/
package sun.net.www.content.audio;
import java.net.*;
import java.io.IOException;
import sun.applet.AppletAudioClip;
/**
* Returns an AppletAudioClip object.
*/
public class x_aiff extends ContentHandler {
public Object getContent(URLConnection uc) throws IOException {
return new AppletAudioClip(uc);
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Basic .wav audio handler.
* @author Jeff Nisewanger
*/
package sun.net.www.content.audio;
import java.net.*;
import java.io.IOException;
import sun.applet.AppletAudioClip;
/**
* Returns an AppletAudioClip object.
*/
public class x_wav extends ContentHandler {
public Object getContent(URLConnection uc) throws IOException {
return new AppletAudioClip(uc);
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www.content.image;
import java.net.*;
import sun.awt.image.*;
import java.io.IOException;
import java.awt.Image;
import java.awt.Toolkit;
public class gif extends ContentHandler {
public Object getContent(URLConnection urlc) throws java.io.IOException {
return new URLImageSource(urlc);
}
@SuppressWarnings("rawtypes")
public Object getContent(URLConnection urlc, Class[] classes) throws IOException {
Class<?>[] cls = classes;
for (int i = 0; i < cls.length; i++) {
if (cls[i].isAssignableFrom(URLImageSource.class)) {
return new URLImageSource(urlc);
}
if (cls[i].isAssignableFrom(Image.class)) {
Toolkit tk = Toolkit.getDefaultToolkit();
return tk.createImage(new URLImageSource(urlc));
}
}
return null;
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www.content.image;
import java.net.*;
import sun.awt.image.*;
import java.io.IOException;
import java.awt.Image;
import java.awt.Toolkit;
public class jpeg extends ContentHandler {
public Object getContent(URLConnection urlc) throws java.io.IOException {
return new URLImageSource(urlc);
}
@SuppressWarnings("rawtypes")
public Object getContent(URLConnection urlc, Class[] classes) throws IOException {
Class<?>[] cls = classes;
for (int i = 0; i < cls.length; i++) {
if (cls[i].isAssignableFrom(URLImageSource.class)) {
return new URLImageSource(urlc);
}
if (cls[i].isAssignableFrom(Image.class)) {
Toolkit tk = Toolkit.getDefaultToolkit();
return tk.createImage(new URLImageSource(urlc));
}
}
return null;
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www.content.image;
import java.net.*;
import java.io.IOException;
import sun.awt.image.*;
import java.awt.Image;
import java.awt.Toolkit;
public class png extends ContentHandler {
public Object getContent(URLConnection urlc) throws java.io.IOException {
return new URLImageSource(urlc);
}
@SuppressWarnings("rawtypes")
public Object getContent(URLConnection urlc, Class[] classes) throws IOException {
Class<?>[] cls = classes;
for (int i = 0; i < cls.length; i++) {
if (cls[i].isAssignableFrom(URLImageSource.class)) {
return new URLImageSource(urlc);
}
if (cls[i].isAssignableFrom(Image.class)) {
Toolkit tk = Toolkit.getDefaultToolkit();
return tk.createImage(new URLImageSource(urlc));
}
}
return null;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www.content.image;
import java.net.*;
import sun.awt.image.*;
import java.awt.Image;
import java.awt.Toolkit;
public class x_xbitmap extends ContentHandler {
public Object getContent(URLConnection urlc) throws java.io.IOException {
return new URLImageSource(urlc);
}
@SuppressWarnings("rawtypes")
public Object getContent(URLConnection urlc, Class[] classes) throws java.io.IOException {
Class<?>[] cls = classes;
for (int i = 0; i < cls.length; i++) {
if (cls[i].isAssignableFrom(URLImageSource.class)) {
return new URLImageSource(urlc);
}
if (cls[i].isAssignableFrom(Image.class)) {
Toolkit tk = Toolkit.getDefaultToolkit();
return tk.createImage(new URLImageSource(urlc));
}
}
return null;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www.content.image;
import java.net.*;
import sun.awt.image.*;
import java.awt.Image;
import java.awt.Toolkit;
public class x_xpixmap extends ContentHandler {
public Object getContent(URLConnection urlc) throws java.io.IOException {
return new URLImageSource(urlc);
}
@SuppressWarnings("rawtypes")
public Object getContent(URLConnection urlc, Class[] classes) throws java.io.IOException {
Class<?>[] cls = classes;
for (int i = 0; i < cls.length; i++) {
if (cls[i].isAssignableFrom(URLImageSource.class)) {
return new URLImageSource(urlc);
}
if (cls[i].isAssignableFrom(Image.class)) {
Toolkit tk = Toolkit.getDefaultToolkit();
return tk.createImage(new URLImageSource(urlc));
}
}
return null;
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 1994, 1995, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* Generic text file handler
*/
package sun.net.www.content.text;
public class Generic extends plain {
/* nothing to do since Generic is identical to plain! */
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www.content.text;
import java.io.InputStream;
import java.io.FilterInputStream;
/**
* PlainTextInputStream class extends the FilterInputStream class.
* Currently all calls to the PlainTextInputStream object will call
* the corresponding methods in the FilterInputStream class. Hence
* for now its use is more semantic.
*
* @author Sunita Mani
*/
public class PlainTextInputStream extends FilterInputStream {
/**
* Calls FilterInputStream's constructor.
* @param an InputStream
*/
PlainTextInputStream(InputStream is) {
super(is);
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 1994, 1996, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Plain text file handler.
* @author Steven B. Byrne
*/
package sun.net.www.content.text;
import java.net.*;
import java.io.InputStream;
import java.io.IOException;
public class plain extends ContentHandler {
/**
* Returns a PlainTextInputStream object from which data
* can be read.
*/
public Object getContent(URLConnection uc) {
try {
InputStream is = uc.getInputStream();
return new PlainTextInputStream(uc.getInputStream());
} catch (IOException e) {
return "Error reading document:\n" + e.toString();
}
}
}

View File

@@ -0,0 +1,780 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www.http;
import java.io.*;
import java.util.*;
import sun.net.*;
import sun.net.www.*;
/**
* A <code>ChunkedInputStream</code> provides a stream for reading a body of
* a http message that can be sent as a series of chunks, each with its own
* size indicator. Optionally the last chunk can be followed by trailers
* containing entity-header fields.
* <p>
* A <code>ChunkedInputStream</code> is also <code>Hurryable</code> so it
* can be hurried to the end of the stream if the bytes are available on
* the underlying stream.
*/
public
class ChunkedInputStream extends InputStream implements Hurryable {
/**
* The underlying stream
*/
private InputStream in;
/**
* The <code>HttpClient</code> that should be notified when the chunked stream has
* completed.
*/
private HttpClient hc;
/**
* The <code>MessageHeader</code> that is populated with any optional trailer
* that appear after the last chunk.
*/
private MessageHeader responses;
/**
* The size, in bytes, of the chunk that is currently being read.
* This size is only valid if the current position in the underlying
* input stream is inside a chunk (ie: state == STATE_READING_CHUNK).
*/
private int chunkSize;
/**
* The number of bytes read from the underlying stream for the current
* chunk. This value is always in the range <code>0</code> through to
* <code>chunkSize</code>
*/
private int chunkRead;
/**
* The internal buffer array where chunk data is available for the
* application to read.
*/
private byte chunkData[] = new byte[4096];
/**
* The current position in the buffer. It contains the index
* of the next byte to read from <code>chunkData</code>
*/
private int chunkPos;
/**
* The index one greater than the index of the last valid byte in the
* buffer. This value is always in the range <code>0</code> through
* <code>chunkData.length</code>.
*/
private int chunkCount;
/**
* The internal buffer where bytes from the underlying stream can be
* read. It may contain bytes representing chunk-size, chunk-data, or
* trailer fields.
*/
private byte rawData[] = new byte[32];
/**
* The current position in the buffer. It contains the index
* of the next byte to read from <code>rawData</code>
*/
private int rawPos;
/**
* The index one greater than the index of the last valid byte in the
* buffer. This value is always in the range <code>0</code> through
* <code>rawData.length</code>.
*/
private int rawCount;
/**
* Indicates if an error was encountered when processing the chunked
* stream.
*/
private boolean error;
/**
* Indicates if the chunked stream has been closed using the
* <code>close</code> method.
*/
private boolean closed;
/*
* Maximum chunk header size of 2KB + 2 bytes for CRLF
*/
private final static int MAX_CHUNK_HEADER_SIZE = 2050;
/**
* State to indicate that next field should be :-
* chunk-size [ chunk-extension ] CRLF
*/
static final int STATE_AWAITING_CHUNK_HEADER = 1;
/**
* State to indicate that we are currently reading the chunk-data.
*/
static final int STATE_READING_CHUNK = 2;
/**
* Indicates that a chunk has been completely read and the next
* fields to be examine should be CRLF
*/
static final int STATE_AWAITING_CHUNK_EOL = 3;
/**
* Indicates that all chunks have been read and the next field
* should be optional trailers or an indication that the chunked
* stream is complete.
*/
static final int STATE_AWAITING_TRAILERS = 4;
/**
* State to indicate that the chunked stream is complete and
* no further bytes should be read from the underlying stream.
*/
static final int STATE_DONE = 5;
/**
* Indicates the current state.
*/
private int state;
/**
* Check to make sure that this stream has not been closed.
*/
private void ensureOpen() throws IOException {
if (closed) {
throw new IOException("stream is closed");
}
}
/**
* Ensures there is <code>size</code> bytes available in
* <code>rawData</code>. This requires that we either
* shift the bytes in use to the begining of the buffer
* or allocate a large buffer with sufficient space available.
*/
private void ensureRawAvailable(int size) {
if (rawCount + size > rawData.length) {
int used = rawCount - rawPos;
if (used + size > rawData.length) {
byte tmp[] = new byte[used + size];
if (used > 0) {
System.arraycopy(rawData, rawPos, tmp, 0, used);
}
rawData = tmp;
} else {
if (used > 0) {
System.arraycopy(rawData, rawPos, rawData, 0, used);
}
}
rawCount = used;
rawPos = 0;
}
}
/**
* Close the underlying input stream by either returning it to the
* keep alive cache or closing the stream.
* <p>
* As a chunked stream is inheritly persistent (see HTTP 1.1 RFC) the
* underlying stream can be returned to the keep alive cache if the
* stream can be completely read without error.
*/
private void closeUnderlying() throws IOException {
if (in == null) {
return;
}
if (!error && state == STATE_DONE) {
hc.finished();
} else {
if (!hurry()) {
hc.closeServer();
}
}
in = null;
}
/**
* Attempt to read the remainder of a chunk directly into the
* caller's buffer.
* <p>
* Return the number of bytes read.
*/
private int fastRead(byte[] b, int off, int len) throws IOException {
// assert state == STATE_READING_CHUNKS;
int remaining = chunkSize - chunkRead;
int cnt = (remaining < len) ? remaining : len;
if (cnt > 0) {
int nread;
try {
nread = in.read(b, off, cnt);
} catch (IOException e) {
error = true;
throw e;
}
if (nread > 0) {
chunkRead += nread;
if (chunkRead >= chunkSize) {
state = STATE_AWAITING_CHUNK_EOL;
}
return nread;
}
error = true;
throw new IOException("Premature EOF");
} else {
return 0;
}
}
/**
* Process any outstanding bytes that have already been read into
* <code>rawData</code>.
* <p>
* The parsing of the chunked stream is performed as a state machine with
* <code>state</code> representing the current state of the processing.
* <p>
* Returns when either all the outstanding bytes in rawData have been
* processed or there is insufficient bytes available to continue
* processing. When the latter occurs <code>rawPos</code> will not have
* been updated and thus the processing can be restarted once further
* bytes have been read into <code>rawData</code>.
*/
private void processRaw() throws IOException {
int pos;
int i;
while (state != STATE_DONE) {
switch (state) {
/**
* We are awaiting a line with a chunk header
*/
case STATE_AWAITING_CHUNK_HEADER:
/*
* Find \n to indicate end of chunk header. If not found when there is
* insufficient bytes in the raw buffer to parse a chunk header.
*/
pos = rawPos;
while (pos < rawCount) {
if (rawData[pos] == '\n') {
break;
}
pos++;
if ((pos - rawPos) >= MAX_CHUNK_HEADER_SIZE) {
error = true;
throw new IOException("Chunk header too long");
}
}
if (pos >= rawCount) {
return;
}
/*
* Extract the chunk size from the header (ignoring extensions).
*/
String header = new String(rawData, rawPos, pos-rawPos+1, "US-ASCII");
for (i=0; i < header.length(); i++) {
if (Character.digit(header.charAt(i), 16) == -1)
break;
}
try {
chunkSize = Integer.parseInt(header.substring(0, i), 16);
} catch (NumberFormatException e) {
error = true;
throw new IOException("Bogus chunk size");
}
/*
* Chunk has been parsed so move rawPos to first byte of chunk
* data.
*/
rawPos = pos + 1;
chunkRead = 0;
/*
* A chunk size of 0 means EOF.
*/
if (chunkSize > 0) {
state = STATE_READING_CHUNK;
} else {
state = STATE_AWAITING_TRAILERS;
}
break;
/**
* We are awaiting raw entity data (some may have already been
* read). chunkSize is the size of the chunk; chunkRead is the
* total read from the underlying stream to date.
*/
case STATE_READING_CHUNK :
/* no data available yet */
if (rawPos >= rawCount) {
return;
}
/*
* Compute the number of bytes of chunk data available in the
* raw buffer.
*/
int copyLen = Math.min( chunkSize-chunkRead, rawCount-rawPos );
/*
* Expand or compact chunkData if needed.
*/
if (chunkData.length < chunkCount + copyLen) {
int cnt = chunkCount - chunkPos;
if (chunkData.length < cnt + copyLen) {
byte tmp[] = new byte[cnt + copyLen];
System.arraycopy(chunkData, chunkPos, tmp, 0, cnt);
chunkData = tmp;
} else {
System.arraycopy(chunkData, chunkPos, chunkData, 0, cnt);
}
chunkPos = 0;
chunkCount = cnt;
}
/*
* Copy the chunk data into chunkData so that it's available
* to the read methods.
*/
System.arraycopy(rawData, rawPos, chunkData, chunkCount, copyLen);
rawPos += copyLen;
chunkCount += copyLen;
chunkRead += copyLen;
/*
* If all the chunk has been copied into chunkData then the next
* token should be CRLF.
*/
if (chunkSize - chunkRead <= 0) {
state = STATE_AWAITING_CHUNK_EOL;
} else {
return;
}
break;
/**
* Awaiting CRLF after the chunk
*/
case STATE_AWAITING_CHUNK_EOL:
/* not available yet */
if (rawPos + 1 >= rawCount) {
return;
}
if (rawData[rawPos] != '\r') {
error = true;
throw new IOException("missing CR");
}
if (rawData[rawPos+1] != '\n') {
error = true;
throw new IOException("missing LF");
}
rawPos += 2;
/*
* Move onto the next chunk
*/
state = STATE_AWAITING_CHUNK_HEADER;
break;
/**
* Last chunk has been read so not we're waiting for optional
* trailers.
*/
case STATE_AWAITING_TRAILERS:
/*
* Do we have an entire line in the raw buffer?
*/
pos = rawPos;
while (pos < rawCount) {
if (rawData[pos] == '\n') {
break;
}
pos++;
}
if (pos >= rawCount) {
return;
}
if (pos == rawPos) {
error = true;
throw new IOException("LF should be proceeded by CR");
}
if (rawData[pos-1] != '\r') {
error = true;
throw new IOException("LF should be proceeded by CR");
}
/*
* Stream done so close underlying stream.
*/
if (pos == (rawPos + 1)) {
state = STATE_DONE;
closeUnderlying();
return;
}
/*
* Extract any tailers and append them to the message
* headers.
*/
String trailer = new String(rawData, rawPos, pos-rawPos, "US-ASCII");
i = trailer.indexOf(':');
if (i == -1) {
throw new IOException("Malformed tailer - format should be key:value");
}
String key = (trailer.substring(0, i)).trim();
String value = (trailer.substring(i+1, trailer.length())).trim();
responses.add(key, value);
/*
* Move onto the next trailer.
*/
rawPos = pos+1;
break;
} /* switch */
}
}
/**
* Reads any available bytes from the underlying stream into
* <code>rawData</code> and returns the number of bytes of
* chunk data available in <code>chunkData</code> that the
* application can read.
*/
private int readAheadNonBlocking() throws IOException {
/*
* If there's anything available on the underlying stream then we read
* it into the raw buffer and process it. Processing ensures that any
* available chunk data is made available in chunkData.
*/
int avail = in.available();
if (avail > 0) {
/* ensure that there is space in rawData to read the available */
ensureRawAvailable(avail);
int nread;
try {
nread = in.read(rawData, rawCount, avail);
} catch (IOException e) {
error = true;
throw e;
}
if (nread < 0) {
error = true; /* premature EOF ? */
return -1;
}
rawCount += nread;
/*
* Process the raw bytes that have been read.
*/
processRaw();
}
/*
* Return the number of chunked bytes available to read
*/
return chunkCount - chunkPos;
}
/**
* Reads from the underlying stream until there is chunk data
* available in <code>chunkData</code> for the application to
* read.
*/
private int readAheadBlocking() throws IOException {
do {
/*
* All of chunked response has been read to return EOF.
*/
if (state == STATE_DONE) {
return -1;
}
/*
* We must read into the raw buffer so make sure there is space
* available. We use a size of 32 to avoid too much chunk data
* being read into the raw buffer.
*/
ensureRawAvailable(32);
int nread;
try {
nread = in.read(rawData, rawCount, rawData.length-rawCount);
} catch (IOException e) {
error = true;
throw e;
}
/**
* If we hit EOF it means there's a problem as we should never
* attempt to read once the last chunk and trailers have been
* received.
*/
if (nread < 0) {
error = true;
throw new IOException("Premature EOF");
}
/**
* Process the bytes from the underlying stream
*/
rawCount += nread;
processRaw();
} while (chunkCount <= 0);
/*
* Return the number of chunked bytes available to read
*/
return chunkCount - chunkPos;
}
/**
* Read ahead in either blocking or non-blocking mode. This method
* is typically used when we run out of available bytes in
* <code>chunkData</code> or we need to determine how many bytes
* are available on the input stream.
*/
private int readAhead(boolean allowBlocking) throws IOException {
/*
* Last chunk already received - return EOF
*/
if (state == STATE_DONE) {
return -1;
}
/*
* Reset position/count if data in chunkData is exhausted.
*/
if (chunkPos >= chunkCount) {
chunkCount = 0;
chunkPos = 0;
}
/*
* Read ahead blocking or non-blocking
*/
if (allowBlocking) {
return readAheadBlocking();
} else {
return readAheadNonBlocking();
}
}
/**
* Creates a <code>ChunkedInputStream</code> and saves its arguments, for
* later use.
*
* @param in the underlying input stream.
* @param hc the HttpClient
* @param responses the MessageHeader that should be populated with optional
* trailers.
*/
public ChunkedInputStream(InputStream in, HttpClient hc, MessageHeader responses) throws IOException {
/* save arguments */
this.in = in;
this.responses = responses;
this.hc = hc;
/*
* Set our initial state to indicate that we are first starting to
* look for a chunk header.
*/
state = STATE_AWAITING_CHUNK_HEADER;
}
/**
* See
* the general contract of the <code>read</code>
* method of <code>InputStream</code>.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterInputStream#in
*/
public synchronized int read() throws IOException {
ensureOpen();
if (chunkPos >= chunkCount) {
if (readAhead(true) <= 0) {
return -1;
}
}
return chunkData[chunkPos++] & 0xff;
}
/**
* Reads bytes from this stream into the specified byte array, starting at
* the given offset.
*
* @param b destination buffer.
* @param off offset at which to start storing bytes.
* @param len maximum number of bytes to read.
* @return the number of bytes read, or <code>-1</code> if the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
*/
public synchronized int read(byte b[], int off, int len)
throws IOException
{
ensureOpen();
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int avail = chunkCount - chunkPos;
if (avail <= 0) {
/*
* Optimization: if we're in the middle of the chunk read
* directly from the underlying stream into the caller's
* buffer
*/
if (state == STATE_READING_CHUNK) {
return fastRead( b, off, len );
}
/*
* We're not in the middle of a chunk so we must read ahead
* until there is some chunk data available.
*/
avail = readAhead(true);
if (avail < 0) {
return -1; /* EOF */
}
}
int cnt = (avail < len) ? avail : len;
System.arraycopy(chunkData, chunkPos, b, off, cnt);
chunkPos += cnt;
return cnt;
}
/**
* Returns the number of bytes that can be read from this input
* stream without blocking.
*
* @return the number of bytes that can be read from this input
* stream without blocking.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterInputStream#in
*/
public synchronized int available() throws IOException {
ensureOpen();
int avail = chunkCount - chunkPos;
if(avail > 0) {
return avail;
}
avail = readAhead(false);
if (avail < 0) {
return 0;
} else {
return avail;
}
}
/**
* Close the stream by either returning the connection to the
* keep alive cache or closing the underlying stream.
* <p>
* If the chunked response hasn't been completely read we
* try to "hurry" to the end of the response. If this is
* possible (without blocking) then the connection can be
* returned to the keep alive cache.
*
* @exception IOException if an I/O error occurs.
*/
public synchronized void close() throws IOException {
if (closed) {
return;
}
closeUnderlying();
closed = true;
}
/**
* Hurry the input stream by reading everything from the underlying
* stream. If the last chunk (and optional trailers) can be read without
* blocking then the stream is considered hurried.
* <p>
* Note that if an error has occurred or we can't get to last chunk
* without blocking then this stream can't be hurried and should be
* closed.
*/
public synchronized boolean hurry() {
if (in == null || error) {
return false;
}
try {
readAhead(false);
} catch (Exception e) {
return false;
}
if (error) {
return false;
}
return (state == STATE_DONE);
}
}

View File

@@ -0,0 +1,300 @@
/*
* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www.http;
import java.io.*;
/**
* OutputStream that sends the output to the underlying stream using chunked
* encoding as specified in RFC 2068.
*/
public class ChunkedOutputStream extends PrintStream {
/* Default chunk size (including chunk header) if not specified */
static final int DEFAULT_CHUNK_SIZE = 4096;
private static final byte[] CRLF = {'\r', '\n'};
private static final int CRLF_SIZE = CRLF.length;
private static final byte[] FOOTER = CRLF;
private static final int FOOTER_SIZE = CRLF_SIZE;
private static final byte[] EMPTY_CHUNK_HEADER = getHeader(0);
private static final int EMPTY_CHUNK_HEADER_SIZE = getHeaderSize(0);
/* internal buffer */
private byte buf[];
/* size of data (excluding footers and headers) already stored in buf */
private int size;
/* current index in buf (i.e. buf[count] */
private int count;
/* number of bytes to be filled up to complete a data chunk
* currently being built */
private int spaceInCurrentChunk;
/* underlying stream */
private PrintStream out;
/* the chunk size we use */
private int preferredChunkDataSize;
private int preferedHeaderSize;
private int preferredChunkGrossSize;
/* header for a complete Chunk */
private byte[] completeHeader;
/* return the size of the header for a particular chunk size */
private static int getHeaderSize(int size) {
return (Integer.toHexString(size)).length() + CRLF_SIZE;
}
/* return a header for a particular chunk size */
private static byte[] getHeader(int size){
try {
String hexStr = Integer.toHexString(size);
byte[] hexBytes = hexStr.getBytes("US-ASCII");
byte[] header = new byte[getHeaderSize(size)];
for (int i=0; i<hexBytes.length; i++)
header[i] = hexBytes[i];
header[hexBytes.length] = CRLF[0];
header[hexBytes.length+1] = CRLF[1];
return header;
} catch (java.io.UnsupportedEncodingException e) {
/* This should never happen */
throw new InternalError(e.getMessage(), e);
}
}
public ChunkedOutputStream(PrintStream o) {
this(o, DEFAULT_CHUNK_SIZE);
}
public ChunkedOutputStream(PrintStream o, int size) {
super(o);
out = o;
if (size <= 0) {
size = DEFAULT_CHUNK_SIZE;
}
/* Adjust the size to cater for the chunk header - eg: if the
* preferred chunk size is 1k this means the chunk size should
* be 1017 bytes (differs by 7 from preferred size because of
* 3 bytes for chunk size in hex and CRLF (header) and CRLF (footer)).
*
* If headerSize(adjusted_size) is shorter then headerSize(size)
* then try to use the extra byte unless headerSize(adjusted_size+1)
* increases back to headerSize(size)
*/
if (size > 0) {
int adjusted_size = size - getHeaderSize(size) - FOOTER_SIZE;
if (getHeaderSize(adjusted_size+1) < getHeaderSize(size)){
adjusted_size++;
}
size = adjusted_size;
}
if (size > 0) {
preferredChunkDataSize = size;
} else {
preferredChunkDataSize = DEFAULT_CHUNK_SIZE -
getHeaderSize(DEFAULT_CHUNK_SIZE) - FOOTER_SIZE;
}
preferedHeaderSize = getHeaderSize(preferredChunkDataSize);
preferredChunkGrossSize = preferedHeaderSize + preferredChunkDataSize
+ FOOTER_SIZE;
completeHeader = getHeader(preferredChunkDataSize);
/* start with an initial buffer */
buf = new byte[preferredChunkGrossSize];
reset();
}
/*
* Flush a buffered, completed chunk to an underlying stream. If the data in
* the buffer is insufficient to build up a chunk of "preferredChunkSize"
* then the data do not get flushed unless flushAll is true. If flushAll is
* true then the remaining data builds up a last chunk which size is smaller
* than preferredChunkSize, and then the last chunk gets flushed to
* underlying stream. If flushAll is true and there is no data in a buffer
* at all then an empty chunk (containing a header only) gets flushed to
* underlying stream.
*/
private void flush(boolean flushAll) {
if (spaceInCurrentChunk == 0) {
/* flush a completed chunk to underlying stream */
out.write(buf, 0, preferredChunkGrossSize);
out.flush();
reset();
} else if (flushAll){
/* complete the last chunk and flush it to underlying stream */
if (size > 0){
/* adjust a header start index in case the header of the last
* chunk is shorter then preferedHeaderSize */
int adjustedHeaderStartIndex = preferedHeaderSize -
getHeaderSize(size);
/* write header */
System.arraycopy(getHeader(size), 0, buf,
adjustedHeaderStartIndex, getHeaderSize(size));
/* write footer */
buf[count++] = FOOTER[0];
buf[count++] = FOOTER[1];
//send the last chunk to underlying stream
out.write(buf, adjustedHeaderStartIndex, count - adjustedHeaderStartIndex);
} else {
//send an empty chunk (containing just a header) to underlying stream
out.write(EMPTY_CHUNK_HEADER, 0, EMPTY_CHUNK_HEADER_SIZE);
}
out.flush();
reset();
}
}
@Override
public boolean checkError() {
return out.checkError();
}
/* Check that the output stream is still open */
private void ensureOpen() {
if (out == null)
setError();
}
/*
* Writes data from b[] to an internal buffer and stores the data as data
* chunks of a following format: {Data length in Hex}{CRLF}{data}{CRLF}
* The size of the data is preferredChunkSize. As soon as a completed chunk
* is read from b[] a process of reading from b[] suspends, the chunk gets
* flushed to the underlying stream and then the reading process from b[]
* continues. When there is no more sufficient data in b[] to build up a
* chunk of preferredChunkSize size the data get stored as an incomplete
* chunk of a following format: {space for data length}{CRLF}{data}
* The size of the data is of course smaller than preferredChunkSize.
*/
@Override
public synchronized void write(byte b[], int off, int len) {
ensureOpen();
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
/* if b[] contains enough data then one loop cycle creates one complete
* data chunk with a header, body and a footer, and then flushes the
* chunk to the underlying stream. Otherwise, the last loop cycle
* creates incomplete data chunk with empty header and with no footer
* and stores this incomplete chunk in an internal buffer buf[]
*/
int bytesToWrite = len;
int inputIndex = off; /* the index of the byte[] currently being written */
do {
/* enough data to complete a chunk */
if (bytesToWrite >= spaceInCurrentChunk) {
/* header */
for (int i=0; i<completeHeader.length; i++)
buf[i] = completeHeader[i];
/* data */
System.arraycopy(b, inputIndex, buf, count, spaceInCurrentChunk);
inputIndex += spaceInCurrentChunk;
bytesToWrite -= spaceInCurrentChunk;
count += spaceInCurrentChunk;
/* footer */
buf[count++] = FOOTER[0];
buf[count++] = FOOTER[1];
spaceInCurrentChunk = 0; //chunk is complete
flush(false);
if (checkError()){
break;
}
}
/* not enough data to build a chunk */
else {
/* header */
/* do not write header if not enough bytes to build a chunk yet */
/* data */
System.arraycopy(b, inputIndex, buf, count, bytesToWrite);
count += bytesToWrite;
size += bytesToWrite;
spaceInCurrentChunk -= bytesToWrite;
bytesToWrite = 0;
/* footer */
/* do not write header if not enough bytes to build a chunk yet */
}
} while (bytesToWrite > 0);
}
@Override
public synchronized void write(int _b) {
byte b[] = {(byte)_b};
write(b, 0, 1);
}
public synchronized void reset() {
count = preferedHeaderSize;
size = 0;
spaceInCurrentChunk = preferredChunkDataSize;
}
public int size() {
return size;
}
@Override
public synchronized void close() {
ensureOpen();
/* if we have buffer a chunked send it */
if (size > 0) {
flush(true);
}
/* send a zero length chunk */
flush(true);
/* don't close the underlying stream */
out = null;
}
@Override
public synchronized void flush() {
ensureOpen();
if (size > 0) {
flush(true);
}
}
}

Some files were not shown because too many files have changed in this diff Show More