Merge "MethodHandles: Unhide java.lang.invoke.*"
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index a9b7675..209e70c 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -210,8 +210,10 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
core-test-rules \
core-tests-support \
+ mockftpserver \
mockwebserver \
nist-pkix-tests \
+ slf4j-jdk14 \
sqlite-jdbc \
tzdata-testing
LOCAL_JAVACFLAGS := $(local_javac_flags)
@@ -376,8 +378,10 @@
okhttp-hostdex
LOCAL_STATIC_JAVA_LIBRARIES := \
core-test-rules-hostdex \
+ mockftpserver-hostdex \
mockwebserver-host \
nist-pkix-tests-host \
+ slf4j-jdk14-hostdex \
sqlite-jdbc-host \
tzdata-testing-hostdex
LOCAL_JAVACFLAGS := $(local_javac_flags)
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
index 7523752..bb9e806 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
@@ -968,4 +968,28 @@
ds.close();
assertEquals(new String("01234"), new String(recvBuffer, 0, recvBuffer.length, "UTF-8"));
}
+
+ // Receive twice reusing the same DatagramPacket.
+ // http://b/33957878
+ public void testReceiveTwice() throws Exception {
+ try (DatagramSocket ds = new DatagramSocket();
+ DatagramSocket sds = new DatagramSocket()) {
+ sds.connect(ds.getLocalSocketAddress());
+ DatagramPacket p = new DatagramPacket(new byte[16], 16);
+
+ byte[] smallPacketBytes = "01234".getBytes("UTF-8");
+ DatagramPacket smallPacket =
+ new DatagramPacket(smallPacketBytes, smallPacketBytes.length);
+ sds.send(smallPacket);
+ ds.receive(p);
+ assertPacketDataEquals(smallPacket, p);
+
+ byte[] largePacketBytes = "0123456789".getBytes("UTF-8");
+ DatagramPacket largerPacket =
+ new DatagramPacket(largePacketBytes, largePacketBytes.length);
+ sds.send(largerPacket);
+ ds.receive(p);
+ assertPacketDataEquals(largerPacket, p);
+ }
+ }
}
diff --git a/luni/src/main/java/libcore/io/IoBridge.java b/luni/src/main/java/libcore/io/IoBridge.java
index fb348bc..0c34d5e 100644
--- a/luni/src/main/java/libcore/io/IoBridge.java
+++ b/luni/src/main/java/libcore/io/IoBridge.java
@@ -35,6 +35,7 @@
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.PortUnreachableException;
+import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketOptions;
import java.net.SocketTimeoutException;
@@ -97,7 +98,12 @@
try {
Libcore.os.bind(fd, address, port);
} catch (ErrnoException errnoException) {
- throw new BindException(errnoException.getMessage(), errnoException);
+ if (errnoException.errno == EADDRINUSE || errnoException.errno == EADDRNOTAVAIL ||
+ errnoException.errno == EPERM || errnoException.errno == EACCES) {
+ throw new BindException(errnoException.getMessage(), errnoException);
+ } else {
+ throw new SocketException(errnoException.getMessage(), errnoException);
+ }
}
}
@@ -285,15 +291,14 @@
private static Object getSocketOptionErrno(FileDescriptor fd, int option) throws ErrnoException, SocketException {
switch (option) {
case SocketOptions.IP_MULTICAST_IF:
- // This is IPv4-only.
- return Libcore.os.getsockoptInAddr(fd, IPPROTO_IP, IP_MULTICAST_IF);
case SocketOptions.IP_MULTICAST_IF2:
- // This is IPv6-only.
return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF);
case SocketOptions.IP_MULTICAST_LOOP:
// Since setting this from java.net always sets IPv4 and IPv6 to the same value,
// it doesn't matter which we return.
- return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP));
+ // NOTE: getsockopt's return value means "isEnabled", while OpenJDK code java.net
+ // requires a value that means "isDisabled" so we NEGATE the system call value here.
+ return !booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP));
case IoBridge.JAVA_IP_MULTICAST_TTL:
// Since setting this from java.net always sets IPv4 and IPv6 to the same value,
// it doesn't matter which we return.
@@ -328,6 +333,8 @@
return (int) Libcore.os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO).toMillis();
case SocketOptions.TCP_NODELAY:
return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY));
+ case SocketOptions.SO_BINDADDR:
+ return ((InetSocketAddress) Libcore.os.getsockname(fd)).getAddress();
default:
throw new SocketException("Unknown socket option: " + option);
}
@@ -356,7 +363,15 @@
private static void setSocketOptionErrno(FileDescriptor fd, int option, Object value) throws ErrnoException, SocketException {
switch (option) {
case SocketOptions.IP_MULTICAST_IF:
- throw new UnsupportedOperationException("Use IP_MULTICAST_IF2 on Android");
+ NetworkInterface nif = NetworkInterface.getByInetAddress((InetAddress) value);
+ if (nif == null) {
+ throw new SocketException(
+ "bad argument for IP_MULTICAST_IF : address not bound to any interface");
+ }
+ // Although IPv6 was cleaned up to use int, IPv4 uses an ip_mreqn containing an int.
+ Libcore.os.setsockoptIpMreqn(fd, IPPROTO_IP, IP_MULTICAST_IF, nif.getIndex());
+ Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, nif.getIndex());
+ return;
case SocketOptions.IP_MULTICAST_IF2:
// Although IPv6 was cleaned up to use int, IPv4 uses an ip_mreqn containing an int.
Libcore.os.setsockoptIpMreqn(fd, IPPROTO_IP, IP_MULTICAST_IF, (Integer) value);
@@ -364,8 +379,11 @@
return;
case SocketOptions.IP_MULTICAST_LOOP:
// Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte.
- Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_LOOP, booleanToInt((Boolean) value));
- Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, booleanToInt((Boolean) value));
+ // NOTE: setsockopt's arguement value means "isEnabled", while OpenJDK code java.net
+ // uses a value that means "isDisabled" so we NEGATE the system call value here.
+ int enable = booleanToInt(!((Boolean) value));
+ Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_LOOP, enable);
+ Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, enable);
return;
case IoBridge.JAVA_IP_MULTICAST_TTL:
// Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int,
@@ -562,10 +580,11 @@
return result;
}
- private static int maybeThrowAfterSendto(boolean isDatagram, ErrnoException errnoException) throws SocketException {
+ private static int maybeThrowAfterSendto(boolean isDatagram, ErrnoException errnoException)
+ throws IOException {
if (isDatagram) {
- if (errnoException.errno == ECONNRESET || errnoException.errno == ECONNREFUSED) {
- return 0;
+ if (errnoException.errno == ECONNREFUSED) {
+ throw new PortUnreachableException("ICMP Port Unreachable");
}
} else {
if (errnoException.errno == EAGAIN) {
@@ -574,7 +593,7 @@
return 0;
}
}
- throw errnoException.rethrowAsSocketException();
+ throw errnoException.rethrowAsIOException();
}
public static int recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
@@ -607,8 +626,12 @@
}
if (packet != null) {
packet.setReceivedLength(byteCount);
- packet.setAddress(srcAddress.getAddress());
packet.setPort(srcAddress.getPort());
+
+ // packet.address should only be changed when it is different from srcAddress.
+ if (!srcAddress.getAddress().equals(packet.getAddress())) {
+ packet.setAddress(srcAddress.getAddress());
+ }
}
return byteCount;
}
@@ -622,7 +645,7 @@
}
} else {
if (isConnected && errnoException.errno == ECONNREFUSED) {
- throw new PortUnreachableException("", errnoException);
+ throw new PortUnreachableException("ICMP Port Unreachable", errnoException);
} else if (errnoException.errno == EAGAIN) {
throw new SocketTimeoutException(errnoException);
} else {
diff --git a/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java b/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java
new file mode 100644
index 0000000..1e0c7b9
--- /dev/null
+++ b/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.java.net;
+
+import junit.framework.TestCase;
+
+import org.mockftpserver.core.util.IoUtil;
+import org.mockftpserver.fake.FakeFtpServer;
+import org.mockftpserver.fake.UserAccount;
+import org.mockftpserver.fake.filesystem.DirectoryEntry;
+import org.mockftpserver.fake.filesystem.FileEntry;
+import org.mockftpserver.fake.filesystem.UnixFakeFileSystem;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * Tests URLConnections for ftp:// URLs.
+ */
+public class FtpURLConnectionTest extends TestCase {
+
+ private static final String FILE_PATH = "test/file/for/FtpURLConnectionTest.txt";
+ private static final String USER = "user";
+ private static final String PASSWORD = "password";
+ private static final String SERVER_HOSTNAME = "localhost";
+ private static final String USER_HOME_DIR = "/home/user";
+
+ private FakeFtpServer fakeFtpServer;
+ private UnixFakeFileSystem fileSystem;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ fakeFtpServer = new FakeFtpServer();
+ fakeFtpServer.setServerControlPort(0 /* allocate port number automatically */);
+ fakeFtpServer.addUserAccount(new UserAccount(USER, PASSWORD, USER_HOME_DIR));
+ fileSystem = new UnixFakeFileSystem();
+ fakeFtpServer.setFileSystem(fileSystem);
+ fileSystem.add(new DirectoryEntry(USER_HOME_DIR));
+ fakeFtpServer.start();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ fakeFtpServer.stop();
+ super.tearDown();
+ }
+
+ public void testInputUrl() throws Exception {
+ byte[] fileContents = "abcdef 1234567890".getBytes(UTF_8);
+ URL fileUrl = addFileEntry(FILE_PATH, fileContents);
+ URLConnection connection = fileUrl.openConnection();
+ assertContents(fileContents, connection.getInputStream());
+ }
+
+ public void testOutputUrl() throws Exception {
+ byte[] fileContents = "abcdef 1234567890".getBytes(UTF_8);
+ addFileEntry("test/output-url/existing file.txt", fileContents);
+ byte[] newFileContents = "contents of brand new file".getBytes(UTF_8);
+ String filePath = "test/output-url/file that is newly created.txt";
+ URL fileUrl = new URL(getFileUrlString(filePath));
+ URLConnection connection = fileUrl.openConnection();
+ connection.setDoInput(false);
+ connection.setDoOutput(true);
+ OutputStream os = connection.getOutputStream();
+ writeBytes(os, newFileContents);
+
+ assertContents(newFileContents, openFileSystemContents(filePath));
+ }
+
+ public void testConnectOverProxy_noProxy() throws Exception {
+ Proxy proxy = Proxy.NO_PROXY;
+ byte[] fileContents = "abcdef 1234567890".getBytes(UTF_8);
+ URL fileUrl = addFileEntry(FILE_PATH, fileContents);
+ URLConnection connection = fileUrl.openConnection(proxy);
+ assertContents(fileContents, connection.getInputStream());
+ // Sanity check that NO_PROXY covers the Type.DIRECT case
+ assertEquals(Proxy.Type.DIRECT, proxy.type());
+ }
+
+ /**
+ * Tests that the helper class {@link CountingProxy} correctly accepts and
+ * counts connection attempts to the address represented by {@code asProxy()}.
+ */
+ public void testCountingProxy() throws Exception {
+ CountingProxy countingProxy = CountingProxy.start();
+ try {
+ Proxy proxy = countingProxy.asProxy();
+ assertEquals(Proxy.Type.HTTP, proxy.type());
+ SocketAddress address = proxy.address();
+ Socket socket = new Socket();
+ socket.connect(address, /* timeout (msec) */ 10); // attempt one connection
+ socket.close();
+ } finally {
+ int numConnections = countingProxy.shutdownAndGetConnectionCount();
+ assertEquals(1, numConnections);
+ }
+ }
+
+ /**
+ * Tests that a HTTP proxy explicitly passed to {@link URL#openConnection(Proxy)}
+ * ignores HTTP proxies (since it doesn't support them) and attempts a direct
+ * connection instead.
+ */
+ public void testConnectOverProxy_explicit_http_uses_direct_connection() throws Exception {
+ byte[] fileContents = "abcdef 1234567890".getBytes(UTF_8);
+ URL fileUrl = addFileEntry(FILE_PATH, fileContents);
+ CountingProxy countingProxy = CountingProxy.start();
+ final int numConnections;
+ try {
+ Proxy proxy = countingProxy.asProxy();
+ URLConnection connection = fileUrl.openConnection(proxy);
+ // direct connection succeeds
+ assertContents(fileContents, connection.getInputStream());
+ } finally {
+ numConnections = countingProxy.shutdownAndGetConnectionCount();
+ }
+ assertEquals(0, numConnections);
+ }
+
+ /**
+ * Tests that if a ProxySelector is set, any HTTP proxies selected for
+ * ftp:// URLs will be rejected. A direct connection will
+ * be selected once the ProxySelector's proxies have failed.
+ */
+ public void testConnectOverProxy_implicit_http_fails() throws Exception {
+ byte[] fileContents = "abcdef 1234567890".getBytes(UTF_8);
+ URL fileUrl = addFileEntry(FILE_PATH, fileContents);
+ ProxySelector defaultProxySelector = ProxySelector.getDefault();
+ try {
+ CountingProxy countingProxy = CountingProxy.start();
+ try {
+ Proxy proxy = countingProxy.asProxy();
+ SingleProxySelector proxySelector = new SingleProxySelector(proxy);
+ ProxySelector.setDefault(proxySelector);
+ URLConnection connection = fileUrl.openConnection();
+ InputStream inputStream = connection.getInputStream();
+
+ IOException e = proxySelector.getLastException();
+ assertEquals("FTP connections over HTTP proxy not supported",
+ e.getMessage());
+
+ // The direct connection is successful
+ assertContents(fileContents, inputStream);
+ } finally {
+ int numConnections = countingProxy.shutdownAndGetConnectionCount();
+ assertEquals(0, numConnections);
+ }
+ } finally {
+ ProxySelector.setDefault(defaultProxySelector);
+ }
+ }
+
+ public void testInputUrlWithSpaces() throws Exception {
+ byte[] fileContents = "abcdef 1234567890".getBytes(UTF_8);
+ URL url = addFileEntry("file with spaces.txt", fileContents);
+ URLConnection connection = url.openConnection();
+ assertContents(fileContents, connection.getInputStream());
+ }
+
+ public void testBinaryFileContents() throws Exception {
+ byte[] data = new byte[4096];
+ new Random(31337).nextBytes(data); // arbitrary pseudo-random but repeatable test data
+ URL url = addFileEntry("binaryfile.dat", data.clone());
+ assertContents(data, url.openConnection().getInputStream());
+ }
+
+ // https://code.google.com/p/android/issues/detail?id=160725
+ public void testInputUrlWithSpacesViaProxySelector() throws Exception {
+ byte[] fileContents = "abcdef 1234567890".getBytes(UTF_8);
+ ProxySelector defaultProxySelector = ProxySelector.getDefault();
+ try {
+ SingleProxySelector proxySelector = new SingleProxySelector(Proxy.NO_PROXY);
+ ProxySelector.setDefault(proxySelector);
+ URL url = addFileEntry("file with spaces.txt", fileContents);
+ assertContents(fileContents, url.openConnection().getInputStream());
+ assertNull(proxySelector.getLastException());
+ } finally {
+ ProxySelector.setDefault(defaultProxySelector);
+ }
+ }
+
+ private InputStream openFileSystemContents(String fileName) throws IOException {
+ String fullFileName = USER_HOME_DIR + "/" + fileName;
+ FileEntry entry = (FileEntry) fileSystem.getEntry(fullFileName);
+ assertNotNull("File must exist with name " + fullFileName, entry);
+ return entry.createInputStream();
+ }
+
+ private static void writeBytes(OutputStream os, byte[] fileContents) throws IOException {
+ os.write(fileContents);
+ os.close();
+ }
+
+ private static void assertContents(byte[] expectedContents, InputStream inputStream)
+ throws IOException {
+ try {
+ byte[] contentBytes = IoUtil.readBytes(inputStream);
+ if (!Arrays.equals(expectedContents, contentBytes)) {
+ // optimize the error message for the case of the content being character data
+ fail("Expected " + new String(expectedContents, UTF_8) + ", but got "
+ + new String(contentBytes, UTF_8));
+ }
+ } finally {
+ inputStream.close();
+ }
+ }
+
+ private String getFileUrlString(String filePath) {
+ int serverPort = fakeFtpServer.getServerControlPort();
+ String urlString = String.format(Locale.US, "ftp://%s:%s@%s:%s/%s",
+ USER, PASSWORD, SERVER_HOSTNAME, serverPort, filePath);
+ return urlString;
+ }
+
+ private URL addFileEntry(String filePath, byte[] fileContents) {
+ FileEntry fileEntry = new FileEntry(USER_HOME_DIR + "/" + filePath);
+ fileEntry.setContents(fileContents);
+ fileSystem.add(fileEntry);
+ String urlString = getFileUrlString(filePath);
+ try {
+ return new URL(urlString);
+ } catch (MalformedURLException e) {
+ fail("Malformed URL: " + urlString);
+ throw new AssertionError("Can never happen");
+ }
+ }
+
+ /**
+ * A {@link ProxySelector} that selects the same (given) Proxy for all URIs.
+ */
+ static class SingleProxySelector extends ProxySelector {
+ private final Proxy proxy;
+ private IOException lastException = null;
+
+ public SingleProxySelector(Proxy proxy) {
+ this.proxy = proxy;
+ }
+
+ @Override
+ public List<Proxy> select(URI uri) {
+ assertNotNull(uri);
+ return Collections.singletonList(proxy);
+ }
+
+ @Override
+ public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
+ lastException = ioe;
+ }
+
+ public IOException getLastException() {
+ return lastException;
+ }
+ }
+
+ /**
+ * Counts the number of attempts to connect to a ServerSocket exposed
+ * {@link #asProxy() as a Proxy}. From {@link #start()} until
+ * {@link #shutdownAndGetConnectionCount()}, a background server thread
+ * accepts and counts connections on the socket but immediately closes
+ * them without reading any data.
+ */
+ static class CountingProxy {
+ class ServerThread extends Thread {
+ public ServerThread(String name) {
+ super(name);
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ try {
+ Socket socket = serverSocket.accept();
+ connectionAttempts.incrementAndGet();
+ socket.close();
+ } catch (SocketException e) {
+ shutdownLatch.countDown();
+ return;
+ } catch (IOException e) {
+ // retry, unless shutdownLatch has reached 0
+ }
+ }
+ }
+ }
+
+ // Signals that serverThread has gracefully completed shutdown (not crashed)
+ private final CountDownLatch shutdownLatch = new CountDownLatch(1);
+ private final ServerSocket serverSocket;
+ private final Proxy proxy;
+ private final Thread serverThread;
+ private final AtomicInteger connectionAttempts = new AtomicInteger(0);
+
+ private CountingProxy() throws IOException {
+ serverSocket = new ServerSocket(0 /* allocate port number automatically */);
+ SocketAddress socketAddress = serverSocket.getLocalSocketAddress();
+ proxy = new Proxy(Proxy.Type.HTTP, socketAddress);
+ String threadName = getClass().getSimpleName() + " @ " +
+ serverSocket.getLocalSocketAddress();
+ serverThread = new ServerThread(threadName);
+ }
+
+ public static CountingProxy start() throws IOException {
+ CountingProxy result = new CountingProxy();
+ // only start the thread once the object has been properly constructed
+ result.serverThread.start();
+ return result;
+ }
+
+ /**
+ * Returns the HTTP {@link Proxy} that can represents the ServerSocket
+ * connections to which this class manages/counts.
+ */
+ public Proxy asProxy() {
+ return proxy;
+ }
+
+ /**
+ * Causes the ServerSocket represented by {@link #asProxy()} to stop accepting
+ * connections by shutting down the server thread.
+ *
+ * @return the number of connections that were attempted during the proxy's lifetime
+ */
+ public int shutdownAndGetConnectionCount() throws IOException, InterruptedException {
+ try {
+ serverSocket.close();
+ // Check that the server shuts down quickly and gracefully via the expected
+ // code path (as opposed to an uncaught exception).
+ shutdownLatch.await(1, TimeUnit.SECONDS);
+ serverThread.join(1000);
+ assertFalse("serverThread failed to shut down quickly", serverThread.isAlive());
+ } finally {
+ return connectionAttempts.get();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return serverThread.toString() ;
+ }
+ }
+
+}
diff --git a/luni/src/test/java/libcore/java/util/DateTest.java b/luni/src/test/java/libcore/java/util/DateTest.java
index d807007..6185f12 100644
--- a/luni/src/test/java/libcore/java/util/DateTest.java
+++ b/luni/src/test/java/libcore/java/util/DateTest.java
@@ -16,6 +16,7 @@
package libcore.java.util;
+import java.time.Instant;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
@@ -77,6 +78,84 @@
assertEquals(
Date.parse("Wed, 06 Jan 2016 11:55:59 GMT+05:00"),
Date.parse("Wed, 06 Jan 2016 11:55:59 GMT+05"));
+ }
+ /**
+ * The minimum long value below which {@link Instant#toEpochMilli()} will
+ * throw is not clearly documented. This test discovers if that minimum
+ * value ever changes, and also checks that it is also the minimum Instant
+ * (at a millisecond boundary) that can be converted to a Date.
+ */
+ public void test_convertFromInstant_lowerBound() {
+ // smallest millisecond Instant that can be converted to Date
+ long minConvertible = -9223372036854775000L;
+
+ // show that this value is < 1 sec away from Long.MIN_VALUE
+ assertEquals(Long.MIN_VALUE + 808, minConvertible);
+
+ Instant inBound = Instant.ofEpochMilli(minConvertible);
+ assertEquals(new Date(minConvertible), Date.from(inBound));
+ assertEquals(minConvertible, inBound.toEpochMilli());
+
+ Instant outOfBound = Instant.ofEpochMilli(minConvertible - 1);
+ try {
+ Date.from(outOfBound);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ assertEquals(ArithmeticException.class, expected.getCause().getClass());
+ }
+
+ try {
+ outOfBound.toEpochMilli();
+ fail();
+ } catch (ArithmeticException expected) {
+
+ }
+ }
+
+ public void test_convertFromInstant_upperBound() {
+ Date.from(Instant.ofEpochMilli(Long.MAX_VALUE));
+
+ Date.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 0));
+ Date.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 999999999));
+ Instant outOfBound = Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1, 0);
+ try {
+ Date.from(outOfBound);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ assertEquals(ArithmeticException.class, expected.getCause().getClass());
+ }
+ }
+
+ /**
+ * Checks conversion between long, Date and Instant.
+ */
+ public void test_convertToInstantAndBack() {
+ check_convertToInstantAndBack(0);
+ check_convertToInstantAndBack(-1);
+ check_convertToInstantAndBack( 999999999);
+ check_convertToInstantAndBack(1000000000);
+ check_convertToInstantAndBack(1000000001);
+ check_convertToInstantAndBack(1000000002);
+ check_convertToInstantAndBack(1000000499);
+ check_convertToInstantAndBack(1000000500);
+ check_convertToInstantAndBack(1000000999);
+ check_convertToInstantAndBack(1000001000);
+ check_convertToInstantAndBack(Long.MIN_VALUE + 808); // minimum ofEpochMilli argument
+ check_convertToInstantAndBack(Long.MAX_VALUE);
+ check_convertToInstantAndBack(System.currentTimeMillis());
+ check_convertToInstantAndBack(Date.parse("Wed, 06 Jan 2016 11:55:59 GMT+0500"));
+ }
+
+ private static void check_convertToInstantAndBack(long millis) {
+ Date date = new Date(millis);
+ Instant instant = date.toInstant();
+ assertEquals(date, Date.from(instant));
+
+ assertEquals(instant, Instant.ofEpochMilli(millis));
+ assertEquals("Millis should be a millions of nanos", 0, instant.getNano() % 1000000);
+
+ assertEquals(millis, date.getTime());
+ assertEquals(millis, instant.toEpochMilli());
}
}
diff --git a/ojluni/src/main/java/java/net/DatagramPacket.java b/ojluni/src/main/java/java/net/DatagramPacket.java
index 1ce7cad..fcdfb1c 100644
--- a/ojluni/src/main/java/java/net/DatagramPacket.java
+++ b/ojluni/src/main/java/java/net/DatagramPacket.java
@@ -43,12 +43,13 @@
public final
class DatagramPacket {
- /**
- * Perform class initialization
- */
- static {
- init();
- }
+ // Android-removed: init method has been removed
+ // /**
+ // * Perform class initialization
+ // */
+ // static {
+ // init();
+ // }
/*
* The fields of this class are package-private since DatagramSocketImpl
@@ -385,8 +386,9 @@
this.bufLength = this.length;
}
- /**
- * Perform class load-time initializations.
- */
- private native static void init();
+ // Android-removed: JNI has been removed
+ // /**
+ // * Perform class load-time initializations.
+ // */
+ // private native static void init();
}
diff --git a/ojluni/src/main/java/java/net/PlainDatagramSocketImpl.java b/ojluni/src/main/java/java/net/PlainDatagramSocketImpl.java
index ea45500..c6a44d5 100644
--- a/ojluni/src/main/java/java/net/PlainDatagramSocketImpl.java
+++ b/ojluni/src/main/java/java/net/PlainDatagramSocketImpl.java
@@ -24,11 +24,27 @@
*/
package java.net;
+import android.system.ErrnoException;
+import android.system.StructGroupReq;
+
import java.io.IOException;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.Collections;
+import libcore.io.IoBridge;
+import libcore.io.Libcore;
+import libcore.util.EmptyArray;
+
import jdk.net.*;
+
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNSPEC;
+import static android.system.OsConstants.IPPROTO_IP;
+import static android.system.OsConstants.IP_MULTICAST_ALL;
+import static android.system.OsConstants.MSG_PEEK;
+import static android.system.OsConstants.POLLERR;
+import static android.system.OsConstants.POLLIN;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static libcore.io.IoBridge.JAVA_IP_MULTICAST_TTL;
+import static libcore.io.IoBridge.JAVA_MCAST_JOIN_GROUP;
+import static libcore.io.IoBridge.JAVA_MCAST_LEAVE_GROUP;
import static sun.net.ExtendedOptionsImpl.*;
/*
@@ -39,9 +55,10 @@
class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
{
- static {
- init();
- }
+ // Android-removed: init method has been removed
+ // static {
+ // init();
+ // }
protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
@@ -78,47 +95,160 @@
}
}
- protected synchronized native void bind0(int lport, InetAddress laddr)
- throws SocketException;
+ protected synchronized void bind0(int lport, InetAddress laddr) throws SocketException {
+ if (isClosed()) {
+ throw new SocketException("Socket closed");
+ }
- protected native void send(DatagramPacket p) throws IOException;
+ IoBridge.bind(fd, laddr, lport);
- protected synchronized native int peek(InetAddress i) throws IOException;
+ if (lport == 0) {
+ // Now that we're a connected socket, let's extract the port number that the system
+ // chose for us and store it in the Socket object.
+ localPort = IoBridge.getLocalInetSocketAddress(fd).getPort();
+ } else {
+ localPort = lport;
+ }
+ }
- protected synchronized native int peekData(DatagramPacket p) throws IOException;
+ protected void send(DatagramPacket p) throws IOException {
+ if (isClosed()) {
+ throw new SocketException("Socket closed");
+ }
+ if (p.getData() == null || p.getAddress() == null) {
+ throw new NullPointerException("null buffer || null address");
+ }
- protected synchronized native void receive0(DatagramPacket p)
- throws IOException;
+ int port = connected ? 0 : p.getPort();
+ InetAddress address = connected ? null : p.getAddress();
+ IoBridge.sendto(fd, p.getData(), p.getOffset(), p.getLength(), 0, address, port);
+ }
- protected native void setTimeToLive(int ttl) throws IOException;
+ protected synchronized int peek(InetAddress i) throws IOException {
+ DatagramPacket p = new DatagramPacket(EmptyArray.BYTE, 0);
+ doRecv(p, MSG_PEEK);
+ i.holder().address = p.getAddress().holder().address;
+ return p.getPort();
+ }
- protected native int getTimeToLive() throws IOException;
+ protected synchronized int peekData(DatagramPacket p) throws IOException {
+ doRecv(p, MSG_PEEK);
+ return p.getPort();
+ }
- protected native void setTTL(byte ttl) throws IOException;
+ protected synchronized void receive0(DatagramPacket p) throws IOException {
+ doRecv(p, 0);
+ }
- protected native byte getTTL() throws IOException;
+ private void doRecv(DatagramPacket p, int flags) throws IOException {
+ if (isClosed()) {
+ throw new SocketException("Socket closed");
+ }
- protected native void join(InetAddress inetaddr, NetworkInterface netIf)
- throws IOException;
+ if (timeout != 0) {
+ IoBridge.poll(fd, POLLIN | POLLERR, timeout);
+ }
- protected native void leave(InetAddress inetaddr, NetworkInterface netIf)
- throws IOException;
+ IoBridge.recvfrom(false, fd, p.getData(), p.getOffset(), p.bufLength, flags, p,
+ connected);
+ }
- protected native void datagramSocketCreate() throws SocketException;
+ protected void setTimeToLive(int ttl) throws IOException {
+ IoBridge.setSocketOption(fd, JAVA_IP_MULTICAST_TTL, ttl);
+ }
- protected native void datagramSocketClose();
+ protected int getTimeToLive() throws IOException {
+ return (Integer) IoBridge.getSocketOption(fd, JAVA_IP_MULTICAST_TTL);
+ }
- protected native void socketSetOption0(int opt, Object val)
- throws SocketException;
+ protected void setTTL(byte ttl) throws IOException {
+ setTimeToLive((int) ttl & 0xff);
+ }
- protected native Object socketGetOption(int opt) throws SocketException;
+ protected byte getTTL() throws IOException {
+ return (byte) getTimeToLive();
+ }
- protected native void connect0(InetAddress address, int port) throws SocketException;
+ private static StructGroupReq makeGroupReq(InetAddress gr_group,
+ NetworkInterface networkInterface) {
+ int gr_interface = (networkInterface != null) ? networkInterface.getIndex() : 0;
+ return new StructGroupReq(gr_interface, gr_group);
+ }
- protected native void disconnect0(int family);
+ protected void join(InetAddress inetaddr, NetworkInterface netIf) throws IOException {
+ if (isClosed()) {
+ throw new SocketException("Socket closed");
+ }
- /**
- * Perform class load-time initializations.
- */
- private native static void init();
+ IoBridge.setSocketOption(fd, JAVA_MCAST_JOIN_GROUP, makeGroupReq(inetaddr, netIf));
+ }
+
+ protected void leave(InetAddress inetaddr, NetworkInterface netIf)
+ throws IOException {
+ if (isClosed()) {
+ throw new SocketException("Socket closed");
+ }
+
+ IoBridge.setSocketOption(fd, JAVA_MCAST_LEAVE_GROUP, makeGroupReq(inetaddr, netIf));
+ }
+
+ protected void datagramSocketCreate() throws SocketException {
+ fd = IoBridge.socket(AF_INET6, SOCK_DGRAM, 0);
+ IoBridge.setSocketOption(fd, SO_BROADCAST, true);
+
+ try {
+ Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_MULTICAST_ALL, 0);
+ } catch (ErrnoException errnoException) {
+ throw errnoException.rethrowAsSocketException();
+ }
+ }
+
+ protected void datagramSocketClose() {
+ try {
+ IoBridge.closeAndSignalBlockedThreads(fd);
+ } catch (IOException ignored) { }
+ }
+
+ protected void socketSetOption0(int opt, Object val) throws SocketException {
+ if (isClosed()) {
+ throw new SocketException("Socket closed");
+ }
+
+ IoBridge.setSocketOption(fd, opt, val);
+ }
+
+ protected Object socketGetOption(int opt) throws SocketException {
+ if (isClosed()) {
+ throw new SocketException("Socket closed");
+ }
+
+ return IoBridge.getSocketOption(fd, opt);
+ }
+
+ protected void connect0(InetAddress address, int port) throws SocketException {
+ if (isClosed()) {
+ throw new SocketException("Socket closed");
+ }
+
+ IoBridge.connect(fd, address, port);
+ }
+
+ protected void disconnect0(int family) {
+ if (isClosed()) {
+ return;
+ }
+
+ InetAddress inetAddressUnspec = new InetAddress();
+ inetAddressUnspec.holder().family = AF_UNSPEC;
+
+ try {
+ IoBridge.connect(fd, inetAddressUnspec, 0);
+ } catch (SocketException ignored) { }
+ }
+
+ // Android-removed: JNI has been removed
+ // /**
+ // * Perform class load-time initializations.
+ // */
+ // private native static void init();
}
diff --git a/ojluni/src/main/java/java/nio/file/attribute/FileTime.java b/ojluni/src/main/java/java/nio/file/attribute/FileTime.java
index 988ad21..2f3399b 100644
--- a/ojluni/src/main/java/java/nio/file/attribute/FileTime.java
+++ b/ojluni/src/main/java/java/nio/file/attribute/FileTime.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -25,12 +25,10 @@
package java.nio.file.attribute;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.Date;
-import java.util.Formatter;
-import java.util.Locale;
-import java.util.TimeZone;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
@@ -51,14 +49,22 @@
implements Comparable<FileTime>
{
/**
+ * The unit of granularity to interpret the value. Null if
+ * this {@code FileTime} is converted from an {@code Instant},
+ * the {@code value} and {@code unit} pair will not be used
+ * in this scenario.
+ */
+ private final TimeUnit unit;
+
+ /**
* The value since the epoch; can be negative.
*/
private final long value;
/**
- * The unit of granularity to interpret the value.
+ * The value as Instant (created lazily, if not from an instant)
*/
- private final TimeUnit unit;
+ private Instant instant;
/**
* The value return by toString (created lazily)
@@ -66,27 +72,12 @@
private String valueAsString;
/**
- * The value in days and excess nanos (created lazily)
- */
- private DaysAndNanos daysAndNanos;
-
- /**
- * Returns a DaysAndNanos object representing the value.
- */
- private DaysAndNanos asDaysAndNanos() {
- if (daysAndNanos == null)
- daysAndNanos = new DaysAndNanos(value, unit);
- return daysAndNanos;
- }
-
- /**
* Initializes a new instance of this class.
*/
- private FileTime(long value, TimeUnit unit) {
- if (unit == null)
- throw new NullPointerException();
+ private FileTime(long value, TimeUnit unit, Instant instant) {
this.value = value;
this.unit = unit;
+ this.instant = instant;
}
/**
@@ -102,7 +93,8 @@
* @return a {@code FileTime} representing the given value
*/
public static FileTime from(long value, TimeUnit unit) {
- return new FileTime(value, unit);
+ Objects.requireNonNull(unit, "unit");
+ return new FileTime(value, unit, null);
}
/**
@@ -115,7 +107,22 @@
* @return a {@code FileTime} representing the given value
*/
public static FileTime fromMillis(long value) {
- return new FileTime(value, TimeUnit.MILLISECONDS);
+ return new FileTime(value, TimeUnit.MILLISECONDS, null);
+ }
+
+ /**
+ * Returns a {@code FileTime} representing the same point of time value
+ * on the time-line as the provided {@code Instant} object.
+ *
+ * @param instant
+ * the instant to convert
+ * @return a {@code FileTime} representing the same point on the time-line
+ * as the provided instant
+ * @since 1.8
+ */
+ public static FileTime from(Instant instant) {
+ Objects.requireNonNull(instant, "instant");
+ return new FileTime(0, null, instant);
}
/**
@@ -132,7 +139,22 @@
* since the epoch (1970-01-01T00:00:00Z); can be negative
*/
public long to(TimeUnit unit) {
- return unit.convert(this.value, this.unit);
+ Objects.requireNonNull(unit, "unit");
+ if (this.unit != null) {
+ return unit.convert(this.value, this.unit);
+ } else {
+ long secs = unit.convert(instant.getEpochSecond(), TimeUnit.SECONDS);
+ if (secs == Long.MIN_VALUE || secs == Long.MAX_VALUE) {
+ return secs;
+ }
+ long nanos = unit.convert(instant.getNano(), TimeUnit.NANOSECONDS);
+ long r = secs + nanos;
+ // Math.addExact() variant
+ if (((secs ^ r) & (nanos ^ r)) < 0) {
+ return (secs < 0) ? Long.MIN_VALUE : Long.MAX_VALUE;
+ }
+ return r;
+ }
}
/**
@@ -145,7 +167,110 @@
* @return the value in milliseconds, since the epoch (1970-01-01T00:00:00Z)
*/
public long toMillis() {
- return unit.toMillis(value);
+ if (unit != null) {
+ return unit.toMillis(value);
+ } else {
+ long secs = instant.getEpochSecond();
+ int nanos = instant.getNano();
+ // Math.multiplyExact() variant
+ long r = secs * 1000;
+ long ax = Math.abs(secs);
+ if (((ax | 1000) >>> 31 != 0)) {
+ if ((r / 1000) != secs) {
+ return (secs < 0) ? Long.MIN_VALUE : Long.MAX_VALUE;
+ }
+ }
+ return r + nanos / 1000_000;
+ }
+ }
+
+ /**
+ * Time unit constants for conversion.
+ */
+ private static final long HOURS_PER_DAY = 24L;
+ private static final long MINUTES_PER_HOUR = 60L;
+ private static final long SECONDS_PER_MINUTE = 60L;
+ private static final long SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
+ private static final long SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
+ private static final long MILLIS_PER_SECOND = 1000L;
+ private static final long MICROS_PER_SECOND = 1000_000L;
+ private static final long NANOS_PER_SECOND = 1000_000_000L;
+ private static final int NANOS_PER_MILLI = 1000_000;
+ private static final int NANOS_PER_MICRO = 1000;
+ // The epoch second of Instant.MIN.
+ private static final long MIN_SECOND = -31557014167219200L;
+ // The epoch second of Instant.MAX.
+ private static final long MAX_SECOND = 31556889864403199L;
+
+ /*
+ * Scale d by m, checking for overflow.
+ */
+ private static long scale(long d, long m, long over) {
+ if (d > over) return Long.MAX_VALUE;
+ if (d < -over) return Long.MIN_VALUE;
+ return d * m;
+ }
+
+ /**
+ * Converts this {@code FileTime} object to an {@code Instant}.
+ *
+ * <p> The conversion creates an {@code Instant} that represents the
+ * same point on the time-line as this {@code FileTime}.
+ *
+ * <p> {@code FileTime} can store points on the time-line further in the
+ * future and further in the past than {@code Instant}. Conversion
+ * from such further time points saturates to {@link Instant#MIN} if
+ * earlier than {@code Instant.MIN} or {@link Instant#MAX} if later
+ * than {@code Instant.MAX}.
+ *
+ * @return an instant representing the same point on the time-line as
+ * this {@code FileTime} object
+ * @since 1.8
+ */
+ public Instant toInstant() {
+ if (instant == null) {
+ long secs = 0L;
+ int nanos = 0;
+ switch (unit) {
+ case DAYS:
+ secs = scale(value, SECONDS_PER_DAY,
+ Long.MAX_VALUE/SECONDS_PER_DAY);
+ break;
+ case HOURS:
+ secs = scale(value, SECONDS_PER_HOUR,
+ Long.MAX_VALUE/SECONDS_PER_HOUR);
+ break;
+ case MINUTES:
+ secs = scale(value, SECONDS_PER_MINUTE,
+ Long.MAX_VALUE/SECONDS_PER_MINUTE);
+ break;
+ case SECONDS:
+ secs = value;
+ break;
+ case MILLISECONDS:
+ secs = Math.floorDiv(value, MILLIS_PER_SECOND);
+ nanos = (int)Math.floorMod(value, MILLIS_PER_SECOND)
+ * NANOS_PER_MILLI;
+ break;
+ case MICROSECONDS:
+ secs = Math.floorDiv(value, MICROS_PER_SECOND);
+ nanos = (int)Math.floorMod(value, MICROS_PER_SECOND)
+ * NANOS_PER_MICRO;
+ break;
+ case NANOSECONDS:
+ secs = Math.floorDiv(value, NANOS_PER_SECOND);
+ nanos = (int)Math.floorMod(value, NANOS_PER_SECOND);
+ break;
+ default : throw new AssertionError("Unit not handled");
+ }
+ if (secs <= MIN_SECOND)
+ instant = Instant.MIN;
+ else if (secs >= MAX_SECOND)
+ instant = Instant.MAX;
+ else
+ instant = Instant.ofEpochSecond(secs, nanos);
+ }
+ return instant;
}
/**
@@ -176,8 +301,25 @@
*/
@Override
public int hashCode() {
- // hashcode of days/nanos representation to satisfy contract with equals
- return asDaysAndNanos().hashCode();
+ // hashcode of instant representation to satisfy contract with equals
+ return toInstant().hashCode();
+ }
+
+ private long toDays() {
+ if (unit != null) {
+ return unit.toDays(value);
+ } else {
+ return TimeUnit.SECONDS.toDays(toInstant().getEpochSecond());
+ }
+ }
+
+ private long toExcessNanos(long days) {
+ if (unit != null) {
+ return unit.toNanos(value - unit.convert(days, TimeUnit.DAYS));
+ } else {
+ return TimeUnit.SECONDS.toNanos(toInstant().getEpochSecond()
+ - TimeUnit.DAYS.toSeconds(days));
+ }
}
/**
@@ -194,14 +336,52 @@
@Override
public int compareTo(FileTime other) {
// same granularity
- if (unit == other.unit) {
- return (value < other.value) ? -1 : (value == other.value ? 0 : 1);
+ if (unit != null && unit == other.unit) {
+ return Long.compare(value, other.value);
} else {
- // compare using days/nanos representation when unit differs
- return asDaysAndNanos().compareTo(other.asDaysAndNanos());
+ // compare using instant representation when unit differs
+ long secs = toInstant().getEpochSecond();
+ long secsOther = other.toInstant().getEpochSecond();
+ int cmp = Long.compare(secs, secsOther);
+ if (cmp != 0) {
+ return cmp;
+ }
+ cmp = Long.compare(toInstant().getNano(), other.toInstant().getNano());
+ if (cmp != 0) {
+ return cmp;
+ }
+ if (secs != MAX_SECOND && secs != MIN_SECOND) {
+ return 0;
+ }
+ // if both this and other's Instant reps are MIN/MAX,
+ // use daysSinceEpoch and nanosOfDays, which will not
+ // saturate during calculation.
+ long days = toDays();
+ long daysOther = other.toDays();
+ if (days == daysOther) {
+ return Long.compare(toExcessNanos(days), other.toExcessNanos(daysOther));
+ }
+ return Long.compare(days, daysOther);
}
}
+ // days in a 400 year cycle = 146097
+ // days in a 10,000 year cycle = 146097 * 25
+ // seconds per day = 86400
+ private static final long DAYS_PER_10000_YEARS = 146097L * 25L;
+ private static final long SECONDS_PER_10000_YEARS = 146097L * 25L * 86400L;
+ private static final long SECONDS_0000_TO_1970 = ((146097L * 5L) - (30L * 365L + 7L)) * 86400L;
+
+ // append year/month/day/hour/minute/second/nano with width and 0 padding
+ private StringBuilder append(StringBuilder sb, int w, int d) {
+ while (w > 0) {
+ sb.append((char)(d/w + '0'));
+ d = d % w;
+ w /= 10;
+ }
+ return sb;
+ }
+
/**
* Returns the string representation of this {@code FileTime}. The string
* is returned in the <a
@@ -229,135 +409,67 @@
*/
@Override
public String toString() {
- String v = valueAsString;
- if (v == null) {
- // overflow saturates to Long.MIN_VALUE or Long.MAX_VALUE so this
- // limits the range:
- // [-292275056-05-16T16:47:04.192Z,292278994-08-17T07:12:55.807Z]
- long ms = toMillis();
-
- // nothing to do when seconds/minutes/hours/days
- String fractionAsString = "";
- if (unit.compareTo(TimeUnit.SECONDS) < 0) {
- long fraction = asDaysAndNanos().fractionOfSecondInNanos();
- if (fraction != 0L) {
- // fraction must be positive
- if (fraction < 0L) {
- final long MAX_FRACTION_PLUS_1 = 1000L * 1000L * 1000L;
- fraction += MAX_FRACTION_PLUS_1;
- if (ms != Long.MIN_VALUE) ms--;
- }
-
- // convert to String, adding leading zeros as required and
- // stripping any trailing zeros
- String s = Long.toString(fraction);
- int len = s.length();
- int width = 9 - len;
- StringBuilder sb = new StringBuilder(".");
- while (width-- > 0) {
- sb.append('0');
- }
- if (s.charAt(len-1) == '0') {
- // drop trailing zeros
- len--;
- while (s.charAt(len-1) == '0')
- len--;
- sb.append(s.substring(0, len));
- } else {
- sb.append(s);
- }
- fractionAsString = sb.toString();
+ if (valueAsString == null) {
+ long secs = 0L;
+ int nanos = 0;
+ if (instant == null && unit.compareTo(TimeUnit.SECONDS) >= 0) {
+ secs = unit.toSeconds(value);
+ } else {
+ secs = toInstant().getEpochSecond();
+ nanos = toInstant().getNano();
+ }
+ LocalDateTime ldt;
+ int year = 0;
+ if (secs >= -SECONDS_0000_TO_1970) {
+ // current era
+ long zeroSecs = secs - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970;
+ long hi = Math.floorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1;
+ long lo = Math.floorMod(zeroSecs, SECONDS_PER_10000_YEARS);
+ ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, nanos, ZoneOffset.UTC);
+ year = ldt.getYear() + (int)hi * 10000;
+ } else {
+ // before current era
+ long zeroSecs = secs + SECONDS_0000_TO_1970;
+ long hi = zeroSecs / SECONDS_PER_10000_YEARS;
+ long lo = zeroSecs % SECONDS_PER_10000_YEARS;
+ ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, nanos, ZoneOffset.UTC);
+ year = ldt.getYear() + (int)hi * 10000;
+ }
+ if (year <= 0) {
+ year = year - 1;
+ }
+ int fraction = ldt.getNano();
+ StringBuilder sb = new StringBuilder(64);
+ sb.append(year < 0 ? "-" : "");
+ year = Math.abs(year);
+ if (year < 10000) {
+ append(sb, 1000, Math.abs(year));
+ } else {
+ sb.append(String.valueOf(year));
+ }
+ sb.append('-');
+ append(sb, 10, ldt.getMonthValue());
+ sb.append('-');
+ append(sb, 10, ldt.getDayOfMonth());
+ sb.append('T');
+ append(sb, 10, ldt.getHour());
+ sb.append(':');
+ append(sb, 10, ldt.getMinute());
+ sb.append(':');
+ append(sb, 10, ldt.getSecond());
+ if (fraction != 0) {
+ sb.append('.');
+ // adding leading zeros and stripping any trailing zeros
+ int w = 100_000_000;
+ while (fraction % 10 == 0) {
+ fraction /= 10;
+ w /= 10;
}
+ append(sb, w, fraction);
}
-
- // create calendar to use with formatter.
- GregorianCalendar cal =
- new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.ROOT);
- if (value < 0L)
- cal.setGregorianChange(new Date(Long.MIN_VALUE));
- cal.setTimeInMillis(ms);
-
- // years are negative before common era
- String sign = (cal.get(Calendar.ERA) == GregorianCalendar.BC) ? "-" : "";
-
- // [-]YYYY-MM-DDThh:mm:ss[.s]Z
- v = new Formatter(Locale.ROOT)
- .format("%s%tFT%tR:%tS%sZ", sign, cal, cal, cal, fractionAsString)
- .toString();
- valueAsString = v;
+ sb.append('Z');
+ valueAsString = sb.toString();
}
- return v;
- }
-
- /**
- * Represents a FileTime's value as two longs: the number of days since
- * the epoch, and the excess (in nanoseconds). This is used for comparing
- * values with different units of granularity.
- */
- private static class DaysAndNanos implements Comparable<DaysAndNanos> {
- // constants for conversion
- private static final long C0 = 1L;
- private static final long C1 = C0 * 24L;
- private static final long C2 = C1 * 60L;
- private static final long C3 = C2 * 60L;
- private static final long C4 = C3 * 1000L;
- private static final long C5 = C4 * 1000L;
- private static final long C6 = C5 * 1000L;
-
- /**
- * The value (in days) since the epoch; can be negative.
- */
- private final long days;
-
- /**
- * The excess (in nanoseconds); can be negative if days <= 0.
- */
- private final long excessNanos;
-
- /**
- * Initializes a new instance of this class.
- */
- DaysAndNanos(long value, TimeUnit unit) {
- long scale;
- switch (unit) {
- case DAYS : scale = C0; break;
- case HOURS : scale = C1; break;
- case MINUTES : scale = C2; break;
- case SECONDS : scale = C3; break;
- case MILLISECONDS : scale = C4; break;
- case MICROSECONDS : scale = C5; break;
- case NANOSECONDS : scale = C6; break;
- default : throw new AssertionError("Unit not handled");
- }
- this.days = unit.toDays(value);
- this.excessNanos = unit.toNanos(value - (this.days * scale));
- }
-
- /**
- * Returns the fraction of a second, in nanoseconds.
- */
- long fractionOfSecondInNanos() {
- return excessNanos % (1000L * 1000L * 1000L);
- }
-
- @Override
- public boolean equals(Object obj) {
- return (obj instanceof DaysAndNanos) ?
- compareTo((DaysAndNanos)obj) == 0 : false;
- }
-
- @Override
- public int hashCode() {
- return (int)(days ^ (days >>> 32) ^
- excessNanos ^ (excessNanos >>> 32));
- }
-
- @Override
- public int compareTo(DaysAndNanos other) {
- if (this.days != other.days)
- return (this.days < other.days) ? -1 : 1;
- return (this.excessNanos < other.excessNanos) ? -1 :
- (this.excessNanos == other.excessNanos) ? 0 : 1;
- }
+ return valueAsString;
}
}
diff --git a/ojluni/src/main/java/java/util/Date.java b/ojluni/src/main/java/java/util/Date.java
index 37f9aad..6ab763e 100644
--- a/ojluni/src/main/java/java/util/Date.java
+++ b/ojluni/src/main/java/java/util/Date.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,10 +27,12 @@
package java.util;
import java.text.DateFormat;
+import java.time.LocalDate;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.lang.ref.SoftReference;
+import java.time.Instant;
import sun.util.calendar.BaseCalendar;
import sun.util.calendar.CalendarDate;
import sun.util.calendar.CalendarSystem;
@@ -488,10 +490,12 @@
if ('0' <= c && c <= '9') {
n = c - '0';
while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
- n = (n * 10) + (c - '0');
+ n = n * 10 + c - '0';
i++;
}
if (prevc == '+' || prevc == '-' && year != Integer.MIN_VALUE) {
+ // Android-changed BEGIN: Android specific time zone logic
+
if (tzoffset != 0 && tzoffset != -1)
break syntax;
@@ -518,6 +522,7 @@
if (prevc == '+') // plus means east of GMT
n = -n;
+ // Android-changed END
tzoffset = n;
} else if (n >= 70)
@@ -788,7 +793,7 @@
*/
@Deprecated
public int getDay() {
- return normalize().getDayOfWeek() - gcal.SUNDAY;
+ return normalize().getDayOfWeek() - BaseCalendar.SUNDAY;
}
/**
@@ -1000,8 +1005,9 @@
* exclusive OR of the two halves of the primitive <tt>long</tt>
* value returned by the {@link Date#getTime}
* method. That is, the hash code is the value of the expression:
- * <blockquote><pre>
- * (int)(this.getTime()^(this.getTime() >>> 32))</pre></blockquote>
+ * <blockquote><pre>{@code
+ * (int)(this.getTime()^(this.getTime() >>> 32))
+ * }</pre></blockquote>
*
* @return a hash code value for this object.
*/
@@ -1045,7 +1051,7 @@
BaseCalendar.Date date = normalize();
StringBuilder sb = new StringBuilder(28);
int index = date.getDayOfWeek();
- if (index == gcal.SUNDAY) {
+ if (index == BaseCalendar.SUNDAY) {
index = 8;
}
convertToAbbr(sb, wtb[index]).append(' '); // EEE
@@ -1057,7 +1063,7 @@
CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
TimeZone zi = date.getZone();
if (zi != null) {
- sb.append(zi.getDisplayName(date.isDaylightTime(), zi.SHORT, Locale.US)); // zzz
+ sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
} else {
sb.append("GMT");
}
@@ -1101,7 +1107,7 @@
/**
* Creates a string representation of this <tt>Date</tt> object of
* the form:
- * <blockquote<pre>
+ * <blockquote><pre>
* d mon yyyy hh:mm:ss GMT</pre></blockquote>
* where:<ul>
* <li><i>d</i> is the day of the month (<tt>1</tt> through <tt>31</tt>),
@@ -1183,6 +1189,7 @@
public int getTimezoneOffset() {
int zoneOffset;
if (cdate == null) {
+ // Android-changed: Android specific time zone logic
GregorianCalendar cal = new GregorianCalendar(fastTime);
zoneOffset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET));
} else {
@@ -1251,7 +1258,7 @@
}
GregorianCalendar gc = new GregorianCalendar(tz);
gc.clear();
- gc.set(gc.MILLISECOND, ms);
+ gc.set(GregorianCalendar.MILLISECOND, ms);
gc.set(y, m-1, d, hh, mm, ss);
fastTime = gc.getTimeInMillis();
BaseCalendar cal = getCalendarSystem(fastTime);
@@ -1342,4 +1349,46 @@
{
fastTime = s.readLong();
}
+
+ /**
+ * Obtains an instance of {@code Date} from an {@code Instant} object.
+ * <p>
+ * {@code Instant} uses a precision of nanoseconds, whereas {@code Date}
+ * uses a precision of milliseconds. The conversion will trancate any
+ * excess precision information as though the amount in nanoseconds was
+ * subject to integer division by one million.
+ * <p>
+ * {@code Instant} can store points on the time-line further in the future
+ * and further in the past than {@code Date}. In this scenario, this method
+ * will throw an exception.
+ *
+ * @param instant the instant to convert
+ * @return a {@code Date} representing the same point on the time-line as
+ * the provided instant
+ * @exception NullPointerException if {@code instant} is null.
+ * @exception IllegalArgumentException if the instant is too large to
+ * represent as a {@code Date}
+ * @since 1.8
+ */
+ public static Date from(Instant instant) {
+ try {
+ return new Date(instant.toEpochMilli());
+ } catch (ArithmeticException ex) {
+ throw new IllegalArgumentException(ex);
+ }
+ }
+
+ /**
+ * Converts this {@code Date} object to an {@code Instant}.
+ * <p>
+ * The conversion creates an {@code Instant} that represents the same
+ * point on the time-line as this {@code Date}.
+ *
+ * @return an instant representing the same point on the time-line as
+ * this {@code Date} object
+ * @since 1.8
+ */
+ public Instant toInstant() {
+ return Instant.ofEpochMilli(getTime());
+ }
}
diff --git a/ojluni/src/main/java/java/util/LinkedHashMap.java b/ojluni/src/main/java/java/util/LinkedHashMap.java
index dd32423..858488e 100644
--- a/ojluni/src/main/java/java/util/LinkedHashMap.java
+++ b/ojluni/src/main/java/java/util/LinkedHashMap.java
@@ -30,6 +30,7 @@
import java.util.function.BiFunction;
import java.io.IOException;
+// Android-added: Note about spliterator order b/33945212 in Android N
/**
* <p>Hash table and linked list implementation of the <tt>Map</tt> interface,
* with predictable iteration order. This implementation differs from
@@ -138,6 +139,23 @@
* returned by all of this class's collection view methods are
* <em><a href="Spliterator.html#binding">late-binding</a></em>,
* <em>fail-fast</em>, and additionally report {@link Spliterator#ORDERED}.
+ * <em>Note</em>: The implementation of these spliterators in Android Nougat
+ * (API levels 24 and 25) uses the wrong order (inconsistent with the
+ * iterators, which use the correct order), despite reporting
+ * {@link Spliterator#ORDERED}. You may use the following code fragments
+ * to obtain a correctly ordered Spliterator on API level 24 and 25:
+ * <ul>
+ * <li>For a Collection view {@code c = lhm.keySet()},
+ * {@code c = lhm.keySet()} or {@code c = lhm.values()}, use
+ * {@code java.util.Spliterators.spliterator(c, c.spliterator().characteristics())}
+ * instead of {@code c.spliterator()}.
+ * <li>Instead of {@code lhm.stream()} or {@code lhm.parallelStream()}, use
+ * {@code java.util.stream.StreamSupport.stream(spliterator, false)}
+ * to construct a (nonparallel) {@link java.util.stream.Stream} from
+ * such a {@code Spliterator}.
+ * </ul>
+ * Note that these workarounds are only suggested where {@code lhm} is a
+ * {@code LinkedHashMap}.
*
* <p>This class is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
diff --git a/ojluni/src/main/java/sun/net/www/MeteredStream.java b/ojluni/src/main/java/sun/net/www/MeteredStream.java
index 29b998a..17c8b83 100644
--- a/ojluni/src/main/java/sun/net/www/MeteredStream.java
+++ b/ojluni/src/main/java/sun/net/www/MeteredStream.java
@@ -29,7 +29,6 @@
import java.util.*;
import java.io.*;
import sun.net.ProgressSource;
-import sun.net.www.http.ChunkedInputStream;
public class MeteredStream extends FilterInputStream {
@@ -143,14 +142,15 @@
return 0;
}
- if (in instanceof ChunkedInputStream) {
- n = in.skip(n);
- }
- else {
+// Android-changed: Remove support for Android-removed class ChunkedInputSTream
+// if (in instanceof ChunkedInputStream) {
+// n = in.skip(n);
+// }
+// else {
// just skip min(n, num_bytes_left)
long min = (n > expected - count) ? expected - count: n;
n = in.skip(min);
- }
+// }
justRead(n);
return n;
}
diff --git a/ojluni/src/main/java/sun/net/www/http/ChunkedInputStream.java b/ojluni/src/main/java/sun/net/www/http/ChunkedInputStream.java
deleted file mode 100644
index af45752..0000000
--- a/ojluni/src/main/java/sun/net/www/http/ChunkedInputStream.java
+++ /dev/null
@@ -1,780 +0,0 @@
-/*
- * Copyright (c) 1999, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.net.www.http;
-
-import java.io.*;
-import java.util.*;
-
-import sun.net.*;
-import sun.net.www.*;
-
-/**
- * A <code>ChunkedInputStream</code> provides a stream for reading a body of
- * a http message that can be sent as a series of chunks, each with its own
- * size indicator. Optionally the last chunk can be followed by trailers
- * containing entity-header fields.
- * <p>
- * A <code>ChunkedInputStream</code> is also <code>Hurryable</code> so it
- * can be hurried to the end of the stream if the bytes are available on
- * the underlying stream.
- */
-public
-class ChunkedInputStream extends InputStream implements Hurryable {
-
- /**
- * The underlying stream
- */
- private InputStream in;
-
- /**
- * The <code>HttpClient</code> that should be notified when the chunked stream has
- * completed.
- */
- private HttpClient hc;
-
- /**
- * The <code>MessageHeader</code> that is populated with any optional trailer
- * that appear after the last chunk.
- */
- private MessageHeader responses;
-
- /**
- * The size, in bytes, of the chunk that is currently being read.
- * This size is only valid if the current position in the underlying
- * input stream is inside a chunk (ie: state == STATE_READING_CHUNK).
- */
- private int chunkSize;
-
- /**
- * The number of bytes read from the underlying stream for the current
- * chunk. This value is always in the range <code>0</code> through to
- * <code>chunkSize</code>
- */
- private int chunkRead;
-
- /**
- * The internal buffer array where chunk data is available for the
- * application to read.
- */
- private byte chunkData[] = new byte[4096];
-
- /**
- * The current position in the buffer. It contains the index
- * of the next byte to read from <code>chunkData</code>
- */
- private int chunkPos;
-
- /**
- * The index one greater than the index of the last valid byte in the
- * buffer. This value is always in the range <code>0</code> through
- * <code>chunkData.length</code>.
- */
- private int chunkCount;
-
- /**
- * The internal buffer where bytes from the underlying stream can be
- * read. It may contain bytes representing chunk-size, chunk-data, or
- * trailer fields.
- */
- private byte rawData[] = new byte[32];
-
- /**
- * The current position in the buffer. It contains the index
- * of the next byte to read from <code>rawData</code>
- */
- private int rawPos;
-
- /**
- * The index one greater than the index of the last valid byte in the
- * buffer. This value is always in the range <code>0</code> through
- * <code>rawData.length</code>.
- */
- private int rawCount;
-
- /**
- * Indicates if an error was encountered when processing the chunked
- * stream.
- */
- private boolean error;
-
- /**
- * Indicates if the chunked stream has been closed using the
- * <code>close</code> method.
- */
- private boolean closed;
-
- /*
- * Maximum chunk header size of 2KB + 2 bytes for CRLF
- */
- private final static int MAX_CHUNK_HEADER_SIZE = 2050;
-
- /**
- * State to indicate that next field should be :-
- * chunk-size [ chunk-extension ] CRLF
- */
- static final int STATE_AWAITING_CHUNK_HEADER = 1;
-
- /**
- * State to indicate that we are currently reading the chunk-data.
- */
- static final int STATE_READING_CHUNK = 2;
-
- /**
- * Indicates that a chunk has been completely read and the next
- * fields to be examine should be CRLF
- */
- static final int STATE_AWAITING_CHUNK_EOL = 3;
-
- /**
- * Indicates that all chunks have been read and the next field
- * should be optional trailers or an indication that the chunked
- * stream is complete.
- */
- static final int STATE_AWAITING_TRAILERS = 4;
-
- /**
- * State to indicate that the chunked stream is complete and
- * no further bytes should be read from the underlying stream.
- */
- static final int STATE_DONE = 5;
-
- /**
- * Indicates the current state.
- */
- private int state;
-
-
- /**
- * Check to make sure that this stream has not been closed.
- */
- private void ensureOpen() throws IOException {
- if (closed) {
- throw new IOException("stream is closed");
- }
- }
-
-
- /**
- * Ensures there is <code>size</code> bytes available in
- * <code>rawData</code>. This requires that we either
- * shift the bytes in use to the begining of the buffer
- * or allocate a large buffer with sufficient space available.
- */
- private void ensureRawAvailable(int size) {
- if (rawCount + size > rawData.length) {
- int used = rawCount - rawPos;
- if (used + size > rawData.length) {
- byte tmp[] = new byte[used + size];
- if (used > 0) {
- System.arraycopy(rawData, rawPos, tmp, 0, used);
- }
- rawData = tmp;
- } else {
- if (used > 0) {
- System.arraycopy(rawData, rawPos, rawData, 0, used);
- }
- }
- rawCount = used;
- rawPos = 0;
- }
- }
-
-
- /**
- * Close the underlying input stream by either returning it to the
- * keep alive cache or closing the stream.
- * <p>
- * As a chunked stream is inheritly persistent (see HTTP 1.1 RFC) the
- * underlying stream can be returned to the keep alive cache if the
- * stream can be completely read without error.
- */
- private void closeUnderlying() throws IOException {
- if (in == null) {
- return;
- }
-
- if (!error && state == STATE_DONE) {
- hc.finished();
- } else {
- if (!hurry()) {
- hc.closeServer();
- }
- }
-
- in = null;
- }
-
- /**
- * Attempt to read the remainder of a chunk directly into the
- * caller's buffer.
- * <p>
- * Return the number of bytes read.
- */
- private int fastRead(byte[] b, int off, int len) throws IOException {
-
- // assert state == STATE_READING_CHUNKS;
-
- int remaining = chunkSize - chunkRead;
- int cnt = (remaining < len) ? remaining : len;
- if (cnt > 0) {
- int nread;
- try {
- nread = in.read(b, off, cnt);
- } catch (IOException e) {
- error = true;
- throw e;
- }
- if (nread > 0) {
- chunkRead += nread;
- if (chunkRead >= chunkSize) {
- state = STATE_AWAITING_CHUNK_EOL;
- }
- return nread;
- }
- error = true;
- throw new IOException("Premature EOF");
- } else {
- return 0;
- }
- }
-
- /**
- * Process any outstanding bytes that have already been read into
- * <code>rawData</code>.
- * <p>
- * The parsing of the chunked stream is performed as a state machine with
- * <code>state</code> representing the current state of the processing.
- * <p>
- * Returns when either all the outstanding bytes in rawData have been
- * processed or there is insufficient bytes available to continue
- * processing. When the latter occurs <code>rawPos</code> will not have
- * been updated and thus the processing can be restarted once further
- * bytes have been read into <code>rawData</code>.
- */
- private void processRaw() throws IOException {
- int pos;
- int i;
-
- while (state != STATE_DONE) {
-
- switch (state) {
-
- /**
- * We are awaiting a line with a chunk header
- */
- case STATE_AWAITING_CHUNK_HEADER:
- /*
- * Find \n to indicate end of chunk header. If not found when there is
- * insufficient bytes in the raw buffer to parse a chunk header.
- */
- pos = rawPos;
- while (pos < rawCount) {
- if (rawData[pos] == '\n') {
- break;
- }
- pos++;
- if ((pos - rawPos) >= MAX_CHUNK_HEADER_SIZE) {
- error = true;
- throw new IOException("Chunk header too long");
- }
- }
- if (pos >= rawCount) {
- return;
- }
-
- /*
- * Extract the chunk size from the header (ignoring extensions).
- */
- String header = new String(rawData, rawPos, pos-rawPos+1, "US-ASCII");
- for (i=0; i < header.length(); i++) {
- if (Character.digit(header.charAt(i), 16) == -1)
- break;
- }
- try {
- chunkSize = Integer.parseInt(header.substring(0, i), 16);
- } catch (NumberFormatException e) {
- error = true;
- throw new IOException("Bogus chunk size");
- }
-
- /*
- * Chunk has been parsed so move rawPos to first byte of chunk
- * data.
- */
- rawPos = pos + 1;
- chunkRead = 0;
-
- /*
- * A chunk size of 0 means EOF.
- */
- if (chunkSize > 0) {
- state = STATE_READING_CHUNK;
- } else {
- state = STATE_AWAITING_TRAILERS;
- }
- break;
-
-
- /**
- * We are awaiting raw entity data (some may have already been
- * read). chunkSize is the size of the chunk; chunkRead is the
- * total read from the underlying stream to date.
- */
- case STATE_READING_CHUNK :
- /* no data available yet */
- if (rawPos >= rawCount) {
- return;
- }
-
- /*
- * Compute the number of bytes of chunk data available in the
- * raw buffer.
- */
- int copyLen = Math.min( chunkSize-chunkRead, rawCount-rawPos );
-
- /*
- * Expand or compact chunkData if needed.
- */
- if (chunkData.length < chunkCount + copyLen) {
- int cnt = chunkCount - chunkPos;
- if (chunkData.length < cnt + copyLen) {
- byte tmp[] = new byte[cnt + copyLen];
- System.arraycopy(chunkData, chunkPos, tmp, 0, cnt);
- chunkData = tmp;
- } else {
- System.arraycopy(chunkData, chunkPos, chunkData, 0, cnt);
- }
- chunkPos = 0;
- chunkCount = cnt;
- }
-
- /*
- * Copy the chunk data into chunkData so that it's available
- * to the read methods.
- */
- System.arraycopy(rawData, rawPos, chunkData, chunkCount, copyLen);
- rawPos += copyLen;
- chunkCount += copyLen;
- chunkRead += copyLen;
-
- /*
- * If all the chunk has been copied into chunkData then the next
- * token should be CRLF.
- */
- if (chunkSize - chunkRead <= 0) {
- state = STATE_AWAITING_CHUNK_EOL;
- } else {
- return;
- }
- break;
-
-
- /**
- * Awaiting CRLF after the chunk
- */
- case STATE_AWAITING_CHUNK_EOL:
- /* not available yet */
- if (rawPos + 1 >= rawCount) {
- return;
- }
-
- if (rawData[rawPos] != '\r') {
- error = true;
- throw new IOException("missing CR");
- }
- if (rawData[rawPos+1] != '\n') {
- error = true;
- throw new IOException("missing LF");
- }
- rawPos += 2;
-
- /*
- * Move onto the next chunk
- */
- state = STATE_AWAITING_CHUNK_HEADER;
- break;
-
-
- /**
- * Last chunk has been read so not we're waiting for optional
- * trailers.
- */
- case STATE_AWAITING_TRAILERS:
-
- /*
- * Do we have an entire line in the raw buffer?
- */
- pos = rawPos;
- while (pos < rawCount) {
- if (rawData[pos] == '\n') {
- break;
- }
- pos++;
- }
- if (pos >= rawCount) {
- return;
- }
-
- if (pos == rawPos) {
- error = true;
- throw new IOException("LF should be proceeded by CR");
- }
- if (rawData[pos-1] != '\r') {
- error = true;
- throw new IOException("LF should be proceeded by CR");
- }
-
- /*
- * Stream done so close underlying stream.
- */
- if (pos == (rawPos + 1)) {
-
- state = STATE_DONE;
- closeUnderlying();
-
- return;
- }
-
- /*
- * Extract any tailers and append them to the message
- * headers.
- */
- String trailer = new String(rawData, rawPos, pos-rawPos, "US-ASCII");
- i = trailer.indexOf(':');
- if (i == -1) {
- throw new IOException("Malformed tailer - format should be key:value");
- }
- String key = (trailer.substring(0, i)).trim();
- String value = (trailer.substring(i+1, trailer.length())).trim();
-
- responses.add(key, value);
-
- /*
- * Move onto the next trailer.
- */
- rawPos = pos+1;
- break;
-
- } /* switch */
- }
- }
-
-
- /**
- * Reads any available bytes from the underlying stream into
- * <code>rawData</code> and returns the number of bytes of
- * chunk data available in <code>chunkData</code> that the
- * application can read.
- */
- private int readAheadNonBlocking() throws IOException {
-
- /*
- * If there's anything available on the underlying stream then we read
- * it into the raw buffer and process it. Processing ensures that any
- * available chunk data is made available in chunkData.
- */
- int avail = in.available();
- if (avail > 0) {
-
- /* ensure that there is space in rawData to read the available */
- ensureRawAvailable(avail);
-
- int nread;
- try {
- nread = in.read(rawData, rawCount, avail);
- } catch (IOException e) {
- error = true;
- throw e;
- }
- if (nread < 0) {
- error = true; /* premature EOF ? */
- return -1;
- }
- rawCount += nread;
-
- /*
- * Process the raw bytes that have been read.
- */
- processRaw();
- }
-
- /*
- * Return the number of chunked bytes available to read
- */
- return chunkCount - chunkPos;
- }
-
- /**
- * Reads from the underlying stream until there is chunk data
- * available in <code>chunkData</code> for the application to
- * read.
- */
- private int readAheadBlocking() throws IOException {
-
- do {
- /*
- * All of chunked response has been read to return EOF.
- */
- if (state == STATE_DONE) {
- return -1;
- }
-
- /*
- * We must read into the raw buffer so make sure there is space
- * available. We use a size of 32 to avoid too much chunk data
- * being read into the raw buffer.
- */
- ensureRawAvailable(32);
- int nread;
- try {
- nread = in.read(rawData, rawCount, rawData.length-rawCount);
- } catch (IOException e) {
- error = true;
- throw e;
- }
-
- /**
- * If we hit EOF it means there's a problem as we should never
- * attempt to read once the last chunk and trailers have been
- * received.
- */
- if (nread < 0) {
- error = true;
- throw new IOException("Premature EOF");
- }
-
- /**
- * Process the bytes from the underlying stream
- */
- rawCount += nread;
- processRaw();
-
- } while (chunkCount <= 0);
-
- /*
- * Return the number of chunked bytes available to read
- */
- return chunkCount - chunkPos;
- }
-
- /**
- * Read ahead in either blocking or non-blocking mode. This method
- * is typically used when we run out of available bytes in
- * <code>chunkData</code> or we need to determine how many bytes
- * are available on the input stream.
- */
- private int readAhead(boolean allowBlocking) throws IOException {
-
- /*
- * Last chunk already received - return EOF
- */
- if (state == STATE_DONE) {
- return -1;
- }
-
- /*
- * Reset position/count if data in chunkData is exhausted.
- */
- if (chunkPos >= chunkCount) {
- chunkCount = 0;
- chunkPos = 0;
- }
-
- /*
- * Read ahead blocking or non-blocking
- */
- if (allowBlocking) {
- return readAheadBlocking();
- } else {
- return readAheadNonBlocking();
- }
- }
-
- /**
- * Creates a <code>ChunkedInputStream</code> and saves its arguments, for
- * later use.
- *
- * @param in the underlying input stream.
- * @param hc the HttpClient
- * @param responses the MessageHeader that should be populated with optional
- * trailers.
- */
- public ChunkedInputStream(InputStream in, HttpClient hc, MessageHeader responses) throws IOException {
-
- /* save arguments */
- this.in = in;
- this.responses = responses;
- this.hc = hc;
-
- /*
- * Set our initial state to indicate that we are first starting to
- * look for a chunk header.
- */
- state = STATE_AWAITING_CHUNK_HEADER;
- }
-
- /**
- * See
- * the general contract of the <code>read</code>
- * method of <code>InputStream</code>.
- *
- * @return the next byte of data, or <code>-1</code> if the end of the
- * stream is reached.
- * @exception IOException if an I/O error occurs.
- * @see java.io.FilterInputStream#in
- */
- public synchronized int read() throws IOException {
- ensureOpen();
- if (chunkPos >= chunkCount) {
- if (readAhead(true) <= 0) {
- return -1;
- }
- }
- return chunkData[chunkPos++] & 0xff;
- }
-
-
- /**
- * Reads bytes from this stream into the specified byte array, starting at
- * the given offset.
- *
- * @param b destination buffer.
- * @param off offset at which to start storing bytes.
- * @param len maximum number of bytes to read.
- * @return the number of bytes read, or <code>-1</code> if the end of
- * the stream has been reached.
- * @exception IOException if an I/O error occurs.
- */
- public synchronized int read(byte b[], int off, int len)
- throws IOException
- {
- ensureOpen();
- if ((off < 0) || (off > b.length) || (len < 0) ||
- ((off + len) > b.length) || ((off + len) < 0)) {
- throw new IndexOutOfBoundsException();
- } else if (len == 0) {
- return 0;
- }
-
- int avail = chunkCount - chunkPos;
- if (avail <= 0) {
- /*
- * Optimization: if we're in the middle of the chunk read
- * directly from the underlying stream into the caller's
- * buffer
- */
- if (state == STATE_READING_CHUNK) {
- return fastRead( b, off, len );
- }
-
- /*
- * We're not in the middle of a chunk so we must read ahead
- * until there is some chunk data available.
- */
- avail = readAhead(true);
- if (avail < 0) {
- return -1; /* EOF */
- }
- }
- int cnt = (avail < len) ? avail : len;
- System.arraycopy(chunkData, chunkPos, b, off, cnt);
- chunkPos += cnt;
-
- return cnt;
- }
-
- /**
- * Returns the number of bytes that can be read from this input
- * stream without blocking.
- *
- * @return the number of bytes that can be read from this input
- * stream without blocking.
- * @exception IOException if an I/O error occurs.
- * @see java.io.FilterInputStream#in
- */
- public synchronized int available() throws IOException {
- ensureOpen();
-
- int avail = chunkCount - chunkPos;
- if(avail > 0) {
- return avail;
- }
-
- avail = readAhead(false);
-
- if (avail < 0) {
- return 0;
- } else {
- return avail;
- }
- }
-
- /**
- * Close the stream by either returning the connection to the
- * keep alive cache or closing the underlying stream.
- * <p>
- * If the chunked response hasn't been completely read we
- * try to "hurry" to the end of the response. If this is
- * possible (without blocking) then the connection can be
- * returned to the keep alive cache.
- *
- * @exception IOException if an I/O error occurs.
- */
- public synchronized void close() throws IOException {
- if (closed) {
- return;
- }
- closeUnderlying();
- closed = true;
- }
-
- /**
- * Hurry the input stream by reading everything from the underlying
- * stream. If the last chunk (and optional trailers) can be read without
- * blocking then the stream is considered hurried.
- * <p>
- * Note that if an error has occured or we can't get to last chunk
- * without blocking then this stream can't be hurried and should be
- * closed.
- */
- public synchronized boolean hurry() {
- if (in == null || error) {
- return false;
- }
-
- try {
- readAhead(false);
- } catch (Exception e) {
- return false;
- }
-
- if (error) {
- return false;
- }
-
- return (state == STATE_DONE);
- }
-
-}
diff --git a/ojluni/src/main/java/sun/net/www/http/ChunkedOutputStream.java b/ojluni/src/main/java/sun/net/www/http/ChunkedOutputStream.java
deleted file mode 100644
index 2a0e35a..0000000
--- a/ojluni/src/main/java/sun/net/www/http/ChunkedOutputStream.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.net.www.http;
-
-import java.io.*;
-
-/**
- * OutputStream that sends the output to the underlying stream using chunked
- * encoding as specified in RFC 2068.
- */
-public class ChunkedOutputStream extends PrintStream {
-
- /* Default chunk size (including chunk header) if not specified */
- static final int DEFAULT_CHUNK_SIZE = 4096;
- private static final byte[] CRLF = {'\r', '\n'};
- private static final int CRLF_SIZE = CRLF.length;
- private static final byte[] FOOTER = CRLF;
- private static final int FOOTER_SIZE = CRLF_SIZE;
- private static final byte[] EMPTY_CHUNK_HEADER = getHeader(0);
- private static final int EMPTY_CHUNK_HEADER_SIZE = getHeaderSize(0);
-
- /* internal buffer */
- private byte buf[];
- /* size of data (excluding footers and headers) already stored in buf */
- private int size;
- /* current index in buf (i.e. buf[count] */
- private int count;
- /* number of bytes to be filled up to complete a data chunk
- * currently being built */
- private int spaceInCurrentChunk;
-
- /* underlying stream */
- private PrintStream out;
-
- /* the chunk size we use */
- private int preferredChunkDataSize;
- private int preferedHeaderSize;
- private int preferredChunkGrossSize;
- /* header for a complete Chunk */
- private byte[] completeHeader;
-
- /* return the size of the header for a particular chunk size */
- private static int getHeaderSize(int size) {
- return (Integer.toHexString(size)).length() + CRLF_SIZE;
- }
-
- /* return a header for a particular chunk size */
- private static byte[] getHeader(int size){
- try {
- String hexStr = Integer.toHexString(size);
- byte[] hexBytes = hexStr.getBytes("US-ASCII");
- byte[] header = new byte[getHeaderSize(size)];
- for (int i=0; i<hexBytes.length; i++)
- header[i] = hexBytes[i];
- header[hexBytes.length] = CRLF[0];
- header[hexBytes.length+1] = CRLF[1];
- return header;
- } catch (java.io.UnsupportedEncodingException e) {
- /* This should never happen */
- throw new InternalError(e.getMessage());
- }
- }
-
- public ChunkedOutputStream(PrintStream o) {
- this(o, DEFAULT_CHUNK_SIZE);
- }
-
- public ChunkedOutputStream(PrintStream o, int size) {
- super(o);
- out = o;
-
- if (size <= 0) {
- size = DEFAULT_CHUNK_SIZE;
- }
-
- /* Adjust the size to cater for the chunk header - eg: if the
- * preferred chunk size is 1k this means the chunk size should
- * be 1017 bytes (differs by 7 from preferred size because of
- * 3 bytes for chunk size in hex and CRLF (header) and CRLF (footer)).
- *
- * If headerSize(adjusted_size) is shorter then headerSize(size)
- * then try to use the extra byte unless headerSize(adjusted_size+1)
- * increases back to headerSize(size)
- */
- if (size > 0) {
- int adjusted_size = size - getHeaderSize(size) - FOOTER_SIZE;
- if (getHeaderSize(adjusted_size+1) < getHeaderSize(size)){
- adjusted_size++;
- }
- size = adjusted_size;
- }
-
- if (size > 0) {
- preferredChunkDataSize = size;
- } else {
- preferredChunkDataSize = DEFAULT_CHUNK_SIZE -
- getHeaderSize(DEFAULT_CHUNK_SIZE) - FOOTER_SIZE;
- }
-
- preferedHeaderSize = getHeaderSize(preferredChunkDataSize);
- preferredChunkGrossSize = preferedHeaderSize + preferredChunkDataSize
- + FOOTER_SIZE;
- completeHeader = getHeader(preferredChunkDataSize);
-
- /* start with an initial buffer */
- buf = new byte[preferredChunkDataSize + 32];
- reset();
- }
-
- /*
- * Flush a buffered, completed chunk to an underlying stream. If the data in
- * the buffer is insufficient to build up a chunk of "preferredChunkSize"
- * then the data do not get flushed unless flushAll is true. If flushAll is
- * true then the remaining data builds up a last chunk which size is smaller
- * than preferredChunkSize, and then the last chunk gets flushed to
- * underlying stream. If flushAll is true and there is no data in a buffer
- * at all then an empty chunk (containing a header only) gets flushed to
- * underlying stream.
- */
- private void flush(boolean flushAll) {
- if (spaceInCurrentChunk == 0) {
- /* flush a completed chunk to underlying stream */
- out.write(buf, 0, preferredChunkGrossSize);
- out.flush();
- reset();
- } else if (flushAll){
- /* complete the last chunk and flush it to underlying stream */
- if (size > 0){
- /* adjust a header start index in case the header of the last
- * chunk is shorter then preferedHeaderSize */
-
- int adjustedHeaderStartIndex = preferedHeaderSize -
- getHeaderSize(size);
-
- /* write header */
- System.arraycopy(getHeader(size), 0, buf,
- adjustedHeaderStartIndex, getHeaderSize(size));
-
- /* write footer */
- buf[count++] = FOOTER[0];
- buf[count++] = FOOTER[1];
-
- //send the last chunk to underlying stream
- out.write(buf, adjustedHeaderStartIndex, count - adjustedHeaderStartIndex);
- } else {
- //send an empty chunk (containing just a header) to underlying stream
- out.write(EMPTY_CHUNK_HEADER, 0, EMPTY_CHUNK_HEADER_SIZE);
- }
-
- out.flush();
- reset();
- }
- }
-
- @Override
- public boolean checkError() {
- return out.checkError();
- }
-
- /* Check that the output stream is still open */
- private void ensureOpen() {
- if (out == null)
- setError();
- }
-
- /*
- * Writes data from b[] to an internal buffer and stores the data as data
- * chunks of a following format: {Data length in Hex}{CRLF}{data}{CRLF}
- * The size of the data is preferredChunkSize. As soon as a completed chunk
- * is read from b[] a process of reading from b[] suspends, the chunk gets
- * flushed to the underlying stream and then the reading process from b[]
- * continues. When there is no more sufficient data in b[] to build up a
- * chunk of preferredChunkSize size the data get stored as an incomplete
- * chunk of a following format: {space for data length}{CRLF}{data}
- * The size of the data is of course smaller than preferredChunkSize.
- */
- @Override
- public synchronized void write(byte b[], int off, int len) {
- ensureOpen();
- if ((off < 0) || (off > b.length) || (len < 0) ||
- ((off + len) > b.length) || ((off + len) < 0)) {
- throw new IndexOutOfBoundsException();
- } else if (len == 0) {
- return;
- }
-
- /* if b[] contains enough data then one loop cycle creates one complete
- * data chunk with a header, body and a footer, and then flushes the
- * chunk to the underlying stream. Otherwise, the last loop cycle
- * creates incomplete data chunk with empty header and with no footer
- * and stores this incomplete chunk in an internal buffer buf[]
- */
- int bytesToWrite = len;
- int inputIndex = off; /* the index of the byte[] currently being written */
-
- do {
- /* enough data to complete a chunk */
- if (bytesToWrite >= spaceInCurrentChunk) {
-
- /* header */
- for (int i=0; i<completeHeader.length; i++)
- buf[i] = completeHeader[i];
-
- /* data */
- System.arraycopy(b, inputIndex, buf, count, spaceInCurrentChunk);
- inputIndex += spaceInCurrentChunk;
- bytesToWrite -= spaceInCurrentChunk;
- count += spaceInCurrentChunk;
-
- /* footer */
- buf[count++] = FOOTER[0];
- buf[count++] = FOOTER[1];
- spaceInCurrentChunk = 0; //chunk is complete
-
- flush(false);
- if (checkError()){
- break;
- }
- }
-
- /* not enough data to build a chunk */
- else {
- /* header */
- /* do not write header if not enough bytes to build a chunk yet */
-
- /* data */
- System.arraycopy(b, inputIndex, buf, count, bytesToWrite);
- count += bytesToWrite;
- size += bytesToWrite;
- spaceInCurrentChunk -= bytesToWrite;
- bytesToWrite = 0;
-
- /* footer */
- /* do not write header if not enough bytes to build a chunk yet */
- }
- } while (bytesToWrite > 0);
- }
-
- @Override
- public synchronized void write(int _b) {
- byte b[] = {(byte)_b};
- write(b, 0, 1);
- }
-
- public synchronized void reset() {
- count = preferedHeaderSize;
- size = 0;
- spaceInCurrentChunk = preferredChunkDataSize;
- }
-
- public int size() {
- return size;
- }
-
- @Override
- public synchronized void close() {
- ensureOpen();
-
- /* if we have buffer a chunked send it */
- if (size > 0) {
- flush(true);
- }
-
- /* send a zero length chunk */
- flush(true);
-
- /* don't close the underlying stream */
- out = null;
- }
-
- @Override
- public synchronized void flush() {
- ensureOpen();
- if (size > 0) {
- flush(true);
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/http/HttpCapture.java b/ojluni/src/main/java/sun/net/www/http/HttpCapture.java
deleted file mode 100644
index 7035295..0000000
--- a/ojluni/src/main/java/sun/net/www/http/HttpCapture.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.http;
-
-import java.io.*;
-import java.util.ArrayList;
-import java.util.regex.*;
-import sun.net.NetProperties;
-import sun.util.logging.PlatformLogger;
-
-/**
- * Main class of the HTTP traffic capture tool.
- * Captures are triggered by the sun.net.http.captureRules system property.
- * If set, it should point to a file containing the capture rules.
- * Format for the file is simple:
- * - 1 rule per line
- * - Lines starting with a # are considered comments and ignored
- * - a rule is a pair of a regular expression and file pattern, separated by a comma
- * - The regular expression is applied to URLs, if it matches, the traffic for
- * that URL will be captured in the associated file.
- * - if the file name contains a '%d', then that sequence will be replaced by a
- * unique random number for each URL. This allow for multi-threaded captures
- * of URLs matching the same pattern.
- * - Rules are checked in sequence, in the same order as in the file, until a
- * match is found or the end of the list is reached.
- *
- * Examples of rules:
- * www\.sun\.com , sun%d.log
- * yahoo\.com\/.*asf , yahoo.log
- *
- * @author jccollet
- */
-public class HttpCapture {
- private File file = null;
- private boolean incoming = true;
- private BufferedWriter out = null;
- private static boolean initialized = false;
- private static volatile ArrayList<Pattern> patterns = null;
- private static volatile ArrayList<String> capFiles = null;
-
- private static synchronized void init() {
- initialized = true;
- String rulesFile = java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<String>() {
- public String run() {
- return NetProperties.get("sun.net.http.captureRules");
- }
- });
- if (rulesFile != null && !rulesFile.isEmpty()) {
- BufferedReader in;
- try {
- in = new BufferedReader(new FileReader(rulesFile));
- } catch (FileNotFoundException ex) {
- return;
- }
- try {
- String line = in.readLine();
- while (line != null) {
- line = line.trim();
- if (!line.startsWith("#")) {
- // skip line if it's a comment
- String[] s = line.split(",");
- if (s.length == 2) {
- if (patterns == null) {
- patterns = new ArrayList<Pattern>();
- capFiles = new ArrayList<String>();
- }
- patterns.add(Pattern.compile(s[0].trim()));
- capFiles.add(s[1].trim());
- }
- }
- line = in.readLine();
- }
- } catch (IOException ioe) {
-
- } finally {
- try {
- in.close();
- } catch (IOException ex) {
- }
- }
- }
- }
-
- private static synchronized boolean isInitialized() {
- return initialized;
- }
-
- private HttpCapture(File f, java.net.URL url) {
- file = f;
- try {
- out = new BufferedWriter(new FileWriter(file, true));
- out.write("URL: " + url + "\n");
- } catch (IOException ex) {
- PlatformLogger.getLogger(HttpCapture.class.getName()).severe(null, ex);
- }
- }
-
- public synchronized void sent(int c) throws IOException {
- if (incoming) {
- out.write("\n------>\n");
- incoming = false;
- out.flush();
- }
- out.write(c);
- }
-
- public synchronized void received(int c) throws IOException {
- if (!incoming) {
- out.write("\n<------\n");
- incoming = true;
- out.flush();
- }
- out.write(c);
- }
-
- public synchronized void flush() throws IOException {
- out.flush();
- }
-
- public static HttpCapture getCapture(java.net.URL url) {
- if (!isInitialized()) {
- init();
- }
- if (patterns == null || patterns.isEmpty()) {
- return null;
- }
- String s = url.toString();
- for (int i = 0; i < patterns.size(); i++) {
- Pattern p = patterns.get(i);
- if (p.matcher(s).find()) {
- String f = capFiles.get(i);
- File fi;
- if (f.indexOf("%d") >= 0) {
- java.util.Random rand = new java.util.Random();
- do {
- String f2 = f.replace("%d", Integer.toString(rand.nextInt()));
- fi = new File(f2);
- } while (fi.exists());
- } else {
- fi = new File(f);
- }
- return new HttpCapture(fi, url);
- }
- }
- return null;
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/http/HttpCaptureInputStream.java b/ojluni/src/main/java/sun/net/www/http/HttpCaptureInputStream.java
deleted file mode 100644
index ff0edf5..0000000
--- a/ojluni/src/main/java/sun/net/www/http/HttpCaptureInputStream.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.http;
-import java.io.*;
-
-/**
- * A Simple FilterInputStream subclass to capture HTTP traffic.
- * Every byte read is also passed to the HttpCapture class.
- *
- * @author jccollet
- */
-public class HttpCaptureInputStream extends FilterInputStream {
- private HttpCapture capture = null;
-
- public HttpCaptureInputStream(InputStream in, HttpCapture cap) {
- super(in);
- capture = cap;
- }
-
- @Override
- public int read() throws IOException {
- int i = super.read();
- capture.received(i);
- return i;
- }
-
- @Override
- public void close() throws IOException {
- try {
- capture.flush();
- } catch (IOException iOException) {
- }
- super.close();
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- int ret = super.read(b);
- for (int i = 0; i < ret; i++) {
- capture.received(b[i]);
- }
- return ret;
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- int ret = super.read(b, off, len);
- for (int i = 0; i < ret; i++) {
- capture.received(b[off+i]);
- }
- return ret;
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/http/HttpCaptureOutputStream.java b/ojluni/src/main/java/sun/net/www/http/HttpCaptureOutputStream.java
deleted file mode 100644
index e402c1c..0000000
--- a/ojluni/src/main/java/sun/net/www/http/HttpCaptureOutputStream.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.http;
-import java.io.*;
-
-/**
- * A Simple FilterOutputStream subclass to capture HTTP traffic.
- * Every byte written is also passed to the HttpCapture class.
- *
- * @author jccollet
- */
-public class HttpCaptureOutputStream extends FilterOutputStream {
- private HttpCapture capture = null;
-
- public HttpCaptureOutputStream(OutputStream out, HttpCapture cap) {
- super(out);
- capture = cap;
- }
-
- @Override
- public void write(int b) throws IOException {
- capture.sent(b);
- out.write(b);
- }
-
- @Override
- public void write(byte[] ba) throws IOException {
- for (byte b : ba) {
- capture.sent(b);
- }
- out.write(ba);
- }
-
- @Override
- public void write(byte[] b, int off, int len) throws IOException {
- for (int i = off; i < len; i++) {
- capture.sent(b[i]);
- }
- out.write(b, off, len);
- }
-
- @Override
- public void flush() throws IOException {
- try {
- capture.flush();
- } catch (IOException iOException) {
- }
- super.flush();
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/http/HttpClient.java b/ojluni/src/main/java/sun/net/www/http/HttpClient.java
deleted file mode 100644
index 09e0dbb..0000000
--- a/ojluni/src/main/java/sun/net/www/http/HttpClient.java
+++ /dev/null
@@ -1,995 +0,0 @@
-/*
- * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.http;
-
-import java.io.*;
-import java.net.*;
-import java.util.Locale;
-import sun.net.NetworkClient;
-import sun.net.ProgressSource;
-import sun.net.www.MessageHeader;
-import sun.net.www.HeaderParser;
-import sun.net.www.MeteredStream;
-import sun.net.www.ParseUtil;
-import sun.net.www.protocol.http.HttpURLConnection;
-import sun.util.logging.PlatformLogger;
-import static sun.net.www.protocol.http.HttpURLConnection.TunnelState.*;
-
-/**
- * @author Herb Jellinek
- * @author Dave Brown
- */
-public class HttpClient extends NetworkClient {
- // whether this httpclient comes from the cache
- protected boolean cachedHttpClient = false;
-
- protected boolean inCache;
-
- // Http requests we send
- MessageHeader requests;
-
- // Http data we send with the headers
- PosterOutputStream poster = null;
-
- // true if we are in streaming mode (fixed length or chunked)
- boolean streaming;
-
- // if we've had one io error
- boolean failedOnce = false;
-
- /** Response code for CONTINUE */
- private boolean ignoreContinue = true;
- private static final int HTTP_CONTINUE = 100;
-
- /** Default port number for http daemons. REMIND: make these private */
- static final int httpPortNumber = 80;
-
- /** return default port number (subclasses may override) */
- protected int getDefaultPort () { return httpPortNumber; }
-
- static private int getDefaultPort(String proto) {
- if ("http".equalsIgnoreCase(proto))
- return 80;
- if ("https".equalsIgnoreCase(proto))
- return 443;
- return -1;
- }
-
- /* All proxying (generic as well as instance-specific) may be
- * disabled through use of this flag
- */
- protected boolean proxyDisabled;
-
- // are we using proxy in this instance?
- public boolean usingProxy = false;
- // target host, port for the URL
- protected String host;
- protected int port;
-
- /* where we cache currently open, persistent connections */
- protected static KeepAliveCache kac = new KeepAliveCache();
-
- private static boolean keepAliveProp = true;
-
- // retryPostProp is true by default so as to preserve behavior
- // from previous releases.
- private static boolean retryPostProp = true;
-
- volatile boolean keepingAlive = false; /* this is a keep-alive connection */
- int keepAliveConnections = -1; /* number of keep-alives left */
-
- /**Idle timeout value, in milliseconds. Zero means infinity,
- * iff keepingAlive=true.
- * Unfortunately, we can't always believe this one. If I'm connected
- * through a Netscape proxy to a server that sent me a keep-alive
- * time of 15 sec, the proxy unilaterally terminates my connection
- * after 5 sec. So we have to hard code our effective timeout to
- * 4 sec for the case where we're using a proxy. *SIGH*
- */
- int keepAliveTimeout = 0;
-
- /** whether the response is to be cached */
- private CacheRequest cacheRequest = null;
-
- /** Url being fetched. */
- protected URL url;
-
- /* if set, the client will be reused and must not be put in cache */
- public boolean reuse = false;
-
- // Traffic capture tool, if configured. See HttpCapture class for info
- private HttpCapture capture = null;
-
- private static final PlatformLogger logger = HttpURLConnection.getHttpLogger();
- private static void logFinest(String msg) {
- if (logger.isLoggable(PlatformLogger.FINEST)) {
- logger.finest(msg);
- }
- }
-
- /**
- * A NOP method kept for backwards binary compatibility
- * @deprecated -- system properties are no longer cached.
- */
- @Deprecated
- public static synchronized void resetProperties() {
- }
-
- int getKeepAliveTimeout() {
- return keepAliveTimeout;
- }
-
- static {
- String keepAlive = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("http.keepAlive"));
-
- String retryPost = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("sun.net.http.retryPost"));
-
- if (keepAlive != null) {
- keepAliveProp = Boolean.parseBoolean(keepAlive);
- } else {
- keepAliveProp = true;
- }
-
- if (retryPost != null) {
- retryPostProp = Boolean.parseBoolean(retryPost);
- } else
- retryPostProp = true;
-
- }
-
- /**
- * @return true iff http keep alive is set (i.e. enabled). Defaults
- * to true if the system property http.keepAlive isn't set.
- */
- public boolean getHttpKeepAliveSet() {
- return keepAliveProp;
- }
-
-
- protected HttpClient() {
- }
-
- private HttpClient(URL url)
- throws IOException {
- this(url, (String)null, -1, false);
- }
-
- protected HttpClient(URL url,
- boolean proxyDisabled) throws IOException {
- this(url, null, -1, proxyDisabled);
- }
-
- /* This package-only CTOR should only be used for FTP piggy-backed on HTTP
- * HTTP URL's that use this won't take advantage of keep-alive.
- * Additionally, this constructor may be used as a last resort when the
- * first HttpClient gotten through New() failed (probably b/c of a
- * Keep-Alive mismatch).
- *
- * XXX That documentation is wrong ... it's not package-private any more
- */
- public HttpClient(URL url, String proxyHost, int proxyPort)
- throws IOException {
- this(url, proxyHost, proxyPort, false);
- }
-
- protected HttpClient(URL url, Proxy p, int to) throws IOException {
- proxy = (p == null) ? Proxy.NO_PROXY : p;
- this.host = url.getHost();
- this.url = url;
- port = url.getPort();
- if (port == -1) {
- port = getDefaultPort();
- }
- setConnectTimeout(to);
-
- capture = HttpCapture.getCapture(url);
- openServer();
- }
-
- static protected Proxy newHttpProxy(String proxyHost, int proxyPort,
- String proto) {
- if (proxyHost == null || proto == null)
- return Proxy.NO_PROXY;
- int pport = proxyPort < 0 ? getDefaultPort(proto) : proxyPort;
- InetSocketAddress saddr = InetSocketAddress.createUnresolved(proxyHost, pport);
- return new Proxy(Proxy.Type.HTTP, saddr);
- }
-
- /*
- * This constructor gives "ultimate" flexibility, including the ability
- * to bypass implicit proxying. Sometimes we need to be using tunneling
- * (transport or network level) instead of proxying (application level),
- * for example when we don't want the application level data to become
- * visible to third parties.
- *
- * @param url the URL to which we're connecting
- * @param proxy proxy to use for this URL (e.g. forwarding)
- * @param proxyPort proxy port to use for this URL
- * @param proxyDisabled true to disable default proxying
- */
- private HttpClient(URL url, String proxyHost, int proxyPort,
- boolean proxyDisabled)
- throws IOException {
- this(url, proxyDisabled ? Proxy.NO_PROXY :
- newHttpProxy(proxyHost, proxyPort, "http"), -1);
- }
-
- public HttpClient(URL url, String proxyHost, int proxyPort,
- boolean proxyDisabled, int to)
- throws IOException {
- this(url, proxyDisabled ? Proxy.NO_PROXY :
- newHttpProxy(proxyHost, proxyPort, "http"), to);
- }
-
- /* This class has no public constructor for HTTP. This method is used to
- * get an HttpClient to the specifed URL. If there's currently an
- * active HttpClient to that server/port, you'll get that one.
- */
- public static HttpClient New(URL url)
- throws IOException {
- return HttpClient.New(url, Proxy.NO_PROXY, -1, true, null);
- }
-
- public static HttpClient New(URL url, boolean useCache)
- throws IOException {
- return HttpClient.New(url, Proxy.NO_PROXY, -1, useCache, null);
- }
-
- public static HttpClient New(URL url, Proxy p, int to, boolean useCache,
- HttpURLConnection httpuc) throws IOException
- {
- if (p == null) {
- p = Proxy.NO_PROXY;
- }
- HttpClient ret = null;
- /* see if one's already around */
- if (useCache) {
- ret = kac.get(url, null);
- if (ret != null && httpuc != null &&
- httpuc.streaming() &&
- httpuc.getRequestMethod() == "POST") {
- if (!ret.available()) {
- ret.inCache = false;
- ret.closeServer();
- ret = null;
- }
- }
-
- if (ret != null) {
- if ((ret.proxy != null && ret.proxy.equals(p)) ||
- (ret.proxy == null && p == null)) {
- synchronized (ret) {
- ret.cachedHttpClient = true;
- assert ret.inCache;
- ret.inCache = false;
- if (httpuc != null && ret.needsTunneling())
- httpuc.setTunnelState(TUNNELING);
- logFinest("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) {
- ret.inCache = false;
- ret.closeServer();
- }
- ret = null;
- }
- }
- }
- if (ret == null) {
- ret = new HttpClient(url, p, to);
- } 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;
- }
- return ret;
- }
-
- public static HttpClient New(URL url, Proxy p, int to,
- HttpURLConnection httpuc) throws IOException
- {
- return New(url, p, to, true, httpuc);
- }
-
- public static HttpClient New(URL url, String proxyHost, int proxyPort,
- boolean useCache)
- throws IOException {
- return New(url, newHttpProxy(proxyHost, proxyPort, "http"),
- -1, useCache, null);
- }
-
- public static HttpClient New(URL url, String proxyHost, int proxyPort,
- boolean useCache, int to,
- HttpURLConnection httpuc)
- throws IOException {
- return New(url, newHttpProxy(proxyHost, proxyPort, "http"),
- to, useCache, httpuc);
- }
-
- /* return it to the cache as still usable, if:
- * 1) It's keeping alive, AND
- * 2) It still has some connections left, AND
- * 3) It hasn't had a error (PrintStream.checkError())
- * 4) It hasn't timed out
- *
- * If this client is not keepingAlive, it should have been
- * removed from the cache in the parseHeaders() method.
- */
-
- public void finished() {
- if (reuse) /* will be reused */
- return;
- keepAliveConnections--;
- poster = null;
- if (keepAliveConnections > 0 && isKeepingAlive() &&
- !(serverOutput.checkError())) {
- /* This connection is keepingAlive && still valid.
- * Return it to the cache.
- */
- putInKeepAliveCache();
- } else {
- closeServer();
- }
- }
-
- protected synchronized boolean available() {
- boolean available = true;
- int old = -1;
-
- try {
- try {
- old = serverSocket.getSoTimeout();
- serverSocket.setSoTimeout(1);
- BufferedInputStream tmpbuf =
- new BufferedInputStream(serverSocket.getInputStream());
- int r = tmpbuf.read();
- if (r == -1) {
- logFinest("HttpClient.available(): " +
- "read returned -1: not available");
- available = false;
- }
- } catch (SocketTimeoutException e) {
- logFinest("HttpClient.available(): " +
- "SocketTimeout: its available");
- } finally {
- if (old != -1)
- serverSocket.setSoTimeout(old);
- }
- } catch (IOException e) {
- logFinest("HttpClient.available(): " +
- "SocketException: not available");
- available = false;
- }
- return available;
- }
-
- protected synchronized void putInKeepAliveCache() {
- if (inCache) {
- assert false : "Duplicate put to keep alive cache";
- return;
- }
- inCache = true;
- kac.put(url, null, this);
- }
-
- protected synchronized boolean isInKeepAliveCache() {
- return inCache;
- }
-
- /*
- * Close an idle connection to this URL (if it exists in the
- * cache).
- */
- public void closeIdleConnection() {
- HttpClient http = kac.get(url, null);
- if (http != null) {
- http.closeServer();
- }
- }
-
- /* We're very particular here about what our InputStream to the server
- * looks like for reasons that are apparent if you can decipher the
- * method parseHTTP(). That's why this method is overidden from the
- * superclass.
- */
- @Override
- public void openServer(String server, int port) throws IOException {
- serverSocket = doConnect(server, port);
- try {
- OutputStream out = serverSocket.getOutputStream();
- if (capture != null) {
- out = new HttpCaptureOutputStream(out, capture);
- }
- serverOutput = new PrintStream(
- new BufferedOutputStream(out),
- false, encoding);
- } catch (UnsupportedEncodingException e) {
- throw new InternalError(encoding+" encoding not found");
- }
- serverSocket.setTcpNoDelay(true);
- }
-
- /*
- * Returns true if the http request should be tunneled through proxy.
- * An example where this is the case is Https.
- */
- public boolean needsTunneling() {
- return false;
- }
-
- /*
- * Returns true if this httpclient is from cache
- */
- public synchronized boolean isCachedConnection() {
- return cachedHttpClient;
- }
-
- /*
- * Finish any work left after the socket connection is
- * established. In the normal http case, it's a NO-OP. Subclass
- * may need to override this. An example is Https, where for
- * direct connection to the origin server, ssl handshake needs to
- * be done; for proxy tunneling, the socket needs to be converted
- * into an SSL socket before ssl handshake can take place.
- */
- public void afterConnect() throws IOException, UnknownHostException {
- // NO-OP. Needs to be overwritten by HttpsClient
- }
-
- /*
- * call openServer in a privileged block
- */
- private synchronized void privilegedOpenServer(final InetSocketAddress server)
- throws IOException
- {
- try {
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedExceptionAction<Void>() {
- public Void run() throws IOException {
- openServer(server.getHostString(), server.getPort());
- return null;
- }
- });
- } catch (java.security.PrivilegedActionException pae) {
- throw (IOException) pae.getException();
- }
- }
-
- /*
- * call super.openServer
- */
- private void superOpenServer(final String proxyHost,
- final int proxyPort)
- throws IOException, UnknownHostException
- {
- super.openServer(proxyHost, proxyPort);
- }
-
- /*
- */
- protected synchronized void openServer() throws IOException {
-
- SecurityManager security = System.getSecurityManager();
-
- if (security != null) {
- security.checkConnect(host, port);
- }
-
- if (keepingAlive) { // already opened
- return;
- }
-
- if (url.getProtocol().equals("http") ||
- url.getProtocol().equals("https") ) {
-
- if ((proxy != null) && (proxy.type() == Proxy.Type.HTTP)) {
- sun.net.www.URLConnection.setProxiedHost(host);
- privilegedOpenServer((InetSocketAddress) proxy.address());
- usingProxy = true;
- return;
- } else {
- // make direct connection
- openServer(host, port);
- usingProxy = false;
- return;
- }
-
- } else {
- /* we're opening some other kind of url, most likely an
- * ftp url.
- */
- if ((proxy != null) && (proxy.type() == Proxy.Type.HTTP)) {
- sun.net.www.URLConnection.setProxiedHost(host);
- privilegedOpenServer((InetSocketAddress) proxy.address());
- usingProxy = true;
- return;
- } else {
- // make direct connection
- super.openServer(host, port);
- usingProxy = false;
- return;
- }
- }
- }
-
- public String getURLFile() throws IOException {
-
- String fileName = url.getFile();
- if ((fileName == null) || (fileName.length() == 0))
- fileName = "/";
-
- /**
- * proxyDisabled is set by subclass HttpsClient!
- */
- if (usingProxy && !proxyDisabled) {
- // Do not use URLStreamHandler.toExternalForm as the fragment
- // should not be part of the RequestURI. It should be an
- // absolute URI which does not have a fragment part.
- StringBuffer result = new StringBuffer(128);
- result.append(url.getProtocol());
- result.append(":");
- if (url.getAuthority() != null && url.getAuthority().length() > 0) {
- result.append("//");
- result.append(url.getAuthority());
- }
- if (url.getPath() != null) {
- result.append(url.getPath());
- }
- if (url.getQuery() != null) {
- result.append('?');
- result.append(url.getQuery());
- }
-
- fileName = result.toString();
- }
- if (fileName.indexOf('\n') == -1)
- return fileName;
- else
- throw new java.net.MalformedURLException("Illegal character in URL");
- }
-
- /**
- * @deprecated
- */
- @Deprecated
- public void writeRequests(MessageHeader head) {
- requests = head;
- requests.print(serverOutput);
- serverOutput.flush();
- }
-
- public void writeRequests(MessageHeader head,
- PosterOutputStream pos) throws IOException {
- requests = head;
- requests.print(serverOutput);
- poster = pos;
- if (poster != null)
- poster.writeTo(serverOutput);
- serverOutput.flush();
- }
-
- public void writeRequests(MessageHeader head,
- PosterOutputStream pos,
- boolean streaming) throws IOException {
- this.streaming = streaming;
- writeRequests(head, pos);
- }
-
- /** Parse the first line of the HTTP request. It usually looks
- something like: "HTTP/1.0 <number> comment\r\n". */
-
- public boolean parseHTTP(MessageHeader responses, ProgressSource pi, HttpURLConnection httpuc)
- throws IOException {
- /* If "HTTP/*" is found in the beginning, return true. Let
- * HttpURLConnection parse the mime header itself.
- *
- * If this isn't valid HTTP, then we don't try to parse a header
- * out of the beginning of the response into the responses,
- * and instead just queue up the output stream to it's very beginning.
- * This seems most reasonable, and is what the NN browser does.
- */
-
- try {
- serverInput = serverSocket.getInputStream();
- if (capture != null) {
- serverInput = new HttpCaptureInputStream(serverInput, capture);
- }
- serverInput = new BufferedInputStream(serverInput);
- return (parseHTTPHeader(responses, pi, httpuc));
- } catch (SocketTimeoutException stex) {
- // We don't want to retry the request when the app. sets a timeout
- // but don't close the server if timeout while waiting for 100-continue
- if (ignoreContinue) {
- closeServer();
- }
- throw stex;
- } catch (IOException e) {
- closeServer();
- cachedHttpClient = false;
- if (!failedOnce && requests != null) {
- failedOnce = true;
- if (getRequestMethod().equals("CONNECT") ||
- (httpuc.getRequestMethod().equals("POST") &&
- (!retryPostProp || streaming))) {
- // do not retry the request
- } else {
- // try once more
- openServer();
- if (needsTunneling()) {
- httpuc.doTunneling();
- }
- afterConnect();
- writeRequests(requests, poster);
- return parseHTTP(responses, pi, httpuc);
- }
- }
- throw e;
- }
-
- }
-
- private boolean parseHTTPHeader(MessageHeader responses, ProgressSource pi, HttpURLConnection httpuc)
- throws IOException {
- /* If "HTTP/*" is found in the beginning, return true. Let
- * HttpURLConnection parse the mime header itself.
- *
- * If this isn't valid HTTP, then we don't try to parse a header
- * out of the beginning of the response into the responses,
- * and instead just queue up the output stream to it's very beginning.
- * This seems most reasonable, and is what the NN browser does.
- */
-
- keepAliveConnections = -1;
- keepAliveTimeout = 0;
-
- boolean ret = false;
- byte[] b = new byte[8];
-
- try {
- int nread = 0;
- serverInput.mark(10);
- while (nread < 8) {
- int r = serverInput.read(b, nread, 8 - nread);
- if (r < 0) {
- break;
- }
- nread += r;
- }
- String keep=null;
- ret = b[0] == 'H' && b[1] == 'T'
- && b[2] == 'T' && b[3] == 'P' && b[4] == '/' &&
- b[5] == '1' && b[6] == '.';
- serverInput.reset();
- if (ret) { // is valid HTTP - response started w/ "HTTP/1."
- responses.parseHeader(serverInput);
-
- // we've finished parsing http headers
- // check if there are any applicable cookies to set (in cache)
- CookieHandler cookieHandler = httpuc.getCookieHandler();
- if (cookieHandler != null) {
- URI uri = ParseUtil.toURI(url);
- // NOTE: That cast from Map shouldn't be necessary but
- // a bug in javac is triggered under certain circumstances
- // So we do put the cast in as a workaround until
- // it is resolved.
- if (uri != null)
- cookieHandler.put(uri, responses.getHeaders());
- }
-
- /* decide if we're keeping alive:
- * This is a bit tricky. There's a spec, but most current
- * servers (10/1/96) that support this differ in dialects.
- * If the server/client misunderstand each other, the
- * protocol should fall back onto HTTP/1.0, no keep-alive.
- */
- if (usingProxy) { // not likely a proxy will return this
- keep = responses.findValue("Proxy-Connection");
- }
- if (keep == null) {
- keep = responses.findValue("Connection");
- }
- if (keep != null && keep.toLowerCase(Locale.US).equals("keep-alive")) {
- /* some servers, notably Apache1.1, send something like:
- * "Keep-Alive: timeout=15, max=1" which we should respect.
- */
- HeaderParser p = new HeaderParser(
- responses.findValue("Keep-Alive"));
- if (p != null) {
- /* default should be larger in case of proxy */
- keepAliveConnections = p.findInt("max", usingProxy?50:5);
- keepAliveTimeout = p.findInt("timeout", usingProxy?60:5);
- }
- } else if (b[7] != '0') {
- /*
- * We're talking 1.1 or later. Keep persistent until
- * the server says to close.
- */
- if (keep != null) {
- /*
- * The only Connection token we understand is close.
- * Paranoia: if there is any Connection header then
- * treat as non-persistent.
- */
- keepAliveConnections = 1;
- } else {
- keepAliveConnections = 5;
- }
- }
- } else if (nread != 8) {
- if (!failedOnce && requests != null) {
- failedOnce = true;
- if (getRequestMethod().equals("CONNECT") ||
- (httpuc.getRequestMethod().equals("POST") &&
- (!retryPostProp || streaming))) {
- // do not retry the request
- } else {
- closeServer();
- cachedHttpClient = false;
- openServer();
- if (needsTunneling()) {
- httpuc.doTunneling();
- }
- afterConnect();
- writeRequests(requests, poster);
- return parseHTTP(responses, pi, httpuc);
- }
- }
- throw new SocketException("Unexpected end of file from server");
- } else {
- // we can't vouche for what this is....
- responses.set("Content-type", "unknown/unknown");
- }
- } catch (IOException e) {
- throw e;
- }
-
- int code = -1;
- try {
- String resp;
- resp = responses.getValue(0);
- /* should have no leading/trailing LWS
- * expedite the typical case by assuming it has
- * form "HTTP/1.x <WS> 2XX <mumble>"
- */
- int ind;
- ind = resp.indexOf(' ');
- while(resp.charAt(ind) == ' ')
- ind++;
- code = Integer.parseInt(resp.substring(ind, ind + 3));
- } catch (Exception e) {}
-
- if (code == HTTP_CONTINUE && ignoreContinue) {
- responses.reset();
- return parseHTTPHeader(responses, pi, httpuc);
- }
-
- long cl = -1;
-
- /*
- * Set things up to parse the entity body of the reply.
- * We should be smarter about avoid pointless work when
- * the HTTP method and response code indicate there will be
- * no entity body to parse.
- */
- String te = responses.findValue("Transfer-Encoding");
- if (te != null && te.equalsIgnoreCase("chunked")) {
- serverInput = new ChunkedInputStream(serverInput, this, responses);
-
- /*
- * If keep alive not specified then close after the stream
- * has completed.
- */
- if (keepAliveConnections <= 1) {
- keepAliveConnections = 1;
- keepingAlive = false;
- } else {
- keepingAlive = true;
- }
- failedOnce = false;
- } else {
-
- /*
- * If it's a keep alive connection then we will keep
- * (alive if :-
- * 1. content-length is specified, or
- * 2. "Not-Modified" or "No-Content" responses - RFC 2616 states that
- * 204 or 304 response must not include a message body.
- */
- String cls = responses.findValue("content-length");
- if (cls != null) {
- try {
- cl = Long.parseLong(cls);
- } catch (NumberFormatException e) {
- cl = -1;
- }
- }
- String requestLine = requests.getKey(0);
-
- if ((requestLine != null &&
- (requestLine.startsWith("HEAD"))) ||
- code == HttpURLConnection.HTTP_NOT_MODIFIED ||
- code == HttpURLConnection.HTTP_NO_CONTENT) {
- cl = 0;
- }
-
- if (keepAliveConnections > 1 &&
- (cl >= 0 ||
- code == HttpURLConnection.HTTP_NOT_MODIFIED ||
- code == HttpURLConnection.HTTP_NO_CONTENT)) {
- keepingAlive = true;
- failedOnce = false;
- } else if (keepingAlive) {
- /* Previously we were keeping alive, and now we're not. Remove
- * this from the cache (but only here, once) - otherwise we get
- * multiple removes and the cache count gets messed up.
- */
- keepingAlive=false;
- }
- }
-
- /* wrap a KeepAliveStream/MeteredStream around it if appropriate */
-
- if (cl > 0) {
- // In this case, content length is well known, so it is okay
- // to wrap the input stream with KeepAliveStream/MeteredStream.
-
- if (pi != null) {
- // Progress monitor is enabled
- pi.setContentType(responses.findValue("content-type"));
- }
-
- if (isKeepingAlive()) {
- // Wrap KeepAliveStream if keep alive is enabled.
- logFinest("KeepAlive stream used: " + url);
- serverInput = new KeepAliveStream(serverInput, pi, cl, this);
- failedOnce = false;
- }
- else {
- serverInput = new MeteredStream(serverInput, pi, cl);
- }
- }
- else if (cl == -1) {
- // In this case, content length is unknown - the input
- // stream would simply be a regular InputStream or
- // ChunkedInputStream.
-
- if (pi != null) {
- // Progress monitoring is enabled.
-
- pi.setContentType(responses.findValue("content-type"));
-
- // Wrap MeteredStream for tracking indeterministic
- // progress, even if the input stream is ChunkedInputStream.
- serverInput = new MeteredStream(serverInput, pi, cl);
- }
- else {
- // Progress monitoring is disabled, and there is no
- // need to wrap an unknown length input stream.
-
- // ** This is an no-op **
- }
- }
- else {
- if (pi != null)
- pi.finishTracking();
- }
-
- return ret;
- }
-
- public synchronized InputStream getInputStream() {
- return serverInput;
- }
-
- public OutputStream getOutputStream() {
- return serverOutput;
- }
-
- @Override
- public String toString() {
- return getClass().getName()+"("+url+")";
- }
-
- public final boolean isKeepingAlive() {
- return getHttpKeepAliveSet() && keepingAlive;
- }
-
- public void setCacheRequest(CacheRequest cacheRequest) {
- this.cacheRequest = cacheRequest;
- }
-
- CacheRequest getCacheRequest() {
- return cacheRequest;
- }
-
- String getRequestMethod() {
- if (requests != null) {
- String requestLine = requests.getKey(0);
- if (requestLine != null) {
- return requestLine.split("\\s+")[0];
- }
- }
- return "";
- }
-
- @Override
- protected void finalize() throws Throwable {
- // This should do nothing. The stream finalizer will
- // close the fd.
- }
-
- public void setDoNotRetry(boolean value) {
- // failedOnce is used to determine if a request should be retried.
- failedOnce = value;
- }
-
- public void setIgnoreContinue(boolean value) {
- ignoreContinue = value;
- }
-
- /* Use only on connections in error. */
- @Override
- public void closeServer() {
- try {
- keepingAlive = false;
- serverSocket.close();
- } catch (Exception e) {}
- }
-
- /**
- * @return the proxy host being used for this client, or null
- * if we're not going through a proxy
- */
- public String getProxyHostUsed() {
- if (!usingProxy) {
- return null;
- } else {
- return ((InetSocketAddress)proxy.address()).getHostString();
- }
- }
-
- /**
- * @return the proxy port being used for this client. Meaningless
- * if getProxyHostUsed() gives null.
- */
- public int getProxyPortUsed() {
- if (usingProxy)
- return ((InetSocketAddress)proxy.address()).getPort();
- return -1;
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/http/Hurryable.java b/ojluni/src/main/java/sun/net/www/http/Hurryable.java
deleted file mode 100644
index 49a74fc..0000000
--- a/ojluni/src/main/java/sun/net/www/http/Hurryable.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.net.www.http;
-
-/**
- * A <code>Hurryable</code> is a class that has been instructed to complete
- * its input processing so as to make resource associated with that input
- * available to others.
- */
-public interface Hurryable {
-
- /**
- * @return a <code>boolean</code> indicating if the stream has been
- * hurried or not.
- */
- boolean hurry();
-
-}
diff --git a/ojluni/src/main/java/sun/net/www/http/KeepAliveCache.java b/ojluni/src/main/java/sun/net/www/http/KeepAliveCache.java
deleted file mode 100644
index 16f02d7..0000000
--- a/ojluni/src/main/java/sun/net/www/http/KeepAliveCache.java
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.http;
-
-import java.io.IOException;
-import java.io.NotSerializableException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.net.URL;
-
-/**
- * A class that implements a cache of idle Http connections for keep-alive
- *
- * @author Stephen R. Pietrowicz (NCSA)
- * @author Dave Brown
- */
-public class KeepAliveCache
- extends HashMap<KeepAliveKey, ClientVector>
- implements Runnable {
- private static final long serialVersionUID = -2937172892064557949L;
-
- /* maximum # keep-alive connections to maintain at once
- * This should be 2 by the HTTP spec, but because we don't support pipe-lining
- * a larger value is more appropriate. So we now set a default of 5, and the value
- * refers to the number of idle connections per destination (in the cache) only.
- * It can be reset by setting system property "http.maxConnections".
- */
- static final int MAX_CONNECTIONS = 5;
- static int result = -1;
- static int getMaxConnections() {
- if (result == -1) {
- result = java.security.AccessController.doPrivileged(
- new sun.security.action.GetIntegerAction("http.maxConnections",
- MAX_CONNECTIONS))
- .intValue();
- if (result <= 0)
- result = MAX_CONNECTIONS;
- }
- return result;
- }
-
- static final int LIFETIME = 5000;
-
- private Thread keepAliveTimer = null;
-
- /**
- * Constructor
- */
- public KeepAliveCache() {}
-
- /**
- * Register this URL and HttpClient (that supports keep-alive) with the cache
- * @param url The URL contains info about the host and port
- * @param http The HttpClient to be cached
- */
- public synchronized void put(final URL url, Object obj, HttpClient http) {
- boolean startThread = (keepAliveTimer == null);
- if (!startThread) {
- if (!keepAliveTimer.isAlive()) {
- startThread = true;
- }
- }
- if (startThread) {
- clear();
- /* Unfortunately, we can't always believe the keep-alive timeout we got
- * back from the server. If I'm connected through a Netscape proxy
- * to a server that sent me a keep-alive
- * time of 15 sec, the proxy unilaterally terminates my connection
- * The robustness to get around this is in HttpClient.parseHTTP()
- */
- final KeepAliveCache cache = this;
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<Void>() {
- public Void run() {
- // We want to create the Keep-Alive-Timer in the
- // system threadgroup
- ThreadGroup grp = Thread.currentThread().getThreadGroup();
- ThreadGroup parent = null;
- while ((parent = grp.getParent()) != null) {
- grp = parent;
- }
-
- keepAliveTimer = new Thread(grp, cache, "Keep-Alive-Timer");
- keepAliveTimer.setDaemon(true);
- keepAliveTimer.setPriority(Thread.MAX_PRIORITY - 2);
- // Set the context class loader to null in order to avoid
- // keeping a strong reference to an application classloader.
- keepAliveTimer.setContextClassLoader(null);
- keepAliveTimer.start();
- return null;
- }
- });
- }
-
- KeepAliveKey key = new KeepAliveKey(url, obj);
- ClientVector v = super.get(key);
-
- if (v == null) {
- int keepAliveTimeout = http.getKeepAliveTimeout();
- v = new ClientVector(keepAliveTimeout > 0?
- keepAliveTimeout*1000 : LIFETIME);
- v.put(http);
- super.put(key, v);
- } else {
- v.put(http);
- }
- }
-
- /* remove an obsolete HttpClient from its VectorCache */
- public synchronized void remove (HttpClient h, Object obj) {
- KeepAliveKey key = new KeepAliveKey(h.url, obj);
- ClientVector v = super.get(key);
- if (v != null) {
- v.remove(h);
- if (v.empty()) {
- removeVector(key);
- }
- }
- }
-
- /* called by a clientVector thread when all its connections have timed out
- * and that vector of connections should be removed.
- */
- synchronized void removeVector(KeepAliveKey k) {
- super.remove(k);
- }
-
- /**
- * Check to see if this URL has a cached HttpClient
- */
- public synchronized HttpClient get(URL url, Object obj) {
-
- KeepAliveKey key = new KeepAliveKey(url, obj);
- ClientVector v = super.get(key);
- if (v == null) { // nothing in cache yet
- return null;
- }
- return v.get();
- }
-
- /* Sleeps for an alloted timeout, then checks for timed out connections.
- * Errs on the side of caution (leave connections idle for a relatively
- * short time).
- */
- @Override
- public void run() {
- do {
- try {
- Thread.sleep(LIFETIME);
- } catch (InterruptedException e) {}
- synchronized (this) {
- /* Remove all unused HttpClients. Starting from the
- * bottom of the stack (the least-recently used first).
- * REMIND: It'd be nice to not remove *all* connections
- * that aren't presently in use. One could have been added
- * a second ago that's still perfectly valid, and we're
- * needlessly axing it. But it's not clear how to do this
- * cleanly, and doing it right may be more trouble than it's
- * worth.
- */
-
- long currentTime = System.currentTimeMillis();
-
- ArrayList<KeepAliveKey> keysToRemove
- = new ArrayList<KeepAliveKey>();
-
- for (KeepAliveKey key : keySet()) {
- ClientVector v = get(key);
- synchronized (v) {
- int i;
-
- for (i = 0; i < v.size(); i++) {
- KeepAliveEntry e = v.elementAt(i);
- if ((currentTime - e.idleStartTime) > v.nap) {
- HttpClient h = e.hc;
- h.closeServer();
- } else {
- break;
- }
- }
- v.subList(0, i).clear();
-
- if (v.size() == 0) {
- keysToRemove.add(key);
- }
- }
- }
-
- for (KeepAliveKey key : keysToRemove) {
- removeVector(key);
- }
- }
- } while (size() > 0);
-
- return;
- }
-
- /*
- * Do not serialize this class!
- */
- private void writeObject(java.io.ObjectOutputStream stream)
- throws IOException {
- throw new NotSerializableException();
- }
-
- private void readObject(java.io.ObjectInputStream stream)
- throws IOException, ClassNotFoundException {
- throw new NotSerializableException();
- }
-}
-
-/* FILO order for recycling HttpClients, should run in a thread
- * to time them out. If > maxConns are in use, block.
- */
-
-
-class ClientVector extends java.util.Stack<KeepAliveEntry> {
- private static final long serialVersionUID = -8680532108106489459L;
-
- // sleep time in milliseconds, before cache clear
- int nap;
-
-
-
- ClientVector (int nap) {
- this.nap = nap;
- }
-
- synchronized HttpClient get() {
- if (empty()) {
- return null;
- } else {
- // Loop until we find a connection that has not timed out
- HttpClient hc = null;
- long currentTime = System.currentTimeMillis();
- do {
- KeepAliveEntry e = pop();
- if ((currentTime - e.idleStartTime) > nap) {
- e.hc.closeServer();
- } else {
- hc = e.hc;
- }
- } while ((hc== null) && (!empty()));
- return hc;
- }
- }
-
- /* return a still valid, unused HttpClient */
- synchronized void put(HttpClient h) {
- if (size() >= KeepAliveCache.getMaxConnections()) {
- h.closeServer(); // otherwise the connection remains in limbo
- } else {
- push(new KeepAliveEntry(h, System.currentTimeMillis()));
- }
- }
-
- /*
- * Do not serialize this class!
- */
- private void writeObject(java.io.ObjectOutputStream stream)
- throws IOException {
- throw new NotSerializableException();
- }
-
- private void readObject(java.io.ObjectInputStream stream)
- throws IOException, ClassNotFoundException {
- throw new NotSerializableException();
- }
-}
-
-
-class KeepAliveKey {
- private String protocol = null;
- private String host = null;
- private int port = 0;
- private Object obj = null; // additional key, such as socketfactory
-
- /**
- * Constructor
- *
- * @param url the URL containing the protocol, host and port information
- */
- public KeepAliveKey(URL url, Object obj) {
- this.protocol = url.getProtocol();
- this.host = url.getHost();
- this.port = url.getPort();
- this.obj = obj;
- }
-
- /**
- * Determine whether or not two objects of this type are equal
- */
- @Override
- public boolean equals(Object obj) {
- if ((obj instanceof KeepAliveKey) == false)
- return false;
- KeepAliveKey kae = (KeepAliveKey)obj;
- return host.equals(kae.host)
- && (port == kae.port)
- && protocol.equals(kae.protocol)
- && this.obj == kae.obj;
- }
-
- /**
- * The hashCode() for this object is the string hashCode() of
- * concatenation of the protocol, host name and port.
- */
- @Override
- public int hashCode() {
- String str = protocol+host+port;
- return this.obj == null? str.hashCode() :
- str.hashCode() + this.obj.hashCode();
- }
-}
-
-class KeepAliveEntry {
- HttpClient hc;
- long idleStartTime;
-
- KeepAliveEntry(HttpClient hc, long idleStartTime) {
- this.hc = hc;
- this.idleStartTime = idleStartTime;
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/http/KeepAliveStream.java b/ojluni/src/main/java/sun/net/www/http/KeepAliveStream.java
deleted file mode 100644
index 5d7bb57..0000000
--- a/ojluni/src/main/java/sun/net/www/http/KeepAliveStream.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.http;
-
-import java.io.*;
-import sun.net.ProgressSource;
-import sun.net.www.MeteredStream;
-
-/**
- * A stream that has the property of being able to be kept alive for
- * multiple downloads from the same server.
- *
- * @author Stephen R. Pietrowicz (NCSA)
- * @author Dave Brown
- */
-public
-class KeepAliveStream extends MeteredStream implements Hurryable {
-
- // instance variables
- HttpClient hc;
-
- boolean hurried;
-
- // has this KeepAliveStream been put on the queue for asynchronous cleanup.
- protected boolean queuedForCleanup = false;
-
- private static final KeepAliveStreamCleaner queue = new KeepAliveStreamCleaner();
- private static Thread cleanerThread; // null
-
- /**
- * Constructor
- */
- public KeepAliveStream(InputStream is, ProgressSource pi, long expected, HttpClient hc) {
- super(is, pi, expected);
- this.hc = hc;
- }
-
- /**
- * Attempt to cache this connection
- */
- public void close() throws IOException {
- // If the inputstream is closed already, just return.
- if (closed) {
- return;
- }
-
- // If this stream has already been queued for cleanup.
- if (queuedForCleanup) {
- return;
- }
-
- // Skip past the data that's left in the Inputstream because
- // some sort of error may have occurred.
- // Do this ONLY if the skip won't block. The stream may have
- // been closed at the beginning of a big file and we don't want
- // to hang around for nothing. So if we can't skip without blocking
- // we just close the socket and, therefore, terminate the keepAlive
- // NOTE: Don't close super class
- try {
- if (expected > count) {
- long nskip = (long) (expected - count);
- if (nskip <= available()) {
- long n = 0;
- while (n < nskip) {
- nskip = nskip - n;
- n = skip(nskip);
- }
- } else if (expected <= KeepAliveStreamCleaner.MAX_DATA_REMAINING && !hurried) {
- //put this KeepAliveStream on the queue so that the data remaining
- //on the socket can be cleanup asyncronously.
- queueForCleanup(new KeepAliveCleanerEntry(this, hc));
- } else {
- hc.closeServer();
- }
- }
- if (!closed && !hurried && !queuedForCleanup) {
- hc.finished();
- }
- } finally {
- if (pi != null)
- pi.finishTracking();
-
- if (!queuedForCleanup) {
- // nulling out the underlying inputstream as well as
- // httpClient to let gc collect the memories faster
- in = null;
- hc = null;
- closed = true;
- }
- }
- }
-
- /* we explicitly do not support mark/reset */
-
- public boolean markSupported() {
- return false;
- }
-
- public void mark(int limit) {}
-
- public void reset() throws IOException {
- throw new IOException("mark/reset not supported");
- }
-
- public synchronized boolean hurry() {
- try {
- /* CASE 0: we're actually already done */
- if (closed || count >= expected) {
- return false;
- } else if (in.available() < (expected - count)) {
- /* CASE I: can't meet the demand */
- return false;
- } else {
- /* CASE II: fill our internal buffer
- * Remind: possibly check memory here
- */
- int size = (int) (expected - count);
- byte[] buf = new byte[size];
- DataInputStream dis = new DataInputStream(in);
- dis.readFully(buf);
- in = new ByteArrayInputStream(buf);
- hurried = true;
- return true;
- }
- } catch (IOException e) {
- // e.printStackTrace();
- return false;
- }
- }
-
- private static void queueForCleanup(KeepAliveCleanerEntry kace) {
- synchronized(queue) {
- if(!kace.getQueuedForCleanup()) {
- if (!queue.offer(kace)) {
- kace.getHttpClient().closeServer();
- return;
- }
-
- kace.setQueuedForCleanup();
- queue.notifyAll();
- }
-
- boolean startCleanupThread = (cleanerThread == null);
- if (!startCleanupThread) {
- if (!cleanerThread.isAlive()) {
- startCleanupThread = true;
- }
- }
-
- if (startCleanupThread) {
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<Void>() {
- public Void run() {
- // We want to create the Keep-Alive-SocketCleaner in the
- // system threadgroup
- ThreadGroup grp = Thread.currentThread().getThreadGroup();
- ThreadGroup parent = null;
- while ((parent = grp.getParent()) != null) {
- grp = parent;
- }
-
- cleanerThread = new Thread(grp, queue, "Keep-Alive-SocketCleaner");
- cleanerThread.setDaemon(true);
- cleanerThread.setPriority(Thread.MAX_PRIORITY - 2);
- // Set the context class loader to null in order to avoid
- // keeping a strong reference to an application classloader.
- cleanerThread.setContextClassLoader(null);
- cleanerThread.start();
- return null;
- }
- });
- }
- } // queue
- }
-
- protected long remainingToRead() {
- return expected - count;
- }
-
- protected void setClosed() {
- in = null;
- hc = null;
- closed = true;
- }
-}
-
-
-class KeepAliveCleanerEntry
-{
- KeepAliveStream kas;
- HttpClient hc;
-
- public KeepAliveCleanerEntry(KeepAliveStream kas, HttpClient hc) {
- this.kas = kas;
- this.hc = hc;
- }
-
- protected KeepAliveStream getKeepAliveStream() {
- return kas;
- }
-
- protected HttpClient getHttpClient() {
- return hc;
- }
-
- protected void setQueuedForCleanup() {
- kas.queuedForCleanup = true;
- }
-
- protected boolean getQueuedForCleanup() {
- return kas.queuedForCleanup;
- }
-
-}
diff --git a/ojluni/src/main/java/sun/net/www/http/KeepAliveStreamCleaner.java b/ojluni/src/main/java/sun/net/www/http/KeepAliveStreamCleaner.java
deleted file mode 100644
index 87f0d09..0000000
--- a/ojluni/src/main/java/sun/net/www/http/KeepAliveStreamCleaner.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.http;
-
-import java.io.IOException;
-import java.util.LinkedList;
-import sun.net.NetProperties;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-
-/**
- * This class is used to cleanup any remaining data that may be on a KeepAliveStream
- * so that the connection can be cached in the KeepAliveCache.
- * Instances of this class can be used as a FIFO queue for KeepAliveCleanerEntry objects.
- * Executing this Runnable removes each KeepAliveCleanerEntry from the Queue, reads
- * the reamining bytes on its KeepAliveStream, and if successful puts the connection in
- * the KeepAliveCache.
- *
- * @author Chris Hegarty
- */
-
-@SuppressWarnings("serial") // never serialized
-class KeepAliveStreamCleaner
- extends LinkedList<KeepAliveCleanerEntry>
- implements Runnable
-{
- // maximum amount of remaining data that we will try to cleanup
- protected static int MAX_DATA_REMAINING = 512;
-
- // maximum amount of KeepAliveStreams to be queued
- protected static int MAX_CAPACITY = 10;
-
- // timeout for both socket and poll on the queue
- protected static final int TIMEOUT = 5000;
-
- // max retries for skipping data
- private static final int MAX_RETRIES = 5;
-
- static {
- final String maxDataKey = "http.KeepAlive.remainingData";
- int maxData = AccessController.doPrivileged(
- new PrivilegedAction<Integer>() {
- public Integer run() {
- return NetProperties.getInteger(maxDataKey, MAX_DATA_REMAINING);
- }}).intValue() * 1024;
- MAX_DATA_REMAINING = maxData;
-
- final String maxCapacityKey = "http.KeepAlive.queuedConnections";
- int maxCapacity = AccessController.doPrivileged(
- new PrivilegedAction<Integer>() {
- public Integer run() {
- return NetProperties.getInteger(maxCapacityKey, MAX_CAPACITY);
- }}).intValue();
- MAX_CAPACITY = maxCapacity;
-
- }
-
-
- @Override
- public boolean offer(KeepAliveCleanerEntry e) {
- if (size() >= MAX_CAPACITY)
- return false;
-
- return super.offer(e);
- }
-
- @Override
- public void run()
- {
- KeepAliveCleanerEntry kace = null;
-
- do {
- try {
- synchronized(this) {
- long before = System.currentTimeMillis();
- long timeout = TIMEOUT;
- while ((kace = poll()) == null) {
- this.wait(timeout);
-
- long after = System.currentTimeMillis();
- long elapsed = after - before;
- if (elapsed > timeout) {
- /* one last try */
- kace = poll();
- break;
- }
- before = after;
- timeout -= elapsed;
- }
- }
-
- if(kace == null)
- break;
-
- KeepAliveStream kas = kace.getKeepAliveStream();
-
- if (kas != null) {
- synchronized(kas) {
- HttpClient hc = kace.getHttpClient();
- try {
- if (hc != null && !hc.isInKeepAliveCache()) {
- int oldTimeout = hc.getReadTimeout();
- hc.setReadTimeout(TIMEOUT);
- long remainingToRead = kas.remainingToRead();
- if (remainingToRead > 0) {
- long n = 0;
- int retries = 0;
- while (n < remainingToRead && retries < MAX_RETRIES) {
- remainingToRead = remainingToRead - n;
- n = kas.skip(remainingToRead);
- if (n == 0)
- retries++;
- }
- remainingToRead = remainingToRead - n;
- }
- if (remainingToRead == 0) {
- hc.setReadTimeout(oldTimeout);
- hc.finished();
- } else
- hc.closeServer();
- }
- } catch (IOException ioe) {
- hc.closeServer();
- } finally {
- kas.setClosed();
- }
- }
- }
- } catch (InterruptedException ie) { }
- } while (kace != null);
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/http/PosterOutputStream.java b/ojluni/src/main/java/sun/net/www/http/PosterOutputStream.java
deleted file mode 100644
index eedd77e..0000000
--- a/ojluni/src/main/java/sun/net/www/http/PosterOutputStream.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.http;
-
-import java.io.*;
-import java.net.*;
-
-/**
- * Instances of this class are returned to applications for the purpose of
- * sending user data for a HTTP POST or PUT request. This class is used
- * when the content-length will be specified in the header of the request.
- * The semantics of ByteArrayOutputStream are extended so that
- * when close() is called, it is no longer possible to write
- * additional data to the stream. From this point the content length of
- * the request is fixed and cannot change.
- *
- * @author Michael McMahon
- */
-
-public class PosterOutputStream extends ByteArrayOutputStream {
-
- private boolean closed;
-
- /**
- * Creates a new output stream for POST user data
- */
- public PosterOutputStream () {
- super (256);
- }
-
- /**
- * Writes the specified byte to this output stream.
- *
- * @param b the byte to be written.
- */
- public synchronized void write(int b) {
- if (closed) {
- return;
- }
- super.write (b);
- }
-
- /**
- * Writes <code>len</code> bytes from the specified byte array
- * starting at offset <code>off</code> to this output stream.
- *
- * @param b the data.
- * @param off the start offset in the data.
- * @param len the number of bytes to write.
- */
- public synchronized void write(byte b[], int off, int len) {
- if (closed) {
- return;
- }
- super.write (b, off, len);
- }
-
- /**
- * Resets the <code>count</code> field of this output
- * stream to zero, so that all currently accumulated output in the
- * ouput stream is discarded. The output stream can be used again,
- * reusing the already allocated buffer space. If the output stream
- * has been closed, then this method has no effect.
- *
- * @see java.io.ByteArrayInputStream#count
- */
- public synchronized void reset() {
- if (closed) {
- return;
- }
- super.reset ();
- }
-
- /**
- * After close() has been called, it is no longer possible to write
- * to this stream. Further calls to write will have no effect.
- */
- public synchronized void close() throws IOException {
- closed = true;
- super.close ();
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java b/ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java
index e2b7fa1..24f2f3b 100644
--- a/ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java
+++ b/ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java
@@ -52,7 +52,6 @@
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;
@@ -82,8 +81,10 @@
*/
public class FtpURLConnection extends URLConnection {
- // In case we have to use proxies, we use HttpURLConnection
- HttpURLConnection http = null;
+// Android-changed: Removed support for proxying FTP over HTTP since it
+// relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+// // In case we have to use proxies, we use HttpURLConnection
+// HttpURLConnection http = null;
private Proxy instProxy;
InputStream is = null;
@@ -245,42 +246,50 @@
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;
- }
+ // Android-changed: Removed support for proxying FTP over HTTP since it
+ // relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+ sel.connectFailed(uri, p.address(), new IOException("FTP connections over HTTP proxy not supported"));
+ continue;
+// 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;
- }
+// Android-changed: Removed support for proxying FTP over HTTP since it
+// relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+// As specified in the documentation for URL.openConnection(Proxy), we
+// ignore the unsupported proxy and attempt a normal (direct) connection
+// 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) {
@@ -401,10 +410,11 @@
if (!connected) {
connect();
}
-
- if (http != null) {
- return http.getInputStream();
- }
+ // Android-changed: Removed support for proxying FTP over HTTP since it
+ // relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+// if (http != null) {
+// return http.getInputStream();
+// }
if (os != null) {
throw new IOException("Already opened for output");
@@ -515,14 +525,15 @@
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;
- }
+// Android-changed: Removed support for proxying FTP over HTTP since it
+// relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+// 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");
diff --git a/ojluni/src/main/java/sun/net/www/protocol/ftp/Handler.java b/ojluni/src/main/java/sun/net/www/protocol/ftp/Handler.java
index f5caad6..72143d9 100644
--- a/ojluni/src/main/java/sun/net/www/protocol/ftp/Handler.java
+++ b/ojluni/src/main/java/sun/net/www/protocol/ftp/Handler.java
@@ -30,12 +30,8 @@
package sun.net.www.protocol.ftp;
import java.io.IOException;
-import java.net.URL;
import java.net.Proxy;
-import java.util.Map;
-import java.util.HashMap;
-import sun.net.ftp.FtpClient;
-import sun.net.www.protocol.http.HttpURLConnection;
+import java.net.URL;
/** open an ftp connection given a URL */
public class Handler extends java.net.URLStreamHandler {
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/AuthCache.java b/ojluni/src/main/java/sun/net/www/protocol/http/AuthCache.java
deleted file mode 100644
index 6af6dd6..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/AuthCache.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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);
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/AuthCacheImpl.java b/ojluni/src/main/java/sun/net/www/protocol/http/AuthCacheImpl.java
deleted file mode 100644
index c2ebf42..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/AuthCacheImpl.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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;
-
-import java.io.IOException;
-import java.net.URL;
-import java.util.Hashtable;
-import java.util.LinkedList;
-import java.util.ListIterator;
-import java.util.Enumeration;
-import java.util.HashMap;
-
-/**
- * @author Michael McMahon
- */
-
-public class AuthCacheImpl implements AuthCache {
- HashMap hashtable;
-
- public AuthCacheImpl () {
- hashtable = new HashMap ();
- }
-
- public void setMap (HashMap 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 list = (LinkedList) hashtable.get (pkey);
- String skey = value.getPath();
- if (list == null) {
- list = new LinkedList ();
- hashtable.put (pkey, list);
- }
- // Check if the path already exists or a super-set of it exists
- ListIterator 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 list = (LinkedList) 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 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 list = (LinkedList) hashtable.get (pkey);
- if (list == null) {
- return;
- }
- if (entry == null) {
- list.clear();
- return;
- }
- ListIterator iter = list.listIterator ();
- while (iter.hasNext()) {
- AuthenticationInfo inf = (AuthenticationInfo)iter.next();
- if (entry.equals(inf)) {
- iter.remove ();
- }
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/AuthCacheValue.java b/ojluni/src/main/java/sun/net/www/protocol/http/AuthCacheValue.java
deleted file mode 100644
index d2c003e..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/AuthCacheValue.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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;
-
-import java.io.Serializable;
-import java.net.PasswordAuthentication;
-
-/**
- * AuthCacheValue: interface to minimise exposure to authentication cache
- * for external users (ie. plugin)
- *
- * @author Michael McMahon
- */
-
-public abstract class AuthCacheValue implements Serializable {
-
- 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();
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/AuthScheme.java b/ojluni/src/main/java/sun/net/www/protocol/http/AuthScheme.java
deleted file mode 100644
index 2c56632..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/AuthScheme.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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;
-}
-
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/AuthenticationHeader.java b/ojluni/src/main/java/sun/net/www/protocol/http/AuthenticationHeader.java
deleted file mode 100644
index eee2579..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/AuthenticationHeader.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (c) 2002, 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 sun.net.www.*;
-import java.util.Iterator;
-import java.util.HashMap;
-
-/**
- * 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 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
-
- /**
- * parse a set of authentication headers and choose the preferred scheme
- * that we support for a given host
- */
- public AuthenticationHeader (String hdrname, MessageHeader response,
- HttpCallerInfo hci, boolean dontUseNegotiate) {
- this.hci = hci;
- this.dontUseNegotiate = dontUseNegotiate;
- rsp = response;
- this.hdrname = hdrname;
- schemes = new HashMap();
- parse();
- }
-
- 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 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 () {
- Iterator iter = rsp.multiValueIterator (hdrname);
- while (iter.hasNext()) {
- String raw = (String)iter.next();
- HeaderParser hp = new HeaderParser (raw);
- Iterator 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);
- schemes.put (scheme, new SchemeMapValue (hpn, raw));
- }
- lastSchemeIndex = i;
- }
- }
- if (i > lastSchemeIndex) {
- HeaderParser hpn = hp.subsequence (lastSchemeIndex, i);
- String scheme = hpn.findKey(0);
- 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=(SchemeMapValue)schemes.get (authPref)) == null) {
-
- if(v == null && !dontUseNegotiate) {
- SchemeMapValue tmp = (SchemeMapValue)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 = (SchemeMapValue)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=(SchemeMapValue)schemes.get ("digest")) == null) {
- if (((v=(SchemeMapValue)schemes.get("ntlm"))==null)) {
- v = (SchemeMapValue)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;
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/AuthenticationInfo.java b/ojluni/src/main/java/sun/net/www/protocol/http/AuthenticationInfo.java
deleted file mode 100644
index 23e84ba..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/AuthenticationInfo.java
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * 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.
- */
-
-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 {
-
- // 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 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;
- }
-
- /**
- * 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);
- 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 ();
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/BasicAuthentication.java b/ojluni/src/main/java/sun/net/www/protocol/http/BasicAuthentication.java
deleted file mode 100644
index 7060372..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/BasicAuthentication.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.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 sun.net.www.HeaderParser;
-import sun.misc.BASE64Encoder;
-
-/**
- * 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 " + (new BasicBASE64Encoder()).encode(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 " + (new BasicBASE64Encoder()).encode(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;
- }
-
- /* It is never expected that the header value will exceed the bytesPerLine */
- private class BasicBASE64Encoder extends BASE64Encoder {
- @Override
- protected int bytesPerLine() {
- return (10000);
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/DigestAuthentication.java b/ojluni/src/main/java/sun/net/www/protocol/http/DigestAuthentication.java
deleted file mode 100644
index 981967b..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/DigestAuthentication.java
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * Copyright (c) 1997, 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.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 java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-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;
-
- // 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 value = authMethod
- + " username=\"" + pw.getUserName()
- + "\", realm=\"" + realm
- + "\", nonce=\"" + nonce
- + ncfield
- + ", uri=\"" + uri
- + "\", response=\"" + response
- + "\", algorithm=\"" + algorithm;
- if (opaque != null) {
- value = value + "\", opaque=\"" + opaque;
- }
- if (cnonce != null) {
- value = value + "\", cnonce=\"" + cnonce;
- }
- if (qop) {
- value = value + "\", qop=\"auth";
- }
- value = value + "\"";
- 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();
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/Handler.java b/ojluni/src/main/java/sun/net/www/protocol/http/Handler.java
deleted file mode 100644
index 0decc5c..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/Handler.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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);
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/HttpAuthenticator.java b/ojluni/src/main/java/sun/net/www/protocol/http/HttpAuthenticator.java
deleted file mode 100644
index 2990202..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/HttpAuthenticator.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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);
-
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/HttpCallerInfo.java b/ojluni/src/main/java/sun/net/www/protocol/http/HttpCallerInfo.java
deleted file mode 100644
index fcb3ac8..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/HttpCallerInfo.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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 = "";
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/HttpURLConnection.java b/ojluni/src/main/java/sun/net/www/protocol/http/HttpURLConnection.java
deleted file mode 100644
index b77976c..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/HttpURLConnection.java
+++ /dev/null
@@ -1,3384 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.protocol.http;
-
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.ProtocolException;
-import java.net.HttpRetryException;
-import java.net.PasswordAuthentication;
-import java.net.Authenticator;
-import java.net.HttpCookie;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.net.SocketTimeoutException;
-import java.net.Proxy;
-import java.net.ProxySelector;
-import java.net.URI;
-import java.net.InetSocketAddress;
-import java.net.CookieHandler;
-import java.net.ResponseCache;
-import java.net.CacheResponse;
-import java.net.SecureCacheResponse;
-import java.net.CacheRequest;
-import java.net.Authenticator.RequestorType;
-import java.io.*;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Map;
-import java.util.List;
-import java.util.Locale;
-import java.util.StringTokenizer;
-import java.util.Iterator;
-import java.util.HashSet;
-import java.util.HashMap;
-import java.util.Set;
-import sun.net.*;
-import sun.net.www.*;
-import sun.net.www.http.HttpClient;
-import sun.net.www.http.PosterOutputStream;
-import sun.net.www.http.ChunkedInputStream;
-import sun.net.www.http.ChunkedOutputStream;
-import sun.util.logging.PlatformLogger;
-import java.text.SimpleDateFormat;
-import java.util.TimeZone;
-import java.net.MalformedURLException;
-import java.nio.ByteBuffer;
-import static sun.net.www.protocol.http.AuthScheme.BASIC;
-import static sun.net.www.protocol.http.AuthScheme.DIGEST;
-import static sun.net.www.protocol.http.AuthScheme.NTLM;
-import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE;
-import static sun.net.www.protocol.http.AuthScheme.KERBEROS;
-import static sun.net.www.protocol.http.AuthScheme.UNKNOWN;
-
-/**
- * A class to represent an HTTP connection to a remote object.
- */
-
-
-public class HttpURLConnection extends java.net.HttpURLConnection {
-
- static String HTTP_CONNECT = "CONNECT";
-
- static final String version;
- public static final String userAgent;
-
- /* max # of allowed re-directs */
- static final int defaultmaxRedirects = 20;
- static final int maxRedirects;
-
- /* Not all servers support the (Proxy)-Authentication-Info headers.
- * By default, we don't require them to be sent
- */
- static final boolean validateProxy;
- static final boolean validateServer;
-
- private StreamingOutputStream strOutputStream;
- private final static String RETRY_MSG1 =
- "cannot retry due to proxy authentication, in streaming mode";
- private final static String RETRY_MSG2 =
- "cannot retry due to server authentication, in streaming mode";
- private final static String RETRY_MSG3 =
- "cannot retry due to redirection, in streaming mode";
-
- /*
- * System properties related to error stream handling:
- *
- * sun.net.http.errorstream.enableBuffering = <boolean>
- *
- * With the above system property set to true (default is false),
- * when the response code is >=400, the HTTP handler will try to
- * buffer the response body (up to a certain amount and within a
- * time limit). Thus freeing up the underlying socket connection
- * for reuse. The rationale behind this is that usually when the
- * server responds with a >=400 error (client error or server
- * error, such as 404 file not found), the server will send a
- * small response body to explain who to contact and what to do to
- * recover. With this property set to true, even if the
- * application doesn't call getErrorStream(), read the response
- * body, and then call close(), the underlying socket connection
- * can still be kept-alive and reused. The following two system
- * properties provide further control to the error stream
- * buffering behaviour.
- *
- * sun.net.http.errorstream.timeout = <int>
- * the timeout (in millisec) waiting the error stream
- * to be buffered; default is 300 ms
- *
- * sun.net.http.errorstream.bufferSize = <int>
- * the size (in bytes) to use for the buffering the error stream;
- * default is 4k
- */
-
-
- /* Should we enable buffering of error streams? */
- private static boolean enableESBuffer = false;
-
- /* timeout waiting for read for buffered error stream;
- */
- private static int timeout4ESBuffer = 0;
-
- /* buffer size for buffered error stream;
- */
- private static int bufSize4ES = 0;
-
- /*
- * Restrict setting of request headers through the public api
- * consistent with JavaScript XMLHttpRequest2 with a few
- * exceptions. Disallowed headers are silently ignored for
- * backwards compatibility reasons rather than throwing a
- * SecurityException. For example, some applets set the
- * Host header since old JREs did not implement HTTP 1.1.
- * Additionally, any header starting with Sec- is
- * disallowed.
- *
- * The following headers are allowed for historical reasons:
- *
- * Accept-Charset, Accept-Encoding, Cookie, Cookie2, Date,
- * Referer, TE, User-Agent, headers beginning with Proxy-.
- *
- * The following headers are allowed in a limited form:
- *
- * Connection: close
- *
- * See http://www.w3.org/TR/XMLHttpRequest2.
- */
- private static final boolean allowRestrictedHeaders;
- private static final Set<String> restrictedHeaderSet;
- private static final String[] restrictedHeaders = {
- /* Restricted by XMLHttpRequest2 */
- //"Accept-Charset",
- //"Accept-Encoding",
- "Access-Control-Request-Headers",
- "Access-Control-Request-Method",
- "Connection", /* close is allowed */
- "Content-Length",
- //"Cookie",
- //"Cookie2",
- "Content-Transfer-Encoding",
- //"Date",
- //"Expect",
- "Host",
- "Keep-Alive",
- "Origin",
- // "Referer",
- // "TE",
- "Trailer",
- "Transfer-Encoding",
- "Upgrade",
- //"User-Agent",
- "Via"
- };
-
- static {
- maxRedirects = java.security.AccessController.doPrivileged(
- new sun.security.action.GetIntegerAction(
- "http.maxRedirects", defaultmaxRedirects)).intValue();
- version = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("java.version"));
- String agent = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("http.agent"));
- if (agent == null) {
- agent = "Java/"+version;
- } else {
- agent = agent + " Java/"+version;
- }
- userAgent = agent;
- validateProxy = java.security.AccessController.doPrivileged(
- new sun.security.action.GetBooleanAction(
- "http.auth.digest.validateProxy")).booleanValue();
- validateServer = java.security.AccessController.doPrivileged(
- new sun.security.action.GetBooleanAction(
- "http.auth.digest.validateServer")).booleanValue();
-
- enableESBuffer = java.security.AccessController.doPrivileged(
- new sun.security.action.GetBooleanAction(
- "sun.net.http.errorstream.enableBuffering")).booleanValue();
- timeout4ESBuffer = java.security.AccessController.doPrivileged(
- new sun.security.action.GetIntegerAction(
- "sun.net.http.errorstream.timeout", 300)).intValue();
- if (timeout4ESBuffer <= 0) {
- timeout4ESBuffer = 300; // use the default
- }
-
- bufSize4ES = java.security.AccessController.doPrivileged(
- new sun.security.action.GetIntegerAction(
- "sun.net.http.errorstream.bufferSize", 4096)).intValue();
- if (bufSize4ES <= 0) {
- bufSize4ES = 4096; // use the default
- }
-
- allowRestrictedHeaders = ((Boolean)java.security.AccessController.doPrivileged(
- new sun.security.action.GetBooleanAction(
- "sun.net.http.allowRestrictedHeaders"))).booleanValue();
- if (!allowRestrictedHeaders) {
- restrictedHeaderSet = new HashSet<String>(restrictedHeaders.length);
- for (int i=0; i < restrictedHeaders.length; i++) {
- restrictedHeaderSet.add(restrictedHeaders[i].toLowerCase());
- }
- } else {
- restrictedHeaderSet = null;
- }
- }
-
- static final String httpVersion = "HTTP/1.1";
- static final String acceptString =
- "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2";
-
- // the following http request headers should NOT have their values
- // returned for security reasons.
- private static final String[] EXCLUDE_HEADERS = {
- "Proxy-Authorization",
- "Authorization"
- };
-
- // also exclude system cookies when any might be set
- private static final String[] EXCLUDE_HEADERS2= {
- "Proxy-Authorization",
- "Authorization",
- "Cookie",
- "Cookie2"
- };
-
- protected HttpClient http;
- protected Handler handler;
- protected Proxy instProxy;
-
- private CookieHandler cookieHandler;
- private ResponseCache cacheHandler;
-
- // the cached response, and cached response headers and body
- protected CacheResponse cachedResponse;
- private MessageHeader cachedHeaders;
- private InputStream cachedInputStream;
-
- /* output stream to server */
- protected PrintStream ps = null;
-
-
- /* buffered error stream */
- private InputStream errorStream = null;
-
- /* User set Cookies */
- private boolean setUserCookies = true;
- private String userCookies = null;
- private String userCookies2 = null;
-
- /* We only have a single static authenticator for now.
- * REMIND: backwards compatibility with JDK 1.1. Should be
- * eliminated for JDK 2.0.
- */
- private static HttpAuthenticator defaultAuth;
-
- /* all the headers we send
- * NOTE: do *NOT* dump out the content of 'requests' in the
- * output or stacktrace since it may contain security-sensitive
- * headers such as those defined in EXCLUDE_HEADERS.
- */
- private MessageHeader requests;
-
- /* The following two fields are only used with Digest Authentication */
- String domain; /* The list of authentication domains */
- DigestAuthentication.Parameters digestparams;
-
- /* Current credentials in use */
- AuthenticationInfo currentProxyCredentials = null;
- AuthenticationInfo currentServerCredentials = null;
- boolean needToCheck = true;
- private boolean doingNTLM2ndStage = false; /* doing the 2nd stage of an NTLM server authentication */
- private boolean doingNTLMp2ndStage = false; /* doing the 2nd stage of an NTLM proxy authentication */
-
- /* try auth without calling Authenticator. Used for transparent NTLM authentication */
- private boolean tryTransparentNTLMServer = true;
- private boolean tryTransparentNTLMProxy = true;
-
- /* Used by Windows specific code */
- private Object authObj;
-
- /* Set if the user is manually setting the Authorization or Proxy-Authorization headers */
- boolean isUserServerAuth;
- boolean isUserProxyAuth;
-
- String serverAuthKey, proxyAuthKey;
-
- /* Progress source */
- protected ProgressSource pi;
-
- /* all the response headers we get back */
- private MessageHeader responses;
- /* the stream _from_ the server */
- private InputStream inputStream = null;
- /* post stream _to_ the server, if any */
- private PosterOutputStream poster = null;
-
- /* Indicates if the std. request headers have been set in requests. */
- private boolean setRequests=false;
-
- /* Indicates whether a request has already failed or not */
- private boolean failedOnce=false;
-
- /* Remembered Exception, we will throw it again if somebody
- calls getInputStream after disconnect */
- private Exception rememberedException = null;
-
- /* If we decide we want to reuse a client, we put it here */
- private HttpClient reuseClient = null;
-
- /* Tunnel states */
- public enum TunnelState {
- /* No tunnel */
- NONE,
-
- /* Setting up a tunnel */
- SETUP,
-
- /* Tunnel has been successfully setup */
- TUNNELING
- }
-
- private TunnelState tunnelState = TunnelState.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;
-
- /* Logging support */
- private static final PlatformLogger logger =
- PlatformLogger.getLogger("sun.net.www.protocol.http.HttpURLConnection");
-
- /*
- * privileged request password authentication
- *
- */
- private static PasswordAuthentication
- privilegedRequestPasswordAuthentication(
- final String host,
- final InetAddress addr,
- final int port,
- final String protocol,
- final String prompt,
- final String scheme,
- final URL url,
- final RequestorType authType) {
- return java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<PasswordAuthentication>() {
- public PasswordAuthentication run() {
- if (logger.isLoggable(PlatformLogger.FINEST)) {
- logger.finest("Requesting Authentication: host =" + host + " url = " + url);
- }
- PasswordAuthentication pass = Authenticator.requestPasswordAuthentication(
- host, addr, port, protocol,
- prompt, scheme, url, authType);
- if (logger.isLoggable(PlatformLogger.FINEST)) {
- logger.finest("Authentication returned: " + (pass != null ? pass.toString() : "null"));
- }
- return pass;
- }
- });
- }
-
- private boolean isRestrictedHeader(String key, String value) {
- if (allowRestrictedHeaders) {
- return false;
- }
-
- key = key.toLowerCase();
- if (restrictedHeaderSet.contains(key)) {
- /*
- * Exceptions to restricted headers:
- *
- * Allow "Connection: close".
- */
- if (key.equals("connection") && value.equalsIgnoreCase("close")) {
- return false;
- }
- return true;
- } else if (key.startsWith("sec-")) {
- return true;
- }
- return false;
- }
-
- /*
- * Checks the validity of http message header and whether the header
- * is restricted and throws IllegalArgumentException if invalid or
- * restricted.
- */
- private boolean isExternalMessageHeaderAllowed(String key, String value) {
- checkMessageHeader(key, value);
- if (!isRestrictedHeader(key, value)) {
- return true;
- }
- return false;
- }
-
- /* Logging support */
- public static PlatformLogger getHttpLogger() {
- return logger;
- }
-
- /* Used for Windows NTLM implementation */
- public Object authObj() {
- return authObj;
- }
-
- public void authObj(Object authObj) {
- this.authObj = authObj;
- }
-
- /*
- * checks the validity of http message header and throws
- * IllegalArgumentException if invalid.
- */
- private void checkMessageHeader(String key, String value) {
- char LF = '\n';
- int index = key.indexOf(LF);
- if (index != -1) {
- throw new IllegalArgumentException(
- "Illegal character(s) in message header field: " + key);
- }
- else {
- if (value == null) {
- return;
- }
-
- index = value.indexOf(LF);
- while (index != -1) {
- index++;
- if (index < value.length()) {
- char c = value.charAt(index);
- if ((c==' ') || (c=='\t')) {
- // ok, check the next occurrence
- index = value.indexOf(LF, index);
- continue;
- }
- }
- throw new IllegalArgumentException(
- "Illegal character(s) in message header value: " + value);
- }
- }
- }
-
- /* adds the standard key/val pairs to reqests if necessary & write to
- * given PrintStream
- */
- private void writeRequests() throws IOException {
- /* print all message headers in the MessageHeader
- * onto the wire - all the ones we've set and any
- * others that have been set
- */
- // send any pre-emptive authentication
- if (http.usingProxy && tunnelState() != TunnelState.TUNNELING) {
- setPreemptiveProxyAuthentication(requests);
- }
- if (!setRequests) {
-
- /* We're very particular about the order in which we
- * set the request headers here. The order should not
- * matter, but some careless CGI programs have been
- * written to expect a very particular order of the
- * standard headers. To name names, the order in which
- * Navigator3.0 sends them. In particular, we make *sure*
- * to send Content-type: <> and Content-length:<> second
- * to last and last, respectively, in the case of a POST
- * request.
- */
- if (!failedOnce)
- requests.prepend(method + " " + getRequestURI()+" " +
- httpVersion, null);
- if (!getUseCaches()) {
- requests.setIfNotSet ("Cache-Control", "no-cache");
- requests.setIfNotSet ("Pragma", "no-cache");
- }
- requests.setIfNotSet("User-Agent", userAgent);
- int port = url.getPort();
- String host = url.getHost();
- if (port != -1 && port != url.getDefaultPort()) {
- host += ":" + String.valueOf(port);
- }
- requests.setIfNotSet("Host", host);
- requests.setIfNotSet("Accept", acceptString);
-
- /*
- * For HTTP/1.1 the default behavior is to keep connections alive.
- * However, we may be talking to a 1.0 server so we should set
- * keep-alive just in case, except if we have encountered an error
- * or if keep alive is disabled via a system property
- */
-
- // Try keep-alive only on first attempt
- if (!failedOnce && http.getHttpKeepAliveSet()) {
- if (http.usingProxy && tunnelState() != TunnelState.TUNNELING) {
- requests.setIfNotSet("Proxy-Connection", "keep-alive");
- } else {
- requests.setIfNotSet("Connection", "keep-alive");
- }
- } else {
- /*
- * RFC 2616 HTTP/1.1 section 14.10 says:
- * HTTP/1.1 applications that do not support persistent
- * connections MUST include the "close" connection option
- * in every message
- */
- requests.setIfNotSet("Connection", "close");
- }
- // Set modified since if necessary
- long modTime = getIfModifiedSince();
- if (modTime != 0 ) {
- Date date = new Date(modTime);
- //use the preferred date format according to RFC 2068(HTTP1.1),
- // RFC 822 and RFC 1123
- SimpleDateFormat fo =
- new SimpleDateFormat ("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
- fo.setTimeZone(TimeZone.getTimeZone("GMT"));
- requests.setIfNotSet("If-Modified-Since", fo.format(date));
- }
- // check for preemptive authorization
- AuthenticationInfo sauth = AuthenticationInfo.getServerAuth(url);
- if (sauth != null && sauth.supportsPreemptiveAuthorization() ) {
- // Sets "Authorization"
- requests.setIfNotSet(sauth.getHeaderName(), sauth.getHeaderValue(url,method));
- currentServerCredentials = sauth;
- }
-
- if (!method.equals("PUT") && (poster != null || streaming())) {
- requests.setIfNotSet ("Content-type",
- "application/x-www-form-urlencoded");
- }
-
- boolean chunked = false;
-
- if (streaming()) {
- if (chunkLength != -1) {
- requests.set ("Transfer-Encoding", "chunked");
- chunked = true;
- } else { /* fixed content length */
- if (fixedContentLengthLong != -1) {
- requests.set ("Content-Length",
- String.valueOf(fixedContentLengthLong));
- } else if (fixedContentLength != -1) {
- requests.set ("Content-Length",
- String.valueOf(fixedContentLength));
- }
- }
- } else if (poster != null) {
- /* add Content-Length & POST/PUT data */
- synchronized (poster) {
- /* close it, so no more data can be added */
- poster.close();
- requests.set("Content-Length",
- String.valueOf(poster.size()));
- }
- }
-
- if (!chunked) {
- if (requests.findValue("Transfer-Encoding") != null) {
- requests.remove("Transfer-Encoding");
- if (logger.isLoggable(PlatformLogger.WARNING)) {
- logger.warning(
- "use streaming mode for chunked encoding");
- }
- }
- }
-
- // get applicable cookies based on the uri and request headers
- // add them to the existing request headers
- setCookieHeader();
-
- setRequests=true;
- }
- if (logger.isLoggable(PlatformLogger.FINE)) {
- logger.fine(requests.toString());
- }
- http.writeRequests(requests, poster, streaming());
- if (ps.checkError()) {
- String proxyHost = http.getProxyHostUsed();
- int proxyPort = http.getProxyPortUsed();
- disconnectInternal();
- if (failedOnce) {
- throw new IOException("Error writing to server");
- } else { // try once more
- failedOnce=true;
- if (proxyHost != null) {
- setProxiedClient(url, proxyHost, proxyPort);
- } else {
- setNewClient (url);
- }
- ps = (PrintStream) http.getOutputStream();
- connected=true;
- responses = new MessageHeader();
- setRequests=false;
- writeRequests();
- }
- }
- }
-
-
- /**
- * 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 {
- setNewClient(url, false);
- }
-
- /**
- * Obtain a HttpsClient 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 {
- http = HttpClient.New(url, null, -1, useCache, connectTimeout, this);
- http.setReadTimeout(readTimeout);
- }
-
-
- /**
- * 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 {
- 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.
- *
- * @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 {
- proxiedConnect(url, proxyHost, proxyPort, useCache);
- }
-
- protected void proxiedConnect(URL url,
- String proxyHost, int proxyPort,
- boolean useCache)
- throws IOException {
- http = HttpClient.New (url, proxyHost, proxyPort, useCache,
- connectTimeout, this);
- http.setReadTimeout(readTimeout);
- }
-
- protected HttpURLConnection(URL u, Handler handler)
- throws IOException {
- // we set proxy == null to distinguish this case with the case
- // when per connection proxy is set
- this(u, null, handler);
- }
-
- public HttpURLConnection(URL u, String host, int port) {
- this(u, new Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved(host, port)));
- }
-
- /** this constructor is used by other protocol handlers such as ftp
- that want to use http to fetch urls on their behalf.*/
- public HttpURLConnection(URL u, Proxy p) {
- this(u, p, new Handler());
- }
-
- protected HttpURLConnection(URL u, Proxy p, Handler handler) {
- super(u);
- requests = new MessageHeader();
- responses = new MessageHeader();
- this.handler = handler;
- instProxy = p;
- if (instProxy instanceof sun.net.ApplicationProxy) {
- /* Application set Proxies should not have access to cookies
- * in a secure environment unless explicitly allowed. */
- try {
- cookieHandler = CookieHandler.getDefault();
- } catch (SecurityException se) { /* swallow exception */ }
- } else {
- cookieHandler = java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<CookieHandler>() {
- public CookieHandler run() {
- return CookieHandler.getDefault();
- }
- });
- }
- cacheHandler = java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<ResponseCache>() {
- public ResponseCache run() {
- return ResponseCache.getDefault();
- }
- });
- }
-
- /**
- * @deprecated. Use java.net.Authenticator.setDefault() instead.
- */
- public static void setDefaultAuthenticator(HttpAuthenticator a) {
- defaultAuth = a;
- }
-
- /**
- * opens a stream allowing redirects only to the same host.
- */
- public static InputStream openConnectionCheckRedirects(URLConnection c)
- throws IOException
- {
- boolean redir;
- int redirects = 0;
- InputStream in;
-
- do {
- if (c instanceof HttpURLConnection) {
- ((HttpURLConnection) c).setInstanceFollowRedirects(false);
- }
-
- // We want to open the input stream before
- // getting headers, because getHeaderField()
- // et al swallow IOExceptions.
- in = c.getInputStream();
- redir = false;
-
- if (c instanceof HttpURLConnection) {
- HttpURLConnection http = (HttpURLConnection) c;
- int stat = http.getResponseCode();
- if (stat >= 300 && stat <= 307 && stat != 306 &&
- stat != HttpURLConnection.HTTP_NOT_MODIFIED) {
- URL base = http.getURL();
- String loc = http.getHeaderField("Location");
- URL target = null;
- if (loc != null) {
- target = new URL(base, loc);
- }
- http.disconnect();
- if (target == null
- || !base.getProtocol().equals(target.getProtocol())
- || base.getPort() != target.getPort()
- || !hostsEqual(base, target)
- || redirects >= 5)
- {
- throw new SecurityException("illegal URL redirect");
- }
- redir = true;
- c = target.openConnection();
- redirects++;
- }
- }
- } while (redir);
- return in;
- }
-
-
- //
- // Same as java.net.URL.hostsEqual
- //
- private static boolean hostsEqual(URL u1, URL u2) {
- final String h1 = u1.getHost();
- final String h2 = u2.getHost();
-
- if (h1 == null) {
- return h2 == null;
- } else if (h2 == null) {
- return false;
- } else if (h1.equalsIgnoreCase(h2)) {
- return true;
- }
- // Have to resolve addresses before comparing, otherwise
- // names like tachyon and tachyon.eng would compare different
- final boolean result[] = {false};
-
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<Void>() {
- public Void run() {
- try {
- InetAddress a1 = InetAddress.getByName(h1);
- InetAddress a2 = InetAddress.getByName(h2);
- result[0] = a1.equals(a2);
- } catch(UnknownHostException e) {
- } catch(SecurityException e) {
- }
- return null;
- }
- });
-
- return result[0];
- }
-
- // overridden in HTTPS subclass
-
- public void connect() throws IOException {
- plainConnect();
- }
-
- private boolean checkReuseConnection () {
- if (connected) {
- return true;
- }
- if (reuseClient != null) {
- http = reuseClient;
- http.setReadTimeout(getReadTimeout());
- http.reuse = false;
- reuseClient = null;
- connected = true;
- return true;
- }
- return false;
- }
-
- protected void plainConnect() throws IOException {
- if (connected) {
- return;
- }
- // try to see if request can be served from local cache
- if (cacheHandler != null && getUseCaches()) {
- try {
- URI uri = ParseUtil.toURI(url);
- if (uri != null) {
- cachedResponse = cacheHandler.get(uri, getRequestMethod(), requests.getHeaders(EXCLUDE_HEADERS));
- if ("https".equalsIgnoreCase(uri.getScheme())
- && !(cachedResponse instanceof SecureCacheResponse)) {
- cachedResponse = null;
- }
- if (logger.isLoggable(PlatformLogger.FINEST)) {
- logger.finest("Cache Request for " + uri + " / " + getRequestMethod());
- logger.finest("From cache: " + (cachedResponse != null ? cachedResponse.toString() : "null"));
- }
- if (cachedResponse != null) {
- cachedHeaders = mapToMessageHeader(cachedResponse.getHeaders());
- cachedInputStream = cachedResponse.getBody();
- }
- }
- } catch (IOException ioex) {
- // ignore and commence normal connection
- }
- if (cachedHeaders != null && cachedInputStream != null) {
- connected = true;
- return;
- } else {
- cachedResponse = null;
- }
- }
- try {
- /* Try to open connections using the following scheme,
- * return on the first one that's successful:
- * 1) if (instProxy != null)
- * connect to instProxy; raise exception if failed
- * 2) else use system default ProxySelector
- * 3) is 2) fails, make direct connection
- */
-
- if (instProxy == null) { // no instance Proxy is set
- /**
- * 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);
- if (logger.isLoggable(PlatformLogger.FINEST)) {
- logger.finest("ProxySelector Request for " + uri);
- }
- Iterator<Proxy> it = sel.select(uri).iterator();
- Proxy p;
- while (it.hasNext()) {
- p = it.next();
- try {
- if (!failedOnce) {
- http = getNewHttpClient(url, p, connectTimeout);
- http.setReadTimeout(readTimeout);
- } else {
- // make sure to construct new connection if first
- // attempt failed
- http = getNewHttpClient(url, p, connectTimeout, false);
- http.setReadTimeout(readTimeout);
- }
- if (logger.isLoggable(PlatformLogger.FINEST)) {
- if (p != null) {
- logger.finest("Proxy used: " + p.toString());
- }
- }
- break;
- } catch (IOException ioex) {
- if (p != Proxy.NO_PROXY) {
- sel.connectFailed(uri, p.address(), ioex);
- if (!it.hasNext()) {
- // fallback to direct connection
- http = getNewHttpClient(url, null, connectTimeout, false);
- http.setReadTimeout(readTimeout);
- break;
- }
- } else {
- throw ioex;
- }
- continue;
- }
- }
- } else {
- // No proxy selector, create http client with no proxy
- if (!failedOnce) {
- http = getNewHttpClient(url, null, connectTimeout);
- http.setReadTimeout(readTimeout);
- } else {
- // make sure to construct new connection if first
- // attempt failed
- http = getNewHttpClient(url, null, connectTimeout, false);
- http.setReadTimeout(readTimeout);
- }
- }
- } else {
- if (!failedOnce) {
- http = getNewHttpClient(url, instProxy, connectTimeout);
- http.setReadTimeout(readTimeout);
- } else {
- // make sure to construct new connection if first
- // attempt failed
- http = getNewHttpClient(url, instProxy, connectTimeout, false);
- http.setReadTimeout(readTimeout);
- }
- }
-
- ps = (PrintStream)http.getOutputStream();
- } catch (IOException e) {
- throw e;
- }
- // constructor to HTTP client calls openserver
- connected = true;
- }
-
- // subclass HttpsClient will overwrite & return an instance of HttpsClient
- protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout)
- throws IOException {
- return HttpClient.New(url, p, connectTimeout, this);
- }
-
- // subclass HttpsClient will overwrite & return an instance of HttpsClient
- protected HttpClient getNewHttpClient(URL url, Proxy p,
- int connectTimeout, boolean useCache)
- throws IOException {
- return HttpClient.New(url, p, connectTimeout, useCache, this);
- }
-
- private void expect100Continue() throws IOException {
- // Expect: 100-Continue was set, so check the return code for
- // Acceptance
- int oldTimeout = http.getReadTimeout();
- boolean enforceTimeOut = false;
- boolean timedOut = false;
- if (oldTimeout <= 0) {
- // 5s read timeout in case the server doesn't understand
- // Expect: 100-Continue
- http.setReadTimeout(5000);
- enforceTimeOut = true;
- }
-
- try {
- http.parseHTTP(responses, pi, this);
- } catch (SocketTimeoutException se) {
- if (!enforceTimeOut) {
- throw se;
- }
- timedOut = true;
- http.setIgnoreContinue(true);
- }
- if (!timedOut) {
- // Can't use getResponseCode() yet
- String resp = responses.getValue(0);
- // Parse the response which is of the form:
- // HTTP/1.1 417 Expectation Failed
- // HTTP/1.1 100 Continue
- if (resp != null && resp.startsWith("HTTP/")) {
- String[] sa = resp.split("\\s+");
- responseCode = -1;
- try {
- // Response code is 2nd token on the line
- if (sa.length > 1)
- responseCode = Integer.parseInt(sa[1]);
- } catch (NumberFormatException numberFormatException) {
- }
- }
- if (responseCode != 100) {
- throw new ProtocolException("Server rejected operation");
- }
- }
-
- http.setReadTimeout(oldTimeout);
-
- responseCode = -1;
- responses.reset();
- // Proceed
- }
-
- /*
- * 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]
- */
-
- @Override
- public synchronized OutputStream getOutputStream() throws IOException {
-
- try {
- if (!doOutput) {
- throw new ProtocolException("cannot write to a URLConnection"
- + " if doOutput=false - call setDoOutput(true)");
- }
-
- if (method.equals("GET")) {
- method = "POST"; // Backward compatibility
- }
- if (!"POST".equals(method) && !"PUT".equals(method) &&
- "http".equals(url.getProtocol())) {
- throw new ProtocolException("HTTP method " + method +
- " doesn't support output");
- }
-
- // if there's already an input stream open, throw an exception
- if (inputStream != null) {
- throw new ProtocolException("Cannot write output after reading input.");
- }
-
- if (!checkReuseConnection())
- connect();
-
- boolean expectContinue = false;
- String expects = requests.findValue("Expect");
- if ("100-Continue".equalsIgnoreCase(expects)) {
- http.setIgnoreContinue(false);
- expectContinue = true;
- }
-
- if (streaming() && strOutputStream == null) {
- writeRequests();
- }
-
- if (expectContinue) {
- expect100Continue();
- }
- ps = (PrintStream)http.getOutputStream();
- if (streaming()) {
- if (strOutputStream == null) {
- if (chunkLength != -1) { /* chunked */
- strOutputStream = new StreamingOutputStream(
- new ChunkedOutputStream(ps, chunkLength), -1L);
- } else { /* must be fixed content length */
- long length = 0L;
- if (fixedContentLengthLong != -1) {
- length = fixedContentLengthLong;
- } else if (fixedContentLength != -1) {
- length = fixedContentLength;
- }
- strOutputStream = new StreamingOutputStream(ps, length);
- }
- }
- return strOutputStream;
- } else {
- if (poster == null) {
- poster = new PosterOutputStream();
- }
- return poster;
- }
- } catch (RuntimeException e) {
- disconnectInternal();
- throw e;
- } catch (ProtocolException e) {
- // Save the response code which may have been set while enforcing
- // the 100-continue. disconnectInternal() forces it to -1
- int i = responseCode;
- disconnectInternal();
- responseCode = i;
- throw e;
- } catch (IOException e) {
- disconnectInternal();
- throw e;
- }
- }
-
- public boolean streaming () {
- return (fixedContentLength != -1) || (fixedContentLengthLong != -1) ||
- (chunkLength != -1);
- }
-
- /*
- * get applicable cookies based on the uri and request headers
- * add them to the existing request headers
- */
- private void setCookieHeader() throws IOException {
- if (cookieHandler != null) {
- // we only want to capture the user defined Cookies once, as
- // they cannot be changed by user code after we are connected,
- // only internally.
- synchronized (this) {
- if (setUserCookies) {
- int k = requests.getKey("Cookie");
- if (k != -1)
- userCookies = requests.getValue(k);
- k = requests.getKey("Cookie2");
- if (k != -1)
- userCookies2 = requests.getValue(k);
- setUserCookies = false;
- }
- }
-
- // remove old Cookie header before setting new one.
- requests.remove("Cookie");
- requests.remove("Cookie2");
-
- URI uri = ParseUtil.toURI(url);
- if (uri != null) {
- if (logger.isLoggable(PlatformLogger.FINEST)) {
- logger.finest("CookieHandler request for " + uri);
- }
- Map<String, List<String>> cookies
- = cookieHandler.get(
- uri, requests.getHeaders(EXCLUDE_HEADERS));
- if (!cookies.isEmpty()) {
- if (logger.isLoggable(PlatformLogger.FINEST)) {
- logger.finest("Cookies retrieved: " + cookies.toString());
- }
- for (Map.Entry<String, List<String>> entry :
- cookies.entrySet()) {
- String key = entry.getKey();
- // ignore all entries that don't have "Cookie"
- // or "Cookie2" as keys
- if (!"Cookie".equalsIgnoreCase(key) &&
- !"Cookie2".equalsIgnoreCase(key)) {
- continue;
- }
- List<String> l = entry.getValue();
- if (l != null && !l.isEmpty()) {
- StringBuilder cookieValue = new StringBuilder();
- for (String value : l) {
- cookieValue.append(value).append("; ");
- }
- // strip off the trailing '; '
- try {
- requests.add(key, cookieValue.substring(0, cookieValue.length() - 2));
- } catch (StringIndexOutOfBoundsException ignored) {
- // no-op
- }
- }
- }
- }
- }
- if (userCookies != null) {
- int k;
- if ((k = requests.getKey("Cookie")) != -1)
- requests.set("Cookie", requests.getValue(k) + ";" + userCookies);
- else
- requests.set("Cookie", userCookies);
- }
- if (userCookies2 != null) {
- int k;
- if ((k = requests.getKey("Cookie2")) != -1)
- requests.set("Cookie2", requests.getValue(k) + ";" + userCookies2);
- else
- requests.set("Cookie2", userCookies2);
- }
-
- } // end of getting cookies
- }
-
- @Override
- @SuppressWarnings("empty-statement")
- public synchronized InputStream getInputStream() throws IOException {
-
- if (!doInput) {
- throw new ProtocolException("Cannot read from URLConnection"
- + " if doInput=false (call setDoInput(true))");
- }
-
- if (rememberedException != null) {
- if (rememberedException instanceof RuntimeException)
- throw new RuntimeException(rememberedException);
- else {
- throw getChainedException((IOException)rememberedException);
- }
- }
-
- if (inputStream != null) {
- return inputStream;
- }
-
- if (streaming() ) {
- if (strOutputStream == null) {
- getOutputStream();
- }
- /* make sure stream is closed */
- strOutputStream.close ();
- if (!strOutputStream.writtenOK()) {
- throw new IOException ("Incomplete output stream");
- }
- }
-
- int redirects = 0;
- int respCode = 0;
- long cl = -1;
- AuthenticationInfo serverAuthentication = null;
- AuthenticationInfo proxyAuthentication = null;
- AuthenticationHeader srvHdr = null;
-
- /**
- * Failed Negotiate
- *
- * In some cases, the Negotiate auth is supported for the
- * remote host but the negotiate process still fails (For
- * example, if the web page is located on a backend server
- * and delegation is needed but fails). The authentication
- * process will start again, and we need to detect this
- * kind of failure and do proper fallback (say, to NTLM).
- *
- * In order to achieve this, the inNegotiate flag is set
- * when the first negotiate challenge is met (and reset
- * if authentication is finished). If a fresh new negotiate
- * challenge (no parameter) is found while inNegotiate is
- * set, we know there's a failed auth attempt recently.
- * Here we'll ignore the header line so that fallback
- * can be practiced.
- *
- * inNegotiateProxy is for proxy authentication.
- */
- boolean inNegotiate = false;
- boolean inNegotiateProxy = false;
-
- // If the user has set either of these headers then do not remove them
- isUserServerAuth = requests.getKey("Authorization") != -1;
- isUserProxyAuth = requests.getKey("Proxy-Authorization") != -1;
-
- try {
- do {
- if (!checkReuseConnection())
- connect();
-
- if (cachedInputStream != null) {
- return cachedInputStream;
- }
-
- // Check if URL should be metered
- boolean meteredInput = ProgressMonitor.getDefault().shouldMeterInput(url, method);
-
- if (meteredInput) {
- pi = new ProgressSource(url, method);
- pi.beginTracking();
- }
-
- /* REMIND: This exists to fix the HttpsURLConnection subclass.
- * Hotjava needs to run on JDK1.1FCS. Do proper fix once a
- * proper solution for SSL can be found.
- */
- ps = (PrintStream)http.getOutputStream();
-
- if (!streaming()) {
- writeRequests();
- }
- http.parseHTTP(responses, pi, this);
- if (logger.isLoggable(PlatformLogger.FINE)) {
- logger.fine(responses.toString());
- }
-
- boolean b1 = responses.filterNTLMResponses("WWW-Authenticate");
- boolean b2 = responses.filterNTLMResponses("Proxy-Authenticate");
- if (b1 || b2) {
- if (logger.isLoggable(PlatformLogger.FINE)) {
- logger.fine(">>>> Headers are filtered");
- logger.fine(responses.toString());
- }
- }
-
- inputStream = http.getInputStream();
-
- respCode = getResponseCode();
- if (respCode == -1) {
- disconnectInternal();
- throw new IOException ("Invalid Http response");
- }
- if (respCode == HTTP_PROXY_AUTH) {
- if (streaming()) {
- disconnectInternal();
- throw new HttpRetryException (
- RETRY_MSG1, HTTP_PROXY_AUTH);
- }
-
- // Read comments labeled "Failed Negotiate" for details.
- boolean dontUseNegotiate = false;
- Iterator iter = responses.multiValueIterator("Proxy-Authenticate");
- while (iter.hasNext()) {
- String value = ((String)iter.next()).trim();
- if (value.equalsIgnoreCase("Negotiate") ||
- value.equalsIgnoreCase("Kerberos")) {
- if (!inNegotiateProxy) {
- inNegotiateProxy = true;
- } else {
- dontUseNegotiate = true;
- doingNTLMp2ndStage = false;
- proxyAuthentication = null;
- }
- break;
- }
- }
-
- // changes: add a 3rd parameter to the constructor of
- // AuthenticationHeader, so that NegotiateAuthentication.
- // isSupported can be tested.
- // The other 2 appearances of "new AuthenticationHeader" is
- // altered in similar ways.
-
- AuthenticationHeader authhdr = new AuthenticationHeader (
- "Proxy-Authenticate", responses,
- new HttpCallerInfo(url, http.getProxyHostUsed(),
- http.getProxyPortUsed()),
- dontUseNegotiate
- );
-
- if (!doingNTLMp2ndStage) {
- proxyAuthentication =
- resetProxyAuthentication(proxyAuthentication, authhdr);
- if (proxyAuthentication != null) {
- redirects++;
- disconnectInternal();
- continue;
- }
- } else {
- /* in this case, only one header field will be present */
- String raw = responses.findValue ("Proxy-Authenticate");
- reset ();
- if (!proxyAuthentication.setHeaders(this,
- authhdr.headerParser(), raw)) {
- disconnectInternal();
- throw new IOException ("Authentication failure");
- }
- if (serverAuthentication != null && srvHdr != null &&
- !serverAuthentication.setHeaders(this,
- srvHdr.headerParser(), raw)) {
- disconnectInternal ();
- throw new IOException ("Authentication failure");
- }
- authObj = null;
- doingNTLMp2ndStage = false;
- continue;
- }
- } else {
- inNegotiateProxy = false;
- doingNTLMp2ndStage = false;
- if (!isUserProxyAuth)
- requests.remove("Proxy-Authorization");
- }
-
- // cache proxy authentication info
- if (proxyAuthentication != null) {
- // cache auth info on success, domain header not relevant.
- proxyAuthentication.addToCache();
- }
-
- if (respCode == HTTP_UNAUTHORIZED) {
- if (streaming()) {
- disconnectInternal();
- throw new HttpRetryException (
- RETRY_MSG2, HTTP_UNAUTHORIZED);
- }
-
- // Read comments labeled "Failed Negotiate" for details.
- boolean dontUseNegotiate = false;
- Iterator iter = responses.multiValueIterator("WWW-Authenticate");
- while (iter.hasNext()) {
- String value = ((String)iter.next()).trim();
- if (value.equalsIgnoreCase("Negotiate") ||
- value.equalsIgnoreCase("Kerberos")) {
- if (!inNegotiate) {
- inNegotiate = true;
- } else {
- dontUseNegotiate = true;
- doingNTLM2ndStage = false;
- serverAuthentication = null;
- }
- break;
- }
- }
-
- srvHdr = new AuthenticationHeader (
- "WWW-Authenticate", responses,
- new HttpCallerInfo(url),
- dontUseNegotiate
- );
-
- String raw = srvHdr.raw();
- if (!doingNTLM2ndStage) {
- if ((serverAuthentication != null)&&
- serverAuthentication.getAuthScheme() != NTLM) {
- if (serverAuthentication.isAuthorizationStale (raw)) {
- /* we can retry with the current credentials */
- disconnectWeb();
- redirects++;
- requests.set(serverAuthentication.getHeaderName(),
- serverAuthentication.getHeaderValue(url, method));
- currentServerCredentials = serverAuthentication;
- setCookieHeader();
- continue;
- } else {
- serverAuthentication.removeFromCache();
- }
- }
- serverAuthentication = getServerAuthentication(srvHdr);
- currentServerCredentials = serverAuthentication;
-
- if (serverAuthentication != null) {
- disconnectWeb();
- redirects++; // don't let things loop ad nauseum
- setCookieHeader();
- continue;
- }
- } else {
- reset ();
- /* header not used for ntlm */
- if (!serverAuthentication.setHeaders(this, null, raw)) {
- disconnectWeb();
- throw new IOException ("Authentication failure");
- }
- doingNTLM2ndStage = false;
- authObj = null;
- setCookieHeader();
- continue;
- }
- }
- // cache server authentication info
- if (serverAuthentication != null) {
- // cache auth info on success
- if (!(serverAuthentication instanceof DigestAuthentication) ||
- (domain == null)) {
- if (serverAuthentication instanceof BasicAuthentication) {
- // check if the path is shorter than the existing entry
- String npath = AuthenticationInfo.reducePath (url.getPath());
- String opath = serverAuthentication.path;
- if (!opath.startsWith (npath) || npath.length() >= opath.length()) {
- /* npath is longer, there must be a common root */
- npath = BasicAuthentication.getRootPath (opath, npath);
- }
- // remove the entry and create a new one
- BasicAuthentication a =
- (BasicAuthentication) serverAuthentication.clone();
- serverAuthentication.removeFromCache();
- a.path = npath;
- serverAuthentication = a;
- }
- serverAuthentication.addToCache();
- } else {
- // what we cache is based on the domain list in the request
- DigestAuthentication srv = (DigestAuthentication)
- serverAuthentication;
- StringTokenizer tok = new StringTokenizer (domain," ");
- String realm = srv.realm;
- PasswordAuthentication pw = srv.pw;
- digestparams = srv.params;
- while (tok.hasMoreTokens()) {
- String path = tok.nextToken();
- try {
- /* path could be an abs_path or a complete URI */
- URL u = new URL (url, path);
- DigestAuthentication d = new DigestAuthentication (
- false, u, realm, "Digest", pw, digestparams);
- d.addToCache ();
- } catch (Exception e) {}
- }
- }
- }
-
- // some flags should be reset to its initialized form so that
- // even after a redirect the necessary checks can still be
- // preformed.
- inNegotiate = false;
- inNegotiateProxy = false;
-
- //serverAuthentication = null;
- doingNTLMp2ndStage = false;
- doingNTLM2ndStage = false;
- if (!isUserServerAuth)
- requests.remove("Authorization");
- if (!isUserProxyAuth)
- requests.remove("Proxy-Authorization");
-
- if (respCode == HTTP_OK) {
- checkResponseCredentials (false);
- } else {
- needToCheck = false;
- }
-
- // a flag need to clean
- needToCheck = true;
-
- if (followRedirect()) {
- /* if we should follow a redirect, then the followRedirects()
- * method will disconnect() and re-connect us to the new
- * location
- */
- redirects++;
-
- // redirecting HTTP response may have set cookie, so
- // need to re-generate request header
- setCookieHeader();
-
- continue;
- }
-
- try {
- cl = Long.parseLong(responses.findValue("content-length"));
- } catch (Exception exc) { };
-
- if (method.equals("HEAD") || cl == 0 ||
- respCode == HTTP_NOT_MODIFIED ||
- respCode == HTTP_NO_CONTENT) {
-
- if (pi != null) {
- pi.finishTracking();
- pi = null;
- }
- http.finished();
- http = null;
- inputStream = new EmptyInputStream();
- connected = false;
- }
-
- if (respCode == 200 || respCode == 203 || respCode == 206 ||
- respCode == 300 || respCode == 301 || respCode == 410) {
- if (cacheHandler != null) {
- // give cache a chance to save response in cache
- URI uri = ParseUtil.toURI(url);
- if (uri != null) {
- URLConnection uconn = this;
- if ("https".equalsIgnoreCase(uri.getScheme())) {
- try {
- // use reflection to get to the public
- // HttpsURLConnection instance saved in
- // DelegateHttpsURLConnection
- uconn = (URLConnection)this.getClass().getField("httpsURLConnection").get(this);
- } catch (IllegalAccessException iae) {
- // ignored; use 'this'
- } catch (NoSuchFieldException nsfe) {
- // ignored; use 'this'
- }
- }
- CacheRequest cacheRequest =
- cacheHandler.put(uri, uconn);
- if (cacheRequest != null && http != null) {
- http.setCacheRequest(cacheRequest);
- inputStream = new HttpInputStream(inputStream, cacheRequest);
- }
- }
- }
- }
-
- if (!(inputStream instanceof HttpInputStream)) {
- inputStream = new HttpInputStream(inputStream);
- }
-
- if (respCode >= 400) {
- if (respCode == 404 || respCode == 410) {
- throw new FileNotFoundException(url.toString());
- } else {
- throw new java.io.IOException("Server returned HTTP" +
- " response code: " + respCode + " for URL: " +
- url.toString());
- }
- }
- poster = null;
- strOutputStream = null;
- return inputStream;
- } while (redirects < maxRedirects);
-
- throw new ProtocolException("Server redirected too many " +
- " times ("+ redirects + ")");
- } catch (RuntimeException e) {
- disconnectInternal();
- rememberedException = e;
- throw e;
- } catch (IOException e) {
- rememberedException = e;
-
- // buffer the error stream if bytes < 4k
- // and it can be buffered within 1 second
- String te = responses.findValue("Transfer-Encoding");
- if (http != null && http.isKeepingAlive() && enableESBuffer &&
- (cl > 0 || (te != null && te.equalsIgnoreCase("chunked")))) {
- errorStream = ErrorStream.getErrorStream(inputStream, cl, http);
- }
- throw e;
- } finally {
- if (proxyAuthKey != null) {
- AuthenticationInfo.endAuthRequest(proxyAuthKey);
- }
- if (serverAuthKey != null) {
- AuthenticationInfo.endAuthRequest(serverAuthKey);
- }
- }
- }
-
- /*
- * Creates a chained exception that has the same type as
- * original exception and with the same message. Right now,
- * there is no convenient APIs for doing so.
- */
- private IOException getChainedException(final IOException rememberedException) {
- try {
- final Object[] args = { rememberedException.getMessage() };
- IOException chainedException =
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedExceptionAction<IOException>() {
- public IOException run() throws Exception {
- return (IOException)
- rememberedException.getClass()
- .getConstructor(new Class[] { String.class })
- .newInstance(args);
- }
- });
- chainedException.initCause(rememberedException);
- return chainedException;
- } catch (Exception ignored) {
- return rememberedException;
- }
- }
-
- @Override
- public InputStream getErrorStream() {
- if (connected && responseCode >= 400) {
- // Client Error 4xx and Server Error 5xx
- if (errorStream != null) {
- return errorStream;
- } else if (inputStream != null) {
- return inputStream;
- }
- }
- return null;
- }
-
- /**
- * set or reset proxy authentication info in request headers
- * after receiving a 407 error. In the case of NTLM however,
- * receiving a 407 is normal and we just skip the stale check
- * because ntlm does not support this feature.
- */
- private AuthenticationInfo
- resetProxyAuthentication(AuthenticationInfo proxyAuthentication, AuthenticationHeader auth) throws IOException {
- if ((proxyAuthentication != null )&&
- proxyAuthentication.getAuthScheme() != NTLM) {
- String raw = auth.raw();
- if (proxyAuthentication.isAuthorizationStale (raw)) {
- /* we can retry with the current credentials */
- String value;
- if (proxyAuthentication instanceof DigestAuthentication) {
- DigestAuthentication digestProxy = (DigestAuthentication)
- proxyAuthentication;
- if (tunnelState() == TunnelState.SETUP) {
- value = digestProxy.getHeaderValue(connectRequestURI(url), HTTP_CONNECT);
- } else {
- value = digestProxy.getHeaderValue(getRequestURI(), method);
- }
- } else {
- value = proxyAuthentication.getHeaderValue(url, method);
- }
- requests.set(proxyAuthentication.getHeaderName(), value);
- currentProxyCredentials = proxyAuthentication;
- return proxyAuthentication;
- } else {
- proxyAuthentication.removeFromCache();
- }
- }
- proxyAuthentication = getHttpProxyAuthentication(auth);
- currentProxyCredentials = proxyAuthentication;
- return proxyAuthentication;
- }
-
- /**
- * Returns the tunnel state.
- *
- * @return the state
- */
- TunnelState tunnelState() {
- return tunnelState;
- }
-
- /**
- * Set the tunneling status.
- *
- * @param the state
- */
- public void setTunnelState(TunnelState tunnelState) {
- this.tunnelState = tunnelState;
- }
-
- /**
- * establish a tunnel through proxy server
- */
- public synchronized void doTunneling() throws IOException {
- int retryTunnel = 0;
- String statusLine = "";
- int respCode = 0;
- AuthenticationInfo proxyAuthentication = null;
- String proxyHost = null;
- int proxyPort = -1;
-
- // save current requests so that they can be restored after tunnel is setup.
- MessageHeader savedRequests = requests;
- requests = new MessageHeader();
-
- // Read comments labeled "Failed Negotiate" for details.
- boolean inNegotiateProxy = false;
-
- try {
- /* Actively setting up a tunnel */
- setTunnelState(TunnelState.SETUP);
-
- do {
- if (!checkReuseConnection()) {
- proxiedConnect(url, proxyHost, proxyPort, false);
- }
- // send the "CONNECT" request to establish a tunnel
- // through proxy server
- sendCONNECTRequest();
- responses.reset();
-
- // There is no need to track progress in HTTP Tunneling,
- // so ProgressSource is null.
- http.parseHTTP(responses, null, this);
-
- /* Log the response to the CONNECT */
- if (logger.isLoggable(PlatformLogger.FINE)) {
- logger.fine(responses.toString());
- }
-
- if (responses.filterNTLMResponses("Proxy-Authenticate")) {
- if (logger.isLoggable(PlatformLogger.FINE)) {
- logger.fine(">>>> Headers are filtered");
- logger.fine(responses.toString());
- }
- }
-
- statusLine = responses.getValue(0);
- StringTokenizer st = new StringTokenizer(statusLine);
- st.nextToken();
- respCode = Integer.parseInt(st.nextToken().trim());
- if (respCode == HTTP_PROXY_AUTH) {
- // Read comments labeled "Failed Negotiate" for details.
- boolean dontUseNegotiate = false;
- Iterator iter = responses.multiValueIterator("Proxy-Authenticate");
- while (iter.hasNext()) {
- String value = ((String)iter.next()).trim();
- if (value.equalsIgnoreCase("Negotiate") ||
- value.equalsIgnoreCase("Kerberos")) {
- if (!inNegotiateProxy) {
- inNegotiateProxy = true;
- } else {
- dontUseNegotiate = true;
- doingNTLMp2ndStage = false;
- proxyAuthentication = null;
- }
- break;
- }
- }
-
- AuthenticationHeader authhdr = new AuthenticationHeader (
- "Proxy-Authenticate", responses,
- new HttpCallerInfo(url, http.getProxyHostUsed(),
- http.getProxyPortUsed()),
- dontUseNegotiate
- );
- if (!doingNTLMp2ndStage) {
- proxyAuthentication =
- resetProxyAuthentication(proxyAuthentication, authhdr);
- if (proxyAuthentication != null) {
- proxyHost = http.getProxyHostUsed();
- proxyPort = http.getProxyPortUsed();
- disconnectInternal();
- retryTunnel++;
- continue;
- }
- } else {
- String raw = responses.findValue ("Proxy-Authenticate");
- reset ();
- if (!proxyAuthentication.setHeaders(this,
- authhdr.headerParser(), raw)) {
- disconnectInternal();
- throw new IOException ("Authentication failure");
- }
- authObj = null;
- doingNTLMp2ndStage = false;
- continue;
- }
- }
- // cache proxy authentication info
- if (proxyAuthentication != null) {
- // cache auth info on success, domain header not relevant.
- proxyAuthentication.addToCache();
- }
-
- if (respCode == HTTP_OK) {
- setTunnelState(TunnelState.TUNNELING);
- break;
- }
- // we don't know how to deal with other response code
- // so disconnect and report error
- disconnectInternal();
- setTunnelState(TunnelState.NONE);
- break;
- } while (retryTunnel < maxRedirects);
-
- if (retryTunnel >= maxRedirects || (respCode != HTTP_OK)) {
- throw new IOException("Unable to tunnel through proxy."+
- " Proxy returns \"" +
- statusLine + "\"");
- }
- } finally {
- if (proxyAuthKey != null) {
- AuthenticationInfo.endAuthRequest(proxyAuthKey);
- }
- }
-
- // restore original request headers
- requests = savedRequests;
-
- // reset responses
- responses.reset();
- }
-
- static String connectRequestURI(URL url) {
- String host = url.getHost();
- int port = url.getPort();
- port = port != -1 ? port : url.getDefaultPort();
-
- return host + ":" + port;
- }
-
- /**
- * send a CONNECT request for establishing a tunnel to proxy server
- */
- private void sendCONNECTRequest() throws IOException {
- int port = url.getPort();
-
- requests.set(0, HTTP_CONNECT + " " + connectRequestURI(url)
- + " " + httpVersion, null);
- requests.setIfNotSet("User-Agent", userAgent);
-
- String host = url.getHost();
- if (port != -1 && port != url.getDefaultPort()) {
- host += ":" + String.valueOf(port);
- }
- requests.setIfNotSet("Host", host);
-
- // Not really necessary for a tunnel, but can't hurt
- requests.setIfNotSet("Accept", acceptString);
-
- if (http.getHttpKeepAliveSet()) {
- requests.setIfNotSet("Proxy-Connection", "keep-alive");
- }
-
- setPreemptiveProxyAuthentication(requests);
-
- /* Log the CONNECT request */
- if (logger.isLoggable(PlatformLogger.FINE)) {
- logger.fine(requests.toString());
- }
-
- http.writeRequests(requests, null);
- }
-
- /**
- * Sets pre-emptive proxy authentication in header
- */
- private void setPreemptiveProxyAuthentication(MessageHeader requests) throws IOException {
- AuthenticationInfo pauth
- = AuthenticationInfo.getProxyAuth(http.getProxyHostUsed(),
- http.getProxyPortUsed());
- if (pauth != null && pauth.supportsPreemptiveAuthorization()) {
- String value;
- if (pauth instanceof DigestAuthentication) {
- DigestAuthentication digestProxy = (DigestAuthentication) pauth;
- if (tunnelState() == TunnelState.SETUP) {
- value = digestProxy
- .getHeaderValue(connectRequestURI(url), HTTP_CONNECT);
- } else {
- value = digestProxy.getHeaderValue(getRequestURI(), method);
- }
- } else {
- value = pauth.getHeaderValue(url, method);
- }
-
- // Sets "Proxy-authorization"
- requests.set(pauth.getHeaderName(), value);
- currentProxyCredentials = pauth;
- }
- }
-
- /**
- * Gets the authentication for an HTTP proxy, and applies it to
- * the connection.
- */
- private AuthenticationInfo getHttpProxyAuthentication (AuthenticationHeader authhdr) {
- /* get authorization from authenticator */
- AuthenticationInfo ret = null;
- String raw = authhdr.raw();
- String host = http.getProxyHostUsed();
- int port = http.getProxyPortUsed();
- if (host != null && authhdr.isPresent()) {
- HeaderParser p = authhdr.headerParser();
- String realm = p.findValue("realm");
- String scheme = authhdr.scheme();
- AuthScheme authScheme = UNKNOWN;
- if ("basic".equalsIgnoreCase(scheme)) {
- authScheme = BASIC;
- } else if ("digest".equalsIgnoreCase(scheme)) {
- authScheme = DIGEST;
- } else if ("ntlm".equalsIgnoreCase(scheme)) {
- authScheme = NTLM;
- doingNTLMp2ndStage = true;
- } else if ("Kerberos".equalsIgnoreCase(scheme)) {
- authScheme = KERBEROS;
- doingNTLMp2ndStage = true;
- } else if ("Negotiate".equalsIgnoreCase(scheme)) {
- authScheme = NEGOTIATE;
- doingNTLMp2ndStage = true;
- }
-
- if (realm == null)
- realm = "";
- proxyAuthKey = AuthenticationInfo.getProxyAuthKey(host, port, realm, authScheme);
- ret = AuthenticationInfo.getProxyAuth(proxyAuthKey);
- if (ret == null) {
- switch (authScheme) {
- case BASIC:
- InetAddress addr = null;
- try {
- final String finalHost = host;
- addr = java.security.AccessController.doPrivileged(
- new java.security.PrivilegedExceptionAction<InetAddress>() {
- public InetAddress run()
- throws java.net.UnknownHostException {
- return InetAddress.getByName(finalHost);
- }
- });
- } catch (java.security.PrivilegedActionException ignored) {
- // User will have an unknown host.
- }
- PasswordAuthentication a =
- privilegedRequestPasswordAuthentication(
- host, addr, port, "http",
- realm, scheme, url, RequestorType.PROXY);
- if (a != null) {
- ret = new BasicAuthentication(true, host, port, realm, a);
- }
- break;
- case DIGEST:
- a = privilegedRequestPasswordAuthentication(
- host, null, port, url.getProtocol(),
- realm, scheme, url, RequestorType.PROXY);
- if (a != null) {
- DigestAuthentication.Parameters params =
- new DigestAuthentication.Parameters();
- ret = new DigestAuthentication(true, host, port, realm,
- scheme, a, params);
- }
- break;
- case NTLM:
- if (NTLMAuthenticationProxy.proxy.supported) {
- /* tryTransparentNTLMProxy will always be true the first
- * time around, but verify that the platform supports it
- * otherwise don't try. */
- if (tryTransparentNTLMProxy) {
- tryTransparentNTLMProxy =
- NTLMAuthenticationProxy.proxy.supportsTransparentAuth;
- }
- a = null;
- if (tryTransparentNTLMProxy) {
- logger.finest("Trying Transparent NTLM authentication");
- } else {
- a = privilegedRequestPasswordAuthentication(
- host, null, port, url.getProtocol(),
- "", scheme, url, RequestorType.PROXY);
- }
- /* If we are not trying transparent authentication then
- * we need to have a PasswordAuthentication instance. For
- * transparent authentication (Windows only) the username
- * and password will be picked up from the current logged
- * on users credentials.
- */
- if (tryTransparentNTLMProxy ||
- (!tryTransparentNTLMProxy && a != null)) {
- ret = NTLMAuthenticationProxy.proxy.create(true, host, port, a);
- }
-
- /* set to false so that we do not try again */
- tryTransparentNTLMProxy = false;
- }
- break;
- case NEGOTIATE:
- ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Negotiate"));
- break;
- case KERBEROS:
- ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Kerberos"));
- break;
- case UNKNOWN:
- logger.finest("Unknown/Unsupported authentication scheme: " + scheme);
- default:
- throw new AssertionError("should not reach here");
- }
- }
- // For backwards compatibility, we also try defaultAuth
- // REMIND: Get rid of this for JDK2.0.
-
- if (ret == null && defaultAuth != null
- && defaultAuth.schemeSupported(scheme)) {
- try {
- URL u = new URL("http", host, port, "/");
- String a = defaultAuth.authString(u, scheme, realm);
- if (a != null) {
- ret = new BasicAuthentication (true, host, port, realm, a);
- // not in cache by default - cache on success
- }
- } catch (java.net.MalformedURLException ignored) {
- }
- }
- if (ret != null) {
- if (!ret.setHeaders(this, p, raw)) {
- ret = null;
- }
- }
- }
- if (logger.isLoggable(PlatformLogger.FINER)) {
- logger.finer("Proxy Authentication for " + authhdr.toString() +" returned " + (ret != null ? ret.toString() : "null"));
- }
- return ret;
- }
-
- /**
- * Gets the authentication for an HTTP server, and applies it to
- * the connection.
- * @param authHdr the AuthenticationHeader which tells what auth scheme is
- * prefered.
- */
- private AuthenticationInfo getServerAuthentication (AuthenticationHeader authhdr) {
- /* get authorization from authenticator */
- AuthenticationInfo ret = null;
- String raw = authhdr.raw();
- /* When we get an NTLM auth from cache, don't set any special headers */
- if (authhdr.isPresent()) {
- HeaderParser p = authhdr.headerParser();
- String realm = p.findValue("realm");
- String scheme = authhdr.scheme();
- AuthScheme authScheme = UNKNOWN;
- if ("basic".equalsIgnoreCase(scheme)) {
- authScheme = BASIC;
- } else if ("digest".equalsIgnoreCase(scheme)) {
- authScheme = DIGEST;
- } else if ("ntlm".equalsIgnoreCase(scheme)) {
- authScheme = NTLM;
- doingNTLM2ndStage = true;
- } else if ("Kerberos".equalsIgnoreCase(scheme)) {
- authScheme = KERBEROS;
- doingNTLM2ndStage = true;
- } else if ("Negotiate".equalsIgnoreCase(scheme)) {
- authScheme = NEGOTIATE;
- doingNTLM2ndStage = true;
- }
-
- domain = p.findValue ("domain");
- if (realm == null)
- realm = "";
- serverAuthKey = AuthenticationInfo.getServerAuthKey(url, realm, authScheme);
- ret = AuthenticationInfo.getServerAuth(serverAuthKey);
- InetAddress addr = null;
- if (ret == null) {
- try {
- addr = InetAddress.getByName(url.getHost());
- } catch (java.net.UnknownHostException ignored) {
- // User will have addr = null
- }
- }
- // replacing -1 with default port for a protocol
- int port = url.getPort();
- if (port == -1) {
- port = url.getDefaultPort();
- }
- if (ret == null) {
- switch(authScheme) {
- case KERBEROS:
- ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Kerberos"));
- break;
- case NEGOTIATE:
- ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Negotiate"));
- break;
- case BASIC:
- PasswordAuthentication a =
- privilegedRequestPasswordAuthentication(
- url.getHost(), addr, port, url.getProtocol(),
- realm, scheme, url, RequestorType.SERVER);
- if (a != null) {
- ret = new BasicAuthentication(false, url, realm, a);
- }
- break;
- case DIGEST:
- a = privilegedRequestPasswordAuthentication(
- url.getHost(), addr, port, url.getProtocol(),
- realm, scheme, url, RequestorType.SERVER);
- if (a != null) {
- digestparams = new DigestAuthentication.Parameters();
- ret = new DigestAuthentication(false, url, realm, scheme, a, digestparams);
- }
- break;
- case NTLM:
- if (NTLMAuthenticationProxy.proxy.supported) {
- URL url1;
- try {
- url1 = new URL (url, "/"); /* truncate the path */
- } catch (Exception e) {
- url1 = url;
- }
-
- /* tryTransparentNTLMServer will always be true the first
- * time around, but verify that the platform supports it
- * otherwise don't try. */
- if (tryTransparentNTLMServer) {
- tryTransparentNTLMServer =
- NTLMAuthenticationProxy.proxy.supportsTransparentAuth;
- /* If the platform supports transparent authentication
- * then check if we are in a secure environment
- * whether, or not, we should try transparent authentication.*/
- if (tryTransparentNTLMServer) {
- tryTransparentNTLMServer =
- NTLMAuthenticationProxy.proxy.isTrustedSite(url);
- }
- }
- a = null;
- if (tryTransparentNTLMServer) {
- logger.finest("Trying Transparent NTLM authentication");
- } else {
- a = privilegedRequestPasswordAuthentication(
- url.getHost(), addr, port, url.getProtocol(),
- "", scheme, url, RequestorType.SERVER);
- }
-
- /* If we are not trying transparent authentication then
- * we need to have a PasswordAuthentication instance. For
- * transparent authentication (Windows only) the username
- * and password will be picked up from the current logged
- * on users credentials.
- */
- if (tryTransparentNTLMServer ||
- (!tryTransparentNTLMServer && a != null)) {
- ret = NTLMAuthenticationProxy.proxy.create(false, url1, a);
- }
-
- /* set to false so that we do not try again */
- tryTransparentNTLMServer = false;
- }
- break;
- case UNKNOWN:
- logger.finest("Unknown/Unsupported authentication scheme: " + scheme);
- default:
- throw new AssertionError("should not reach here");
- }
- }
-
- // For backwards compatibility, we also try defaultAuth
- // REMIND: Get rid of this for JDK2.0.
-
- if (ret == null && defaultAuth != null
- && defaultAuth.schemeSupported(scheme)) {
- String a = defaultAuth.authString(url, scheme, realm);
- if (a != null) {
- ret = new BasicAuthentication (false, url, realm, a);
- // not in cache by default - cache on success
- }
- }
-
- if (ret != null ) {
- if (!ret.setHeaders(this, p, raw)) {
- ret = null;
- }
- }
- }
- if (logger.isLoggable(PlatformLogger.FINER)) {
- logger.finer("Server Authentication for " + authhdr.toString() +" returned " + (ret != null ? ret.toString() : "null"));
- }
- return ret;
- }
-
- /* inclose will be true if called from close(), in which case we
- * force the call to check because this is the last chance to do so.
- * If not in close(), then the authentication info could arrive in a trailer
- * field, which we have not read yet.
- */
- private void checkResponseCredentials (boolean inClose) throws IOException {
- try {
- if (!needToCheck)
- return;
- if ((validateProxy && currentProxyCredentials != null) &&
- (currentProxyCredentials instanceof DigestAuthentication)) {
- String raw = responses.findValue ("Proxy-Authentication-Info");
- if (inClose || (raw != null)) {
- DigestAuthentication da = (DigestAuthentication)
- currentProxyCredentials;
- da.checkResponse (raw, method, getRequestURI());
- currentProxyCredentials = null;
- }
- }
- if ((validateServer && currentServerCredentials != null) &&
- (currentServerCredentials instanceof DigestAuthentication)) {
- String raw = responses.findValue ("Authentication-Info");
- if (inClose || (raw != null)) {
- DigestAuthentication da = (DigestAuthentication)
- currentServerCredentials;
- da.checkResponse (raw, method, url);
- currentServerCredentials = null;
- }
- }
- if ((currentServerCredentials==null) && (currentProxyCredentials == null)) {
- needToCheck = false;
- }
- } catch (IOException e) {
- disconnectInternal();
- connected = false;
- throw e;
- }
- }
-
- /* The request URI used in the request line for this request.
- * Also, needed for digest authentication
- */
-
- String requestURI = null;
-
- String getRequestURI() throws IOException {
- if (requestURI == null) {
- requestURI = http.getURLFile();
- }
- return requestURI;
- }
-
- /* Tells us whether to follow a redirect. If so, it
- * closes the connection (break any keep-alive) and
- * resets the url, re-connects, and resets the request
- * property.
- */
- private boolean followRedirect() throws IOException {
- if (!getInstanceFollowRedirects()) {
- return false;
- }
-
- int stat = getResponseCode();
- if (stat < 300 || stat > 307 || stat == 306
- || stat == HTTP_NOT_MODIFIED) {
- return false;
- }
- String loc = getHeaderField("Location");
- if (loc == null) {
- /* this should be present - if not, we have no choice
- * but to go forward w/ the response we got
- */
- return false;
- }
- URL locUrl;
- try {
- locUrl = new URL(loc);
- if (!url.getProtocol().equalsIgnoreCase(locUrl.getProtocol())) {
- return false;
- }
-
- } catch (MalformedURLException mue) {
- // treat loc as a relative URI to conform to popular browsers
- locUrl = new URL(url, loc);
- }
- disconnectInternal();
- if (streaming()) {
- throw new HttpRetryException (RETRY_MSG3, stat, loc);
- }
- if (logger.isLoggable(PlatformLogger.FINE)) {
- logger.fine("Redirected from " + url + " to " + locUrl);
- }
-
- // clear out old response headers!!!!
- responses = new MessageHeader();
- if (stat == HTTP_USE_PROXY) {
- /* This means we must re-request the resource through the
- * proxy denoted in the "Location:" field of the response.
- * Judging by the spec, the string in the Location header
- * _should_ denote a URL - let's hope for "http://my.proxy.org"
- * Make a new HttpClient to the proxy, using HttpClient's
- * Instance-specific proxy fields, but note we're still fetching
- * the same URL.
- */
- String proxyHost = locUrl.getHost();
- int proxyPort = locUrl.getPort();
-
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- security.checkConnect(proxyHost, proxyPort);
- }
-
- setProxiedClient (url, proxyHost, proxyPort);
- requests.set(0, method + " " + getRequestURI()+" " +
- httpVersion, null);
- connected = true;
- } else {
- // maintain previous headers, just change the name
- // of the file we're getting
- url = locUrl;
- requestURI = null; // force it to be recalculated
- if (method.equals("POST") && !Boolean.getBoolean("http.strictPostRedirect") && (stat!=307)) {
- /* The HTTP/1.1 spec says that a redirect from a POST
- * *should not* be immediately turned into a GET, and
- * that some HTTP/1.0 clients incorrectly did this.
- * Correct behavior redirects a POST to another POST.
- * Unfortunately, since most browsers have this incorrect
- * behavior, the web works this way now. Typical usage
- * seems to be:
- * POST a login code or passwd to a web page.
- * after validation, the server redirects to another
- * (welcome) page
- * The second request is (erroneously) expected to be GET
- *
- * We will do the incorrect thing (POST-->GET) by default.
- * We will provide the capability to do the "right" thing
- * (POST-->POST) by a system property, "http.strictPostRedirect=true"
- */
-
- requests = new MessageHeader();
- setRequests = false;
- setRequestMethod("GET");
- poster = null;
- if (!checkReuseConnection())
- connect();
- } else {
- if (!checkReuseConnection())
- connect();
- /* Even after a connect() call, http variable still can be
- * null, if a ResponseCache has been installed and it returns
- * a non-null CacheResponse instance. So check nullity before using it.
- *
- * And further, if http is null, there's no need to do anything
- * about request headers because successive http session will use
- * cachedInputStream/cachedHeaders anyway, which is returned by
- * CacheResponse.
- */
- if (http != null) {
- requests.set(0, method + " " + getRequestURI()+" " +
- httpVersion, null);
- int port = url.getPort();
- String host = url.getHost();
- if (port != -1 && port != url.getDefaultPort()) {
- host += ":" + String.valueOf(port);
- }
- requests.set("Host", host);
- }
- }
- }
- return true;
- }
-
- /* dummy byte buffer for reading off socket prior to closing */
- byte[] cdata = new byte [128];
-
- /**
- * Reset (without disconnecting the TCP conn) in order to do another transaction with this instance
- */
- private void reset() throws IOException {
- http.reuse = true;
- /* must save before calling close */
- reuseClient = http;
- InputStream is = http.getInputStream();
- if (!method.equals("HEAD")) {
- try {
- /* we want to read the rest of the response without using the
- * hurry mechanism, because that would close the connection
- * if everything is not available immediately
- */
- if ((is instanceof ChunkedInputStream) ||
- (is instanceof MeteredStream)) {
- /* reading until eof will not block */
- while (is.read (cdata) > 0) {}
- } else {
- /* raw stream, which will block on read, so only read
- * the expected number of bytes, probably 0
- */
- long cl = 0;
- int n = 0;
- String cls = responses.findValue ("Content-Length");
- if (cls != null) {
- try {
- cl = Long.parseLong (cls);
- } catch (NumberFormatException e) {
- cl = 0;
- }
- }
- for (long i=0; i<cl; ) {
- if ((n = is.read (cdata)) == -1) {
- break;
- } else {
- i+= n;
- }
- }
- }
- } catch (IOException e) {
- http.reuse = false;
- reuseClient = null;
- disconnectInternal();
- return;
- }
- try {
- if (is instanceof MeteredStream) {
- is.close();
- }
- } catch (IOException e) { }
- }
- responseCode = -1;
- responses = new MessageHeader();
- connected = false;
- }
-
- /**
- * Disconnect from the web server at the first 401 error. Do not
- * disconnect when using a proxy, a good proxy should have already
- * closed the connection to the web server.
- */
- private void disconnectWeb() throws IOException {
- if (usingProxy() && http.isKeepingAlive()) {
- responseCode = -1;
- // clean up, particularly, skip the content part
- // of a 401 error response
- reset();
- } else {
- disconnectInternal();
- }
- }
-
- /**
- * Disconnect from the server (for internal use)
- */
- private void disconnectInternal() {
- responseCode = -1;
- inputStream = null;
- if (pi != null) {
- pi.finishTracking();
- pi = null;
- }
- if (http != null) {
- http.closeServer();
- http = null;
- connected = false;
- }
- }
-
- /**
- * Disconnect from the server (public API)
- */
- public void disconnect() {
-
- responseCode = -1;
- if (pi != null) {
- pi.finishTracking();
- pi = null;
- }
-
- if (http != null) {
- /*
- * If we have an input stream this means we received a response
- * from the server. That stream may have been read to EOF and
- * dependening on the stream type may already be closed or the
- * the http client may be returned to the keep-alive cache.
- * If the http client has been returned to the keep-alive cache
- * it may be closed (idle timeout) or may be allocated to
- * another request.
- *
- * In other to avoid timing issues we close the input stream
- * which will either close the underlying connection or return
- * the client to the cache. If there's a possibility that the
- * client has been returned to the cache (ie: stream is a keep
- * alive stream or a chunked input stream) then we remove an
- * idle connection to the server. Note that this approach
- * can be considered an approximation in that we may close a
- * different idle connection to that used by the request.
- * Additionally it's possible that we close two connections
- * - the first becuase it wasn't an EOF (and couldn't be
- * hurried) - the second, another idle connection to the
- * same server. The is okay because "disconnect" is an
- * indication that the application doesn't intend to access
- * this http server for a while.
- */
-
- if (inputStream != null) {
- HttpClient hc = http;
-
- // un-synchronized
- boolean ka = hc.isKeepingAlive();
-
- try {
- inputStream.close();
- } catch (IOException ioe) { }
-
- // if the connection is persistent it may have been closed
- // or returned to the keep-alive cache. If it's been returned
- // to the keep-alive cache then we would like to close it
- // but it may have been allocated
-
- if (ka) {
- hc.closeIdleConnection();
- }
-
-
- } else {
- // We are deliberatly being disconnected so HttpClient
- // should not try to resend the request no matter what stage
- // of the connection we are in.
- http.setDoNotRetry(true);
-
- http.closeServer();
- }
-
- // poster = null;
- http = null;
- connected = false;
- }
- cachedInputStream = null;
- if (cachedHeaders != null) {
- cachedHeaders.reset();
- }
- }
-
- public boolean usingProxy() {
- if (http != null) {
- return (http.getProxyHostUsed() != null);
- }
- return false;
- }
-
- // constant strings represent set-cookie header names
- private final static String SET_COOKIE = "set-cookie";
- private final static String SET_COOKIE2 = "set-cookie2";
-
- /**
- * Returns a filtered version of the given headers value.
- *
- * Note: The implementation currently only filters out HttpOnly cookies
- * from Set-Cookie and Set-Cookie2 headers.
- */
- private String filterHeaderField(String name, String value) {
- if (value == null)
- return null;
-
- if (SET_COOKIE.equalsIgnoreCase(name) ||
- SET_COOKIE2.equalsIgnoreCase(name)) {
- // Filtering only if there is a cookie handler. [Assumption: the
- // cookie handler will store/retrieve the HttpOnly cookies]
- if (cookieHandler == null)
- return value;
-
- StringBuilder retValue = new StringBuilder();
- List<HttpCookie> cookies = HttpCookie.parse(value, true);
- boolean multipleCookies = false;
- for (HttpCookie cookie : cookies) {
- // skip HttpOnly cookies
- if (cookie.isHttpOnly())
- continue;
- if (multipleCookies)
- retValue.append(','); // RFC 2965, comma separated
- retValue.append(cookie.header);
- multipleCookies = true;
- }
-
- return retValue.length() == 0 ? "" : retValue.toString();
- }
-
- return value;
- }
-
- // Cache the filtered response headers so that they don't need
- // to be generated for every getHeaderFields() call.
- private Map<String, List<String>> filteredHeaders; // null
-
- private Map<String, List<String>> getFilteredHeaderFields() {
- if (filteredHeaders != null)
- return filteredHeaders;
-
- Map<String, List<String>> headers, tmpMap = new HashMap<>();
-
- if (cachedHeaders != null)
- headers = cachedHeaders.getHeaders();
- else
- headers = responses.getHeaders();
-
- for (Map.Entry<String, List<String>> e: headers.entrySet()) {
- String key = e.getKey();
- List<String> values = e.getValue(), filteredVals = new ArrayList<>();
- for (String value : values) {
- String fVal = filterHeaderField(key, value);
- if (fVal != null)
- filteredVals.add(fVal);
- }
- if (!filteredVals.isEmpty())
- tmpMap.put(key, Collections.unmodifiableList(filteredVals));
- }
-
- return filteredHeaders = Collections.unmodifiableMap(tmpMap);
- }
-
- /**
- * Gets a header field by name. Returns null if not known.
- * @param name the name of the header field
- */
- @Override
- public String getHeaderField(String name) {
- try {
- getInputStream();
- } catch (IOException e) {}
-
- if (cachedHeaders != null) {
- return filterHeaderField(name, cachedHeaders.findValue(name));
- }
-
- return filterHeaderField(name, responses.findValue(name));
- }
-
- /**
- * 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
- */
- @Override
- public Map<String, List<String>> getHeaderFields() {
- try {
- getInputStream();
- } catch (IOException e) {}
-
- return getFilteredHeaderFields();
- }
-
- /**
- * Gets a header field by index. Returns null if not known.
- * @param n the index of the header field
- */
- @Override
- public String getHeaderField(int n) {
- try {
- getInputStream();
- } catch (IOException e) {}
-
- if (cachedHeaders != null) {
- return filterHeaderField(cachedHeaders.getKey(n),
- cachedHeaders.getValue(n));
- }
- return filterHeaderField(responses.getKey(n), responses.getValue(n));
- }
-
- /**
- * Gets a header field by index. Returns null if not known.
- * @param n the index of the header field
- */
- @Override
- public String getHeaderFieldKey(int n) {
- try {
- getInputStream();
- } catch (IOException e) {}
-
- if (cachedHeaders != null) {
- return cachedHeaders.getKey(n);
- }
-
- return responses.getKey(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
- */
- @Override
- public void setRequestProperty(String key, String value) {
- if (connected)
- throw new IllegalStateException("Already connected");
- if (key == null)
- throw new NullPointerException ("key is null");
-
- if (isExternalMessageHeaderAllowed(key, value)) {
- requests.set(key, value);
- }
- }
-
- /**
- * Adds a general request property specified by a
- * key-value pair. This method will not overwrite
- * existing values associated with the same key.
- *
- * @param key the keyword by which the request is known
- * (e.g., "<code>accept</code>").
- * @param value the value associated with it.
- * @see #getRequestProperties(java.lang.String)
- * @since 1.4
- */
- @Override
- public void addRequestProperty(String key, String value) {
- if (connected)
- throw new IllegalStateException("Already connected");
- if (key == null)
- throw new NullPointerException ("key is null");
-
- if (isExternalMessageHeaderAllowed(key, value)) {
- requests.add(key, value);
- }
- }
-
- //
- // Set a property for authentication. This can safely disregard
- // the connected test.
- //
- public void setAuthenticationProperty(String key, String value) {
- checkMessageHeader(key, value);
- requests.set(key, value);
- }
-
- @Override
- public synchronized String getRequestProperty (String key) {
- if (key == null) {
- return null;
- }
-
- // don't return headers containing security sensitive information
- for (int i=0; i < EXCLUDE_HEADERS.length; i++) {
- if (key.equalsIgnoreCase(EXCLUDE_HEADERS[i])) {
- return null;
- }
- }
- if (!setUserCookies) {
- if (key.equalsIgnoreCase("Cookie")) {
- return userCookies;
- }
- if (key.equalsIgnoreCase("Cookie2")) {
- return userCookies2;
- }
- }
- return requests.findValue(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
- */
- @Override
- public synchronized Map<String, List<String>> getRequestProperties() {
- if (connected)
- throw new IllegalStateException("Already connected");
-
- // exclude headers containing security-sensitive info
- if (setUserCookies) {
- return requests.getHeaders(EXCLUDE_HEADERS);
- }
- /*
- * The cookies in the requests message headers may have
- * been modified. Use the saved user cookies instead.
- */
- Map userCookiesMap = null;
- if (userCookies != null || userCookies2 != null) {
- userCookiesMap = new HashMap();
- if (userCookies != null) {
- userCookiesMap.put("Cookie", userCookies);
- }
- if (userCookies2 != null) {
- userCookiesMap.put("Cookie2", userCookies2);
- }
- }
- return requests.filterAndAddHeaders(EXCLUDE_HEADERS2, userCookiesMap);
- }
-
- @Override
- public void setConnectTimeout(int timeout) {
- if (timeout < 0)
- throw new IllegalArgumentException("timeouts can't be negative");
- connectTimeout = timeout;
- }
-
-
- /**
- * Returns setting for connect timeout.
- * <p>
- * 0 return implies that the option is disabled
- * (i.e., timeout of infinity).
- *
- * @return an <code>int</code> that indicates the connect timeout
- * value in milliseconds
- * @see java.net.URLConnection#setConnectTimeout(int)
- * @see java.net.URLConnection#connect()
- * @since 1.5
- */
- @Override
- public int getConnectTimeout() {
- return (connectTimeout < 0 ? 0 : connectTimeout);
- }
-
- /**
- * Sets the read timeout to a specified timeout, in
- * milliseconds. A non-zero value specifies the timeout when
- * reading from Input stream when a connection is established to a
- * resource. If the timeout expires before there is data available
- * for read, a java.net.SocketTimeoutException is raised. A
- * timeout of zero is interpreted as an infinite timeout.
- *
- * <p> Some non-standard implementation of this method ignores the
- * specified timeout. To see the read timeout set, please call
- * getReadTimeout().
- *
- * @param timeout an <code>int</code> that specifies the timeout
- * value to be used in milliseconds
- * @throws IllegalArgumentException if the timeout parameter is negative
- *
- * @see java.net.URLConnectiongetReadTimeout()
- * @see java.io.InputStream#read()
- * @since 1.5
- */
- @Override
- public void setReadTimeout(int timeout) {
- if (timeout < 0)
- throw new IllegalArgumentException("timeouts can't be negative");
- readTimeout = timeout;
- }
-
- /**
- * Returns setting for read timeout. 0 return implies that the
- * option is disabled (i.e., timeout of infinity).
- *
- * @return an <code>int</code> that indicates the read timeout
- * value in milliseconds
- *
- * @see java.net.URLConnection#setReadTimeout(int)
- * @see java.io.InputStream#read()
- * @since 1.5
- */
- @Override
- public int getReadTimeout() {
- return readTimeout < 0 ? 0 : readTimeout;
- }
-
- public CookieHandler getCookieHandler() {
- return cookieHandler;
- }
-
- String getMethod() {
- return method;
- }
-
- private MessageHeader mapToMessageHeader(Map<String, List<String>> map) {
- MessageHeader headers = new MessageHeader();
- if (map == null || map.isEmpty()) {
- return headers;
- }
- for (Map.Entry<String, List<String>> entry : map.entrySet()) {
- String key = entry.getKey();
- List<String> values = entry.getValue();
- for (String value : values) {
- if (key == null) {
- headers.prepend(key, value);
- } else {
- headers.add(key, value);
- }
- }
- }
- return headers;
- }
-
- /* The purpose of this wrapper is just to capture the close() call
- * so we can check authentication information that may have
- * arrived in a Trailer field
- */
- class HttpInputStream extends FilterInputStream {
- private CacheRequest cacheRequest;
- private OutputStream outputStream;
- private boolean marked = false;
- private int inCache = 0;
- private int markCount = 0;
-
- public HttpInputStream (InputStream is) {
- super (is);
- this.cacheRequest = null;
- this.outputStream = null;
- }
-
- public HttpInputStream (InputStream is, CacheRequest cacheRequest) {
- super (is);
- this.cacheRequest = cacheRequest;
- try {
- this.outputStream = cacheRequest.getBody();
- } catch (IOException ioex) {
- this.cacheRequest.abort();
- this.cacheRequest = null;
- this.outputStream = null;
- }
- }
-
- /**
- * Marks the current position in this input stream. A subsequent
- * call to the <code>reset</code> method repositions this stream at
- * the last marked position so that subsequent reads re-read the same
- * bytes.
- * <p>
- * The <code>readlimit</code> argument tells this input stream to
- * allow that many bytes to be read before the mark position gets
- * invalidated.
- * <p>
- * This method simply performs <code>in.mark(readlimit)</code>.
- *
- * @param readlimit the maximum limit of bytes that can be read before
- * the mark position becomes invalid.
- * @see java.io.FilterInputStream#in
- * @see java.io.FilterInputStream#reset()
- */
- @Override
- public synchronized void mark(int readlimit) {
- super.mark(readlimit);
- if (cacheRequest != null) {
- marked = true;
- markCount = 0;
- }
- }
-
- /**
- * Repositions this stream to the position at the time the
- * <code>mark</code> method was last called on this input stream.
- * <p>
- * This method
- * simply performs <code>in.reset()</code>.
- * <p>
- * Stream marks are intended to be used in
- * situations where you need to read ahead a little to see what's in
- * the stream. Often this is most easily done by invoking some
- * general parser. If the stream is of the type handled by the
- * parse, it just chugs along happily. If the stream is not of
- * that type, the parser should toss an exception when it fails.
- * If this happens within readlimit bytes, it allows the outer
- * code to reset the stream and try another parser.
- *
- * @exception IOException if the stream has not been marked or if the
- * mark has been invalidated.
- * @see java.io.FilterInputStream#in
- * @see java.io.FilterInputStream#mark(int)
- */
- @Override
- public synchronized void reset() throws IOException {
- super.reset();
- if (cacheRequest != null) {
- marked = false;
- inCache += markCount;
- }
- }
-
- @Override
- public int read() throws IOException {
- try {
- byte[] b = new byte[1];
- int ret = read(b);
- return (ret == -1? ret : (b[0] & 0x00FF));
- } catch (IOException ioex) {
- if (cacheRequest != null) {
- cacheRequest.abort();
- }
- throw ioex;
- }
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- return read(b, 0, b.length);
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- try {
- int newLen = super.read(b, off, len);
- int nWrite;
- // write to cache
- if (inCache > 0) {
- if (inCache >= newLen) {
- inCache -= newLen;
- nWrite = 0;
- } else {
- nWrite = newLen - inCache;
- inCache = 0;
- }
- } else {
- nWrite = newLen;
- }
- if (nWrite > 0 && outputStream != null)
- outputStream.write(b, off + (newLen-nWrite), nWrite);
- if (marked) {
- markCount += newLen;
- }
- return newLen;
- } catch (IOException ioex) {
- if (cacheRequest != null) {
- cacheRequest.abort();
- }
- throw ioex;
- }
- }
-
- /* skip() calls read() in order to ensure that entire response gets
- * cached. same implementation as InputStream.skip */
-
- private byte[] skipBuffer;
- private static final int SKIP_BUFFER_SIZE = 8096;
-
- @Override
- public long skip (long n) throws IOException {
-
- long remaining = n;
- int nr;
- if (skipBuffer == null)
- skipBuffer = new byte[SKIP_BUFFER_SIZE];
-
- byte[] localSkipBuffer = skipBuffer;
-
- if (n <= 0) {
- return 0;
- }
-
- while (remaining > 0) {
- nr = read(localSkipBuffer, 0,
- (int) Math.min(SKIP_BUFFER_SIZE, remaining));
- if (nr < 0) {
- break;
- }
- remaining -= nr;
- }
-
- return n - remaining;
- }
-
- @Override
- public void close () throws IOException {
- try {
- if (outputStream != null) {
- if (read() != -1) {
- cacheRequest.abort();
- } else {
- outputStream.close();
- }
- }
- super.close ();
- } catch (IOException ioex) {
- if (cacheRequest != null) {
- cacheRequest.abort();
- }
- throw ioex;
- } finally {
- HttpURLConnection.this.http = null;
- checkResponseCredentials (true);
- }
- }
- }
-
- class StreamingOutputStream extends FilterOutputStream {
-
- long expected;
- long written;
- boolean closed;
- boolean error;
- IOException errorExcp;
-
- /**
- * expectedLength == -1 if the stream is chunked
- * expectedLength > 0 if the stream is fixed content-length
- * In the 2nd case, we make sure the expected number of
- * of bytes are actually written
- */
- StreamingOutputStream (OutputStream os, long expectedLength) {
- super (os);
- expected = expectedLength;
- written = 0L;
- closed = false;
- error = false;
- }
-
- @Override
- public void write (int b) throws IOException {
- checkError();
- written ++;
- if (expected != -1L && written > expected) {
- throw new IOException ("too many bytes written");
- }
- out.write (b);
- }
-
- @Override
- public void write (byte[] b) throws IOException {
- write (b, 0, b.length);
- }
-
- @Override
- public void write (byte[] b, int off, int len) throws IOException {
- checkError();
- written += len;
- if (expected != -1L && written > expected) {
- out.close ();
- throw new IOException ("too many bytes written");
- }
- out.write (b, off, len);
- }
-
- void checkError () throws IOException {
- if (closed) {
- throw new IOException ("Stream is closed");
- }
- if (error) {
- throw errorExcp;
- }
- if (((PrintStream)out).checkError()) {
- throw new IOException("Error writing request body to server");
- }
- }
-
- /* this is called to check that all the bytes
- * that were supposed to be written were written
- * and that the stream is now closed().
- */
- boolean writtenOK () {
- return closed && ! error;
- }
-
- @Override
- public void close () throws IOException {
- if (closed) {
- return;
- }
- closed = true;
- if (expected != -1L) {
- /* not chunked */
- if (written != expected) {
- error = true;
- errorExcp = new IOException ("insufficient data written");
- out.close ();
- throw errorExcp;
- }
- super.flush(); /* can't close the socket */
- } else {
- /* chunked */
- super.close (); /* force final chunk to be written */
- /* trailing \r\n */
- OutputStream o = http.getOutputStream();
- o.write ('\r');
- o.write ('\n');
- o.flush();
- }
- }
- }
-
-
- static class ErrorStream extends InputStream {
- ByteBuffer buffer;
- InputStream is;
-
- private ErrorStream(ByteBuffer buf) {
- buffer = buf;
- is = null;
- }
-
- private ErrorStream(ByteBuffer buf, InputStream is) {
- buffer = buf;
- this.is = is;
- }
-
- // when this method is called, it's either the case that cl > 0, or
- // if chunk-encoded, cl = -1; in other words, cl can't be 0
- public static InputStream getErrorStream(InputStream is, long cl, HttpClient http) {
-
- // cl can't be 0; this following is here for extra precaution
- if (cl == 0) {
- return null;
- }
-
- try {
- // set SO_TIMEOUT to 1/5th of the total timeout
- // remember the old timeout value so that we can restore it
- int oldTimeout = http.getReadTimeout();
- http.setReadTimeout(timeout4ESBuffer/5);
-
- long expected = 0;
- boolean isChunked = false;
- // the chunked case
- if (cl < 0) {
- expected = bufSize4ES;
- isChunked = true;
- } else {
- expected = cl;
- }
- if (expected <= bufSize4ES) {
- int exp = (int) expected;
- byte[] buffer = new byte[exp];
- int count = 0, time = 0, len = 0;
- do {
- try {
- len = is.read(buffer, count,
- buffer.length - count);
- if (len < 0) {
- if (isChunked) {
- // chunked ended
- // if chunked ended prematurely,
- // an IOException would be thrown
- break;
- }
- // the server sends less than cl bytes of data
- throw new IOException("the server closes"+
- " before sending "+cl+
- " bytes of data");
- }
- count += len;
- } catch (SocketTimeoutException ex) {
- time += timeout4ESBuffer/5;
- }
- } while (count < exp && time < timeout4ESBuffer);
-
- // reset SO_TIMEOUT to old value
- http.setReadTimeout(oldTimeout);
-
- // if count < cl at this point, we will not try to reuse
- // the connection
- if (count == 0) {
- // since we haven't read anything,
- // we will return the underlying
- // inputstream back to the application
- return null;
- } else if ((count == expected && !(isChunked)) || (isChunked && len <0)) {
- // put the connection into keep-alive cache
- // the inputstream will try to do the right thing
- is.close();
- return new ErrorStream(ByteBuffer.wrap(buffer, 0, count));
- } else {
- // we read part of the response body
- return new ErrorStream(
- ByteBuffer.wrap(buffer, 0, count), is);
- }
- }
- return null;
- } catch (IOException ioex) {
- // ioex.printStackTrace();
- return null;
- }
- }
-
- @Override
- public int available() throws IOException {
- if (is == null) {
- return buffer.remaining();
- } else {
- return buffer.remaining()+is.available();
- }
- }
-
- public int read() throws IOException {
- byte[] b = new byte[1];
- int ret = read(b);
- return (ret == -1? ret : (b[0] & 0x00FF));
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- return read(b, 0, b.length);
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- int rem = buffer.remaining();
- if (rem > 0) {
- int ret = rem < len? rem : len;
- buffer.get(b, off, ret);
- return ret;
- } else {
- if (is == null) {
- return -1;
- } else {
- return is.read(b, off, len);
- }
- }
- }
-
- @Override
- public void close() throws IOException {
- buffer = null;
- if (is != null) {
- is.close();
- }
- }
- }
-}
-
-/** An input stream that just returns EOF. This is for
- * HTTP URLConnections that are KeepAlive && use the
- * HEAD method - i.e., stream not dead, but nothing to be read.
- */
-
-class EmptyInputStream extends InputStream {
-
- @Override
- public int available() {
- return 0;
- }
-
- public int read() {
- return -1;
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/NTLMAuthenticationProxy.java b/ojluni/src/main/java/sun/net/www/protocol/http/NTLMAuthenticationProxy.java
deleted file mode 100644
index 5d656a0..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/NTLMAuthenticationProxy.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.net.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();
- logger.finest("NTLMAuthenticationProxy: " + e);
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/NegotiateAuthentication.java b/ojluni/src/main/java/sun/net/www/protocol/http/NegotiateAuthentication.java
deleted file mode 100644
index 23a8a83..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/NegotiateAuthentication.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * 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;
-
-import java.net.URL;
-import java.io.IOException;
-import java.net.Authenticator.RequestorType;
-import java.util.HashMap;
-import sun.net.www.HeaderParser;
-import sun.misc.BASE64Decoder;
-import sun.misc.BASE64Encoder;
-import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE;
-import static sun.net.www.protocol.http.AuthScheme.KERBEROS;
-
-/**
- * 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 HashMap <String, Negotiator> cache = null;
-
- // 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, Boolean>();
- cache = new HashMap <String, Negotiator>();
- }
- 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
- cache.put(hostname, neg);
- return true;
- } else {
- supported.put(hostname, false);
- return false;
- }
- }
-
- /**
- * 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 = new BASE64Decoder().decodeBuffer(parts[1]);
- }
- response = hci.scheme + " " + new B64Encoder().encode(
- 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;
- if (cache != null) {
- synchronized(cache) {
- negotiator = cache.get(getHost());
- if (negotiator != null) {
- cache.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);
- }
-
- class B64Encoder extends BASE64Encoder {
- protected int bytesPerLine () {
- return 100000; // as big as it can be, maybe INT_MAX
- }
- }
-
- // 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.
-
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/http/Negotiator.java b/ojluni/src/main/java/sun/net/www/protocol/http/Negotiator.java
deleted file mode 100644
index 522d6fb..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/http/Negotiator.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.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();
- logger.finest("NegotiateAuthentication: " + e);
- }
-}
-
diff --git a/ojluni/src/main/native/DatagramPacket.c b/ojluni/src/main/native/DatagramPacket.c
deleted file mode 100644
index fac60ed..0000000
--- a/ojluni/src/main/native/DatagramPacket.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "net_util.h"
-#include "JNIHelp.h"
-
-#define NATIVE_METHOD(className, functionName, signature) \
-{ #functionName, signature, (void*)(className ## _ ## functionName) }
-
-/************************************************************************
- * DatagramPacket
- */
-
-jfieldID dp_addressID;
-jfieldID dp_portID;
-jfieldID dp_bufID;
-jfieldID dp_offsetID;
-jfieldID dp_lengthID;
-jfieldID dp_bufLengthID;
-
-/*
- * Class: java_net_DatagramPacket
- * Method: init
- * Signature: ()V
- */
-JNIEXPORT void JNICALL
-DatagramPacket_init (JNIEnv *env, jclass cls) {
- dp_addressID = (*env)->GetFieldID(env, cls, "address",
- "Ljava/net/InetAddress;");
- CHECK_NULL(dp_addressID);
- dp_portID = (*env)->GetFieldID(env, cls, "port", "I");
- CHECK_NULL(dp_portID);
- dp_bufID = (*env)->GetFieldID(env, cls, "buf", "[B");
- CHECK_NULL(dp_bufID);
- dp_offsetID = (*env)->GetFieldID(env, cls, "offset", "I");
- CHECK_NULL(dp_offsetID);
- dp_lengthID = (*env)->GetFieldID(env, cls, "length", "I");
- CHECK_NULL(dp_lengthID);
- dp_bufLengthID = (*env)->GetFieldID(env, cls, "bufLength", "I");
- CHECK_NULL(dp_bufLengthID);
-}
-
-static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(DatagramPacket, init, "()V"),
-};
-
-void register_java_net_DatagramPacket(JNIEnv* env) {
- jniRegisterNativeMethods(env, "java/net/DatagramPacket", gMethods, NELEM(gMethods));
-}
diff --git a/ojluni/src/main/native/PlainDatagramSocketImpl.c b/ojluni/src/main/native/PlainDatagramSocketImpl.c
deleted file mode 100644
index b36e286..0000000
--- a/ojluni/src/main/native/PlainDatagramSocketImpl.c
+++ /dev/null
@@ -1,1965 +0,0 @@
-/*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include <errno.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#ifdef __solaris__
-#include <fcntl.h>
-#endif
-#ifdef __linux__
-#include <unistd.h>
-//#include <sys/sysctl.h>
-#include <sys/utsname.h>
-#include <netinet/ip.h>
-
-#define IPV6_MULTICAST_IF 17
-#ifndef SO_BSDCOMPAT
-#define SO_BSDCOMPAT 14
-#endif
-/**
- * IP_MULTICAST_ALL has been supported since kernel version 2.6.31
- * but we may be building on a machine that is older than that.
- */
-#ifndef IP_MULTICAST_ALL
-#define IP_MULTICAST_ALL 49
-#endif
-#endif // __linux__
-
-#ifndef IPTOS_TOS_MASK
-#define IPTOS_TOS_MASK 0x1e
-#endif
-#ifndef IPTOS_PREC_MASK
-#define IPTOS_PREC_MASK 0xe0
-#endif
-
-#include "jvm.h"
-#include "jni_util.h"
-#include "net_util.h"
-
-#include "java_net_SocketOptions.h"
-#include "java_net_PlainDatagramSocketImpl.h"
-#include "JNIHelp.h"
-
-#define NATIVE_METHOD(className, functionName, signature) \
-{ #functionName, signature, (void*)(className ## _ ## functionName) }
-/************************************************************************
- * PlainDatagramSocketImpl
- */
-
-static jfieldID IO_fd_fdID;
-
-static jfieldID pdsi_fdID;
-static jfieldID pdsi_timeoutID;
-static jfieldID pdsi_trafficClassID;
-static jfieldID pdsi_localPortID;
-static jfieldID pdsi_connected;
-static jfieldID pdsi_connectedAddress;
-static jfieldID pdsi_connectedPort;
-
-extern void setDefaultScopeID(JNIEnv *env, struct sockaddr *him);
-extern int getDefaultScopeID(JNIEnv *env);
-
-/*
- * Returns a java.lang.Integer based on 'i'
- */
-static jobject createInteger(JNIEnv *env, int i) {
- static jclass i_class;
- static jmethodID i_ctrID;
-
- if (i_class == NULL) {
- jclass c = (*env)->FindClass(env, "java/lang/Integer");
- CHECK_NULL_RETURN(c, NULL);
- i_ctrID = (*env)->GetMethodID(env, c, "<init>", "(I)V");
- CHECK_NULL_RETURN(i_ctrID, NULL);
- i_class = (*env)->NewGlobalRef(env, c);
- CHECK_NULL_RETURN(i_class, NULL);
- }
-
- return ( (*env)->NewObject(env, i_class, i_ctrID, i) );
-}
-
-/*
- * Returns a java.lang.Boolean based on 'b'
- */
-static jobject createBoolean(JNIEnv *env, int b) {
- static jclass b_class;
- static jmethodID b_ctrID;
-
- if (b_class == NULL) {
- jclass c = (*env)->FindClass(env, "java/lang/Boolean");
- CHECK_NULL_RETURN(c, NULL);
- b_ctrID = (*env)->GetMethodID(env, c, "<init>", "(Z)V");
- CHECK_NULL_RETURN(b_ctrID, NULL);
- b_class = (*env)->NewGlobalRef(env, c);
- CHECK_NULL_RETURN(b_class, NULL);
- }
-
- return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) );
-}
-
-
-/*
- * Returns the fd for a PlainDatagramSocketImpl or -1
- * if closed.
- */
-static int getFD(JNIEnv *env, jobject this) {
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- if (fdObj == NULL) {
- return -1;
- }
- return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
-}
-
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: init
- * Signature: ()V
- */
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) {
-
-#ifdef __linux__
- struct utsname sysinfo;
-#endif
- pdsi_fdID = (*env)->GetFieldID(env, cls, "fd",
- "Ljava/io/FileDescriptor;");
- CHECK_NULL(pdsi_fdID);
- pdsi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
- CHECK_NULL(pdsi_timeoutID);
- pdsi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
- CHECK_NULL(pdsi_trafficClassID);
- pdsi_localPortID = (*env)->GetFieldID(env, cls, "localPort", "I");
- CHECK_NULL(pdsi_localPortID);
- pdsi_connected = (*env)->GetFieldID(env, cls, "connected", "Z");
- CHECK_NULL(pdsi_connected);
- pdsi_connectedAddress = (*env)->GetFieldID(env, cls, "connectedAddress",
- "Ljava/net/InetAddress;");
- CHECK_NULL(pdsi_connectedAddress);
- pdsi_connectedPort = (*env)->GetFieldID(env, cls, "connectedPort", "I");
- CHECK_NULL(pdsi_connectedPort);
-
- IO_fd_fdID = NET_GetFileDescriptorID(env);
- CHECK_NULL(IO_fd_fdID);
-}
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: bind
- * Signature: (ILjava/net/InetAddress;)V
- */
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
- jint localport, jobject iaObj) {
- /* fdObj is the FileDescriptor field on this */
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- /* fd is an int field on fdObj */
- int fd;
- int len = 0;
- SOCKADDR him;
-
- if (IS_NULL(fdObj)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- return;
- } else {
- fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
- }
-
- if (IS_NULL(iaObj)) {
- JNU_ThrowNullPointerException(env, "iaObj is null.");
- return;
- }
-
- /* bind */
- if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
- return;
- }
- setDefaultScopeID(env, (struct sockaddr *)&him);
-
- if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0) {
- if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
- errno == EPERM || errno == EACCES) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
- "Bind failed");
- } else {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Bind failed");
- }
- return;
- }
-
- /* initialize the local port */
- if (localport == 0) {
- /* Now that we're a connected socket, let's extract the port number
- * that the system chose for us and store it in the Socket object.
- */
- if (JVM_GetSockName(fd, (struct sockaddr *)&him, &len) == -1) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Error getting socket name");
- return;
- }
-
- localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
-
- (*env)->SetIntField(env, this, pdsi_localPortID, localport);
- } else {
- (*env)->SetIntField(env, this, pdsi_localPortID, localport);
- }
-}
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: connect0
- * Signature: (Ljava/net/InetAddress;I)V
- */
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,
- jobject address, jint port) {
- /* The object's field */
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- /* The fdObj'fd */
- jint fd;
- /* The packetAddress address, family and port */
- SOCKADDR rmtaddr;
- int len = 0;
-
- if (IS_NULL(fdObj)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- return;
- }
- fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
-
- if (IS_NULL(address)) {
- JNU_ThrowNullPointerException(env, "address");
- return;
- }
-
- if (NET_InetAddressToSockaddr(env, address, port, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
- return;
- }
-
- setDefaultScopeID(env, (struct sockaddr *)&rmtaddr);
- if (JVM_Connect(fd, (struct sockaddr *)&rmtaddr, len) == -1) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
- "Connect failed");
- return;
- }
-
-}
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: disconnect0
- * Signature: ()V
- */
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
- /* The object's field */
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- /* The fdObj'fd */
- jint fd;
-
-#if defined(__linux__) || defined(_ALLBSD_SOURCE)
- SOCKADDR addr;
- int len;
-#endif
-
- if (IS_NULL(fdObj)) {
- return;
- }
- fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
-
-#if defined(__linux__) || defined(_ALLBSD_SOURCE)
- memset(&addr, 0, sizeof(addr));
-#ifdef AF_INET6
- if (ipv6_available()) {
- struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)&addr;
- him6->sin6_family = AF_UNSPEC;
- len = sizeof(struct sockaddr_in6);
- } else
-#endif
- {
- struct sockaddr_in *him4 = (struct sockaddr_in*)&addr;
- him4->sin_family = AF_UNSPEC;
- len = sizeof(struct sockaddr_in);
- }
- JVM_Connect(fd, (struct sockaddr *)&addr, len);
-
-#ifdef __linux__
- int localPort = 0;
- if (JVM_GetSockName(fd, (struct sockaddr *)&addr, &len) == -1)
- return;
- localPort = NET_GetPortFromSockaddr((struct sockaddr *)&addr);
- if (localPort == 0) {
- localPort = (*env)->GetIntField(env, this, pdsi_localPortID);
-#ifdef AF_INET6
- if (((struct sockaddr*)&addr)->sa_family == AF_INET6) {
- ((struct sockaddr_in6*)&addr)->sin6_port = htons(localPort);
- } else
-#endif /* AF_INET6 */
- {
- ((struct sockaddr_in*)&addr)->sin_port = htons(localPort);
- }
- NET_Bind(fd, (struct sockaddr *)&addr, len);
- }
-#endif
-#else
- JVM_Connect(fd, 0, 0);
-#endif
-}
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: send
- * Signature: (Ljava/net/DatagramPacket;)V
- */
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_send(JNIEnv *env, jobject this,
- jobject packet) {
-
- char BUF[MAX_BUFFER_LEN];
- char *fullPacket = NULL;
- int ret, mallocedPacket = JNI_FALSE;
- /* The object's field */
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- jint trafficClass = (*env)->GetIntField(env, this, pdsi_trafficClassID);
-
- jbyteArray packetBuffer;
- jobject packetAddress;
- jint packetBufferOffset, packetBufferLen, packetPort;
- jboolean connected;
-
- /* The fdObj'fd */
- jint fd;
-
- SOCKADDR rmtaddr, *rmtaddrP=&rmtaddr;
- int len;
-
- if (IS_NULL(fdObj)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- return;
- }
- fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
-
- if (IS_NULL(packet)) {
- JNU_ThrowNullPointerException(env, "packet");
- return;
- }
-
- connected = (*env)->GetBooleanField(env, this, pdsi_connected);
-
- packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
- packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
- if (IS_NULL(packetBuffer) || IS_NULL(packetAddress)) {
- JNU_ThrowNullPointerException(env, "null buffer || null address");
- return;
- }
-
- packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
- packetBufferLen = (*env)->GetIntField(env, packet, dp_lengthID);
-
- if (connected) {
- /* arg to NET_Sendto () null in this case */
- len = 0;
- rmtaddrP = 0;
- } else {
- packetPort = (*env)->GetIntField(env, packet, dp_portID);
- if (NET_InetAddressToSockaddr(env, packetAddress, packetPort, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
- return;
- }
- }
- setDefaultScopeID(env, (struct sockaddr *)&rmtaddr);
-
- if (packetBufferLen > MAX_BUFFER_LEN) {
- /* When JNI-ifying the JDK's IO routines, we turned
- * reads and writes of byte arrays of size greater
- * than 2048 bytes into several operations of size 2048.
- * This saves a malloc()/memcpy()/free() for big
- * buffers. This is OK for file IO and TCP, but that
- * strategy violates the semantics of a datagram protocol.
- * (one big send) != (several smaller sends). So here
- * we *must* allocate the buffer. Note it needn't be bigger
- * than 65,536 (0xFFFF), the max size of an IP packet.
- * Anything bigger should be truncated anyway.
- *
- * We may want to use a smarter allocation scheme at some
- * point.
- */
- if (packetBufferLen > MAX_PACKET_LEN) {
- packetBufferLen = MAX_PACKET_LEN;
- }
- fullPacket = (char *)malloc(packetBufferLen);
-
- if (!fullPacket) {
- JNU_ThrowOutOfMemoryError(env, "Send buffer native heap allocation failed");
- return;
- } else {
- mallocedPacket = JNI_TRUE;
- }
- } else {
- fullPacket = &(BUF[0]);
- }
-
- (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen,
- (jbyte *)fullPacket);
-#ifdef AF_INET6
- if (trafficClass != 0 && ipv6_available()) {
- NET_SetTrafficClass((struct sockaddr *)&rmtaddr, trafficClass);
- }
-#endif /* AF_INET6 */
-
-
- /*
- * Send the datagram.
- *
- * If we are connected it's possible that sendto will return
- * ECONNREFUSED indicating that an ICMP port unreachable has
- * received.
- */
- ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0,
- (struct sockaddr *)rmtaddrP, len);
-
- if (ret < 0) {
- switch (ret) {
- case JVM_IO_ERR :
- if (errno == ECONNREFUSED) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
- "ICMP Port Unreachable");
- } else {
- NET_ThrowByNameWithLastError(env, "java/io/IOException", "sendto failed");
- }
- break;
-
- case JVM_IO_INTR:
- JNU_ThrowByName(env, "java/io/InterruptedIOException",
- "operation interrupted");
- break;
- }
- }
-
- if (mallocedPacket) {
- free(fullPacket);
- }
- return;
-}
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: peek
- * Signature: (Ljava/net/InetAddress;)I
- */
-JNIEXPORT jint JNICALL
-PlainDatagramSocketImpl_peek(JNIEnv *env, jobject this,
- jobject addressObj) {
-
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
- jint fd;
- ssize_t n;
- SOCKADDR remote_addr;
- int len;
- char buf[1];
- jint family;
- jobject iaObj;
- int port;
- if (IS_NULL(fdObj)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
- return -1;
- } else {
- fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
- }
- if (IS_NULL(addressObj)) {
- JNU_ThrowNullPointerException(env, "Null address in peek()");
- return -1;
- }
- if (timeout) {
- int ret = NET_Timeout(fd, timeout);
- if (ret == 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
- "Peek timed out");
- return ret;
- } else if (ret == JVM_IO_ERR) {
- if (errno == EBADF) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
- } else {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
- }
- return ret;
- } else if (ret == JVM_IO_INTR) {
- JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
- "operation interrupted");
- return ret; /* WARNING: SHOULD WE REALLY RETURN -2??? */
- }
- }
-
- len = SOCKADDR_LEN;
- n = NET_RecvFrom(fd, buf, 1, MSG_PEEK,
- (struct sockaddr *)&remote_addr, &len);
-
- if (n == JVM_IO_ERR) {
-
-#ifdef __solaris__
- if (errno == ECONNREFUSED) {
- int orig_errno = errno;
- (void) recv(fd, buf, 1, 0);
- errno = orig_errno;
- }
-#endif
- if (errno == ECONNREFUSED) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
- "ICMP Port Unreachable");
- } else {
- if (errno == EBADF) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
- } else {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
- }
- }
- return 0;
- } else if (n == JVM_IO_INTR) {
- JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
- return 0;
- }
-
- iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
-#ifdef AF_INET6
- family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
-#else
- family = AF_INET;
-#endif
- if (family == AF_INET) { /* this API can't handle IPV6 addresses */
- int address = getInetAddress_addr(env, iaObj);
- setInetAddress_addr(env, addressObj, address);
- }
- return port;
-}
-
-JNIEXPORT jint JNICALL
-PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
- jobject packet) {
-
- char BUF[MAX_BUFFER_LEN];
- char *fullPacket = NULL;
- int mallocedPacket = JNI_FALSE;
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
-
- jbyteArray packetBuffer;
- jint packetBufferOffset, packetBufferLen;
-
- int fd;
-
- int n;
- SOCKADDR remote_addr;
- int len;
- int port;
-
- if (IS_NULL(fdObj)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- return -1;
- }
-
- fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
-
- if (IS_NULL(packet)) {
- JNU_ThrowNullPointerException(env, "packet");
- return -1;
- }
-
- packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
- if (IS_NULL(packetBuffer)) {
- JNU_ThrowNullPointerException(env, "packet buffer");
- return -1;
- }
- packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
- packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
- if (timeout) {
- int ret = NET_Timeout(fd, timeout);
- if (ret == 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
- "Receive timed out");
- return -1;
- } else if (ret == JVM_IO_ERR) {
-#ifdef __linux__
- if (errno == EBADF) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
- } else {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
- }
-#else
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
-#endif
- return -1;
- } else if (ret == JVM_IO_INTR) {
- JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
- "operation interrupted");
- return -1;
- }
- }
-
- if (packetBufferLen > MAX_BUFFER_LEN) {
-
- /* When JNI-ifying the JDK's IO routines, we turned
- * reads and writes of byte arrays of size greater
- * than 2048 bytes into several operations of size 2048.
- * This saves a malloc()/memcpy()/free() for big
- * buffers. This is OK for file IO and TCP, but that
- * strategy violates the semantics of a datagram protocol.
- * (one big send) != (several smaller sends). So here
- * we *must* allocate the buffer. Note it needn't be bigger
- * than 65,536 (0xFFFF), the max size of an IP packet.
- * anything bigger is truncated anyway.
- *
- * We may want to use a smarter allocation scheme at some
- * point.
- */
- if (packetBufferLen > MAX_PACKET_LEN) {
- packetBufferLen = MAX_PACKET_LEN;
- }
- fullPacket = (char *)malloc(packetBufferLen);
-
- if (!fullPacket) {
- JNU_ThrowOutOfMemoryError(env, "Peek buffer native heap allocation failed");
- return -1;
- } else {
- mallocedPacket = JNI_TRUE;
- }
- } else {
- fullPacket = &(BUF[0]);
- }
-
- len = SOCKADDR_LEN;
- n = NET_RecvFrom(fd, fullPacket, packetBufferLen, MSG_PEEK,
- (struct sockaddr *)&remote_addr, &len);
- /* truncate the data if the packet's length is too small */
- if (n > packetBufferLen) {
- n = packetBufferLen;
- }
- if (n == JVM_IO_ERR) {
-
-#ifdef __solaris__
- if (errno == ECONNREFUSED) {
- int orig_errno = errno;
- (void) recv(fd, fullPacket, 1, 0);
- errno = orig_errno;
- }
-#endif
- (*env)->SetIntField(env, packet, dp_offsetID, 0);
- (*env)->SetIntField(env, packet, dp_lengthID, 0);
- if (errno == ECONNREFUSED) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
- "ICMP Port Unreachable");
- } else {
- if (errno == EBADF) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
- } else {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
- }
- }
- } else if (n == JVM_IO_INTR) {
- (*env)->SetIntField(env, packet, dp_offsetID, 0);
- (*env)->SetIntField(env, packet, dp_lengthID, 0);
- JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
- "operation interrupted");
- } else {
- /*
- * success - fill in received address...
- *
- * REMIND: Fill in an int on the packet, and create inetadd
- * object in Java, as a performance improvement. Also
- * construct the inetadd object lazily.
- */
-
- jobject packetAddress;
-
- /*
- * Check if there is an InetAddress already associated with this
- * packet. If so we check if it is the same source address. We
- * can't update any existing InetAddress because it is immutable
- */
- packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
- if (packetAddress != NULL) {
- if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
- /* force a new InetAddress to be created */
- packetAddress = NULL;
- }
- }
- if (packetAddress == NULL) {
- packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
- /* stuff the new Inetaddress in the packet */
- (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
- } else {
- /* only get the new port number */
- port = NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr);
- }
- /* and fill in the data, remote address/port and such */
- (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
- (jbyte *)fullPacket);
- (*env)->SetIntField(env, packet, dp_portID, port);
- (*env)->SetIntField(env, packet, dp_lengthID, n);
- }
-
- if (mallocedPacket) {
- free(fullPacket);
- }
- return port;
-}
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: receive
- * Signature: (Ljava/net/DatagramPacket;)V
- */
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this,
- jobject packet) {
-
- char BUF[MAX_BUFFER_LEN];
- char *fullPacket = NULL;
- int mallocedPacket = JNI_FALSE;
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
-
- jbyteArray packetBuffer;
- jint packetBufferOffset, packetBufferLen;
-
- int fd;
-
- int n;
- SOCKADDR remote_addr;
- int len;
- jboolean retry;
-#ifdef __linux__
- jboolean connected = JNI_FALSE;
- jobject connectedAddress = NULL;
- jint connectedPort = 0;
- jlong prevTime = 0;
-#endif
-
- if (IS_NULL(fdObj)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- return;
- }
-
- fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
-
- if (IS_NULL(packet)) {
- JNU_ThrowNullPointerException(env, "packet");
- return;
- }
-
- packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
- if (IS_NULL(packetBuffer)) {
- JNU_ThrowNullPointerException(env, "packet buffer");
- return;
- }
- packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
- packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
-
- if (packetBufferLen > MAX_BUFFER_LEN) {
-
- /* When JNI-ifying the JDK's IO routines, we turned
- * reads and writes of byte arrays of size greater
- * than 2048 bytes into several operations of size 2048.
- * This saves a malloc()/memcpy()/free() for big
- * buffers. This is OK for file IO and TCP, but that
- * strategy violates the semantics of a datagram protocol.
- * (one big send) != (several smaller sends). So here
- * we *must* allocate the buffer. Note it needn't be bigger
- * than 65,536 (0xFFFF), the max size of an IP packet.
- * anything bigger is truncated anyway.
- *
- * We may want to use a smarter allocation scheme at some
- * point.
- */
- if (packetBufferLen > MAX_PACKET_LEN) {
- packetBufferLen = MAX_PACKET_LEN;
- }
- fullPacket = (char *)malloc(packetBufferLen);
-
- if (!fullPacket) {
- JNU_ThrowOutOfMemoryError(env, "Receive buffer native heap allocation failed");
- return;
- } else {
- mallocedPacket = JNI_TRUE;
- }
- } else {
- fullPacket = &(BUF[0]);
- }
-
-
- do {
- retry = JNI_FALSE;
-
- if (timeout) {
- int ret = NET_Timeout(fd, timeout);
- if (ret <= 0) {
- if (ret == 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
- "Receive timed out");
- } else if (ret == JVM_IO_ERR) {
-#ifdef __linux__
- if (errno == EBADF) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
- } else {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
- }
-#else
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
-#endif
- } else if (ret == JVM_IO_INTR) {
- JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
- "operation interrupted");
- }
-
- if (mallocedPacket) {
- free(fullPacket);
- }
-
- return;
- }
- }
-
- len = SOCKADDR_LEN;
- n = NET_RecvFrom(fd, fullPacket, packetBufferLen, 0,
- (struct sockaddr *)&remote_addr, &len);
- /* truncate the data if the packet's length is too small */
- if (n > packetBufferLen) {
- n = packetBufferLen;
- }
- if (n == JVM_IO_ERR) {
- (*env)->SetIntField(env, packet, dp_offsetID, 0);
- (*env)->SetIntField(env, packet, dp_lengthID, 0);
- if (errno == ECONNREFUSED) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
- "ICMP Port Unreachable");
- } else {
- if (errno == EBADF) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
- } else {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
- }
- }
- } else if (n == JVM_IO_INTR) {
- (*env)->SetIntField(env, packet, dp_offsetID, 0);
- (*env)->SetIntField(env, packet, dp_lengthID, 0);
- JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
- "operation interrupted");
- } else {
- int port;
- jobject packetAddress;
-
- /*
- * success - fill in received address...
- *
- * REMIND: Fill in an int on the packet, and create inetadd
- * object in Java, as a performance improvement. Also
- * construct the inetadd object lazily.
- */
-
- /*
- * Check if there is an InetAddress already associated with this
- * packet. If so we check if it is the same source address. We
- * can't update any existing InetAddress because it is immutable
- */
- packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
- if (packetAddress != NULL) {
- if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
- /* force a new InetAddress to be created */
- packetAddress = NULL;
- }
- }
- if (packetAddress == NULL) {
- packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
- /* stuff the new Inetaddress in the packet */
- (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
- } else {
- /* only get the new port number */
- port = NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr);
- }
- /* and fill in the data, remote address/port and such */
- (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
- (jbyte *)fullPacket);
- (*env)->SetIntField(env, packet, dp_portID, port);
- (*env)->SetIntField(env, packet, dp_lengthID, n);
- }
-
- } while (retry);
-
- if (mallocedPacket) {
- free(fullPacket);
- }
-}
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: datagramSocketCreate
- * Signature: ()V
- */
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
- jobject this) {
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- int arg, fd, t = 1;
-#ifdef AF_INET6
- int domain = ipv6_available() ? AF_INET6 : AF_INET;
-#else
- int domain = AF_INET;
-#endif
-
- if (IS_NULL(fdObj)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- return;
- }
-
- if ((fd = JVM_Socket(domain, SOCK_DGRAM, 0)) == JVM_IO_ERR) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Error creating socket");
- return;
- }
- tagSocket(env, fd);
-
-#ifdef AF_INET6
- /* Disable IPV6_V6ONLY to ensure dual-socket support */
- if (domain == AF_INET6) {
- arg = 0;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
- sizeof(int)) < 0) {
- NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
- untagSocket(env, fd);
- close(fd);
- return;
- }
- }
-#endif /* AF_INET6 */
-
-#ifdef __APPLE__
- arg = 65507;
- if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_SNDBUF,
- (char *)&arg, sizeof(arg)) < 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- strerror(errno));
- return;
- }
- if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_RCVBUF,
- (char *)&arg, sizeof(arg)) < 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- strerror(errno));
- return;
- }
-#endif /* __APPLE__ */
-
- setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int));
-
-#if defined(__linux__)
- arg = 0;
- int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;
- if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&
- (errno != ENOPROTOOPT)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- strerror(errno));
- close(fd);
- return;
- }
-#endif
-
-#if defined (__linux__) && defined (AF_INET6)
- /*
- * On Linux for IPv6 sockets we must set the hop limit
- * to 1 to be compatible with default TTL of 1 for IPv4 sockets.
- */
- if (domain == AF_INET6) {
- int ttl = 1;
- setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ttl,
- sizeof(ttl));
- }
-#endif /* __linux__ */
-
- (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
-}
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: datagramSocketClose
- * Signature: ()V
- */
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_datagramSocketClose(JNIEnv *env,
- jobject this) {
- /*
- * REMIND: PUT A LOCK AROUND THIS CODE
- */
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- int fd;
-
- if (IS_NULL(fdObj)) {
- return;
- }
- fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
- if (fd == -1) {
- return;
- }
- (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
- untagSocket(env, fd);
- NET_SocketClose(fd);
-}
-
-
-/*
- * Set outgoing multicast interface designated by a NetworkInterface index.
- * Throw exception if failed.
- *
- * Android changed: return 0 on success, negative on failure.
- * Android changed: Interface index (not NetworkInterface) as the parameter
- */
-static int mcast_set_if_by_if_v4(JNIEnv *env, jobject this, int fd, jint ifindex) {
- struct ip_mreqn req;
- memset(&req, 0, sizeof(req));
- req.imr_ifindex = ifindex;
-
- if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
- (const char*)&req, sizeof(req)) < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Error setting socket option");
- return -1;
- }
-
- return 0;
-}
-
-/*
- * Set outgoing multicast interface designated by a NetworkInterface.
- * Throw exception if failed.
- * Android changed: Interface index (not NetworkInterface) as the parameter
- */
-static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jint ifindex) {
- if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
- (const char*)&ifindex, sizeof(ifindex)) < 0) {
- if (errno == EINVAL && ifindex > 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "IPV6_MULTICAST_IF failed (interface has IPv4 "
- "address only?)");
- } else {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Error setting socket option");
- }
- return;
- }
-}
-
-/*
- * Set outgoing multicast interface designated by an InetAddress.
- * Throw exception if failed.
- *
- * Android-changed : Return type, return 0 on success, negative on failure.
- */
-static int mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject value) {
- struct in_addr in;
-
- in.s_addr = htonl( getInetAddress_addr(env, value) );
-
- if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
- (const char*)&in, sizeof(in)) < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Error setting socket option");
- return -1;
- }
-
- return 0;
-}
-
-/*
- * Set outgoing multicast interface designated by an InetAddress.
- * Throw exception if failed.
- */
-static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject value) {
- static jclass ni_class;
- static jmethodID ni_getByInetAddress;
- static jmethodID ni_getIndex;
- if (ni_class == NULL) {
- jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
- CHECK_NULL(c);
- ni_class = (*env)->NewGlobalRef(env, c);
- CHECK_NULL(ni_class);
- ni_getByInetAddress = (*env)->GetStaticMethodID(
- env, ni_class, "getByInetAddress", "(Ljava/net/InetAddress;)Ljava/net/NetworkInterface;");
- CHECK_NULL(ni_getByInetAddress);
- ni_getIndex = (*env)->GetMethodID(
- env, ni_class, "getIndex", "()I");
- CHECK_NULL(ni_getIndex);
- }
-
- /*
- * Get the NetworkInterface by inetAddress
- */
- jobject ni_value = (*env)->CallStaticObjectMethod(
- env, ni_class, ni_getByInetAddress, value);
- if (ni_value == NULL) {
- if (!(*env)->ExceptionOccurred(env)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "bad argument for IP_MULTICAST_IF"
- ": address not bound to any interface");
- }
- return;
- }
-
- /*
- * Get the NetworkInterface index
- */
- jint ifindex = (*env)->CallIntMethod(env, ni_value, ni_getIndex);
- if ((*env)->ExceptionOccurred(env)) {
- return;
- }
-
- mcast_set_if_by_if_v6(env, this, fd, ifindex);
-}
-
-/*
- * Sets the multicast interface.
- *
- * SocketOptions.IP_MULTICAST_IF :-
- * value is a InetAddress
- * IPv4: set outgoing multicast interface using
- * IPPROTO_IP/IP_MULTICAST_IF
- * IPv6: Get the index of the interface to which the
- * InetAddress is bound
- * Set outgoing multicast interface using
- * IPPROTO_IPV6/IPV6_MULTICAST_IF
- *
- * SockOptions.IF_MULTICAST_IF2 :-
- * value is a NetworkInterface
- * IPv4: Obtain IP address bound to network interface
- * (NetworkInterface.addres[0])
- * set outgoing multicast interface using
- * IPPROTO_IP/IP_MULTICAST_IF
- * IPv6: Obtain NetworkInterface.index
- * Set outgoing multicast interface using
- * IPPROTO_IPV6/IPV6_MULTICAST_IF
- *
- */
-static void setMulticastInterface(JNIEnv *env, jobject this, int fd,
- jint opt, jobject value)
-{
- if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
- /*
- * value is an InetAddress.
- */
- // Android-changed: Return early if mcast_set_if_by_addr_v4 threw.
- // We don't want to call into the IPV6 code with a pending exception.
- if (mcast_set_if_by_addr_v4(env, this, fd, value)) {
- return;
- }
- if (ipv6_available()) {
- mcast_set_if_by_addr_v6(env, this, fd, value);
- }
- }
-
- if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
- /*
- * value is a Integer (Android-changed, openJdk uses NetworkInterface)
- */
- static jfieldID integer_valueID;
- if (integer_valueID == NULL) {
- jclass c = (*env)->FindClass(env, "java/lang/Integer");
- CHECK_NULL(c);
- integer_valueID = (*env)->GetFieldID(env, c, "value", "I");
- CHECK_NULL(integer_valueID);
- }
- int index = (*env)->GetIntField(env, value, integer_valueID);
-
- // Android-changed: Return early if mcast_set_if_by_addr_v4 threw.
- // We don't want to call into the IPV6 code with a pending exception.
- if (mcast_set_if_by_if_v4(env, this, fd, index)) {
- return;
- }
- if (ipv6_available()) {
- mcast_set_if_by_if_v6(env, this, fd, index);
- }
- }
-}
-
-/*
- * Enable/disable local loopback of multicast datagrams.
- */
-static void mcast_set_loop_v4(JNIEnv *env, jobject this, int fd, jobject value) {
- jclass cls;
- jfieldID fid;
- jboolean on;
- char loopback;
-
- cls = (*env)->FindClass(env, "java/lang/Boolean");
- CHECK_NULL(cls);
- fid = (*env)->GetFieldID(env, cls, "value", "Z");
- CHECK_NULL(fid);
-
- on = (*env)->GetBooleanField(env, value, fid);
- loopback = (!on ? 1 : 0);
-
- if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&loopback, sizeof(char)) < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
- return;
- }
-}
-
-/*
- * Enable/disable local loopback of multicast datagrams.
- */
-#ifdef AF_INET6
-static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject value) {
- jclass cls;
- jfieldID fid;
- jboolean on;
- int loopback;
-
- cls = (*env)->FindClass(env, "java/lang/Boolean");
- CHECK_NULL(cls);
- fid = (*env)->GetFieldID(env, cls, "value", "Z");
- CHECK_NULL(fid);
-
- on = (*env)->GetBooleanField(env, value, fid);
- loopback = (!on ? 1 : 0);
-
- if (NET_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&loopback, sizeof(int)) < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
- return;
- }
-
-}
-#endif /* AF_INET6 */
-
-/*
- * Sets the multicast loopback mode.
- */
-static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd,
- jint opt, jobject value) {
-#ifdef AF_INET6
-#ifdef __linux__
- mcast_set_loop_v4(env, this, fd, value);
- if (ipv6_available()) {
- mcast_set_loop_v6(env, this, fd, value);
- }
-#else /* __linux__ not defined */
- if (ipv6_available()) {
- mcast_set_loop_v6(env, this, fd, value);
- } else {
- mcast_set_loop_v4(env, this, fd, value);
- }
-#endif /* __linux__ */
-#else
- mcast_set_loop_v4(env, this, fd, value);
-#endif /* AF_INET6 */
-}
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: socketSetOption0
- * Signature: (ILjava/lang/Object;)V
- */
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_socketSetOption0(JNIEnv *env,
- jobject this,
- jint opt,
- jobject value) {
- int fd;
- int level, optname, optlen;
- union {
- int i;
- char c;
- } optval;
-
- /*
- * Check that socket hasn't been closed
- */
- fd = getFD(env, this);
- if (fd < 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- return;
- }
-
- /*
- * Check argument has been provided
- */
- if (IS_NULL(value)) {
- JNU_ThrowNullPointerException(env, "value argument");
- return;
- }
-
- /*
- * Setting the multicast interface handled seperately
- */
- if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
- opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
-
- setMulticastInterface(env, this, fd, opt, value);
- return;
- }
-
- /*
- * Setting the multicast loopback mode handled separately
- */
- if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
- setMulticastLoopbackMode(env, this, fd, opt, value);
- return;
- }
-
- /*
- * Map the Java level socket option to the platform specific
- * level and option name.
- */
- if (NET_MapSocketOption(opt, &level, &optname)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
- return;
- }
-
- switch (opt) {
- case java_net_SocketOptions_SO_SNDBUF :
- case java_net_SocketOptions_SO_RCVBUF :
- case java_net_SocketOptions_IP_TOS :
- {
- jclass cls;
- jfieldID fid;
-
- cls = (*env)->FindClass(env, "java/lang/Integer");
- CHECK_NULL(cls);
- fid = (*env)->GetFieldID(env, cls, "value", "I");
- CHECK_NULL(fid);
-
- optval.i = (*env)->GetIntField(env, value, fid);
- optlen = sizeof(optval.i);
- break;
- }
-
- case java_net_SocketOptions_SO_REUSEADDR:
- case java_net_SocketOptions_SO_BROADCAST:
- {
- jclass cls;
- jfieldID fid;
- jboolean on;
-
- cls = (*env)->FindClass(env, "java/lang/Boolean");
- CHECK_NULL(cls);
- fid = (*env)->GetFieldID(env, cls, "value", "Z");
- CHECK_NULL(fid);
-
- on = (*env)->GetBooleanField(env, value, fid);
-
- /* SO_REUSEADDR or SO_BROADCAST */
- optval.i = (on ? 1 : 0);
- optlen = sizeof(optval.i);
-
- break;
- }
-
- default :
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket option not supported by PlainDatagramSocketImp");
- return;
-
- }
-
- if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
- return;
- }
-}
-
-
-/*
- * Return the multicast interface:
- *
- * SocketOptions.IP_MULTICAST_IF
- * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
- * Create InetAddress
- * IP_MULTICAST_IF returns struct ip_mreqn on 2.2
- * kernel but struct in_addr on 2.4 kernel
- * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
- * If index == 0 return InetAddress representing
- * anyLocalAddress.
- * If index > 0 query NetworkInterface by index
- * and returns addrs[0]
- *
- * SocketOptions.IP_MULTICAST_IF2
- * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
- * Query NetworkInterface by IP address and
- * return the NetworkInterface that the address
- * is bound too.
- * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
- * (except Linux .2 kernel)
- * Query NetworkInterface by index and
- * return NetworkInterface.
- */
-jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) {
- if ((opt == java_net_SocketOptions_IP_MULTICAST_IF2) ||
- (opt == java_net_SocketOptions_IP_MULTICAST_IF)) {
- int index;
- int len = sizeof(index);
-
- if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
- (char*)&index, &len) < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Error getting socket option");
- return NULL;
- }
-
- jobject ifindex = createInteger(env, index);
- CHECK_NULL_RETURN(ifindex, NULL);
- return ifindex;
- }
- return NULL;
-}
-
-
-
-/*
- * Returns relevant info as a jint.
- *
- * Class: java_net_PlainDatagramSocketImpl
- * Method: socketGetOption
- * Signature: (I)Ljava/lang/Object;
- */
-JNIEXPORT jobject JNICALL
-PlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobject this,
- jint opt) {
- int fd;
- int level, optname, optlen;
- union {
- int i;
- char c;
- } optval;
-
- fd = getFD(env, this);
- if (fd < 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "socket closed");
- return NULL;
- }
-
- /*
- * Handle IP_MULTICAST_IF separately
- */
- if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
- opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
- return getMulticastInterface(env, this, fd, opt);
-
- }
-
- /*
- * SO_BINDADDR implemented using getsockname
- */
- if (opt == java_net_SocketOptions_SO_BINDADDR) {
- /* find out local IP address */
- SOCKADDR him;
- socklen_t len = 0;
- int port;
- jobject iaObj;
-
- len = SOCKADDR_LEN;
-
- if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Error getting socket name");
- return NULL;
- }
- iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
-
- return iaObj;
- }
-
- /*
- * Map the Java level socket option to the platform specific
- * level and option name.
- */
- if (NET_MapSocketOption(opt, &level, &optname)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
- return NULL;
- }
-
- if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP &&
- level == IPPROTO_IP) {
- optlen = sizeof(optval.c);
- } else {
- optlen = sizeof(optval.i);
- }
-
- if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Error getting socket option");
- return NULL;
- }
-
- switch (opt) {
- case java_net_SocketOptions_IP_MULTICAST_LOOP:
- /* getLoopbackMode() returns true if IP_MULTICAST_LOOP disabled */
- if (level == IPPROTO_IP) {
- return createBoolean(env, (int)!optval.c);
- } else {
- return createBoolean(env, !optval.i);
- }
-
- case java_net_SocketOptions_SO_BROADCAST:
- case java_net_SocketOptions_SO_REUSEADDR:
- return createBoolean(env, optval.i);
-
- case java_net_SocketOptions_SO_SNDBUF:
- case java_net_SocketOptions_SO_RCVBUF:
- case java_net_SocketOptions_IP_TOS:
- return createInteger(env, optval.i);
-
- }
-
- /* should never reach here */
- return NULL;
-}
-
-/*
- * Multicast-related calls
- */
-
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
- jbyte ttl) {
- jint ittl = ttl;
- if (ittl < 0) {
- ittl += 0x100;
- }
- PlainDatagramSocketImpl_setTimeToLive(env, this, ittl);
-}
-
-/*
- * Set TTL for a socket. Throw exception if failed.
- */
-static void setTTL(JNIEnv *env, int fd, jint ttl) {
- char ittl = (char)ttl;
- if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
- sizeof(ittl)) < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Error setting socket option");
- }
-}
-
-/*
- * Set hops limit for a socket. Throw exception if failed.
- */
-#ifdef AF_INET6
-static void setHopLimit(JNIEnv *env, int fd, jint ttl) {
- int ittl = (int)ttl;
- if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
- (char*)&ittl, sizeof(ittl)) < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Error setting socket option");
- }
-}
-#endif
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: setTTL
- * Signature: (B)V
- */
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
- jint ttl) {
-
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- int fd;
- /* it is important to cast this to a char, otherwise setsockopt gets confused */
-
- if (IS_NULL(fdObj)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- return;
- } else {
- fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
- }
- /* setsockopt to be correct TTL */
-#ifdef AF_INET6
-#ifdef __linux__
- setTTL(env, fd, ttl);
- if ((*env)->ExceptionCheck(env)) {
- return;
- }
- if (ipv6_available()) {
- setHopLimit(env, fd, ttl);
- }
-#else /* __linux__ not defined */
- if (ipv6_available()) {
- setHopLimit(env, fd, ttl);
- } else {
- setTTL(env, fd, ttl);
- }
-#endif /* __linux__ */
-#else
- setTTL(env, fd, ttl);
-#endif /* AF_INET6 */
-}
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: getTTL
- * Signature: ()B
- */
-JNIEXPORT jbyte JNICALL
-PlainDatagramSocketImpl_getTTL(JNIEnv *env, jobject this) {
- return (jbyte)PlainDatagramSocketImpl_getTimeToLive(env, this);
-}
-
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: getTTL
- * Signature: ()B
- */
-JNIEXPORT jint JNICALL
-PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
-
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- jint fd = -1;
-
- if (IS_NULL(fdObj)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- return -1;
- } else {
- fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
- }
- /* getsockopt of TTL */
-#ifdef AF_INET6
- if (ipv6_available()) {
- int ttl = 0;
- int len = sizeof(ttl);
-
- if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
- (char*)&ttl, &len) < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Error getting socket option");
- return -1;
- }
- return (jint)ttl;
- } else
-#endif /* AF_INET6 */
- {
- u_char ttl = 0;
- int len = sizeof(ttl);
- if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
- (char*)&ttl, &len) < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
- "Error getting socket option");
- return -1;
- }
- return (jint)ttl;
- }
-}
-
-
-/*
- * mcast_join_leave: Join or leave a multicast group.
- *
- * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
- * to join/leave multicast group.
- *
- * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
- * to join/leave multicast group. If multicast group is an IPv4 address then
- * an IPv4-mapped address is used.
- *
- * On Linux with IPv6 if we wish to join/leave an IPv4 multicast group then
- * we must use the IPv4 socket options. This is because the IPv6 socket options
- * don't support IPv4-mapped addresses. This is true as per 2.2.19 and 2.4.7
- * kernel releases. In the future it's possible that IP_ADD_MEMBERSHIP
- * will be updated to return ENOPROTOOPT if uses with an IPv6 socket (Solaris
- * already does this). Thus to cater for this we first try with the IPv4
- * socket options and if they fail we use the IPv6 socket options. This
- * seems a reasonable failsafe solution.
- */
-static void mcast_join_leave(JNIEnv *env, jobject this,
- jobject iaObj, jobject niObj,
- jboolean join) {
-
- jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- jint fd;
- jint ipv6_join_leave;
-
- if (IS_NULL(fdObj)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- return;
- } else {
- fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
- }
- if (IS_NULL(iaObj)) {
- JNU_ThrowNullPointerException(env, "iaObj");
- return;
- }
-
- /*
- * Get java/net/NetworkInterface#index field.
- */
- static jfieldID ni_indexID;
-
- if (ni_indexID == NULL) {
- jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
- CHECK_NULL(c);
- ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
- CHECK_NULL(ni_indexID);
- }
-
- /*
- * Determine if this is an IPv4 or IPv6 join/leave.
- */
- ipv6_join_leave = ipv6_available();
-
- if (getInetAddress_family(env, iaObj) == IPv4) {
- ipv6_join_leave = JNI_FALSE;
- }
-
- /*
- * For IPv4 join use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
- *
- * On Linux if IPv4 or IPv6 use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP
- */
- if (!ipv6_join_leave) {
- struct ip_mreqn mname;
- int mname_len;
-
- /*
- * joinGroup(InetAddress, NetworkInterface) implementation :-
- *
- * Linux/IPv6: use ip_mreqn structure populated with multicast
- * address and interface index.
- *
- */
- if (niObj != NULL) {
- mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
- mname.imr_address.s_addr = 0;
- mname.imr_ifindex = (*env)->GetIntField(env, niObj, ni_indexID);
- mname_len = sizeof(struct ip_mreqn);
- }
-
-
- /*
- * joinGroup(InetAddress) implementation :-
- *
- * Linux/IPv6: use ip_mreqn structure populated with multicast
- * address and interface index. index obtained
- * from cached value or IPV6_MULTICAST_IF.
- *
- * IPv4: use ip_mreq structure populated with multicast
- * address and local address obtained from
- * IP_MULTICAST_IF. On Linux IP_MULTICAST_IF
- * returns different structure depending on
- * kernel.
- */
-
- if (niObj == NULL) {
- int index;
- int len = sizeof(index);
-
- if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
- (char*)&index, &len) < 0) {
- NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
- return;
- }
-
- mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
- mname.imr_address.s_addr = 0 ;
- mname.imr_ifindex = index;
- mname_len = sizeof(struct ip_mreqn);
- }
-
-
- /*
- * Join the multicast group.
- */
- if (JVM_SetSockOpt(fd, IPPROTO_IP, (join ? IP_ADD_MEMBERSHIP:IP_DROP_MEMBERSHIP),
- (char *) &mname, mname_len) < 0) {
-
- /*
- * If IP_ADD_MEMBERSHIP returns ENOPROTOOPT on Linux and we've got
- * IPv6 enabled then it's possible that the kernel has been fixed
- * so we switch to IPV6_ADD_MEMBERSHIP socket option.
- * As of 2.4.7 kernel IPV6_ADD_MEMBERSHIP can't handle IPv4-mapped
- * addresses so we have to use IP_ADD_MEMBERSHIP for IPv4 multicast
- * groups. However if the socket is an IPv6 socket then then setsockopt
- * should return ENOPROTOOPT. We assume this will be fixed in Linux
- * at some stage.
- */
- if (errno == ENOPROTOOPT) {
- if (ipv6_available()) {
- ipv6_join_leave = JNI_TRUE;
- errno = 0;
- } else {
- errno = ENOPROTOOPT; /* errno can be changed by ipv6_available */
- }
- }
- if (errno) {
- if (join) {
- NET_ThrowCurrent(env, "setsockopt IP_ADD_MEMBERSHIP failed");
- } else {
- if (errno == ENOENT)
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Not a member of the multicast group");
- else
- NET_ThrowCurrent(env, "setsockopt IP_DROP_MEMBERSHIP failed");
- }
- return;
- }
- }
-
- /*
- * If we haven't switched to IPv6 socket option then we're done.
- */
- if (!ipv6_join_leave) {
- return;
- }
- }
-
-
- /*
- * IPv6 join. If it's an IPv4 multicast group then we use an IPv4-mapped
- * address.
- */
- {
- struct ipv6_mreq mname6;
-
- jbyteArray ipaddress;
- jbyte caddr[16];
- jint family;
- jint address;
- family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
- if (family == AF_INET) { /* will convert to IPv4-mapped address */
- memset((char *) caddr, 0, 16);
- address = getInetAddress_addr(env, iaObj);
-
- caddr[10] = 0xff;
- caddr[11] = 0xff;
-
- caddr[12] = ((address >> 24) & 0xff);
- caddr[13] = ((address >> 16) & 0xff);
- caddr[14] = ((address >> 8) & 0xff);
- caddr[15] = (address & 0xff);
- } else {
- // Android-changed: explicit cast to suppress compiler warning.
- getInet6Address_ipaddress(env, iaObj, (char*)caddr);
- }
-
- memcpy((void *)&(mname6.ipv6mr_multiaddr), caddr, sizeof(struct in6_addr));
- if (IS_NULL(niObj)) {
- int index;
- int len = sizeof(index);
-
- if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
- (char*)&index, &len) < 0) {
- NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
- return;
- }
-
- mname6.ipv6mr_interface = index;
- } else {
- jint idx = (*env)->GetIntField(env, niObj, ni_indexID);
- mname6.ipv6mr_interface = idx;
- }
-
-#define ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
-#define DRP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
-#define S_ADD_MEMBERSHIP "IPV6_ADD_MEMBERSHIP"
-#define S_DRP_MEMBERSHIP "IPV6_DROP_MEMBERSHIP"
-
- /* Join the multicast group */
- if (JVM_SetSockOpt(fd, IPPROTO_IPV6, (join ? ADD_MEMBERSHIP : DRP_MEMBERSHIP),
- (char *) &mname6, sizeof (mname6)) < 0) {
-
- if (join) {
- NET_ThrowCurrent(env, "setsockopt " S_ADD_MEMBERSHIP " failed");
- } else {
- if (errno == ENOENT) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Not a member of the multicast group");
- } else {
- NET_ThrowCurrent(env, "setsockopt " S_DRP_MEMBERSHIP " failed");
- }
- }
- }
- }
-}
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: join
- * Signature: (Ljava/net/InetAddress;)V
- */
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_join(JNIEnv *env, jobject this,
- jobject iaObj, jobject niObj)
-{
- mcast_join_leave(env, this, iaObj, niObj, JNI_TRUE);
-}
-
-/*
- * Class: java_net_PlainDatagramSocketImpl
- * Method: leave
- * Signature: (Ljava/net/InetAddress;)V
- */
-JNIEXPORT void JNICALL
-PlainDatagramSocketImpl_leave(JNIEnv *env, jobject this,
- jobject iaObj, jobject niObj)
-{
- mcast_join_leave(env, this, iaObj, niObj, JNI_FALSE);
-}
-
-static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(PlainDatagramSocketImpl, leave, "(Ljava/net/InetAddress;Ljava/net/NetworkInterface;)V"),
- NATIVE_METHOD(PlainDatagramSocketImpl, join, "(Ljava/net/InetAddress;Ljava/net/NetworkInterface;)V"),
- NATIVE_METHOD(PlainDatagramSocketImpl, getTimeToLive, "()I"),
- NATIVE_METHOD(PlainDatagramSocketImpl, getTTL, "()B"),
- NATIVE_METHOD(PlainDatagramSocketImpl, setTimeToLive, "(I)V"),
- NATIVE_METHOD(PlainDatagramSocketImpl, setTTL, "(B)V"),
- NATIVE_METHOD(PlainDatagramSocketImpl, socketGetOption, "(I)Ljava/lang/Object;"),
- NATIVE_METHOD(PlainDatagramSocketImpl, socketSetOption0, "(ILjava/lang/Object;)V"),
- NATIVE_METHOD(PlainDatagramSocketImpl, datagramSocketClose, "()V"),
- NATIVE_METHOD(PlainDatagramSocketImpl, datagramSocketCreate, "()V"),
- NATIVE_METHOD(PlainDatagramSocketImpl, receive0, "(Ljava/net/DatagramPacket;)V"),
- NATIVE_METHOD(PlainDatagramSocketImpl, peekData, "(Ljava/net/DatagramPacket;)I"),
- NATIVE_METHOD(PlainDatagramSocketImpl, peek, "(Ljava/net/InetAddress;)I"),
- NATIVE_METHOD(PlainDatagramSocketImpl, send, "(Ljava/net/DatagramPacket;)V"),
- NATIVE_METHOD(PlainDatagramSocketImpl, disconnect0, "(I)V"),
- NATIVE_METHOD(PlainDatagramSocketImpl, connect0, "(Ljava/net/InetAddress;I)V"),
- NATIVE_METHOD(PlainDatagramSocketImpl, bind0, "(ILjava/net/InetAddress;)V"),
- NATIVE_METHOD(PlainDatagramSocketImpl, init, "()V"),
-};
-
-void register_java_net_PlainDatagramSocketImpl(JNIEnv* env) {
- jniRegisterNativeMethods(env, "java/net/PlainDatagramSocketImpl", gMethods, NELEM(gMethods));
-}
diff --git a/ojluni/src/main/native/Register.cpp b/ojluni/src/main/native/Register.cpp
index 8e767f7..42b1a62 100644
--- a/ojluni/src/main/native/Register.cpp
+++ b/ojluni/src/main/native/Register.cpp
@@ -127,8 +127,6 @@
register_java_net_Inet4Address(env);
register_java_net_Inet6Address(env);
register_java_net_PlainSocketImpl(env);
- register_java_net_PlainDatagramSocketImpl(env);
- register_java_net_DatagramPacket(env);
register_java_net_SocketInputStream(env);
register_java_net_SocketOutputStream(env);
register_java_nio_Bits(env);
diff --git a/ojluni/src/main/native/net_util.h b/ojluni/src/main/native/net_util.h
index 4b7310b..839e947 100644
--- a/ojluni/src/main/native/net_util.h
+++ b/ojluni/src/main/native/net_util.h
@@ -93,6 +93,8 @@
extern jfieldID psi_portID;
extern jfieldID psi_localportID;
+/* Android-removed: DatagramSocket moved away from JNI */
+#if 0
/* DatagramPacket fields */
extern jfieldID dp_addressID;
extern jfieldID dp_portID;
@@ -100,6 +102,7 @@
extern jfieldID dp_offsetID;
extern jfieldID dp_lengthID;
extern jfieldID dp_bufLengthID;
+#endif
/* Inet6Address fields */
extern jclass ia6_class;
diff --git a/ojluni/src/main/native/openjdksub.mk b/ojluni/src/main/native/openjdksub.mk
index da03db2..a083a6b 100644
--- a/ojluni/src/main/native/openjdksub.mk
+++ b/ojluni/src/main/native/openjdksub.mk
@@ -52,8 +52,6 @@
Inet4Address.c \
linux_close.cpp \
PlainSocketImpl.c \
- PlainDatagramSocketImpl.c \
- DatagramPacket.c \
ServerSocketChannelImpl.c \
SocketInputStream.c \
SocketOutputStream.c \
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index aed6c1a..a38fa4d 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -1436,36 +1436,10 @@
ojluni/src/main/java/sun/net/www/MeteredStream.java \
ojluni/src/main/java/sun/net/www/ParseUtil.java \
ojluni/src/main/java/sun/net/www/URLConnection.java \
- ojluni/src/main/java/sun/net/www/http/ChunkedInputStream.java \
- ojluni/src/main/java/sun/net/www/http/ChunkedOutputStream.java \
- ojluni/src/main/java/sun/net/www/http/HttpCapture.java \
- ojluni/src/main/java/sun/net/www/http/HttpCaptureInputStream.java \
- ojluni/src/main/java/sun/net/www/http/HttpCaptureOutputStream.java \
- ojluni/src/main/java/sun/net/www/http/HttpClient.java \
- ojluni/src/main/java/sun/net/www/http/Hurryable.java \
- ojluni/src/main/java/sun/net/www/http/KeepAliveCache.java \
- ojluni/src/main/java/sun/net/www/http/KeepAliveStream.java \
- ojluni/src/main/java/sun/net/www/http/KeepAliveStreamCleaner.java \
- ojluni/src/main/java/sun/net/www/http/PosterOutputStream.java \
ojluni/src/main/java/sun/net/www/protocol/file/FileURLConnection.java \
ojluni/src/main/java/sun/net/www/protocol/file/Handler.java \
ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java \
ojluni/src/main/java/sun/net/www/protocol/ftp/Handler.java \
- ojluni/src/main/java/sun/net/www/protocol/http/AuthCache.java \
- ojluni/src/main/java/sun/net/www/protocol/http/AuthCacheImpl.java \
- ojluni/src/main/java/sun/net/www/protocol/http/AuthCacheValue.java \
- ojluni/src/main/java/sun/net/www/protocol/http/AuthScheme.java \
- ojluni/src/main/java/sun/net/www/protocol/http/AuthenticationHeader.java \
- ojluni/src/main/java/sun/net/www/protocol/http/AuthenticationInfo.java \
- ojluni/src/main/java/sun/net/www/protocol/http/BasicAuthentication.java \
- ojluni/src/main/java/sun/net/www/protocol/http/DigestAuthentication.java \
- ojluni/src/main/java/sun/net/www/protocol/http/Handler.java \
- ojluni/src/main/java/sun/net/www/protocol/http/HttpAuthenticator.java \
- ojluni/src/main/java/sun/net/www/protocol/http/HttpCallerInfo.java \
- ojluni/src/main/java/sun/net/www/protocol/http/HttpURLConnection.java \
- ojluni/src/main/java/sun/net/www/protocol/http/NTLMAuthenticationProxy.java \
- ojluni/src/main/java/sun/net/www/protocol/http/NegotiateAuthentication.java \
- ojluni/src/main/java/sun/net/www/protocol/http/Negotiator.java \
ojluni/src/main/java/sun/net/www/protocol/jar/Handler.java \
ojluni/src/main/java/sun/net/www/protocol/jar/JarFileFactory.java \
ojluni/src/main/java/sun/net/www/protocol/jar/JarURLConnection.java \