8187443: Forest Consolidation: Move files to unified layout

Reviewed-by: darcy, ihse
This commit is contained in:
Erik Joelsson 2017-09-12 19:03:39 +02:00
parent 270fe13182
commit 3789983e89
56923 changed files with 3 additions and 15727 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,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,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 {
private static 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
*/
private static 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, "conf");
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>
*/
public static 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>
*/
public static 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 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>
*/
public static 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,275 @@
/*
* Copyright (c) 1994, 2016, 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<>() {
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<>() {
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(Proxy.NO_PROXY); // direct connection
}
protected InetAddress getLocalAddress() throws IOException {
if (serverSocket == null)
throw new IOException("not connected");
return AccessController.doPrivileged(
new PrivilegedAction<>() {
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;
}
public final 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(null, n, "NetworkServer", 0, false).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. */
public final void startServer(int port) throws IOException {
serverSocket = new ServerSocket(port, 50);
serverInstance = new Thread(null, this, "NetworkServer", 0, false);
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,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<>();
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<>();
// 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<>();
// 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<>();
// 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,82 @@
/*
* 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 = GetPropertyAction
.privilegedGetProperty("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 {@literal <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 {@literal <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 {
StringBuilder replyBuf = new StringBuilder(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, 0, 3, 10);
} catch (NumberFormatException e) {
code = -1;
} catch (IndexOutOfBoundsException 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,129 @@
/*
* 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:
* <pre>{@code
* ftp.mumble.bar/... => ftp://ftp.mumble.bar/...
* gopher.mumble.bar/... => gopher://gopher.mumble.bar/...
* other.name.dom/... => http://other.name.dom/...
* /foo/... => file:/foo/...
* }</pre>
*
* 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 abstract static 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,110 @@
/*
* Copyright (c) 2016, 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.ext;
import java.io.FileDescriptor;
import java.net.SocketException;
import java.net.SocketOption;
import java.util.Collections;
import java.util.Set;
/**
* Defines the infrastructure to support extended socket options, beyond those
* defined in {@link java.net.StandardSocketOptions}.
*
* Extended socket options are accessed through the jdk.net API, which is in
* the jdk.net module.
*/
public abstract class ExtendedSocketOptions {
private final Set<SocketOption<?>> options;
/** Tells whether or not the option is supported. */
public final boolean isOptionSupported(SocketOption<?> option) {
return options().contains(option);
}
/** Return the, possibly empty, set of extended socket options available. */
public final Set<SocketOption<?>> options() { return options; }
/** Sets the value of a socket option, for the given socket. */
public abstract void setOption(FileDescriptor fd, SocketOption<?> option, Object value)
throws SocketException;
/** Returns the value of a socket option, for the given socket. */
public abstract Object getOption(FileDescriptor fd, SocketOption<?> option)
throws SocketException;
protected ExtendedSocketOptions(Set<SocketOption<?>> options) {
this.options = options;
}
private static volatile ExtendedSocketOptions instance;
public static final ExtendedSocketOptions getInstance() { return instance; }
/** Registers support for extended socket options. Invoked by the jdk.net module. */
public static final void register(ExtendedSocketOptions extOptions) {
if (instance != null)
throw new InternalError("Attempting to reregister extended options");
instance = extOptions;
}
static {
try {
// If the class is present, it will be initialized which
// triggers registration of the extended socket options.
Class<?> c = Class.forName("jdk.net.ExtendedSocketOptions");
} catch (ClassNotFoundException e) {
// the jdk.net module is not present => no extended socket options
instance = new NoExtendedSocketOptions();
}
}
static final class NoExtendedSocketOptions extends ExtendedSocketOptions {
NoExtendedSocketOptions() {
super(Collections.<SocketOption<?>>emptySet());
}
@Override
public void setOption(FileDescriptor fd, SocketOption<?> option, Object value)
throws SocketException
{
throw new UnsupportedOperationException(
"no extended options: " + option.name());
}
@Override
public Object getOption(FileDescriptor fd, SocketOption<?> option)
throws SocketException
{
throw new UnsupportedOperationException(
"no extended options: " + option.name());
}
}
}

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 an {@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,158 @@
/*
* 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}{@code ("ftpClientProvider")}
*/
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 {
@SuppressWarnings("deprecation")
Object o = Class.forName(cm, true, null).newInstance();
provider = (FtpClientProvider)o;
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
* {@code java.net.FtpClientProvider} 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
* {@code java.net.FtpClientProvider} in the resource
* directory {@code META-INF/services}, 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,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 IndexOutOfBoundsException();
}
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,486 @@
/*
* 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.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 = UCharacter.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));
}
/*
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,112 @@
/*
* 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
*/
@SuppressWarnings("deprecation")
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;
}
}

Binary file not shown.

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 jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
import sun.security.action.GetPropertyAction;
/**
* 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 = GetPropertyAction.privilegedGetProperty("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,289 @@
/*
* 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.io.*;
import java.net.*;
import sun.net.TransferProtocolClient;
import sun.security.action.GetPropertyAction;
/**
* 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 = GetPropertyAction.privilegedGetProperty("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 = GetPropertyAction.privilegedGetProperty("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,407 @@
/*
* Copyright (c) 2003, 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.spi;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.Collections;
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 java.util.stream.Stream;
import sun.net.NetProperties;
import sun.net.SocksProxy;
import static java.util.regex.Pattern.quote;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;
/**
* 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
*/
static final 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;
private static final List<Proxy> NO_PROXY_LIST = List.of(Proxy.NO_PROXY);
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();
}
}
public static int socksProxyVersion() {
return AccessController.doPrivileged(
new PrivilegedAction<Integer>() {
@Override public Integer run() {
return NetProperties.getInteger(SOCKS_PROXY_VERSION, 5);
}
});
}
/**
* 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 typically
* contain one single proxy, default being NO_PROXY.
* If we can get a system proxy it might contain more entries.
*/
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);
}
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[] proxyArray = 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, MacOsX & Windows) if
* we were instructed to.
*/
if (hasSystemProxies) {
String sproto;
if (proto.equalsIgnoreCase("socket"))
sproto = "socks";
else
sproto = proto;
return getSystemProxies(sproto, urlhost);
}
return null;
}
// 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 null;
}
}
}
// 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)) {
return new Proxy[] {SocksProxy.create(saddr, socksProxyVersion())};
}
return new Proxy[] {new Proxy(Proxy.Type.HTTP, saddr)};
}
}
return null;
}});
if (proxyArray != null) {
// Remove duplicate entries, while preserving order.
return Stream.of(proxyArray).distinct().collect(
collectingAndThen(toList(), Collections::unmodifiableList));
}
// If no specific proxy was found, return a standard list containing
// only one NO_PROXY entry.
return NO_PROXY_LIST;
}
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 static native boolean init();
private synchronized native Proxy[] getSystemProxies(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,290 @@
/*
* Copyright (c) 2004, 2015, 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;
public class IPAddressUtil {
private static final int INADDR4SZ = 4;
private static final int INADDR16SZ = 16;
private static final 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 = Character.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;
}
/*
* 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 = Character.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;
}
}

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,265 @@
/*
* Copyright (c) 1996, 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.util.Iterator;
/* 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();
StringBuilder sb = new StringBuilder();
sb.append("{size=").append(asize).append(" nkeys=").append(nkeys)
.append(' ');
for (int i=0; k.hasNext(); i++) {
String key = k.next();
String val = findValue (i);
if (val != null && "".equals (val)) {
val = null;
}
sb.append(" {").append(key).append(val == null ? "" : "," + val)
.append('}');
if (k.hasNext()) {
sb.append (',');
}
}
sb.append (" }");
return sb.toString();
}
public int findInt(String k, int Default) {
try {
return Integer.parseInt(findValue(k, String.valueOf(Default)));
} catch (Throwable t) {
return Default;
}
}
/*
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,522 @@
/*
* 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.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;
public MessageHeader () {
grow();
}
public MessageHeader (InputStream is) throws java.io.IOException {
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<>();
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<>();
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<>();
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);
}
/** 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. */
public synchronized void print(PrintStream p) {
for (int i = 0; i < nkeys; i++)
if (keys[i] != null) {
p.print(keys[i] +
(values[i] != null ? ": "+values[i]: "") + "\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 {@literal <>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;
}
mergeHeader(is);
}
/** 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;
parseloop:{
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;
}
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);
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,218 @@
/*
* Copyright (c) 1994, 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.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();
}
@SuppressWarnings("deprecation")
protected void finalize() throws Throwable {
try {
close();
if (pi != null)
pi.close();
}
finally {
// Call super class
super.finalize();
}
}
}

View file

@ -0,0 +1,323 @@
/*
* Copyright (c) 1994, 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.www;
import java.net.URL;
import java.io.*;
import java.util.StringJoiner;
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() {
StringJoiner sj = new StringJoiner("; ");
int action = getAction();
if (action != MimeEntry.UNKNOWN) {
sj.add("action=" + actionKeywords[action]);
}
String command = getLaunchString();
if (command != null && command.length() > 0) {
sj.add("application=" + command);
}
String image = getImageFileName();
if (image != null) {
sj.add("icon=" + image);
}
String extensions = getExtensionsAsList();
if (extensions.length() > 0) {
sj.add("file_extensions=" + extensions);
}
String description = getDescription();
if (description != null && !description.equals(getType())) {
sj.add("description=" + description);
}
return sj.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;
import sun.security.action.GetPropertyAction;
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(null, null, threadName, 0, false);
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 = GetPropertyAction.privilegedGetProperty("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,436 @@
/*
* 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;
InputStream in;
// 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)).exists()) {
try {
in = new FileInputStream(file);
} catch (FileNotFoundException e) {
System.err.println("Warning: " + file.getPath()
+ " mime table not found.");
return;
}
} else {
in = MimeTable.class.getResourceAsStream("content-types.properties");
if (in == null)
throw new InternalError("default mime table not found");
}
try (BufferedInputStream bin = new BufferedInputStream(in)) {
entries.load(bin);
} catch (IOException e) {
System.err.println("Warning: " + e.getMessage());
}
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 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,696 @@
/*
* 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.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 {
/**
* 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) {
if (flag && File.separatorChar != '/') {
return encodePath(path, 0, File.separatorChar);
} else {
int index = firstEncodeIndex(path);
if (index > -1) {
return encodePath(path, index, '/');
} else {
return path;
}
}
}
private static int firstEncodeIndex(String path) {
int len = path.length();
for (int i = 0; i < len; i++) {
char c = path.charAt(i);
if (c == '/' || c == '.' ||
c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9') {
continue;
} else if (c > 0x007F || match(c, L_ENCODED, H_ENCODED)) {
return i;
}
}
return -1;
}
private static String encodePath(String path, int index, char sep) {
char[] pathCC = path.toCharArray();
char[] retCC = new char[pathCC.length * 2 + 16 - index];
if (index > 0) {
System.arraycopy(pathCC, 0, retCC, 0, index);
}
int retLen = index;
for (int i = index; i < pathCC.length; i++) {
char c = pathCC[i];
if (c == sep)
retCC[retLen++] = '/';
else {
if (c <= 0x007F) {
if (c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9') {
retCC[retLen++] = c;
} else if (match(c, L_ENCODED, H_ENCODED)) {
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, 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, 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, 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 static final 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 --
// To save startup time, we manually calculate the low-/highMask constants.
// For reference, the following methods were used to calculate the values:
// 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 = 0x3FF000000000000L; // 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 = 0x7E0000007EL; // 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 = 0x7FFFFFEL; // 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 = 0x7FFFFFE00000000L; // 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 = 0x678200000000L; // lowMask("-_.!~*'()");
private static final long H_MARK = 0x4000000080000000L; // 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 = 0xAC00985000000000L; // lowMask(";/?:@&=+$,[]");
private static final long H_RESERVED = 0x28000001L; // 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;
// 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 | 0x2400185000000000L; // lowMask(":@&=+$,");
private static final long H_PCHAR
= H_UNRESERVED | H_ESCAPED | 0x1L; // highMask(":@&=+$,");
// All valid path characters
private static final long L_PATH = L_PCHAR | 0x800800000000000L; // lowMask(";/");
private static final long H_PATH = H_PCHAR; // highMask(";/") == 0x0L;
// Dash, for use in domainlabel and toplabel
private static final long L_DASH = 0x200000000000L; // lowMask("-");
private static final long H_DASH = 0x0L; // highMask("-");
// userinfo = *( unreserved | escaped |
// ";" | ":" | "&" | "=" | "+" | "$" | "," )
private static final long L_USERINFO
= L_UNRESERVED | L_ESCAPED | 0x2C00185000000000L; // lowMask(";:&=+$,");
private static final long H_USERINFO
= H_UNRESERVED | H_ESCAPED; // | highMask(";:&=+$,") == 0L;
// reg_name = 1*( unreserved | escaped | "$" | "," |
// ";" | ":" | "@" | "&" | "=" | "+" )
private static final long L_REG_NAME
= L_UNRESERVED | L_ESCAPED | 0x2C00185000000000L; // lowMask("$,;:@&=+");
private static final long H_REG_NAME
= H_UNRESERVED | H_ESCAPED | 0x1L; // highMask("$,;:@&=+");
// All valid characters for server-based authorities
private static final long L_SERVER
= L_USERINFO | L_ALPHANUM | L_DASH | 0x400400000000000L; // lowMask(".:@[]");
private static final long H_SERVER
= H_USERINFO | H_ALPHANUM | H_DASH | 0x28000001L; // highMask(".:@[]");
// 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:
// "=" | ";" | "?" | "/"
//
// 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:
// "#" | " " | "<" | ">" | "%" | "\"" | "{" | "}" | "|" | "\\" | "^" |
// "[" | "]" | "`"
//
// Also US ASCII control characters 00-1F and 7F.
// lowMask((char)0, (char)31) | lowMask("=;?/# <>%\"{}|\\^[]`");
private static final long L_ENCODED = 0xF800802DFFFFFFFFL;
// highMask((char)0x7F, (char)0x7F) | highMask("=;?/# <>%\"{}|\\^[]`");
private static final long H_ENCODED = 0xB800000178000000L;
}

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
*/
public abstract 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 static synchronized void setProxiedHost(String host) {
proxiedHosts.put(host.toLowerCase(), null);
}
public static synchronized boolean isProxiedHost(String host) {
return proxiedHosts.containsKey(host.toLowerCase());
}
}

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 static final 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, 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);
}
}
}

View file

@ -0,0 +1,171 @@
/*
* 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.www.http;
import java.io.*;
import java.util.ArrayList;
import java.util.regex.*;
import sun.net.NetProperties;
import sun.util.logging.PlatformLogger;
/**
* Main class of the HTTP traffic capture tool.
* Captures are triggered by the sun.net.http.captureRules system property.
* If set, it should point to a file containing the capture rules.
* Format for the file is simple:
* - 1 rule per line
* - Lines starting with a # are considered comments and ignored
* - a rule is a pair of a regular expression and file pattern, separated by a comma
* - The regular expression is applied to URLs, if it matches, the traffic for
* that URL will be captured in the associated file.
* - if the file name contains a '%d', then that sequence will be replaced by a
* unique random number for each URL. This allow for multi-threaded captures
* of URLs matching the same pattern.
* - Rules are checked in sequence, in the same order as in the file, until a
* match is found or the end of the list is reached.
*
* Examples of rules:
* www\.sun\.com , sun%d.log
* yahoo\.com\/.*asf , yahoo.log
*
* @author jccollet
*/
public class HttpCapture {
private File file;
private boolean incoming = true;
private BufferedWriter out;
private static boolean initialized;
private static volatile ArrayList<Pattern> patterns;
private static volatile ArrayList<String> capFiles;
private static synchronized void init() {
initialized = true;
String rulesFile = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<>() {
public String run() {
return NetProperties.get("sun.net.http.captureRules");
}
});
if (rulesFile != null && !rulesFile.isEmpty()) {
BufferedReader in;
try {
in = new BufferedReader(new FileReader(rulesFile));
} catch (FileNotFoundException ex) {
return;
}
try {
String line = in.readLine();
while (line != null) {
line = line.trim();
if (!line.startsWith("#")) {
// skip line if it's a comment
String[] s = line.split(",");
if (s.length == 2) {
if (patterns == null) {
patterns = new ArrayList<>();
capFiles = new ArrayList<>();
}
patterns.add(Pattern.compile(s[0].trim()));
capFiles.add(s[1].trim());
}
}
line = in.readLine();
}
} catch (IOException ioe) {
} finally {
try {
in.close();
} catch (IOException ex) {
}
}
}
}
private static synchronized boolean isInitialized() {
return initialized;
}
private HttpCapture(File f, java.net.URL url) {
file = f;
try {
out = new BufferedWriter(new FileWriter(file, true));
out.write("URL: " + url + "\n");
} catch (IOException ex) {
PlatformLogger.getLogger(HttpCapture.class.getName()).severe(null, ex);
}
}
public synchronized void sent(int c) throws IOException {
if (incoming) {
out.write("\n------>\n");
incoming = false;
out.flush();
}
out.write(c);
}
public synchronized void received(int c) throws IOException {
if (!incoming) {
out.write("\n<------\n");
incoming = true;
out.flush();
}
out.write(c);
}
public synchronized void flush() throws IOException {
out.flush();
}
public static HttpCapture getCapture(java.net.URL url) {
if (!isInitialized()) {
init();
}
if (patterns == null || patterns.isEmpty()) {
return null;
}
String s = url.toString();
for (int i = 0; i < patterns.size(); i++) {
Pattern p = patterns.get(i);
if (p.matcher(s).find()) {
String f = capFiles.get(i);
File fi;
if (f.indexOf("%d") >= 0) {
java.util.Random rand = new java.util.Random();
do {
String f2 = f.replace("%d", Integer.toString(rand.nextInt()));
fi = new File(f2);
} while (fi.exists());
} else {
fi = new File(f);
}
return new HttpCapture(fi, url);
}
}
return null;
}
}

View file

@ -0,0 +1,76 @@
/*
* 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.www.http;
import java.io.*;
/**
* A Simple FilterInputStream subclass to capture HTTP traffic.
* Every byte read is also passed to the HttpCapture class.
*
* @author jccollet
*/
public class HttpCaptureInputStream extends FilterInputStream {
private HttpCapture capture = null;
public HttpCaptureInputStream(InputStream in, HttpCapture cap) {
super(in);
capture = cap;
}
@Override
public int read() throws IOException {
int i = super.read();
capture.received(i);
return i;
}
@Override
public void close() throws IOException {
try {
capture.flush();
} catch (IOException iOException) {
}
super.close();
}
@Override
public int read(byte[] b) throws IOException {
int ret = super.read(b);
for (int i = 0; i < ret; i++) {
capture.received(b[i]);
}
return ret;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int ret = super.read(b, off, len);
for (int i = 0; i < ret; i++) {
capture.received(b[off+i]);
}
return ret;
}
}

View file

@ -0,0 +1,73 @@
/*
* 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.www.http;
import java.io.*;
/**
* A Simple FilterOutputStream subclass to capture HTTP traffic.
* Every byte written is also passed to the HttpCapture class.
*
* @author jccollet
*/
public class HttpCaptureOutputStream extends FilterOutputStream {
private HttpCapture capture = null;
public HttpCaptureOutputStream(OutputStream out, HttpCapture cap) {
super(out);
capture = cap;
}
@Override
public void write(int b) throws IOException {
capture.sent(b);
out.write(b);
}
@Override
public void write(byte[] ba) throws IOException {
for (byte b : ba) {
capture.sent(b);
}
out.write(ba);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
for (int i = off; i < len; i++) {
capture.sent(b[i]);
}
out.write(b, off, len);
}
@Override
public void flush() throws IOException {
try {
capture.flush();
} catch (IOException iOException) {
}
super.flush();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2001, 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;
/**
* A <code>Hurryable</code> is a class that has been instructed to complete
* its input processing so as to make resource associated with that input
* available to others.
*/
public interface Hurryable {
/**
* @return a <code>boolean</code> indicating if the stream has been
* hurried or not.
*/
boolean hurry();
}

View file

@ -0,0 +1,337 @@
/*
* Copyright (c) 1996, 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.http;
import java.io.IOException;
import java.io.NotSerializableException;
import java.util.ArrayList;
import java.util.HashMap;
import java.net.URL;
import jdk.internal.misc.InnocuousThread;
/**
* A class that implements a cache of idle Http connections for keep-alive
*
* @author Stephen R. Pietrowicz (NCSA)
* @author Dave Brown
*/
public class KeepAliveCache
extends HashMap<KeepAliveKey, ClientVector>
implements Runnable {
private static final long serialVersionUID = -2937172892064557949L;
/* maximum # keep-alive connections to maintain at once
* This should be 2 by the HTTP spec, but because we don't support pipe-lining
* a larger value is more appropriate. So we now set a default of 5, and the value
* refers to the number of idle connections per destination (in the cache) only.
* It can be reset by setting system property "http.maxConnections".
*/
static final int MAX_CONNECTIONS = 5;
static int result = -1;
static int getMaxConnections() {
if (result == -1) {
result = java.security.AccessController.doPrivileged(
new sun.security.action.GetIntegerAction("http.maxConnections",
MAX_CONNECTIONS))
.intValue();
if (result <= 0)
result = MAX_CONNECTIONS;
}
return result;
}
static final int LIFETIME = 5000;
private Thread keepAliveTimer = null;
/**
* Constructor
*/
public KeepAliveCache() {}
/**
* Register this URL and HttpClient (that supports keep-alive) with the cache
* @param url The URL contains info about the host and port
* @param http The HttpClient to be cached
*/
public synchronized void put(final URL url, Object obj, HttpClient http) {
boolean startThread = (keepAliveTimer == null);
if (!startThread) {
if (!keepAliveTimer.isAlive()) {
startThread = true;
}
}
if (startThread) {
clear();
/* Unfortunately, we can't always believe the keep-alive timeout we got
* back from the server. If I'm connected through a Netscape proxy
* to a server that sent me a keep-alive
* time of 15 sec, the proxy unilaterally terminates my connection
* The robustness to get around this is in HttpClient.parseHTTP()
*/
final KeepAliveCache cache = this;
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<>() {
public Void run() {
keepAliveTimer = InnocuousThread.newSystemThread("Keep-Alive-Timer", cache);
keepAliveTimer.setDaemon(true);
keepAliveTimer.setPriority(Thread.MAX_PRIORITY - 2);
keepAliveTimer.start();
return null;
}
});
}
KeepAliveKey key = new KeepAliveKey(url, obj);
ClientVector v = super.get(key);
if (v == null) {
int keepAliveTimeout = http.getKeepAliveTimeout();
v = new ClientVector(keepAliveTimeout > 0?
keepAliveTimeout*1000 : LIFETIME);
v.put(http);
super.put(key, v);
} else {
v.put(http);
}
}
/* remove an obsolete HttpClient from its VectorCache */
public synchronized void remove (HttpClient h, Object obj) {
KeepAliveKey key = new KeepAliveKey(h.url, obj);
ClientVector v = super.get(key);
if (v != null) {
v.remove(h);
if (v.empty()) {
removeVector(key);
}
}
}
/* called by a clientVector thread when all its connections have timed out
* and that vector of connections should be removed.
*/
synchronized void removeVector(KeepAliveKey k) {
super.remove(k);
}
/**
* Check to see if this URL has a cached HttpClient
*/
public synchronized HttpClient get(URL url, Object obj) {
KeepAliveKey key = new KeepAliveKey(url, obj);
ClientVector v = super.get(key);
if (v == null) { // nothing in cache yet
return null;
}
return v.get();
}
/* Sleeps for an alloted timeout, then checks for timed out connections.
* Errs on the side of caution (leave connections idle for a relatively
* short time).
*/
@Override
public void run() {
do {
try {
Thread.sleep(LIFETIME);
} catch (InterruptedException e) {}
synchronized (this) {
/* Remove all unused HttpClients. Starting from the
* bottom of the stack (the least-recently used first).
* REMIND: It'd be nice to not remove *all* connections
* that aren't presently in use. One could have been added
* a second ago that's still perfectly valid, and we're
* needlessly axing it. But it's not clear how to do this
* cleanly, and doing it right may be more trouble than it's
* worth.
*/
long currentTime = System.currentTimeMillis();
ArrayList<KeepAliveKey> keysToRemove
= new ArrayList<>();
for (KeepAliveKey key : keySet()) {
ClientVector v = get(key);
synchronized (v) {
int i;
for (i = 0; i < v.size(); i++) {
KeepAliveEntry e = v.elementAt(i);
if ((currentTime - e.idleStartTime) > v.nap) {
HttpClient h = e.hc;
h.closeServer();
} else {
break;
}
}
v.subList(0, i).clear();
if (v.size() == 0) {
keysToRemove.add(key);
}
}
}
for (KeepAliveKey key : keysToRemove) {
removeVector(key);
}
}
} while (size() > 0);
return;
}
/*
* Do not serialize this class!
*/
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException {
throw new NotSerializableException();
}
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException {
throw new NotSerializableException();
}
}
/* FILO order for recycling HttpClients, should run in a thread
* to time them out. If > maxConns are in use, block.
*/
class ClientVector extends java.util.Stack<KeepAliveEntry> {
private static final long serialVersionUID = -8680532108106489459L;
// sleep time in milliseconds, before cache clear
int nap;
ClientVector (int nap) {
this.nap = nap;
}
synchronized HttpClient get() {
if (empty()) {
return null;
} else {
// Loop until we find a connection that has not timed out
HttpClient hc = null;
long currentTime = System.currentTimeMillis();
do {
KeepAliveEntry e = pop();
if ((currentTime - e.idleStartTime) > nap) {
e.hc.closeServer();
} else {
hc = e.hc;
}
} while ((hc== null) && (!empty()));
return hc;
}
}
/* return a still valid, unused HttpClient */
synchronized void put(HttpClient h) {
if (size() >= KeepAliveCache.getMaxConnections()) {
h.closeServer(); // otherwise the connection remains in limbo
} else {
push(new KeepAliveEntry(h, System.currentTimeMillis()));
}
}
/*
* Do not serialize this class!
*/
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException {
throw new NotSerializableException();
}
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException {
throw new NotSerializableException();
}
}
class KeepAliveKey {
private String protocol = null;
private String host = null;
private int port = 0;
private Object obj = null; // additional key, such as socketfactory
/**
* Constructor
*
* @param url the URL containing the protocol, host and port information
*/
public KeepAliveKey(URL url, Object obj) {
this.protocol = url.getProtocol();
this.host = url.getHost();
this.port = url.getPort();
this.obj = obj;
}
/**
* Determine whether or not two objects of this type are equal
*/
@Override
public boolean equals(Object obj) {
if ((obj instanceof KeepAliveKey) == false)
return false;
KeepAliveKey kae = (KeepAliveKey)obj;
return host.equals(kae.host)
&& (port == kae.port)
&& protocol.equals(kae.protocol)
&& this.obj == kae.obj;
}
/**
* The hashCode() for this object is the string hashCode() of
* concatenation of the protocol, host name and port.
*/
@Override
public int hashCode() {
String str = protocol+host+port;
return this.obj == null? str.hashCode() :
str.hashCode() + this.obj.hashCode();
}
}
class KeepAliveEntry {
HttpClient hc;
long idleStartTime;
KeepAliveEntry(HttpClient hc, long idleStartTime) {
this.hc = hc;
this.idleStartTime = idleStartTime;
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 1996, 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.www.http;
import java.io.*;
class KeepAliveCleanerEntry
{
KeepAliveStream kas;
HttpClient hc;
public KeepAliveCleanerEntry(KeepAliveStream kas, HttpClient hc) {
this.kas = kas;
this.hc = hc;
}
protected KeepAliveStream getKeepAliveStream() {
return kas;
}
protected HttpClient getHttpClient() {
return hc;
}
protected void setQueuedForCleanup() {
kas.queuedForCleanup = true;
}
protected boolean getQueuedForCleanup() {
return kas.queuedForCleanup;
}
}

View file

@ -0,0 +1,196 @@
/*
* Copyright (c) 1996, 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.www.http;
import java.io.*;
import sun.net.ProgressSource;
import sun.net.www.MeteredStream;
import jdk.internal.misc.InnocuousThread;
/**
* A stream that has the property of being able to be kept alive for
* multiple downloads from the same server.
*
* @author Stephen R. Pietrowicz (NCSA)
* @author Dave Brown
*/
public
class KeepAliveStream extends MeteredStream implements Hurryable {
// instance variables
HttpClient hc;
boolean hurried;
// has this KeepAliveStream been put on the queue for asynchronous cleanup.
protected boolean queuedForCleanup = false;
private static final KeepAliveStreamCleaner queue = new KeepAliveStreamCleaner();
private static Thread cleanerThread; // null
/**
* Constructor
*/
public KeepAliveStream(InputStream is, ProgressSource pi, long expected, HttpClient hc) {
super(is, pi, expected);
this.hc = hc;
}
/**
* Attempt to cache this connection
*/
public void close() throws IOException {
// If the inputstream is closed already, just return.
if (closed) {
return;
}
// If this stream has already been queued for cleanup.
if (queuedForCleanup) {
return;
}
// Skip past the data that's left in the Inputstream because
// some sort of error may have occurred.
// Do this ONLY if the skip won't block. The stream may have
// been closed at the beginning of a big file and we don't want
// to hang around for nothing. So if we can't skip without blocking
// we just close the socket and, therefore, terminate the keepAlive
// NOTE: Don't close super class
try {
if (expected > count) {
long nskip = expected - count;
if (nskip <= available()) {
do {} while ((nskip = (expected - count)) > 0L
&& skip(Math.min(nskip, available())) > 0L);
} else if (expected <= KeepAliveStreamCleaner.MAX_DATA_REMAINING && !hurried) {
//put this KeepAliveStream on the queue so that the data remaining
//on the socket can be cleanup asyncronously.
queueForCleanup(new KeepAliveCleanerEntry(this, hc));
} else {
hc.closeServer();
}
}
if (!closed && !hurried && !queuedForCleanup) {
hc.finished();
}
} finally {
if (pi != null)
pi.finishTracking();
if (!queuedForCleanup) {
// nulling out the underlying inputstream as well as
// httpClient to let gc collect the memories faster
in = null;
hc = null;
closed = true;
}
}
}
/* we explicitly do not support mark/reset */
public boolean markSupported() {
return false;
}
public void mark(int limit) {}
public void reset() throws IOException {
throw new IOException("mark/reset not supported");
}
public synchronized boolean hurry() {
try {
/* CASE 0: we're actually already done */
if (closed || count >= expected) {
return false;
} else if (in.available() < (expected - count)) {
/* CASE I: can't meet the demand */
return false;
} else {
/* CASE II: fill our internal buffer
* Remind: possibly check memory here
*/
int size = (int) (expected - count);
byte[] buf = new byte[size];
DataInputStream dis = new DataInputStream(in);
dis.readFully(buf);
in = new ByteArrayInputStream(buf);
hurried = true;
return true;
}
} catch (IOException e) {
// e.printStackTrace();
return false;
}
}
private static void queueForCleanup(KeepAliveCleanerEntry kace) {
synchronized(queue) {
if(!kace.getQueuedForCleanup()) {
if (!queue.offer(kace)) {
kace.getHttpClient().closeServer();
return;
}
kace.setQueuedForCleanup();
queue.notifyAll();
}
boolean startCleanupThread = (cleanerThread == null);
if (!startCleanupThread) {
if (!cleanerThread.isAlive()) {
startCleanupThread = true;
}
}
if (startCleanupThread) {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
cleanerThread = InnocuousThread.newSystemThread("Keep-Alive-SocketCleaner", queue);
cleanerThread.setDaemon(true);
cleanerThread.setPriority(Thread.MAX_PRIORITY - 2);
cleanerThread.start();
return null;
}
});
}
} // queue
}
protected long remainingToRead() {
return expected - count;
}
protected void setClosed() {
in = null;
hc = null;
closed = true;
}
}

View file

@ -0,0 +1,155 @@
/*
* 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.www.http;
import java.io.IOException;
import java.util.LinkedList;
import sun.net.NetProperties;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* This class is used to cleanup any remaining data that may be on a KeepAliveStream
* so that the connection can be cached in the KeepAliveCache.
* Instances of this class can be used as a FIFO queue for KeepAliveCleanerEntry objects.
* Executing this Runnable removes each KeepAliveCleanerEntry from the Queue, reads
* the reamining bytes on its KeepAliveStream, and if successful puts the connection in
* the KeepAliveCache.
*
* @author Chris Hegarty
*/
@SuppressWarnings("serial") // never serialized
class KeepAliveStreamCleaner
extends LinkedList<KeepAliveCleanerEntry>
implements Runnable
{
// maximum amount of remaining data that we will try to cleanup
protected static int MAX_DATA_REMAINING = 512;
// maximum amount of KeepAliveStreams to be queued
protected static int MAX_CAPACITY = 10;
// timeout for both socket and poll on the queue
protected static final int TIMEOUT = 5000;
// max retries for skipping data
private static final int MAX_RETRIES = 5;
static {
final String maxDataKey = "http.KeepAlive.remainingData";
int maxData = AccessController.doPrivileged(
new PrivilegedAction<Integer>() {
public Integer run() {
return NetProperties.getInteger(maxDataKey, MAX_DATA_REMAINING);
}}).intValue() * 1024;
MAX_DATA_REMAINING = maxData;
final String maxCapacityKey = "http.KeepAlive.queuedConnections";
int maxCapacity = AccessController.doPrivileged(
new PrivilegedAction<Integer>() {
public Integer run() {
return NetProperties.getInteger(maxCapacityKey, MAX_CAPACITY);
}}).intValue();
MAX_CAPACITY = maxCapacity;
}
@Override
public boolean offer(KeepAliveCleanerEntry e) {
if (size() >= MAX_CAPACITY)
return false;
return super.offer(e);
}
@Override
public void run()
{
KeepAliveCleanerEntry kace = null;
do {
try {
synchronized(this) {
long before = System.currentTimeMillis();
long timeout = TIMEOUT;
while ((kace = poll()) == null) {
this.wait(timeout);
long after = System.currentTimeMillis();
long elapsed = after - before;
if (elapsed > timeout) {
/* one last try */
kace = poll();
break;
}
before = after;
timeout -= elapsed;
}
}
if(kace == null)
break;
KeepAliveStream kas = kace.getKeepAliveStream();
if (kas != null) {
synchronized(kas) {
HttpClient hc = kace.getHttpClient();
try {
if (hc != null && !hc.isInKeepAliveCache()) {
int oldTimeout = hc.getReadTimeout();
hc.setReadTimeout(TIMEOUT);
long remainingToRead = kas.remainingToRead();
if (remainingToRead > 0) {
long n = 0;
int retries = 0;
while (n < remainingToRead && retries < MAX_RETRIES) {
remainingToRead = remainingToRead - n;
n = kas.skip(remainingToRead);
if (n == 0)
retries++;
}
remainingToRead = remainingToRead - n;
}
if (remainingToRead == 0) {
hc.setReadTimeout(oldTimeout);
hc.finished();
} else
hc.closeServer();
}
} catch (IOException ioe) {
hc.closeServer();
} finally {
kas.setClosed();
}
}
}
} catch (InterruptedException ie) { }
} while (kace != null);
}
}

View file

@ -0,0 +1,105 @@
/*
* Copyright (c) 2001, 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.net.*;
/**
* Instances of this class are returned to applications for the purpose of
* sending user data for a HTTP request (excluding TRACE). This class is used
* when the content-length will be specified in the header of the request.
* The semantics of ByteArrayOutputStream are extended so that
* when close() is called, it is no longer possible to write
* additional data to the stream. From this point the content length of
* the request is fixed and cannot change.
*
* @author Michael McMahon
*/
public class PosterOutputStream extends ByteArrayOutputStream {
private boolean closed;
/**
* Creates a new output stream for POST user data
*/
public PosterOutputStream () {
super (256);
}
/**
* Writes the specified byte to this output stream.
*
* @param b the byte to be written.
*/
public synchronized void write(int b) {
if (closed) {
return;
}
super.write (b);
}
/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this output stream.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
*/
public synchronized void write(byte b[], int off, int len) {
if (closed) {
return;
}
super.write (b, off, len);
}
/**
* Resets the <code>count</code> field of this output
* stream to zero, so that all currently accumulated output in the
* output stream is discarded. The output stream can be used again,
* reusing the already allocated buffer space. If the output stream
* has been closed, then this method has no effect.
*
* @see java.io.ByteArrayInputStream#count
*/
public synchronized void reset() {
if (closed) {
return;
}
super.reset ();
}
/**
* After close() has been called, it is no longer possible to write
* to this stream. Further calls to write will have no effect.
*/
public synchronized void close() throws IOException {
closed = true;
super.close ();
}
}

View file

@ -0,0 +1,234 @@
/*
* Copyright (c) 1995, 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.
*/
/**
* Open an file input stream given a URL.
* @author James Gosling
* @author Steven B. Byrne
*/
package sun.net.www.protocol.file;
import java.net.URL;
import java.net.FileNameMap;
import java.io.*;
import java.text.Collator;
import java.security.Permission;
import sun.net.*;
import sun.net.www.*;
import java.util.*;
import java.text.SimpleDateFormat;
public class FileURLConnection extends URLConnection {
static String CONTENT_LENGTH = "content-length";
static String CONTENT_TYPE = "content-type";
static String TEXT_PLAIN = "text/plain";
static String LAST_MODIFIED = "last-modified";
String contentType;
InputStream is;
File file;
String filename;
boolean isDirectory = false;
boolean exists = false;
List<String> files;
long length = -1;
long lastModified = 0;
protected FileURLConnection(URL u, File file) {
super(u);
this.file = file;
}
/*
* Note: the semantics of FileURLConnection object is that the
* results of the various URLConnection calls, such as
* getContentType, getInputStream or getContentLength reflect
* whatever was true when connect was called.
*/
public void connect() throws IOException {
if (!connected) {
try {
filename = file.toString();
isDirectory = file.isDirectory();
if (isDirectory) {
String[] fileList = file.list();
if (fileList == null)
throw new FileNotFoundException(filename + " exists, but is not accessible");
files = Arrays.<String>asList(fileList);
} else {
is = new BufferedInputStream(new FileInputStream(filename));
// Check if URL should be metered
boolean meteredInput = ProgressMonitor.getDefault().shouldMeterInput(url, "GET");
if (meteredInput) {
ProgressSource pi = new ProgressSource(url, "GET", file.length());
is = new MeteredStream(is, pi, file.length());
}
}
} catch (IOException e) {
throw e;
}
connected = true;
}
}
private boolean initializedHeaders = false;
private void initializeHeaders() {
try {
connect();
exists = file.exists();
} catch (IOException e) {
}
if (!initializedHeaders || !exists) {
length = file.length();
lastModified = file.lastModified();
if (!isDirectory) {
FileNameMap map = java.net.URLConnection.getFileNameMap();
contentType = map.getContentTypeFor(filename);
if (contentType != null) {
properties.add(CONTENT_TYPE, contentType);
}
properties.add(CONTENT_LENGTH, String.valueOf(length));
/*
* Format the last-modified field into the preferred
* Internet standard - ie: fixed-length subset of that
* defined by RFC 1123
*/
if (lastModified != 0) {
Date date = new Date(lastModified);
SimpleDateFormat fo =
new SimpleDateFormat ("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
fo.setTimeZone(TimeZone.getTimeZone("GMT"));
properties.add(LAST_MODIFIED, fo.format(date));
}
} else {
properties.add(CONTENT_TYPE, TEXT_PLAIN);
}
initializedHeaders = true;
}
}
public String getHeaderField(String name) {
initializeHeaders();
return super.getHeaderField(name);
}
public String getHeaderField(int n) {
initializeHeaders();
return super.getHeaderField(n);
}
public int getContentLength() {
initializeHeaders();
if (length > Integer.MAX_VALUE)
return -1;
return (int) length;
}
public long getContentLengthLong() {
initializeHeaders();
return length;
}
public String getHeaderFieldKey(int n) {
initializeHeaders();
return super.getHeaderFieldKey(n);
}
public MessageHeader getProperties() {
initializeHeaders();
return super.getProperties();
}
public long getLastModified() {
initializeHeaders();
return lastModified;
}
public synchronized InputStream getInputStream()
throws IOException {
int iconHeight;
int iconWidth;
connect();
if (is == null) {
if (isDirectory) {
FileNameMap map = java.net.URLConnection.getFileNameMap();
StringBuilder sb = new StringBuilder();
if (files == null) {
throw new FileNotFoundException(filename);
}
Collections.sort(files, Collator.getInstance());
for (int i = 0 ; i < files.size() ; i++) {
String fileName = files.get(i);
sb.append(fileName);
sb.append("\n");
}
// Put it into a (default) locale-specific byte-stream.
is = new ByteArrayInputStream(sb.toString().getBytes());
} else {
throw new FileNotFoundException(filename);
}
}
return is;
}
Permission permission;
/* since getOutputStream isn't supported, only read permission is
* relevant
*/
public Permission getPermission() throws IOException {
if (permission == null) {
String decodedPath = ParseUtil.decode(url.getPath());
if (File.separatorChar == '/') {
permission = new FilePermission(decodedPath, "read");
} else {
// decode could return /c:/x/y/z.
if (decodedPath.length() > 2 && decodedPath.charAt(0) == '/'
&& decodedPath.charAt(2) == ':') {
decodedPath = decodedPath.substring(1);
}
permission = new FilePermission(
decodedPath.replace('/', File.separatorChar), "read");
}
}
return permission;
}
}

View file

@ -0,0 +1,674 @@
/*
* Copyright (c) 1994, 2016, 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.
*/
/**
* FTP stream opener.
*/
package sun.net.www.protocol.ftp;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.BufferedInputStream;
import java.io.FilterInputStream;
import java.io.FilterOutputStream;
import java.io.FileNotFoundException;
import java.net.URL;
import java.net.SocketPermission;
import java.net.UnknownHostException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.Proxy;
import java.net.ProxySelector;
import java.util.StringTokenizer;
import java.util.Iterator;
import java.security.Permission;
import java.util.Properties;
import sun.net.NetworkClient;
import sun.net.www.MessageHeader;
import sun.net.www.MeteredStream;
import sun.net.www.URLConnection;
import sun.net.www.protocol.http.HttpURLConnection;
import sun.net.ftp.FtpClient;
import sun.net.ftp.FtpProtocolException;
import sun.net.ProgressSource;
import sun.net.ProgressMonitor;
import sun.net.www.ParseUtil;
import sun.security.action.GetPropertyAction;
/**
* This class Opens an FTP input (or output) stream given a URL.
* It works as a one shot FTP transfer :
* <UL>
* <LI>Login</LI>
* <LI>Get (or Put) the file</LI>
* <LI>Disconnect</LI>
* </UL>
* You should not have to use it directly in most cases because all will be handled
* in a abstract layer. Here is an example of how to use the class:
* <pre>{@code
* URL url = new URL("ftp://ftp.sun.com/pub/test.txt");
* UrlConnection con = url.openConnection();
* InputStream is = con.getInputStream();
* ...
* is.close();
* }</pre>
*
* @see sun.net.ftp.FtpClient
*/
public class FtpURLConnection extends URLConnection {
// In case we have to use proxies, we use HttpURLConnection
HttpURLConnection http = null;
private Proxy instProxy;
InputStream is = null;
OutputStream os = null;
FtpClient ftp = null;
Permission permission;
String password;
String user;
String host;
String pathname;
String filename;
String fullpath;
int port;
static final int NONE = 0;
static final int ASCII = 1;
static final int BIN = 2;
static final int DIR = 3;
int type = NONE;
/* Redefine timeouts from java.net.URLConnection as we need -1 to mean
* not set. This is to ensure backward compatibility.
*/
private int connectTimeout = NetworkClient.DEFAULT_CONNECT_TIMEOUT;;
private int readTimeout = NetworkClient.DEFAULT_READ_TIMEOUT;;
/**
* For FTP URLs we need to have a special InputStream because we
* need to close 2 sockets after we're done with it :
* - The Data socket (for the file).
* - The command socket (FtpClient).
* Since that's the only class that needs to see that, it is an inner class.
*/
protected class FtpInputStream extends FilterInputStream {
FtpClient ftp;
FtpInputStream(FtpClient cl, InputStream fd) {
super(new BufferedInputStream(fd));
ftp = cl;
}
@Override
public void close() throws IOException {
super.close();
if (ftp != null) {
ftp.close();
}
}
}
/**
* For FTP URLs we need to have a special OutputStream because we
* need to close 2 sockets after we're done with it :
* - The Data socket (for the file).
* - The command socket (FtpClient).
* Since that's the only class that needs to see that, it is an inner class.
*/
protected class FtpOutputStream extends FilterOutputStream {
FtpClient ftp;
FtpOutputStream(FtpClient cl, OutputStream fd) {
super(fd);
ftp = cl;
}
@Override
public void close() throws IOException {
super.close();
if (ftp != null) {
ftp.close();
}
}
}
/**
* Creates an FtpURLConnection from a URL.
*
* @param url The {@code URL} to retrieve or store.
*/
public FtpURLConnection(URL url) {
this(url, null);
}
/**
* Same as FtpURLconnection(URL) with a per connection proxy specified
*/
FtpURLConnection(URL url, Proxy p) {
super(url);
instProxy = p;
host = url.getHost();
port = url.getPort();
String userInfo = url.getUserInfo();
if (userInfo != null) { // get the user and password
int delimiter = userInfo.indexOf(':');
if (delimiter == -1) {
user = ParseUtil.decode(userInfo);
password = null;
} else {
user = ParseUtil.decode(userInfo.substring(0, delimiter++));
password = ParseUtil.decode(userInfo.substring(delimiter));
}
}
}
private void setTimeouts() {
if (ftp != null) {
if (connectTimeout >= 0) {
ftp.setConnectTimeout(connectTimeout);
}
if (readTimeout >= 0) {
ftp.setReadTimeout(readTimeout);
}
}
}
/**
* Connects to the FTP server and logs in.
*
* @throws FtpLoginException if the login is unsuccessful
* @throws FtpProtocolException if an error occurs
* @throws UnknownHostException if trying to connect to an unknown host
*/
public synchronized void connect() throws IOException {
if (connected) {
return;
}
Proxy p = null;
if (instProxy == null) { // no per connection proxy specified
/**
* Do we have to use a proxy?
*/
ProxySelector sel = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<ProxySelector>() {
public ProxySelector run() {
return ProxySelector.getDefault();
}
});
if (sel != null) {
URI uri = sun.net.www.ParseUtil.toURI(url);
Iterator<Proxy> it = sel.select(uri).iterator();
while (it.hasNext()) {
p = it.next();
if (p == null || p == Proxy.NO_PROXY ||
p.type() == Proxy.Type.SOCKS) {
break;
}
if (p.type() != Proxy.Type.HTTP ||
!(p.address() instanceof InetSocketAddress)) {
sel.connectFailed(uri, p.address(), new IOException("Wrong proxy type"));
continue;
}
// OK, we have an http proxy
InetSocketAddress paddr = (InetSocketAddress) p.address();
try {
http = new HttpURLConnection(url, p);
http.setDoInput(getDoInput());
http.setDoOutput(getDoOutput());
if (connectTimeout >= 0) {
http.setConnectTimeout(connectTimeout);
}
if (readTimeout >= 0) {
http.setReadTimeout(readTimeout);
}
http.connect();
connected = true;
return;
} catch (IOException ioe) {
sel.connectFailed(uri, paddr, ioe);
http = null;
}
}
}
} else { // per connection proxy specified
p = instProxy;
if (p.type() == Proxy.Type.HTTP) {
http = new HttpURLConnection(url, instProxy);
http.setDoInput(getDoInput());
http.setDoOutput(getDoOutput());
if (connectTimeout >= 0) {
http.setConnectTimeout(connectTimeout);
}
if (readTimeout >= 0) {
http.setReadTimeout(readTimeout);
}
http.connect();
connected = true;
return;
}
}
if (user == null) {
user = "anonymous";
Properties props = GetPropertyAction.privilegedGetProperties();
String vers = props.getProperty("java.version");
password = props.getProperty("ftp.protocol.user",
"Java" + vers + "@");
}
try {
ftp = FtpClient.create();
if (p != null) {
ftp.setProxy(p);
}
setTimeouts();
if (port != -1) {
ftp.connect(new InetSocketAddress(host, port));
} else {
ftp.connect(new InetSocketAddress(host, FtpClient.defaultPort()));
}
} catch (UnknownHostException e) {
// Maybe do something smart here, like use a proxy like iftp.
// Just keep throwing for now.
throw e;
} catch (FtpProtocolException fe) {
if (ftp != null) {
try {
ftp.close();
} catch (IOException ioe) {
fe.addSuppressed(ioe);
}
}
throw new IOException(fe);
}
try {
ftp.login(user, password == null ? null : password.toCharArray());
} catch (sun.net.ftp.FtpProtocolException e) {
ftp.close();
// Backward compatibility
throw new sun.net.ftp.FtpLoginException("Invalid username/password");
}
connected = true;
}
/*
* Decodes the path as per the RFC-1738 specifications.
*/
private void decodePath(String path) {
int i = path.indexOf(";type=");
if (i >= 0) {
String s1 = path.substring(i + 6, path.length());
if ("i".equalsIgnoreCase(s1)) {
type = BIN;
}
if ("a".equalsIgnoreCase(s1)) {
type = ASCII;
}
if ("d".equalsIgnoreCase(s1)) {
type = DIR;
}
path = path.substring(0, i);
}
if (path != null && path.length() > 1 &&
path.charAt(0) == '/') {
path = path.substring(1);
}
if (path == null || path.length() == 0) {
path = "./";
}
if (!path.endsWith("/")) {
i = path.lastIndexOf('/');
if (i > 0) {
filename = path.substring(i + 1, path.length());
filename = ParseUtil.decode(filename);
pathname = path.substring(0, i);
} else {
filename = ParseUtil.decode(path);
pathname = null;
}
} else {
pathname = path.substring(0, path.length() - 1);
filename = null;
}
if (pathname != null) {
fullpath = pathname + "/" + (filename != null ? filename : "");
} else {
fullpath = filename;
}
}
/*
* As part of RFC-1738 it is specified that the path should be
* interpreted as a series of FTP CWD commands.
* This is because, '/' is not necessarly the directory delimiter
* on every systems.
*/
private void cd(String path) throws FtpProtocolException, IOException {
if (path == null || path.isEmpty()) {
return;
}
if (path.indexOf('/') == -1) {
ftp.changeDirectory(ParseUtil.decode(path));
return;
}
StringTokenizer token = new StringTokenizer(path, "/");
while (token.hasMoreTokens()) {
ftp.changeDirectory(ParseUtil.decode(token.nextToken()));
}
}
/**
* Get the InputStream to retreive the remote file. It will issue the
* "get" (or "dir") command to the ftp server.
*
* @return the {@code InputStream} to the connection.
*
* @throws IOException if already opened for output
* @throws FtpProtocolException if errors occur during the transfert.
*/
@Override
public InputStream getInputStream() throws IOException {
if (!connected) {
connect();
}
if (http != null) {
return http.getInputStream();
}
if (os != null) {
throw new IOException("Already opened for output");
}
if (is != null) {
return is;
}
MessageHeader msgh = new MessageHeader();
boolean isAdir = false;
try {
decodePath(url.getPath());
if (filename == null || type == DIR) {
ftp.setAsciiType();
cd(pathname);
if (filename == null) {
is = new FtpInputStream(ftp, ftp.list(null));
} else {
is = new FtpInputStream(ftp, ftp.nameList(filename));
}
} else {
if (type == ASCII) {
ftp.setAsciiType();
} else {
ftp.setBinaryType();
}
cd(pathname);
is = new FtpInputStream(ftp, ftp.getFileStream(filename));
}
/* Try to get the size of the file in bytes. If that is
successful, then create a MeteredStream. */
try {
long l = ftp.getLastTransferSize();
msgh.add("content-length", Long.toString(l));
if (l > 0) {
// Wrap input stream with MeteredStream to ensure read() will always return -1
// at expected length.
// Check if URL should be metered
boolean meteredInput = ProgressMonitor.getDefault().shouldMeterInput(url, "GET");
ProgressSource pi = null;
if (meteredInput) {
pi = new ProgressSource(url, "GET", l);
pi.beginTracking();
}
is = new MeteredStream(is, pi, l);
}
} catch (Exception e) {
e.printStackTrace();
/* do nothing, since all we were doing was trying to
get the size in bytes of the file */
}
if (isAdir) {
msgh.add("content-type", "text/plain");
msgh.add("access-type", "directory");
} else {
msgh.add("access-type", "file");
String ftype = guessContentTypeFromName(fullpath);
if (ftype == null && is.markSupported()) {
ftype = guessContentTypeFromStream(is);
}
if (ftype != null) {
msgh.add("content-type", ftype);
}
}
} catch (FileNotFoundException e) {
try {
cd(fullpath);
/* if that worked, then make a directory listing
and build an html stream with all the files in
the directory */
ftp.setAsciiType();
is = new FtpInputStream(ftp, ftp.list(null));
msgh.add("content-type", "text/plain");
msgh.add("access-type", "directory");
} catch (IOException ex) {
FileNotFoundException fnfe = new FileNotFoundException(fullpath);
if (ftp != null) {
try {
ftp.close();
} catch (IOException ioe) {
fnfe.addSuppressed(ioe);
}
}
throw fnfe;
} catch (FtpProtocolException ex2) {
FileNotFoundException fnfe = new FileNotFoundException(fullpath);
if (ftp != null) {
try {
ftp.close();
} catch (IOException ioe) {
fnfe.addSuppressed(ioe);
}
}
throw fnfe;
}
} catch (FtpProtocolException ftpe) {
if (ftp != null) {
try {
ftp.close();
} catch (IOException ioe) {
ftpe.addSuppressed(ioe);
}
}
throw new IOException(ftpe);
}
setProperties(msgh);
return is;
}
/**
* Get the OutputStream to store the remote file. It will issue the
* "put" command to the ftp server.
*
* @return the {@code OutputStream} to the connection.
*
* @throws IOException if already opened for input or the URL
* points to a directory
* @throws FtpProtocolException if errors occur during the transfert.
*/
@Override
public OutputStream getOutputStream() throws IOException {
if (!connected) {
connect();
}
if (http != null) {
OutputStream out = http.getOutputStream();
// getInputStream() is neccessary to force a writeRequests()
// on the http client.
http.getInputStream();
return out;
}
if (is != null) {
throw new IOException("Already opened for input");
}
if (os != null) {
return os;
}
decodePath(url.getPath());
if (filename == null || filename.length() == 0) {
throw new IOException("illegal filename for a PUT");
}
try {
if (pathname != null) {
cd(pathname);
}
if (type == ASCII) {
ftp.setAsciiType();
} else {
ftp.setBinaryType();
}
os = new FtpOutputStream(ftp, ftp.putFileStream(filename, false));
} catch (FtpProtocolException e) {
throw new IOException(e);
}
return os;
}
String guessContentTypeFromFilename(String fname) {
return guessContentTypeFromName(fname);
}
/**
* Gets the {@code Permission} associated with the host and port.
*
* @return The {@code Permission} object.
*/
@Override
public Permission getPermission() {
if (permission == null) {
int urlport = url.getPort();
urlport = urlport < 0 ? FtpClient.defaultPort() : urlport;
String urlhost = this.host + ":" + urlport;
permission = new SocketPermission(urlhost, "connect");
}
return permission;
}
/**
* Sets the general request property. If a property with the key already
* exists, overwrite its value with the new value.
*
* @param key the keyword by which the request is known
* (e.g., "{@code accept}").
* @param value the value associated with it.
* @throws IllegalStateException if already connected
* @see #getRequestProperty(java.lang.String)
*/
@Override
public void setRequestProperty(String key, String value) {
super.setRequestProperty(key, value);
if ("type".equals(key)) {
if ("i".equalsIgnoreCase(value)) {
type = BIN;
} else if ("a".equalsIgnoreCase(value)) {
type = ASCII;
} else if ("d".equalsIgnoreCase(value)) {
type = DIR;
} else {
throw new IllegalArgumentException(
"Value of '" + key +
"' request property was '" + value +
"' when it must be either 'i', 'a' or 'd'");
}
}
}
/**
* Returns the value of the named general request property for this
* connection.
*
* @param key the keyword by which the request is known (e.g., "accept").
* @return the value of the named general request property for this
* connection.
* @throws IllegalStateException if already connected
* @see #setRequestProperty(java.lang.String, java.lang.String)
*/
@Override
public String getRequestProperty(String key) {
String value = super.getRequestProperty(key);
if (value == null) {
if ("type".equals(key)) {
value = (type == ASCII ? "a" : type == DIR ? "d" : "i");
}
}
return value;
}
@Override
public void setConnectTimeout(int timeout) {
if (timeout < 0) {
throw new IllegalArgumentException("timeouts can't be negative");
}
connectTimeout = timeout;
}
@Override
public int getConnectTimeout() {
return (connectTimeout < 0 ? 0 : connectTimeout);
}
@Override
public void setReadTimeout(int timeout) {
if (timeout < 0) {
throw new IllegalArgumentException("timeouts can't be negative");
}
readTimeout = timeout;
}
@Override
public int getReadTimeout() {
return readTimeout < 0 ? 0 : readTimeout;
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 1994, 2003, 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.
*/
/*-
* FTP stream opener
*/
package sun.net.www.protocol.ftp;
import java.io.IOException;
import java.net.URL;
import java.net.Proxy;
import java.util.Map;
import java.util.HashMap;
import sun.net.ftp.FtpClient;
import sun.net.www.protocol.http.HttpURLConnection;
/** open an ftp connection given a URL */
public class Handler extends java.net.URLStreamHandler {
protected int getDefaultPort() {
return 21;
}
protected boolean equals(URL u1, URL u2) {
String userInfo1 = u1.getUserInfo();
String userInfo2 = u2.getUserInfo();
return super.equals(u1, u2) &&
(userInfo1 == null? userInfo2 == null: userInfo1.equals(userInfo2));
}
protected java.net.URLConnection openConnection(URL u)
throws IOException {
return openConnection(u, null);
}
protected java.net.URLConnection openConnection(URL u, Proxy p)
throws IOException {
return new FtpURLConnection(u, p);
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2003, 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.protocol.http;
/**
* @author Michael McMahon
*
* Interface provided by internal http authentication cache.
* NB. This API will be replaced in a future release, and should
* not be made public.
*/
public interface AuthCache {
/**
* Put an entry in the cache. pkey is a string specified as follows:
*
* A:[B:]C:D:E[:F][;key=value] Between 4 and 6 fields separated by ":",
* and an optional semicolon-separated key=value list postfix,
* where the fields have the following meaning:
* A is "s" or "p" for server or proxy authentication respectively
* B is optional and is the {@link AuthScheme}, e.g. BASIC, DIGEST, NTLM, etc
* C is either "http" or "https"
* D is the hostname
* E is the port number
* F is optional and if present is the realm
*
* The semi-colon separated key=value list postfix can be used to
* provide additional contextual information, thus allowing
* to separate AuthCacheValue instances obtained from different
* contexts.
*
* Generally, two entries are created for each AuthCacheValue,
* one including the realm and one without the realm.
* Also, for some schemes (digest) multiple entries may be created
* with the same pkey, but with a different path value in
* the AuthCacheValue.
*/
public void put (String pkey, AuthCacheValue value);
/**
* Get an entry from the cache based on pkey as described above, but also
* using a pathname (skey) and the cache must return an entry
* if skey is a sub-path of the AuthCacheValue.path field.
*/
public AuthCacheValue get (String pkey, String skey);
/**
* remove the entry from the cache whose pkey is specified and
* whose path is equal to entry.path. If entry is null then
* all entries with the same pkey should be removed.
*/
public void remove (String pkey, AuthCacheValue entry);
}

View file

@ -0,0 +1,108 @@
/*
* Copyright (c) 2003, 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.protocol.http;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.HashMap;
/**
* @author Michael McMahon
*/
public class AuthCacheImpl implements AuthCache {
HashMap<String,LinkedList<AuthCacheValue>> hashtable;
public AuthCacheImpl () {
hashtable = new HashMap<String,LinkedList<AuthCacheValue>>();
}
public void setMap (HashMap<String,LinkedList<AuthCacheValue>> map) {
hashtable = map;
}
// put a value in map according to primary key + secondary key which
// is the path field of AuthenticationInfo
public synchronized void put (String pkey, AuthCacheValue value) {
LinkedList<AuthCacheValue> list = hashtable.get (pkey);
String skey = value.getPath();
if (list == null) {
list = new LinkedList<AuthCacheValue>();
hashtable.put(pkey, list);
}
// Check if the path already exists or a super-set of it exists
ListIterator<AuthCacheValue> iter = list.listIterator();
while (iter.hasNext()) {
AuthenticationInfo inf = (AuthenticationInfo)iter.next();
if (inf.path == null || inf.path.startsWith (skey)) {
iter.remove ();
}
}
iter.add(value);
}
// get a value from map checking both primary
// and secondary (urlpath) key
public synchronized AuthCacheValue get (String pkey, String skey) {
AuthenticationInfo result = null;
LinkedList<AuthCacheValue> list = hashtable.get (pkey);
if (list == null || list.size() == 0) {
return null;
}
if (skey == null) {
// list should contain only one element
return (AuthenticationInfo)list.get (0);
}
ListIterator<AuthCacheValue> iter = list.listIterator();
while (iter.hasNext()) {
AuthenticationInfo inf = (AuthenticationInfo)iter.next();
if (skey.startsWith (inf.path)) {
return inf;
}
}
return null;
}
public synchronized void remove (String pkey, AuthCacheValue entry) {
LinkedList<AuthCacheValue> list = hashtable.get (pkey);
if (list == null) {
return;
}
if (entry == null) {
list.clear();
return;
}
ListIterator<AuthCacheValue> iter = list.listIterator ();
while (iter.hasNext()) {
AuthenticationInfo inf = (AuthenticationInfo)iter.next();
if (entry.equals(inf)) {
iter.remove ();
}
}
}
}

View file

@ -0,0 +1,100 @@
/*
* 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.www.protocol.http;
import java.io.Serializable;
import java.net.PasswordAuthentication;
/**
* AuthCacheValue: interface to minimize exposure to authentication cache
* for external users (ie. plugin)
*
* @author Michael McMahon
*/
public abstract class AuthCacheValue implements Serializable {
static final long serialVersionUID = 735249334068211611L;
public enum Type {
Proxy,
Server
};
/**
* Caches authentication info entered by user. See cacheKey()
*/
protected static AuthCache cache = new AuthCacheImpl();
public static void setAuthCache (AuthCache map) {
cache = map;
}
/* Package private ctor to prevent extension outside package */
AuthCacheValue() {}
/**
* Proxy or Server
*/
abstract Type getAuthType ();
/**
* Authentication scheme
*/
abstract AuthScheme getAuthScheme();
/**
* name of server/proxy
*/
abstract String getHost ();
/**
* portnumber of server/proxy
*/
abstract int getPort();
/**
* realm of authentication if known
*/
abstract String getRealm();
/**
* root path of realm or the request path if the root
* is not known yet.
*/
abstract String getPath();
/**
* returns http or https
*/
abstract String getProtocolScheme();
/**
* the credentials associated with this authentication
*/
abstract PasswordAuthentication credentials();
}

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.www.protocol.http;
/* Authentication schemes supported by the http implementation. New schemes, if
* supported, should be defined here.
*/
public enum AuthScheme {
BASIC,
DIGEST,
NTLM,
NEGOTIATE,
KERBEROS,
UNKNOWN;
}

View file

@ -0,0 +1,280 @@
/*
* Copyright (c) 2002, 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.protocol.http;
import java.util.Collections;
import java.util.Iterator;
import java.util.HashMap;
import java.util.Set;
import sun.net.www.*;
import sun.security.action.GetPropertyAction;
/**
* This class is used to parse the information in WWW-Authenticate: and Proxy-Authenticate:
* headers. It searches among multiple header lines and within each header line
* for the best currently supported scheme. It can also return a HeaderParser
* containing the challenge data for that particular scheme.
*
* Some examples:
*
* WWW-Authenticate: Basic realm="foo" Digest realm="bar" NTLM
* Note the realm parameter must be associated with the particular scheme.
*
* or
*
* WWW-Authenticate: Basic realm="foo"
* WWW-Authenticate: Digest realm="foo",qop="auth",nonce="thisisanunlikelynonce"
* WWW-Authenticate: NTLM
*
* or
*
* WWW-Authenticate: Basic realm="foo"
* WWW-Authenticate: NTLM ASKAJK9893289889QWQIOIONMNMN
*
* The last example shows how NTLM breaks the rules of rfc2617 for the structure of
* the authentication header. This is the reason why the raw header field is used for ntlm.
*
* At present, the class chooses schemes in following order :
* 1. Negotiate (if supported)
* 2. Kerberos (if supported)
* 3. Digest
* 4. NTLM (if supported)
* 5. Basic
*
* This choice can be modified by setting a system property:
*
* -Dhttp.auth.preference="scheme"
*
* which in this case, specifies that "scheme" should be used as the auth scheme when offered
* disregarding the default prioritisation. If scheme is not offered, or explicitly
* disabled, by {@code disabledSchemes}, then the default priority is used.
*
* Attention: when http.auth.preference is set as SPNEGO or Kerberos, it's actually "Negotiate
* with SPNEGO" or "Negotiate with Kerberos", which means the user will prefer the Negotiate
* scheme with GSS/SPNEGO or GSS/Kerberos mechanism.
*
* This also means that the real "Kerberos" scheme can never be set as a preference.
*/
public class AuthenticationHeader {
MessageHeader rsp; // the response to be parsed
HeaderParser preferred;
String preferred_r; // raw Strings
private final HttpCallerInfo hci; // un-schemed, need check
// When set true, do not use Negotiate even if the response
// headers suggest so.
boolean dontUseNegotiate = false;
static String authPref=null;
public String toString() {
return "AuthenticationHeader: prefer " + preferred_r;
}
static {
authPref = GetPropertyAction.privilegedGetProperty("http.auth.preference");
// http.auth.preference can be set to SPNEGO or Kerberos.
// In fact they means "Negotiate with SPNEGO" and "Negotiate with
// Kerberos" separately, so here they are all translated into
// Negotiate. Read NegotiateAuthentication.java to see how they
// were used later.
if (authPref != null) {
authPref = authPref.toLowerCase();
if(authPref.equals("spnego") || authPref.equals("kerberos")) {
authPref = "negotiate";
}
}
}
String hdrname; // Name of the header to look for
/**
* Parses a set of authentication headers and chooses the preferred scheme
* that is supported for a given host.
*/
public AuthenticationHeader (String hdrname, MessageHeader response,
HttpCallerInfo hci, boolean dontUseNegotiate) {
this(hdrname, response, hci, dontUseNegotiate, Collections.emptySet());
}
/**
* Parses a set of authentication headers and chooses the preferred scheme
* that is supported for a given host.
*
* <p> The {@code disabledSchemes} parameter is a, possibly empty, set of
* authentication schemes that are disabled.
*/
public AuthenticationHeader(String hdrname,
MessageHeader response,
HttpCallerInfo hci,
boolean dontUseNegotiate,
Set<String> disabledSchemes) {
this.hci = hci;
this.dontUseNegotiate = dontUseNegotiate;
this.rsp = response;
this.hdrname = hdrname;
this.schemes = new HashMap<>();
parse(disabledSchemes);
}
public HttpCallerInfo getHttpCallerInfo() {
return hci;
}
/* we build up a map of scheme names mapped to SchemeMapValue objects */
static class SchemeMapValue {
SchemeMapValue (HeaderParser h, String r) {raw=r; parser=h;}
String raw;
HeaderParser parser;
}
HashMap<String, SchemeMapValue> schemes;
/* Iterate through each header line, and then within each line.
* If multiple entries exist for a particular scheme (unlikely)
* then the last one will be used. The
* preferred scheme that we support will be used.
*/
private void parse(Set<String> disabledSchemes) {
Iterator<String> iter = rsp.multiValueIterator(hdrname);
while (iter.hasNext()) {
String raw = iter.next();
// HeaderParser lower cases everything, so can be used case-insensitively
HeaderParser hp = new HeaderParser(raw);
Iterator<String> keys = hp.keys();
int i, lastSchemeIndex;
for (i=0, lastSchemeIndex = -1; keys.hasNext(); i++) {
keys.next();
if (hp.findValue(i) == null) { /* found a scheme name */
if (lastSchemeIndex != -1) {
HeaderParser hpn = hp.subsequence (lastSchemeIndex, i);
String scheme = hpn.findKey(0);
if (!disabledSchemes.contains(scheme))
schemes.put(scheme, new SchemeMapValue (hpn, raw));
}
lastSchemeIndex = i;
}
}
if (i > lastSchemeIndex) {
HeaderParser hpn = hp.subsequence (lastSchemeIndex, i);
String scheme = hpn.findKey(0);
if (!disabledSchemes.contains(scheme))
schemes.put(scheme, new SchemeMapValue (hpn, raw));
}
}
/* choose the best of them, the order is
* negotiate -> kerberos -> digest -> ntlm -> basic
*/
SchemeMapValue v = null;
if (authPref == null || (v=schemes.get (authPref)) == null) {
if(v == null && !dontUseNegotiate) {
SchemeMapValue tmp = schemes.get("negotiate");
if(tmp != null) {
if(hci == null || !NegotiateAuthentication.isSupported(new HttpCallerInfo(hci, "Negotiate"))) {
tmp = null;
}
v = tmp;
}
}
if(v == null && !dontUseNegotiate) {
SchemeMapValue tmp = schemes.get("kerberos");
if(tmp != null) {
// the Kerberos scheme is only observed in MS ISA Server. In
// fact i think it's a Kerberos-mechnism-only Negotiate.
// Since the Kerberos scheme is always accompanied with the
// Negotiate scheme, so it seems impossible to reach this
// line. Even if the user explicitly set http.auth.preference
// as Kerberos, it means Negotiate with Kerberos, and the code
// will still tried to use Negotiate at first.
//
// The only chance this line get executed is that the server
// only suggest the Kerberos scheme.
if(hci == null || !NegotiateAuthentication.isSupported(new HttpCallerInfo(hci, "Kerberos"))) {
tmp = null;
}
v = tmp;
}
}
if(v == null) {
if ((v=schemes.get ("digest")) == null) {
if (!NTLMAuthenticationProxy.supported
|| ((v=schemes.get("ntlm"))==null)) {
v = schemes.get ("basic");
}
}
}
} else { // authPref != null && it's found in reponses'
if (dontUseNegotiate && authPref.equals("negotiate")) {
v = null;
}
}
if (v != null) {
preferred = v.parser;
preferred_r = v.raw;
}
}
/**
* return a header parser containing the preferred authentication scheme (only).
* The preferred scheme is the strongest of the schemes proposed by the server.
* The returned HeaderParser will contain the relevant parameters for that scheme
*/
public HeaderParser headerParser() {
return preferred;
}
/**
* return the name of the preferred scheme
*/
public String scheme() {
if (preferred != null) {
return preferred.findKey(0);
} else {
return null;
}
}
/* return the raw header field for the preferred/chosen scheme */
public String raw () {
return preferred_r;
}
/**
* returns true is the header exists and contains a recognised scheme
*/
public boolean isPresent () {
return preferred != null;
}
}

View file

@ -0,0 +1,502 @@
/*
* Copyright (c) 1995, 2016, 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.protocol.http;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.util.HashMap;
import java.util.Objects;
import sun.net.www.HeaderParser;
/**
* AuthenticationInfo: Encapsulate the information needed to
* authenticate a user to a server.
*
* @author Jon Payne
* @author Herb Jellinek
* @author Bill Foote
*/
// REMIND: It would be nice if this class understood about partial matching.
// If you're authorized for foo.com, chances are high you're also
// authorized for baz.foo.com.
// NB: When this gets implemented, be careful about the uncaching
// policy in HttpURLConnection. A failure on baz.foo.com shouldn't
// uncache foo.com!
public abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
static final long serialVersionUID = -2588378268010453259L;
// Constants saying what kind of authroization this is. This determines
// the namespace in the hash table lookup.
public static final char SERVER_AUTHENTICATION = 's';
public static final char PROXY_AUTHENTICATION = 'p';
/**
* If true, then simultaneous authentication requests to the same realm/proxy
* are serialized, in order to avoid a user having to type the same username/passwords
* repeatedly, via the Authenticator. Default is false, which means that this
* behavior is switched off.
*/
static final boolean serializeAuth;
static {
serializeAuth = java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction(
"http.auth.serializeRequests")).booleanValue();
}
/* AuthCacheValue: */
protected transient PasswordAuthentication pw;
public PasswordAuthentication credentials() {
return pw;
}
public AuthCacheValue.Type getAuthType() {
return type == SERVER_AUTHENTICATION ?
AuthCacheValue.Type.Server:
AuthCacheValue.Type.Proxy;
}
AuthScheme getAuthScheme() {
return authScheme;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public String getRealm() {
return realm;
}
public String getPath() {
return path;
}
public String getProtocolScheme() {
return protocol;
}
/**
* Whether we should cache this instance in the AuthCache.
* This method returns {@code true} by default.
* Subclasses may override this method to add
* additional restrictions.
* @return {@code true} by default.
*/
protected boolean useAuthCache() {
return true;
}
/**
* requests is used to ensure that interaction with the
* Authenticator for a particular realm is single threaded.
* ie. if multiple threads need to get credentials from the user
* at the same time, then all but the first will block until
* the first completes its authentication.
*/
private static HashMap<String,Thread> requests = new HashMap<>();
/* check if a request for this destination is in progress
* return false immediately if not. Otherwise block until
* request is finished and return true
*/
private static boolean requestIsInProgress (String key) {
if (!serializeAuth) {
/* behavior is disabled. Revert to concurrent requests */
return false;
}
synchronized (requests) {
Thread t, c;
c = Thread.currentThread();
if ((t = requests.get(key)) == null) {
requests.put (key, c);
return false;
}
if (t == c) {
return false;
}
while (requests.containsKey(key)) {
try {
requests.wait ();
} catch (InterruptedException e) {}
}
}
/* entry may be in cache now. */
return true;
}
/* signal completion of an authentication (whether it succeeded or not)
* so that other threads can continue.
*/
private static void requestCompleted (String key) {
synchronized (requests) {
Thread thread = requests.get(key);
if (thread != null && thread == Thread.currentThread()) {
boolean waspresent = requests.remove(key) != null;
assert waspresent;
}
requests.notifyAll();
}
}
//public String toString () {
//return ("{"+type+":"+authScheme+":"+protocol+":"+host+":"+port+":"+realm+":"+path+"}");
//}
// REMIND: This cache just grows forever. We should put in a bounded
// cache, or maybe something using WeakRef's.
/** The type (server/proxy) of authentication this is. Used for key lookup */
char type;
/** The authentication scheme (basic/digest). Also used for key lookup */
AuthScheme authScheme;
/** The protocol/scheme (i.e. http or https ). Need to keep the caches
* logically separate for the two protocols. This field is only used
* when constructed with a URL (the normal case for server authentication)
* For proxy authentication the protocol is not relevant.
*/
String protocol;
/** The host we're authenticating against. */
String host;
/** The port on the host we're authenticating against. */
int port;
/** The realm we're authenticating against. */
String realm;
/** The shortest path from the URL we authenticated against. */
String path;
/**
* A key identifying the authenticator from which the credentials
* were obtained.
* {@link AuthenticatorKeys#DEFAULT} identifies the {@linkplain
* java.net.Authenticator#setDefault(java.net.Authenticator) default}
* authenticator.
*/
String authenticatorKey;
/** Use this constructor only for proxy entries */
public AuthenticationInfo(char type, AuthScheme authScheme, String host,
int port, String realm, String authenticatorKey) {
this.type = type;
this.authScheme = authScheme;
this.protocol = "";
this.host = host.toLowerCase();
this.port = port;
this.realm = realm;
this.path = null;
this.authenticatorKey = Objects.requireNonNull(authenticatorKey);
}
public Object clone() {
try {
return super.clone ();
} catch (CloneNotSupportedException e) {
// Cannot happen because Cloneable implemented by AuthenticationInfo
return null;
}
}
/*
* Constructor used to limit the authorization to the path within
* the URL. Use this constructor for origin server entries.
*/
public AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm,
String authenticatorKey) {
this.type = type;
this.authScheme = authScheme;
this.protocol = url.getProtocol().toLowerCase();
this.host = url.getHost().toLowerCase();
this.port = url.getPort();
if (this.port == -1) {
this.port = url.getDefaultPort();
}
this.realm = realm;
String urlPath = url.getPath();
if (urlPath.length() == 0)
this.path = urlPath;
else {
this.path = reducePath (urlPath);
}
this.authenticatorKey = Objects.requireNonNull(authenticatorKey);
}
/**
* The {@linkplain java.net.Authenticator#getKey(java.net.Authenticator) key}
* of the authenticator that was used to obtain the credentials.
* @return The authenticator's key.
*/
public final String getAuthenticatorKey() {
return authenticatorKey;
}
/*
* reduce the path to the root of where we think the
* authorization begins. This could get shorter as
* the url is traversed up following a successful challenge.
*/
static String reducePath (String urlPath) {
int sepIndex = urlPath.lastIndexOf('/');
int targetSuffixIndex = urlPath.lastIndexOf('.');
if (sepIndex != -1)
if (sepIndex < targetSuffixIndex)
return urlPath.substring(0, sepIndex+1);
else
return urlPath;
else
return urlPath;
}
/**
* Returns info for the URL, for an HTTP server auth. Used when we
* don't yet know the realm
* (i.e. when we're preemptively setting the auth).
*/
static AuthenticationInfo getServerAuth(URL url, String authenticatorKey) {
int port = url.getPort();
if (port == -1) {
port = url.getDefaultPort();
}
String key = SERVER_AUTHENTICATION + ":" + url.getProtocol().toLowerCase()
+ ":" + url.getHost().toLowerCase() + ":" + port
+ ";auth=" + authenticatorKey;
return getAuth(key, url);
}
/**
* Returns info for the URL, for an HTTP server auth. Used when we
* do know the realm (i.e. when we're responding to a challenge).
* In this case we do not use the path because the protection space
* is identified by the host:port:realm only
*/
static String getServerAuthKey(URL url, String realm, AuthScheme scheme,
String authenticatorKey) {
int port = url.getPort();
if (port == -1) {
port = url.getDefaultPort();
}
String key = SERVER_AUTHENTICATION + ":" + scheme + ":"
+ url.getProtocol().toLowerCase()
+ ":" + url.getHost().toLowerCase()
+ ":" + port + ":" + realm
+ ";auth=" + authenticatorKey;
return key;
}
static AuthenticationInfo getServerAuth(String key) {
AuthenticationInfo cached = getAuth(key, null);
if ((cached == null) && requestIsInProgress (key)) {
/* check the cache again, it might contain an entry */
cached = getAuth(key, null);
}
return cached;
}
/**
* Return the AuthenticationInfo object from the cache if it's path is
* a substring of the supplied URLs path.
*/
static AuthenticationInfo getAuth(String key, URL url) {
if (url == null) {
return (AuthenticationInfo)cache.get (key, null);
} else {
return (AuthenticationInfo)cache.get (key, url.getPath());
}
}
/**
* Returns a firewall authentication, for the given host/port. Used
* for preemptive header-setting. Note, the protocol field is always
* blank for proxies.
*/
static AuthenticationInfo getProxyAuth(String host, int port,
String authenticatorKey) {
String key = PROXY_AUTHENTICATION + "::" + host.toLowerCase() + ":" + port
+ ";auth=" + authenticatorKey;
AuthenticationInfo result = (AuthenticationInfo) cache.get(key, null);
return result;
}
/**
* Returns a firewall authentication, for the given host/port and realm.
* Used in response to a challenge. Note, the protocol field is always
* blank for proxies.
*/
static String getProxyAuthKey(String host, int port, String realm,
AuthScheme scheme, String authenticatorKey) {
String key = PROXY_AUTHENTICATION + ":" + scheme
+ "::" + host.toLowerCase()
+ ":" + port + ":" + realm
+ ";auth=" + authenticatorKey;
return key;
}
static AuthenticationInfo getProxyAuth(String key) {
AuthenticationInfo cached = (AuthenticationInfo) cache.get(key, null);
if ((cached == null) && requestIsInProgress (key)) {
/* check the cache again, it might contain an entry */
cached = (AuthenticationInfo) cache.get(key, null);
}
return cached;
}
/**
* Add this authentication to the cache
*/
void addToCache() {
String key = cacheKey(true);
if (useAuthCache()) {
cache.put(key, this);
if (supportsPreemptiveAuthorization()) {
cache.put(cacheKey(false), this);
}
}
endAuthRequest(key);
}
static void endAuthRequest (String key) {
if (!serializeAuth) {
return;
}
synchronized (requests) {
requestCompleted(key);
}
}
/**
* Remove this authentication from the cache
*/
void removeFromCache() {
cache.remove(cacheKey(true), this);
if (supportsPreemptiveAuthorization()) {
cache.remove(cacheKey(false), this);
}
}
/**
* @return true if this authentication supports preemptive authorization
*/
public abstract boolean supportsPreemptiveAuthorization();
/**
* @return the name of the HTTP header this authentication wants set.
* This is used for preemptive authorization.
*/
public String getHeaderName() {
if (type == SERVER_AUTHENTICATION) {
return "Authorization";
} else {
return "Proxy-authorization";
}
}
/**
* Calculates and returns the authentication header value based
* on the stored authentication parameters. If the calculation does not depend
* on the URL or the request method then these parameters are ignored.
* @param url The URL
* @param method The request method
* @return the value of the HTTP header this authentication wants set.
* Used for preemptive authorization.
*/
public abstract String getHeaderValue(URL url, String method);
/**
* Set header(s) on the given connection. Subclasses must override
* This will only be called for
* definitive (i.e. non-preemptive) authorization.
* @param conn The connection to apply the header(s) to
* @param p A source of header values for this connection, if needed.
* @param raw The raw header field (if needed)
* @return true if all goes well, false if no headers were set.
*/
public abstract boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw);
/**
* Check if the header indicates that the current auth. parameters are stale.
* If so, then replace the relevant field with the new value
* and return true. Otherwise return false.
* returning true means the request can be retried with the same userid/password
* returning false means we have to go back to the user to ask for a new
* username password.
*/
public abstract boolean isAuthorizationStale (String header);
/**
* Give a key for hash table lookups.
* @param includeRealm if you want the realm considered. Preemptively
* setting an authorization is done before the realm is known.
*/
String cacheKey(boolean includeRealm) {
// This must be kept in sync with the getXXXAuth() methods in this
// class.
String authenticatorKey = getAuthenticatorKey();
if (includeRealm) {
return type + ":" + authScheme + ":" + protocol + ":"
+ host + ":" + port + ":" + realm
+ ";auth=" + authenticatorKey;
} else {
return type + ":" + protocol + ":" + host + ":" + port
+ ";auth=" + authenticatorKey;
}
}
String s1, s2; /* used for serialization of pw */
private synchronized void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
s.defaultReadObject ();
pw = new PasswordAuthentication (s1, s2.toCharArray());
s1 = null; s2= null;
if (authenticatorKey == null) {
authenticatorKey = AuthenticatorKeys.DEFAULT;
}
}
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws IOException
{
Objects.requireNonNull(authenticatorKey);
s1 = pw.getUserName();
s2 = new String (pw.getPassword());
s.defaultWriteObject ();
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2016, 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.protocol.http;
import java.net.Authenticator;
import java.util.concurrent.atomic.AtomicLong;
/**
* A class used to tie a key to an authenticator instance.
*/
public final class AuthenticatorKeys {
private AuthenticatorKeys() {
throw new InternalError("Trying to instantiate static class");
}
public static final String DEFAULT = "default";
private static final AtomicLong IDS = new AtomicLong();
public static String computeKey(Authenticator a) {
return System.identityHashCode(a) + "-" + IDS.incrementAndGet()
+ "@" + a.getClass().getName();
}
/**
* Returns a key for the given authenticator.
*
* @param authenticator The authenticator; {@code null} should be
* passed when the {@linkplain
* Authenticator#setDefault(java.net.Authenticator) default}
* authenticator is meant.
* @return A key for the given authenticator, {@link #DEFAULT} for
* {@code null}.
*/
public static String getKey(Authenticator authenticator) {
if (authenticator == null) {
return DEFAULT;
}
return authenticatorKeyAccess.getKey(authenticator);
}
@FunctionalInterface
public interface AuthenticatorKeyAccess {
public String getKey(Authenticator a);
}
private static AuthenticatorKeyAccess authenticatorKeyAccess;
public static void setAuthenticatorKeyAccess(AuthenticatorKeyAccess access) {
if (authenticatorKeyAccess == null && access != null) {
authenticatorKeyAccess = access;
}
}
}

View file

@ -0,0 +1,212 @@
/*
* Copyright (c) 1997, 2016, 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.protocol.http;
import java.net.URL;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.PasswordAuthentication;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Base64;
import java.util.Objects;
import sun.net.www.HeaderParser;
/**
* BasicAuthentication: Encapsulate an http server authentication using
* the "basic" scheme.
*
* @author Bill Foote
*/
class BasicAuthentication extends AuthenticationInfo {
private static final long serialVersionUID = 100L;
/** The authentication string for this host, port, and realm. This is
a simple BASE64 encoding of "login:password". */
String auth;
/**
* Create a BasicAuthentication
*/
public BasicAuthentication(boolean isProxy, String host, int port,
String realm, PasswordAuthentication pw,
String authenticatorKey) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.BASIC, host, port, realm,
Objects.requireNonNull(authenticatorKey));
String plain = pw.getUserName() + ":";
byte[] nameBytes = null;
try {
nameBytes = plain.getBytes("ISO-8859-1");
} catch (java.io.UnsupportedEncodingException uee) {
assert false;
}
// get password bytes
char[] passwd = pw.getPassword();
byte[] passwdBytes = new byte[passwd.length];
for (int i=0; i<passwd.length; i++)
passwdBytes[i] = (byte)passwd[i];
// concatenate user name and password bytes and encode them
byte[] concat = new byte[nameBytes.length + passwdBytes.length];
System.arraycopy(nameBytes, 0, concat, 0, nameBytes.length);
System.arraycopy(passwdBytes, 0, concat, nameBytes.length,
passwdBytes.length);
this.auth = "Basic " + Base64.getEncoder().encodeToString(concat);
this.pw = pw;
}
/**
* Create a BasicAuthentication
*/
public BasicAuthentication(boolean isProxy, String host, int port,
String realm, String auth,
String authenticatorKey) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.BASIC, host, port, realm,
Objects.requireNonNull(authenticatorKey));
this.auth = "Basic " + auth;
}
/**
* Create a BasicAuthentication
*/
public BasicAuthentication(boolean isProxy, URL url, String realm,
PasswordAuthentication pw,
String authenticatorKey) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.BASIC, url, realm,
Objects.requireNonNull(authenticatorKey));
String plain = pw.getUserName() + ":";
byte[] nameBytes = null;
try {
nameBytes = plain.getBytes("ISO-8859-1");
} catch (java.io.UnsupportedEncodingException uee) {
assert false;
}
// get password bytes
char[] passwd = pw.getPassword();
byte[] passwdBytes = new byte[passwd.length];
for (int i=0; i<passwd.length; i++)
passwdBytes[i] = (byte)passwd[i];
// concatenate user name and password bytes and encode them
byte[] concat = new byte[nameBytes.length + passwdBytes.length];
System.arraycopy(nameBytes, 0, concat, 0, nameBytes.length);
System.arraycopy(passwdBytes, 0, concat, nameBytes.length,
passwdBytes.length);
this.auth = "Basic " + Base64.getEncoder().encodeToString(concat);
this.pw = pw;
}
/**
* Create a BasicAuthentication
*/
public BasicAuthentication(boolean isProxy, URL url, String realm,
String auth, String authenticatorKey) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.BASIC, url, realm,
Objects.requireNonNull(authenticatorKey));
this.auth = "Basic " + auth;
}
/**
* @return true if this authentication supports preemptive authorization
*/
@Override
public boolean supportsPreemptiveAuthorization() {
return true;
}
/**
* Set header(s) on the given connection. This will only be called for
* definitive (i.e. non-preemptive) authorization.
* @param conn The connection to apply the header(s) to
* @param p A source of header values for this connection, if needed.
* @param raw The raw header values for this connection, if needed.
* @return true if all goes well, false if no headers were set.
*/
@Override
public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
conn.setAuthenticationProperty(getHeaderName(), getHeaderValue(null,null));
return true;
}
/**
* @return the value of the HTTP header this authentication wants set
*/
@Override
public String getHeaderValue(URL url, String method) {
/* For Basic the authorization string does not depend on the request URL
* or the request method
*/
return auth;
}
/**
* For Basic Authentication, the security parameters can never be stale.
* In other words there is no possibility to reuse the credentials.
* They are always either valid or invalid.
*/
@Override
public boolean isAuthorizationStale (String header) {
return false;
}
/**
* @return the common root path between npath and path.
* This is used to detect when we have an authentication for two
* paths and the root of th authentication space is the common root.
*/
static String getRootPath(String npath, String opath) {
int index = 0;
int toindex;
/* Must normalize so we don't get confused by ../ and ./ segments */
try {
npath = new URI (npath).normalize().getPath();
opath = new URI (opath).normalize().getPath();
} catch (URISyntaxException e) {
/* ignore error and use the old value */
}
while (index < opath.length()) {
toindex = opath.indexOf('/', index+1);
if (toindex != -1 && opath.regionMatches(0, npath, 0, toindex+1))
index = toindex;
else
return opath.substring(0, index+1);
}
/*should not reach here. If we do simply return npath*/
return npath;
}
}

View file

@ -0,0 +1,546 @@
/*
* Copyright (c) 1997, 2016, 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.protocol.http;
import java.io.*;
import java.net.URL;
import java.net.ProtocolException;
import java.net.PasswordAuthentication;
import java.util.Arrays;
import java.util.Random;
import sun.net.www.HeaderParser;
import sun.net.NetProperties;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivilegedAction;
import java.security.AccessController;
import java.util.Objects;
import static sun.net.www.protocol.http.HttpURLConnection.HTTP_CONNECT;
/**
* DigestAuthentication: Encapsulate an http server authentication using
* the "Digest" scheme, as described in RFC2069 and updated in RFC2617
*
* @author Bill Foote
*/
class DigestAuthentication extends AuthenticationInfo {
private static final long serialVersionUID = 100L;
private String authMethod;
private static final String compatPropName = "http.auth.digest." +
"quoteParameters";
// true if http.auth.digest.quoteParameters Net property is true
private static final boolean delimCompatFlag;
static {
Boolean b = AccessController.doPrivileged(
new PrivilegedAction<>() {
public Boolean run() {
return NetProperties.getBoolean(compatPropName);
}
}
);
delimCompatFlag = (b == null) ? false : b.booleanValue();
}
// Authentication parameters defined in RFC2617.
// One instance of these may be shared among several DigestAuthentication
// instances as a result of a single authorization (for multiple domains)
static class Parameters implements java.io.Serializable {
private static final long serialVersionUID = -3584543755194526252L;
private boolean serverQop; // server proposed qop=auth
private String opaque;
private String cnonce;
private String nonce;
private String algorithm;
private int NCcount=0;
// The H(A1) string used for MD5-sess
private String cachedHA1;
// Force the HA1 value to be recalculated because the nonce has changed
private boolean redoCachedHA1 = true;
private static final int cnonceRepeat = 5;
private static final int cnoncelen = 40; /* number of characters in cnonce */
private static Random random;
static {
random = new Random();
}
Parameters () {
serverQop = false;
opaque = null;
algorithm = null;
cachedHA1 = null;
nonce = null;
setNewCnonce();
}
boolean authQop () {
return serverQop;
}
synchronized void incrementNC() {
NCcount ++;
}
synchronized int getNCCount () {
return NCcount;
}
int cnonce_count = 0;
/* each call increments the counter */
synchronized String getCnonce () {
if (cnonce_count >= cnonceRepeat) {
setNewCnonce();
}
cnonce_count++;
return cnonce;
}
synchronized void setNewCnonce () {
byte bb[] = new byte [cnoncelen/2];
char cc[] = new char [cnoncelen];
random.nextBytes (bb);
for (int i=0; i<(cnoncelen/2); i++) {
int x = bb[i] + 128;
cc[i*2]= (char) ('A'+ x/16);
cc[i*2+1]= (char) ('A'+ x%16);
}
cnonce = new String (cc, 0, cnoncelen);
cnonce_count = 0;
redoCachedHA1 = true;
}
synchronized void setQop (String qop) {
if (qop != null) {
String items[] = qop.split(",");
for (String item : items) {
if ("auth".equalsIgnoreCase(item.trim())) {
serverQop = true;
return;
}
}
}
serverQop = false;
}
synchronized String getOpaque () { return opaque;}
synchronized void setOpaque (String s) { opaque=s;}
synchronized String getNonce () { return nonce;}
synchronized void setNonce (String s) {
if (nonce == null || !s.equals(nonce)) {
nonce=s;
NCcount = 0;
redoCachedHA1 = true;
}
}
synchronized String getCachedHA1 () {
if (redoCachedHA1) {
return null;
} else {
return cachedHA1;
}
}
synchronized void setCachedHA1 (String s) {
cachedHA1=s;
redoCachedHA1=false;
}
synchronized String getAlgorithm () { return algorithm;}
synchronized void setAlgorithm (String s) { algorithm=s;}
}
Parameters params;
/**
* Create a DigestAuthentication
*/
public DigestAuthentication(boolean isProxy, URL url, String realm,
String authMethod, PasswordAuthentication pw,
Parameters params, String authenticatorKey) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.DIGEST,
url,
realm,
Objects.requireNonNull(authenticatorKey));
this.authMethod = authMethod;
this.pw = pw;
this.params = params;
}
public DigestAuthentication(boolean isProxy, String host, int port, String realm,
String authMethod, PasswordAuthentication pw,
Parameters params, String authenticatorKey) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.DIGEST,
host,
port,
realm,
Objects.requireNonNull(authenticatorKey));
this.authMethod = authMethod;
this.pw = pw;
this.params = params;
}
/**
* @return true if this authentication supports preemptive authorization
*/
@Override
public boolean supportsPreemptiveAuthorization() {
return true;
}
/**
* Recalculates the request-digest and returns it.
*
* <P> Used in the common case where the requestURI is simply the
* abs_path.
*
* @param url
* the URL
*
* @param method
* the HTTP method
*
* @return the value of the HTTP header this authentication wants set
*/
@Override
public String getHeaderValue(URL url, String method) {
return getHeaderValueImpl(url.getFile(), method);
}
/**
* Recalculates the request-digest and returns it.
*
* <P> Used when the requestURI is not the abs_path. The exact
* requestURI can be passed as a String.
*
* @param requestURI
* the Request-URI from the HTTP request line
*
* @param method
* the HTTP method
*
* @return the value of the HTTP header this authentication wants set
*/
String getHeaderValue(String requestURI, String method) {
return getHeaderValueImpl(requestURI, method);
}
/**
* Check if the header indicates that the current auth. parameters are stale.
* If so, then replace the relevant field with the new value
* and return true. Otherwise return false.
* returning true means the request can be retried with the same userid/password
* returning false means we have to go back to the user to ask for a new
* username password.
*/
@Override
public boolean isAuthorizationStale (String header) {
HeaderParser p = new HeaderParser (header);
String s = p.findValue ("stale");
if (s == null || !s.equals("true"))
return false;
String newNonce = p.findValue ("nonce");
if (newNonce == null || "".equals(newNonce)) {
return false;
}
params.setNonce (newNonce);
return true;
}
/**
* Set header(s) on the given connection.
* @param conn The connection to apply the header(s) to
* @param p A source of header values for this connection, if needed.
* @param raw Raw header values for this connection, if needed.
* @return true if all goes well, false if no headers were set.
*/
@Override
public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
params.setNonce (p.findValue("nonce"));
params.setOpaque (p.findValue("opaque"));
params.setQop (p.findValue("qop"));
String uri="";
String method;
if (type == PROXY_AUTHENTICATION &&
conn.tunnelState() == HttpURLConnection.TunnelState.SETUP) {
uri = HttpURLConnection.connectRequestURI(conn.getURL());
method = HTTP_CONNECT;
} else {
try {
uri = conn.getRequestURI();
} catch (IOException e) {}
method = conn.getMethod();
}
if (params.nonce == null || authMethod == null || pw == null || realm == null) {
return false;
}
if (authMethod.length() >= 1) {
// Method seems to get converted to all lower case elsewhere.
// It really does need to start with an upper case letter
// here.
authMethod = Character.toUpperCase(authMethod.charAt(0))
+ authMethod.substring(1).toLowerCase();
}
String algorithm = p.findValue("algorithm");
if (algorithm == null || "".equals(algorithm)) {
algorithm = "MD5"; // The default, accoriding to rfc2069
}
params.setAlgorithm (algorithm);
// If authQop is true, then the server is doing RFC2617 and
// has offered qop=auth. We do not support any other modes
// and if auth is not offered we fallback to the RFC2069 behavior
if (params.authQop()) {
params.setNewCnonce();
}
String value = getHeaderValueImpl (uri, method);
if (value != null) {
conn.setAuthenticationProperty(getHeaderName(), value);
return true;
} else {
return false;
}
}
/* Calculate the Authorization header field given the request URI
* and based on the authorization information in params
*/
private String getHeaderValueImpl (String uri, String method) {
String response;
char[] passwd = pw.getPassword();
boolean qop = params.authQop();
String opaque = params.getOpaque();
String cnonce = params.getCnonce ();
String nonce = params.getNonce ();
String algorithm = params.getAlgorithm ();
params.incrementNC ();
int nccount = params.getNCCount ();
String ncstring=null;
if (nccount != -1) {
ncstring = Integer.toHexString (nccount).toLowerCase();
int len = ncstring.length();
if (len < 8)
ncstring = zeroPad [len] + ncstring;
}
try {
response = computeDigest(true, pw.getUserName(),passwd,realm,
method, uri, nonce, cnonce, ncstring);
} catch (NoSuchAlgorithmException ex) {
return null;
}
String ncfield = "\"";
if (qop) {
ncfield = "\", nc=" + ncstring;
}
String algoS, qopS;
if (delimCompatFlag) {
// Put quotes around these String value parameters
algoS = ", algorithm=\"" + algorithm + "\"";
qopS = ", qop=\"auth\"";
} else {
// Don't put quotes around them, per the RFC
algoS = ", algorithm=" + algorithm;
qopS = ", qop=auth";
}
String value = authMethod
+ " username=\"" + pw.getUserName()
+ "\", realm=\"" + realm
+ "\", nonce=\"" + nonce
+ ncfield
+ ", uri=\"" + uri
+ "\", response=\"" + response + "\""
+ algoS;
if (opaque != null) {
value += ", opaque=\"" + opaque + "\"";
}
if (cnonce != null) {
value += ", cnonce=\"" + cnonce + "\"";
}
if (qop) {
value += qopS;
}
return value;
}
public void checkResponse (String header, String method, URL url)
throws IOException {
checkResponse (header, method, url.getFile());
}
public void checkResponse (String header, String method, String uri)
throws IOException {
char[] passwd = pw.getPassword();
String username = pw.getUserName();
boolean qop = params.authQop();
String opaque = params.getOpaque();
String cnonce = params.cnonce;
String nonce = params.getNonce ();
String algorithm = params.getAlgorithm ();
int nccount = params.getNCCount ();
String ncstring=null;
if (header == null) {
throw new ProtocolException ("No authentication information in response");
}
if (nccount != -1) {
ncstring = Integer.toHexString (nccount).toUpperCase();
int len = ncstring.length();
if (len < 8)
ncstring = zeroPad [len] + ncstring;
}
try {
String expected = computeDigest(false, username,passwd,realm,
method, uri, nonce, cnonce, ncstring);
HeaderParser p = new HeaderParser (header);
String rspauth = p.findValue ("rspauth");
if (rspauth == null) {
throw new ProtocolException ("No digest in response");
}
if (!rspauth.equals (expected)) {
throw new ProtocolException ("Response digest invalid");
}
/* Check if there is a nextnonce field */
String nextnonce = p.findValue ("nextnonce");
if (nextnonce != null && ! "".equals(nextnonce)) {
params.setNonce (nextnonce);
}
} catch (NoSuchAlgorithmException ex) {
throw new ProtocolException ("Unsupported algorithm in response");
}
}
private String computeDigest(
boolean isRequest, String userName, char[] password,
String realm, String connMethod,
String requestURI, String nonceString,
String cnonce, String ncValue
) throws NoSuchAlgorithmException
{
String A1, HashA1;
String algorithm = params.getAlgorithm ();
boolean md5sess = algorithm.equalsIgnoreCase ("MD5-sess");
MessageDigest md = MessageDigest.getInstance(md5sess?"MD5":algorithm);
if (md5sess) {
if ((HashA1 = params.getCachedHA1 ()) == null) {
String s = userName + ":" + realm + ":";
String s1 = encode (s, password, md);
A1 = s1 + ":" + nonceString + ":" + cnonce;
HashA1 = encode(A1, null, md);
params.setCachedHA1 (HashA1);
}
} else {
A1 = userName + ":" + realm + ":";
HashA1 = encode(A1, password, md);
}
String A2;
if (isRequest) {
A2 = connMethod + ":" + requestURI;
} else {
A2 = ":" + requestURI;
}
String HashA2 = encode(A2, null, md);
String combo, finalHash;
if (params.authQop()) { /* RRC2617 when qop=auth */
combo = HashA1+ ":" + nonceString + ":" + ncValue + ":" +
cnonce + ":auth:" +HashA2;
} else { /* for compatibility with RFC2069 */
combo = HashA1 + ":" +
nonceString + ":" +
HashA2;
}
finalHash = encode(combo, null, md);
return finalHash;
}
private static final char charArray[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
private static final String zeroPad[] = {
// 0 1 2 3 4 5 6 7
"00000000", "0000000", "000000", "00000", "0000", "000", "00", "0"
};
private String encode(String src, char[] passwd, MessageDigest md) {
try {
md.update(src.getBytes("ISO-8859-1"));
} catch (java.io.UnsupportedEncodingException uee) {
assert false;
}
if (passwd != null) {
byte[] passwdBytes = new byte[passwd.length];
for (int i=0; i<passwd.length; i++)
passwdBytes[i] = (byte)passwd[i];
md.update(passwdBytes);
Arrays.fill(passwdBytes, (byte)0x00);
}
byte[] digest = md.digest();
StringBuilder res = new StringBuilder(digest.length * 2);
for (int i = 0; i < digest.length; i++) {
int hashchar = ((digest[i] >>> 4) & 0xf);
res.append(charArray[hashchar]);
hashchar = (digest[i] & 0xf);
res.append(charArray[hashchar]);
}
return res.toString();
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 1994, 2003, 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.
*/
/*-
* HTTP stream opener
*/
package sun.net.www.protocol.http;
import java.io.IOException;
import java.net.URL;
import java.net.Proxy;
/** open an http input stream given a URL */
public class Handler extends java.net.URLStreamHandler {
protected String proxy;
protected int proxyPort;
protected int getDefaultPort() {
return 80;
}
public Handler () {
proxy = null;
proxyPort = -1;
}
public Handler (String proxy, int port) {
this.proxy = proxy;
this.proxyPort = port;
}
protected java.net.URLConnection openConnection(URL u)
throws IOException {
return openConnection(u, (Proxy)null);
}
protected java.net.URLConnection openConnection(URL u, Proxy p)
throws IOException {
return new HttpURLConnection(u, p, this);
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 1996, 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.protocol.http;
import java.net.URL;
/**
* An interface for all objects that implement HTTP authentication.
* See the HTTP spec for details on how this works in general.
* A single class or object can implement an arbitrary number of
* authentication schemes.
*
* @author David Brown
*
* @deprecated -- use java.net.Authenticator instead
* @see java.net.Authenticator
*/
//
// REMIND: Unless compatibility with sun.* API's from 1.2 to 2.0 is
// a goal, there's no reason to carry this forward into JDK 2.0.
@Deprecated
public interface HttpAuthenticator {
/**
* Indicate whether the specified authentication scheme is
* supported. In accordance with HTTP specifications, the
* scheme name should be checked in a case-insensitive fashion.
*/
boolean schemeSupported (String scheme);
/**
* Returns the String that should be included in the HTTP
* <B>Authorization</B> field. Return null if no info was
* supplied or could be found.
* <P>
* Example:
* <pre>{@code
* --> GET http://www.authorization-required.com/ HTTP/1.0
* <-- HTTP/1.0 403 Unauthorized
* <-- WWW-Authenticate: Basic realm="WallyWorld"
* call schemeSupported("Basic"); (return true)
* call authString(u, "Basic", "WallyWorld", null);
* return "QWadhgWERghghWERfdfQ=="
* --> GET http://www.authorization-required.com/ HTTP/1.0
* --> Authorization: Basic QWadhgWERghghWERfdfQ==
* <-- HTTP/1.0 200 OK}
* <B> YAY!!!</B>
* </pre>
*/
public String authString (URL u, String scheme, String realm);
}

View file

@ -0,0 +1,113 @@
/*
* Copyright (c) 2009, 2016, 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.protocol.http;
import java.net.Authenticator;
import java.net.Authenticator.RequestorType;
import java.net.InetAddress;
import java.net.URL;
/**
* Used in HTTP/Negotiate, to feed HTTP request info into JGSS as a HttpCaller,
* so that special actions can be taken, including special callback handler,
* special useSubjectCredsOnly value.
*
* This is an immutable class. It can be instantiated in two styles;
*
* 1. Un-schemed: Create at the beginning before the preferred scheme is
* determined. This object can be fed into AuthenticationHeader to check
* for the preference.
*
* 2. Schemed: With the scheme field filled, can be used in JGSS-API calls.
*/
public final class HttpCallerInfo {
// All info that an Authenticator needs.
public final URL url;
public final String host, protocol, prompt, scheme;
public final int port;
public final InetAddress addr;
public final RequestorType authType;
public final Authenticator authenticator;
/**
* Create a schemed object based on an un-schemed one.
*/
public HttpCallerInfo(HttpCallerInfo old, String scheme) {
this.url = old.url;
this.host = old.host;
this.protocol = old.protocol;
this.prompt = old.prompt;
this.port = old.port;
this.addr = old.addr;
this.authType = old.authType;
this.scheme = scheme;
this.authenticator = old.authenticator;
}
/**
* Constructor an un-schemed object for site access.
*/
public HttpCallerInfo(URL url, Authenticator a) {
this.url= url;
prompt = "";
host = url.getHost();
int p = url.getPort();
if (p == -1) {
port = url.getDefaultPort();
} else {
port = p;
}
InetAddress ia;
try {
ia = InetAddress.getByName(url.getHost());
} catch (Exception e) {
ia = null;
}
addr = ia;
protocol = url.getProtocol();
authType = RequestorType.SERVER;
scheme = "";
authenticator = a;
}
/**
* Constructor an un-schemed object for proxy access.
*/
public HttpCallerInfo(URL url, String host, int port, Authenticator a) {
this.url= url;
this.host = host;
this.port = port;
prompt = "";
addr = null;
protocol = url.getProtocol();
authType = RequestorType.PROXY;
scheme = "";
authenticator = a;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2009, 2016, 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.protocol.http;
import java.net.URL;
import java.net.PasswordAuthentication;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import sun.util.logging.PlatformLogger;
/**
* Proxy class for loading NTLMAuthentication, so as to remove static
* dependancy.
*/
class NTLMAuthenticationProxy {
private static Method supportsTA;
private static Method isTrustedSite;
private static final String clazzStr = "sun.net.www.protocol.http.ntlm.NTLMAuthentication";
private static final String supportsTAStr = "supportsTransparentAuth";
private static final String isTrustedSiteStr = "isTrustedSite";
static final NTLMAuthenticationProxy proxy = tryLoadNTLMAuthentication();
static final boolean supported = proxy != null ? true : false;
static final boolean supportsTransparentAuth = supported ? supportsTransparentAuth() : false;
private final Constructor<? extends AuthenticationInfo> fourArgCtr;
private final Constructor<? extends AuthenticationInfo> sixArgCtr;
private NTLMAuthenticationProxy(Constructor<? extends AuthenticationInfo> fourArgCtr,
Constructor<? extends AuthenticationInfo> sixArgCtr) {
this.fourArgCtr = fourArgCtr;
this.sixArgCtr = sixArgCtr;
}
AuthenticationInfo create(boolean isProxy,
URL url,
PasswordAuthentication pw,
String authenticatorKey) {
try {
return fourArgCtr.newInstance(isProxy, url, pw, authenticatorKey);
} catch (ReflectiveOperationException roe) {
finest(roe);
}
return null;
}
AuthenticationInfo create(boolean isProxy,
String host,
int port,
PasswordAuthentication pw,
String authenticatorKey) {
try {
return sixArgCtr.newInstance(isProxy, host, port, pw, authenticatorKey);
} catch (ReflectiveOperationException roe) {
finest(roe);
}
return null;
}
/* Returns true if the NTLM implementation supports transparent
* authentication (try with the current users credentials before
* prompting for username and password, etc).
*/
private static boolean supportsTransparentAuth() {
try {
return (Boolean)supportsTA.invoke(null);
} catch (ReflectiveOperationException roe) {
finest(roe);
}
return false;
}
/* Transparent authentication should only be tried with a trusted
* site ( when running in a secure environment ).
*/
public static boolean isTrustedSite(URL url) {
try {
return (Boolean)isTrustedSite.invoke(null, url);
} catch (ReflectiveOperationException roe) {
finest(roe);
}
return false;
}
/**
* Loads the NTLM authentiation implementation through reflection. If
* the class is present, then it must have the required constructors and
* method. Otherwise, it is considered an error.
*/
@SuppressWarnings("unchecked")
private static NTLMAuthenticationProxy tryLoadNTLMAuthentication() {
Class<? extends AuthenticationInfo> cl;
Constructor<? extends AuthenticationInfo> fourArg, sixArg;
try {
cl = (Class<? extends AuthenticationInfo>)Class.forName(clazzStr, true, null);
if (cl != null) {
fourArg = cl.getConstructor(boolean.class,
URL.class,
PasswordAuthentication.class,
String.class);
sixArg = cl.getConstructor(boolean.class,
String.class,
int.class,
PasswordAuthentication.class,
String.class);
supportsTA = cl.getDeclaredMethod(supportsTAStr);
isTrustedSite = cl.getDeclaredMethod(isTrustedSiteStr, java.net.URL.class);
return new NTLMAuthenticationProxy(fourArg,
sixArg);
}
} catch (ClassNotFoundException cnfe) {
finest(cnfe);
} catch (ReflectiveOperationException roe) {
throw new AssertionError(roe);
}
return null;
}
static void finest(Exception e) {
PlatformLogger logger = HttpURLConnection.getHttpLogger();
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
logger.finest("NTLMAuthenticationProxy: " + e);
}
}
}

View file

@ -0,0 +1,262 @@
/*
* Copyright (c) 2005, 2016, 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.protocol.http;
import java.net.URL;
import java.io.IOException;
import java.net.Authenticator.RequestorType;
import java.util.Base64;
import java.util.HashMap;
import sun.net.www.HeaderParser;
import sun.util.logging.PlatformLogger;
import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE;
import static sun.net.www.protocol.http.AuthScheme.KERBEROS;
import sun.security.action.GetPropertyAction;
/**
* NegotiateAuthentication:
*
* @author weijun.wang@sun.com
* @since 1.6
*/
class NegotiateAuthentication extends AuthenticationInfo {
private static final long serialVersionUID = 100L;
private static final PlatformLogger logger = HttpURLConnection.getHttpLogger();
private final HttpCallerInfo hci;
// These maps are used to manage the GSS availability for diffrent
// hosts. The key for both maps is the host name.
// <code>supported</code> is set when isSupported is checked,
// if it's true, a cached Negotiator is put into <code>cache</code>.
// the cache can be used only once, so after the first use, it's cleaned.
static HashMap <String, Boolean> supported = null;
static ThreadLocal <HashMap <String, Negotiator>> cache = null;
/* Whether cache is enabled for Negotiate/Kerberos */
private static final boolean cacheSPNEGO;
static {
String spnegoCacheProp =
GetPropertyAction.privilegedGetProperty("jdk.spnego.cache", "true");
cacheSPNEGO = Boolean.parseBoolean(spnegoCacheProp);
}
// The HTTP Negotiate Helper
private Negotiator negotiator = null;
/**
* Constructor used for both WWW and proxy entries.
* @param hci a schemed object.
*/
public NegotiateAuthentication(HttpCallerInfo hci) {
super(RequestorType.PROXY==hci.authType ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
hci.scheme.equalsIgnoreCase("Negotiate") ? NEGOTIATE : KERBEROS,
hci.url,
"",
AuthenticatorKeys.getKey(hci.authenticator));
this.hci = hci;
}
/**
* @return true if this authentication supports preemptive authorization
*/
@Override
public boolean supportsPreemptiveAuthorization() {
return false;
}
/**
* Find out if the HttpCallerInfo supports Negotiate protocol.
* @return true if supported
*/
public static boolean isSupported(HttpCallerInfo hci) {
ClassLoader loader = null;
try {
loader = Thread.currentThread().getContextClassLoader();
} catch (SecurityException se) {
if (logger.isLoggable(PlatformLogger.Level.FINER)) {
logger.finer("NegotiateAuthentication: " +
"Attempt to get the context class loader failed - " + se);
}
}
if (loader != null) {
// Lock on the class loader instance to avoid the deadlock engaging
// the lock in "ClassLoader.loadClass(String, boolean)" method.
synchronized (loader) {
return isSupportedImpl(hci);
}
}
return isSupportedImpl(hci);
}
/**
* Find out if the HttpCallerInfo supports Negotiate protocol. In order to
* find out yes or no, an initialization of a Negotiator object against it
* is tried. The generated object will be cached under the name of ths
* hostname at a success try.<br>
*
* If this method is called for the second time on an HttpCallerInfo with
* the same hostname, the answer is retrieved from cache.
*
* @return true if supported
*/
private static synchronized boolean isSupportedImpl(HttpCallerInfo hci) {
if (supported == null) {
supported = new HashMap<>();
}
String hostname = hci.host;
hostname = hostname.toLowerCase();
if (supported.containsKey(hostname)) {
return supported.get(hostname);
}
Negotiator neg = Negotiator.getNegotiator(hci);
if (neg != null) {
supported.put(hostname, true);
// the only place cache.put is called. here we can make sure
// the object is valid and the oneToken inside is not null
if (cache == null) {
cache = new ThreadLocal<>() {
@Override
protected HashMap<String, Negotiator> initialValue() {
return new HashMap<>();
}
};
}
cache.get().put(hostname, neg);
return true;
} else {
supported.put(hostname, false);
return false;
}
}
private static synchronized HashMap<String, Negotiator> getCache() {
if (cache == null) return null;
return cache.get();
}
@Override
protected boolean useAuthCache() {
return super.useAuthCache() && cacheSPNEGO;
}
/**
* Not supported. Must use the setHeaders() method
*/
@Override
public String getHeaderValue(URL url, String method) {
throw new RuntimeException ("getHeaderValue not supported");
}
/**
* Check if the header indicates that the current auth. parameters are stale.
* If so, then replace the relevant field with the new value
* and return true. Otherwise return false.
* returning true means the request can be retried with the same userid/password
* returning false means we have to go back to the user to ask for a new
* username password.
*/
@Override
public boolean isAuthorizationStale (String header) {
return false; /* should not be called for Negotiate */
}
/**
* Set header(s) on the given connection.
* @param conn The connection to apply the header(s) to
* @param p A source of header values for this connection, not used because
* HeaderParser converts the fields to lower case, use raw instead
* @param raw The raw header field.
* @return true if all goes well, false if no headers were set.
*/
@Override
public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
try {
String response;
byte[] incoming = null;
String[] parts = raw.split("\\s+");
if (parts.length > 1) {
incoming = Base64.getDecoder().decode(parts[1]);
}
response = hci.scheme + " " + Base64.getEncoder().encodeToString(
incoming==null?firstToken():nextToken(incoming));
conn.setAuthenticationProperty(getHeaderName(), response);
return true;
} catch (IOException e) {
return false;
}
}
/**
* return the first token.
* @return the token
* @throws IOException if <code>Negotiator.getNegotiator()</code> or
* <code>Negotiator.firstToken()</code> failed.
*/
private byte[] firstToken() throws IOException {
negotiator = null;
HashMap <String, Negotiator> cachedMap = getCache();
if (cachedMap != null) {
negotiator = cachedMap.get(getHost());
if (negotiator != null) {
cachedMap.remove(getHost()); // so that it is only used once
}
}
if (negotiator == null) {
negotiator = Negotiator.getNegotiator(hci);
if (negotiator == null) {
IOException ioe = new IOException("Cannot initialize Negotiator");
throw ioe;
}
}
return negotiator.firstToken();
}
/**
* return more tokens
* @param token the token to be fed into <code>negotiator.nextToken()</code>
* @return the token
* @throws IOException if <code>negotiator.nextToken()</code> throws Exception.
* May happen if the input token is invalid.
*/
private byte[] nextToken(byte[] token) throws IOException {
return negotiator.nextToken(token);
}
// MS will send a final WWW-Authenticate even if the status is already
// 200 OK. The token can be fed into initSecContext() again to determine
// if the server can be trusted. This is not the same concept as Digest's
// Authentication-Info header.
//
// Currently we ignore this header.
}

View file

@ -0,0 +1,86 @@
/*
* 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.www.protocol.http;
import java.io.IOException;
import java.lang.reflect.Constructor;
import sun.util.logging.PlatformLogger;
/**
* This abstract class is a bridge to connect NegotiteAuthentication and
* NegotiatorImpl, so that JAAS and JGSS calls can be made
*/
public abstract class Negotiator {
static Negotiator getNegotiator(HttpCallerInfo hci) {
// These lines are equivalent to
// return new NegotiatorImpl(hci);
// The current implementation will make sure NegotiatorImpl is not
// directly referenced when compiling, thus smooth the way of building
// the J2SE platform where HttpURLConnection is a bootstrap class.
//
// Makes NegotiatorImpl, and the security classes it references, a
// runtime dependency rather than a static one.
Class<?> clazz;
Constructor<?> c;
try {
clazz = Class.forName("sun.net.www.protocol.http.spnego.NegotiatorImpl",
true,
ClassLoader.getPlatformClassLoader());
c = clazz.getConstructor(HttpCallerInfo.class);
} catch (ClassNotFoundException cnfe) {
finest(cnfe);
return null;
} catch (ReflectiveOperationException roe) {
// if the class is there then something seriously wrong if
// the constructor is not.
throw new AssertionError(roe);
}
try {
return (Negotiator) (c.newInstance(hci));
} catch (ReflectiveOperationException roe) {
finest(roe);
Throwable t = roe.getCause();
if (t != null && t instanceof Exception)
finest((Exception)t);
return null;
}
}
public abstract byte[] firstToken() throws IOException;
public abstract byte[] nextToken(byte[] in) throws IOException;
private static void finest(Exception e) {
PlatformLogger logger = HttpURLConnection.getHttpLogger();
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
logger.finest("NegotiateAuthentication: " + e);
}
}
}

View file

@ -0,0 +1,59 @@
/*
* 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.www.protocol.http.ntlm;
import java.net.URL;
/**
* This class is used to call back to deployment to determine if a given
* URL is trusted. Transparent authentication (try with logged in users
* credentials without prompting) should only be tried with trusted sites.
*/
public abstract class NTLMAuthenticationCallback {
private static volatile NTLMAuthenticationCallback callback =
new DefaultNTLMAuthenticationCallback();
public static void setNTLMAuthenticationCallback(
NTLMAuthenticationCallback callback) {
NTLMAuthenticationCallback.callback = callback;
}
public static NTLMAuthenticationCallback getNTLMAuthenticationCallback() {
return callback;
}
/**
* Returns true if the given site is trusted, i.e. we can try
* transparent Authentication.
*/
public abstract boolean isTrustedSite(URL url);
static class DefaultNTLMAuthenticationCallback extends NTLMAuthenticationCallback {
@Override
public boolean isTrustedSite(URL url) { return true; }
}
}

View file

@ -0,0 +1,299 @@
/*
* Copyright (c) 2001, 2015, 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.protocol.https;
import java.net.URL;
import java.net.Proxy;
import java.net.SecureCacheResponse;
import java.security.Principal;
import java.io.IOException;
import java.util.List;
import javax.net.ssl.SSLPeerUnverifiedException;
import sun.net.www.http.*;
import sun.net.www.protocol.http.HttpURLConnection;
/**
* HTTPS URL connection support.
* We need this delegate because HttpsURLConnection is a subclass of
* java.net.HttpURLConnection. We will avoid copying over the code from
* sun.net.www.protocol.http.HttpURLConnection by having this class
*
*/
public abstract class AbstractDelegateHttpsURLConnection extends
HttpURLConnection {
protected AbstractDelegateHttpsURLConnection(URL url,
sun.net.www.protocol.http.Handler handler) throws IOException {
this(url, null, handler);
}
protected AbstractDelegateHttpsURLConnection(URL url, Proxy p,
sun.net.www.protocol.http.Handler handler) throws IOException {
super(url, p, handler);
}
protected abstract javax.net.ssl.SSLSocketFactory getSSLSocketFactory();
protected abstract javax.net.ssl.HostnameVerifier getHostnameVerifier();
/**
* No user application is able to call these routines, as no one
* should ever get access to an instance of
* DelegateHttpsURLConnection (sun.* or com.*)
*/
/**
* Create a new HttpClient object, bypassing the cache of
* HTTP client objects/connections.
*
* Note: this method is changed from protected to public because
* the com.sun.ssl.internal.www.protocol.https handler reuses this
* class for its actual implemantation
*
* @param url the URL being accessed
*/
public void setNewClient (URL url)
throws IOException {
setNewClient (url, false);
}
/**
* Obtain a HttpClient object. Use the cached copy if specified.
*
* Note: this method is changed from protected to public because
* the com.sun.ssl.internal.www.protocol.https handler reuses this
* class for its actual implemantation
*
* @param url the URL being accessed
* @param useCache whether the cached connection should be used
* if present
*/
public void setNewClient (URL url, boolean useCache)
throws IOException {
http = HttpsClient.New (getSSLSocketFactory(),
url,
getHostnameVerifier(),
useCache, this);
((HttpsClient)http).afterConnect();
}
/**
* Create a new HttpClient object, set up so that it uses
* per-instance proxying to the given HTTP proxy. This
* bypasses the cache of HTTP client objects/connections.
*
* Note: this method is changed from protected to public because
* the com.sun.ssl.internal.www.protocol.https handler reuses this
* class for its actual implemantation
*
* @param url the URL being accessed
* @param proxyHost the proxy host to use
* @param proxyPort the proxy port to use
*/
public void setProxiedClient (URL url, String proxyHost, int proxyPort)
throws IOException {
setProxiedClient(url, proxyHost, proxyPort, false);
}
/**
* Obtain a HttpClient object, set up so that it uses per-instance
* proxying to the given HTTP proxy. Use the cached copy of HTTP
* client objects/connections if specified.
*
* Note: this method is changed from protected to public because
* the com.sun.ssl.internal.www.protocol.https handler reuses this
* class for its actual implemantation
*
* @param url the URL being accessed
* @param proxyHost the proxy host to use
* @param proxyPort the proxy port to use
* @param useCache whether the cached connection should be used
* if present
*/
public void setProxiedClient (URL url, String proxyHost, int proxyPort,
boolean useCache) throws IOException {
proxiedConnect(url, proxyHost, proxyPort, useCache);
if (!http.isCachedConnection()) {
doTunneling();
}
((HttpsClient)http).afterConnect();
}
protected void proxiedConnect(URL url, String proxyHost, int proxyPort,
boolean useCache) throws IOException {
if (connected)
return;
http = HttpsClient.New (getSSLSocketFactory(),
url,
getHostnameVerifier(),
proxyHost, proxyPort, useCache, this);
connected = true;
}
/**
* Used by subclass to access "connected" variable.
*/
public boolean isConnected() {
return connected;
}
/**
* Used by subclass to access "connected" variable.
*/
public void setConnected(boolean conn) {
connected = conn;
}
/**
* Implements the HTTP protocol handler's "connect" method,
* establishing an SSL connection to the server as necessary.
*/
public void connect() throws IOException {
if (connected)
return;
plainConnect();
if (cachedResponse != null) {
// using cached response
return;
}
if (!http.isCachedConnection() && http.needsTunneling()) {
doTunneling();
}
((HttpsClient)http).afterConnect();
}
// will try to use cached HttpsClient
protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout)
throws IOException {
return HttpsClient.New(getSSLSocketFactory(), url,
getHostnameVerifier(), p, true, connectTimeout,
this);
}
// will open new connection
protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout,
boolean useCache)
throws IOException {
return HttpsClient.New(getSSLSocketFactory(), url,
getHostnameVerifier(), p,
useCache, connectTimeout, this);
}
/**
* Returns the cipher suite in use on this connection.
*/
public String getCipherSuite () {
if (cachedResponse != null) {
return ((SecureCacheResponse)cachedResponse).getCipherSuite();
}
if (http == null) {
throw new IllegalStateException("connection not yet open");
} else {
return ((HttpsClient)http).getCipherSuite ();
}
}
/**
* Returns the certificate chain the client sent to the
* server, or null if the client did not authenticate.
*/
public java.security.cert.Certificate[] getLocalCertificates() {
if (cachedResponse != null) {
List<java.security.cert.Certificate> l = ((SecureCacheResponse)cachedResponse).getLocalCertificateChain();
if (l == null) {
return null;
} else {
return l.toArray(new java.security.cert.Certificate[0]);
}
}
if (http == null) {
throw new IllegalStateException("connection not yet open");
} else {
return (((HttpsClient)http).getLocalCertificates ());
}
}
/**
* Returns the server's certificate chain, or throws
* SSLPeerUnverified Exception if
* the server did not authenticate.
*/
public java.security.cert.Certificate[] getServerCertificates()
throws SSLPeerUnverifiedException {
if (cachedResponse != null) {
List<java.security.cert.Certificate> l =
((SecureCacheResponse)cachedResponse)
.getServerCertificateChain();
if (l == null) {
return null;
} else {
return l.toArray(new java.security.cert.Certificate[0]);
}
}
if (http == null) {
throw new IllegalStateException("connection not yet open");
} else {
return (((HttpsClient)http).getServerCertificates ());
}
}
/**
* Returns the server's principal, or throws SSLPeerUnverifiedException
* if the server did not authenticate.
*/
Principal getPeerPrincipal()
throws SSLPeerUnverifiedException
{
if (cachedResponse != null) {
return ((SecureCacheResponse)cachedResponse).getPeerPrincipal();
}
if (http == null) {
throw new IllegalStateException("connection not yet open");
} else {
return (((HttpsClient)http).getPeerPrincipal());
}
}
/**
* Returns the principal the client sent to the
* server, or null if the client did not authenticate.
*/
Principal getLocalPrincipal()
{
if (cachedResponse != null) {
return ((SecureCacheResponse)cachedResponse).getLocalPrincipal();
}
if (http == null) {
throw new IllegalStateException("connection not yet open");
} else {
return (((HttpsClient)http).getLocalPrincipal());
}
}
}

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2001, 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.www.protocol.https;
import java.net.URL;
import java.net.Proxy;
import java.io.IOException;
/**
* This class was introduced to provide an additional level of
* abstraction between javax.net.ssl.HttpURLConnection and
* com.sun.net.ssl.HttpURLConnection objects. <p>
*
* javax.net.ssl.HttpURLConnection is used in the new sun.net version
* of protocol implementation (this one)
* com.sun.net.ssl.HttpURLConnection is used in the com.sun version.
*
*/
public class DelegateHttpsURLConnection extends AbstractDelegateHttpsURLConnection {
// we need a reference to the HttpsURLConnection to get
// the properties set there
// we also need it to be public so that it can be referenced
// from sun.net.www.protocol.http.HttpURLConnection
// this is for ResponseCache.put(URI, URLConnection)
// second parameter needs to be cast to javax.net.ssl.HttpsURLConnection
// instead of AbstractDelegateHttpsURLConnection
public javax.net.ssl.HttpsURLConnection httpsURLConnection;
DelegateHttpsURLConnection(URL url,
sun.net.www.protocol.http.Handler handler,
javax.net.ssl.HttpsURLConnection httpsURLConnection)
throws IOException {
this(url, null, handler, httpsURLConnection);
}
DelegateHttpsURLConnection(URL url, Proxy p,
sun.net.www.protocol.http.Handler handler,
javax.net.ssl.HttpsURLConnection httpsURLConnection)
throws IOException {
super(url, p, handler);
this.httpsURLConnection = httpsURLConnection;
}
protected javax.net.ssl.SSLSocketFactory getSSLSocketFactory() {
return httpsURLConnection.getSSLSocketFactory();
}
protected javax.net.ssl.HostnameVerifier getHostnameVerifier() {
return httpsURLConnection.getHostnameVerifier();
}
/*
* Called by layered delegator's finalize() method to handle closing
* the underlying object.
*/
@SuppressWarnings("deprecation")
protected void dispose() throws Throwable {
super.finalize();
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2001, 2003, 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.
*/
/*-
* HTTP stream opener
*/
package sun.net.www.protocol.https;
import java.io.IOException;
import java.net.URL;
import java.net.Proxy;
/** open an http input stream given a URL */
public class Handler extends sun.net.www.protocol.http.Handler {
protected String proxy;
protected int proxyPort;
protected int getDefaultPort() {
return 443;
}
public Handler () {
proxy = null;
proxyPort = -1;
}
public Handler (String proxy, int port) {
this.proxy = proxy;
this.proxyPort = port;
}
protected java.net.URLConnection openConnection(URL u)
throws IOException {
return openConnection(u, (Proxy)null);
}
protected java.net.URLConnection openConnection(URL u, Proxy p)
throws IOException {
return new HttpsURLConnectionImpl(u, p, this);
}
}

View file

@ -0,0 +1,786 @@
/*
* Copyright (c) 2001, 2016, 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.protocol.https;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.PrintStream;
import java.io.BufferedOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.security.Principal;
import java.security.cert.*;
import java.util.Objects;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.security.auth.x500.X500Principal;
import javax.net.ssl.*;
import sun.net.www.http.HttpClient;
import sun.net.www.protocol.http.AuthenticatorKeys;
import sun.net.www.protocol.http.HttpURLConnection;
import sun.security.action.*;
import sun.security.util.HostnameChecker;
import sun.security.ssl.SSLSocketImpl;
import sun.util.logging.PlatformLogger;
import static sun.net.www.protocol.http.HttpURLConnection.TunnelState.*;
/**
* This class provides HTTPS client URL support, building on the standard
* "sun.net.www" HTTP protocol handler. HTTPS is the same protocol as HTTP,
* but differs in the transport layer which it uses: <UL>
*
* <LI>There's a <em>Secure Sockets Layer</em> between TCP
* and the HTTP protocol code.
*
* <LI>It uses a different default TCP port.
*
* <LI>It doesn't use application level proxies, which can see and
* manipulate HTTP user level data, compromising privacy. It uses
* low level tunneling instead, which hides HTTP protocol and data
* from all third parties. (Traffic analysis is still possible).
*
* <LI>It does basic server authentication, to protect
* against "URL spoofing" attacks. This involves deciding
* whether the X.509 certificate chain identifying the server
* is trusted, and verifying that the name of the server is
* found in the certificate. (The application may enable an
* anonymous SSL cipher suite, and such checks are not done
* for anonymous ciphers.)
*
* <LI>It exposes key SSL session attributes, specifically the
* cipher suite in use and the server's X509 certificates, to
* application software which knows about this protocol handler.
*
* </UL>
*
* <P> System properties used include: <UL>
*
* <LI><em>https.proxyHost</em> ... the host supporting SSL
* tunneling using the conventional CONNECT syntax
*
* <LI><em>https.proxyPort</em> ... port to use on proxyHost
*
* <LI><em>https.cipherSuites</em> ... comma separated list of
* SSL cipher suite names to enable.
*
* <LI><em>http.nonProxyHosts</em> ...
*
* </UL>
*
* @author David Brownell
* @author Bill Foote
*/
// final for export control reasons (access to APIs); remove with care
final class HttpsClient extends HttpClient
implements HandshakeCompletedListener
{
// STATIC STATE and ACCESSORS THERETO
// HTTPS uses a different default port number than HTTP.
private static final int httpsPortNumber = 443;
// default HostnameVerifier class canonical name
private static final String defaultHVCanonicalName =
"javax.net.ssl.HttpsURLConnection.DefaultHostnameVerifier";
/** Returns the default HTTPS port (443) */
@Override
protected int getDefaultPort() { return httpsPortNumber; }
private HostnameVerifier hv;
private SSLSocketFactory sslSocketFactory;
// HttpClient.proxyDisabled will always be false, because we don't
// use an application-level HTTP proxy. We might tunnel through
// our http proxy, though.
// INSTANCE DATA
// last negotiated SSL session
private SSLSession session;
private String [] getCipherSuites() {
//
// If ciphers are assigned, sort them into an array.
//
String ciphers [];
String cipherString =
GetPropertyAction.privilegedGetProperty("https.cipherSuites");
if (cipherString == null || "".equals(cipherString)) {
ciphers = null;
} else {
StringTokenizer tokenizer;
Vector<String> v = new Vector<String>();
tokenizer = new StringTokenizer(cipherString, ",");
while (tokenizer.hasMoreTokens())
v.addElement(tokenizer.nextToken());
ciphers = new String [v.size()];
for (int i = 0; i < ciphers.length; i++)
ciphers [i] = v.elementAt(i);
}
return ciphers;
}
private String [] getProtocols() {
//
// If protocols are assigned, sort them into an array.
//
String protocols [];
String protocolString =
GetPropertyAction.privilegedGetProperty("https.protocols");
if (protocolString == null || "".equals(protocolString)) {
protocols = null;
} else {
StringTokenizer tokenizer;
Vector<String> v = new Vector<String>();
tokenizer = new StringTokenizer(protocolString, ",");
while (tokenizer.hasMoreTokens())
v.addElement(tokenizer.nextToken());
protocols = new String [v.size()];
for (int i = 0; i < protocols.length; i++) {
protocols [i] = v.elementAt(i);
}
}
return protocols;
}
private String getUserAgent() {
String userAgent =
GetPropertyAction.privilegedGetProperty("https.agent");
if (userAgent == null || userAgent.length() == 0) {
userAgent = "JSSE";
}
return userAgent;
}
// CONSTRUCTOR, FACTORY
/**
* Create an HTTPS client URL. Traffic will be tunneled through any
* intermediate nodes rather than proxied, so that confidentiality
* of data exchanged can be preserved. However, note that all the
* anonymous SSL flavors are subject to "person-in-the-middle"
* attacks against confidentiality. If you enable use of those
* flavors, you may be giving up the protection you get through
* SSL tunneling.
*
* Use New to get new HttpsClient. This constructor is meant to be
* used only by New method. New properly checks for URL spoofing.
*
* @param URL https URL with which a connection must be established
*/
private HttpsClient(SSLSocketFactory sf, URL url)
throws IOException
{
// HttpClient-level proxying is always disabled,
// because we override doConnect to do tunneling instead.
this(sf, url, (String)null, -1);
}
/**
* Create an HTTPS client URL. Traffic will be tunneled through
* the specified proxy server.
*/
HttpsClient(SSLSocketFactory sf, URL url, String proxyHost, int proxyPort)
throws IOException {
this(sf, url, proxyHost, proxyPort, -1);
}
/**
* Create an HTTPS client URL. Traffic will be tunneled through
* the specified proxy server, with a connect timeout
*/
HttpsClient(SSLSocketFactory sf, URL url, String proxyHost, int proxyPort,
int connectTimeout)
throws IOException {
this(sf, url,
(proxyHost == null? null:
HttpClient.newHttpProxy(proxyHost, proxyPort, "https")),
connectTimeout);
}
/**
* Same as previous constructor except using a Proxy
*/
HttpsClient(SSLSocketFactory sf, URL url, Proxy proxy,
int connectTimeout)
throws IOException {
PlatformLogger logger = HttpURLConnection.getHttpLogger();
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
logger.finest("Creating new HttpsClient with url:" + url + " and proxy:" + proxy +
" with connect timeout:" + connectTimeout);
}
this.proxy = proxy;
setSSLSocketFactory(sf);
this.proxyDisabled = true;
this.host = url.getHost();
this.url = url;
port = url.getPort();
if (port == -1) {
port = getDefaultPort();
}
setConnectTimeout(connectTimeout);
openServer();
}
// This code largely ripped off from HttpClient.New, and
// it uses the same keepalive cache.
static HttpClient New(SSLSocketFactory sf, URL url, HostnameVerifier hv,
HttpURLConnection httpuc)
throws IOException {
return HttpsClient.New(sf, url, hv, true, httpuc);
}
/** See HttpClient for the model for this method. */
static HttpClient New(SSLSocketFactory sf, URL url,
HostnameVerifier hv, boolean useCache,
HttpURLConnection httpuc) throws IOException {
return HttpsClient.New(sf, url, hv, (String)null, -1, useCache, httpuc);
}
/**
* Get a HTTPS client to the URL. Traffic will be tunneled through
* the specified proxy server.
*/
static HttpClient New(SSLSocketFactory sf, URL url, HostnameVerifier hv,
String proxyHost, int proxyPort,
HttpURLConnection httpuc) throws IOException {
return HttpsClient.New(sf, url, hv, proxyHost, proxyPort, true, httpuc);
}
static HttpClient New(SSLSocketFactory sf, URL url, HostnameVerifier hv,
String proxyHost, int proxyPort, boolean useCache,
HttpURLConnection httpuc)
throws IOException {
return HttpsClient.New(sf, url, hv, proxyHost, proxyPort, useCache, -1,
httpuc);
}
static HttpClient New(SSLSocketFactory sf, URL url, HostnameVerifier hv,
String proxyHost, int proxyPort, boolean useCache,
int connectTimeout, HttpURLConnection httpuc)
throws IOException {
return HttpsClient.New(sf, url, hv,
(proxyHost == null? null :
HttpClient.newHttpProxy(proxyHost, proxyPort, "https")),
useCache, connectTimeout, httpuc);
}
static HttpClient New(SSLSocketFactory sf, URL url, HostnameVerifier hv,
Proxy p, boolean useCache,
int connectTimeout, HttpURLConnection httpuc)
throws IOException
{
if (p == null) {
p = Proxy.NO_PROXY;
}
PlatformLogger logger = HttpURLConnection.getHttpLogger();
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
logger.finest("Looking for HttpClient for URL " + url +
" and proxy value of " + p);
}
HttpsClient ret = null;
if (useCache) {
/* see if one's already around */
ret = (HttpsClient) kac.get(url, sf);
if (ret != null && httpuc != null &&
httpuc.streaming() &&
httpuc.getRequestMethod() == "POST") {
if (!ret.available())
ret = null;
}
if (ret != null) {
String ak = httpuc == null ? AuthenticatorKeys.DEFAULT
: httpuc.getAuthenticatorKey();
boolean compatible = ((ret.proxy != null && ret.proxy.equals(p)) ||
(ret.proxy == null && p == Proxy.NO_PROXY))
&& Objects.equals(ret.getAuthenticatorKey(), ak);
if (compatible) {
synchronized (ret) {
ret.cachedHttpClient = true;
assert ret.inCache;
ret.inCache = false;
if (httpuc != null && ret.needsTunneling())
httpuc.setTunnelState(TUNNELING);
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
logger.finest("KeepAlive stream retrieved from the cache, " + ret);
}
}
} else {
// We cannot return this connection to the cache as it's
// KeepAliveTimeout will get reset. We simply close the connection.
// This should be fine as it is very rare that a connection
// to the same host will not use the same proxy.
synchronized(ret) {
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
logger.finest("Not returning this connection to cache: " + ret);
}
ret.inCache = false;
ret.closeServer();
}
ret = null;
}
}
}
if (ret == null) {
ret = new HttpsClient(sf, url, p, connectTimeout);
if (httpuc != null) {
ret.authenticatorKey = httpuc.getAuthenticatorKey();
}
} else {
SecurityManager security = System.getSecurityManager();
if (security != null) {
if (ret.proxy == Proxy.NO_PROXY || ret.proxy == null) {
security.checkConnect(InetAddress.getByName(url.getHost()).getHostAddress(), url.getPort());
} else {
security.checkConnect(url.getHost(), url.getPort());
}
}
ret.url = url;
}
ret.setHostnameVerifier(hv);
return ret;
}
// METHODS
void setHostnameVerifier(HostnameVerifier hv) {
this.hv = hv;
}
void setSSLSocketFactory(SSLSocketFactory sf) {
sslSocketFactory = sf;
}
SSLSocketFactory getSSLSocketFactory() {
return sslSocketFactory;
}
/**
* The following method, createSocket, is defined in NetworkClient
* and overridden here so that the socket facroty is used to create
* new sockets.
*/
@Override
protected Socket createSocket() throws IOException {
try {
return sslSocketFactory.createSocket();
} catch (SocketException se) {
//
// bug 6771432
// javax.net.SocketFactory throws a SocketException with an
// UnsupportedOperationException as its cause to indicate that
// unconnected sockets have not been implemented.
//
Throwable t = se.getCause();
if (t != null && t instanceof UnsupportedOperationException) {
return super.createSocket();
} else {
throw se;
}
}
}
@Override
public boolean needsTunneling() {
return (proxy != null && proxy.type() != Proxy.Type.DIRECT
&& proxy.type() != Proxy.Type.SOCKS);
}
@Override
public void afterConnect() throws IOException, UnknownHostException {
if (!isCachedConnection()) {
SSLSocket s = null;
SSLSocketFactory factory = sslSocketFactory;
try {
if (!(serverSocket instanceof SSLSocket)) {
s = (SSLSocket)factory.createSocket(serverSocket,
host, port, true);
} else {
s = (SSLSocket)serverSocket;
if (s instanceof SSLSocketImpl) {
((SSLSocketImpl)s).setHost(host);
}
}
} catch (IOException ex) {
// If we fail to connect through the tunnel, try it
// locally, as a last resort. If this doesn't work,
// throw the original exception.
try {
s = (SSLSocket)factory.createSocket(host, port);
} catch (IOException ignored) {
throw ex;
}
}
//
// Force handshaking, so that we get any authentication.
// Register a handshake callback so our session state tracks any
// later session renegotiations.
//
String [] protocols = getProtocols();
String [] ciphers = getCipherSuites();
if (protocols != null) {
s.setEnabledProtocols(protocols);
}
if (ciphers != null) {
s.setEnabledCipherSuites(ciphers);
}
s.addHandshakeCompletedListener(this);
// We have two hostname verification approaches. One is in
// SSL/TLS socket layer, where the algorithm is configured with
// SSLParameters.setEndpointIdentificationAlgorithm(), and the
// hostname verification is done by X509ExtendedTrustManager when
// the algorithm is "HTTPS". The other one is in HTTPS layer,
// where the algorithm is customized by
// HttpsURLConnection.setHostnameVerifier(), and the hostname
// verification is done by HostnameVerifier when the default
// rules for hostname verification fail.
//
// The relationship between two hostname verification approaches
// likes the following:
//
// | EIA algorithm
// +----------------------------------------------
// | null | HTTPS | LDAP/other |
// -------------------------------------------------------------
// | |1 |2 |3 |
// HNV | default | Set HTTPS EIA | use EIA | HTTPS |
// |--------------------------------------------------------
// | non - |4 |5 |6 |
// | default | HTTPS/HNV | use EIA | HTTPS/HNV |
// -------------------------------------------------------------
//
// Abbreviation:
// EIA: the endpoint identification algorithm in SSL/TLS
// socket layer
// HNV: the hostname verification object in HTTPS layer
// Notes:
// case 1. default HNV and EIA is null
// Set EIA as HTTPS, hostname check done in SSL/TLS
// layer.
// case 2. default HNV and EIA is HTTPS
// Use existing EIA, hostname check done in SSL/TLS
// layer.
// case 3. default HNV and EIA is other than HTTPS
// Use existing EIA, EIA check done in SSL/TLS
// layer, then do HTTPS check in HTTPS layer.
// case 4. non-default HNV and EIA is null
// No EIA, no EIA check done in SSL/TLS layer, then do
// HTTPS check in HTTPS layer using HNV as override.
// case 5. non-default HNV and EIA is HTTPS
// Use existing EIA, hostname check done in SSL/TLS
// layer. No HNV override possible. We will review this
// decision and may update the architecture for JDK 7.
// case 6. non-default HNV and EIA is other than HTTPS
// Use existing EIA, EIA check done in SSL/TLS layer,
// then do HTTPS check in HTTPS layer as override.
boolean needToCheckSpoofing = true;
String identification =
s.getSSLParameters().getEndpointIdentificationAlgorithm();
if (identification != null && identification.length() != 0) {
if (identification.equalsIgnoreCase("HTTPS")) {
// Do not check server identity again out of SSLSocket,
// the endpoint will be identified during TLS handshaking
// in SSLSocket.
needToCheckSpoofing = false;
} // else, we don't understand the identification algorithm,
// need to check URL spoofing here.
} else {
boolean isDefaultHostnameVerifier = false;
// We prefer to let the SSLSocket do the spoof checks, but if
// the application has specified a HostnameVerifier (HNV),
// we will always use that.
if (hv != null) {
String canonicalName = hv.getClass().getCanonicalName();
if (canonicalName != null &&
canonicalName.equalsIgnoreCase(defaultHVCanonicalName)) {
isDefaultHostnameVerifier = true;
}
} else {
// Unlikely to happen! As the behavior is the same as the
// default hostname verifier, so we prefer to let the
// SSLSocket do the spoof checks.
isDefaultHostnameVerifier = true;
}
if (isDefaultHostnameVerifier) {
// If the HNV is the default from HttpsURLConnection, we
// will do the spoof checks in SSLSocket.
SSLParameters paramaters = s.getSSLParameters();
paramaters.setEndpointIdentificationAlgorithm("HTTPS");
s.setSSLParameters(paramaters);
needToCheckSpoofing = false;
}
}
s.startHandshake();
session = s.getSession();
// change the serverSocket and serverOutput
serverSocket = s;
try {
serverOutput = new PrintStream(
new BufferedOutputStream(serverSocket.getOutputStream()),
false, encoding);
} catch (UnsupportedEncodingException e) {
throw new InternalError(encoding+" encoding not found");
}
// check URL spoofing if it has not been checked under handshaking
if (needToCheckSpoofing) {
checkURLSpoofing(hv);
}
} else {
// if we are reusing a cached https session,
// we don't need to do handshaking etc. But we do need to
// set the ssl session
session = ((SSLSocket)serverSocket).getSession();
}
}
// Server identity checking is done according to RFC 2818: HTTP over TLS
// Section 3.1 Server Identity
private void checkURLSpoofing(HostnameVerifier hostnameVerifier)
throws IOException {
//
// Get authenticated server name, if any
//
String host = url.getHost();
// if IPv6 strip off the "[]"
if (host != null && host.startsWith("[") && host.endsWith("]")) {
host = host.substring(1, host.length()-1);
}
Certificate[] peerCerts = null;
String cipher = session.getCipherSuite();
try {
HostnameChecker checker = HostnameChecker.getInstance(
HostnameChecker.TYPE_TLS);
// Use ciphersuite to determine whether Kerberos is present.
if (cipher.startsWith("TLS_KRB5")) {
if (!HostnameChecker.match(host, getPeerPrincipal())) {
throw new SSLPeerUnverifiedException("Hostname checker" +
" failed for Kerberos");
}
} else { // X.509
// get the subject's certificate
peerCerts = session.getPeerCertificates();
X509Certificate peerCert;
if (peerCerts[0] instanceof
java.security.cert.X509Certificate) {
peerCert = (java.security.cert.X509Certificate)peerCerts[0];
} else {
throw new SSLPeerUnverifiedException("");
}
checker.match(host, peerCert);
}
// if it doesn't throw an exception, we passed. Return.
return;
} catch (SSLPeerUnverifiedException e) {
//
// client explicitly changed default policy and enabled
// anonymous ciphers; we can't check the standard policy
//
// ignore
} catch (java.security.cert.CertificateException cpe) {
// ignore
}
if ((cipher != null) && (cipher.indexOf("_anon_") != -1)) {
return;
} else if ((hostnameVerifier != null) &&
(hostnameVerifier.verify(host, session))) {
return;
}
serverSocket.close();
session.invalidate();
throw new IOException("HTTPS hostname wrong: should be <"
+ url.getHost() + ">");
}
@Override
protected void putInKeepAliveCache() {
if (inCache) {
assert false : "Duplicate put to keep alive cache";
return;
}
inCache = true;
kac.put(url, sslSocketFactory, this);
}
/*
* Close an idle connection to this URL (if it exists in the cache).
*/
@Override
public void closeIdleConnection() {
HttpClient http = kac.get(url, sslSocketFactory);
if (http != null) {
http.closeServer();
}
}
/**
* Returns the cipher suite in use on this connection.
*/
String getCipherSuite() {
return session.getCipherSuite();
}
/**
* Returns the certificate chain the client sent to the
* server, or null if the client did not authenticate.
*/
public java.security.cert.Certificate [] getLocalCertificates() {
return session.getLocalCertificates();
}
/**
* Returns the certificate chain with which the server
* authenticated itself, or throw a SSLPeerUnverifiedException
* if the server did not authenticate.
*/
java.security.cert.Certificate [] getServerCertificates()
throws SSLPeerUnverifiedException
{
return session.getPeerCertificates();
}
/**
* Returns the principal with which the server authenticated
* itself, or throw a SSLPeerUnverifiedException if the
* server did not authenticate.
*/
Principal getPeerPrincipal()
throws SSLPeerUnverifiedException
{
Principal principal;
try {
principal = session.getPeerPrincipal();
} catch (AbstractMethodError e) {
// if the provider does not support it, fallback to peer certs.
// return the X500Principal of the end-entity cert.
java.security.cert.Certificate[] certs =
session.getPeerCertificates();
principal = ((X509Certificate)certs[0]).getSubjectX500Principal();
}
return principal;
}
/**
* Returns the principal the client sent to the
* server, or null if the client did not authenticate.
*/
Principal getLocalPrincipal()
{
Principal principal;
try {
principal = session.getLocalPrincipal();
} catch (AbstractMethodError e) {
principal = null;
// if the provider does not support it, fallback to local certs.
// return the X500Principal of the end-entity cert.
java.security.cert.Certificate[] certs =
session.getLocalCertificates();
if (certs != null) {
principal = ((X509Certificate)certs[0]).getSubjectX500Principal();
}
}
return principal;
}
/**
* This method implements the SSL HandshakeCompleted callback,
* remembering the resulting session so that it may be queried
* for the current cipher suite and peer certificates. Servers
* sometimes re-initiate handshaking, so the session in use on
* a given connection may change. When sessions change, so may
* peer identities and cipher suites.
*/
public void handshakeCompleted(HandshakeCompletedEvent event)
{
session = event.getSession();
}
/**
* @return the proxy host being used for this client, or null
* if we're not going through a proxy
*/
@Override
public String getProxyHostUsed() {
if (!needsTunneling()) {
return null;
} else {
return super.getProxyHostUsed();
}
}
/**
* @return the proxy port being used for this client. Meaningless
* if getProxyHostUsed() gives null.
*/
@Override
public int getProxyPortUsed() {
return (proxy == null || proxy.type() == Proxy.Type.DIRECT ||
proxy.type() == Proxy.Type.SOCKS)? -1:
((InetSocketAddress)proxy.address()).getPort();
}
}

View file

@ -0,0 +1,527 @@
/*
* Copyright (c) 2001, 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.
*/
/*
* NOTE: This class lives in the package sun.net.www.protocol.https.
* There is a copy in com.sun.net.ssl.internal.www.protocol.https for JSSE
* 1.0.2 compatibility. It is 100% identical except the package and extends
* lines. Any changes should be made to be class in sun.net.* and then copied
* to com.sun.net.*.
*/
// For both copies of the file, uncomment one line and comment the other
package sun.net.www.protocol.https;
// package com.sun.net.ssl.internal.www.protocol.https;
import java.net.URL;
import java.net.Proxy;
import java.net.ProtocolException;
import java.io.*;
import java.net.Authenticator;
import javax.net.ssl.*;
import java.security.Permission;
import java.security.Principal;
import java.util.Map;
import java.util.List;
import sun.net.www.http.HttpClient;
/**
* A class to represent an HTTP connection to a remote object.
*
* Ideally, this class should subclass and inherit the http handler
* implementation, but it can't do so because that class have the
* wrong Java Type. Thus it uses the delegate (aka, the
* Adapter/Wrapper design pattern) to reuse code from the http
* handler.
*
* Since it would use a delegate to access
* sun.net.www.protocol.http.HttpURLConnection functionalities, it
* needs to implement all public methods in it's super class and all
* the way to Object.
*
*/
// For both copies of the file, uncomment one line and comment the
// other. The differences between the two copies are introduced for
// plugin, and it is marked as such.
public class HttpsURLConnectionImpl
extends javax.net.ssl.HttpsURLConnection {
// public class HttpsURLConnectionOldImpl
// extends com.sun.net.ssl.HttpsURLConnection {
// NOTE: made protected for plugin so that subclass can set it.
protected DelegateHttpsURLConnection delegate;
// For both copies of the file, uncomment one line and comment the other
HttpsURLConnectionImpl(URL u, Handler handler) throws IOException {
// HttpsURLConnectionOldImpl(URL u, Handler handler) throws IOException {
this(u, null, handler);
}
// For both copies of the file, uncomment one line and comment the other
HttpsURLConnectionImpl(URL u, Proxy p, Handler handler) throws IOException {
// HttpsURLConnectionOldImpl(URL u, Proxy p, Handler handler) throws IOException {
super(u);
delegate = new DelegateHttpsURLConnection(url, p, handler, this);
}
// NOTE: introduced for plugin
// subclass needs to overwrite this to set delegate to
// the appropriate delegatee
protected HttpsURLConnectionImpl(URL u) throws IOException {
super(u);
}
/**
* Create a new HttpClient object, bypassing the cache of
* HTTP client objects/connections.
*
* @param url the URL being accessed
*/
protected void setNewClient(URL url) throws IOException {
delegate.setNewClient(url, false);
}
/**
* Obtain a HttpClient object. Use the cached copy if specified.
*
* @param url the URL being accessed
* @param useCache whether the cached connection should be used
* if present
*/
protected void setNewClient(URL url, boolean useCache)
throws IOException {
delegate.setNewClient(url, useCache);
}
/**
* Create a new HttpClient object, set up so that it uses
* per-instance proxying to the given HTTP proxy. This
* bypasses the cache of HTTP client objects/connections.
*
* @param url the URL being accessed
* @param proxyHost the proxy host to use
* @param proxyPort the proxy port to use
*/
protected void setProxiedClient(URL url, String proxyHost, int proxyPort)
throws IOException {
delegate.setProxiedClient(url, proxyHost, proxyPort);
}
/**
* Obtain a HttpClient object, set up so that it uses per-instance
* proxying to the given HTTP proxy. Use the cached copy of HTTP
* client objects/connections if specified.
*
* @param url the URL being accessed
* @param proxyHost the proxy host to use
* @param proxyPort the proxy port to use
* @param useCache whether the cached connection should be used
* if present
*/
protected void setProxiedClient(URL url, String proxyHost, int proxyPort,
boolean useCache) throws IOException {
delegate.setProxiedClient(url, proxyHost, proxyPort, useCache);
}
/**
* Implements the HTTP protocol handler's "connect" method,
* establishing an SSL connection to the server as necessary.
*/
public void connect() throws IOException {
delegate.connect();
}
/**
* Used by subclass to access "connected" variable. Since we are
* delegating the actual implementation to "delegate", we need to
* delegate the access of "connected" as well.
*/
protected boolean isConnected() {
return delegate.isConnected();
}
/**
* Used by subclass to access "connected" variable. Since we are
* delegating the actual implementation to "delegate", we need to
* delegate the access of "connected" as well.
*/
protected void setConnected(boolean conn) {
delegate.setConnected(conn);
}
/**
* Returns the cipher suite in use on this connection.
*/
public String getCipherSuite() {
return delegate.getCipherSuite();
}
/**
* Returns the certificate chain the client sent to the
* server, or null if the client did not authenticate.
*/
public java.security.cert.Certificate []
getLocalCertificates() {
return delegate.getLocalCertificates();
}
/**
* Returns the server's certificate chain, or throws
* SSLPeerUnverified Exception if
* the server did not authenticate.
*/
public java.security.cert.Certificate []
getServerCertificates() throws SSLPeerUnverifiedException {
return delegate.getServerCertificates();
}
/**
* Returns the principal with which the server authenticated itself,
* or throw a SSLPeerUnverifiedException if the server did not authenticate.
*/
public Principal getPeerPrincipal()
throws SSLPeerUnverifiedException
{
return delegate.getPeerPrincipal();
}
/**
* Returns the principal the client sent to the
* server, or null if the client did not authenticate.
*/
public Principal getLocalPrincipal()
{
return delegate.getLocalPrincipal();
}
/*
* Allowable input/output sequences:
* [interpreted as POST/PUT]
* - get output, [write output,] get input, [read input]
* - get output, [write output]
* [interpreted as GET]
* - get input, [read input]
* Disallowed:
* - get input, [read input,] get output, [write output]
*/
public synchronized OutputStream getOutputStream() throws IOException {
return delegate.getOutputStream();
}
public synchronized InputStream getInputStream() throws IOException {
return delegate.getInputStream();
}
public InputStream getErrorStream() {
return delegate.getErrorStream();
}
/**
* Disconnect from the server.
*/
public void disconnect() {
delegate.disconnect();
}
public boolean usingProxy() {
return delegate.usingProxy();
}
/**
* Returns an unmodifiable Map of the header fields.
* The Map keys are Strings that represent the
* response-header field names. Each Map value is an
* unmodifiable List of Strings that represents
* the corresponding field values.
*
* @return a Map of header fields
* @since 1.4
*/
public Map<String,List<String>> getHeaderFields() {
return delegate.getHeaderFields();
}
/**
* Gets a header field by name. Returns null if not known.
* @param name the name of the header field
*/
public String getHeaderField(String name) {
return delegate.getHeaderField(name);
}
/**
* Gets a header field by index. Returns null if not known.
* @param n the index of the header field
*/
public String getHeaderField(int n) {
return delegate.getHeaderField(n);
}
/**
* Gets a header field by index. Returns null if not known.
* @param n the index of the header field
*/
public String getHeaderFieldKey(int n) {
return delegate.getHeaderFieldKey(n);
}
/**
* Sets request property. If a property with the key already
* exists, overwrite its value with the new value.
* @param value the value to be set
*/
public void setRequestProperty(String key, String value) {
delegate.setRequestProperty(key, value);
}
/**
* Adds a general request property specified by a
* key-value pair. This method will not overwrite
* existing values associated with the same key.
*
* @param key the keyword by which the request is known
* (e.g., "<code>accept</code>").
* @param value the value associated with it.
* @see #getRequestProperties(java.lang.String)
* @since 1.4
*/
public void addRequestProperty(String key, String value) {
delegate.addRequestProperty(key, value);
}
/**
* Overwrite super class method
*/
public int getResponseCode() throws IOException {
return delegate.getResponseCode();
}
public String getRequestProperty(String key) {
return delegate.getRequestProperty(key);
}
/**
* Returns an unmodifiable Map of general request
* properties for this connection. The Map keys
* are Strings that represent the request-header
* field names. Each Map value is a unmodifiable List
* of Strings that represents the corresponding
* field values.
*
* @return a Map of the general request properties for this connection.
* @throws IllegalStateException if already connected
* @since 1.4
*/
public Map<String,List<String>> getRequestProperties() {
return delegate.getRequestProperties();
}
/*
* We support JDK 1.2.x so we can't count on these from JDK 1.3.
* We override and supply our own version.
*/
public void setInstanceFollowRedirects(boolean shouldFollow) {
delegate.setInstanceFollowRedirects(shouldFollow);
}
public boolean getInstanceFollowRedirects() {
return delegate.getInstanceFollowRedirects();
}
public void setRequestMethod(String method) throws ProtocolException {
delegate.setRequestMethod(method);
}
public String getRequestMethod() {
return delegate.getRequestMethod();
}
public String getResponseMessage() throws IOException {
return delegate.getResponseMessage();
}
public long getHeaderFieldDate(String name, long Default) {
return delegate.getHeaderFieldDate(name, Default);
}
public Permission getPermission() throws IOException {
return delegate.getPermission();
}
public URL getURL() {
return delegate.getURL();
}
public int getContentLength() {
return delegate.getContentLength();
}
public long getContentLengthLong() {
return delegate.getContentLengthLong();
}
public String getContentType() {
return delegate.getContentType();
}
public String getContentEncoding() {
return delegate.getContentEncoding();
}
public long getExpiration() {
return delegate.getExpiration();
}
public long getDate() {
return delegate.getDate();
}
public long getLastModified() {
return delegate.getLastModified();
}
public int getHeaderFieldInt(String name, int Default) {
return delegate.getHeaderFieldInt(name, Default);
}
public long getHeaderFieldLong(String name, long Default) {
return delegate.getHeaderFieldLong(name, Default);
}
public Object getContent() throws IOException {
return delegate.getContent();
}
@SuppressWarnings("rawtypes")
public Object getContent(Class[] classes) throws IOException {
return delegate.getContent(classes);
}
public String toString() {
return delegate.toString();
}
public void setDoInput(boolean doinput) {
delegate.setDoInput(doinput);
}
public boolean getDoInput() {
return delegate.getDoInput();
}
public void setDoOutput(boolean dooutput) {
delegate.setDoOutput(dooutput);
}
public boolean getDoOutput() {
return delegate.getDoOutput();
}
public void setAllowUserInteraction(boolean allowuserinteraction) {
delegate.setAllowUserInteraction(allowuserinteraction);
}
public boolean getAllowUserInteraction() {
return delegate.getAllowUserInteraction();
}
public void setUseCaches(boolean usecaches) {
delegate.setUseCaches(usecaches);
}
public boolean getUseCaches() {
return delegate.getUseCaches();
}
public void setIfModifiedSince(long ifmodifiedsince) {
delegate.setIfModifiedSince(ifmodifiedsince);
}
public long getIfModifiedSince() {
return delegate.getIfModifiedSince();
}
public boolean getDefaultUseCaches() {
return delegate.getDefaultUseCaches();
}
public void setDefaultUseCaches(boolean defaultusecaches) {
delegate.setDefaultUseCaches(defaultusecaches);
}
/*
* finalize (dispose) the delegated object. Otherwise
* sun.net.www.protocol.http.HttpURLConnection's finalize()
* would have to be made public.
*/
@SuppressWarnings("deprecation")
protected void finalize() throws Throwable {
delegate.dispose();
}
public boolean equals(Object obj) {
return this == obj || ((obj instanceof HttpsURLConnectionImpl) &&
delegate.equals(((HttpsURLConnectionImpl)obj).delegate));
}
public int hashCode() {
return delegate.hashCode();
}
public void setConnectTimeout(int timeout) {
delegate.setConnectTimeout(timeout);
}
public int getConnectTimeout() {
return delegate.getConnectTimeout();
}
public void setReadTimeout(int timeout) {
delegate.setReadTimeout(timeout);
}
public int getReadTimeout() {
return delegate.getReadTimeout();
}
public void setFixedLengthStreamingMode (int contentLength) {
delegate.setFixedLengthStreamingMode(contentLength);
}
public void setFixedLengthStreamingMode(long contentLength) {
delegate.setFixedLengthStreamingMode(contentLength);
}
public void setChunkedStreamingMode (int chunklen) {
delegate.setChunkedStreamingMode(chunklen);
}
@Override
public void setAuthenticator(Authenticator auth) {
delegate.setAuthenticator(auth);
}
}

View file

@ -0,0 +1,209 @@
/*
* Copyright (c) 1997, 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.protocol.jar;
import java.io.IOException;
import java.net.*;
import sun.net.www.ParseUtil;
/*
* Jar URL Handler
*/
public class Handler extends java.net.URLStreamHandler {
private static final String separator = "!/";
protected java.net.URLConnection openConnection(URL u)
throws IOException {
return new JarURLConnection(u, this);
}
private static int indexOfBangSlash(String spec) {
int indexOfBang = spec.length();
while((indexOfBang = spec.lastIndexOf('!', indexOfBang)) != -1) {
if ((indexOfBang != (spec.length() - 1)) &&
(spec.charAt(indexOfBang + 1) == '/')) {
return indexOfBang + 1;
} else {
indexOfBang--;
}
}
return -1;
}
/**
* Compare two jar URLs
*/
@Override
protected boolean sameFile(URL u1, URL u2) {
if (!u1.getProtocol().equals("jar") || !u2.getProtocol().equals("jar"))
return false;
String file1 = u1.getFile();
String file2 = u2.getFile();
int sep1 = file1.indexOf(separator);
int sep2 = file2.indexOf(separator);
if (sep1 == -1 || sep2 == -1) {
return super.sameFile(u1, u2);
}
String entry1 = file1.substring(sep1 + 2);
String entry2 = file2.substring(sep2 + 2);
if (!entry1.equals(entry2))
return false;
URL enclosedURL1 = null, enclosedURL2 = null;
try {
enclosedURL1 = new URL(file1.substring(0, sep1));
enclosedURL2 = new URL(file2.substring(0, sep2));
} catch (MalformedURLException unused) {
return super.sameFile(u1, u2);
}
if (!super.sameFile(enclosedURL1, enclosedURL2)) {
return false;
}
return true;
}
@Override
protected int hashCode(URL u) {
int h = 0;
String protocol = u.getProtocol();
if (protocol != null)
h += protocol.hashCode();
String file = u.getFile();
int sep = file.indexOf(separator);
if (sep == -1)
return h + file.hashCode();
URL enclosedURL = null;
String fileWithoutEntry = file.substring(0, sep);
try {
enclosedURL = new URL(fileWithoutEntry);
h += enclosedURL.hashCode();
} catch (MalformedURLException unused) {
h += fileWithoutEntry.hashCode();
}
String entry = file.substring(sep + 2);
h += entry.hashCode();
return h;
}
@Override
@SuppressWarnings("deprecation")
protected void parseURL(URL url, String spec,
int start, int limit) {
String file = null;
String ref = null;
// first figure out if there is an anchor
int refPos = spec.indexOf('#', limit);
boolean refOnly = refPos == start;
if (refPos > -1) {
ref = spec.substring(refPos + 1, spec.length());
if (refOnly) {
file = url.getFile();
}
}
// then figure out if the spec is
// 1. absolute (jar:)
// 2. relative (i.e. url + foo/bar/baz.ext)
// 3. anchor-only (i.e. url + #foo), which we already did (refOnly)
boolean absoluteSpec = false;
if (spec.length() >= 4) {
absoluteSpec = spec.substring(0, 4).equalsIgnoreCase("jar:");
}
spec = spec.substring(start, limit);
if (absoluteSpec) {
file = parseAbsoluteSpec(spec);
} else if (!refOnly) {
file = parseContextSpec(url, spec);
// Canonize the result after the bangslash
int bangSlash = indexOfBangSlash(file);
String toBangSlash = file.substring(0, bangSlash);
String afterBangSlash = file.substring(bangSlash);
sun.net.www.ParseUtil canonizer = new ParseUtil();
afterBangSlash = canonizer.canonizeString(afterBangSlash);
file = toBangSlash + afterBangSlash;
}
setURL(url, "jar", "", -1, file, ref);
}
private String parseAbsoluteSpec(String spec) {
URL url = null;
int index = -1;
// check for !/
if ((index = indexOfBangSlash(spec)) == -1) {
throw new NullPointerException("no !/ in spec");
}
// test the inner URL
try {
String innerSpec = spec.substring(0, index - 1);
url = new URL(innerSpec);
} catch (MalformedURLException e) {
throw new NullPointerException("invalid url: " +
spec + " (" + e + ")");
}
return spec;
}
private String parseContextSpec(URL url, String spec) {
String ctxFile = url.getFile();
// if the spec begins with /, chop up the jar back !/
if (spec.startsWith("/")) {
int bangSlash = indexOfBangSlash(ctxFile);
if (bangSlash == -1) {
throw new NullPointerException("malformed " +
"context url:" +
url +
": no !/");
}
ctxFile = ctxFile.substring(0, bangSlash);
}
if (!ctxFile.endsWith("/") && (!spec.startsWith("/"))){
// chop up the last component
int lastSlash = ctxFile.lastIndexOf('/');
if (lastSlash == -1) {
throw new NullPointerException("malformed " +
"context url:" +
url);
}
ctxFile = ctxFile.substring(0, lastSlash + 1);
}
return (ctxFile + spec);
}
}

View file

@ -0,0 +1,379 @@
/*
* Copyright (c) 1997, 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.protocol.jar;
import java.io.InputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.BufferedInputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.MalformedURLException;
import java.net.UnknownServiceException;
import java.util.Enumeration;
import java.util.Map;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.security.Permission;
/**
* @author Benjamin Renaud
* @since 1.2
*/
public class JarURLConnection extends java.net.JarURLConnection {
private static final boolean debug = false;
/* the Jar file factory. It handles both retrieval and caching.
*/
private static final JarFileFactory factory = JarFileFactory.getInstance();
/* the url for the Jar file */
private URL jarFileURL;
/* the permission to get this JAR file. This is the actual, ultimate,
* permission, returned by the jar file factory.
*/
private Permission permission;
/* the url connection for the JAR file */
private URLConnection jarFileURLConnection;
/* the entry name, if any */
private String entryName;
/* the JarEntry */
private JarEntry jarEntry;
/* the jar file corresponding to this connection */
private JarFile jarFile;
/* the content type for this connection */
private String contentType;
public JarURLConnection(URL url, Handler handler)
throws MalformedURLException, IOException {
super(url);
jarFileURL = getJarFileURL();
jarFileURLConnection = jarFileURL.openConnection();
// whether, or not, the embedded URL should use the cache will depend
// on this instance's cache value
jarFileURLConnection.setUseCaches(useCaches);
entryName = getEntryName();
}
public JarFile getJarFile() throws IOException {
connect();
return jarFile;
}
public JarEntry getJarEntry() throws IOException {
connect();
return jarEntry;
}
public Permission getPermission() throws IOException {
return jarFileURLConnection.getPermission();
}
class JarURLInputStream extends java.io.FilterInputStream {
JarURLInputStream (InputStream src) {
super (src);
}
public void close () throws IOException {
try {
super.close();
} finally {
if (!getUseCaches()) {
jarFile.close();
}
}
}
}
public void connect() throws IOException {
if (!connected) {
/* the factory call will do the security checks */
jarFile = factory.get(getJarFileURL(), getUseCaches());
/* we also ask the factory the permission that was required
* to get the jarFile, and set it as our permission.
*/
if (getUseCaches()) {
boolean oldUseCaches = jarFileURLConnection.getUseCaches();
jarFileURLConnection = factory.getConnection(jarFile);
jarFileURLConnection.setUseCaches(oldUseCaches);
}
if ((entryName != null)) {
jarEntry = (JarEntry)jarFile.getEntry(entryName);
if (jarEntry == null) {
try {
if (!getUseCaches()) {
jarFile.close();
}
} catch (Exception e) {
}
throw new FileNotFoundException("JAR entry " + entryName +
" not found in " +
jarFile.getName());
}
}
connected = true;
}
}
public InputStream getInputStream() throws IOException {
connect();
InputStream result = null;
if (entryName == null) {
throw new IOException("no entry name specified");
} else {
if (jarEntry == null) {
throw new FileNotFoundException("JAR entry " + entryName +
" not found in " +
jarFile.getName());
}
result = new JarURLInputStream (jarFile.getInputStream(jarEntry));
}
return result;
}
public int getContentLength() {
long result = getContentLengthLong();
if (result > Integer.MAX_VALUE)
return -1;
return (int) result;
}
public long getContentLengthLong() {
long result = -1;
try {
connect();
if (jarEntry == null) {
/* if the URL referes to an archive */
result = jarFileURLConnection.getContentLengthLong();
} else {
/* if the URL referes to an archive entry */
result = getJarEntry().getSize();
}
} catch (IOException e) {
}
return result;
}
public Object getContent() throws IOException {
Object result = null;
connect();
if (entryName == null) {
result = jarFile;
} else {
result = super.getContent();
}
return result;
}
public String getContentType() {
if (contentType == null) {
if (entryName == null) {
contentType = "x-java/jar";
} else {
try {
connect();
InputStream in = jarFile.getInputStream(jarEntry);
contentType = guessContentTypeFromStream(
new BufferedInputStream(in));
in.close();
} catch (IOException e) {
// don't do anything
}
}
if (contentType == null) {
contentType = guessContentTypeFromName(entryName);
}
if (contentType == null) {
contentType = "content/unknown";
}
}
return contentType;
}
public String getHeaderField(String name) {
return jarFileURLConnection.getHeaderField(name);
}
/**
* Sets the general request property.
*
* @param key the keyword by which the request is known
* (e.g., "<code>accept</code>").
* @param value the value associated with it.
*/
public void setRequestProperty(String key, String value) {
jarFileURLConnection.setRequestProperty(key, value);
}
/**
* Returns the value of the named general request property for this
* connection.
*
* @return the value of the named general request property for this
* connection.
*/
public String getRequestProperty(String key) {
return jarFileURLConnection.getRequestProperty(key);
}
/**
* Adds a general request property specified by a
* key-value pair. This method will not overwrite
* existing values associated with the same key.
*
* @param key the keyword by which the request is known
* (e.g., "<code>accept</code>").
* @param value the value associated with it.
*/
public void addRequestProperty(String key, String value) {
jarFileURLConnection.addRequestProperty(key, value);
}
/**
* Returns an unmodifiable Map of general request
* properties for this connection. The Map keys
* are Strings that represent the request-header
* field names. Each Map value is a unmodifiable List
* of Strings that represents the corresponding
* field values.
*
* @return a Map of the general request properties for this connection.
*/
public Map<String,List<String>> getRequestProperties() {
return jarFileURLConnection.getRequestProperties();
}
/**
* Set the value of the <code>allowUserInteraction</code> field of
* this <code>URLConnection</code>.
*
* @param allowuserinteraction the new value.
* @see java.net.URLConnection#allowUserInteraction
*/
public void setAllowUserInteraction(boolean allowuserinteraction) {
jarFileURLConnection.setAllowUserInteraction(allowuserinteraction);
}
/**
* Returns the value of the <code>allowUserInteraction</code> field for
* this object.
*
* @return the value of the <code>allowUserInteraction</code> field for
* this object.
* @see java.net.URLConnection#allowUserInteraction
*/
public boolean getAllowUserInteraction() {
return jarFileURLConnection.getAllowUserInteraction();
}
/*
* cache control
*/
/**
* Sets the value of the <code>useCaches</code> field of this
* <code>URLConnection</code> to the specified value.
* <p>
* Some protocols do caching of documents. Occasionally, it is important
* to be able to "tunnel through" and ignore the caches (e.g., the
* "reload" button in a browser). If the UseCaches flag on a connection
* is true, the connection is allowed to use whatever caches it can.
* If false, caches are to be ignored.
* The default value comes from DefaultUseCaches, which defaults to
* true.
*
* @see java.net.URLConnection#useCaches
*/
public void setUseCaches(boolean usecaches) {
jarFileURLConnection.setUseCaches(usecaches);
}
/**
* Returns the value of this <code>URLConnection</code>'s
* <code>useCaches</code> field.
*
* @return the value of this <code>URLConnection</code>'s
* <code>useCaches</code> field.
* @see java.net.URLConnection#useCaches
*/
public boolean getUseCaches() {
return jarFileURLConnection.getUseCaches();
}
/**
* Sets the value of the <code>ifModifiedSince</code> field of
* this <code>URLConnection</code> to the specified value.
*
* @param ifmodifiedsince the new value.
* @see java.net.URLConnection#ifModifiedSince
*/
public void setIfModifiedSince(long ifmodifiedsince) {
jarFileURLConnection.setIfModifiedSince(ifmodifiedsince);
}
/**
* Sets the default value of the <code>useCaches</code> field to the
* specified value.
*
* @param defaultusecaches the new value.
* @see java.net.URLConnection#useCaches
*/
public void setDefaultUseCaches(boolean defaultusecaches) {
jarFileURLConnection.setDefaultUseCaches(defaultusecaches);
}
/**
* Returns the default value of a <code>URLConnection</code>'s
* <code>useCaches</code> flag.
* <p>
* Ths default is "sticky", being a part of the static state of all
* URLConnections. This flag applies to the next, and all following
* URLConnections that are created.
*
* @return the default value of a <code>URLConnection</code>'s
* <code>useCaches</code> flag.
* @see java.net.URLConnection#useCaches
*/
public boolean getDefaultUseCaches() {
return jarFileURLConnection.getDefaultUseCaches();
}
}

View file

@ -0,0 +1,284 @@
/*
* Copyright (c) 2001, 2016, 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.protocol.jar;
import java.io.*;
import java.net.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.jar.*;
import java.util.zip.ZipFile;
import java.util.zip.ZipEntry;
import java.security.CodeSigner;
import java.security.cert.Certificate;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import sun.net.www.ParseUtil;
/* URL jar file is a common JarFile subtype used for JarURLConnection */
public class URLJarFile extends JarFile {
/*
* Interface to be able to call retrieve() in plugin if
* this variable is set.
*/
private static URLJarFileCallBack callback = null;
/* Controller of the Jar File's closing */
private URLJarFileCloseController closeController = null;
private static int BUF_SIZE = 2048;
private Manifest superMan;
private Attributes superAttr;
private Map<String, Attributes> superEntries;
static JarFile getJarFile(URL url) throws IOException {
return getJarFile(url, null);
}
static JarFile getJarFile(URL url, URLJarFileCloseController closeController) throws IOException {
if (isFileURL(url)) {
Runtime.Version version = "runtime".equals(url.getRef())
? JarFile.runtimeVersion()
: JarFile.baseVersion();
return new URLJarFile(url, closeController, version);
} else {
return retrieve(url, closeController);
}
}
/*
* Changed modifier from private to public in order to be able
* to instantiate URLJarFile from sun.plugin package.
*/
public URLJarFile(File file) throws IOException {
this(file, null);
}
/*
* Changed modifier from private to public in order to be able
* to instantiate URLJarFile from sun.plugin package.
*/
public URLJarFile(File file, URLJarFileCloseController closeController) throws IOException {
super(file, true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE);
this.closeController = closeController;
}
private URLJarFile(File file, URLJarFileCloseController closeController, Runtime.Version version)
throws IOException {
super(file, true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE, version);
this.closeController = closeController;
}
private URLJarFile(URL url, URLJarFileCloseController closeController, Runtime.Version version)
throws IOException {
super(new File(ParseUtil.decode(url.getFile())), true, ZipFile.OPEN_READ, version);
this.closeController = closeController;
}
private static boolean isFileURL(URL url) {
if (url.getProtocol().equalsIgnoreCase("file")) {
/*
* Consider this a 'file' only if it's a LOCAL file, because
* 'file:' URLs can be accessible through ftp.
*/
String host = url.getHost();
if (host == null || host.equals("") || host.equals("~") ||
host.equalsIgnoreCase("localhost"))
return true;
}
return false;
}
/**
* Returns the <code>ZipEntry</code> for the given entry name or
* <code>null</code> if not found.
*
* @param name the JAR file entry name
* @return the <code>ZipEntry</code> for the given entry name or
* <code>null</code> if not found
* @see java.util.zip.ZipEntry
*/
public ZipEntry getEntry(String name) {
ZipEntry ze = super.getEntry(name);
if (ze != null) {
if (ze instanceof JarEntry)
return new URLJarFileEntry((JarEntry)ze);
else
throw new InternalError(super.getClass() +
" returned unexpected entry type " +
ze.getClass());
}
return null;
}
public Manifest getManifest() throws IOException {
if (!isSuperMan()) {
return null;
}
Manifest man = new Manifest();
Attributes attr = man.getMainAttributes();
attr.putAll((Map)superAttr.clone());
// now deep copy the manifest entries
if (superEntries != null) {
Map<String, Attributes> entries = man.getEntries();
for (String key : superEntries.keySet()) {
Attributes at = superEntries.get(key);
entries.put(key, (Attributes) at.clone());
}
}
return man;
}
/* If close controller is set the notify the controller about the pending close */
public void close() throws IOException {
if (closeController != null) {
closeController.close(this);
}
super.close();
}
// optimal side-effects
private synchronized boolean isSuperMan() throws IOException {
if (superMan == null) {
superMan = super.getManifest();
}
if (superMan != null) {
superAttr = superMan.getMainAttributes();
superEntries = superMan.getEntries();
return true;
} else
return false;
}
/**
* Given a URL, retrieves a JAR file, caches it to disk, and creates a
* cached JAR file object.
*/
private static JarFile retrieve(final URL url, final URLJarFileCloseController closeController) throws IOException {
/*
* See if interface is set, then call retrieve function of the class
* that implements URLJarFileCallBack interface (sun.plugin - to
* handle the cache failure for JARJAR file.)
*/
if (callback != null)
{
return callback.retrieve(url);
}
else
{
JarFile result = null;
Runtime.Version version = "runtime".equals(url.getRef())
? JarFile.runtimeVersion()
: JarFile.baseVersion();
/* get the stream before asserting privileges */
try (final InputStream in = url.openConnection().getInputStream()) {
result = AccessController.doPrivileged(
new PrivilegedExceptionAction<>() {
public JarFile run() throws IOException {
Path tmpFile = Files.createTempFile("jar_cache", null);
try {
Files.copy(in, tmpFile, StandardCopyOption.REPLACE_EXISTING);
JarFile jarFile = new URLJarFile(tmpFile.toFile(), closeController, version);
tmpFile.toFile().deleteOnExit();
return jarFile;
} catch (Throwable thr) {
try {
Files.delete(tmpFile);
} catch (IOException ioe) {
thr.addSuppressed(ioe);
}
throw thr;
}
}
});
} catch (PrivilegedActionException pae) {
throw (IOException) pae.getException();
}
return result;
}
}
/*
* Set the call back interface to call retrive function in sun.plugin
* package if plugin is running.
*/
public static void setCallBack(URLJarFileCallBack cb)
{
callback = cb;
}
private class URLJarFileEntry extends JarEntry {
private JarEntry je;
URLJarFileEntry(JarEntry je) {
super(je);
this.je=je;
}
public Attributes getAttributes() throws IOException {
if (URLJarFile.this.isSuperMan()) {
Map<String, Attributes> e = URLJarFile.this.superEntries;
if (e != null) {
Attributes a = e.get(getName());
if (a != null)
return (Attributes)a.clone();
}
}
return null;
}
public java.security.cert.Certificate[] getCertificates() {
Certificate[] certs = je.getCertificates();
return certs == null? null: certs.clone();
}
public CodeSigner[] getCodeSigners() {
CodeSigner[] csg = je.getCodeSigners();
return csg == null? null: csg.clone();
}
}
public interface URLJarFileCloseController {
public void close(JarFile jarFile);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2001, 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.protocol.jar;
import java.io.*;
import java.net.*;
import java.util.jar.*;
/*
* This interface is used to call back to sun.plugin package.
*/
public interface URLJarFileCallBack
{
public JarFile retrieve (URL url) throws IOException;
}

View file

@ -0,0 +1,50 @@
/*
* 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.www.protocol.jmod;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.MalformedURLException;
import java.io.IOException;
/**
* Placeholder protocol handler for the jmod protocol.
*/
public class Handler extends URLStreamHandler {
public Handler() { }
@Override
protected URLConnection openConnection(URL url) throws IOException {
String s = url.toString();
int index = s.indexOf("!/");
if (index == -1)
throw new MalformedURLException("no !/ found in url spec:" + s);
throw new IOException("Can't connect to jmod URL");
}
}

View file

@ -0,0 +1,44 @@
/*
* 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.www.protocol.jrt;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
/**
* Protocol handler for accessing resources in the runtime image.
*/
public class Handler extends URLStreamHandler {
public Handler() { }
@Override
protected URLConnection openConnection(URL url) throws IOException {
return new JavaRuntimeURLConnection(url);
}
}

View file

@ -0,0 +1,186 @@
/*
* Copyright (c) 2014, 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.www.protocol.jrt;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import jdk.internal.jimage.ImageLocation;
import jdk.internal.jimage.ImageReader;
import jdk.internal.jimage.ImageReaderFactory;
import jdk.internal.loader.URLClassPath;
import jdk.internal.loader.Resource;
import sun.net.www.ParseUtil;
import sun.net.www.URLConnection;
/**
* URLConnection implementation that can be used to connect to resources
* contained in the runtime image.
*/
public class JavaRuntimeURLConnection extends URLConnection {
// ImageReader to access resources in jimage
private static final ImageReader reader;
static {
PrivilegedAction<ImageReader> pa = ImageReaderFactory::getImageReader;
reader = AccessController.doPrivileged(pa);
}
// the module and resource name in the URL
private final String module;
private final String name;
// the Resource when connected
private volatile Resource resource;
JavaRuntimeURLConnection(URL url) throws IOException {
super(url);
String path = url.getPath();
if (path.length() == 0 || path.charAt(0) != '/')
throw new MalformedURLException(url + " missing path or /");
if (path.length() == 1) {
this.module = null;
this.name = null;
} else {
int pos = path.indexOf('/', 1);
if (pos == -1) {
this.module = path.substring(1);
this.name = null;
} else {
this.module = path.substring(1, pos);
this.name = ParseUtil.decode(path.substring(pos+1));
}
}
}
/**
* Finds a resource in a module, returning {@code null} if the resource
* is not found.
*/
private static Resource findResource(String module, String name) {
if (reader != null) {
URL url = toJrtURL(module, name);
ImageLocation location = reader.findLocation(module, name);
if (location != null && URLClassPath.checkURL(url) != null) {
return new Resource() {
@Override
public String getName() {
return name;
}
@Override
public URL getURL() {
return url;
}
@Override
public URL getCodeSourceURL() {
return toJrtURL(module);
}
@Override
public InputStream getInputStream() throws IOException {
byte[] resource = reader.getResource(location);
return new ByteArrayInputStream(resource);
}
@Override
public int getContentLength() {
long size = location.getUncompressedSize();
return (size > Integer.MAX_VALUE) ? -1 : (int) size;
}
};
}
}
return null;
}
@Override
public synchronized void connect() throws IOException {
if (!connected) {
if (name == null) {
String s = (module == null) ? "" : module;
throw new IOException("cannot connect to jrt:/" + s);
}
resource = findResource(module, name);
if (resource == null)
throw new IOException(module + "/" + name + " not found");
connected = true;
}
}
@Override
public InputStream getInputStream() throws IOException {
connect();
return resource.getInputStream();
}
@Override
public long getContentLengthLong() {
try {
connect();
return resource.getContentLength();
} catch (IOException ioe) {
return -1L;
}
}
@Override
public int getContentLength() {
long len = getContentLengthLong();
return len > Integer.MAX_VALUE ? -1 : (int)len;
}
@Override
public Permission getPermission() {
return new RuntimePermission("accessSystemModules");
}
/**
* Returns a jrt URL for the given module and resource name.
*/
private static URL toJrtURL(String module, String name) {
try {
return new URL("jrt:/" + module + "/" + name);
} catch (MalformedURLException e) {
throw new InternalError(e);
}
}
/**
* Returns a jrt URL for the given module.
*/
private static URL toJrtURL(String module) {
try {
return new URL("jrt:/" + module);
} catch (MalformedURLException e) {
throw new InternalError(e);
}
}
}

View file

@ -0,0 +1,158 @@
/*
* 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.
*/
/*-
* mailto stream opener
*/
package sun.net.www.protocol.mailto;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.io.*;
import sun.net.www.*;
//import sun.net.www.protocol.news.ArticlePoster;
import sun.net.smtp.SmtpClient;
/** open an nntp input stream given a URL */
public class Handler extends URLStreamHandler {
/*
// private String decodePercent(String s) {
// if (s==null || s.indexOf('%') < 0)
// return s;
// int limit = s.length();
// char d[] = new char[limit];
// int dp = 0;
// for (int sp = 0; sp < limit; sp++) {
// int c = s.charAt(sp);
// if (c == '%' && sp + 2 < limit) {
// int s1 = s.charAt(sp + 1);
// int s2 = s.charAt(sp + 2);
// if ('0' <= s1 && s1 <= '9')
// s1 = s1 - '0';
// else if ('a' <= s1 && s1 <= 'f')
// s1 = s1 - 'a' + 10;
// else if ('A' <= s1 && s1 <= 'F')
// s1 = s1 - 'A' + 10;
// else
// s1 = -1;
// if ('0' <= s2 && s2 <= '9')
// s2 = s2 - '0';
// else if ('a' <= s2 && s2 <= 'f')
// s2 = s2 - 'a' + 10;
// else if ('A' <= s2 && s2 <= 'F')
// s2 = s2 - 'A' + 10;
// else
// s2 = -1;
// if (s1 >= 0 && s2 >= 0) {
// c = (s1 << 4) | s2;
// sp += 2;
// }
// }
// d[dp++] = (char) c;
// }
// return new String(d, 0, dp);
// }
// public InputStream openStream(URL u) {
// String dest = u.file;
// String subj = "";
// int lastsl = dest.lastIndexOf('/');
// if (lastsl >= 0) {
// int st = dest.charAt(0) == '/' ? 1 : 0;
// if (lastsl > st)
// subj = dest.substring(st, lastsl);
// dest = dest.substring(lastsl + 1);
// }
// if (u.postData != null) {
// ArticlePoster.MailTo("Posted form",
// decodePercent(dest),
// u.postData);
// }
// else
// ArticlePoster.MailTo(decodePercent(subj), decodePercent(dest));
// return null;
// }
*/
public synchronized URLConnection openConnection(URL u) {
return new MailToURLConnection(u);
}
/**
* This method is called to parse the string spec into URL u for a
* mailto protocol.
*
* @param u the URL to receive the result of parsing the spec
* @param spec the URL string to parse
* @param start the character position to start parsing at. This is
* just past the ':'.
* @param limit the character position to stop parsing at.
*/
public void parseURL(URL u, String spec, int start, int limit) {
String protocol = u.getProtocol();
String host = "";
int port = u.getPort();
String file = "";
if (start < limit) {
file = spec.substring(start, limit);
}
/*
* Let's just make sure we DO have an Email address in the URL.
*/
boolean nogood = false;
if (file == null || file.equals(""))
nogood = true;
else {
boolean allwhites = true;
for (int i = 0; i < file.length(); i++)
if (!Character.isWhitespace(file.charAt(i)))
allwhites = false;
if (allwhites)
nogood = true;
}
if (nogood)
throw new RuntimeException("No email address");
setURLHandler(u, protocol, host, port, file, null);
}
/**
* This method is used to suppress the deprecated warning
*
* @param u the URL to receive the result of parsing the spec
* @param spec the URL string to parse
* @param start the character position to start parsing at. This is
* just past the ':'.
* @param limit the character position to stop parsing at.
*/
@SuppressWarnings("deprecation")
private void setURLHandler(URL u, String protocol, String host, int port, String file, String ref) {
setURL(u,protocol,host,port,file,null);
}
}

View file

@ -0,0 +1,140 @@
/*
* 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.protocol.mailto;
import java.net.URL;
import java.net.InetAddress;
import java.net.SocketPermission;
import java.io.*;
import java.security.Permission;
import sun.net.www.*;
import sun.net.smtp.SmtpClient;
import sun.net.www.ParseUtil;
/**
* Handle mailto URLs. To send mail using a mailto URLConnection,
* call <code>getOutputStream</code>, write the message to the output
* stream, and close it.
*
*/
public class MailToURLConnection extends URLConnection {
InputStream is = null;
OutputStream os = null;
SmtpClient client;
Permission permission;
private int connectTimeout = -1;
private int readTimeout = -1;
MailToURLConnection(URL u) {
super(u);
MessageHeader props = new MessageHeader();
props.add("content-type", "text/html");
setProperties(props);
}
/**
* Get the user's full email address - stolen from
* HotJavaApplet.getMailAddress().
*/
String getFromAddress() {
String str = System.getProperty("user.fromaddr");
if (str == null) {
str = System.getProperty("user.name");
if (str != null) {
String host = System.getProperty("mail.host");
if (host == null) {
try {
host = InetAddress.getLocalHost().getHostName();
} catch (java.net.UnknownHostException e) {
}
}
str += "@" + host;
} else {
str = "";
}
}
return str;
}
public void connect() throws IOException {
client = new SmtpClient(connectTimeout);
client.setReadTimeout(readTimeout);
}
@Override
public synchronized OutputStream getOutputStream() throws IOException {
if (os != null) {
return os;
} else if (is != null) {
throw new IOException("Cannot write output after reading input.");
}
connect();
String to = ParseUtil.decode(url.getPath());
client.from(getFromAddress());
client.to(to);
os = client.startMessage();
return os;
}
@Override
public Permission getPermission() throws IOException {
if (permission == null) {
connect();
String host = client.getMailHost() + ":" + 25;
permission = new SocketPermission(host, "connect");
}
return permission;
}
@Override
public void setConnectTimeout(int timeout) {
if (timeout < 0)
throw new IllegalArgumentException("timeouts can't be negative");
connectTimeout = timeout;
}
@Override
public int getConnectTimeout() {
return (connectTimeout < 0 ? 0 : connectTimeout);
}
@Override
public void setReadTimeout(int timeout) {
if (timeout < 0)
throw new IllegalArgumentException("timeouts can't be negative");
readTimeout = timeout;
}
@Override
public int getReadTimeout() {
return readTimeout < 0 ? 0 : readTimeout;
}
}