diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java index 6091a84f2a..73720a96ba 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java @@ -32,6 +32,9 @@ import java.io.OutputStream; import java.io.FileDescriptor; +/* J2ObjC removed +import dalvik.annotation.optimization.ReachabilitySensitive; +*/ import dalvik.system.BlockGuard; import dalvik.system.CloseGuard; import dalvik.system.SocketTagger; @@ -50,8 +53,8 @@ abstract class AbstractPlainSocketImpl extends SocketImpl { /* instance variable for SO_TIMEOUT */ int timeout; // timeout in millisec - // traffic class - int trafficClass; + // Android-removed: traffic class is set through socket. + // private int trafficClass; private boolean shut_rd = false; private boolean shut_wr = false; @@ -237,70 +240,78 @@ public void setOption(int opt, Object val) throws SocketException { if (isClosedOrPending()) { throw new SocketException("Socket Closed"); } + // BEGIN Android-removed: Logic dealing with value type moved to socketSetOption. + /* boolean on = true; switch (opt) { /* check type safety b4 going native. These should never * fail, since only java.Socket* has access to * PlainSocketImpl.setOption(). - */ - case SO_LINGER: - if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean))) - throw new SocketException("Bad parameter for option"); - if (val instanceof Boolean) { - /* true only if disabling - enabling should be Integer */ - on = false; - } - break; - case SO_TIMEOUT: - if (val == null || (!(val instanceof Integer))) - throw new SocketException("Bad parameter for SO_TIMEOUT"); - int tmp = ((Integer) val).intValue(); - if (tmp < 0) - throw new IllegalArgumentException("timeout < 0"); - timeout = tmp; - break; - case IP_TOS: - if (val == null || !(val instanceof Integer)) { - throw new SocketException("bad argument for IP_TOS"); - } - trafficClass = ((Integer)val).intValue(); - break; - case SO_BINDADDR: - throw new SocketException("Cannot re-bind socket"); - case TCP_NODELAY: - if (val == null || !(val instanceof Boolean)) - throw new SocketException("bad parameter for TCP_NODELAY"); - on = ((Boolean)val).booleanValue(); - break; - case SO_SNDBUF: - case SO_RCVBUF: - if (val == null || !(val instanceof Integer) || - !(((Integer)val).intValue() > 0)) { - throw new SocketException("bad parameter for SO_SNDBUF " + - "or SO_RCVBUF"); - } - break; - case SO_KEEPALIVE: - if (val == null || !(val instanceof Boolean)) - throw new SocketException("bad parameter for SO_KEEPALIVE"); - on = ((Boolean)val).booleanValue(); - break; - case SO_OOBINLINE: - if (val == null || !(val instanceof Boolean)) - throw new SocketException("bad parameter for SO_OOBINLINE"); - on = ((Boolean)val).booleanValue(); - break; - case SO_REUSEADDR: - if (val == null || !(val instanceof Boolean)) - throw new SocketException("bad parameter for SO_REUSEADDR"); - on = ((Boolean)val).booleanValue(); - break; - default: - throw new SocketException("unrecognized TCP option: " + opt); + * + case SO_LINGER: + if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean))) + throw new SocketException("Bad parameter for option"); + if (val instanceof Boolean) { + /* true only if disabling - enabling should be Integer * + on = false; + } + break; + case SO_TIMEOUT: + if (val == null || (!(val instanceof Integer))) + throw new SocketException("Bad parameter for SO_TIMEOUT"); + int tmp = ((Integer) val).intValue(); + if (tmp < 0) + throw new IllegalArgumentException("timeout < 0"); + timeout = tmp; + break; + case IP_TOS: + if (val == null || !(val instanceof Integer)) { + throw new SocketException("bad argument for IP_TOS"); + } + trafficClass = ((Integer)val).intValue(); + break; + case SO_BINDADDR: + throw new SocketException("Cannot re-bind socket"); + case TCP_NODELAY: + if (val == null || !(val instanceof Boolean)) + throw new SocketException("bad parameter for TCP_NODELAY"); + on = ((Boolean)val).booleanValue(); + break; + case SO_SNDBUF: + case SO_RCVBUF: + if (val == null || !(val instanceof Integer) || + !(((Integer)val).intValue() > 0)) { + throw new SocketException("bad parameter for SO_SNDBUF " + + "or SO_RCVBUF"); + } + break; + case SO_KEEPALIVE: + if (val == null || !(val instanceof Boolean)) + throw new SocketException("bad parameter for SO_KEEPALIVE"); + on = ((Boolean)val).booleanValue(); + break; + case SO_OOBINLINE: + if (val == null || !(val instanceof Boolean)) + throw new SocketException("bad parameter for SO_OOBINLINE"); + on = ((Boolean)val).booleanValue(); + break; + case SO_REUSEADDR: + if (val == null || !(val instanceof Boolean)) + throw new SocketException("bad parameter for SO_REUSEADDR"); + on = ((Boolean)val).booleanValue(); + break; + default: + throw new SocketException("unrecognized TCP option: " + opt); } socketSetOption(opt, on, val); + */ + // END Android-removed: Logic dealing with value type moved to socketSetOption. + // Android-added: Keep track of timeout value not handled by socketSetOption. + if (opt == SO_TIMEOUT) { + timeout = (Integer) val; + } + socketSetOption(opt, val); } - public Object getOption(int opt) throws SocketException { if (isClosedOrPending()) { throw new SocketException("Socket Closed"); @@ -308,6 +319,8 @@ public Object getOption(int opt) throws SocketException { if (opt == SO_TIMEOUT) { return new Integer(timeout); } + // BEGIN Android-changed: Logic dealing with value type moved to socketGetOption. + /* int ret = 0; /* * The native socketGetOption() knows about 3 options. @@ -315,43 +328,51 @@ public Object getOption(int opt) throws SocketException { * to what we're asking. A return of -1 means it understands * the option but its turned off. It will raise a SocketException * if "opt" isn't one it understands. - */ + * switch (opt) { - case TCP_NODELAY: - ret = socketGetOption(opt, null); - return Boolean.valueOf(ret != -1); - case SO_OOBINLINE: - ret = socketGetOption(opt, null); - return Boolean.valueOf(ret != -1); - case SO_LINGER: - ret = socketGetOption(opt, null); - return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret)); - case SO_REUSEADDR: - ret = socketGetOption(opt, null); - return Boolean.valueOf(ret != -1); - case SO_BINDADDR: - InetAddressContainer in = new InetAddressContainer(); - ret = socketGetOption(opt, in); - return in.addr; - case SO_SNDBUF: - case SO_RCVBUF: - ret = socketGetOption(opt, null); - return new Integer(ret); - case IP_TOS: + case TCP_NODELAY: + ret = socketGetOption(opt, null); + return Boolean.valueOf(ret != -1); + case SO_OOBINLINE: + ret = socketGetOption(opt, null); + return Boolean.valueOf(ret != -1); + case SO_LINGER: + ret = socketGetOption(opt, null); + return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret)); + case SO_REUSEADDR: + ret = socketGetOption(opt, null); + return Boolean.valueOf(ret != -1); + case SO_BINDADDR: + InetAddressContainer in = new InetAddressContainer(); + ret = socketGetOption(opt, in); + return in.addr; + case SO_SNDBUF: + case SO_RCVBUF: + ret = socketGetOption(opt, null); + return new Integer(ret); + case IP_TOS: + try { ret = socketGetOption(opt, null); if (ret == -1) { // ipv6 tos - return new Integer(trafficClass); + return trafficClass; } else { - return new Integer(ret); + return ret; } - case SO_KEEPALIVE: - ret = socketGetOption(opt, null); - return Boolean.valueOf(ret != -1); - // should never get here - default: - return null; + } catch (SocketException se) { + // TODO - should make better effort to read TOS or TCLASS + return trafficClass; // ipv6 tos + } + case SO_KEEPALIVE: + ret = socketGetOption(opt, null); + return Boolean.valueOf(ret != -1); + // should never get here + default: + return null; } + */ + return socketGetOption(opt); + // END Android-changed: Logic dealing with value type moved to socketGetOption. } /** @@ -542,12 +563,44 @@ protected void close() throws IOException { if (!stream) { ResourceManager.afterUdpClose(); } - if (closePending) { - return; + // Android-changed: Socket should be untagged before the preclose. + // After preclose, socket will dup2-ed to marker_fd, therefore, it won't describe + // the same file. If closingPending is true, then the socket has been preclosed. + // + // Also, close the CloseGuard when the #close is called. + if (!closePending) { + closePending = true; + guard.close(); + + if (fdUseCount == 0) { + /* + * We close the FileDescriptor in two-steps - first the + * "pre-close" which closes the socket but doesn't + * release the underlying file descriptor. This operation + * may be lengthy due to untransmitted data and a long + * linger interval. Once the pre-close is done we do the + * actual socket to release the fd. + */ + try { + socketPreClose(); + } finally { + socketClose(); + } + // Android-changed: Closed sockets use an invalid fd, not null. b/26470377 + // socketClose invalidates the fd by closing the fd. + // fd = null; + return; + } else { + /* + * If a thread has acquired the fd and a close + * isn't pending then use a deferred close. + * Also decrement fdUseCount to signal the last + * thread that releases the fd to close it. + */ + fdUseCount--; + socketPreClose(); + } } - closePending = true; - socketClose(); - return; } } } @@ -701,40 +754,45 @@ public int getTimeout() { return timeout; } + /* + * "Pre-close" a socket by dup'ing the file descriptor - this enables + * the socket to be closed without releasing the file descriptor. + */ + private void socketPreClose() throws IOException { + socketClose0(true); + } + /* * Close the socket (and release the file descriptor). */ protected void socketClose() throws IOException { - guard.close(); - - socketClose0(); + socketClose0(false); } abstract void socketCreate(boolean isServer) throws IOException; abstract void socketConnect(InetAddress address, int port, int timeout) - throws IOException; + throws IOException; abstract void socketBind(InetAddress address, int port) - throws IOException; + throws IOException; abstract void socketListen(int count) - throws IOException; + throws IOException; abstract void socketAccept(SocketImpl s) - throws IOException; + throws IOException; abstract int socketAvailable() - throws IOException; - abstract void socketClose0() - throws IOException; + throws IOException; + abstract void socketClose0(boolean useDeferredClose) + throws IOException; abstract void socketShutdown(int howto) - throws IOException; - abstract void socketSetOption(int cmd, boolean on, Object value) - throws SocketException; - abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException; + throws IOException; + + // Android-changed: Method signature changes. + // socket{Get,Set}Option work directly with Object values. + abstract void socketSetOption(int cmd, Object value) throws SocketException; + abstract Object socketGetOption(int opt) throws SocketException; + abstract void socketSendUrgentData(int data) - throws IOException; + throws IOException; public final static int SHUT_RD = 0; public final static int SHUT_WR = 1; } - -class InetAddressContainer { - InetAddress addr; -} \ No newline at end of file diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/BindException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/BindException.java index 9c2bb4830d..48c7106ec7 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/BindException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/BindException.java @@ -31,7 +31,7 @@ * socket to a local address and port. Typically, the port is * in use, or the requested local address could not be assigned. * - * @since JDK1.1 + * @since 1.1 */ public class BindException extends SocketException { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ConnectException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ConnectException.java index ff58643187..e67894e698 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ConnectException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ConnectException.java @@ -32,7 +32,7 @@ * was refused remotely (e.g., no process is listening on the * remote address/port). * - * @since JDK1.1 + * @since 1.1 */ public class ConnectException extends SocketException { private static final long serialVersionUID = 3831404271622369215L; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ContentHandlerFactory.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ContentHandlerFactory.java index 64112e3a80..994e266240 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ContentHandlerFactory.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ContentHandlerFactory.java @@ -36,15 +36,16 @@ * @author James Gosling * @see java.net.ContentHandler * @see java.net.URLStreamHandler - * @since JDK1.0 + * @since 1.0 */ public interface ContentHandlerFactory { + /** * Creates a new {@code ContentHandler} to read an object from * a {@code URLStreamHandler}. * * @param mimetype the MIME type for which a content handler is desired. - + * * @return a new {@code ContentHandler} to read an object from a * {@code URLStreamHandler}. * @see java.net.ContentHandler diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/CookieHandler.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/CookieHandler.java index 0d01256065..92fc9959b4 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/CookieHandler.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/CookieHandler.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.List; import java.io.IOException; +import sun.security.util.SecurityConstants; /** * A CookieHandler object provides a callback mechanism to hook up a @@ -35,9 +36,9 @@ * handler. The HTTP state management mechanism specifies a way to * create a stateful session with HTTP requests and responses. * - *

A system-wide CookieHandler that to used by the HTTP protocol - * handler can be registered by doing a - * CookieHandler.setDefault(CookieHandler). The currently registered + *

A system-wide CookieHandler to be used by the {@linkplain + * HttpURLConnection HTTP URL stream protocol handler} can be registered by + * doing a CookieHandler.setDefault(CookieHandler). The currently registered * CookieHandler can be retrieved by calling * CookieHandler.getDefault(). * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/CookieManager.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/CookieManager.java index bff9734cca..e35a271cd0 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/CookieManager.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/CookieManager.java @@ -82,7 +82,7 @@ *

  • * Currently, only CookieStore.add(URI, HttpCookie) and CookieStore.get(URI) * are used by CookieManager. Others are for completeness and might be needed - * by a more sophisticated CookieStore implementation, e.g. a NetscapeCookieSotre. + * by a more sophisticated CookieStore implementation, e.g. a NetscapeCookieStore. *
  • * * @@ -209,7 +209,7 @@ public CookieStore getCookieStore() { return Collections.unmodifiableMap(cookieMap); boolean secureLink = "https".equalsIgnoreCase(uri.getScheme()); - List cookies = new java.util.ArrayList(); + List cookies = new java.util.ArrayList<>(); // BEGIN Android-removed: The logic of converting null path is moved into pathMatches. /* String path = uri.getPath(); @@ -307,7 +307,7 @@ public CookieStore getCookieStore() { // the path is the directory of the page/doc String path = uri.getPath(); if (!path.endsWith("/")) { - int i = path.lastIndexOf("/"); + int i = path.lastIndexOf('/'); if (i > 0) { path = path.substring(0, i + 1); } else { @@ -382,8 +382,8 @@ private boolean shouldAcceptInternal(URI uri, HttpCookie cookie) { } - static private boolean isInPortList(String lst, int port) { - int i = lst.indexOf(","); + private static boolean isInPortList(String lst, int port) { + int i = lst.indexOf(','); int val = -1; while (i > 0) { try { @@ -394,7 +394,7 @@ static private boolean isInPortList(String lst, int port) { } catch (NumberFormatException numberFormatException) { } lst = lst.substring(i+1); - i = lst.indexOf(","); + i = lst.indexOf(','); } if (!lst.isEmpty()) { try { @@ -459,7 +459,7 @@ private List sortByPath(List cookies) { result.append(cookies.get(i).toString()); } - List cookieHeader = new java.util.ArrayList(); + List cookieHeader = new java.util.ArrayList<>(); cookieHeader.add(result.toString()); // END Android-changed: Cookie header differs in Netscape cookie spec and RFC 2965. return cookieHeader; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DatagramPacket.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DatagramPacket.java index 67edf468d4..85273863c0 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DatagramPacket.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DatagramPacket.java @@ -38,7 +38,7 @@ * * @author Pavani Diwanji * @author Benjamin Renaud - * @since JDK1.0 + * @since 1.0 */ public final class DatagramPacket { @@ -46,9 +46,8 @@ class DatagramPacket { // BEGIN Android-removed: Android doesn't need to load native net library. /** * Perform class initialization - */ + * static { - /* J2ObjC modified. java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { @@ -56,9 +55,9 @@ public Void run() { return null; } }); - */ init(); } + */ // END Android-removed: Android doesn't need to load native net library. /* @@ -293,7 +292,7 @@ public synchronized void setData(byte[] buf, int offset, int length) { * Sets the IP address of the machine to which this datagram * is being sent. * @param iaddr the {@code InetAddress} - * @since JDK1.1 + * @since 1.1 * @see #getAddress() */ public synchronized void setAddress(InetAddress iaddr) { @@ -314,7 +313,7 @@ public void setReceivedLength(int length) { * Sets the port number on the remote host to which this datagram * is being sent. * @param iport the port number - * @since JDK1.1 + * @since 1.1 * @see #getPort() */ public synchronized void setPort(int iport) { @@ -369,7 +368,7 @@ public synchronized SocketAddress getSocketAddress() { * @see #getLength * @see #getData * - * @since JDK1.1 + * @since 1.1 */ public synchronized void setData(byte[] buf) { if (buf == null) { @@ -397,7 +396,7 @@ public synchronized void setData(byte[] buf) { * @see #getLength * @see #setData * - * @since JDK1.1 + * @since 1.1 */ public synchronized void setLength(int length) { if ((length + offset) > buf.length || length < 0 || @@ -408,9 +407,9 @@ public synchronized void setLength(int length) { this.bufLength = this.length; } - /* J2ObjC added: native implementation. */ - /** - * 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/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DatagramSocket.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DatagramSocket.java index a1f0d1325b..b55b8d4031 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DatagramSocket.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DatagramSocket.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,8 @@ import java.security.AccessController; import java.security.PrivilegedExceptionAction; */ +import java.util.Set; +import java.util.Collections; import libcore.io.Libcore; /** @@ -127,7 +129,7 @@ class DatagramSocket implements java.io.Closeable { /** * Connects this socket to a remote socket address (IP address + port number). * Binds socket if not already bound. - *

    + * * @param address The remote address. * @param port The remote port * @throws SocketException if binding the socket fails. @@ -315,7 +317,7 @@ public DatagramSocket(int port) throws SocketException { * {@code checkListen} method doesn't allow the operation. * * @see SecurityManager#checkListen - * @since JDK1.1 + * @since 1.1 */ public DatagramSocket(int port, InetAddress laddr) throws SocketException { this(new InetSocketAddress(laddr, port)); @@ -329,7 +331,7 @@ private void checkOldImpl() { try { /* J2ObjC removed. AccessController.doPrivileged( - new PrivilegedExceptionAction() { + new PrivilegedExceptionAction<>() { public Void run() throws NoSuchMethodException { */ Class[] cl = new Class[1]; @@ -386,7 +388,7 @@ DatagramSocketImpl getImpl() throws SocketException { *

    * If the address is {@code null}, then the system will pick up * an ephemeral port and a valid local address to bind the socket. - *

    + * * @param addr The address and port to bind to. * @throws SocketException if any error happens during the bind, or if the * socket is already bound. @@ -496,7 +498,7 @@ public void connect(InetAddress address, int port) { * *

    If given an {@link InetSocketAddress InetSocketAddress}, this method * behaves as if invoking {@link #connect(InetAddress,int) connect(InetAddress,int)} - * with the the given socket addresses IP address and port number. + * with the given socket addresses IP address and port number. * * @param addr The remote address. * @@ -935,13 +937,13 @@ public int getLocalPort() { * * @param timeout the specified timeout in milliseconds. * @throws SocketException if there is an error in the underlying protocol, such as an UDP error. - * @since JDK1.1 + * @since 1.1 * @see #getSoTimeout() */ public synchronized void setSoTimeout(int timeout) throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); - getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); + getImpl().setOption(SocketOptions.SO_TIMEOUT, timeout); } /** @@ -950,7 +952,7 @@ public synchronized void setSoTimeout(int timeout) throws SocketException { * * @return the setting for SO_TIMEOUT * @throws SocketException if there is an error in the underlying protocol, such as an UDP error. - * @since JDK1.1 + * @since 1.1 * @see #setSoTimeout(int) */ public synchronized int getSoTimeout() throws SocketException { @@ -1003,7 +1005,7 @@ public synchronized void setSendBufferSize(int size) } if (isClosed()) throw new SocketException("Socket is closed"); - getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size)); + getImpl().setOption(SocketOptions.SO_SNDBUF, size); } /** @@ -1028,7 +1030,7 @@ public synchronized int getSendBufferSize() throws SocketException { /** * Sets the SO_RCVBUF option to the specified value for this - * {@code DatagramSocket}. The SO_RCVBUF option is used by the + * {@code DatagramSocket}. The SO_RCVBUF option is used by * the network implementation as a hint to size the underlying * network I/O buffers. The SO_RCVBUF setting may also be used * by the network implementation to determine the maximum size @@ -1061,7 +1063,7 @@ public synchronized void setReceiveBufferSize(int size) } if (isClosed()) throw new SocketException("Socket is closed"); - getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size)); + getImpl().setOption(SocketOptions.SO_RCVBUF, size); } /** @@ -1123,7 +1125,7 @@ public synchronized void setReuseAddress(boolean on) throws SocketException { throw new SocketException("Socket is closed"); // Integer instead of Boolean for compatibility with older DatagramSocketImpl if (oldImpl) - getImpl().setOption(SocketOptions.SO_REUSEADDR, new Integer(on?-1:0)); + getImpl().setOption(SocketOptions.SO_REUSEADDR, on?-1:0); else getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); } @@ -1333,10 +1335,8 @@ public DatagramChannel getChannel() { * datagram socket factory. * @exception SocketException if the factory is already defined. * @exception SecurityException if a security manager exists and its - * {@code checkSetFactory} method doesn't allow the - operation. - * @see - java.net.DatagramSocketImplFactory#createDatagramSocketImpl() + * {@code checkSetFactory} method doesn't allow the operation. + * @see java.net.DatagramSocketImplFactory#createDatagramSocketImpl() * @see SecurityManager#checkSetFactory * @since 1.3 */ @@ -1354,12 +1354,107 @@ public DatagramChannel getChannel() { factory = fac; } + /** + * Sets the value of a socket option. + * + * @param The type of the socket option value + * @param name The socket option + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * + * @return this DatagramSocket + * + * @throws UnsupportedOperationException if the datagram socket + * does not support the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @throws NullPointerException if name is {@code null} + * + * @since 9 + */ + public DatagramSocket setOption(SocketOption name, T value) + throws IOException + { + getImpl().setOption(name, value); + return this; + } + + /** + * Returns the value of a socket option. + * + * @param The type of the socket option value + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the datagram socket + * does not support the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 9 + */ + public T getOption(SocketOption name) throws IOException { + return getImpl().getOption(name); + } + + private static Set> options; + private static boolean optionsSet = false; + + /** + * Returns a set of the socket options supported by this socket. + * + * This method will continue to return the set of options even after + * the socket has been closed. + * + * @return A set of the socket options supported by this socket. This set + * may be empty if the socket's DatagramSocketImpl cannot be created. + * + * @since 9 + */ + public Set> supportedOptions() { + synchronized(DatagramSocket.class) { + if (optionsSet) { + return options; + } + try { + DatagramSocketImpl impl = getImpl(); + options = Collections.unmodifiableSet(impl.supportedOptions()); + } catch (IOException e) { + options = Collections.emptySet(); + } + optionsSet = true; + return options; + } + } + // Android-added: for testing and internal use. /** + * Gets socket's underlying {@link FileDescriptor}. + * * @hide internal use only + * + * @return socket's underlying {@link FileDescriptor}. */ public FileDescriptor getFileDescriptor$() { return impl.fd; } - } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DatagramSocketImpl.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DatagramSocketImpl.java index 611632ee51..d6fabef110 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DatagramSocketImpl.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DatagramSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,12 +28,12 @@ import com.google.j2objc.annotations.Weak; import java.io.FileDescriptor; import java.io.IOException; -import java.io.InterruptedIOException; +import java.util.Set; /** * Abstract datagram and multicast socket implementation base class. * @author Pavani Diwanji - * @since JDK1.1 + * @since 1.1 */ public abstract class DatagramSocketImpl implements SocketOptions { @@ -48,12 +48,6 @@ public abstract class DatagramSocketImpl implements SocketOptions { */ protected FileDescriptor fd; - int dataAvailable() { - // default impl returns zero, which disables the calling - // functionality - return 0; - } - /** * The DatagramSocket or MulticastSocket * that owns this impl @@ -69,6 +63,12 @@ DatagramSocket getDatagramSocket() { return socket; } + int dataAvailable() { + // default impl returns zero, which disables the calling + // functionality + return 0; + } + /** * Creates a datagram socket. * @exception SocketException if there is an error in the @@ -255,13 +255,41 @@ protected int getLocalPort() { return localPort; } - void setOption(SocketOption name, T value) throws IOException { + /** + * Gets the datagram socket file descriptor. + * @return a {@code FileDescriptor} object representing the datagram socket + * file descriptor + */ + protected FileDescriptor getFileDescriptor() { + return fd; + } + + /** + * Called to set a socket option. + * + * @param The type of the socket option value + * @param name The socket option + * + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * + * @throws UnsupportedOperationException if the DatagramSocketImpl does not + * support the option + * + * @throws NullPointerException if name is {@code null} + * @throws IOException if an I/O problem occurs while attempting to set the option + * @since 9 + */ + protected void setOption(SocketOption name, T value) throws IOException { if (name == StandardSocketOptions.SO_SNDBUF) { setOption(SocketOptions.SO_SNDBUF, value); } else if (name == StandardSocketOptions.SO_RCVBUF) { setOption(SocketOptions.SO_RCVBUF, value); } else if (name == StandardSocketOptions.SO_REUSEADDR) { setOption(SocketOptions.SO_REUSEADDR, value); + } else if (name == StandardSocketOptions.SO_REUSEPORT && + supportedOptions().contains(name)) { + setOption(SocketOptions.SO_REUSEPORT, value); } else if (name == StandardSocketOptions.IP_TOS) { setOption(SocketOptions.IP_TOS, value); } else if (name == StandardSocketOptions.IP_MULTICAST_IF && @@ -281,13 +309,32 @@ void setOption(SocketOption name, T value) throws IOException { } } - T getOption(SocketOption name) throws IOException { + /** + * Called to get a socket option. + * + * @return the socket option + * @param The type of the socket option value + * @param name The socket option + * + * @throws UnsupportedOperationException if the DatagramSocketImpl does not + * support the option + * + * @throws NullPointerException if name is {@code null} + * @throws IOException if an I/O problem occurs while attempting to set the option + * + * @since 9 + */ + @SuppressWarnings("unchecked") + protected T getOption(SocketOption name) throws IOException { if (name == StandardSocketOptions.SO_SNDBUF) { return (T) getOption(SocketOptions.SO_SNDBUF); } else if (name == StandardSocketOptions.SO_RCVBUF) { return (T) getOption(SocketOptions.SO_RCVBUF); } else if (name == StandardSocketOptions.SO_REUSEADDR) { return (T) getOption(SocketOptions.SO_REUSEADDR); + } else if (name == StandardSocketOptions.SO_REUSEPORT && + supportedOptions().contains(name)) { + return (T) getOption(SocketOptions.SO_REUSEPORT); } else if (name == StandardSocketOptions.IP_TOS) { return (T) getOption(SocketOptions.IP_TOS); } else if (name == StandardSocketOptions.IP_MULTICAST_IF && @@ -305,12 +352,38 @@ T getOption(SocketOption name) throws IOException { } } + private static final Set> dgSocketOptions; + + private static final Set> mcSocketOptions; + + static { + dgSocketOptions = Set.of(StandardSocketOptions.SO_SNDBUF, + StandardSocketOptions.SO_RCVBUF, + StandardSocketOptions.SO_REUSEADDR, + StandardSocketOptions.IP_TOS); + + mcSocketOptions = Set.of(StandardSocketOptions.SO_SNDBUF, + StandardSocketOptions.SO_RCVBUF, + StandardSocketOptions.SO_REUSEADDR, + StandardSocketOptions.IP_TOS, + StandardSocketOptions.IP_MULTICAST_IF, + StandardSocketOptions.IP_MULTICAST_TTL, + StandardSocketOptions.IP_MULTICAST_LOOP); + } + /** - * Gets the datagram socket file descriptor. - * @return a {@code FileDescriptor} object representing the datagram socket - * file descriptor + * Returns a set of SocketOptions supported by this impl + * and by this impl's socket (DatagramSocket or MulticastSocket) + * + * @return a Set of SocketOptions + * + * @since 9 */ - protected FileDescriptor getFileDescriptor() { - return fd; + protected Set> supportedOptions() { + if (getDatagramSocket() instanceof MulticastSocket) { + return mcSocketOptions; + } else { + return dgSocketOptions; + } } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DefaultDatagramSocketImplFactory.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DefaultDatagramSocketImplFactory.java index 6b342728b6..450697497a 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DefaultDatagramSocketImplFactory.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/DefaultDatagramSocketImplFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007,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 diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/FileNameMap.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/FileNameMap.java index 393b5aa6d9..857787d9ab 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/FileNameMap.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/FileNameMap.java @@ -30,7 +30,7 @@ * between a file name and a MIME type string. * * @author Steven B. Byrne - * @since JDK1.1 + * @since 1.1 */ public interface FileNameMap { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/HttpURLConnection.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/HttpURLConnection.java index db05c5f2ac..b72168bb88 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/HttpURLConnection.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/HttpURLConnection.java @@ -315,7 +315,7 @@ abstract public class HttpURLConnection extends URLConnection { * server. In this case, {@link #getHeaderField(int) getHeaderField(0)} returns the status * line, but {@code getHeaderFieldKey(0)} returns null. * - * @param n an index, where n >=0. + * @param n an index, where {@code n >=0}. * @return the key for the {@code n}th header field, * or {@code null} if the key does not exist. */ @@ -466,7 +466,7 @@ public void setChunkedStreamingMode (int chunklen) { * {@link #getHeaderFieldKey getHeaderFieldKey} method to iterate through all * the headers in the message. * - * @param n an index, where n>=0. + * @param n an index, where {@code n>=0}. * @return the value of the {@code n}th header field, * or {@code null} if the value does not exist. * @see java.net.HttpURLConnection#getHeaderFieldKey(int) diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/IDN.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/IDN.java index 4e60209789..a87ec11441 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/IDN.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/IDN.java @@ -1,106 +1,506 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 +/* + * Copyright (C) 2014 The Android Open Source Project + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * - * 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. + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 java.net; import libcore.icu.NativeIDN; /** - * Converts internationalized domain names between Unicode and the ASCII Compatible Encoding - * (ACE) representation. + * Provides methods to convert internationalized domain names (IDNs) between + * a normal Unicode representation and an ASCII Compatible Encoding (ACE) representation. + * Internationalized domain names can use characters from the entire range of + * Unicode, while traditional domain names are restricted to ASCII characters. + * ACE is an encoding of Unicode strings that uses only ASCII characters and + * can be used with software (such as the Domain Name System) that only + * understands traditional domain names. + * + *

    Internationalized domain names are defined in RFC 3490. + * RFC 3490 defines two operations: ToASCII and ToUnicode. These 2 operations employ + * Nameprep algorithm, which is a + * profile of Stringprep, and + * Punycode algorithm to convert + * domain name string back and forth. + * + *

    The behavior of aforementioned conversion process can be adjusted by various flags: + *

      + *
    • If the ALLOW_UNASSIGNED flag is used, the domain name string to be converted + * can contain code points that are unassigned in Unicode 3.2, which is the + * Unicode version on which IDN conversion is based. If the flag is not used, + * the presence of such unassigned code points is treated as an error. + *
    • If the USE_STD3_ASCII_RULES flag is used, ASCII strings are checked against RFC 1122 and RFC 1123. + * It is an error if they don't meet the requirements. + *
    + * These flags can be logically OR'ed together. * - *

    See RFC 3490 for full details. + *

    The security consideration is important with respect to internationalization + * domain name support. For example, English domain names may be homographed + * - maliciously misspelled by substitution of non-Latin letters. + * Unicode Technical Report #36 + * discusses security issues of IDN support as well as possible solutions. + * Applications are responsible for taking adequate security measures when using + * international domain names. * + * @author Edward Wang * @since 1.6 + * */ public final class IDN { /** - * When set, allows IDN to process unassigned unicode points. + * Flag to allow processing of unassigned code points */ - public static final int ALLOW_UNASSIGNED = 1; + public static final int ALLOW_UNASSIGNED = 0x01; /** - * When set, ASCII strings are checked against - * RFC 1122 and - * RFC 1123. + * Flag to turn on the check against STD-3 ASCII rules */ - public static final int USE_STD3_ASCII_RULES = 2; + public static final int USE_STD3_ASCII_RULES = 0x02; - private IDN() { - } /** - * Transform a Unicode String to ASCII Compatible Encoding String according - * to the algorithm defined in RFC 3490. - * - *

    If the transformation fails (because the input is not a valid IDN), an - * exception will be thrown. - * - *

    This method can handle either an individual label or an entire domain name. - * In the latter case, the separators are: U+002E (full stop), U+3002 (ideographic full stop), - * U+FF0E (fullwidth full stop), and U+FF61 (halfwidth ideographic full stop). - * All of these will become U+002E (full stop) in the result. - * - * @param input the Unicode name - * @param flags 0, {@code ALLOW_UNASSIGNED}, {@code USE_STD3_ASCII_RULES}, - * or {@code ALLOW_UNASSIGNED | USE_STD3_ASCII_RULES} - * @return the ACE name - * @throws IllegalArgumentException if {@code input} does not conform to RFC 3490 + * Translates a string from Unicode to ASCII Compatible Encoding (ACE), + * as defined by the ToASCII operation of RFC 3490. + * + *

    ToASCII operation can fail. ToASCII fails if any step of it fails. + * If ToASCII operation fails, an IllegalArgumentException will be thrown. + * In this case, the input string should not be used in an internationalized domain name. + * + *

    A label is an individual part of a domain name. The original ToASCII operation, + * as defined in RFC 3490, only operates on a single label. This method can handle + * both label and entire domain name, by assuming that labels in a domain name are + * always separated by dots. The following characters are recognized as dots: + * \u002E (full stop), \u3002 (ideographic full stop), \uFF0E (fullwidth full stop), + * and \uFF61 (halfwidth ideographic full stop). if dots are + * used as label separators, this method also changes all of them to \u002E (full stop) + * in output translated string. + * + * @param input the string to be processed + * @param flag process flag; can be 0 or any logical OR of possible flags + * + * @return the translated {@code String} + * + * @throws IllegalArgumentException if the input string doesn't conform to RFC 3490 specification */ - public static String toASCII(String input, int flags) { - return NativeIDN.toASCII(input, flags); + public static String toASCII(String input, int flag) { + return NativeIDN.toASCII(input, flag); + /* J2ObjC modified + // BEGIN Android-changed: Use ICU4J implementation. + try { + return NativeIDN.toASCII(input, flag); + } catch (android.icu.text.StringPrepParseException e) { + // b/113787610: "." is a valid IDN but is rejected by ICU. + // Usage is relatively uncommon, so only check for it if ICU throws. + if (".".equals(input)) { + return input; + } + throw new IllegalArgumentException("Invalid input to toASCII: " + input, e); + } + // END Android-changed: Use ICU4J implementation. + */ } + /** - * Equivalent to {@code toASCII(input, 0)}. + * Translates a string from Unicode to ASCII Compatible Encoding (ACE), + * as defined by the ToASCII operation of RFC 3490. + * + *

    This convenience method works as if by invoking the + * two-argument counterpart as follows: + *

    + * {@link #toASCII(String, int) toASCII}(input, 0); + *
    + * + * @param input the string to be processed * - * @param input the Unicode name - * @return the ACE name - * @throws IllegalArgumentException if {@code input} does not conform to RFC 3490 + * @return the translated {@code String} + * + * @throws IllegalArgumentException if the input string doesn't conform to RFC 3490 specification */ public static String toASCII(String input) { return toASCII(input, 0); } + /** - * Translates a string from ASCII Compatible Encoding (ACE) to Unicode - * according to the algorithm defined in RFC 3490. + * Translates a string from ASCII Compatible Encoding (ACE) to Unicode, + * as defined by the ToUnicode operation of RFC 3490. + * + *

    ToUnicode never fails. In case of any error, the input string is returned unmodified. * - *

    Unlike {@code toASCII}, this transformation cannot fail. + *

    A label is an individual part of a domain name. The original ToUnicode operation, + * as defined in RFC 3490, only operates on a single label. This method can handle + * both label and entire domain name, by assuming that labels in a domain name are + * always separated by dots. The following characters are recognized as dots: + * \u002E (full stop), \u3002 (ideographic full stop), \uFF0E (fullwidth full stop), + * and \uFF61 (halfwidth ideographic full stop). * - *

    This method can handle either an individual label or an entire domain name. - * In the latter case, the separators are: U+002E (full stop), U+3002 (ideographic full stop), - * U+FF0E (fullwidth full stop), and U+FF61 (halfwidth ideographic full stop). + * @param input the string to be processed + * @param flag process flag; can be 0 or any logical OR of possible flags * - * @param input the ACE name - * @return the Unicode name - * @param flags 0, {@code ALLOW_UNASSIGNED}, {@code USE_STD3_ASCII_RULES}, - * or {@code ALLOW_UNASSIGNED | USE_STD3_ASCII_RULES} + * @return the translated {@code String} */ - public static String toUnicode(String input, int flags) { - return NativeIDN.toUnicode(input, flags); + public static String toUnicode(String input, int flag) { + return NativeIDN.toUnicode(input, flag); + /* J2ObjC modified + // BEGIN Android-changed: Use ICU4J implementation. + try { + // ICU only translates separators to ASCII for toASCII. + // Java expects the translation for toUnicode too. + return convertFullStop(ExtendedIDNA.convertIDNToUnicode(input, flag)).toString(); + } catch (android.icu.text.StringPrepParseException e) { + // The RI documentation explicitly states that if the conversion was unsuccessful + // the original string is returned. + return input; + } + // END Android-changed: Use ICU4J implementation. + */ + } + + /* J2ObjC removed + // BEGIN Android-added: Use ICU4J implementation. + private static boolean isLabelSeperator(char c) { + return (c == '\u3002' || c == '\uff0e' || c == '\uff61'); } + private static StringBuffer convertFullStop(StringBuffer input) { + for (int i = 0; i < input.length(); i++) { + if (isLabelSeperator(input.charAt(i))) { + input.setCharAt(i, '.'); + } + } + return input; + } + // END Android-added: Use ICU4J implementation. + */ + /** - * Equivalent to {@code toUnicode(input, 0)}. + * Translates a string from ASCII Compatible Encoding (ACE) to Unicode, + * as defined by the ToUnicode operation of RFC 3490. + * + *

    This convenience method works as if by invoking the + * two-argument counterpart as follows: + *

    + * {@link #toUnicode(String, int) toUnicode}(input, 0); + *
    * - * @param input the ACE name - * @return the Unicode name + * @param input the string to be processed + * + * @return the translated {@code String} */ public static String toUnicode(String input) { return NativeIDN.toUnicode(input, 0); } + + + /* ---------------- Private members -------------- */ + + // Android-removed: Private helper methods, unused because we use ICU. + /* + // ACE Prefix is "xn--" + private static final String ACE_PREFIX = "xn--"; + private static final int ACE_PREFIX_LENGTH = ACE_PREFIX.length(); + + private static final int MAX_LABEL_LENGTH = 63; + + // single instance of nameprep + private static StringPrep namePrep = null; + + static { + InputStream stream = null; + + try { + final String IDN_PROFILE = "uidna.spp"; + if (System.getSecurityManager() != null) { + stream = AccessController.doPrivileged(new PrivilegedAction() { + public InputStream run() { + return StringPrep.class.getResourceAsStream(IDN_PROFILE); + } + }); + } else { + stream = StringPrep.class.getResourceAsStream(IDN_PROFILE); + } + + namePrep = new StringPrep(stream); + stream.close(); + } catch (IOException e) { + // should never reach here + assert false; + } + } + */ + + /* ---------------- Private operations -------------- */ + + + // + // to suppress the default zero-argument constructor + // + private IDN() {} + + // Android-removed: Private helper methods, unused because we use ICU. + /* + // + // toASCII operation; should only apply to a single label + // + private static String toASCIIInternal(String label, int flag) + { + // step 1 + // Check if the string contains code points outside the ASCII range 0..0x7c. + boolean isASCII = isAllASCII(label); + StringBuffer dest; + + // step 2 + // perform the nameprep operation; flag ALLOW_UNASSIGNED is used here + if (!isASCII) { + UCharacterIterator iter = UCharacterIterator.getInstance(label); + try { + dest = namePrep.prepare(iter, flag); + } catch (java.text.ParseException e) { + throw new IllegalArgumentException(e); + } + } else { + dest = new StringBuffer(label); + } + + // step 8, move forward to check the smallest number of the code points + // the length must be inside 1..63 + if (dest.length() == 0) { + throw new IllegalArgumentException( + "Empty label is not a legal name"); + } + + // step 3 + // Verify the absence of non-LDH ASCII code points + // 0..0x2c, 0x2e..0x2f, 0x3a..0x40, 0x5b..0x60, 0x7b..0x7f + // Verify the absence of leading and trailing hyphen + boolean useSTD3ASCIIRules = ((flag & USE_STD3_ASCII_RULES) != 0); + if (useSTD3ASCIIRules) { + for (int i = 0; i < dest.length(); i++) { + int c = dest.charAt(i); + if (isNonLDHAsciiCodePoint(c)) { + throw new IllegalArgumentException( + "Contains non-LDH ASCII characters"); + } + } + + if (dest.charAt(0) == '-' || + dest.charAt(dest.length() - 1) == '-') { + + throw new IllegalArgumentException( + "Has leading or trailing hyphen"); + } + } + + if (!isASCII) { + // step 4 + // If all code points are inside 0..0x7f, skip to step 8 + if (!isAllASCII(dest.toString())) { + // step 5 + // verify the sequence does not begin with ACE prefix + if(!startsWithACEPrefix(dest)){ + + // step 6 + // encode the sequence with punycode + try { + dest = Punycode.encode(dest, null); + } catch (java.text.ParseException e) { + throw new IllegalArgumentException(e); + } + + dest = toASCIILower(dest); + + // step 7 + // prepend the ACE prefix + dest.insert(0, ACE_PREFIX); + } else { + throw new IllegalArgumentException("The input starts with the ACE Prefix"); + } + + } + } + + // step 8 + // the length must be inside 1..63 + if (dest.length() > MAX_LABEL_LENGTH) { + throw new IllegalArgumentException("The label in the input is too long"); + } + + return dest.toString(); + } + + // + // toUnicode operation; should only apply to a single label + // + private static String toUnicodeInternal(String label, int flag) { + boolean[] caseFlags = null; + StringBuffer dest; + + // step 1 + // find out if all the codepoints in input are ASCII + boolean isASCII = isAllASCII(label); + + if(!isASCII){ + // step 2 + // perform the nameprep operation; flag ALLOW_UNASSIGNED is used here + try { + UCharacterIterator iter = UCharacterIterator.getInstance(label); + dest = namePrep.prepare(iter, flag); + } catch (Exception e) { + // toUnicode never fails; if any step fails, return the input string + return label; + } + } else { + dest = new StringBuffer(label); + } + + // step 3 + // verify ACE Prefix + if(startsWithACEPrefix(dest)) { + + // step 4 + // Remove the ACE Prefix + String temp = dest.substring(ACE_PREFIX_LENGTH, dest.length()); + + try { + // step 5 + // Decode using punycode + StringBuffer decodeOut = Punycode.decode(new StringBuffer(temp), null); + + // step 6 + // Apply toASCII + String toASCIIOut = toASCII(decodeOut.toString(), flag); + + // step 7 + // verify + if (toASCIIOut.equalsIgnoreCase(dest.toString())) { + // step 8 + // return output of step 5 + return decodeOut.toString(); + } + } catch (Exception ignored) { + // no-op + } + } + + // just return the input + return label; + } + + + // + // LDH stands for "letter/digit/hyphen", with characters restricted to the + // 26-letter Latin alphabet , the digits <0-9>, and the hyphen + // <->. + // Non LDH refers to characters in the ASCII range, but which are not + // letters, digits or the hypen. + // + // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x5B..0x60, 0x7B..0x7F + // + private static boolean isNonLDHAsciiCodePoint(int ch){ + return (0x0000 <= ch && ch <= 0x002C) || + (0x002E <= ch && ch <= 0x002F) || + (0x003A <= ch && ch <= 0x0040) || + (0x005B <= ch && ch <= 0x0060) || + (0x007B <= ch && ch <= 0x007F); + } + + // + // search dots in a string and return the index of that character; + // or if there is no dots, return the length of input string + // dots might be: \u002E (full stop), \u3002 (ideographic full stop), \uFF0E (fullwidth full stop), + // and \uFF61 (halfwidth ideographic full stop). + // + private static int searchDots(String s, int start) { + int i; + for (i = start; i < s.length(); i++) { + if (isLabelSeparator(s.charAt(i))) { + break; + } + } + + return i; + } + + // + // to check if a string is a root label, ".". + // + private static boolean isRootLabel(String s) { + return (s.length() == 1 && isLabelSeparator(s.charAt(0))); + } + + // + // to check if a character is a label separator, i.e. a dot character. + // + private static boolean isLabelSeparator(char c) { + return (c == '.' || c == '\u3002' || c == '\uFF0E' || c == '\uFF61'); + } + + // + // to check if a string only contains US-ASCII code point + // + private static boolean isAllASCII(String input) { + boolean isASCII = true; + for (int i = 0; i < input.length(); i++) { + int c = input.charAt(i); + if (c > 0x7F) { + isASCII = false; + break; + } + } + return isASCII; + } + + // + // to check if a string starts with ACE-prefix + // + private static boolean startsWithACEPrefix(StringBuffer input){ + boolean startsWithPrefix = true; + + if(input.length() < ACE_PREFIX_LENGTH){ + return false; + } + for(int i = 0; i < ACE_PREFIX_LENGTH; i++){ + if(toASCIILower(input.charAt(i)) != ACE_PREFIX.charAt(i)){ + startsWithPrefix = false; + } + } + return startsWithPrefix; + } + + private static char toASCIILower(char ch){ + if('A' <= ch && ch <= 'Z'){ + return (char)(ch + 'a' - 'A'); + } + return ch; + } + + private static StringBuffer toASCIILower(StringBuffer input){ + StringBuffer dest = new StringBuffer(); + for(int i = 0; i < input.length();i++){ + dest.append(toASCIILower(input.charAt(i))); + } + return dest; + } + */ } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/InMemoryCookieStore.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/InMemoryCookieStore.java index c041ebff70..e716404d5b 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/InMemoryCookieStore.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/InMemoryCookieStore.java @@ -79,8 +79,8 @@ public class InMemoryCookieStore implements CookieStore { * The default ctor */ public InMemoryCookieStore() { - /* J2ObjC modified: use hard-coded Android version number for Android 10. */ - this(/*VMRuntime.getRuntime().getTargetSdkVersion()*/ 29); + /* J2ObjC modified: use hard-coded Android version number for Android 13. */ + this(/*VMRuntime.getRuntime().getTargetSdkVersion()*/ 33); } public InMemoryCookieStore(int targetSdkVersion) { @@ -178,7 +178,7 @@ public List getCookies() { public List getURIs() { // BEGIN Android-changed: App compat. Return URI with no cookies. http://b/65538736 /* - List uris = new ArrayList(); + List uris = new ArrayList<>(); lock.lock(); try { @@ -408,7 +408,7 @@ private void addIndex(Map> indexStore, cookies.add(cookie); } else { - cookies = new ArrayList(); + cookies = new ArrayList<>(); cookies.add(cookie); indexStore.put(index, cookies); } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Inet4Address.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Inet4Address.java index 415bc19452..af7995b388 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Inet4Address.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Inet4Address.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,17 +38,17 @@ * and RFC 2365: * Administratively Scoped IP Multicast * - *

    Textual representation of IP addresses

    + *

    Textual representation of IP addresses

    * * Textual representation of IPv4 address used as input to methods * takes one of the following forms: * - *
    - * - * - * - * - *
    {@code d.d.d.d}
    {@code d.d.d}
    {@code d.d}
    {@code d}
    + *
      + *
    • {@code d.d.d.d}
    • + *
    • {@code d.d.d}
    • + *
    • {@code d.d}
    • + *
    • {@code d}
    • + *
    * *

    When four parts are specified, each is interpreted as a byte of * data and assigned, from left to right, to the four bytes of an IPv4 @@ -86,7 +86,7 @@ public final class Inet4Address extends InetAddress { - final static int INADDRSZ = 4; + static final int INADDRSZ = 4; /** use serialVersionUID from InetAddress, but Inet4Address instance * is always replaced by an InetAddress instance before being @@ -94,14 +94,27 @@ class Inet4Address extends InetAddress { private static final long serialVersionUID = 3286316764910316507L; // BEGIN Android-added: Define special-purpose IPv4 address. - /** @hide */ + /** + * Reserved address for {@code INADDR_ANY}, to specify any IPv4 address at all. + * + * @hide + */ public static final InetAddress ANY = new Inet4Address(null, new byte[] { 0, 0, 0, 0 }); - /** @hide */ + /** + * Broadcast address to transmit to all devices on network. + * + * @hide + */ public static final InetAddress ALL = new Inet4Address(null, new byte[] { (byte) 255, (byte) 255, (byte) 255, (byte) 255 }); - /** @hide */ + + /** + * Loopback address to the local host. + * + * @hide + */ public static final InetAddress LOOPBACK = new Inet4Address("localhost", new byte[] { 127, 0, 0, 1 }); // END Android-added: Define special-purpose IPv4 address. @@ -175,17 +188,15 @@ private Object writeReplace() throws ObjectStreamException { * address i.e first four bits of the address are 1110. * @return a {@code boolean} indicating if the InetAddress is * an IP multicast address - * @since JDK1.1 */ public boolean isMulticastAddress() { return ((holder().getAddress() & 0xf0000000) == 0xe0000000); } /** - * Utility routine to check if the InetAddress in a wildcard address. + * Utility routine to check if the InetAddress is a wildcard address. * @return a {@code boolean} indicating if the Inetaddress is * a wildcard address. - * @since 1.4 */ public boolean isAnyLocalAddress() { return holder().getAddress() == 0; @@ -196,7 +207,6 @@ public boolean isAnyLocalAddress() { * * @return a {@code boolean} indicating if the InetAddress is * a loopback address; or false otherwise. - * @since 1.4 */ public boolean isLoopbackAddress() { /* 127.x.x.x */ @@ -209,7 +219,6 @@ public boolean isLoopbackAddress() { * * @return a {@code boolean} indicating if the InetAddress is * a link local address; or false if address is not a link local unicast address. - * @since 1.4 */ public boolean isLinkLocalAddress() { // link-local unicast in IPv4 (169.254.0.0/16) @@ -226,7 +235,6 @@ public boolean isLinkLocalAddress() { * * @return a {@code boolean} indicating if the InetAddress is * a site local address; or false if address is not a site local unicast address. - * @since 1.4 */ public boolean isSiteLocalAddress() { // refer to RFC 1918 @@ -247,7 +255,6 @@ public boolean isSiteLocalAddress() { * @return a {@code boolean} indicating if the address has * is a multicast address of global scope, false if it is not * of global scope or it is not a multicast address - * @since 1.4 */ public boolean isMCGlobal() { // 224.0.1.0 to 238.255.255.255 @@ -263,7 +270,6 @@ public boolean isMCGlobal() { * @return a {@code boolean} indicating if the address has * is a multicast address of node-local scope, false if it is not * of node-local scope or it is not a multicast address - * @since 1.4 */ public boolean isMCNodeLocal() { // unless ttl == 0 @@ -276,7 +282,6 @@ public boolean isMCNodeLocal() { * @return a {@code boolean} indicating if the address has * is a multicast address of link-local scope, false if it is not * of link-local scope or it is not a multicast address - * @since 1.4 */ public boolean isMCLinkLocal() { // 224.0.0/24 prefix and ttl == 1 @@ -292,7 +297,6 @@ public boolean isMCLinkLocal() { * @return a {@code boolean} indicating if the address has * is a multicast address of site-local scope, false if it is not * of site-local scope or it is not a multicast address - * @since 1.4 */ public boolean isMCSiteLocal() { // 239.255/16 prefix or ttl < 32 @@ -308,7 +312,6 @@ public boolean isMCSiteLocal() { * is a multicast address of organization-local scope, * false if it is not of organization-local scope * or it is not a multicast address - * @since 1.4 */ public boolean isMCOrgLocal() { // 239.192 - 239.195 @@ -340,7 +343,6 @@ public byte[] getAddress() { * Returns the IP address string in textual presentation form. * * @return the raw IP address in a string format. - * @since JDK1.0.2 */ public String getHostAddress() { return numericToTextFormat(getAddress()); @@ -377,15 +379,13 @@ public boolean equals(Object obj) { } // Utilities - /* + + /** * Converts IPv4 binary address into a string suitable for presentation. * * @param src a byte array representing an IPv4 numeric address * @return a String representing the IPv4 address in - * textual representation format - * @since 1.4 */ - static String numericToTextFormat(byte[] src) { return (src[0] & 0xff) + "." + (src[1] & 0xff) + "." + (src[2] & 0xff) + "." + (src[3] & 0xff); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Inet6Address.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Inet6Address.java index 6ea112742d..e1ba7d734f 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Inet6Address.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Inet6Address.java @@ -26,17 +26,17 @@ package java.net; +import static libcore.io.OsConstants.*; + import com.google.j2objc.annotations.Weak; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; -import java.util.Enumeration; import java.util.Arrays; -import libcore.io.Libcore; +import java.util.Enumeration; import libcore.io.NetworkOs; -import static libcore.io.OsConstants.*; /*-[ #include "JreRetainedWith.h" @@ -184,22 +184,31 @@ class Inet6Address extends InetAddress { final static int INADDRSZ = 16; - // BEGIN Android-removed: Remove special handling for link-local addresses. - /* - * cached scope_id - for link-local address use only. - * - private transient int cached_scope_id; // 0 - */ - // END Android-removed: Remove special handling for link-local addresses. - - // BEGIN Android-added: Define special-purpose IPv6 address. - /** @hide */ - public static final InetAddress ANY = - new Inet6Address("::", new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0); - - /** @hide */ - public static final InetAddress LOOPBACK = new Inet6Address("ip6-localhost", - new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 0); + // BEGIN Android-removed: Remove special handling for link-local addresses. + /* + * cached scope_id - for link-local address use only. + * + private transient int cached_scope_id; // 0 + */ + // END Android-removed: Remove special handling for link-local addresses. + + // BEGIN Android-added: Define special-purpose IPv6 address. + /** + * Reserved address for {@code INADDR_ANY}, to specify any IPv6 address at all. + * + * @hide + */ + public static final InetAddress ANY = + new Inet6Address("::", new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0); + + /** + * Loopback address to the local host. + * + * @hide + */ + public static final InetAddress LOOPBACK = + new Inet6Address( + "ip6-localhost", new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 0); // END Android-added: Define special-purpose IPv6 address. /* J2ObjC removed: private */ class Inet6AddressHolder { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Inet6AddressImpl.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Inet6AddressImpl.java index 66b8995bbc..964c47fc73 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Inet6AddressImpl.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Inet6AddressImpl.java @@ -44,6 +44,12 @@ import static libcore.io.OsConstants.ECONNREFUSED; import static libcore.io.OsConstants.EPERM; import static libcore.io.OsConstants.NI_NAMEREQD; +/* J2ObjC removed +import static libcore.io.OsConstants.ICMP6_ECHO_REPLY; +import static libcore.io.OsConstants.ICMP_ECHOREPLY; +import static libcore.io.OsConstants.IPPROTO_ICMP; +import static libcore.io.OsConstants.IPPROTO_ICMPV6; +*/ import static libcore.io.OsConstants.SOCK_DGRAM; import static libcore.io.OsConstants.SOCK_STREAM; @@ -201,19 +207,19 @@ public boolean isReachable(InetAddress addr, int timeout, NetworkInterface netif } // Android-changed: http://b/36933260 Implement root-less ICMP for isReachable(). - /* - if (addr instanceof Inet6Address) - scope = ((Inet6Address) addr).getScopeId(); - return isReachable0(addr.getAddress(), scope, timeout, ifaddr, ttl, netif_scope); + /* + if (addr instanceof Inet6Address) + scope = ((Inet6Address) addr).getScopeId(); + return isReachable0(addr.getAddress(), scope, timeout, ifaddr, ttl, netif_scope); * // Try ICMP first - if (icmpEcho(addr, timeout, sourceAddr, ttl)) { + if (icmpEcho(addr, timeout, sourceAddr, ttl)) { return true; } // No good, let's fall back to TCP - return tcpEcho(addr, timeout, sourceAddr, ttl); - */ + return tcpEcho(addr, timeout, sourceAddr, ttl); + */ byte[] ifaddr = null; int scope = -1; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/InetAddress.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/InetAddress.java index 7856a0dd26..b7ce5ac1ee 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/InetAddress.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/InetAddress.java @@ -1050,7 +1050,7 @@ public static InetAddress getByAddress(String host, byte[] addr) throws UnknownH // Android-added: Called by native code in Libcore.io. // Do not delete. Called from native code. - public static InetAddress getByAddress(String host, byte[] addr, int scopeId) + private static InetAddress getByAddress(String host, byte[] addr, int scopeId) throws UnknownHostException { if (host != null && host.length() > 0 && host.charAt(0) == '[') { if (host.charAt(host.length()-1) == ']') { @@ -1678,7 +1678,7 @@ public static void clearDnsCache() { * @param netId the network to use for host resolution. * @return the {@code InetAddress} instance representing the host. * @throws UnknownHostException if the address lookup fails. - * @hide internal use only + * @hide */ public static InetAddress getByNameOnNet(String host, int netId) throws UnknownHostException { return impl.lookupAllHostAddr(host, netId)[0]; @@ -1692,7 +1692,7 @@ public static InetAddress getByNameOnNet(String host, int netId) throws UnknownH * @param netId the network to use for host resolution. * @return the array of addresses associated with the specified host. * @throws UnknownHostException if the address lookup fails. - * @hide internal use only + * @hide */ public static InetAddress[] getAllByNameOnNet(String host, int netId) throws UnknownHostException { return impl.lookupAllHostAddr(host, netId).clone(); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/InetSocketAddress.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/InetSocketAddress.java index 74b559bcf7..9f53d147f2 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/InetSocketAddress.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/InetSocketAddress.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, 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 @@ -168,7 +168,7 @@ public InetSocketAddress() { * A valid port value is between 0 and 65535. * A port number of {@code zero} will let the system pick up an * ephemeral port in a {@code bind} operation. - *

    + * * @param port The port number * @throws IllegalArgumentException if the port parameter is outside the specified * range of valid port values. @@ -188,7 +188,7 @@ public InetSocketAddress(int port) { * ephemeral port in a {@code bind} operation. *

    * A {@code null} address will assign the wildcard address. - *

    + * * @param addr The IP address * @param port The port number * @throws IllegalArgumentException if the port parameter is outside the specified @@ -217,11 +217,11 @@ public InetSocketAddress(InetAddress addr, int port) { * A valid port value is between 0 and 65535. * A port number of {@code zero} will let the system pick up an * ephemeral port in a {@code bind} operation. - *

    + * * @param hostname the Host name * @param port The port number * @throws IllegalArgumentException if the port parameter is outside the range - * of valid port values, or if the hostname parameter is null. + * of valid port values, or if the hostname parameter is {@code null}. * @throws SecurityException if a security manager is present and * permission to resolve the host name is * denied. @@ -254,14 +254,14 @@ private InetSocketAddress(int port, String hostname) { * A valid port value is between 0 and 65535. * A port number of {@code zero} will let the system pick up an * ephemeral port in a {@code bind} operation. - *

    + * * @param host the Host name * @param port The port number * @throws IllegalArgumentException if the port parameter is outside * the range of valid port values, or if the hostname - * parameter is null. + * parameter is {@code null}. * @see #isUnresolved() - * @return a {@code InetSocketAddress} representing the unresolved + * @return an {@code InetSocketAddress} representing the unresolved * socket address * @since 1.5 */ @@ -317,6 +317,13 @@ private void readObjectNoData() throw new InvalidObjectException("Stream data required"); } + /* J2ObjC modified + private static final jdk.internal.misc.Unsafe UNSAFE + = jdk.internal.misc.Unsafe.getUnsafe(); + private static final long FIELDS_OFFSET + = UNSAFE.objectFieldOffset(InetSocketAddress.class, "holder"); + */ + private static final long FIELDS_OFFSET; private static final sun.misc.Unsafe UNSAFE; static { @@ -340,10 +347,9 @@ public final int getPort() { } /** - * * Gets the {@code InetAddress}. * - * @return the InetAdress or {@code null} if it is unresolved. + * @return the InetAddress or {@code null} if it is unresolved. */ public final InetAddress getAddress() { return holder.getAddress(); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/JarURLConnection.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/JarURLConnection.java index 70dedec795..c5acbf4b65 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/JarURLConnection.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/JarURLConnection.java @@ -173,7 +173,18 @@ private void parseSpecs(URL url) throws MalformedURLException { } jarFileURL = new URL(spec.substring(0, separator++)); + + // Android-removed: runtime versioning is unsupported + /* + * The url argument may have had a runtime fragment appended, so + * we need to add a runtime fragment to the jarFileURL to enable + * runtime versioning when the underlying jar file is opened. + * + if ("runtime".equals(url.getRef())) { + jarFileURL = new URL(jarFileURL, "#runtime"); + } entryName = null; + */ /* if ! is the last letter of the innerURL, entryName is null */ if (++separator != spec.length()) { @@ -246,7 +257,7 @@ public Manifest getManifest() throws IOException { * @see #getJarEntry */ public JarEntry getJarEntry() throws IOException { - return getJarFile().getJarEntry(entryName); + return entryName == null ? null : getJarFile().getJarEntry(entryName); } /** diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/MalformedURLException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/MalformedURLException.java index 7aef75c782..5f9ab5111a 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/MalformedURLException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/MalformedURLException.java @@ -33,7 +33,7 @@ * string could not be parsed. * * @author Arthur van Hoff - * @since JDK1.0 + * @since 1.0 */ public class MalformedURLException extends IOException { private static final long serialVersionUID = -182787522200415866L; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/MulticastSocket.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/MulticastSocket.java index 83a18c3a3d..5b5863f984 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/MulticastSocket.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/MulticastSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,9 @@ package java.net; import java.io.IOException; +import java.util.Collections; import java.util.Enumeration; +import java.util.Set; // Android-changed: Updated example code to handle non-ASCII characters /** @@ -79,7 +81,7 @@ * Currently applets are not allowed to use multicast sockets. * * @author Pavani Diwanji - * @since JDK1.1 + * @since 1.1 */ public class MulticastSocket extends DatagramSocket { @@ -93,21 +95,22 @@ class MulticastSocket extends DatagramSocket { /** * Create a multicast socket. * - *

    If there is a security manager, - * its {@code checkListen} method is first called - * with 0 as its argument to ensure the operation is allowed. - * This could result in a SecurityException. + *

    + * If there is a security manager, its {@code checkListen} method is first + * called with 0 as its argument to ensure the operation is allowed. This + * could result in a SecurityException. *

    * When the socket is created the - * {@link DatagramSocket#setReuseAddress(boolean)} method is - * called to enable the SO_REUSEADDR socket option. + * {@link DatagramSocket#setReuseAddress(boolean)} method is called to + * enable the SO_REUSEADDR socket option. * - * @exception IOException if an I/O exception occurs - * while creating the MulticastSocket - * @exception SecurityException if a security manager exists and its - * {@code checkListen} method doesn't allow the operation. + * @exception IOException if an I/O exception occurs while creating the + * MulticastSocket + * @exception SecurityException if a security manager exists and its + * {@code checkListen} method doesn't allow the operation. * @see SecurityManager#checkListen * @see java.net.DatagramSocket#setReuseAddress(boolean) + * @see java.net.DatagramSocketImpl#setOption(SocketOption, Object) */ public MulticastSocket() throws IOException { this(new InetSocketAddress(0)); @@ -173,8 +176,9 @@ public MulticastSocket(SocketAddress bindaddr) throws IOException { try { bind(bindaddr); } finally { - if (!isBound()) + if (!isBound()) { close(); + } } } } @@ -290,8 +294,9 @@ public int getTimeToLive() throws IOException { * * @param mcastaddr is the multicast address to join * - * @exception IOException if there is an error joining - * or when the address is not a multicast address. + * @exception IOException if there is an error joining, or when the address + * is not a multicast address, or the platform does not support + * multicasting * @exception SecurityException if a security manager exists and its * {@code checkMulticast} method doesn't allow the join. * @@ -374,8 +379,9 @@ public void leaveGroup(InetAddress mcastaddr) throws IOException { * {@link MulticastSocket#setInterface(InetAddress)} or * {@link MulticastSocket#setNetworkInterface(NetworkInterface)} * - * @exception IOException if there is an error joining - * or when the address is not a multicast address. + * @exception IOException if there is an error joining, or when the address + * is not a multicast address, or the platform does not support + * multicasting * @exception SecurityException if a security manager exists and its * {@code checkMulticast} method doesn't allow the join. * @throws IllegalArgumentException if mcastaddr is null or is a @@ -709,4 +715,24 @@ public void send(DatagramPacket p, byte ttl) } // synch p } //synch ttl } //method + + private static Set> options; + private static boolean optionsSet = false; + + @Override + public Set> supportedOptions() { + synchronized (MulticastSocket.class) { + if (optionsSet) { + return options; + } + try { + DatagramSocketImpl impl = getImpl(); + options = Collections.unmodifiableSet(impl.supportedOptions()); + } catch (SocketException ex) { + options = Collections.emptySet(); + } + optionsSet = true; + return options; + } + } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/NetPermission.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/NetPermission.java index b5a0eabcc2..10918e0f9a 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/NetPermission.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/NetPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/NetworkInterface.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/NetworkInterface.java index 89cb000a28..4715073ec6 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/NetworkInterface.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/NetworkInterface.java @@ -40,6 +40,10 @@ import libcore.io.IoUtils; import libcore.io.Libcore; /* J2ObjC removed. +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; +import dalvik.annotation.compat.VersionCodes; import android.system.StructIfaddrs; import sun.security.action.*; import java.security.AccessController; @@ -49,7 +53,7 @@ // Android-note: NetworkInterface has been rewritten to avoid native code. // Fix upstream bug not returning link-down interfaces. http://b/26238832 -// Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849 +// Android-added: Document restrictions for non-system apps. http://b/170188668 /** * This class represents a Network Interface made up of a name, * and a list of IP addresses assigned to this interface. @@ -60,13 +64,32 @@ *

    * Note that information about * {@link NetworkInterface}s may be restricted. For example, non-system apps - * with {@code targetSdkVersion >= android.internal.Build.VERSION_CODES.R} will only - * have access to information about {@link NetworkInterface}s that are + * will only have access to information about {@link NetworkInterface}s that are * associated with an {@link InetAddress}. * * @since 1.4 */ public final class NetworkInterface { + // Android-added: Anonymized address for apps targeting old API versions. http://b/170188668 + /** + * If this change is enabled, {@link #getHardwareAddress()} returns null when the hardware + * address is inaccessible. If the change is disabled, the + * default MAC address (02:00:00:00:00:00) is returned instead. + * + * @hide + */ + /* J2ObjC removed + @ChangeId + @EnabledSince(targetSdkVersion=VersionCodes.R) + */ + public static final long RETURN_NULL_HARDWARE_ADDRESS = 170188668L; + // The default hardware address is a zeroed-out MAC address with only its + // locally-administered bit set, returned to apps targeting older API versions if they would + // otherwise see a null MAC address. + // Matches android.net.wifi.WifiInfo.DEFAULT_MAC_ADDRESS + private static final byte[] DEFAULT_MAC_ADDRESS = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; + private String name; private String displayName; private int index; @@ -275,7 +298,7 @@ public String getDisplayName() { return "".equals(displayName) ? null : displayName; } - // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849 + // Android-added: Document restrictions for non-system apps. http://b/170188668 /** * Searches for the network interface with the specified name. * @@ -310,7 +333,7 @@ public static NetworkInterface getByName(String name) throws SocketException { return getByName0(name); } - // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849 + // Android-added: Document restrictions for non-system apps. http://b/170188668 /** * Get a network interface given its index. * @@ -385,7 +408,8 @@ public static NetworkInterface getByInetAddress(InetAddress addr) throws SocketE return getByInetAddress0(addr); } - // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849 + // Android-added: Document restrictions for non-system apps. http://b/170188668 + // Android-added: Note about NullPointerException in older versions. http://b/206053582 /** * Returns all the interfaces on this machine. The {@code Enumeration} * contains at least one element, possibly representing a loopback @@ -395,10 +419,12 @@ public static NetworkInterface getByInetAddress(InetAddress addr) throws SocketE * NOTE: can use getNetworkInterfaces()+getInetAddresses() * to obtain all IP addresses for this node *

    - * For non-system apps with - * {@code targetSdkVersion >= android.internal.Build.VERSION_CODES.R}, this - * method will only return information for {@link NetworkInterface}s that - * are associated with an {@link InetAddress}. + * For non-system apps, this method will only return information for + * {@link NetworkInterface}s associated with an {@link InetAddress}. + *

    + * ANDROID NOTE: On Android versions before S (API level 31), this method may throw a + * NullPointerException if called in an environment where there is a virtual + * interface without a parent interface present. * * @return an Enumeration of NetworkInterfaces found on this machine * that are accessible. @@ -446,6 +472,10 @@ private static NetworkInterface[] getAll() throws SocketException { StructIfaddrs[] ifaddrs; try { ifaddrs = Libcore.os.getifaddrs(); + // Defensive check for b/217749090: ifaddrs should never be null. + if (ifaddrs == null) { + throw new SocketException("Failed to query network interfaces."); + } } catch (ErrnoException e) { throw e.rethrowAsSocketException(); } @@ -507,8 +537,11 @@ private static NetworkInterface[] getAll() throws SocketException { NetworkInterface parent = nis.get(parentName); ni.virtual = true; - ni.parent = parent; - parent.childs.add(ni); + + if (parent != null) { + ni.parent = parent; + parent.childs.add(ni); + } } } @@ -599,7 +632,7 @@ public boolean supportsMulticast() throws SocketException { return supportsMulticast0(name, index); } - // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849 + // Android-added: Restrictions for non-system apps. http://b/170188668 /** * Returns the hardware address (usually MAC) of the interface if it * has one and if it can be accessed given the current privileges. @@ -611,8 +644,8 @@ public boolean supportsMulticast() throws SocketException { * manager is set and the caller does not have the permission * NetPermission("getNetworkInformation"). For example, this * method will generally return {@code null} when called by - * non-system apps having - * {@code targetSdkVersion >= android.internal.Build.VERSION_CODES.R}. + * non-system apps (or 02:00:00:00:00:00 for apps having + * {@code targetSdkVersion < android.os.Build.VERSION_CODES.R}). * * @exception SocketException if an I/O error occurs. * @since 1.6 @@ -631,6 +664,15 @@ public byte[] getHardwareAddress() throws SocketException { if (ni == null) { throw new SocketException("NetworkInterface doesn't exist anymore"); } + + /* J2ObjC removed + // Return 02:00:00:00:00:00 for apps having a target SDK version < R if they would have + // otherwise gotten a null MAC address (excluding loopback). + if (ni.hardwareAddr == null && !"lo".equals(name) + && !Compatibility.isChangeEnabled(RETURN_NULL_HARDWARE_ADDRESS)) { + return DEFAULT_MAC_ADDRESS.clone(); + } + */ return ni.hardwareAddr; // END Android-changed: Fix upstream not returning link-down interfaces. http://b/26238832 } @@ -684,6 +726,7 @@ public boolean isVirtual() { private native static boolean isLoopback0(String name, int ind) throws SocketException; private native static boolean supportsMulticast0(String name, int ind) throws SocketException; private native static boolean isP2P0(String name, int ind) throws SocketException; + private native static byte[] getMacAddr0(byte[] inAddr, String name, int ind) throws SocketException; private native static int getMTU0(String name, int ind) throws SocketException; /* J2ObjC removed: use native methods instead. diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/NoRouteToHostException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/NoRouteToHostException.java index 76f0814cb4..cf6e68cfa5 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/NoRouteToHostException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/NoRouteToHostException.java @@ -31,7 +31,7 @@ * host cannot be reached because of an intervening firewall, or * if an intermediate router is down. * - * @since JDK1.1 + * @since 1.1 */ public class NoRouteToHostException extends SocketException { private static final long serialVersionUID = -1897550894873493790L; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/PlainDatagramSocketImpl.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/PlainDatagramSocketImpl.java index cd00b0bd88..ef776f779f 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/PlainDatagramSocketImpl.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/PlainDatagramSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007,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 @@ -26,6 +26,32 @@ import java.io.IOException; +/* J2ObjC removed +import android.system.ErrnoException; +import android.system.StructGroupReq; + + +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.*; +*/ + +// Android-changed: Rewritten to use android.system POSIX calls and assume AF_INET6. /* * On Unix systems we simply delegate to native methods. * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/PlainSocketImpl.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/PlainSocketImpl.java index 0734662f3b..ce4d6a6355 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/PlainSocketImpl.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/PlainSocketImpl.java @@ -37,23 +37,27 @@ class PlainSocketImpl extends AbstractPlainSocketImpl { static { - initProto(); + initProto(); } /** * Constructs an empty instance. */ PlainSocketImpl() { - this(new FileDescriptor()); + // Android-changed: Let PlainSocketImpl construct its own FileDescriptor. + this.fd = new FileDescriptor(); } /** * Constructs an instance with the given file descriptor. */ + // Android-removed: Let PlainSocketImpl construct its own FileDescriptor. + // J2ObjC modified PlainSocketImpl(FileDescriptor fd) { this.fd = fd; } + private static native void initProto(); native void socketCreate(boolean isServer) throws IOException; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ProtocolException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ProtocolException.java index 594428255c..31d044927b 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ProtocolException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ProtocolException.java @@ -33,7 +33,7 @@ * protocol, such as a TCP error. * * @author Chris Warth - * @since JDK1.0 + * @since 1.0 */ public class ProtocolException extends IOException { @@ -43,10 +43,10 @@ class ProtocolException extends IOException { * Constructs a new {@code ProtocolException} with the * specified detail message. * - * @param host the detail message. + * @param message the detail message. */ - public ProtocolException(String host) { - super(host); + public ProtocolException(String message) { + super(message); } /** diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Proxy.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Proxy.java index 8ba020ef48..672235b527 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Proxy.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Proxy.java @@ -69,7 +69,7 @@ public enum Type { * {@code Socket s = new Socket(Proxy.NO_PROXY);} * */ - public final static Proxy NO_PROXY = new Proxy(); + public static final Proxy NO_PROXY = new Proxy(); // Creates the proxy that represents a {@code DIRECT} connection. private Proxy() { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ResponseCache.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ResponseCache.java index 7da0ae2775..dc203a32a6 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ResponseCache.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ResponseCache.java @@ -82,7 +82,7 @@ public abstract class ResponseCache { * @return the system-wide {@code ResponseCache} * @since 1.5 */ - public synchronized static ResponseCache getDefault() { + public static synchronized ResponseCache getDefault() { SecurityManager sm = System.getSecurityManager(); if (sm != null) { /* J2ObjC removed. @@ -107,7 +107,7 @@ public synchronized static ResponseCache getDefault() { * @see #getDefault() * @since 1.5 */ - public synchronized static void setDefault(ResponseCache responseCache) { + public static synchronized void setDefault(ResponseCache responseCache) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { /* J2ObjC removed. diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ServerSocket.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ServerSocket.java index 334314d708..a8ad7692da 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ServerSocket.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/ServerSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2018, 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 @@ -24,14 +24,20 @@ */ package java.net; - +/* J2ObjC removed +import sun.security.util.SecurityConstants; +*/ import java.io.FileDescriptor; import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.nio.channels.ServerSocketChannel; /* J2ObjC removed import java.security.AccessController; import java.security.PrivilegedExceptionAction; - */ +*/ +import java.util.Set; +import java.util.Collections; /** * This class implements server sockets. A server socket waits for @@ -48,7 +54,7 @@ * @see java.net.SocketImpl * @see java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory) * @see java.nio.channels.ServerSocketChannel - * @since JDK1.0 + * @since 1.0 */ public class ServerSocket implements java.io.Closeable { @@ -73,12 +79,29 @@ class ServerSocket implements java.io.Closeable { /** * Package-private constructor to create a ServerSocket associated with * the given SocketImpl. + * + * @throws SecurityException if a security manager is set and + * its {@code checkPermission} method doesn't allow + * {@code NetPermission("setSocketImpl")}. */ ServerSocket(SocketImpl impl) { + checkPermission(); this.impl = impl; impl.setServerSocket(this); } + private static Void checkPermission() { + // BEGIN Android-removed: SM is no-op. + /* + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(SecurityConstants.SET_SOCKETIMPL_PERMISSION); + } + */ + // END Android-removed: SM is no-op. + return null; + } + /** * Creates an unbound server socket. * @@ -159,7 +182,6 @@ public ServerSocket(int port) throws IOException { * or may choose to ignore the parameter altogther. The value provided * should be greater than {@code 0}. If it is less than or equal to * {@code 0}, then an implementation specific default will be used. - *

    * * @param port the port number, or {@code 0} to use a port * number that is automatically allocated. @@ -208,7 +230,7 @@ public ServerSocket(int port, int backlog) throws IOException { * or may choose to ignore the parameter altogther. The value provided * should be greater than {@code 0}. If it is less than or equal to * {@code 0}, then an implementation specific default will be used. - *

    + * * @param port the port number, or {@code 0} to use a port * number that is automatically allocated. * @param backlog requested maximum length of the queue of incoming @@ -226,7 +248,7 @@ public ServerSocket(int port, int backlog) throws IOException { * @see SocketOptions * @see SocketImpl * @see SecurityManager#checkListen - * @since JDK1.1 + * @since 1.1 */ public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException { setImpl(); @@ -324,7 +346,7 @@ void createImpl() throws SocketException { *

    * If the address is {@code null}, then the system will pick up * an ephemeral port and a valid local address to bind the socket. - *

    + * * @param endpoint The IP address and port number to bind to. * @throws IOException if the bind operation fails, or if the socket * is already bound. @@ -535,7 +557,7 @@ public Socket accept() throws IOException { * and the channel is in non-blocking mode * @throws IOException if an I/O error occurs when waiting * for a connection. - * @since JDK1.1 + * @since 1.1 * @revised 1.4 * @spec JSR-51 */ @@ -552,6 +574,8 @@ protected final void implAccept(Socket s) throws IOException { si.address = new InetAddress(); si.fd = new FileDescriptor(); getImpl().accept(si); + // Android-removed: SocketCleanable is unsupported + // SocketCleanable.register(si.fd); // raw fd has been set SecurityManager security = System.getSecurityManager(); if (security != null) { @@ -652,13 +676,13 @@ public boolean isClosed() { * @param timeout the specified timeout, in milliseconds * @exception SocketException if there is an error in * the underlying protocol, such as a TCP error. - * @since JDK1.1 + * @since 1.1 * @see #getSoTimeout() */ public synchronized void setSoTimeout(int timeout) throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); - getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); + getImpl().setOption(SocketOptions.SO_TIMEOUT, timeout); } /** @@ -666,7 +690,7 @@ public synchronized void setSoTimeout(int timeout) throws SocketException { * 0 returns implies that the option is disabled (i.e., timeout of infinity). * @return the {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT} value * @exception IOException if an I/O error occurs - * @since JDK1.1 + * @since 1.1 * @see #setSoTimeout(int) */ public synchronized int getSoTimeout() throws IOException { @@ -855,7 +879,7 @@ public synchronized void setReceiveBufferSize (int size) throws SocketException } if (isClosed()) throw new SocketException("Socket is closed"); - getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size)); + getImpl().setOption(SocketOptions.SO_RCVBUF, size); } /** @@ -929,6 +953,123 @@ public void setPerformancePreferences(int connectionTime, /* Not implemented yet */ } + /** + * Sets the value of a socket option. + * + * @param The type of the socket option value + * @param name The socket option + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * @return this ServerSocket + * + * @throws UnsupportedOperationException if the server socket does not + * support the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 9 + */ + public ServerSocket setOption(SocketOption name, T value) + throws IOException + { + getImpl().setOption(name, value); + return this; + } + + /** + * Returns the value of a socket option. + * + * @param The type of the socket option value + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the server socket does not + * support the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 9 + */ + public T getOption(SocketOption name) throws IOException { + return getImpl().getOption(name); + } + + private static Set> options; + private static boolean optionsSet = false; + + /** + * Returns a set of the socket options supported by this server socket. + * + * This method will continue to return the set of options even after + * the socket has been closed. + * + * @return A set of the socket options supported by this socket. This set + * may be empty if the socket's SocketImpl cannot be created. + * + * @since 9 + */ + public Set> supportedOptions() { + synchronized (ServerSocket.class) { + if (optionsSet) { + return options; + } + try { + SocketImpl impl = getImpl(); + options = Collections.unmodifiableSet(impl.supportedOptions()); + } catch (IOException e) { + options = Collections.emptySet(); + } + optionsSet = true; + return options; + } + } + + // BEGIN Android-removed: Pruned unused access interfaces. + /* + static { + SharedSecrets.setJavaNetSocketAccess( + new JavaNetSocketAccess() { + @Override + public ServerSocket newServerSocket(SocketImpl impl) { + return new ServerSocket(impl); + } + + @Override + public SocketImpl newSocketImpl(Class implClass) { + try { + Constructor ctor = + implClass.getDeclaredConstructor(); + return ctor.newInstance(); + } catch (NoSuchMethodException | InstantiationException | + IllegalAccessException | InvocationTargetException e) { + throw new AssertionError(e); + } + } + } + ); + } + */ + // Android-added: getFileDescriptor$(), for testing / internal use. /** * @hide internal use only diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Socket.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Socket.java index 9767e8a1e8..a21f1f94f4 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Socket.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/Socket.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,9 @@ */ package java.net; +/* J2ObjC removed. +import sun.security.util.SecurityConstants; + */ import java.io.FileDescriptor; import java.io.InputStream; @@ -36,6 +39,8 @@ import java.security.PrivilegedExceptionAction; import java.security.PrivilegedAction; */ +import java.util.Set; +import java.util.Collections; /** * This class implements client sockets (also called just @@ -52,7 +57,7 @@ * @see java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory) * @see java.net.SocketImpl * @see java.nio.channels.SocketChannel - * @since JDK1.0 + * @since 1.0 */ public class Socket implements java.io.Closeable { @@ -81,7 +86,7 @@ class Socket implements java.io.Closeable { * Creates an unconnected socket, with the * system-default type of SocketImpl. * - * @since JDK1.1 + * @since 1.1 * @revised 1.4 */ public Socket() { @@ -161,15 +166,20 @@ public Socket(Proxy proxy) { /** * Creates an unconnected Socket with a user-specified * SocketImpl. - *

    + * * @param impl an instance of a SocketImpl * the subclass wishes to use on the Socket. * * @exception SocketException if there is an error in the underlying protocol, * such as a TCP error. - * @since JDK1.1 + * + * @throws SecurityException if {@code impl} is non-null and a security manager is set + * and its {@code checkPermission} method doesn't allow {@code NetPermission("setSocketImpl")}. + * + * @since 1.1 */ protected Socket(SocketImpl impl) throws SocketException { + checkPermission(impl); this.impl = impl; if (impl != null) { checkOldImpl(); @@ -177,6 +187,21 @@ protected Socket(SocketImpl impl) throws SocketException { } } + private static Void checkPermission(SocketImpl impl) { + // BEGIN Android-removed: SM is no-op. + /* + if (impl == null) { + return null; + } + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(SecurityConstants.SET_SOCKETIMPL_PERMISSION); + } + */ + // END Android-removed: SM is no-op. + return null; + } + /** * Creates a stream socket and connects it to the specified port * number on the named host. @@ -286,7 +311,7 @@ public Socket(InetAddress address, int port) throws IOException { * parameter is outside the specified range of valid port values, * which is between 0 and 65535, inclusive. * @see SecurityManager#checkConnect - * @since JDK1.1 + * @since 1.1 */ public Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException { @@ -328,7 +353,7 @@ public Socket(String host, int port, InetAddress localAddr, * which is between 0 and 65535, inclusive. * @exception NullPointerException if {@code address} is null. * @see SecurityManager#checkConnect - * @since JDK1.1 + * @since 1.1 */ public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException { @@ -525,7 +550,7 @@ private void checkOldImpl() { /* J2ObjC modified. oldImpl = AccessController.doPrivileged - (new PrivilegedAction() { + (new PrivilegedAction<>() { public Boolean run() { Class clazz = impl.getClass(); while (true) { @@ -765,7 +790,7 @@ public InetAddress getInetAddress() { * @return the local address to which the socket is bound, * the loopback address if denied by the security manager, or * the wildcard address if the socket is closed or not bound yet. - * @since JDK1.1 + * @since 1.1 * * @see SecurityManager#checkConnect */ @@ -964,12 +989,11 @@ public InputStream getInputStream() throws IOException { throw new SocketException("Socket is not connected"); if (isInputShutdown()) throw new SocketException("Socket input is shutdown"); - final Socket s = this; InputStream is = null; /* J2ObjC modified. try { is = AccessController.doPrivileged( - new PrivilegedExceptionAction() { + new PrivilegedExceptionAction<>() { public InputStream run() throws IOException { return impl.getInputStream(); } @@ -1007,12 +1031,11 @@ public OutputStream getOutputStream() throws IOException { throw new SocketException("Socket is not connected"); if (isOutputShutdown()) throw new SocketException("Socket output is shutdown"); - final Socket s = this; OutputStream os = null; /* J2ObjC modified. try { os = AccessController.doPrivileged( - new PrivilegedExceptionAction() { + new PrivilegedExceptionAction<>() { public OutputStream run() throws IOException { return impl.getOutputStream(); } @@ -1035,7 +1058,7 @@ public OutputStream run() throws IOException { * @exception SocketException if there is an error * in the underlying protocol, such as a TCP error. * - * @since JDK1.1 + * @since 1.1 * * @see #getTcpNoDelay() */ @@ -1052,7 +1075,7 @@ public void setTcpNoDelay(boolean on) throws SocketException { * {@link SocketOptions#TCP_NODELAY TCP_NODELAY} is enabled. * @exception SocketException if there is an error * in the underlying protocol, such as a TCP error. - * @since JDK1.1 + * @since 1.1 * @see #setTcpNoDelay(boolean) */ public boolean getTcpNoDelay() throws SocketException { @@ -1073,21 +1096,21 @@ public boolean getTcpNoDelay() throws SocketException { * @exception SocketException if there is an error * in the underlying protocol, such as a TCP error. * @exception IllegalArgumentException if the linger value is negative. - * @since JDK1.1 + * @since 1.1 * @see #getSoLinger() */ public void setSoLinger(boolean on, int linger) throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); if (!on) { - getImpl().setOption(SocketOptions.SO_LINGER, new Boolean(on)); + getImpl().setOption(SocketOptions.SO_LINGER, on); } else { if (linger < 0) { throw new IllegalArgumentException("invalid value for SO_LINGER"); } if (linger > 65535) linger = 65535; - getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger)); + getImpl().setOption(SocketOptions.SO_LINGER, linger); } } @@ -1101,7 +1124,7 @@ public void setSoLinger(boolean on, int linger) throws SocketException { * @return the setting for {@link SocketOptions#SO_LINGER SO_LINGER}. * @exception SocketException if there is an error * in the underlying protocol, such as a TCP error. - * @since JDK1.1 + * @since 1.1 * @see #setSoLinger(boolean, int) */ public int getSoLinger() throws SocketException { @@ -1201,7 +1224,7 @@ public boolean getOOBInline() throws SocketException { * @param timeout the specified timeout, in milliseconds. * @exception SocketException if there is an error * in the underlying protocol, such as a TCP error. - * @since JDK 1.1 + * @since 1.1 * @see #getSoTimeout() */ public synchronized void setSoTimeout(int timeout) throws SocketException { @@ -1210,7 +1233,7 @@ public synchronized void setSoTimeout(int timeout) throws SocketException { if (timeout < 0) throw new IllegalArgumentException("timeout can't be negative"); - getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); + getImpl().setOption(SocketOptions.SO_TIMEOUT, timeout); } /** @@ -1221,7 +1244,7 @@ public synchronized void setSoTimeout(int timeout) throws SocketException { * @exception SocketException if there is an error * in the underlying protocol, such as a TCP error. * - * @since JDK1.1 + * @since 1.1 * @see #setSoTimeout(int) */ public synchronized int getSoTimeout() throws SocketException { @@ -1266,7 +1289,7 @@ public synchronized void setSendBufferSize(int size) } if (isClosed()) throw new SocketException("Socket is closed"); - getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size)); + getImpl().setOption(SocketOptions.SO_SNDBUF, size); } /** @@ -1317,7 +1340,7 @@ public synchronized int getSendBufferSize() throws SocketException { *

      *
    1. For sockets accepted from a ServerSocket, this must be done by calling * {@link ServerSocket#setReceiveBufferSize(int)} before the ServerSocket - * is bound to a local address.

    2. + * is bound to a local address. *
    3. For client sockets, setReceiveBufferSize() must be called before * connecting the socket to its remote peer.
    * @param size the size to which to set the receive buffer @@ -1340,7 +1363,7 @@ public synchronized void setReceiveBufferSize(int size) } if (isClosed()) throw new SocketException("Socket is closed"); - getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size)); + getImpl().setOption(SocketOptions.SO_RCVBUF, size); } /** @@ -1806,9 +1829,104 @@ public void setPerformancePreferences(int connectionTime, /* Not implemented yet */ } + + /** + * Sets the value of a socket option. + * + * @param The type of the socket option value + * @param name The socket option + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * @return this Socket + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 9 + */ + public Socket setOption(SocketOption name, T value) throws IOException { + getImpl().setOption(name, value); + return this; + } + + /** + * Returns the value of a socket option. + * + * @param The type of the socket option value + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 9 + */ + @SuppressWarnings("unchecked") + public T getOption(SocketOption name) throws IOException { + return getImpl().getOption(name); + } + + private static Set> options; + private static boolean optionsSet = false; + + /** + * Returns a set of the socket options supported by this socket. + * + * This method will continue to return the set of options even after + * the socket has been closed. + * + * @return A set of the socket options supported by this socket. This set + * may be empty if the socket's SocketImpl cannot be created. + * + * @since 9 + */ + public Set> supportedOptions() { + synchronized (Socket.class) { + if (optionsSet) { + return options; + } + try { + SocketImpl impl = getImpl(); + options = Collections.unmodifiableSet(impl.supportedOptions()); + } catch (IOException e) { + options = Collections.emptySet(); + } + optionsSet = true; + return options; + } + } + // Android-added: getFileDescriptor$() method for testing and internal use. /** + * Gets socket's underlying {@link FileDescriptor}. + * * @hide internal use only + * + * @return socket's underlying {@link FileDescriptor}. */ public FileDescriptor getFileDescriptor$() { return impl.getFileDescriptor(); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketException.java index 64ae771080..679c1dc32d 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketException.java @@ -32,7 +32,7 @@ * Thrown to indicate that there is an error creating or accessing a Socket. * * @author Jonathan Payne - * @since JDK1.0 + * @since 1.0 */ public class SocketException extends IOException { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketImpl.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketImpl.java index 983ad2e60f..0c5ab4de4a 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketImpl.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketImpl.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.FileDescriptor; +import java.util.Set; /** * The abstract class {@code SocketImpl} is a common superclass @@ -41,7 +42,7 @@ * described, without attempting to go through a firewall or proxy. * * @author unascribed - * @since JDK1.0 + * @since 1.0 */ public abstract class SocketImpl implements SocketOptions { /** @@ -232,7 +233,11 @@ protected FileDescriptor getFileDescriptor() { // Android-added: getFD$() for testing. /** + * Gets socket's underlying {@link FileDescriptor}. + * * @hide used by java.nio tests + * + * @return socket's underlying {@link FileDescriptor}. */ public FileDescriptor getFD$() { return fd; @@ -344,7 +349,7 @@ void reset() throws IOException { * latency, and low latency above short connection time, then it could * invoke this method with the values {@code (0, 1, 2)}. * - * By default, this method does nothing, unless it is overridden in a + * By default, this method does nothing, unless it is overridden in * a sub-class. * * @param connectionTime @@ -368,43 +373,123 @@ protected void setPerformancePreferences(int connectionTime, /* Not implemented yet */ } - void setOption(SocketOption name, T value) throws IOException { - if (name == StandardSocketOptions.SO_KEEPALIVE) { + /** + * Called to set a socket option. + * + * @param The type of the socket option value + * @param name The socket option + * + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * + * @throws UnsupportedOperationException if the SocketImpl does not + * support the option + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @since 9 + */ + protected void setOption(SocketOption name, T value) throws IOException { + if (name == StandardSocketOptions.SO_KEEPALIVE && + (getSocket() != null)) { setOption(SocketOptions.SO_KEEPALIVE, value); - } else if (name == StandardSocketOptions.SO_SNDBUF) { + } else if (name == StandardSocketOptions.SO_SNDBUF && + (getSocket() != null)) { setOption(SocketOptions.SO_SNDBUF, value); } else if (name == StandardSocketOptions.SO_RCVBUF) { setOption(SocketOptions.SO_RCVBUF, value); } else if (name == StandardSocketOptions.SO_REUSEADDR) { setOption(SocketOptions.SO_REUSEADDR, value); - } else if (name == StandardSocketOptions.SO_LINGER) { + } else if (name == StandardSocketOptions.SO_REUSEPORT && + supportedOptions().contains(name)) { + setOption(SocketOptions.SO_REUSEPORT, value); + } else if (name == StandardSocketOptions.SO_LINGER && + (getSocket() != null)) { setOption(SocketOptions.SO_LINGER, value); } else if (name == StandardSocketOptions.IP_TOS) { setOption(SocketOptions.IP_TOS, value); - } else if (name == StandardSocketOptions.TCP_NODELAY) { + } else if (name == StandardSocketOptions.TCP_NODELAY && + (getSocket() != null)) { setOption(SocketOptions.TCP_NODELAY, value); } else { throw new UnsupportedOperationException("unsupported option"); } } - T getOption(SocketOption name) throws IOException { - if (name == StandardSocketOptions.SO_KEEPALIVE) { + /** + * Called to get a socket option. + * + * @param The type of the socket option value + * @param name The socket option + * + * @return the value of the named option + * + * @throws UnsupportedOperationException if the SocketImpl does not + * support the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @since 9 + */ + @SuppressWarnings("unchecked") + protected T getOption(SocketOption name) throws IOException { + if (name == StandardSocketOptions.SO_KEEPALIVE && + (getSocket() != null)) { return (T)getOption(SocketOptions.SO_KEEPALIVE); - } else if (name == StandardSocketOptions.SO_SNDBUF) { + } else if (name == StandardSocketOptions.SO_SNDBUF && + (getSocket() != null)) { return (T)getOption(SocketOptions.SO_SNDBUF); } else if (name == StandardSocketOptions.SO_RCVBUF) { return (T)getOption(SocketOptions.SO_RCVBUF); } else if (name == StandardSocketOptions.SO_REUSEADDR) { return (T)getOption(SocketOptions.SO_REUSEADDR); - } else if (name == StandardSocketOptions.SO_LINGER) { + } else if (name == StandardSocketOptions.SO_REUSEPORT && + supportedOptions().contains(name)) { + return (T)getOption(SocketOptions.SO_REUSEPORT); + } else if (name == StandardSocketOptions.SO_LINGER && + (getSocket() != null)) { return (T)getOption(SocketOptions.SO_LINGER); } else if (name == StandardSocketOptions.IP_TOS) { return (T)getOption(SocketOptions.IP_TOS); - } else if (name == StandardSocketOptions.TCP_NODELAY) { + } else if (name == StandardSocketOptions.TCP_NODELAY && + (getSocket() != null)) { return (T)getOption(SocketOptions.TCP_NODELAY); } else { throw new UnsupportedOperationException("unsupported option"); } } + + private static final Set> socketOptions; + + private static final Set> serverSocketOptions; + + static { + socketOptions = Set.of(StandardSocketOptions.SO_KEEPALIVE, + StandardSocketOptions.SO_SNDBUF, + StandardSocketOptions.SO_RCVBUF, + StandardSocketOptions.SO_REUSEADDR, + StandardSocketOptions.SO_LINGER, + StandardSocketOptions.IP_TOS, + StandardSocketOptions.TCP_NODELAY); + + serverSocketOptions = Set.of(StandardSocketOptions.SO_RCVBUF, + StandardSocketOptions.SO_REUSEADDR, + StandardSocketOptions.IP_TOS); + } + + /** + * Returns a set of SocketOptions supported by this impl + * and by this impl's socket (Socket or ServerSocket) + * + * @return a Set of SocketOptions + * + * @since 9 + */ + protected Set> supportedOptions() { + if (getSocket() != null) { + return socketOptions; + } else { + return serverSocketOptions; + } + } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketImplFactory.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketImplFactory.java index 7aa6363b4f..57b40da189 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketImplFactory.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketImplFactory.java @@ -34,7 +34,7 @@ * @author Arthur van Hoff * @see java.net.Socket * @see java.net.ServerSocket - * @since JDK1.0 + * @since 1.0 */ public interface SocketImplFactory { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketInputStream.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketInputStream.java index d3c015bdd6..f47eee6ad3 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketInputStream.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketInputStream.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2018, 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 @@ -51,7 +51,7 @@ class SocketInputStream extends FileInputStream //} private boolean eof; - private final AbstractPlainSocketImpl impl; + private AbstractPlainSocketImpl impl = null; private byte temp[]; @Weak private Socket socket = null; @@ -168,8 +168,6 @@ int read(byte b[], int off, int length, int timeout) throws IOException { + " off == " + off + " buffer length == " + b.length); } - boolean gotReset = false; - // acquire file descriptor and do the read FileDescriptor fd = impl.acquireFD(); try { @@ -180,29 +178,11 @@ int read(byte b[], int off, int length, int timeout) throws IOException { return n; } } catch (ConnectionResetException rstExc) { - gotReset = true; + impl.setConnectionReset(); } finally { impl.releaseFD(); } - /* - * We receive a "connection reset" but there may be bytes still - * buffered on the socket - */ - if (gotReset) { - impl.setConnectionResetPending(); - impl.acquireFD(); - try { - n = socketRead(fd, b, off, length, timeout); - if (n > 0) { - return n; - } - } catch (ConnectionResetException rstExc) { - } finally { - impl.releaseFD(); - } - } - /* * If we get here we are at EOF, the socket has been closed, * or the connection has been reset. @@ -210,9 +190,6 @@ int read(byte b[], int off, int length, int timeout) throws IOException { if (impl.isClosedOrPending()) { throw new SocketException("Socket closed"); } - if (impl.isConnectionResetPending()) { - impl.setConnectionReset(); - } if (impl.isConnectionReset()) { throw new SocketException("Connection reset"); } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketOptions.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketOptions.java index 7e1b0fc85b..2e9d28a3ce 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketOptions.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,8 +38,9 @@ * DatagramSocketImpl, you won't use these directly. There are * type-safe methods to get/set each of these options in Socket, ServerSocket, * DatagramSocket and MulticastSocket. - *

    + * * @author David Brown + * @since 1.1 */ @@ -61,21 +62,21 @@ public interface SocketOptions { * If the requested option is binary, it can be set using this method by * a java.lang.Boolean: *

    -     * s.setOption(TCP_NODELAY, new Boolean(true));
    +     * s.setOption(TCP_NODELAY, Boolean.TRUE);
          *    // OK - enables TCP_NODELAY, a binary option
          * 
    *
    - * Any option can be disabled using this method with a Boolean(false): + * Any option can be disabled using this method with a Boolean.FALSE: *
    -     * s.setOption(TCP_NODELAY, new Boolean(false));
    +     * s.setOption(TCP_NODELAY, Boolean.FALSE);
          *    // OK - disables TCP_NODELAY
    -     * s.setOption(SO_LINGER, new Boolean(false));
    +     * s.setOption(SO_LINGER, Boolean.FALSE);
          *    // OK - disables SO_LINGER
          * 
    *
    * For an option that has a notion of on and off, and requires * a non-boolean parameter, setting its value to anything other than - * Boolean(false) implicitly enables it. + * Boolean.FALSE implicitly enables it. *
    * Throws SocketException if the option is unrecognized, * the socket is closed, or some low-level error occurred @@ -91,8 +92,8 @@ public interface SocketOptions { /** * Fetch the value of an option. - * Binary options will return java.lang.Boolean(true) - * if enabled, java.lang.Boolean(false) if disabled, e.g.: + * Binary options will return java.lang.Boolean.TRUE + * if enabled, java.lang.Boolean.FALSE if disabled, e.g.: *
          * SocketImpl s;
          * ...
    @@ -105,13 +106,13 @@ public interface SocketOptions {
          * 

    * For options that take a particular type as a parameter, * getOption(int) will return the parameter's value, else - * it will return java.lang.Boolean(false): + * it will return java.lang.Boolean.FALSE: *

          * Object o = s.getOption(SO_LINGER);
          * if (o instanceof Integer) {
          *     System.out.print("Linger time is " + ((Integer)o).intValue());
          * } else {
    -     *   // the true type of o is java.lang.Boolean(false);
    +     *   // the true type of o is java.lang.Boolean.FALSE;
          * }
          * 
    * @@ -139,7 +140,7 @@ public interface SocketOptions { * @see Socket#getTcpNoDelay */ - @Native public final static int TCP_NODELAY = 0x0001; + @Native public static final int TCP_NODELAY = 0x0001; /** * Fetch the local address binding of a socket (this option cannot @@ -160,7 +161,7 @@ public interface SocketOptions { * @see DatagramSocket#getLocalAddress */ - @Native public final static int SO_BINDADDR = 0x000F; + @Native public static final int SO_BINDADDR = 0x000F; /** Sets SO_REUSEADDR for a socket. This is used only for MulticastSockets * in java, and it is set by default for MulticastSockets. @@ -168,7 +169,18 @@ public interface SocketOptions { * Valid for: DatagramSocketImpl */ - @Native public final static int SO_REUSEADDR = 0x04; + @Native public static final int SO_REUSEADDR = 0x04; + + /** Sets SO_REUSEPORT for a socket. This option enables and disables + * the ability to have multiple sockets listen to the same address + * and port. + *

    + * Valid for: SocketImpl, DatagramSocketImpl + * + * @since 9 + * @see StandardSocketOptions#SO_REUSEPORT + */ + @Native public static final int SO_REUSEPORT = 0x0E; /** * Sets SO_BROADCAST for a socket. This option enables and disables @@ -179,7 +191,7 @@ public interface SocketOptions { * @since 1.4 */ - @Native public final static int SO_BROADCAST = 0x0020; + @Native public static final int SO_BROADCAST = 0x0020; /** Set which outgoing interface on which to send multicast packets. * Useful on hosts with multiple network interfaces, where applications @@ -191,7 +203,7 @@ public interface SocketOptions { * @see MulticastSocket#getInterface() */ - @Native public final static int IP_MULTICAST_IF = 0x10; + @Native public static final int IP_MULTICAST_IF = 0x10; /** Same as above. This option is introduced so that the behaviour * with IP_MULTICAST_IF will be kept the same as before, while @@ -203,7 +215,7 @@ public interface SocketOptions { * @see MulticastSocket#getNetworkInterface() * @since 1.4 */ - @Native public final static int IP_MULTICAST_IF2 = 0x1f; + @Native public static final int IP_MULTICAST_IF2 = 0x1f; /** * This option enables or disables local loopback of multicast datagrams. @@ -211,7 +223,7 @@ public interface SocketOptions { * @since 1.4 */ - @Native public final static int IP_MULTICAST_LOOP = 0x12; + @Native public static final int IP_MULTICAST_LOOP = 0x12; /** * This option sets the type-of-service or traffic class field @@ -219,7 +231,7 @@ public interface SocketOptions { * @since 1.4 */ - @Native public final static int IP_TOS = 0x3; + @Native public static final int IP_TOS = 0x3; /** * Specify a linger-on-close timeout. This option disables/enables @@ -237,7 +249,7 @@ public interface SocketOptions { * @see Socket#setSoLinger * @see Socket#getSoLinger */ - @Native public final static int SO_LINGER = 0x0080; + @Native public static final int SO_LINGER = 0x0080; /** Set a timeout on blocking Socket operations: *

    @@ -258,7 +270,7 @@ public interface SocketOptions {
          * @see ServerSocket#setSoTimeout
          * @see DatagramSocket#setSoTimeout
          */
    -    @Native public final static int SO_TIMEOUT = 0x1006;
    +    @Native public static final int SO_TIMEOUT = 0x1006;
     
         /**
          * Set a hint the size of the underlying buffers used by the
    @@ -275,7 +287,7 @@ public interface SocketOptions {
          * @see DatagramSocket#setSendBufferSize
          * @see DatagramSocket#getSendBufferSize
          */
    -    @Native public final static int SO_SNDBUF = 0x1001;
    +    @Native public static final int SO_SNDBUF = 0x1001;
     
         /**
          * Set a hint the size of the underlying buffers used by the
    @@ -293,7 +305,7 @@ public interface SocketOptions {
          * @see DatagramSocket#setReceiveBufferSize
          * @see DatagramSocket#getReceiveBufferSize
          */
    -    @Native public final static int SO_RCVBUF = 0x1002;
    +    @Native public static final int SO_RCVBUF = 0x1002;
     
         /**
          * When the keepalive option is set for a TCP socket and no data
    @@ -316,7 +328,7 @@ public interface SocketOptions {
          * @see Socket#setKeepAlive
          * @see Socket#getKeepAlive
          */
    -    @Native public final static int SO_KEEPALIVE = 0x0008;
    +    @Native public static final int SO_KEEPALIVE = 0x0008;
     
         /**
          * When the OOBINLINE option is set, any TCP urgent data received on
    @@ -327,5 +339,5 @@ public interface SocketOptions {
          * @see Socket#setOOBInline
          * @see Socket#getOOBInline
          */
    -    @Native public final static int SO_OOBINLINE = 0x1003;
    +    @Native public static final int SO_OOBINLINE = 0x1003;
     }
    diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketOutputStream.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketOutputStream.java
    index 9e8e7926e7..e8b23b11c0 100644
    --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketOutputStream.java
    +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketOutputStream.java
    @@ -1,6 +1,6 @@
     /*
      * Copyright (C) 2014 The Android Open Source Project
    - * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1995, 2018, 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
    @@ -41,8 +41,7 @@
      * @author      Jonathan Payne
      * @author      Arthur van Hoff
      */
    -class SocketOutputStream extends FileOutputStream
    -{
    +class SocketOutputStream extends FileOutputStream {
         // Android-removed: Android doesn't need to call native init.
         // static {
         //    init();
    @@ -116,10 +115,6 @@ private void socketWrite(byte b[], int off, int len) throws IOException {
                 BlockGuard.getThreadPolicy().onNetwork();
                 socketWrite0(fd, b, off, len);
             } catch (SocketException se) {
    -            if (se instanceof sun.net.ConnectionResetException) {
    -                impl.setConnectionResetPending();
    -                se = new SocketException("Connection reset");
    -            }
                 if (impl.isClosedOrPending()) {
                     throw new SocketException("Socket closed");
                 } else {
    diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketPermission.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketPermission.java
    index 2195eccd71..97346cd285 100644
    --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketPermission.java
    +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketPermission.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketTimeoutException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketTimeoutException.java
    index 3b5b50a2e6..5daf600269 100644
    --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketTimeoutException.java
    +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/SocketTimeoutException.java
    @@ -48,14 +48,4 @@ public SocketTimeoutException(String msg) {
          * Construct a new SocketTimeoutException with no detailed message.
          */
         public SocketTimeoutException() {}
    -
    -    /** @hide */
    -    public SocketTimeoutException(Throwable cause) {
    -        super(cause);
    -    }
    -
    -    /** @hide */
    -    public SocketTimeoutException(String msg, Throwable cause) {
    -        super(msg, cause);
    -    }
     }
    diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/StandardSocketOptions.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/StandardSocketOptions.java
    index 7fdd5f075d..ae47845fae 100644
    --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/StandardSocketOptions.java
    +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/StandardSocketOptions.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -186,6 +186,29 @@ private StandardSocketOptions() { }
         public static final SocketOption SO_REUSEADDR =
             new StdSocketOption("SO_REUSEADDR", Boolean.class);
     
    +    /**
    +     * Re-use port.
    +     *
    +     * 

    The value of this socket option is a {@code Boolean} that represents + * whether the option is enabled or disabled. The exact semantics of this + * socket option are socket type and system dependent. + * + *

    In the case of stream-oriented sockets, this socket option usually allows + * multiple listening sockets to be bound to both same address + * and same port. + * + *

    For datagram-oriented sockets the socket option usually allows + * multiple UDP sockets to be bound to the same address and port. + * + *

    An implementation allows this socket option to be set before the + * socket is bound or connected. Changing the value of this socket option + * after the socket is bound has no effect. + * + * @since 9 + */ + public static final SocketOption SO_REUSEPORT = + new StdSocketOption("SO_REUSEPORT", Boolean.class); + /** * Linger on close if data is present. * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URI.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URI.java index 488d16f12a..b305e1adc1 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URI.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URI.java @@ -44,6 +44,7 @@ import java.lang.NullPointerException; // for javadoc +// Android-changed: Reformat @see links. /** * Represents a Uniform Resource Identifier (URI) reference. * @@ -194,7 +195,7 @@ * Resolving the relative URI * *

    - * {@code ../../../demo/jfc/SwingSet2/src/SwingSet2.java    }(2) + * {@code ../../../demo/jfc/SwingSet2/src/SwingSet2.java}    (2) *
    * * against this result yields, in turn, @@ -308,7 +309,7 @@ * *
  • A character is encoded by replacing it * with the sequence of escaped octets that represent that character in the - * UTF-8 character set. The Euro currency symbol ({@code '\u20AC'}), + * UTF-8 character set. The Euro currency symbol ({@code '\u005Cu20AC'}), * for example, is encoded as {@code "%E2%82%AC"}. (Deviation from * RFC 2396, which does not specify any particular character * set.)

  • @@ -327,7 +328,7 @@ * decoding any encoded non-US-ASCII characters. If a decoding error occurs * when decoding the escaped octets then the erroneous octets are replaced by - * {@code '\uFFFD'}, the Unicode replacement character.

    + * {@code '\u005CuFFFD'}, the Unicode replacement character.

    * * * @@ -455,7 +456,7 @@ * @see RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax * @see RFC 2732: Format for Literal IPv6 Addresses in URLs */ -// Android-changed: Reformat @see links. + public final class URI implements Comparable, Serializable { @@ -1065,7 +1066,7 @@ public URI relativize(URI uri) { * Constructs a URL from this URI. * *

    This convenience method works as if invoking it were equivalent to - * evaluating the expression {@code new URL(this.toString())} after + * evaluating the expression {@code new URL(this.toString())} after * first checking that this URI is absolute.

    * * @return A URL constructed from this URI @@ -1483,7 +1484,7 @@ public int hashCode() { * *

    The ordering of URIs is defined as follows:

    * - *
      + *
        * *
      • Two URIs with different schemes are ordered according the * ordering of their schemes, without regard to case.

      • @@ -1501,7 +1502,7 @@ public int hashCode() { *
      • Two hierarchical URIs with identical schemes are ordered * according to the ordering of their authority components:

        * - *
          + *
            * *
          • If both authority components are server-based then the URIs * are ordered according to their user-information components; if these @@ -2020,6 +2021,8 @@ private static String resolvePath(String base, String child, } // 5.2 (6c-f) + // Android-changed: App compat. Remove leading dots when resolving path. http://b/25897693 + // String np = normalize(path); String np = normalize(path, true); // 5.2 (6g): If the result is absolute but the path begins with "../", @@ -2071,8 +2074,10 @@ private static URI resolve(URI base, URI child) { ru.userInfo = base.userInfo; ru.port = base.port; + // BEGIN Android-changed: App Compat. Handle null and empty path using RFC 3986 logic + // http://b/25897693 if (child.path == null || child.path.isEmpty()) { - // This is an addtional path from RFC 3986 RI, which fixes following RFC 2396 + // This is an additional path from RFC 3986 RI, which fixes following RFC 2396 // "normal" examples: // Base: http://a/b/c/d;p?q // "?y" = "http://a/b/c/d;p?y" @@ -2080,12 +2085,15 @@ private static URI resolve(URI base, URI child) { // http://b/25897693 ru.path = base.path; ru.query = child.query != null ? child.query : base.query; + // END Android-changed: App Compat. Handle null and empty path using RFC 3986 logic } else if ((child.path.length() > 0) && (child.path.charAt(0) == '/')) { // 5.2 (5): Child path is absolute // + // Android-changed: App Compat. Remove leading dots in path. // There is an additional step from RFC 3986 RI, requiring to remove dots for // absolute path as well. // http://b/25897693 + // ru.path = child.path; ru.path = normalize(child.path, true); } else { // 5.2 (6): Resolve relative path @@ -2144,12 +2152,13 @@ private static URI relativize(URI base, URI child) { String bp = normalize(base.path); String cp = normalize(child.path); if (!bp.equals(cp)) { - // Android-changed: The original OpenJdk implementation would append a trailing slash - // to paths like "/a/b" before relativizing them. This would relativize /a/b/c to - // "/c" against "/a/b" the android implementation did not do this. It would assume that - // "b" wasn't a directory and relativize the path to "/b/c". The spec is pretty vague - // about this but this change is being made because we have several tests that expect - // this behaviour. + // Android-changed: App Compat. Interpret ambiguous base path as a file, not a directory + // Upstream would append '/' to bp if not present, interpreting it as a directory; thus, + // /a/b/c relative to /a/b would become /c, whereas Android would relativize to /b/c. + // The spec is pretty vague about this but the Android behavior is kept because several + // tests enforce it. + // if (!bp.endsWith("/")) + // bp = bp + "/"; if (bp.indexOf('/') != -1) { bp = bp.substring(0, bp.lastIndexOf('/') + 1); } @@ -2339,6 +2348,8 @@ static private int join(char[] path, int[] segs) { // Remove "." segments from the given path, and remove segment pairs // consisting of a non-".." segment followed by a ".." segment. // + // Android-changed: App compat. Remove leading dots when resolving path. http://b/25897693 + // private static void removeDots(char[] path, int[] segs) { private static void removeDots(char[] path, int[] segs, boolean removeLeading) { int ns = segs.length; int end = path.length - 1; @@ -2386,10 +2397,11 @@ private static void removeDots(char[] path, int[] segs, boolean removeLeading) { segs[i] = -1; segs[j] = -1; } + // Android-added: App compat. Remove leading dots when resolving path. + // This is a leading ".." segment. Per RFC 3986 RI, this should be removed as + // well. This fixes RFC 2396 "abnormal" examples. + // http://b/25897693 } else if (removeLeading) { - // This is a leading ".." segment. Per RFC 3986 RI, this should be removed as - // well. This fixes RFC 2396 "abnormal" examples. - // http://b/25897693 segs[i] = -1; } } @@ -2439,11 +2451,13 @@ private static void maybeAddLeadingDot(char[] path, int[] segs) { // always retain trailing slashes. // private static String normalize(String ps) { + // BEGIN Android-changed: App compat. Remove leading dots when resolving path. + // Controlled by the "boolean removeLeading" argument added to normalize(). return normalize(ps, false); } private static String normalize(String ps, boolean removeLeading) { - + // END Android-changed: App compat. Remove leading dots when resolving path. // Does this path need normalization? int ns = needsNormalization(ps); // Number of segments if (ns < 0) @@ -2457,6 +2471,8 @@ private static String normalize(String ps, boolean removeLeading) { split(path, segs); // Remove dots + // Android-changed: App compat. Remove leading dots when resolving path. + // removeDots(path, segs); removeDots(path, segs, removeLeading); // Prevent scheme-name confusion @@ -2616,9 +2632,11 @@ private static boolean match(char c, long lowMask, long highMask) { private static final long L_DASH = lowMask("-"); private static final long H_DASH = highMask("-"); + // BEGIN Android-added: Allow underscore in hostname. // UNDERSCORE, for use in domainlabel and toplabel private static final long L_UNDERSCORE = lowMask("_"); private static final long H_UNDERSCORE = highMask("_"); + // END Android-added: Allow underscore in hostname. // Dot, for use in hostnames private static final long L_DOT = lowMask("."); @@ -2701,6 +2719,7 @@ private static void appendEncoded(StringBuffer sb, char c) { // by the given mask pair // private static String quote(String s, long lowMask, long highMask) { + int n = s.length(); StringBuffer sb = null; boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0); for (int i = 0; i < s.length(); i++) { @@ -2826,6 +2845,7 @@ private static String decode(String s) { continue; } bb.clear(); + int ui = i; for (;;) { assert (n - i >= 2); bb.put(decode(s.charAt(++i), s.charAt(++i))); @@ -3379,6 +3399,8 @@ private int parseIPv4Address(int start, int n) { return p; } + // Android-changed: Allow underscore in hostname. + // Added "_" to the grammars for domainLabel and topLabel. // hostname = domainlabel [ "." ] | 1*( domainlabel "." ) toplabel [ "." ] // domainlabel = alphanum | alphanum *( alphanum | "-" | "_" ) alphanum // toplabel = alpha | alpha *( alphanum | "-" | "_" ) alphanum @@ -3391,20 +3413,23 @@ private int parseHostname(int start, int n) int l = -1; // Start of last parsed label do { - // domainlabel = alphanum [ *( alphanum | "-" | "_" ) alphanum ] - // - // The RFCs don't permit underscores in hostnames, but URI has to because a certain - // large website doesn't seem to care about standards and specs. + // Android-changed: Allow underscore in hostname. + // RFC 2396 only allows alphanumeric characters and hyphens, but real, + // large Internet hosts in the wild use underscore, so we have to allow it. // http://code.google.com/p/android/issues/detail?id=37577 // http://b/17579865 // http://b/18016625 // http://b/18023709 + + // domainlabel = alphanum [ *( alphanum | "-" | "_" ) alphanum ] q = scan(p, n, L_ALPHANUM, H_ALPHANUM); if (q <= p) break; l = p; if (q > p) { p = q; + // Android-changed: Allow underscore in hostname. + // q = scan(p, n, L_ALPHANUM | L_DASH, H_ALPHANUM | H_DASH); q = scan(p, n, L_ALPHANUM | L_DASH | L_UNDERSCORE, H_ALPHANUM | H_DASH | H_UNDERSCORE); if (q > p) { if (charAt(q - 1) == '-') diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URISyntaxException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URISyntaxException.java index 8072c37244..17d12bd963 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URISyntaxException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URISyntaxException.java @@ -121,7 +121,7 @@ public int getIndex() { * @return A string describing the parse error */ public String getMessage() { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(getReason()); if (index > -1) { sb.append(" at index "); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URL.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URL.java index cb44d1c55d..a3a5e37031 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URL.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URL.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,25 +30,41 @@ import com.google.j2objc.annotations.ObjectiveCName; import java.io.IOException; import java.io.InputStream; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream.GetField; +import java.io.ObjectStreamException; +import java.io.ObjectStreamField; +import java.util.Collections; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Set; +import java.util.StringTokenizer; +/* J2ObjC: removed +import sun.security.util.SecurityConstants; +*/ /** - * Class URL represents a Uniform Resource + * Class {@code URL} represents a Uniform Resource * Locator, a pointer to a "resource" on the World * Wide Web. A resource can be something as simple as a file or a * directory, or it can be a reference to a more complicated object, * such as a query to a database or to a search engine. More * information on the types of URLs and their formats can be found at: - *

            - * - * http://www.socs.uts.edu.au/MosaicDocs-old/url-primer.html - *
            + * + * Types of URL *

            - * In general, a URL can be broken into several parts. The previous - * example of a URL indicates that the protocol to use is - * http (HyperText Transfer Protocol) and that the + * In general, a URL can be broken into several parts. Consider the + * following example: + *

            + *     http://www.example.com/docs/resource1.html
            + * 
            + *

            + * The URL above indicates that the protocol to use is + * {@code http} (HyperText Transfer Protocol) and that the * information resides on a host machine named - * www.socs.uts.edu.au. The information on that host - * machine is named /MosaicDocs-old/url-primer.html. The exact + * {@code www.example.com}. The information on that host + * machine is named {@code /docs/resource1.html}. The exact * meaning of this name on the host machine is both protocol * dependent and host dependent. The information normally resides in * a file, but it could be generated on the fly. This component of @@ -58,13 +74,13 @@ * port number to which the TCP connection is made on the remote host * machine. If the port is not specified, the default port for * the protocol is used instead. For example, the default port for - * http is 80. An alternative port could be + * {@code http} is {@code 80}. An alternative port could be * specified as: *

            - *     http://www.socs.uts.edu.au:80/MosaicDocs-old/url-primer.html
            + *     http://www.example.com:1080/docs/resource1.html
              * 
            *

            - * The syntax of URL is defined by RFC 2396: Uniform * Resource Identifiers (URI): Generic Syntax, amended by RFC 2732: Format for @@ -82,7 +98,7 @@ * This fragment is not technically part of the URL. Rather, it * indicates that after the specified resource is retrieved, the * application is specifically interested in that part of the - * document that has the tag chapter1 attached to it. The + * document that has the tag {@code chapter1} attached to it. The * meaning of a tag is resource specific. *

            * An application can also specify a "relative URL", @@ -136,6 +152,10 @@ public final class URL implements java.io.Serializable { * core classes like ClassLoader reference URL publicly. */ + // Android-changed: Custom built-in URLStreamHandlers for http, https. + // static final String BUILTIN_HANDLERS_PREFIX = "sun.net.www.protocol"; + // J2ObjC removed + // private static final Set BUILTIN_HANDLER_CLASS_NAMES = createBuiltinHandlerClassNames(); static final long serialVersionUID = -7627629688361524110L; /** @@ -157,8 +177,8 @@ public final class URL implements java.io.Serializable { private int port = -1; /** - * The specified file name on that host. file is - * defined as path[?query] + * The specified file name on that host. {@code file} is + * defined as {@code path[?query]} * @serial */ private String file; @@ -205,48 +225,47 @@ public final class URL implements java.io.Serializable { /* Our hash code. * @serial */ - // ----- BEGIN android ----- - //private int hashCode = -1; - private transient int hashCode = -1; - // ----- END android ----- + private int hashCode = -1; + + private transient UrlDeserializedState tempState; /** - * Creates a URL object from the specified - * protocol, host, port - * number, and file.

            + * Creates a {@code URL} object from the specified + * {@code protocol}, {@code host}, {@code port} + * number, and {@code file}.

            * - * host can be expressed as a host name or a literal + * {@code host} can be expressed as a host name or a literal * IP address. If IPv6 literal address is used, it should be - * enclosed in square brackets ('[' and ']'), as + * enclosed in square brackets ({@code '['} and {@code ']'}), as * specified by RFC 2732; * However, the literal IPv6 address format defined in RFC 2373: IP * Version 6 Addressing Architecture is also accepted.

            * - * Specifying a port number of -1 + * Specifying a {@code port} number of {@code -1} * indicates that the URL should use the default port for the * protocol.

            * * If this is the first URL object being created with the specified * protocol, a stream protocol handler object, an instance of - * class URLStreamHandler, is created for that protocol: + * class {@code URLStreamHandler}, is created for that protocol: *

              *
            1. If the application has previously set up an instance of - * URLStreamHandlerFactory as the stream handler factory, - * then the createURLStreamHandler method of that instance + * {@code URLStreamHandlerFactory} as the stream handler factory, + * then the {@code createURLStreamHandler} method of that instance * is called with the protocol string as an argument to create the * stream protocol handler. - *
            2. If no URLStreamHandlerFactory has yet been set up, - * or if the factory's createURLStreamHandler method - * returns null, then the constructor finds the + *
            3. If no {@code URLStreamHandlerFactory} has yet been set up, + * or if the factory's {@code createURLStreamHandler} method + * returns {@code null}, then the constructor finds the * value of the system property: *
                    *         java.protocol.handler.pkgs
                    *     
              - * If the value of that system property is not null, + * If the value of that system property is not {@code null}, * it is interpreted as a list of packages separated by a vertical - * slash character '|'. The constructor tries to load + * slash character '{@code |}'. The constructor tries to load * the class named: *
                    *         <package>.<protocol>.Handler
              @@ -254,7 +273,7 @@ public final class URL implements java.io.Serializable {
                    *     where <package> is replaced by the name of the package
                    *     and <protocol> is replaced by the name of the protocol.
                    *     If this class does not exist, or if the class exists but it is not
              -     *     a subclass of URLStreamHandler, then the next package
              +     *     a subclass of {@code URLStreamHandler}, then the next package
                    *     in the list is tried.
                    * 
            4. If the previous step fails to find a protocol handler, then the * constructor tries to load from a system default package. @@ -262,14 +281,14 @@ public final class URL implements java.io.Serializable { * <system default package>.<protocol>.Handler *
            5. * If this class does not exist, or if the class exists but it is not a - * subclass of URLStreamHandler, then a - * MalformedURLException is thrown. + * subclass of {@code URLStreamHandler}, then a + * {@code MalformedURLException} is thrown. *
            * *

            Protocol handlers for the following protocols are guaranteed * to exist on the search path :- *

            -     *     http, https, ftp, file, and jar
            +     *     http, https, file, and jar
                  * 
            * Protocol handlers for additional protocols may also be * available. @@ -295,13 +314,13 @@ public URL(String protocol, String host, int port, String file) } /** - * Creates a URL from the specified protocol - * name, host name, and file name. The + * Creates a URL from the specified {@code protocol} + * name, {@code host} name, and {@code file} name. The * default port for the specified protocol is used. *

            * This method is equivalent to calling the four-argument - * constructor with the arguments being protocol, - * host, -1, and file. + * constructor with the arguments being {@code protocol}, + * {@code host}, {@code -1}, and {@code file}. * * No validation of the inputs is performed by this constructor. * @@ -318,21 +337,21 @@ public URL(String protocol, String host, String file) } /** - * Creates a URL object from the specified - * protocol, host, port - * number, file, and handler. Specifying - * a port number of -1 indicates that + * Creates a {@code URL} object from the specified + * {@code protocol}, {@code host}, {@code port} + * number, {@code file}, and {@code handler}. Specifying + * a {@code port} number of {@code -1} indicates that * the URL should use the default port for the protocol. Specifying - * a handler of null indicates that the URL + * a {@code handler} of {@code null} indicates that the URL * should use a default stream handler for the protocol, as outlined * for: * java.net.URL#URL(java.lang.String, java.lang.String, int, * java.lang.String) * *

            If the handler is not null and there is a security manager, - * the security manager's checkPermission + * the security manager's {@code checkPermission} * method is called with a - * NetPermission("specifyStreamHandler") permission. + * {@code NetPermission("specifyStreamHandler")} permission. * This may result in a SecurityException. * * No validation of the inputs is performed by this constructor. @@ -345,7 +364,7 @@ public URL(String protocol, String host, String file) * @exception MalformedURLException if an unknown protocol is specified. * @exception SecurityException * if a security manager exists and its - * checkPermission method doesn't allow + * {@code checkPermission} method doesn't allow * specifying a stream handler explicitly. * @see java.lang.System#getProperty(java.lang.String) * @see java.net.URL#setURLStreamHandlerFactory( @@ -388,6 +407,8 @@ public URL(String protocol, String host, int port, String file, authority = (port == -1) ? host : host + ":" + port; } + // Android-changed: App compat. Prepend '/' if host is null / empty + // Parts parts = new Parts(file); Parts parts = new Parts(file, host); path = parts.getPath(); query = parts.getQuery(); @@ -398,19 +419,28 @@ public URL(String protocol, String host, int port, String file, this.file = path; } ref = parts.getRef(); + + /* J2Objc remove + // Note: we don't do validation of the URL here. Too risky to change + // right now, but worth considering for future reference. -br + if (handler == null && + (handler = getURLStreamHandler(protocol)) == null) { + throw new MalformedURLException("unknown protocol: " + protocol); + } + */ this.handler = handler; } /** - * Creates a URL object from the String + * Creates a {@code URL} object from the {@code String} * representation. *

            * This constructor is equivalent to a call to the two-argument - * constructor with a null first argument. + * constructor with a {@code null} first argument. * - * @param spec the String to parse as a URL. + * @param spec the {@code String} to parse as a URL. * @exception MalformedURLException if no protocol is specified, or an - * unknown protocol is found, or spec is null. + * unknown protocol is found, or {@code spec} is {@code null}. * @see java.net.URL#URL(java.net.URL, java.lang.String) */ public URL(String spec) throws MalformedURLException { @@ -450,14 +480,14 @@ public URL(String spec) throws MalformedURLException { * Otherwise, the path is treated as a relative path and is appended to the * context path, as described in RFC2396. Also, in this case, * the path is canonicalized through the removal of directory - * changes made by occurences of ".." and ".". + * changes made by occurrences of ".." and ".". *

            * For a more detailed description of URL parsing, refer to RFC2396. * * @param context the context in which to parse the specification. - * @param spec the String to parse as a URL. + * @param spec the {@code String} to parse as a URL. * @exception MalformedURLException if no protocol is specified, or an - * unknown protocol is found, or spec is null. + * unknown protocol is found, or {@code spec} is {@code null}. * @see java.net.URL#URL(java.lang.String, java.lang.String, * int, java.lang.String) * @see java.net.URLStreamHandler @@ -474,13 +504,13 @@ public URL(URL context, String spec) throws MalformedURLException { * occurs as with the two argument constructor. * * @param context the context in which to parse the specification. - * @param spec the String to parse as a URL. + * @param spec the {@code String} to parse as a URL. * @param handler the stream handler for the URL. * @exception MalformedURLException if no protocol is specified, or an - * unknown protocol is found, or spec is null. + * unknown protocol is found, or {@code spec} is {@code null}. * @exception SecurityException * if a security manager exists and its - * checkPermission method doesn't allow + * {@code checkPermission} method doesn't allow * specifying a stream handler. * @see java.net.URL#URL(java.lang.String, java.lang.String, * int, java.lang.String) @@ -492,10 +522,150 @@ public URL(URL context, String spec) throws MalformedURLException { public URL(URL context, String spec, Object handler) throws MalformedURLException { - getDelegate().initURL(this, context, spec, handler); + getDelegate().initURL(this, context, spec, handler); + /* J2ObjC: disabled + String original = spec; + int i, limit, c; + int start = 0; + String newProtocol = null; + boolean aRef=false; + boolean isRelative = false; + + // Check for permission to specify a handler + if (handler != null) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + checkSpecifyHandler(sm); + } + } + + try { + limit = spec.length(); + while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) { + limit--; //eliminate trailing whitespace + } + while ((start < limit) && (spec.charAt(start) <= ' ')) { + start++; // eliminate leading whitespace + } + + if (spec.regionMatches(true, start, "url:", 0, 4)) { + start += 4; + } + if (start < spec.length() && spec.charAt(start) == '#') { + / we're assuming this is a ref relative to the context URL. + * This means protocols cannot start w/ '#', but we must parse + * ref URL's like: "hello:there" w/ a ':' in them. + / + aRef=true; + } + for (i = start ; !aRef && (i < limit) && + ((c = spec.charAt(i)) != '/') ; i++) { + if (c == ':') { + + String s = spec.substring(start, i).toLowerCase(); + if (isValidProtocol(s)) { + newProtocol = s; + start = i + 1; + } + break; + } + } + + // Only use our context if the protocols match. + protocol = newProtocol; + if ((context != null) && ((newProtocol == null) || + newProtocol.equalsIgnoreCase(context.protocol))) { + // inherit the protocol handler from the context + // if not specified to the constructor + if (handler == null) { + handler = context.handler; + } + + // If the context is a hierarchical URL scheme and the spec + // contains a matching scheme then maintain backwards + // compatibility and treat it as if the spec didn't contain + // the scheme; see 5.2.3 of RFC2396 + if (context.path != null && context.path.startsWith("/")) + newProtocol = null; + + if (newProtocol == null) { + protocol = context.protocol; + authority = context.authority; + userInfo = context.userInfo; + host = context.host; + port = context.port; + file = context.file; + path = context.path; + isRelative = true; + } + } + + if (protocol == null) { + throw new MalformedURLException("no protocol: "+original); + } + + // Get the protocol handler if not specified or the protocol + // of the context could not be used + if (handler == null && + (handler = getURLStreamHandler(protocol)) == null) { + throw new MalformedURLException("unknown protocol: "+protocol); + } + + this.handler = handler; + + i = spec.indexOf('#', start); + if (i >= 0) { + ref = spec.substring(i + 1, limit); + limit = i; + } + + / + * Handle special case inheritance of query and fragment + * implied by RFC2396 section 5.2.2. + / + if (isRelative && start == limit) { + query = context.query; + if (ref == null) { + ref = context.ref; + } + } + + handler.parseURL(this, spec, start, limit); + + } catch(MalformedURLException e) { + throw e; + } catch(Exception e) { + MalformedURLException exception = new MalformedURLException(e.getMessage()); + exception.initCause(e); + throw exception; + } + */ + } + + /* + * J2ObjC: disabled + * Returns true if specified string is a valid protocol name. + + private boolean isValidProtocol(String protocol) { + int len = protocol.length(); + if (len < 1) + return false; + char c = protocol.charAt(0); + if (!Character.isLetter(c)) + return false; + for (int i = 1; i < len; i++) { + c = protocol.charAt(i); + if (!Character.isLetterOrDigit(c) && c != '.' && c != '+' && + c != '-') { + return false; + } + } + return true; } + */ - /* J2ObjC: disabled. + /* + * J2ObjC: disabled * Checks for permission to specify a stream handler. private void checkSpecifyHandler(SecurityManager sm) { sm.checkPermission(SecurityConstants.SPECIFY_HANDLER_PERMISSION); @@ -551,12 +721,14 @@ protected void set(String protocol, String host, * @since 1.3 */ protected void set(String protocol, String host, int port, - String authority, String userInfo, String path, - String query, String ref) { + String authority, String userInfo, String path, + String query, String ref) { synchronized (this) { this.protocol = protocol; this.host = host; this.port = port; + // Android-changed: App compat. Only include query part if it's nonempty. + // this.file = query == null ? path : path + "?" + query; this.file = (query == null || query.isEmpty()) ? path : path + "?" + query; this.userInfo = userInfo; this.path = path; @@ -570,14 +742,15 @@ protected void set(String protocol, String host, int port, } } + /* J2ObjC: added */ void setURLHandler(Object handler) { this.handler = handler; } /** - * Gets the query part of this URL. + * Gets the query part of this {@code URL}. * - * @return the query part of this URL, + * @return the query part of this {@code URL}, * or null if one does not exist * @since 1.3 */ @@ -586,9 +759,9 @@ public String getQuery() { } /** - * Gets the path part of this URL. + * Gets the path part of this {@code URL}. * - * @return the path part of this URL, or an + * @return the path part of this {@code URL}, or an * empty string if one does not exist * @since 1.3 */ @@ -597,9 +770,9 @@ public String getPath() { } /** - * Gets the userInfo part of this URL. + * Gets the userInfo part of this {@code URL}. * - * @return the userInfo part of this URL, or + * @return the userInfo part of this {@code URL}, or * null if one does not exist * @since 1.3 */ @@ -608,9 +781,9 @@ public String getUserInfo() { } /** - * Gets the authority part of this URL. + * Gets the authority part of this {@code URL}. * - * @return the authority part of this URL + * @return the authority part of this {@code URL} * @since 1.3 */ public String getAuthority() { @@ -618,7 +791,7 @@ public String getAuthority() { } /** - * Gets the port number of this URL. + * Gets the port number of this {@code URL}. * * @return the port number, or -1 if the port is not set */ @@ -628,7 +801,7 @@ public int getPort() { /** * Gets the default port number of the protocol associated - * with this URL. If the URL scheme or the URLStreamHandler + * with this {@code URL}. If the URL scheme or the URLStreamHandler * for the URL do not define a default port number, * then -1 is returned. * @@ -636,6 +809,7 @@ public int getPort() { * @since 1.4 */ public int getDefaultPort() { + /* J2ObjC: modified */ try { return getDelegate().getDefaultPort(this); } catch (MalformedURLException e) { @@ -644,35 +818,35 @@ public int getDefaultPort() { } /** - * Gets the protocol name of this URL. + * Gets the protocol name of this {@code URL}. * - * @return the protocol of this URL. + * @return the protocol of this {@code URL}. */ public String getProtocol() { return protocol; } /** - * Gets the host name of this URL, if applicable. + * Gets the host name of this {@code URL}, if applicable. * The format of the host conforms to RFC 2732, i.e. for a * literal IPv6 address, this method will return the IPv6 address - * enclosed in square brackets ('[' and ']'). + * enclosed in square brackets ({@code '['} and {@code ']'}). * - * @return the host name of this URL. + * @return the host name of this {@code URL}. */ public String getHost() { return host; } /** - * Gets the file name of this URL. + * Gets the file name of this {@code URL}. * The returned file portion will be * the same as getPath(), plus the concatenation of * the value of getQuery(), if any. If there is * no query portion, this method and getPath() will * return identical results. * - * @return the file name of this URL, + * @return the file name of this {@code URL}, * or an empty string if one does not exist */ public String getFile() { @@ -681,20 +855,21 @@ public String getFile() { /** * Gets the anchor (also known as the "reference") of this - * URL. + * {@code URL}. * * @return the anchor (also known as the "reference") of this - * URL, or null if one does not exist + * {@code URL}, or null if one does not exist */ public String getRef() { return ref; } + // Android-changed: Don't let URL.equals() attempt to resolve host names. /** * Compares this URL for equality with another object.

            * * If the given object is not a URL then this method immediately returns - * false.

            + * {@code false}.

            * * Two URL objects are equal if they have the same protocol, reference * equivalent hosts, have the same port number on the host, and the same @@ -728,14 +903,14 @@ public String getRef() { * case). * * @param obj the URL to compare against. - * @return true if the objects are the same; - * false otherwise. + * @return {@code true} if the objects are the same; + * {@code false} otherwise. */ public boolean equals(Object obj) { if (!(obj instanceof URL)) return false; URL u2 = (URL)obj; - + // J2ObjC: modified try { return getDelegate().equals(this, u2); } catch (MalformedURLException e) { @@ -749,12 +924,12 @@ public boolean equals(Object obj) { * The hash code is based upon all the URL components relevant for URL * comparison. As such, this operation is a blocking operation.

            * - * @return a hash code for this URL. + * @return a hash code for this {@code URL}. */ public synchronized int hashCode() { if (hashCode != -1) return hashCode; - + // J2ObjC: modified try { hashCode = getDelegate().hashCode(this); } catch (MalformedURLException e) { @@ -766,15 +941,16 @@ public synchronized int hashCode() { /** * Compares two URLs, excluding the fragment component.

            * - * Returns true if this URL and the - * other argument are equal without taking the + * Returns {@code true} if this {@code URL} and the + * {@code other} argument are equal without taking the * fragment component into consideration. * - * @param other the URL to compare against. - * @return true if they reference the same remote object; - * false otherwise. + * @param other the {@code URL} to compare against. + * @return {@code true} if they reference the same remote object; + * {@code false} otherwise. */ public boolean sameFile(URL other) { + // J2ObjC: modified try { return getDelegate().sameFile(this, other); } catch (MalformedURLException e) { @@ -783,8 +959,8 @@ public boolean sameFile(URL other) { } /** - * Constructs a string representation of this URL. The - * string is created by calling the toExternalForm + * Constructs a string representation of this {@code URL}. The + * string is created by calling the {@code toExternalForm} * method of the stream protocol handler for this object. * * @return a string representation of this object. @@ -797,8 +973,8 @@ public String toString() { } /** - * Constructs a string representation of this URL. The - * string is created by calling the toExternalForm + * Constructs a string representation of this {@code URL}. The + * string is created by calling the {@code toExternalForm} * method of the stream protocol handler for this object. * * @return a string representation of this object. @@ -807,6 +983,7 @@ public String toString() { * @see java.net.URLStreamHandler#toExternalForm(java.net.URL) */ public String toExternalForm() { + // J2ObjC: modified try { return getDelegate().toExternalForm(this); } catch (MalformedURLException e) { @@ -816,7 +993,7 @@ public String toExternalForm() { /** * Returns a {@link java.net.URI} equivalent to this URL. - * This method functions in the same way as new URI (this.toString()). + * This method functions in the same way as {@code new URI (this.toString())}. *

            Note, any URL instance that complies with RFC 2396 can be converted * to a URI. However, some URLs that are not strictly in compliance * can not be converted to a URI. @@ -861,6 +1038,7 @@ public URI toURI() throws URISyntaxException { * int, java.lang.String) */ public URLConnection openConnection() throws java.io.IOException { + // J2ObjC: modified return getDelegate().openConnection(this); } @@ -876,7 +1054,7 @@ public URLConnection openConnection() throws java.io.IOException { * @param proxy the Proxy through which this connection * will be made. If direct connection is desired, * Proxy.NO_PROXY should be specified. - * @return a URLConnection to the URL. + * @return a {@code URLConnection} to the URL. * @exception IOException if an I/O exception occurs. * @exception SecurityException if a security manager is present * and the caller doesn't have permission to connect @@ -895,12 +1073,13 @@ public URLConnection openConnection() throws java.io.IOException { */ @ObjectiveCName("openConnectionWithJavaNetProxy:") public URLConnection openConnection(Object proxy) throws java.io.IOException { + // J2ObjC: modified return getDelegate().openConnection(this, proxy); } /** - * Opens a connection to this URL and returns an - * InputStream for reading from that connection. This + * Opens a connection to this {@code URL} and returns an + * {@code InputStream} for reading from that connection. This * method is a shorthand for: *

                  *     openConnection().getInputStream()
            @@ -943,14 +1122,74 @@ public final Object getContent() throws java.io.IOException {
                  * @see        java.net.URLConnection#getContent(Class[])
                  * @since 1.3
                  */
            -    public final Object getContent(Class[] classes)
            +    public final Object getContent(Class[] classes)
                 throws java.io.IOException {
                     return openConnection().getContent(classes);
                 }
             
            +    /*
            +     * J2ObjC: removed
            +     * The URLStreamHandler factory.
            +     */
            +    static URLStreamHandlerFactory factory;
            +
            +    /**
            +     * Sets an application's {@code URLStreamHandlerFactory}.
            +     * This method can be called at most once in a given Java Virtual
            +     * Machine.
            +     *
            +     *

            The {@code URLStreamHandlerFactory} instance is used to + *construct a stream protocol handler from a protocol name. + * + *

            If there is a security manager, this method first calls + * the security manager's {@code checkSetFactory} method + * to ensure the operation is allowed. + * This could result in a SecurityException. + * + * @param fac the desired factory. + * @exception Error if the application has already set a factory. + * @exception SecurityException if a security manager exists and its + * {@code checkSetFactory} method doesn't allow + * the operation. + * @see java.net.URL#URL(java.lang.String, java.lang.String, + * int, java.lang.String) + * @see java.net.URLStreamHandlerFactory + * @see SecurityManager#checkSetFactory + */ public static void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) { + // J2ObjC: modified getDelegate().setURLStreamHandlerFactory(fac); } + // END Android-added: Custom built-in URLStreamHandlers for http, https. + + /** + * J2ObjC: removed + * @serialField protocol String + * + * @serialField host String + * + * @serialField port int + * + * @serialField authority String + * + * @serialField file String + * + * @serialField ref String + * + * @serialField hashCode int + * + + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("protocol", String.class), + new ObjectStreamField("host", String.class), + new ObjectStreamField("port", int.class), + new ObjectStreamField("authority", String.class), + new ObjectStreamField("file", String.class), + new ObjectStreamField("ref", String.class), + // Android-changed: App compat: hashCode should not be serialized. + // new ObjectStreamField("hashCode", int.class), }; + }; + */ /** * WriteObject is called to save the state of the URL to an @@ -974,16 +1213,70 @@ private synchronized void writeObject(java.io.ObjectOutputStream s) * stream handler. */ private synchronized void readObject(java.io.ObjectInputStream s) - throws IOException, ClassNotFoundException - { - s.defaultReadObject(); // read the fields - if ((handler = getDelegate().getURLStreamHandler(protocol)) == null) { + throws IOException, ClassNotFoundException { + GetField gf = s.readFields(); + String protocol = (String)gf.get("protocol", null); + if (getDelegate().getURLStreamHandler(protocol) == null) { throw new IOException("unknown protocol: " + protocol); } + String host = (String)gf.get("host", null); + int port = gf.get("port", -1); + String authority = (String)gf.get("authority", null); + String file = (String)gf.get("file", null); + String ref = (String)gf.get("ref", null); + // Android-changed: App compat: hashCode should not be serialized. + // int hashCode = gf.get("hashCode", -1); + final int hashCode = -1; + if (authority == null + && ((host != null && host.length() > 0) || port != -1)) { + if (host == null) + host = ""; + authority = (port == -1) ? host : host + ":" + port; + } + tempState = new UrlDeserializedState(protocol, host, port, authority, + file, ref, hashCode); + } + + /* + * J2ObjC: removed + * Replaces the de-serialized object with an URL object. + * + * @return a newly created object from the deserialzed state. + * + * @throws ObjectStreamException if a new object replacing this + * object could not be created + + + private Object readResolve() throws ObjectStreamException { + + URLStreamHandler handler = null; + // already been checked in readObject + handler = getURLStreamHandler(tempState.getProtocol()); + + URL replacementURL = null; + if (isBuiltinStreamHandler(handler.getClass().getName())) { + replacementURL = fabricateNewURL(); + } else { + replacementURL = setDeserializedFields(handler); + } + return replacementURL; + } + + private URL setDeserializedFields(URLStreamHandler handler) { + URL replacementURL; + String userInfo = null; + String protocol = tempState.getProtocol(); + String host = tempState.getHost(); + int port = tempState.getPort(); + String authority = tempState.getAuthority(); + String file = tempState.getFile(); + String ref = tempState.getRef(); + int hashCode = tempState.getHashCode(); + // Construct authority part - if (authority == null && - ((host != null && host.length() > 0) || port != -1)) { + if (authority == null + && ((host != null && host.length() > 0) || port != -1)) { if (host == null) host = ""; authority = (port == -1) ? host : host + ":" + port; @@ -1002,8 +1295,8 @@ private synchronized void readObject(java.io.ObjectInputStream s) } // Construct path and query part - path = null; - query = null; + String path = null; + String query = null; if (file != null) { // Fix: only do this if hierarchical? int q = file.lastIndexOf('?'); @@ -1013,8 +1306,68 @@ private synchronized void readObject(java.io.ObjectInputStream s) } else path = file; } - hashCode = -1; + + // Set the object fields. + this.protocol = protocol; + this.host = host; + this.port = port; + this.file = file; + this.authority = authority; + this.ref = ref; + this.hashCode = hashCode; + this.handler = handler; + this.query = query; + this.path = path; + this.userInfo = userInfo; + replacementURL = this; + return replacementURL; + } + + private URL fabricateNewURL() + throws InvalidObjectException { + // create URL string from deserialized object + URL replacementURL = null; + String urlString = tempState.reconstituteUrlString(); + + try { + replacementURL = new URL(urlString); + } catch (MalformedURLException mEx) { + resetState(); + InvalidObjectException invoEx = new InvalidObjectException( + "Malformed URL: " + urlString); + invoEx.initCause(mEx); + throw invoEx; + } + replacementURL.setSerializedHashCode(tempState.getHashCode()); + resetState(); + return replacementURL; + } + + private boolean isBuiltinStreamHandler(String handlerClassName) { + // Android-changed: Some built-in handlers (eg. HttpHandler) are not in sun.net.www.protocol. + // return (handlerClassName.startsWith(BUILTIN_HANDLERS_PREFIX)); + return BUILTIN_HANDLER_CLASS_NAMES.contains(handlerClassName); + } + + private void resetState() { + this.protocol = null; + this.host = null; + this.port = -1; + this.file = null; + this.authority = null; + this.ref = null; + this.hashCode = -1; + this.handler = null; + this.query = null; + this.path = null; + this.userInfo = null; + this.tempState = null; + } + + private void setSerializedHashCode(int hc) { + this.hashCode = hc; } + */ // ----- BEGIN j2objc ----- private static final URLDelegate IMPL = findImplementation(); @@ -1082,6 +1435,8 @@ void setQueryByDelegate(String query) { class Parts { String path, query, ref; + // Android-changed: App compat. Prepend '/' if host is null / empty. + // Parts(String file) Parts(String file, String host) { int ind = file.indexOf('#'); ref = ind < 0 ? null: file.substring(ind + 1); @@ -1093,10 +1448,12 @@ class Parts { } else { path = file; } + // BEGIN Android-changed: App compat. Prepend '/' if host is null / empty. if (path != null && path.length() > 0 && path.charAt(0) != '/' && host != null && !host.isEmpty()) { path = '/' + path; } + // END Android-changed: App compat. Prepend '/' if host is null / empty. } String getPath() { @@ -1111,3 +1468,82 @@ String getRef() { return ref; } } + +final class UrlDeserializedState { + private final String protocol; + private final String host; + private final int port; + private final String authority; + private final String file; + private final String ref; + private final int hashCode; + + public UrlDeserializedState(String protocol, + String host, int port, + String authority, String file, + String ref, int hashCode) { + this.protocol = protocol; + this.host = host; + this.port = port; + this.authority = authority; + this.file = file; + this.ref = ref; + this.hashCode = hashCode; + } + + String getProtocol() { + return protocol; + } + + String getHost() { + return host; + } + + String getAuthority () { + return authority; + } + + int getPort() { + return port; + } + + String getFile () { + return file; + } + + String getRef () { + return ref; + } + + int getHashCode () { + return hashCode; + } + + String reconstituteUrlString() { + + // pre-compute length of StringBuilder + int len = protocol.length() + 1; + if (authority != null && authority.length() > 0) + len += 2 + authority.length(); + if (file != null) { + len += file.length(); + } + if (ref != null) + len += 1 + ref.length(); + StringBuilder result = new StringBuilder(len); + result.append(protocol); + result.append(":"); + if (authority != null && authority.length() > 0) { + result.append("//"); + result.append(authority); + } + if (file != null) { + result.append(file); + } + if (ref != null) { + result.append("#"); + result.append(ref); + } + return result.toString(); + } +} diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLDecoder.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLDecoder.java index 8b14eb86da..0d2d43102c 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLDecoder.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLDecoder.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,10 @@ package java.net; import java.io.*; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; +import java.util.Objects; /** * Utility class for HTML form decoding. This class contains static methods @@ -107,41 +111,73 @@ public static String decode(String s) { } /** - * Decodes a {@code application/x-www-form-urlencoded} string using a specific - * encoding scheme. - * The supplied encoding is used to determine - * what characters are represented by any consecutive sequences of the - * form "{@code %xy}". + * Decodes an {@code application/x-www-form-urlencoded} string using + * a specific encoding scheme. + * *

            - * Note: The - * World Wide Web Consortium Recommendation states that - * UTF-8 should be used. Not doing so may introduce - * incompatibilities. + * This method behaves the same as {@linkplain String decode(String s, Charset charset)} + * except that it will {@linkplain java.nio.charset.Charset#forName look up the charset} + * using the given encoding name. + * + * @implNote This implementation will throw an {@link java.lang.IllegalArgumentException} + * when illegal strings are encountered. * * @param s the {@code String} to decode * @param enc The name of a supported * character * encoding. * @return the newly decoded {@code String} - * @exception UnsupportedEncodingException + * @throws UnsupportedEncodingException * If character encoding needs to be consulted, but * named character encoding is not supported * @see URLEncoder#encode(java.lang.String, java.lang.String) * @since 1.4 */ - public static String decode(String s, String enc) - throws UnsupportedEncodingException{ + public static String decode(String s, String enc) throws UnsupportedEncodingException { + if (enc.isEmpty()) { + throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter"); + } + + try { + Charset charset = Charset.forName(enc); + return decode(s, charset); + } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { + throw new UnsupportedEncodingException(enc); + } + } + /** + * Decodes an {@code application/x-www-form-urlencoded} string using + * a specific {@linkplain java.nio.charset.Charset Charset}. + * The supplied charset is used to determine + * what characters are represented by any consecutive sequences of the + * form "{@code %xy}". + *

            + * Note: The + * World Wide Web Consortium Recommendation states that + * UTF-8 should be used. Not doing so may introduce + * incompatibilities. + * + * @implNote This implementation will throw an {@link java.lang.IllegalArgumentException} + * when illegal strings are encountered. + * + * @param s the {@code String} to decode + * @param charset the given charset + * @return the newly decoded {@code String} + * @throws NullPointerException if {@code s} or {@code charset} is {@code null} + * @throws IllegalArgumentException if the implementation encounters illegal + * characters + * @see URLEncoder#encode(java.lang.String, java.nio.charset.Charset) + * @since 10 + */ + public static String decode(String s, Charset charset) { + Objects.requireNonNull(charset, "Charset"); boolean needToChange = false; int numChars = s.length(); - StringBuffer sb = new StringBuffer(numChars > 500 ? numChars / 2 : numChars); + StringBuilder sb = new StringBuilder(numChars > 500 ? numChars / 2 : numChars); int i = 0; - if (enc.length() == 0) { - throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter"); - } - char c; byte[] bytes = null; while (i < numChars) { @@ -196,7 +232,7 @@ public static String decode(String s, String enc) throw new IllegalArgumentException( "URLDecoder: Incomplete trailing escape (%) pattern"); - sb.append(new String(bytes, 0, pos, enc)); + sb.append(new String(bytes, 0, pos, charset)); } catch (NumberFormatException e) { throw new IllegalArgumentException( "URLDecoder: Illegal hex characters in escape (%) pattern - " diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLEncoder.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLEncoder.java index 8d26d2e0e8..43a3544dc3 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLEncoder.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,16 @@ package java.net; -import java.io.ByteArrayOutputStream; -import java.io.BufferedWriter; -import java.io.OutputStreamWriter; -import java.io.IOException; import java.io.UnsupportedEncodingException; import java.io.CharArrayWriter; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException ; import java.util.BitSet; +import java.util.Objects; /* J2ObjC removed. -import java.security.AccessController; -import java.security.PrivilegedAction; -import sun.security.action.GetBooleanAction; import sun.security.action.GetPropertyAction; - */ +*/ /** * Utility class for HTML form encoding. This class contains static methods @@ -79,7 +73,7 @@ * character @ is encoded as one byte 40 (hex). * * @author Herb Jellinek - * @since JDK1.0 + * @since 1.0 */ public class URLEncoder { static BitSet dontNeedEncoding; @@ -182,44 +176,60 @@ public static String encode(String s) { /** * Translates a string into {@code application/x-www-form-urlencoded} - * format using a specific encoding scheme. This method uses the - * supplied encoding scheme to obtain the bytes for unsafe - * characters. + * format using a specific encoding scheme. *

            - * Note: The - * World Wide Web Consortium Recommendation states that - * UTF-8 should be used. Not doing so may introduce - * incompatibilities. + * This method behaves the same as {@linkplain String encode(String s, Charset charset)} + * except that it will {@linkplain java.nio.charset.Charset#forName look up the charset} + * using the given encoding name. * * @param s {@code String} to be translated. * @param enc The name of a supported * character * encoding. * @return the translated {@code String}. - * @exception UnsupportedEncodingException + * @throws UnsupportedEncodingException * If the named encoding is not supported * @see URLDecoder#decode(java.lang.String, java.lang.String) * @since 1.4 */ public static String encode(String s, String enc) throws UnsupportedEncodingException { - - boolean needToChange = false; - StringBuffer out = new StringBuffer(s.length()); - Charset charset; - CharArrayWriter charArrayWriter = new CharArrayWriter(); - - if (enc == null) + if (enc == null) { throw new NullPointerException("charsetName"); + } try { - charset = Charset.forName(enc); - } catch (IllegalCharsetNameException e) { - throw new UnsupportedEncodingException(enc); - } catch (UnsupportedCharsetException e) { + Charset charset = Charset.forName(enc); + return encode(s, charset); + } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { throw new UnsupportedEncodingException(enc); } + } + + /** + * Translates a string into {@code application/x-www-form-urlencoded} + * format using a specific {@linkplain java.nio.charset.Charset Charset}. + * This method uses the supplied charset to obtain the bytes for unsafe + * characters. + *

            + * Note: The + * World Wide Web Consortium Recommendation states that + * UTF-8 should be used. Not doing so may introduce incompatibilities. + * + * @param s {@code String} to be translated. + * @param charset the given charset + * @return the translated {@code String}. + * @throws NullPointerException if {@code s} or {@code charset} is {@code null}. + * @see URLDecoder#decode(java.lang.String, java.nio.charset.Charset) + * @since 10 + */ + public static String encode(String s, Charset charset) { + Objects.requireNonNull(charset, "charset"); + + boolean needToChange = false; + StringBuilder out = new StringBuilder(s.length()); + CharArrayWriter charArrayWriter = new CharArrayWriter(); for (int i = 0; i < s.length();) { int c = (int) s.charAt(i); @@ -239,7 +249,7 @@ public static String encode(String s, String enc) /* * If this character represents the start of a Unicode * surrogate pair, then pass in two characters. It's not - * clear what should be done if a bytes reserved in the + * clear what should be done if a byte reserved in the * surrogate pairs range occurs outside of a legal * surrogate pair. For now, just treat it as if it were * any other character. diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLStreamHandler.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLStreamHandler.java index a56c0a1c83..5896975ac8 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLStreamHandler.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLStreamHandler.java @@ -134,9 +134,9 @@ protected void parseURL(URL u, String spec, int start, int limit) { boolean isRelPath = false; boolean queryOnly = false; - // BEGIN Android-changed + // BEGIN Android-changed: App compat. boolean querySet = false; - // END Android-changed + // END Android-changed: App compat. // FIX: should not assume query if opaque // Strip off the query part @@ -148,31 +148,44 @@ protected void parseURL(URL u, String spec, int start, int limit) { if (limit > queryStart) limit = queryStart; spec = spec.substring(0, queryStart); - // BEGIN Android-changed + // BEGIN Android-changed: App compat. querySet = true; - // END Android-changed + // END Android-changed: App compat. } } int i = 0; // Parse the authority part if any - // BEGIN Android-changed + // BEGIN Android-changed: App compat. // boolean isUNCName = (start <= limit - 4) && // (spec.charAt(start) == '/') && // (spec.charAt(start + 1) == '/') && // (spec.charAt(start + 2) == '/') && // (spec.charAt(start + 3) == '/'); boolean isUNCName = false; - // END Android-changed + // END Android-changed: App compat. if (!isUNCName && (start <= limit - 2) && (spec.charAt(start) == '/') && (spec.charAt(start + 1) == '/')) { start += 2; + // BEGIN Android-changed: Check for all hostname termination chars. http://b/110955991 + /* i = spec.indexOf('/', start); if (i < 0 || i > limit) { i = spec.indexOf('?', start); if (i < 0 || i > limit) i = limit; } + */ + LOOP: for (i = start; i < limit; i++) { + switch (spec.charAt(i)) { + case '/': // Start of path + case '\\': // Start of path - see https://url.spec.whatwg.org/#host-state + case '?': // Start of query + case '#': // Start of fragment + break LOOP; + } + } + // END Android-changed: Check for all hostname termination chars. http://b/110955991 host = authority = spec.substring(start, i); @@ -226,7 +239,7 @@ protected void parseURL(URL u, String spec, int start, int limit) { if (ind >= 0) { // port can be null according to RFC2396 if (host.length() > (ind + 1)) { - // BEGIN Android-changed + // BEGIN Android-changed: App compat. // port = Integer.parseInt(host.substring(ind + 1)); char firstPortChar = host.charAt(ind+1); if (firstPortChar >= '0' && firstPortChar <= '9') { @@ -235,7 +248,7 @@ protected void parseURL(URL u, String spec, int start, int limit) { throw new IllegalArgumentException("invalid port: " + host.substring(ind + 1)); } - // END Android-changed + // END Android-changed: App compat. } host = host.substring(0, ind); } @@ -248,16 +261,16 @@ protected void parseURL(URL u, String spec, int start, int limit) { port); start = i; - // BEGIN Android-changed // If the authority is defined then the path is defined by the // spec only; See RFC 2396 Section 5.2.4. + // BEGIN Android-changed: App compat. // if (authority != null && authority.length() > 0) // path = ""; path = null; if (!querySet) { query = null; } - // END Android-changed + // END Android-changed: App compat. } if (host == null) { @@ -266,7 +279,9 @@ protected void parseURL(URL u, String spec, int start, int limit) { // Parse the file path if any if (start < limit) { - if (spec.charAt(start) == '/') { + // Android-changed: Check for all hostname termination chars. http://b/110955991 + // if (spec.charAt(start) == '/') { + if (spec.charAt(start) == '/' || spec.charAt(start) == '\\') { path = spec.substring(start, limit); } else if (path != null && path.length() > 0) { isRelPath = true; @@ -282,21 +297,21 @@ protected void parseURL(URL u, String spec, int start, int limit) { path = seperator + spec.substring(start, limit); } } - // BEGIN Android-changed + // BEGIN Android-changed: App compat. //else if (queryOnly && path != null) { // int ind = path.lastIndexOf('/'); // if (ind < 0) // ind = 0; // path = path.substring(0, ind) + "/"; //} - // END Android-changed + // END Android-changed: App compat. if (path == null) path = ""; - // BEGIN Android-changed + // BEGIN Android-changed: always assume isRelPath is true. //if (isRelPath) { if (true) { - // END Android-changed + // END Android-changed: always assume isRelPath is true. // Remove embedded /./ while ((i = path.indexOf("/./")) >= 0) { path = path.substring(0, i) + path.substring(i + 2); @@ -304,20 +319,22 @@ protected void parseURL(URL u, String spec, int start, int limit) { // Remove embedded /../ if possible i = 0; while ((i = path.indexOf("/../", i)) >= 0) { - // BEGIN Android-changed + // BEGIN Android-changed: App compat. /* * Trailing /../ */ if (i == 0) { path = path.substring(i + 3); i = 0; - // END Android-changed + // END Android-changed: App compat. /* * A "/../" will cancel the previous segment and itself, * unless that segment is a "/../" itself * i.e. "/a/b/../c" becomes "/a/c" * but "/../../a" should stay unchanged */ + // Android-changed: App compat. + // if (i > 0 && (limit = path.lastIndexOf('/', i - 1)) >= 0 && } else if (i > 0 && (limit = path.lastIndexOf('/', i - 1)) >= 0 && (path.indexOf("/../", limit) != 0)) { path = path.substring(0, limit) + path.substring(i + 3); @@ -343,7 +360,7 @@ protected void parseURL(URL u, String spec, int start, int limit) { if (path.endsWith("/.")) path = path.substring(0, path.length() -1); - // Remove trailing ? + // Android-changed: App compat: Remove trailing '?'. if (path.endsWith("?")) path = path.substring(0, path.length() -1); } @@ -374,6 +391,7 @@ protected int getDefaultPort() { * @since 1.3 */ protected boolean equals(URL u1, URL u2) { + // Android-changed: Avoid network I/O. return Objects.equals(u1.getRef(), u2.getRef()) && Objects.equals(u1.getQuery(), u2.getQuery()) && // sameFile compares the protocol, file, port & host components of @@ -390,6 +408,7 @@ protected boolean equals(URL u1, URL u2) { * @since 1.3 */ protected int hashCode(URL u) { + // Android-changed: Avoid network I/O. // Hash on the same set of fields that we compare in equals(). return Objects.hash( u.getRef(), @@ -425,13 +444,14 @@ protected boolean sameFile(URL u1, URL u2) { // Compare the ports. int port1, port2; + // J2ObjC modified try { port1 = (u1.getPort() != -1) ? u1.getPort() : ((URLStreamHandler) u1.getHandler()).getDefaultPort(); port2 = (u2.getPort() != -1) ? u2.getPort() : ((URLStreamHandler) u2.getHandler()).getDefaultPort(); - if (port1 != port2) - return false; + if (port1 != port2) + return false; } catch (MalformedURLException e) { return false; } @@ -509,6 +529,8 @@ protected String toExternalForm(URL u) { if (u.getRef() != null) len += 1 + u.getRef().length(); + // BEGIN Android-changed: New toExternalForm variant that optionally escapes illegal chars. + // TODO: The variant has been removed. We can potentially revert the change StringBuilder result = new StringBuilder(len); result.append(u.getProtocol()); result.append(":"); @@ -520,6 +542,7 @@ protected String toExternalForm(URL u) { if (fileAndQuery != null) { result.append(fileAndQuery); } + // END Android-changed: New toExternalForm variant that optionally escapes illegal chars. if (u.getRef() != null) { result.append("#"); result.append(u.getRef()); @@ -527,6 +550,8 @@ protected String toExternalForm(URL u) { return result.toString(); } + // Android-changed: Removed @see tag (target is package-private). + // @see java.net.URL#set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String) /** * Sets the fields of the {@code URL} argument to the indicated values. * Only classes derived from URLStreamHandler are able @@ -543,7 +568,6 @@ protected String toExternalForm(URL u) { * @param ref the reference. * @exception SecurityException if the protocol handler of the URL is * different from this one - * @see java.net.URL#set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String) * @since 1.3 */ protected void setURL(URL u, String protocol, String host, int port, @@ -551,8 +575,8 @@ protected void setURL(URL u, String protocol, String host, int port, String query, String ref) { try { if (this != u.getHandler()) { - throw new SecurityException("handler for url different from " + - "this handler"); + throw new SecurityException("handler for url different from " + + "this handler"); } } catch (MalformedURLException e) { // Ignore. diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLStreamHandlerFactory.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLStreamHandlerFactory.java index e46e02857e..c35af100b9 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLStreamHandlerFactory.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/URLStreamHandlerFactory.java @@ -28,14 +28,14 @@ /** * This interface defines a factory for {@code URL} stream * protocol handlers. - *

            - * It is used by the {@code URL} class to create a - * {@code URLStreamHandler} for a specific protocol. + * + *

            A URL stream handler factory is used as specified in the + * {@linkplain java.net.URL#URL(String,String,int,String) URL constructor}. * * @author Arthur van Hoff * @see java.net.URL * @see java.net.URLStreamHandler - * @since JDK1.0 + * @since 1.0 */ public interface URLStreamHandlerFactory { /** @@ -44,7 +44,9 @@ public interface URLStreamHandlerFactory { * * @param protocol the protocol ("{@code ftp}", * "{@code http}", "{@code nntp}", etc.). - * @return a {@code URLStreamHandler} for the specific protocol. + * @return a {@code URLStreamHandler} for the specific protocol, or {@code + * null} if this factory cannot create a handler for the specific + * protocol * @see java.net.URLStreamHandler */ URLStreamHandler createURLStreamHandler(String protocol); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/UnknownHostException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/UnknownHostException.java index 21a9d1450c..9a9fea53fa 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/UnknownHostException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/UnknownHostException.java @@ -31,7 +31,7 @@ * Thrown to indicate that the IP address of a host could not be determined. * * @author Jonathan Payne - * @since JDK1.0 + * @since 1.0 */ public class UnknownHostException extends IOException { @@ -41,10 +41,10 @@ class UnknownHostException extends IOException { * Constructs a new {@code UnknownHostException} with the * specified detail message. * - * @param host the detail message. + * @param message the detail message. */ - public UnknownHostException(String host) { - super(host); + public UnknownHostException(String message) { + super(message); } /** diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/UnknownServiceException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/UnknownServiceException.java index 4eea4a769d..7daa8a47c6 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/UnknownServiceException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/net/UnknownServiceException.java @@ -34,7 +34,7 @@ * read-only URL connection. * * @author unascribed - * @since JDK1.0 + * @since 1.0 */ public class UnknownServiceException extends IOException { private static final long serialVersionUID = -4169033248853639508L;