feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
233
jdkSrc/jdk8/sun/net/www/protocol/file/FileURLConnection.java
Normal file
233
jdkSrc/jdk8/sun/net/www/protocol/file/FileURLConnection.java
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.security.action.GetIntegerAction;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
|
||||
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();
|
||||
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
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);
|
||||
buf.append(fileName);
|
||||
buf.append("\n");
|
||||
}
|
||||
// Put it into a (default) locale-specific byte-stream.
|
||||
is = new ByteArrayInputStream(buf.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 {
|
||||
permission = new FilePermission(
|
||||
decodedPath.replace('/',File.separatorChar), "read");
|
||||
}
|
||||
}
|
||||
return permission;
|
||||
}
|
||||
}
|
||||
154
jdkSrc/jdk8/sun/net/www/protocol/file/Handler.java
Normal file
154
jdkSrc/jdk8/sun/net/www/protocol/file/Handler.java
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2019, 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.file;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.Proxy;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import sun.net.www.ParseUtil;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Open an file input stream given a URL.
|
||||
* @author James Gosling
|
||||
*/
|
||||
public class Handler extends URLStreamHandler {
|
||||
|
||||
private String getHost(URL url) {
|
||||
String host = url.getHost();
|
||||
if (host == null)
|
||||
host = "";
|
||||
return host;
|
||||
}
|
||||
|
||||
|
||||
protected void parseURL(URL u, String spec, int start, int limit) {
|
||||
/*
|
||||
* Ugly backwards compatibility. Flip any file separator
|
||||
* characters to be forward slashes. This is a nop on Unix
|
||||
* and "fixes" win32 file paths. According to RFC 2396,
|
||||
* only forward slashes may be used to represent hierarchy
|
||||
* separation in a URL but previous releases unfortunately
|
||||
* performed this "fixup" behavior in the file URL parsing code
|
||||
* rather than forcing this to be fixed in the caller of the URL
|
||||
* class where it belongs. Since backslash is an "unwise"
|
||||
* character that would normally be encoded if literally intended
|
||||
* as a non-seperator character the damage of veering away from the
|
||||
* specification is presumably limited.
|
||||
*/
|
||||
super.parseURL(u, spec.replace(File.separatorChar, '/'), start, limit);
|
||||
}
|
||||
|
||||
public synchronized URLConnection openConnection(URL url)
|
||||
throws IOException {
|
||||
return openConnection(url, null);
|
||||
}
|
||||
|
||||
public synchronized URLConnection openConnection(URL url, Proxy p)
|
||||
throws IOException {
|
||||
|
||||
String path;
|
||||
String file = url.getFile();
|
||||
String host = url.getHost();
|
||||
|
||||
path = ParseUtil.decode(file);
|
||||
path = path.replace('/', '\\');
|
||||
path = path.replace('|', ':');
|
||||
|
||||
if ((host == null) || host.equals("") ||
|
||||
host.equalsIgnoreCase("localhost") ||
|
||||
host.equals("~")) {
|
||||
return createFileURLConnection(url, new File(path));
|
||||
}
|
||||
|
||||
/*
|
||||
* attempt to treat this as a UNC path. See 4180841
|
||||
*/
|
||||
path = "\\\\" + host + path;
|
||||
File f = new File(path);
|
||||
if (f.exists()) {
|
||||
return new UNCFileURLConnection(url, f, path);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now attempt an ftp connection.
|
||||
*/
|
||||
URLConnection uc;
|
||||
URL newurl;
|
||||
|
||||
try {
|
||||
newurl = new URL("ftp", host, file +
|
||||
(url.getRef() == null ? "":
|
||||
"#" + url.getRef()));
|
||||
if (p != null) {
|
||||
uc = newurl.openConnection(p);
|
||||
} else {
|
||||
uc = newurl.openConnection();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
uc = null;
|
||||
}
|
||||
if (uc == null) {
|
||||
throw new IOException("Unable to connect to: " +
|
||||
url.toExternalForm());
|
||||
}
|
||||
return uc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method to be overriden by Java Plug-in. [stanleyh]
|
||||
*/
|
||||
protected URLConnection createFileURLConnection(URL url, File file) {
|
||||
return new FileURLConnection(url, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the host components of two URLs.
|
||||
* @param u1 the URL of the first host to compare
|
||||
* @param u2 the URL of the second host to compare
|
||||
* @return <tt>true</tt> if and only if they
|
||||
* are equal, <tt>false</tt> otherwise.
|
||||
*/
|
||||
protected boolean hostsEqual(URL u1, URL u2) {
|
||||
/*
|
||||
* Special case for file: URLs
|
||||
* per RFC 1738 no hostname is equivalent to 'localhost'
|
||||
* i.e. file:///path is equal to file://localhost/path
|
||||
*/
|
||||
String s1 = u1.getHost();
|
||||
String s2 = u2.getHost();
|
||||
if ("localhost".equalsIgnoreCase(s1) && ( s2 == null || "".equals(s2)))
|
||||
return true;
|
||||
if ("localhost".equalsIgnoreCase(s2) && ( s1 == null || "".equals(s1)))
|
||||
return true;
|
||||
return super.hostsEqual(u1, u2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.file;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilePermission;
|
||||
import java.net.URL;
|
||||
import java.security.Permission;
|
||||
|
||||
final class UNCFileURLConnection extends FileURLConnection {
|
||||
|
||||
private final String effectivePath;
|
||||
private volatile Permission permission;
|
||||
|
||||
UNCFileURLConnection(URL u, File file, String effectivePath) {
|
||||
super(u, file);
|
||||
this.effectivePath = effectivePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission getPermission() {
|
||||
Permission perm = permission;
|
||||
if (perm == null) {
|
||||
permission = perm = new FilePermission(effectivePath, "read");
|
||||
}
|
||||
return perm;
|
||||
}
|
||||
}
|
||||
|
||||
692
jdkSrc/jdk8/sun/net/www/protocol/ftp/FtpURLConnection.java
Normal file
692
jdkSrc/jdk8/sun/net/www/protocol/ftp/FtpURLConnection.java
Normal file
@@ -0,0 +1,692 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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.MalformedURLException;
|
||||
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 sun.net.NetworkClient;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
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;
|
||||
|
||||
import static sun.net.util.ProxyUtil.copyProxy;
|
||||
|
||||
/**
|
||||
* 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 :
|
||||
* <P>
|
||||
* <code>URL url = new URL("ftp://ftp.sun.com/pub/test.txt");<p>
|
||||
* UrlConnection con = url.openConnection();<p>
|
||||
* InputStream is = con.getInputStream();<p>
|
||||
* ...<p>
|
||||
* is.close();</code>
|
||||
*
|
||||
* @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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static URL checkURL(URL u) throws IllegalArgumentException {
|
||||
if (u != null) {
|
||||
if (u.toExternalForm().indexOf('\n') > -1) {
|
||||
Exception mfue = new MalformedURLException("Illegal character in URL");
|
||||
throw new IllegalArgumentException(mfue.getMessage(), mfue);
|
||||
}
|
||||
}
|
||||
String s = IPAddressUtil.checkAuthority(u);
|
||||
if (s != null) {
|
||||
Exception mfue = new MalformedURLException(s);
|
||||
throw new IllegalArgumentException(mfue.getMessage(), mfue);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an FtpURLConnection from a URL.
|
||||
*
|
||||
* @param url The <code>URL</code> 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(checkURL(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 = copyProxy(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";
|
||||
String vers = java.security.AccessController.doPrivileged(
|
||||
new GetPropertyAction("java.version"));
|
||||
password = java.security.AccessController.doPrivileged(
|
||||
new GetPropertyAction("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</code> 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</code> 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</code> associated with the host & port.
|
||||
*
|
||||
* @return The <code>Permission</code> 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</code>").
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
60
jdkSrc/jdk8/sun/net/www/protocol/ftp/Handler.java
Normal file
60
jdkSrc/jdk8/sun/net/www/protocol/ftp/Handler.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* FTP stream opener
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.ftp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.Proxy;
|
||||
import static sun.net.util.ProxyUtil.copyProxy;
|
||||
|
||||
/** 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 proxy)
|
||||
throws IOException {
|
||||
return new FtpURLConnection(u, copyProxy(proxy));
|
||||
}
|
||||
}
|
||||
71
jdkSrc/jdk8/sun/net/www/protocol/http/AuthCache.java
Normal file
71
jdkSrc/jdk8/sun/net/www/protocol/http/AuthCache.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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] Between 4 and 6 fields separated by ":"
|
||||
* 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
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
108
jdkSrc/jdk8/sun/net/www/protocol/http/AuthCacheImpl.java
Normal file
108
jdkSrc/jdk8/sun/net/www/protocol/http/AuthCacheImpl.java
Normal 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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
100
jdkSrc/jdk8/sun/net/www/protocol/http/AuthCacheValue.java
Normal file
100
jdkSrc/jdk8/sun/net/www/protocol/http/AuthCacheValue.java
Normal 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()
|
||||
*/
|
||||
static protected 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();
|
||||
}
|
||||
38
jdkSrc/jdk8/sun/net/www/protocol/http/AuthScheme.java
Normal file
38
jdkSrc/jdk8/sun/net/www/protocol/http/AuthScheme.java
Normal 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;
|
||||
}
|
||||
|
||||
279
jdkSrc/jdk8/sun/net/www/protocol/http/AuthenticationHeader.java
Normal file
279
jdkSrc/jdk8/sun/net/www/protocol/http/AuthenticationHeader.java
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* 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 sun.net.www.*;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 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 = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("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;
|
||||
}
|
||||
}
|
||||
463
jdkSrc/jdk8/sun/net/www/protocol/http/AuthenticationInfo.java
Normal file
463
jdkSrc/jdk8/sun/net/www/protocol/http/AuthenticationInfo.java
Normal file
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* 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 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: */
|
||||
|
||||
transient protected 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.
|
||||
*/
|
||||
static private 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
|
||||
*/
|
||||
static private 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.
|
||||
*/
|
||||
static private 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;
|
||||
|
||||
/** Use this constructor only for proxy entries */
|
||||
public AuthenticationInfo(char type, AuthScheme authScheme, String host, int port, String realm) {
|
||||
this.type = type;
|
||||
this.authScheme = authScheme;
|
||||
this.protocol = "";
|
||||
this.host = host.toLowerCase();
|
||||
this.port = port;
|
||||
this.realm = realm;
|
||||
this.path = null;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
int port = url.getPort();
|
||||
if (port == -1) {
|
||||
port = url.getDefaultPort();
|
||||
}
|
||||
String key = SERVER_AUTHENTICATION + ":" + url.getProtocol().toLowerCase()
|
||||
+ ":" + url.getHost().toLowerCase() + ":" + port;
|
||||
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) {
|
||||
int port = url.getPort();
|
||||
if (port == -1) {
|
||||
port = url.getDefaultPort();
|
||||
}
|
||||
String key = SERVER_AUTHENTICATION + ":" + scheme + ":" + url.getProtocol().toLowerCase()
|
||||
+ ":" + url.getHost().toLowerCase() + ":" + port + ":" + realm;
|
||||
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 key = PROXY_AUTHENTICATION + "::" + host.toLowerCase() + ":" + port;
|
||||
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 key = PROXY_AUTHENTICATION + ":" + scheme + "::" + host.toLowerCase()
|
||||
+ ":" + port + ":" + realm;
|
||||
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.
|
||||
if (includeRealm) {
|
||||
return type + ":" + authScheme + ":" + protocol + ":"
|
||||
+ host + ":" + port + ":" + realm;
|
||||
} else {
|
||||
return type + ":" + protocol + ":" + host + ":" + port;
|
||||
}
|
||||
}
|
||||
|
||||
String s1, s2; /* used for serialization of pw */
|
||||
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
s.defaultReadObject ();
|
||||
pw = new PasswordAuthentication (s1, s2.toCharArray());
|
||||
s1 = null; s2= null;
|
||||
}
|
||||
|
||||
private synchronized void writeObject(java.io.ObjectOutputStream s)
|
||||
throws IOException
|
||||
{
|
||||
s1 = pw.getUserName();
|
||||
s2 = new String (pw.getPassword());
|
||||
s.defaultWriteObject ();
|
||||
}
|
||||
}
|
||||
205
jdkSrc/jdk8/sun/net/www/protocol/http/BasicAuthentication.java
Normal file
205
jdkSrc/jdk8/sun/net/www/protocol/http/BasicAuthentication.java
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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.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 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) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.BASIC, host, port, realm);
|
||||
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) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.BASIC, host, port, realm);
|
||||
this.auth = "Basic " + auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a BasicAuthentication
|
||||
*/
|
||||
public BasicAuthentication(boolean isProxy, URL url, String realm,
|
||||
PasswordAuthentication pw) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.BASIC, url, realm);
|
||||
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) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.BASIC, url, realm);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
544
jdkSrc/jdk8/sun/net/www/protocol/http/DigestAuthentication.java
Normal file
544
jdkSrc/jdk8/sun/net/www/protocol/http/DigestAuthentication.java
Normal file
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
* 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.http;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.ProtocolException;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.util.Arrays;
|
||||
import java.util.StringTokenizer;
|
||||
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 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 final static 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<Boolean>() {
|
||||
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) {
|
||||
StringTokenizer st = new StringTokenizer (qop, " ");
|
||||
while (st.hasMoreTokens()) {
|
||||
if (st.nextToken().equalsIgnoreCase ("auth")) {
|
||||
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 (!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) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.DIGEST,
|
||||
url,
|
||||
realm);
|
||||
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) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.DIGEST,
|
||||
host,
|
||||
port,
|
||||
realm);
|
||||
this.authMethod = authMethod;
|
||||
this.pw = pw;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this authentication supports preemptive authorization
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsPreemptiveAuthorization() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reclaculates 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reclaculates 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 final static char charArray[] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
};
|
||||
|
||||
private final static 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();
|
||||
|
||||
StringBuffer res = new StringBuffer(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();
|
||||
}
|
||||
}
|
||||
64
jdkSrc/jdk8/sun/net/www/protocol/http/Handler.java
Normal file
64
jdkSrc/jdk8/sun/net/www/protocol/http/Handler.java
Normal 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);
|
||||
}
|
||||
}
|
||||
76
jdkSrc/jdk8/sun/net/www/protocol/http/HttpAuthenticator.java
Normal file
76
jdkSrc/jdk8/sun/net/www/protocol/http/HttpAuthenticator.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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:
|
||||
* --> 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>
|
||||
*/
|
||||
|
||||
public String authString (URL u, String scheme, String realm);
|
||||
|
||||
}
|
||||
108
jdkSrc/jdk8/sun/net/www/protocol/http/HttpCallerInfo.java
Normal file
108
jdkSrc/jdk8/sun/net/www/protocol/http/HttpCallerInfo.java
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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.
|
||||
*/
|
||||
final public class HttpCallerInfo {
|
||||
// All info that an Authenticator needs.
|
||||
final public URL url;
|
||||
final public String host, protocol, prompt, scheme;
|
||||
final public int port;
|
||||
final public InetAddress addr;
|
||||
final public RequestorType authType;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor an un-schemed object for site access.
|
||||
*/
|
||||
public HttpCallerInfo(URL url) {
|
||||
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 = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor an un-schemed object for proxy access.
|
||||
*/
|
||||
public HttpCallerInfo(URL url, String host, int port) {
|
||||
this.url= url;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
prompt = "";
|
||||
addr = null;
|
||||
protocol = url.getProtocol();
|
||||
authType = RequestorType.PROXY;
|
||||
scheme = "";
|
||||
}
|
||||
}
|
||||
3834
jdkSrc/jdk8/sun/net/www/protocol/http/HttpURLConnection.java
Normal file
3834
jdkSrc/jdk8/sun/net/www/protocol/http/HttpURLConnection.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.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> threeArgCtr;
|
||||
private final Constructor<? extends AuthenticationInfo> fiveArgCtr;
|
||||
|
||||
private NTLMAuthenticationProxy(Constructor<? extends AuthenticationInfo> threeArgCtr,
|
||||
Constructor<? extends AuthenticationInfo> fiveArgCtr) {
|
||||
this.threeArgCtr = threeArgCtr;
|
||||
this.fiveArgCtr = fiveArgCtr;
|
||||
}
|
||||
|
||||
|
||||
AuthenticationInfo create(boolean isProxy,
|
||||
URL url,
|
||||
PasswordAuthentication pw) {
|
||||
try {
|
||||
return threeArgCtr.newInstance(isProxy, url, pw);
|
||||
} catch (ReflectiveOperationException roe) {
|
||||
finest(roe);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
AuthenticationInfo create(boolean isProxy,
|
||||
String host,
|
||||
int port,
|
||||
PasswordAuthentication pw) {
|
||||
try {
|
||||
return fiveArgCtr.newInstance(isProxy, host, port, pw);
|
||||
} 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> threeArg, fiveArg;
|
||||
try {
|
||||
cl = (Class<? extends AuthenticationInfo>)Class.forName(clazzStr, true, null);
|
||||
if (cl != null) {
|
||||
threeArg = cl.getConstructor(boolean.class,
|
||||
URL.class,
|
||||
PasswordAuthentication.class);
|
||||
fiveArg = cl.getConstructor(boolean.class,
|
||||
String.class,
|
||||
int.class,
|
||||
PasswordAuthentication.class);
|
||||
supportsTA = cl.getDeclaredMethod(supportsTAStr);
|
||||
isTrustedSite = cl.getDeclaredMethod(isTrustedSiteStr, java.net.URL.class);
|
||||
return new NTLMAuthenticationProxy(threeArg,
|
||||
fiveArg);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.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 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;
|
||||
|
||||
final private 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 = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("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,
|
||||
"");
|
||||
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. 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
|
||||
*/
|
||||
synchronized public static boolean isSupported(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<HashMap<String, Negotiator>>() {
|
||||
@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.
|
||||
* @returns 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>
|
||||
* @returns 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.
|
||||
|
||||
}
|
||||
84
jdkSrc/jdk8/sun/net/www/protocol/http/Negotiator.java
Normal file
84
jdkSrc/jdk8/sun/net/www/protocol/http/Negotiator.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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, null);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.logging;
|
||||
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.regex.*;
|
||||
|
||||
/**
|
||||
* A Formatter to make the HTTP logs a bit more palatable to the developer
|
||||
* looking at them. The idea is to present the HTTP events in such a way that
|
||||
* commands and headers are easily spotted (i.e. on separate lines).
|
||||
* @author jccollet
|
||||
*/
|
||||
public class HttpLogFormatter extends java.util.logging.SimpleFormatter {
|
||||
// Pattern for MessageHeader data. Mostly pairs within curly brackets
|
||||
private static volatile Pattern pattern = null;
|
||||
// Pattern for Cookies
|
||||
private static volatile Pattern cpattern = null;
|
||||
|
||||
public HttpLogFormatter() {
|
||||
if (pattern == null) {
|
||||
pattern = Pattern.compile("\\{[^\\}]*\\}");
|
||||
cpattern = Pattern.compile("[^,\\] ]{2,}");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
String sourceClassName = record.getSourceClassName();
|
||||
if (sourceClassName == null ||
|
||||
!(sourceClassName.startsWith("sun.net.www.protocol.http") ||
|
||||
sourceClassName.startsWith("sun.net.www.http"))) {
|
||||
return super.format(record);
|
||||
}
|
||||
String src = record.getMessage();
|
||||
StringBuilder buf = new StringBuilder("HTTP: ");
|
||||
if (src.startsWith("sun.net.www.MessageHeader@")) {
|
||||
// MessageHeader logs are composed of pairs within curly brackets
|
||||
// Let's extract them to make it more readable. That way we get one
|
||||
// header pair (name, value) per line. A lot easier to read.
|
||||
Matcher match = pattern.matcher(src);
|
||||
while (match.find()) {
|
||||
int i = match.start();
|
||||
int j = match.end();
|
||||
String s = src.substring(i + 1, j - 1);
|
||||
if (s.startsWith("null: ")) {
|
||||
s = s.substring(6);
|
||||
}
|
||||
if (s.endsWith(": null")) {
|
||||
s = s.substring(0, s.length() - 6);
|
||||
}
|
||||
buf.append("\t").append(s).append("\n");
|
||||
}
|
||||
} else if (src.startsWith("Cookies retrieved: {")) {
|
||||
// This comes from the Cookie handler, let's clean up the format a bit
|
||||
String s = src.substring(20);
|
||||
buf.append("Cookies from handler:\n");
|
||||
while (s.length() >= 7) {
|
||||
if (s.startsWith("Cookie=[")) {
|
||||
String s2 = s.substring(8);
|
||||
int c = s2.indexOf("Cookie2=[");
|
||||
if (c > 0) {
|
||||
s2 = s2.substring(0, c-1);
|
||||
s = s2.substring(c);
|
||||
} else {
|
||||
s = "";
|
||||
}
|
||||
if (s2.length() < 4) {
|
||||
continue;
|
||||
}
|
||||
Matcher m = cpattern.matcher(s2);
|
||||
while (m.find()) {
|
||||
int i = m.start();
|
||||
int j = m.end();
|
||||
if (i >= 0) {
|
||||
String cookie = s2.substring(i + 1, j > 0 ? j - 1 : s2.length() - 1);
|
||||
buf.append("\t").append(cookie).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s.startsWith("Cookie2=[")) {
|
||||
String s2 = s.substring(9);
|
||||
int c = s2.indexOf("Cookie=[");
|
||||
if (c > 0) {
|
||||
s2 = s2.substring(0, c-1);
|
||||
s = s2.substring(c);
|
||||
} else {
|
||||
s = "";
|
||||
}
|
||||
Matcher m = cpattern.matcher(s2);
|
||||
while (m.find()) {
|
||||
int i = m.start();
|
||||
int j = m.end();
|
||||
if (i >= 0) {
|
||||
String cookie = s2.substring(i+1, j > 0 ? j-1 : s2.length() - 1);
|
||||
buf.append("\t").append(cookie).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Anything else we let as is.
|
||||
buf.append(src).append("\n");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.ntlm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
|
||||
/*
|
||||
* Hooks into Windows implementation of NTLM.
|
||||
* This class will be replaced if a cross-platform version of NTLM
|
||||
* is implemented in the future.
|
||||
*/
|
||||
|
||||
public class NTLMAuthSequence {
|
||||
|
||||
private String username;
|
||||
private String password;
|
||||
private String ntdomain;
|
||||
private int state;
|
||||
private long crdHandle;
|
||||
private long ctxHandle;
|
||||
|
||||
static {
|
||||
initFirst(Status.class);
|
||||
}
|
||||
|
||||
// Used by native code to indicate when a particular protocol sequence is completed
|
||||
// and must not be re-used.
|
||||
|
||||
class Status {
|
||||
boolean sequenceComplete;
|
||||
}
|
||||
|
||||
Status status;
|
||||
|
||||
NTLMAuthSequence (String username, String password, String ntdomain)
|
||||
throws IOException
|
||||
{
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.ntdomain = ntdomain;
|
||||
this.status = new Status();
|
||||
state = 0;
|
||||
crdHandle = getCredentialsHandle (username, ntdomain, password);
|
||||
if (crdHandle == 0) {
|
||||
throw new IOException ("could not get credentials handle");
|
||||
}
|
||||
}
|
||||
|
||||
public String getAuthHeader (String token) throws IOException {
|
||||
byte[] input = null;
|
||||
|
||||
assert !status.sequenceComplete;
|
||||
|
||||
if (token != null)
|
||||
input = Base64.getDecoder().decode(token);
|
||||
byte[] b = getNextToken (crdHandle, input, status);
|
||||
if (b == null)
|
||||
throw new IOException ("Internal authentication error");
|
||||
return Base64.getEncoder().encodeToString(b);
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return status.sequenceComplete;
|
||||
}
|
||||
|
||||
private native static void initFirst (Class<NTLMAuthSequence.Status> clazz);
|
||||
|
||||
private native long getCredentialsHandle (String user, String domain, String password);
|
||||
|
||||
private native byte[] getNextToken (long crdHandle, byte[] lastToken, Status returned);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2019, 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.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.URL;
|
||||
import sun.net.NetProperties;
|
||||
import sun.net.www.HeaderParser;
|
||||
import sun.net.www.protocol.http.AuthenticationInfo;
|
||||
import sun.net.www.protocol.http.AuthScheme;
|
||||
import sun.net.www.protocol.http.HttpURLConnection;
|
||||
|
||||
/**
|
||||
* NTLMAuthentication:
|
||||
*
|
||||
* @author Michael McMahon
|
||||
*/
|
||||
|
||||
public class NTLMAuthentication extends AuthenticationInfo {
|
||||
|
||||
private static final long serialVersionUID = 100L;
|
||||
|
||||
private static final NTLMAuthenticationCallback NTLMAuthCallback =
|
||||
NTLMAuthenticationCallback.getNTLMAuthenticationCallback();
|
||||
|
||||
private String hostname;
|
||||
private static String defaultDomain; /* Domain to use if not specified by user */
|
||||
private static final boolean ntlmCache; /* Whether cache is enabled for NTLM */
|
||||
|
||||
enum TransparentAuth {
|
||||
DISABLED, // disable for all hosts (default)
|
||||
TRUSTED_HOSTS, // use Windows trusted hosts settings
|
||||
ALL_HOSTS // attempt for all hosts
|
||||
}
|
||||
|
||||
private static final TransparentAuth authMode;
|
||||
|
||||
static {
|
||||
defaultDomain = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("http.auth.ntlm.domain",
|
||||
"domain"));
|
||||
String ntlmCacheProp = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("jdk.ntlm.cache", "true"));
|
||||
ntlmCache = Boolean.parseBoolean(ntlmCacheProp);
|
||||
String modeProp = java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
return NetProperties.get("jdk.http.ntlm.transparentAuth");
|
||||
}
|
||||
});
|
||||
|
||||
if ("trustedHosts".equalsIgnoreCase(modeProp))
|
||||
authMode = TransparentAuth.TRUSTED_HOSTS;
|
||||
else if ("allHosts".equalsIgnoreCase(modeProp))
|
||||
authMode = TransparentAuth.ALL_HOSTS;
|
||||
else
|
||||
authMode = TransparentAuth.DISABLED;
|
||||
};
|
||||
|
||||
private void init0() {
|
||||
|
||||
hostname = java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
String localhost;
|
||||
try {
|
||||
localhost = InetAddress.getLocalHost().getHostName().toUpperCase();
|
||||
} catch (UnknownHostException e) {
|
||||
localhost = "localhost";
|
||||
}
|
||||
return localhost;
|
||||
}
|
||||
});
|
||||
int x = hostname.indexOf ('.');
|
||||
if (x != -1) {
|
||||
hostname = hostname.substring (0, x);
|
||||
}
|
||||
}
|
||||
|
||||
String username;
|
||||
String ntdomain;
|
||||
String password;
|
||||
|
||||
/**
|
||||
* Create a NTLMAuthentication:
|
||||
* Username may be specified as domain<BACKSLASH>username in the application Authenticator.
|
||||
* If this notation is not used, then the domain will be taken
|
||||
* from a system property: "http.auth.ntlm.domain".
|
||||
*/
|
||||
public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.NTLM,
|
||||
url,
|
||||
"");
|
||||
init (pw);
|
||||
}
|
||||
|
||||
private void init (PasswordAuthentication pw) {
|
||||
this.pw = pw;
|
||||
if (pw != null) {
|
||||
String s = pw.getUserName();
|
||||
int i = s.indexOf ('\\');
|
||||
if (i == -1) {
|
||||
username = s;
|
||||
ntdomain = defaultDomain;
|
||||
} else {
|
||||
ntdomain = s.substring (0, i).toUpperCase();
|
||||
username = s.substring (i+1);
|
||||
}
|
||||
password = new String (pw.getPassword());
|
||||
} else {
|
||||
/* credentials will be acquired from OS */
|
||||
username = null;
|
||||
ntdomain = null;
|
||||
password = null;
|
||||
}
|
||||
init0();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor used for proxy entries
|
||||
*/
|
||||
public NTLMAuthentication(boolean isProxy, String host, int port,
|
||||
PasswordAuthentication pw) {
|
||||
super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION,
|
||||
AuthScheme.NTLM,
|
||||
host,
|
||||
port,
|
||||
"");
|
||||
init (pw);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean useAuthCache() {
|
||||
return ntlmCache && super.useAuthCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this authentication supports preemptive authorization
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsPreemptiveAuthorization() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if NTLM supported transparently (no password needed, SSO)
|
||||
*/
|
||||
public static boolean supportsTransparentAuth() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given site is trusted, i.e. we can try
|
||||
* transparent Authentication.
|
||||
*/
|
||||
public static boolean isTrustedSite(URL url) {
|
||||
if (NTLMAuthCallback != null)
|
||||
return NTLMAuthCallback.isTrustedSite(url);
|
||||
|
||||
switch (authMode) {
|
||||
case TRUSTED_HOSTS:
|
||||
return isTrustedSite(url.toString());
|
||||
case ALL_HOSTS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final boolean isTrustedSiteAvailable = isTrustedSiteAvailable();
|
||||
|
||||
private static native boolean isTrustedSiteAvailable();
|
||||
|
||||
private static boolean isTrustedSite(String url) {
|
||||
if (isTrustedSiteAvailable)
|
||||
return isTrustedSite0(url);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static native boolean isTrustedSite0(String url);
|
||||
|
||||
/**
|
||||
* 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 ntlm */
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
NTLMAuthSequence seq = (NTLMAuthSequence)conn.authObj();
|
||||
if (seq == null) {
|
||||
seq = new NTLMAuthSequence (username, password, ntdomain);
|
||||
conn.authObj(seq);
|
||||
}
|
||||
String response = "NTLM " + seq.getAuthHeader (raw.length()>6?raw.substring(5):null);
|
||||
conn.setAuthenticationProperty(getHeaderName(), response);
|
||||
if (seq.isComplete()) {
|
||||
conn.authObj(null);
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
conn.authObj(null);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http.spnego;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Authenticator;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.util.Arrays;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.NameCallback;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import sun.net.www.protocol.http.HttpCallerInfo;
|
||||
import sun.security.jgss.LoginConfigImpl;
|
||||
|
||||
/**
|
||||
* @since 1.6
|
||||
* Special callback handler used in JGSS for the HttpCaller.
|
||||
*/
|
||||
public class NegotiateCallbackHandler implements CallbackHandler {
|
||||
|
||||
private String username;
|
||||
private char[] password;
|
||||
|
||||
/**
|
||||
* Authenticator asks for username and password in a single prompt,
|
||||
* but CallbackHandler checks one by one. So, no matter which callback
|
||||
* gets handled first, make sure Authenticator is only called once.
|
||||
*/
|
||||
private boolean answered;
|
||||
|
||||
private final HttpCallerInfo hci;
|
||||
|
||||
public NegotiateCallbackHandler(HttpCallerInfo hci) {
|
||||
this.hci = hci;
|
||||
}
|
||||
|
||||
private void getAnswer() {
|
||||
if (!answered) {
|
||||
answered = true;
|
||||
|
||||
if (LoginConfigImpl.HTTP_USE_GLOBAL_CREDS) {
|
||||
PasswordAuthentication passAuth =
|
||||
Authenticator.requestPasswordAuthentication(
|
||||
hci.host, hci.addr, hci.port, hci.protocol,
|
||||
hci.prompt, hci.scheme, hci.url, hci.authType);
|
||||
/**
|
||||
* To be compatible with existing callback handler implementations,
|
||||
* when the underlying Authenticator is canceled, username and
|
||||
* password are assigned null. No exception is thrown.
|
||||
*/
|
||||
if (passAuth != null) {
|
||||
username = passAuth.getUserName();
|
||||
password = passAuth.getPassword();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(Callback[] callbacks) throws
|
||||
UnsupportedCallbackException, IOException {
|
||||
for (int i=0; i<callbacks.length; i++) {
|
||||
Callback callBack = callbacks[i];
|
||||
|
||||
if (callBack instanceof NameCallback) {
|
||||
getAnswer();
|
||||
((NameCallback)callBack).setName(username);
|
||||
} else if (callBack instanceof PasswordCallback) {
|
||||
getAnswer();
|
||||
((PasswordCallback)callBack).setPassword(password);
|
||||
if (password != null) Arrays.fill(password, ' ');
|
||||
} else {
|
||||
throw new UnsupportedCallbackException(callBack,
|
||||
"Call back not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
159
jdkSrc/jdk8/sun/net/www/protocol/http/spnego/NegotiatorImpl.java
Normal file
159
jdkSrc/jdk8/sun/net/www/protocol/http/spnego/NegotiatorImpl.java
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 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.spnego;
|
||||
|
||||
import com.sun.security.jgss.ExtendedGSSContext;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.ietf.jgss.GSSContext;
|
||||
import org.ietf.jgss.GSSException;
|
||||
import org.ietf.jgss.GSSName;
|
||||
import org.ietf.jgss.Oid;
|
||||
|
||||
import sun.net.www.protocol.http.HttpCallerInfo;
|
||||
import sun.net.www.protocol.http.Negotiator;
|
||||
import sun.security.jgss.GSSManagerImpl;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.HttpCaller;
|
||||
|
||||
/**
|
||||
* This class encapsulates all JAAS and JGSS API calls in a separate class
|
||||
* outside NegotiateAuthentication.java so that J2SE build can go smoothly
|
||||
* without the presence of it.
|
||||
*
|
||||
* @author weijun.wang@sun.com
|
||||
* @since 1.6
|
||||
*/
|
||||
public class NegotiatorImpl extends Negotiator {
|
||||
|
||||
private static final boolean DEBUG =
|
||||
java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetBooleanAction("sun.security.krb5.debug"));
|
||||
|
||||
private GSSContext context;
|
||||
private byte[] oneToken;
|
||||
|
||||
/**
|
||||
* Initialize the object, which includes:<ul>
|
||||
* <li>Find out what GSS mechanism to use from the system property
|
||||
* <code>http.negotiate.mechanism.oid</code>, defaults SPNEGO
|
||||
* <li>Creating the GSSName for the target host, "HTTP/"+hostname
|
||||
* <li>Creating GSSContext
|
||||
* <li>A first call to initSecContext</ul>
|
||||
*/
|
||||
private void init(HttpCallerInfo hci) throws GSSException {
|
||||
final Oid oid;
|
||||
|
||||
if (hci.scheme.equalsIgnoreCase("Kerberos")) {
|
||||
// we can only use Kerberos mech when the scheme is kerberos
|
||||
oid = GSSUtil.GSS_KRB5_MECH_OID;
|
||||
} else {
|
||||
String pref = java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
return System.getProperty(
|
||||
"http.auth.preference",
|
||||
"spnego");
|
||||
}
|
||||
});
|
||||
if (pref.equalsIgnoreCase("kerberos")) {
|
||||
oid = GSSUtil.GSS_KRB5_MECH_OID;
|
||||
} else {
|
||||
// currently there is no 3rd mech we can use
|
||||
oid = GSSUtil.GSS_SPNEGO_MECH_OID;
|
||||
}
|
||||
}
|
||||
|
||||
GSSManagerImpl manager = new GSSManagerImpl(
|
||||
new HttpCaller(hci));
|
||||
|
||||
// RFC 4559 4.1 uses uppercase service name "HTTP".
|
||||
// RFC 4120 6.2.1 demands the host be lowercase
|
||||
String peerName = "HTTP@" + hci.host.toLowerCase();
|
||||
|
||||
GSSName serverName = manager.createName(peerName,
|
||||
GSSName.NT_HOSTBASED_SERVICE);
|
||||
context = manager.createContext(serverName,
|
||||
oid,
|
||||
null,
|
||||
GSSContext.DEFAULT_LIFETIME);
|
||||
|
||||
// Always respect delegation policy in HTTP/SPNEGO.
|
||||
if (context instanceof ExtendedGSSContext) {
|
||||
((ExtendedGSSContext)context).requestDelegPolicy(true);
|
||||
}
|
||||
oneToken = context.initSecContext(new byte[0], 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @throws java.io.IOException If negotiator cannot be constructed
|
||||
*/
|
||||
public NegotiatorImpl(HttpCallerInfo hci) throws IOException {
|
||||
try {
|
||||
init(hci);
|
||||
} catch (GSSException e) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Negotiate support not initiated, will " +
|
||||
"fallback to other scheme if allowed. Reason:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
IOException ioe = new IOException("Negotiate support not initiated");
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first token of GSS, in SPNEGO, it's called NegTokenInit
|
||||
* @return the first token
|
||||
*/
|
||||
@Override
|
||||
public byte[] firstToken() {
|
||||
return oneToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rest tokens of GSS, in SPNEGO, it's called NegTokenTarg
|
||||
* @param token the token received from server
|
||||
* @return the next token
|
||||
* @throws java.io.IOException if the token cannot be created successfully
|
||||
*/
|
||||
@Override
|
||||
public byte[] nextToken(byte[] token) throws IOException {
|
||||
try {
|
||||
return context.initSecContext(token, 0, token.length);
|
||||
} catch (GSSException e) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Negotiate support cannot continue. Reason:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
IOException ioe = new IOException("Negotiate support cannot continue");
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2020, 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 {
|
||||
int readTimeout = getReadTimeout();
|
||||
http = HttpsClient.New (getSSLSocketFactory(),
|
||||
url,
|
||||
getHostnameVerifier(),
|
||||
null,
|
||||
-1,
|
||||
useCache,
|
||||
getConnectTimeout(),
|
||||
this);
|
||||
http.setReadTimeout(readTimeout);
|
||||
((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;
|
||||
int readTimeout = getReadTimeout();
|
||||
http = HttpsClient.New (getSSLSocketFactory(),
|
||||
url,
|
||||
getHostnameVerifier(),
|
||||
proxyHost,
|
||||
proxyPort,
|
||||
useCache,
|
||||
getConnectTimeout(),
|
||||
this);
|
||||
http.setReadTimeout(readTimeout);
|
||||
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 X.509 certificate chain, or null if
|
||||
* the server did not authenticate.
|
||||
*/
|
||||
public javax.security.cert.X509Certificate[] getServerCertificateChain()
|
||||
throws SSLPeerUnverifiedException {
|
||||
if (cachedResponse != null) {
|
||||
throw new UnsupportedOperationException("this method is not supported when using cache");
|
||||
}
|
||||
if (http == null) {
|
||||
throw new IllegalStateException("connection not yet open");
|
||||
} else {
|
||||
return ((HttpsClient)http).getServerCertificateChain ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.https;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
/**
|
||||
* <code>HostnameVerifier</code> provides a callback mechanism so that
|
||||
* implementers of this interface can supply a policy for
|
||||
* handling the case where the host to connect to and
|
||||
* the server name from the certificate mismatch.
|
||||
*
|
||||
* The default implementation will deny such connections.
|
||||
*
|
||||
* @author Xuelei Fan
|
||||
*/
|
||||
final public class DefaultHostnameVerifier implements HostnameVerifier {
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.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.
|
||||
*/
|
||||
protected void dispose() throws Throwable {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
64
jdkSrc/jdk8/sun/net/www/protocol/https/Handler.java
Normal file
64
jdkSrc/jdk8/sun/net/www/protocol/https/Handler.java
Normal 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);
|
||||
}
|
||||
}
|
||||
796
jdkSrc/jdk8/sun/net/www/protocol/https/HttpsClient.java
Normal file
796
jdkSrc/jdk8/sun/net/www/protocol/https/HttpsClient.java
Normal file
@@ -0,0 +1,796 @@
|
||||
/*
|
||||
* 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.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.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
import java.security.AccessController;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import sun.net.www.http.HttpClient;
|
||||
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 = AccessController.doPrivileged(
|
||||
new GetPropertyAction("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 = AccessController.doPrivileged(
|
||||
new GetPropertyAction("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 = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("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() &&
|
||||
"POST".equals(httpuc.getRequestMethod())) {
|
||||
if (!ret.available())
|
||||
ret = null;
|
||||
}
|
||||
|
||||
if (ret != null) {
|
||||
if ((ret.proxy != null && ret.proxy.equals(p)) ||
|
||||
(ret.proxy == null && p == Proxy.NO_PROXY)) {
|
||||
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);
|
||||
} 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 void closeServer() {
|
||||
try {
|
||||
// SSLSocket.close may block up to timeout. Make sure it's short.
|
||||
serverSocket.setSoTimeout(1);
|
||||
} catch (Exception e) {}
|
||||
super.closeServer();
|
||||
}
|
||||
|
||||
@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 X.509 certificate chain with which the server
|
||||
* authenticated itself, or null if the server did not authenticate.
|
||||
*/
|
||||
javax.security.cert.X509Certificate [] getServerCertificateChain()
|
||||
throws SSLPeerUnverifiedException
|
||||
{
|
||||
return session.getPeerCertificateChain();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.net.MalformedURLException;
|
||||
import java.io.*;
|
||||
import javax.net.ssl.*;
|
||||
import java.security.Permission;
|
||||
import java.security.Principal;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
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);
|
||||
}
|
||||
|
||||
static URL checkURL(URL u) throws IOException {
|
||||
if (u != null) {
|
||||
if (u.toExternalForm().indexOf('\n') > -1) {
|
||||
throw new MalformedURLException("Illegal character in URL");
|
||||
}
|
||||
}
|
||||
String s = IPAddressUtil.checkAuthority(u);
|
||||
if (s != null) {
|
||||
throw new MalformedURLException(s);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
// 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(checkURL(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 server's X.509 certificate chain, or null if
|
||||
* the server did not authenticate.
|
||||
*
|
||||
* NOTE: This method is not necessary for the version of this class
|
||||
* implementing javax.net.ssl.HttpsURLConnection, but provided for
|
||||
* compatibility with the com.sun.net.ssl.HttpsURLConnection version.
|
||||
*/
|
||||
public javax.security.cert.X509Certificate[] getServerCertificateChain() {
|
||||
try {
|
||||
return delegate.getServerCertificateChain();
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
// this method does not throw an exception as declared in
|
||||
// com.sun.net.ssl.HttpsURLConnection.
|
||||
// Return null for compatibility.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 #getRequestProperty(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.
|
||||
*/
|
||||
protected void finalize() throws Throwable {
|
||||
delegate.dispose();
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
return delegate.equals(obj);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
222
jdkSrc/jdk8/sun/net/www/protocol/jar/Handler.java
Normal file
222
jdkSrc/jdk8/sun/net/www/protocol/jar/Handler.java
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2019, 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;
|
||||
}
|
||||
|
||||
public String checkNestedProtocol(String spec) {
|
||||
if (spec.regionMatches(true, 0, "jar:", 0, 4)) {
|
||||
return "Nested JAR URLs are not supported";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
String exceptionMessage = checkNestedProtocol(spec);
|
||||
if (exceptionMessage != null) {
|
||||
// NPE will be transformed into MalformedURLException by the caller
|
||||
throw new NullPointerException(exceptionMessage);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
173
jdkSrc/jdk8/sun/net/www/protocol/jar/JarFileFactory.java
Normal file
173
jdkSrc/jdk8/sun/net/www/protocol/jar/JarFileFactory.java
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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.protocol.jar;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.HashMap;
|
||||
import java.util.jar.JarFile;
|
||||
import java.security.Permission;
|
||||
import sun.net.util.URLUtil;
|
||||
|
||||
/* A factory for cached JAR file. This class is used to both retrieve
|
||||
* and cache Jar files.
|
||||
*
|
||||
* @author Benjamin Renaud
|
||||
* @since JDK1.2
|
||||
*/
|
||||
class JarFileFactory implements URLJarFile.URLJarFileCloseController {
|
||||
|
||||
/* the url to file cache */
|
||||
private static final HashMap<String, JarFile> fileCache = new HashMap<>();
|
||||
|
||||
/* the file to url cache */
|
||||
private static final HashMap<JarFile, URL> urlCache = new HashMap<>();
|
||||
|
||||
private static final JarFileFactory instance = new JarFileFactory();
|
||||
|
||||
private JarFileFactory() { }
|
||||
|
||||
public static JarFileFactory getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
URLConnection getConnection(JarFile jarFile) throws IOException {
|
||||
URL u;
|
||||
synchronized (instance) {
|
||||
u = urlCache.get(jarFile);
|
||||
}
|
||||
if (u != null)
|
||||
return u.openConnection();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public JarFile get(URL url) throws IOException {
|
||||
return get(url, true);
|
||||
}
|
||||
|
||||
JarFile get(URL url, boolean useCaches) throws IOException {
|
||||
if (url.getProtocol().equalsIgnoreCase("file")) {
|
||||
// Deal with UNC pathnames specially. See 4180841
|
||||
|
||||
String host = url.getHost();
|
||||
if (host != null && !host.equals("") &&
|
||||
!host.equalsIgnoreCase("localhost")) {
|
||||
|
||||
url = new URL("file", "", "//" + host + url.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
JarFile result;
|
||||
JarFile local_result;
|
||||
|
||||
if (useCaches) {
|
||||
synchronized (instance) {
|
||||
result = getCachedJarFile(url);
|
||||
}
|
||||
if (result == null) {
|
||||
local_result = URLJarFile.getJarFile(url, this);
|
||||
synchronized (instance) {
|
||||
result = getCachedJarFile(url);
|
||||
if (result == null) {
|
||||
fileCache.put(URLUtil.urlNoFragString(url), local_result);
|
||||
urlCache.put(local_result, url);
|
||||
result = local_result;
|
||||
} else {
|
||||
if (local_result != null) {
|
||||
local_result.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = URLJarFile.getJarFile(url, this);
|
||||
}
|
||||
if (result == null)
|
||||
throw new FileNotFoundException(url.toString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method of the URLJarFileCloseController to
|
||||
* indicate that the JarFile is close. This way we can
|
||||
* remove the JarFile from the cache
|
||||
*/
|
||||
public void close(JarFile jarFile) {
|
||||
synchronized (instance) {
|
||||
URL urlRemoved = urlCache.remove(jarFile);
|
||||
if (urlRemoved != null)
|
||||
fileCache.remove(URLUtil.urlNoFragString(urlRemoved));
|
||||
}
|
||||
}
|
||||
|
||||
private JarFile getCachedJarFile(URL url) {
|
||||
assert Thread.holdsLock(instance);
|
||||
JarFile result = fileCache.get(URLUtil.urlNoFragString(url));
|
||||
|
||||
/* if the JAR file is cached, the permission will always be there */
|
||||
if (result != null) {
|
||||
Permission perm = getPermission(result);
|
||||
if (perm != null) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
try {
|
||||
sm.checkPermission(perm);
|
||||
} catch (SecurityException se) {
|
||||
// fallback to checkRead/checkConnect for pre 1.2
|
||||
// security managers
|
||||
if ((perm instanceof java.io.FilePermission) &&
|
||||
perm.getActions().indexOf("read") != -1) {
|
||||
sm.checkRead(perm.getName());
|
||||
} else if ((perm instanceof
|
||||
java.net.SocketPermission) &&
|
||||
perm.getActions().indexOf("connect") != -1) {
|
||||
sm.checkConnect(url.getHost(), url.getPort());
|
||||
} else {
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Permission getPermission(JarFile jarFile) {
|
||||
try {
|
||||
URLConnection uc = getConnection(jarFile);
|
||||
if (uc != null)
|
||||
return uc.getPermission();
|
||||
} catch (IOException ioe) {
|
||||
// gulp
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
376
jdkSrc/jdk8/sun/net/www/protocol/jar/JarURLConnection.java
Normal file
376
jdkSrc/jdk8/sun/net/www/protocol/jar/JarURLConnection.java
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* 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();
|
||||
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 value 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();
|
||||
}
|
||||
}
|
||||
286
jdkSrc/jdk8/sun/net/www/protocol/jar/URLJarFile.java
Normal file
286
jdkSrc/jdk8/sun/net/www/protocol/jar/URLJarFile.java
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 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.*;
|
||||
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))
|
||||
return new URLJarFile(url, closeController);
|
||||
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(URL url, URLJarFileCloseController closeController) throws IOException {
|
||||
super(ParseUtil.decode(url.getFile()));
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* close the jar file.
|
||||
*/
|
||||
protected void finalize() throws IOException {
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) throws IOException {
|
||||
return retrieve(url, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/* get the stream before asserting privileges */
|
||||
try (final InputStream in = url.openConnection().getInputStream()) {
|
||||
result = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<JarFile>() {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
39
jdkSrc/jdk8/sun/net/www/protocol/jar/URLJarFileCallBack.java
Normal file
39
jdkSrc/jdk8/sun/net/www/protocol/jar/URLJarFileCallBack.java
Normal 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;
|
||||
}
|
||||
158
jdkSrc/jdk8/sun/net/www/protocol/mailto/Handler.java
Normal file
158
jdkSrc/jdk8/sun/net/www/protocol/mailto/Handler.java
Normal 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);
|
||||
}
|
||||
}
|
||||
140
jdkSrc/jdk8/sun/net/www/protocol/mailto/MailToURLConnection.java
Normal file
140
jdkSrc/jdk8/sun/net/www/protocol/mailto/MailToURLConnection.java
Normal 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;
|
||||
}
|
||||
}
|
||||
98
jdkSrc/jdk8/sun/net/www/protocol/netdoc/Handler.java
Normal file
98
jdkSrc/jdk8/sun/net/www/protocol/netdoc/Handler.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 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.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* netdoc urls point either into the local filesystem or externally
|
||||
* through an http url, with network documents being preferred. Useful for
|
||||
* FAQs & other documents which are likely to be changing over time at the
|
||||
* central site, and where the user will want the most recent edition.
|
||||
*
|
||||
* @author Steven B. Byrne
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.netdoc;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Handler extends URLStreamHandler {
|
||||
static URL base;
|
||||
|
||||
/*
|
||||
* Attempt to find a load the given url using the default (network)
|
||||
* documentation location. If that fails, use the local copy
|
||||
*/
|
||||
public synchronized URLConnection openConnection(URL u)
|
||||
throws IOException
|
||||
{
|
||||
URLConnection uc = null;
|
||||
URL ru;
|
||||
|
||||
Boolean tmp = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetBooleanAction("newdoc.localonly"));
|
||||
boolean localonly = tmp.booleanValue();
|
||||
|
||||
String docurl = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("doc.url"));
|
||||
|
||||
String file = u.getFile();
|
||||
if (!localonly) {
|
||||
try {
|
||||
if (base == null) {
|
||||
base = new URL(docurl);
|
||||
}
|
||||
ru = new URL(base, file);
|
||||
} catch (MalformedURLException e) {
|
||||
ru = null;
|
||||
}
|
||||
if (ru != null) {
|
||||
uc = ru.openConnection();
|
||||
}
|
||||
}
|
||||
|
||||
if (uc == null) {
|
||||
try {
|
||||
ru = new URL("file", "~", file);
|
||||
|
||||
uc = ru.openConnection();
|
||||
InputStream is = uc.getInputStream(); // Check for success.
|
||||
} catch (MalformedURLException e) {
|
||||
uc = null;
|
||||
} catch (IOException e) {
|
||||
uc = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (uc == null) {
|
||||
throw new IOException("Can't find file for URL: "
|
||||
+u.toExternalForm());
|
||||
}
|
||||
return uc;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user