This commit is contained in:
Phil Race 2017-08-16 11:31:56 -07:00
commit a6132067a5
38 changed files with 2907 additions and 192 deletions

View File

@ -72,10 +72,13 @@ import sun.net.util.IPAddressUtil;
*
* <h3> Address types </h3>
*
* <blockquote><table class="borderless">
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">Description of unicast and multicast address types</caption>
* <thead>
* <tr><th scope="col">Address Type</th><th scope="col">Description</th></tr>
* </thead>
* <tbody>
* <tr><th style="vertical-align:top"><i>unicast</i></th>
* <tr><th scope="row" style="vertical-align:top">unicast</th>
* <td>An identifier for a single interface. A packet sent to
* a unicast address is delivered to the interface identified by
* that address.
@ -94,12 +97,12 @@ import sun.net.util.IPAddressUtil;
* IP address loops around and becomes IP input on the local
* host. This address is often used when testing a
* client.</td></tr>
* <tr><th style="vertical-align:top"><i>multicast</i></th>
* <tr><th scope="row" style="vertical-align:top">multicast</th>
* <td>An identifier for a set of interfaces (typically belonging
* to different nodes). A packet sent to a multicast address is
* delivered to all interfaces identified by that address.</td></tr>
* </tbody>
* </table></blockquote>
* </table>
*
* <h4> IP address scope </h4>
*
@ -163,8 +166,7 @@ import sun.net.util.IPAddressUtil;
* <p> Two Java security properties control the TTL values used for
* positive and negative host name resolution caching:
*
* <blockquote>
* <dl>
* <dl style="margin-left:2em">
* <dt><b>networkaddress.cache.ttl</b></dt>
* <dd>Indicates the caching policy for successful name lookups from
* the name service. The value is specified as an integer to indicate
@ -183,7 +185,6 @@ import sun.net.util.IPAddressUtil;
* A value of -1 indicates "cache forever".
* </dd>
* </dl>
* </blockquote>
*
* @author Chris Warth
* @see java.net.InetAddress#getByAddress(byte[])

View File

@ -132,23 +132,23 @@ import java.lang.NullPointerException; // for javadoc
*
* <p> All told, then, a URI instance has the following nine components:
*
* <blockquote><table class="borderless">
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">Describes the components of a URI:scheme,scheme-specific-part,authority,user-info,host,port,path,query,fragment</caption>
* <thead>
* <tr><th><i>Component</i></th><th><i>Type</i></th></tr>
* <tr><th scope="col">Component</th><th scope="col">Type</th></tr>
* </thead>
* <tbody>
* <tr><td>scheme</td><td>{@code String}</td></tr>
* <tr><td>scheme-specific-part&nbsp;&nbsp;&nbsp;&nbsp;</td><td>{@code String}</td></tr>
* <tr><td>authority</td><td>{@code String}</td></tr>
* <tr><td>user-info</td><td>{@code String}</td></tr>
* <tr><td>host</td><td>{@code String}</td></tr>
* <tr><td>port</td><td>{@code int}</td></tr>
* <tr><td>path</td><td>{@code String}</td></tr>
* <tr><td>query</td><td>{@code String}</td></tr>
* <tr><td>fragment</td><td>{@code String}</td></tr>
* <tbody style="text-align:left">
* <tr><th scope="row">scheme</th><td>{@code String}</td></tr>
* <tr><th scope="row">scheme-specific-part</th><td>{@code String}</td></tr>
* <tr><th scope="row">authority</th><td>{@code String}</td></tr>
* <tr><th scope="row">user-info</th><td>{@code String}</td></tr>
* <tr><th scope="row">host</th><td>{@code String}</td></tr>
* <tr><th scope="row">port</th><td>{@code int}</td></tr>
* <tr><th scope="row">path</th><td>{@code String}</td></tr>
* <tr><th scope="row">query</th><td>{@code String}</td></tr>
* <tr><th scope="row">fragment</th><td>{@code String}</td></tr>
* </tbody>
* </table></blockquote>
* </table>
*
* In a given instance any particular component is either <i>undefined</i> or
* <i>defined</i> with a distinct value. Undefined string components are
@ -253,32 +253,35 @@ import java.lang.NullPointerException; // for javadoc
* which are taken from that specification, are used below to describe these
* constraints:
*
* <blockquote><table class="borderless">
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">Describes categories alpha,digit,alphanum,unreserved,punct,reserved,escaped,and other</caption>
* <tbody>
* <tr><th style="vertical-align:top"><i>alpha</i></th>
* <thead>
* <tr><th scope="col">Category</th><th scope="col">Description</th></tr>
* </thead>
* <tbody style="text-align:left">
* <tr><th scope="row" style="vertical-align:top">alpha</th>
* <td>The US-ASCII alphabetic characters,
* {@code 'A'}&nbsp;through&nbsp;{@code 'Z'}
* and {@code 'a'}&nbsp;through&nbsp;{@code 'z'}</td></tr>
* <tr><th style="vertical-align:top"><i>digit</i></th>
* <tr><th scope="row" style="vertical-align:top">digit</th>
* <td>The US-ASCII decimal digit characters,
* {@code '0'}&nbsp;through&nbsp;{@code '9'}</td></tr>
* <tr><th style="vertical-align:top"><i>alphanum</i></th>
* <tr><th scope="row" style="vertical-align:top">alphanum</th>
* <td>All <i>alpha</i> and <i>digit</i> characters</td></tr>
* <tr><th style="vertical-align:top"><i>unreserved</i>&nbsp;&nbsp;&nbsp;&nbsp;</th>
* <tr><th scope="row" style="vertical-align:top">unreserved</th>
* <td>All <i>alphanum</i> characters together with those in the string
* {@code "_-!.~'()*"}</td></tr>
* <tr><th style="vertical-align:top"><i>punct</i></th>
* <tr><th scope="row" style="vertical-align:top">punct</th>
* <td>The characters in the string {@code ",;:$&+="}</td></tr>
* <tr><th style="vertical-align:top"><i>reserved</i></th>
* <tr><th scope="row" style="vertical-align:top">reserved</th>
* <td>All <i>punct</i> characters together with those in the string
* {@code "?/[]@"}</td></tr>
* <tr><th style="vertical-align:top"><i>escaped</i></th>
* <tr><th scope="row" style="vertical-align:top">escaped</th>
* <td>Escaped octets, that is, triplets consisting of the percent
* character ({@code '%'}) followed by two hexadecimal digits
* ({@code '0'}-{@code '9'}, {@code 'A'}-{@code 'F'}, and
* {@code 'a'}-{@code 'f'})</td></tr>
* <tr><th style="vertical-align:top"><i>other</i></th>
* <tr><th scope="row" style="vertical-align:top">other</th>
* <td>The Unicode characters that are not in the US-ASCII character set,
* are not control characters (according to the {@link
* java.lang.Character#isISOControl(char) Character.isISOControl}
@ -287,7 +290,7 @@ import java.lang.NullPointerException; // for javadoc
* method)&nbsp;&nbsp;<i>(<b>Deviation from RFC 2396</b>, which is
* limited to US-ASCII)</i></td></tr>
* </tbody>
* </table></blockquote>
* </table>
*
* <p><a id="legal-chars"></a> The set of all legal URI characters consists of
* the <i>unreserved</i>, <i>reserved</i>, <i>escaped</i>, and <i>other</i>

View File

@ -51,31 +51,16 @@ import sun.security.action.GetPropertyAction;
* The abstract class {@code URLConnection} is the superclass
* of all classes that represent a communications link between the
* application and a URL. Instances of this class can be used both to
* read from and to write to the resource referenced by the URL. In
* general, creating a connection to a URL is a multistep process:
*
* <div style="text-align:center"><table class="plain" style="margin:0 auto">
* <caption style="display:none">Describes the process of creating a connection to a URL: openConnection() and connect() over time.</caption>
* <thead>
* <tr><th>{@code openConnection()}</th>
* <th>{@code connect()}</th></tr>
* </thead>
* <tbody>
* <tr><td>Manipulate parameters that affect the connection to the remote
* resource.</td>
* <td>Interact with the resource; query header fields and
* contents.</td></tr>
* </tbody>
* </table>
* ----------------------------&gt;
* <br>time</div>
* read from and to write to the resource referenced by the URL.
*
* <p>
* In general, creating a connection to a URL is a multistep process:
* <ol>
* <li>The connection object is created by invoking the
* {@code openConnection} method on a URL.
* {@link URL#openConnection() openConnection} method on a URL.
* <li>The setup parameters and general request properties are manipulated.
* <li>The actual connection to the remote object is made, using the
* {@code connect} method.
* {@link #connect() connect} method.
* <li>The remote object becomes available. The header fields and the contents
* of the remote object can be accessed.
* </ol>

View File

@ -72,22 +72,22 @@ import java.security.Permission;
* separated by '/' characters. <i>path</i> may also be empty. The path is specified
* in a similar way to the path in {@link java.io.FilePermission}. There are
* three different ways as the following examples show:
* <table class="plain">
* <table class="striped">
* <caption>URL Examples</caption>
* <thead>
* <tr><th>Example url</th><th>Description</th></tr>
* <tr><th scope="col">Example url</th><th scope="col">Description</th></tr>
* </thead>
* <tbody>
* <tr><td style="white-space:nowrap;">http://www.oracle.com/a/b/c.html</td>
* <tbody style="text-align:left">
* <tr><th scope="row" style="white-space:nowrap;">http://www.oracle.com/a/b/c.html</th>
* <td>A url which identifies a specific (single) resource</td>
* </tr>
* <tr><td>http://www.oracle.com/a/b/*</td>
* <tr><th scope="row">http://www.oracle.com/a/b/*</th>
* <td>The '*' character refers to all resources in the same "directory" - in
* other words all resources with the same number of path components, and
* which only differ in the final path component, represented by the '*'.
* </td>
* </tr>
* <tr><td>http://www.oracle.com/a/b/-</td>
* <tr><th scope="row">http://www.oracle.com/a/b/-</th>
* <td>The '-' character refers to all resources recursively below the
* preceding path (eg. http://www.oracle.com/a/b/c/d/e.html matches this
* example).
@ -114,11 +114,12 @@ import java.security.Permission;
* methods and permitted request headers of the permission (respectively). The two lists
* are separated by a colon ':' character and elements of each list are comma separated.
* Some examples are:
* <pre>
* "POST,GET,DELETE"
* "GET:X-Foo-Request,X-Bar-Request"
* "POST,GET:Header1,Header2"
* </pre>
* <ul>
* <li>"POST,GET,DELETE"
* <li>"GET:X-Foo-Request,X-Bar-Request"
* <li>"POST,GET:Header1,Header2"
* </ul>
* <p>
* The first example specifies the methods: POST, GET and DELETE, but no request headers.
* The second example specifies one request method and two headers. The third
* example specifies two request methods, and two headers.
@ -253,16 +254,16 @@ public final class URLPermission extends Permission {
* <table class="plain">
* <caption>Examples of Path Matching</caption>
* <thead>
* <tr><th>this's path</th><th>p's path</th><th>match</th></tr>
* <tr><th scope="col">this's path</th><th scope="col">p's path</th><th>match</th></tr>
* </thead>
* <tbody>
* <tr><td>/a/b</td><td>/a/b</td><td>yes</td></tr>
* <tr><td>/a/b/*</td><td>/a/b/c</td><td>yes</td></tr>
* <tr><td>/a/b/*</td><td>/a/b/c/d</td><td>no</td></tr>
* <tr><td>/a/b/-</td><td>/a/b/c/d</td><td>yes</td></tr>
* <tr><td>/a/b/-</td><td>/a/b/c/d/e</td><td>yes</td></tr>
* <tr><td>/a/b/-</td><td>/a/b/c/*</td><td>yes</td></tr>
* <tr><td>/a/b/*</td><td>/a/b/c/-</td><td>no</td></tr>
* <tbody style="text-align:left">
* <tr><th scope="row">/a/b</th><th scope="row">/a/b</th><td>yes</td></tr>
* <tr><th scope="row" rowspan="3">/a/b/*</th><th scope="row">/a/b/c</th><td>yes</td></tr>
* <tr> <th scope="row">/a/b/c/d</th><td>no</td></tr>
* <tr> <th scope="row">/a/b/c/-</th><td>no</td></tr>
* <tr><th scope="row" rowspan="3">/a/b/-</th><th scope="row">/a/b/c/d</th><td>yes</td></tr>
* <tr> <th scope="row">/a/b/c/d/e</th><td>yes</td></tr>
* <tr> <th scope="row">/a/b/c/*</th><td>yes</td></tr>
* </tbody>
* </table>
*/

View File

@ -23,7 +23,7 @@
or visit www.oracle.com if you need additional information or have any
questions.
-->
<HTML>
<HTML lang="EN">
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<TITLE>Networking Properties</TITLE>
@ -35,7 +35,7 @@ alter the mechanisms and behavior of the various classes of the
java.net package. Some are checked only once at startup of the VM,
and therefore are best set using the -D option of the java command,
while others have a more dynamic nature and can also be changed using
the <a href="../../lang/System.html#setProperty(java.lang.String,%20java.lang.String)">System.setProperty()</a> API.
the <a href="../../lang/System.html#setProperty-java.lang.String-java.lang.String-">System.setProperty()</a> API.
The purpose of this document is to list
and detail all of these properties.</P>
<P>If there is no special note, a property value is checked every time it is used.</P>

View File

@ -263,18 +263,18 @@ public class DrbgParameters {
* Capability effective = ((DrbgParametes.Initiate) s.getParameters())
* .getCapability();</pre>
* </blockquote>
* <table class="plain">
* <table class="striped">
* <caption style="display:none">requested and effective capabilities</caption>
* <thead>
* <tr>
* <th>Requested Value</th>
* <th>Possible Effective Values</th>
* <th scope="col">Requested Value</th>
* <th scope="col">Possible Effective Values</th>
* </tr>
* </thead>
* <tbody>
* <tr><td>NONE</td><td>NONE, RESEED_ONLY, PR_AND_RESEED</td></tr>
* <tr><td>RESEED_ONLY</td><td>RESEED_ONLY, PR_AND_RESEED</td></tr>
* <tr><td>PR_AND_RESEED</td><td>PR_AND_RESEED</td></tr>
* <tbody style="text-align:left">
* <tr><th scope="row">NONE</th><td>NONE, RESEED_ONLY, PR_AND_RESEED</td></tr>
* <tr><th scope="row">RESEED_ONLY</th><td>RESEED_ONLY, PR_AND_RESEED</td></tr>
* <tr><th scope="row">PR_AND_RESEED</th><td>PR_AND_RESEED</td></tr>
* </tbody>
* </table>
* <p>

View File

@ -61,19 +61,19 @@ import java.util.function.Function;
* security framework. Services of this type cannot be added, removed,
* or modified by applications.
* The following attributes are automatically placed in each Provider object:
* <table class="plain">
* <table class="striped">
* <caption><b>Attributes Automatically Placed in a Provider Object</b></caption>
* <thead>
* <tr><th>Name</th><th>Value</th>
* <tr><th scope="col">Name</th><th scope="col">Value</th>
* </thead>
* <tbody>
* <tr><td>{@code Provider.id name}</td>
* <tbody style="text-align:left">
* <tr><th scope="row">{@code Provider.id name}</th>
* <td>{@code String.valueOf(provider.getName())}</td>
* <tr><td>{@code Provider.id version}</td>
* <tr><th scope="row">{@code Provider.id version}</th>
* <td>{@code String.valueOf(provider.getVersionStr())}</td>
* <tr><td>{@code Provider.id info}</td>
* <tr><th scope="row">{@code Provider.id info}</th>
* <td>{@code String.valueOf(provider.getInfo())}</td>
* <tr><td>{@code Provider.id className}</td>
* <tr><th scope="row">{@code Provider.id className}</th>
* <td>{@code provider.getClass().getName()}</td>
* </tbody>
* </table>

View File

@ -153,33 +153,33 @@ public interface X509Extension {
* by periods.
*
* <p>For example:<br>
* <table class="plain">
* <table class="striped">
* <caption style="display:none">Examples of OIDs and extension names</caption>
* <thead>
* <tr>
* <th>OID <em>(Object Identifier)</em></th>
* <th>Extension Name</th></tr>
* <th scope="col">OID <em>(Object Identifier)</em></th>
* <th scope="col">Extension Name</th></tr>
* </thead>
* <tbody>
* <tr><td>2.5.29.14</td>
* <tbody style="text-align:left">
* <tr><th scope="row">2.5.29.14</th>
* <td>SubjectKeyIdentifier</td></tr>
* <tr><td>2.5.29.15</td>
* <tr><th scope="row">2.5.29.15</th>
* <td>KeyUsage</td></tr>
* <tr><td>2.5.29.16</td>
* <tr><th scope="row">2.5.29.16</th>
* <td>PrivateKeyUsage</td></tr>
* <tr><td>2.5.29.17</td>
* <tr><th scope="row">2.5.29.17</th>
* <td>SubjectAlternativeName</td></tr>
* <tr><td>2.5.29.18</td>
* <tr><th scope="row">2.5.29.18</th>
* <td>IssuerAlternativeName</td></tr>
* <tr><td>2.5.29.19</td>
* <tr><th scope="row">2.5.29.19</th>
* <td>BasicConstraints</td></tr>
* <tr><td>2.5.29.30</td>
* <tr><th scope="row">2.5.29.30</th>
* <td>NameConstraints</td></tr>
* <tr><td>2.5.29.33</td>
* <tr><th scope="row">2.5.29.33</th>
* <td>PolicyMappings</td></tr>
* <tr><td>2.5.29.35</td>
* <tr><th scope="row">2.5.29.35</th>
* <td>AuthorityKeyIdentifier</td></tr>
* <tr><td>2.5.29.36</td>
* <tr><th scope="row">2.5.29.36</th>
* <td>PolicyConstraints</td></tr>
* </tbody>
* </table>

View File

@ -81,13 +81,24 @@ class ZipUtils {
* Converts DOS time to Java time (number of milliseconds since epoch).
*/
public static long dosToJavaTime(long dtime) {
LocalDateTime ldt = LocalDateTime.of(
(int) (((dtime >> 25) & 0x7f) + 1980),
(int) ((dtime >> 21) & 0x0f),
(int) ((dtime >> 16) & 0x1f),
(int) ((dtime >> 11) & 0x1f),
(int) ((dtime >> 5) & 0x3f),
(int) ((dtime << 1) & 0x3e));
int year;
int month;
int day;
int hour = (int) ((dtime >> 11) & 0x1f);
int minute = (int) ((dtime >> 5) & 0x3f);
int second = (int) ((dtime << 1) & 0x3e);
if ((dtime >> 16) == 0) {
// Interpret the 0 DOS date as 1979-11-30 for compatibility with
// other implementations.
year = 1979;
month = 11;
day = 30;
} else {
year = (int) (((dtime >> 25) & 0x7f) + 1980);
month = (int) ((dtime >> 21) & 0x0f);
day = (int) ((dtime >> 16) & 0x1f);
}
LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, minute, second);
return TimeUnit.MILLISECONDS.convert(ldt.toEpochSecond(
ZoneId.systemDefault().getRules().getOffset(ldt)), TimeUnit.SECONDS);
}

View File

@ -1292,7 +1292,7 @@ public abstract class SSLEngine {
* href="http://www.ietf.org/rfc/rfc7301.txt"> RFC 7301 </a>, the
* Application-Layer Protocol Negotiation (ALPN), can negotiate
* application-level values between peers.
* <p>
*
* @implSpec
* The implementation in this class throws
* {@code UnsupportedOperationException} and performs no other action.
@ -1317,7 +1317,7 @@ public abstract class SSLEngine {
* Like {@link #getHandshakeSession()},
* a connection may be in the middle of a handshake. The
* application protocol may or may not yet be available.
* <p>
*
* @implSpec
* The implementation in this class throws
* {@code UnsupportedOperationException} and performs no other action.

View File

@ -646,7 +646,7 @@ public class SSLParameters {
* requested by the peer, the underlying protocol will determine what
* action to take. (For example, ALPN will send a
* {@code "no_application_protocol"} alert and terminate the connection.)
* <p>
*
* @implSpec
* This method will make a copy of the {@code protocols} array.
*

View File

@ -702,7 +702,7 @@ public abstract class SSLSocket extends Socket
* href="http://www.ietf.org/rfc/rfc7301.txt"> RFC 7301 </a>, the
* Application-Layer Protocol Negotiation (ALPN), can negotiate
* application-level values between peers.
* <p>
*
* @implSpec
* The implementation in this class throws
* {@code UnsupportedOperationException} and performs no other action.
@ -727,7 +727,7 @@ public abstract class SSLSocket extends Socket
* Like {@link #getHandshakeSession()},
* a connection may be in the middle of a handshake. The
* application protocol may or may not yet be available.
* <p>
*
* @implSpec
* The implementation in this class throws
* {@code UnsupportedOperationException} and performs no other action.

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.incubator.http;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.concurrent.CompletableFuture;
import javax.net.ssl.SSLEngine;
import jdk.incubator.http.internal.common.ExceptionallyCloseable;
/**
* Asynchronous version of SSLConnection.
*
* There are two concrete implementations of this class: AsyncSSLConnection
* and AsyncSSLTunnelConnection.
* This abstraction is useful when downgrading from HTTP/2 to HTTP/1.1 over
* an SSL connection. See ExchangeImpl::get in the case where an ALPNException
* is thrown.
*
* Note: An AsyncSSLConnection wraps a PlainHttpConnection, while an
* AsyncSSLTunnelConnection wraps a PlainTunnelingConnection.
* If both these wrapped classes where made to inherit from a
* common abstraction then it might be possible to merge
* AsyncSSLConnection and AsyncSSLTunnelConnection back into
* a single class - and simply use different factory methods to
* create different wrappees, but this is left up for further cleanup.
*
*/
abstract class AbstractAsyncSSLConnection extends HttpConnection
implements AsyncConnection, ExceptionallyCloseable {
AbstractAsyncSSLConnection(InetSocketAddress addr, HttpClientImpl client) {
super(addr, client);
}
abstract SSLEngine getEngine();
abstract AsyncSSLDelegate sslDelegate();
abstract HttpConnection plainConnection();
abstract HttpConnection downgrade();
@Override
final boolean isSecure() {
return true;
}
// Blocking read functions not used here
@Override
protected final ByteBuffer readImpl() throws IOException {
throw new UnsupportedOperationException("Not supported.");
}
// whenReceivedResponse only used in HTTP/1.1 (Http1Exchange)
// AbstractAsyncSSLConnection is only used with HTTP/2
@Override
final CompletableFuture<Void> whenReceivingResponse() {
throw new UnsupportedOperationException("Not supported.");
}
}

View File

@ -35,14 +35,12 @@ import java.util.function.Supplier;
import javax.net.ssl.SSLEngine;
import jdk.incubator.http.internal.common.ByteBufferReference;
import jdk.incubator.http.internal.common.ExceptionallyCloseable;
import jdk.incubator.http.internal.common.Utils;
/**
* Asynchronous version of SSLConnection.
*/
class AsyncSSLConnection extends HttpConnection
implements AsyncConnection, ExceptionallyCloseable {
class AsyncSSLConnection extends AbstractAsyncSSLConnection {
final AsyncSSLDelegate sslDelegate;
final PlainHttpConnection plainConnection;
@ -61,15 +59,14 @@ class AsyncSSLConnection extends HttpConnection
plainConnection.configureMode(mode);
}
private CompletableFuture<Void> configureModeAsync(Void ignore) {
CompletableFuture<Void> cf = new CompletableFuture<>();
try {
configureMode(Mode.ASYNC);
cf.complete(null);
} catch (Throwable t) {
cf.completeExceptionally(t);
}
return cf;
@Override
PlainHttpConnection plainConnection() {
return plainConnection;
}
@Override
AsyncSSLDelegate sslDelegate() {
return sslDelegate;
}
@Override
@ -91,11 +88,6 @@ class AsyncSSLConnection extends HttpConnection
return plainConnection.connected() && sslDelegate.connected();
}
@Override
boolean isSecure() {
return true;
}
@Override
boolean isProxied() {
return false;
@ -172,6 +164,7 @@ class AsyncSSLConnection extends HttpConnection
plainConnection.channel().shutdownOutput();
}
@Override
SSLEngine getEngine() {
return sslDelegate.getEngine();
}
@ -184,18 +177,6 @@ class AsyncSSLConnection extends HttpConnection
plainConnection.setAsyncCallbacks(sslDelegate::asyncReceive, errorReceiver, sslDelegate::getNetBuffer);
}
// Blocking read functions not used here
@Override
protected ByteBuffer readImpl() throws IOException {
throw new UnsupportedOperationException("Not supported.");
}
@Override
CompletableFuture<Void> whenReceivingResponse() {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public void startReading() {
plainConnection.startReading();
@ -206,4 +187,9 @@ class AsyncSSLConnection extends HttpConnection
public void stopAsyncReading() {
plainConnection.stopAsyncReading();
}
@Override
SSLConnection downgrade() {
return new SSLConnection(this);
}
}

View File

@ -0,0 +1,206 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.incubator.http;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import jdk.incubator.http.internal.common.ByteBufferReference;
import jdk.incubator.http.internal.common.Utils;
/**
* An SSL tunnel built on a Plain (CONNECT) TCP tunnel.
*/
class AsyncSSLTunnelConnection extends AbstractAsyncSSLConnection {
final PlainTunnelingConnection plainConnection;
final AsyncSSLDelegate sslDelegate;
final String serverName;
@Override
public void connect() throws IOException, InterruptedException {
plainConnection.connect();
configureMode(Mode.ASYNC);
startReading();
sslDelegate.connect();
}
@Override
boolean connected() {
return plainConnection.connected() && sslDelegate.connected();
}
@Override
public CompletableFuture<Void> connectAsync() {
throw new InternalError();
}
AsyncSSLTunnelConnection(InetSocketAddress addr,
HttpClientImpl client,
String[] alpn,
InetSocketAddress proxy)
{
super(addr, client);
this.serverName = Utils.getServerName(addr);
this.plainConnection = new PlainTunnelingConnection(addr, proxy, client);
this.sslDelegate = new AsyncSSLDelegate(plainConnection, client, alpn, serverName);
}
@Override
synchronized void configureMode(Mode mode) throws IOException {
super.configureMode(mode);
plainConnection.configureMode(mode);
}
@Override
SSLParameters sslParameters() {
return sslDelegate.getSSLParameters();
}
@Override
public String toString() {
return "AsyncSSLTunnelConnection: " + super.toString();
}
@Override
PlainTunnelingConnection plainConnection() {
return plainConnection;
}
@Override
AsyncSSLDelegate sslDelegate() {
return sslDelegate;
}
@Override
ConnectionPool.CacheKey cacheKey() {
return ConnectionPool.cacheKey(address, plainConnection.proxyAddr);
}
@Override
long write(ByteBuffer[] buffers, int start, int number) throws IOException {
//debugPrint("Send", buffers, start, number);
ByteBuffer[] bufs = Utils.reduce(buffers, start, number);
long n = Utils.remaining(bufs);
sslDelegate.writeAsync(ByteBufferReference.toReferences(bufs));
sslDelegate.flushAsync();
return n;
}
@Override
long write(ByteBuffer buffer) throws IOException {
//debugPrint("Send", buffer);
long n = buffer.remaining();
sslDelegate.writeAsync(ByteBufferReference.toReferences(buffer));
sslDelegate.flushAsync();
return n;
}
@Override
public void writeAsync(ByteBufferReference[] buffers) throws IOException {
sslDelegate.writeAsync(buffers);
}
@Override
public void writeAsyncUnordered(ByteBufferReference[] buffers) throws IOException {
sslDelegate.writeAsyncUnordered(buffers);
}
@Override
public void flushAsync() throws IOException {
sslDelegate.flushAsync();
}
@Override
public void close() {
Utils.close(sslDelegate, plainConnection.channel());
}
@Override
void shutdownInput() throws IOException {
plainConnection.channel().shutdownInput();
}
@Override
void shutdownOutput() throws IOException {
plainConnection.channel().shutdownOutput();
}
@Override
SocketChannel channel() {
return plainConnection.channel();
}
@Override
boolean isProxied() {
return true;
}
@Override
public void setAsyncCallbacks(Consumer<ByteBufferReference> asyncReceiver,
Consumer<Throwable> errorReceiver,
Supplier<ByteBufferReference> readBufferSupplier) {
sslDelegate.setAsyncCallbacks(asyncReceiver, errorReceiver, readBufferSupplier);
plainConnection.setAsyncCallbacks(sslDelegate::asyncReceive, errorReceiver, sslDelegate::getNetBuffer);
}
@Override
public void startReading() {
plainConnection.startReading();
sslDelegate.startReading();
}
@Override
public void stopAsyncReading() {
plainConnection.stopAsyncReading();
}
@Override
public void enableCallback() {
sslDelegate.enableCallback();
}
@Override
public void closeExceptionally(Throwable cause) throws IOException {
Utils.close(cause, sslDelegate, plainConnection.channel());
}
@Override
SSLEngine getEngine() {
return sslDelegate.getEngine();
}
@Override
SSLTunnelConnection downgrade() {
return new SSLTunnelConnection(this);
}
}

View File

@ -82,9 +82,9 @@ abstract class ExchangeImpl<T> {
c = c2.getConnectionFor(request);
} catch (Http2Connection.ALPNException e) {
// failed to negotiate "h2"
AsyncSSLConnection as = e.getConnection();
AbstractAsyncSSLConnection as = e.getConnection();
as.stopAsyncReading();
SSLConnection sslc = new SSLConnection(as);
HttpConnection sslc = as.downgrade();
ExchangeImpl<U> ex = new Http1Exchange<>(exchange, sslc);
return ex;
}

View File

@ -211,12 +211,13 @@ class Http2Connection {
this.hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE));
this.windowUpdater = new ConnectionWindowUpdateSender(this, client.getReceiveBufferSize());
}
/**
* Case 1) Create from upgraded HTTP/1.1 connection.
* Is ready to use. Will not be SSL. exchange is the Exchange
* that initiated the connection, whose response will be delivered
* on a Stream.
*/
/**
* Case 1) Create from upgraded HTTP/1.1 connection.
* Is ready to use. Will not be SSL. exchange is the Exchange
* that initiated the connection, whose response will be delivered
* on a Stream.
*/
Http2Connection(HttpConnection connection,
Http2ClientImpl client2,
Exchange<?> exchange,
@ -280,7 +281,7 @@ class Http2Connection {
* Throws an IOException if h2 was not negotiated
*/
private void checkSSLConfig() throws IOException {
AsyncSSLConnection aconn = (AsyncSSLConnection)connection;
AbstractAsyncSSLConnection aconn = (AbstractAsyncSSLConnection)connection;
SSLEngine engine = aconn.getEngine();
String alpn = engine.getApplicationProtocol();
if (alpn == null || !alpn.equals("h2")) {
@ -906,14 +907,14 @@ class Http2Connection {
*/
static final class ALPNException extends IOException {
private static final long serialVersionUID = 23138275393635783L;
final AsyncSSLConnection connection;
final AbstractAsyncSSLConnection connection;
ALPNException(String msg, AsyncSSLConnection connection) {
ALPNException(String msg, AbstractAsyncSSLConnection connection) {
super(msg);
this.connection = connection;
}
AsyncSSLConnection getConnection() {
AbstractAsyncSSLConnection getConnection() {
return connection;
}
}

View File

@ -34,7 +34,6 @@ import java.nio.channels.SocketChannel;
import java.util.concurrent.CompletableFuture;
import jdk.incubator.http.internal.common.ByteBufferReference;
import jdk.incubator.http.internal.common.Utils;
/**
* Wraps socket channel layer and takes care of SSL also.
@ -136,7 +135,11 @@ abstract class HttpConnection implements Closeable {
String[] alpn, boolean isHttp2, HttpClientImpl client)
{
if (proxy != null) {
return new SSLTunnelConnection(addr, client, proxy);
if (!isHttp2) {
return new SSLTunnelConnection(addr, client, proxy);
} else {
return new AsyncSSLTunnelConnection(addr, client, alpn, proxy);
}
} else if (!isHttp2) {
return new SSLConnection(addr, client, alpn);
} else {

View File

@ -34,12 +34,15 @@ import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* A plain text socket tunnel through a proxy. Uses "CONNECT" but does not
* encrypt. Used by WebSocket. Subclassed in SSLTunnelConnection for encryption.
* encrypt. Used by WebSocket, as well as HTTP over SSL + Proxy.
* Wrapped in SSLTunnelConnection or AsyncSSLTunnelConnection for encryption.
*/
class PlainTunnelingConnection extends HttpConnection {
class PlainTunnelingConnection extends HttpConnection implements AsyncConnection {
final PlainHttpConnection delegate;
protected final InetSocketAddress proxyAddr;
@ -116,17 +119,17 @@ class PlainTunnelingConnection extends HttpConnection {
}
@Override
void writeAsync(ByteBufferReference[] buffers) throws IOException {
public void writeAsync(ByteBufferReference[] buffers) throws IOException {
delegate.writeAsync(buffers);
}
@Override
void writeAsyncUnordered(ByteBufferReference[] buffers) throws IOException {
public void writeAsyncUnordered(ByteBufferReference[] buffers) throws IOException {
delegate.writeAsyncUnordered(buffers);
}
@Override
void flushAsync() throws IOException {
public void flushAsync() throws IOException {
delegate.flushAsync();
}
@ -165,4 +168,32 @@ class PlainTunnelingConnection extends HttpConnection {
boolean isProxied() {
return true;
}
@Override
public void setAsyncCallbacks(Consumer<ByteBufferReference> asyncReceiver,
Consumer<Throwable> errorReceiver,
Supplier<ByteBufferReference> readBufferSupplier) {
delegate.setAsyncCallbacks(asyncReceiver, errorReceiver, readBufferSupplier);
}
@Override
public void startReading() {
delegate.startReading();
}
@Override
public void stopAsyncReading() {
delegate.stopAsyncReading();
}
@Override
public void enableCallback() {
delegate.enableCallback();
}
@Override
synchronized void configureMode(Mode mode) throws IOException {
super.configureMode(mode);
delegate.configureMode(mode);
}
}

View File

@ -77,8 +77,8 @@ class SSLConnection extends HttpConnection {
*/
SSLConnection(AsyncSSLConnection c) {
super(c.address, c.client);
this.delegate = c.plainConnection;
AsyncSSLDelegate adel = c.sslDelegate;
this.delegate = c.plainConnection();
AsyncSSLDelegate adel = c.sslDelegate();
this.sslDelegate = new SSLDelegate(adel.engine, delegate.channel(), client, adel.serverName);
this.alpn = adel.alpn;
this.serverName = adel.serverName;

View File

@ -85,6 +85,19 @@ class SSLTunnelConnection extends HttpConnection {
delegate = new PlainTunnelingConnection(addr, proxy, client);
}
/**
* Create an SSLTunnelConnection from an existing connected AsyncSSLTunnelConnection.
* Used when downgrading from HTTP/2 to HTTP/1.1
*/
SSLTunnelConnection(AsyncSSLTunnelConnection c) {
super(c.address, c.client);
this.delegate = c.plainConnection();
AsyncSSLDelegate adel = c.sslDelegate();
this.sslDelegate = new SSLDelegate(adel.engine, delegate.channel(), client, adel.serverName);
this.serverName = adel.serverName;
connected = c.connected();
}
@Override
SSLParameters sslParameters() {
return sslDelegate.getSSLParameters();

View File

@ -106,13 +106,24 @@ class ZipUtils {
* Converts DOS time to Java time (number of milliseconds since epoch).
*/
public static long dosToJavaTime(long dtime) {
LocalDateTime ldt = LocalDateTime.of(
(int) (((dtime >> 25) & 0x7f) + 1980),
(int) ((dtime >> 21) & 0x0f),
(int) ((dtime >> 16) & 0x1f),
(int) ((dtime >> 11) & 0x1f),
(int) ((dtime >> 5) & 0x3f),
(int) ((dtime << 1) & 0x3e));
int year;
int month;
int day;
int hour = (int) ((dtime >> 11) & 0x1f);
int minute = (int) ((dtime >> 5) & 0x3f);
int second = (int) ((dtime << 1) & 0x3e);
if ((dtime >> 16) == 0) {
// Interpret the 0 DOS date as 1979-11-30 for compatibility with
// other implementations.
year = 1979;
month = 11;
day = 30;
} else {
year = (int) (((dtime >> 25) & 0x7f) + 1980);
month = (int) ((dtime >> 21) & 0x0f);
day = (int) ((dtime >> 16) & 0x1f);
}
LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, minute, second);
return TimeUnit.MILLISECONDS.convert(ldt.toEpochSecond(
ZoneId.systemDefault().getRules().getOffset(ldt)), TimeUnit.SECONDS);
}

View File

@ -21,17 +21,6 @@
* questions.
*/
/**
* @test
* @key headful
* @bug 6193279
* @summary REGRESSION: AppletViewer throws IOException when path is encoded URL
* @author Dmitry Cherepanov: area=appletviewer
* @run compile IOExceptionIfEncodedURLTest.java
* @run main IOExceptionIfEncodedURLTest
* @run shell IOExceptionIfEncodedURLTest.sh
*/
import java.applet.Applet;
import sun.net.www.ParseUtil;
import java.io.File;

View File

@ -25,7 +25,7 @@
#
# @test IOExceptionIfEncodedURLTest.sh
# @key headful
# @bug 6193279 6619458 8137087
# @bug 6193279 6619458 8137087 8186259
# @summary REGRESSION: AppletViewer throws IOException when path is encoded URL
# @author Dmitry Cherepanov: area=appletviewer
# @modules java.base/sun.net.www

View File

@ -56,9 +56,12 @@ import jdk.testlibrary.SimpleSSLContext;
/**
* @test
* @bug 8185852
* @summary verifies that passing a proxy with an unresolved address does
* not cause java.nio.channels.UnresolvedAddressException
* @bug 8185852 8181422
* @summary Verifies that passing a proxy with an unresolved address does
* not cause java.nio.channels.UnresolvedAddressException.
* Verifies that downgrading from HTTP/2 to HTTP/1.1 works through
* an SSL Tunnel connection when the client is HTTP/2 and the server
* and proxy are HTTP/1.1
* @modules jdk.incubator.httpclient
* @library /lib/testlibrary/
* @build jdk.testlibrary.SimpleSSLContext ProxyTest
@ -111,7 +114,7 @@ public class ProxyTest {
server.start();
try {
test(server, HttpClient.Version.HTTP_1_1);
// test(server, HttpClient.Version.HTTP_2);
test(server, HttpClient.Version.HTTP_2);
} finally {
server.stop(0);
System.out.println("Server stopped");

View File

@ -0,0 +1,323 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsParameters;
import com.sun.net.httpserver.HttpsServer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import jdk.incubator.http.HttpClient;
import jdk.incubator.http.HttpRequest;
import jdk.incubator.http.HttpResponse;
import jdk.testlibrary.SimpleSSLContext;
import java.util.concurrent.*;
/**
* @test
* @bug 8181422
* @summary Verifies that you can access an HTTP/2 server over HTTPS by
* tunnelling through an HTTP/1.1 proxy.
* @modules jdk.incubator.httpclient
* @library /lib/testlibrary server
* @modules jdk.incubator.httpclient/jdk.incubator.http.internal.common
* jdk.incubator.httpclient/jdk.incubator.http.internal.frame
* jdk.incubator.httpclient/jdk.incubator.http.internal.hpack
* @build jdk.testlibrary.SimpleSSLContext ProxyTest2
* @run main/othervm ProxyTest2
* @author danielfuchs
*/
public class ProxyTest2 {
static {
try {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
SSLContext.setDefault(new SimpleSSLContext().get());
} catch (IOException ex) {
throw new ExceptionInInitializerError(ex);
}
}
static final String RESPONSE = "<html><body><p>Hello World!</body></html>";
static final String PATH = "/foo/";
static Http2TestServer createHttpsServer(ExecutorService exec) throws Exception {
Http2TestServer server = new Http2TestServer(true, 0, exec, SSLContext.getDefault());
server.addHandler(new Http2Handler() {
@Override
public void handle(Http2TestExchange he) throws IOException {
he.getResponseHeaders().addHeader("encoding", "UTF-8");
he.sendResponseHeaders(200, RESPONSE.length());
he.getResponseBody().write(RESPONSE.getBytes(StandardCharsets.UTF_8));
he.close();
}
}, PATH);
return server;
}
public static void main(String[] args)
throws Exception
{
ExecutorService exec = Executors.newCachedThreadPool();
Http2TestServer server = createHttpsServer(exec);
server.start();
try {
// Http2TestServer over HTTPS does not support HTTP/1.1
// => only test with a HTTP/2 client
test(server, HttpClient.Version.HTTP_2);
} finally {
server.stop();
exec.shutdown();
System.out.println("Server stopped");
}
}
public static void test(Http2TestServer server, HttpClient.Version version)
throws Exception
{
System.out.println("Server is: " + server.getAddress().toString());
URI uri = new URI("https://localhost:" + server.getAddress().getPort() + PATH + "x");
TunnelingProxy proxy = new TunnelingProxy(server);
proxy.start();
try {
System.out.println("Proxy started");
Proxy p = new Proxy(Proxy.Type.HTTP,
InetSocketAddress.createUnresolved("localhost", proxy.getAddress().getPort()));
System.out.println("Setting up request with HttpClient for version: "
+ version.name() + "URI=" + uri);
ProxySelector ps = ProxySelector.of(
InetSocketAddress.createUnresolved("localhost", proxy.getAddress().getPort()));
HttpClient client = HttpClient.newBuilder()
.version(version)
.proxy(ps)
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(uri)
.GET()
.build();
System.out.println("Sending request with HttpClient");
HttpResponse<String> response
= client.send(request, HttpResponse.BodyHandler.asString());
System.out.println("Got response");
String resp = response.body();
System.out.println("Received: " + resp);
if (!RESPONSE.equals(resp)) {
throw new AssertionError("Unexpected response");
}
} finally {
System.out.println("Stopping proxy");
proxy.stop();
System.out.println("Proxy stopped");
}
}
static class TunnelingProxy {
final Thread accept;
final ServerSocket ss;
final boolean DEBUG = false;
final Http2TestServer serverImpl;
TunnelingProxy(Http2TestServer serverImpl) throws IOException {
this.serverImpl = serverImpl;
ss = new ServerSocket();
accept = new Thread(this::accept);
}
void start() throws IOException {
ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
accept.start();
}
// Pipe the input stream to the output stream.
private synchronized Thread pipe(InputStream is, OutputStream os, char tag) {
return new Thread("TunnelPipe("+tag+")") {
@Override
public void run() {
try {
try {
int c;
while ((c = is.read()) != -1) {
os.write(c);
os.flush();
// if DEBUG prints a + or a - for each transferred
// character.
if (DEBUG) System.out.print(tag);
}
is.close();
} finally {
os.close();
}
} catch (IOException ex) {
if (DEBUG) ex.printStackTrace(System.out);
}
}
};
}
public InetSocketAddress getAddress() {
return new InetSocketAddress(ss.getInetAddress(), ss.getLocalPort());
}
// This is a bit shaky. It doesn't handle continuation
// lines, but our client shouldn't send any.
// Read a line from the input stream, swallowing the final
// \r\n sequence. Stops at the first \n, doesn't complain
// if it wasn't preceded by '\r'.
//
String readLine(InputStream r) throws IOException {
StringBuilder b = new StringBuilder();
int c;
while ((c = r.read()) != -1) {
if (c == '\n') break;
b.appendCodePoint(c);
}
if (b.codePointAt(b.length() -1) == '\r') {
b.delete(b.length() -1, b.length());
}
return b.toString();
}
public void accept() {
Socket clientConnection = null;
try {
while (true) {
System.out.println("Tunnel: Waiting for client");
Socket previous = clientConnection;
try {
clientConnection = ss.accept();
} catch (IOException io) {
if (DEBUG) io.printStackTrace(System.out);
break;
} finally {
// we have only 1 client at a time, so it is safe
// to close the previous connection here
if (previous != null) previous.close();
}
System.out.println("Tunnel: Client accepted");
Socket targetConnection = null;
InputStream ccis = clientConnection.getInputStream();
OutputStream ccos = clientConnection.getOutputStream();
Writer w = new OutputStreamWriter(ccos, "UTF-8");
PrintWriter pw = new PrintWriter(w);
System.out.println("Tunnel: Reading request line");
String requestLine = readLine(ccis);
System.out.println("Tunnel: Request status line: " + requestLine);
if (requestLine.startsWith("CONNECT ")) {
// We should probably check that the next word following
// CONNECT is the host:port of our HTTPS serverImpl.
// Some improvement for a followup!
// Read all headers until we find the empty line that
// signals the end of all headers.
while(!requestLine.equals("")) {
System.out.println("Tunnel: Reading header: "
+ (requestLine = readLine(ccis)));
}
// Open target connection
targetConnection = new Socket(
serverImpl.getAddress().getAddress(),
serverImpl.getAddress().getPort());
// Then send the 200 OK response to the client
System.out.println("Tunnel: Sending "
+ "HTTP/1.1 200 OK\r\n\r\n");
pw.print("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
pw.flush();
} else {
// This should not happen.
throw new IOException("Tunnel: Unexpected status line: "
+ requestLine);
}
// Pipe the input stream of the client connection to the
// output stream of the target connection and conversely.
// Now the client and target will just talk to each other.
System.out.println("Tunnel: Starting tunnel pipes");
Thread t1 = pipe(ccis, targetConnection.getOutputStream(), '+');
Thread t2 = pipe(targetConnection.getInputStream(), ccos, '-');
t1.start();
t2.start();
// We have only 1 client... wait until it has finished before
// accepting a new connection request.
// System.out.println("Tunnel: Waiting for pipes to close");
t1.join();
t2.join();
System.out.println("Tunnel: Done - waiting for next client");
}
} catch (Throwable ex) {
try {
ss.close();
} catch (IOException ex1) {
ex.addSuppressed(ex1);
}
ex.printStackTrace(System.err);
}
}
void stop() throws IOException {
ss.close();
}
}
static class Configurator extends HttpsConfigurator {
public Configurator(SSLContext ctx) {
super(ctx);
}
@Override
public void configure (HttpsParameters params) {
params.setSSLParameters (getSSLContext().getSupportedSSLParameters());
}
}
}

View File

@ -201,7 +201,17 @@ public class Http2TestServer implements AutoCloseable {
InetSocketAddress addr = (InetSocketAddress) socket.getRemoteSocketAddress();
Http2TestServerConnection c = new Http2TestServerConnection(this, socket);
connections.put(addr, c);
c.run();
try {
c.run();
} catch(Throwable e) {
// we should not reach here, but if we do
// the connection might not have been closed
// and if so then the client might wait
// forever.
connections.remove(addr, c);
c.close();
throw e;
}
}
} catch (Throwable e) {
if (!stopping) {

View File

@ -133,10 +133,10 @@ public class Http2TestServerConnection {
}
void close() {
stopping = true;
streams.forEach((i, q) -> {
q.close();
});
stopping = true;
try {
socket.close();
// TODO: put a reset on each stream
@ -557,7 +557,14 @@ public class Http2TestServerConnection {
void writeLoop() {
try {
while (!stopping) {
Http2Frame frame = outputQ.take();
Http2Frame frame;
try {
frame = outputQ.take();
} catch(IOException x) {
if (stopping && x.getCause() instanceof InterruptedException) {
break;
} else throw x;
}
if (frame instanceof ResponseHeaders) {
ResponseHeaders rh = (ResponseHeaders)frame;
HeadersFrame hf = new HeadersFrame(rh.streamid(), rh.getFlags(), encodeHeaders(rh.headers));

View File

@ -0,0 +1,112 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import static java.util.zip.ZipFile.CENOFF;
import static java.util.zip.ZipFile.CENTIM;
import static java.util.zip.ZipFile.ENDHDR;
import static java.util.zip.ZipFile.ENDOFF;
import static java.util.zip.ZipFile.LOCTIM;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/* @test
* @bug 8184940
* @summary JDK 9 rejects zip files where the modified day or month is 0
* @author Liam Miller-Cushon
*/
public class ZeroDate {
public static void main(String[] args) throws Exception {
// create a zip file, and read it in as a byte array
Path path = Files.createTempFile("bad", ".zip");
try (OutputStream os = Files.newOutputStream(path);
ZipOutputStream zos = new ZipOutputStream(os)) {
ZipEntry e = new ZipEntry("x");
zos.putNextEntry(e);
zos.write((int) 'x');
}
int len = (int) Files.size(path);
byte[] data = new byte[len];
try (InputStream is = Files.newInputStream(path)) {
is.read(data);
}
Files.delete(path);
// year, month, day are zero
testDate(data.clone(), 0, LocalDate.of(1979, 11, 30));
// only year is zero
testDate(data.clone(), 0 << 25 | 4 << 21 | 5 << 16, LocalDate.of(1980, 4, 5));
}
private static void testDate(byte[] data, int date, LocalDate expected) throws IOException {
// set the datetime
int endpos = data.length - ENDHDR;
int cenpos = u16(data, endpos + ENDOFF);
int locpos = u16(data, cenpos + CENOFF);
writeU32(data, cenpos + CENTIM, date);
writeU32(data, locpos + LOCTIM, date);
// ensure that the archive is still readable, and the date is 1979-11-30
Path path = Files.createTempFile("out", ".zip");
try (OutputStream os = Files.newOutputStream(path)) {
os.write(data);
}
try (ZipFile zf = new ZipFile(path.toFile())) {
ZipEntry ze = zf.entries().nextElement();
Instant actualInstant = ze.getLastModifiedTime().toInstant();
Instant expectedInstant =
expected.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
if (!actualInstant.equals(expectedInstant)) {
throw new AssertionError(
String.format("actual: %s, expected: %s", actualInstant, expectedInstant));
}
} finally {
Files.delete(path);
}
}
static int u8(byte[] data, int offset) {
return data[offset] & 0xff;
}
static int u16(byte[] data, int offset) {
return u8(data, offset) + (u8(data, offset + 1) << 8);
}
private static void writeU32(byte[] data, int pos, int value) {
data[pos] = (byte) (value & 0xff);
data[pos + 1] = (byte) ((value >> 8) & 0xff);
data[pos + 2] = (byte) ((value >> 16) & 0xff);
data[pos + 3] = (byte) ((value >> 24) & 0xff);
}
}

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import static java.util.zip.ZipFile.CENOFF;
import static java.util.zip.ZipFile.CENTIM;
import static java.util.zip.ZipFile.ENDHDR;
import static java.util.zip.ZipFile.ENDOFF;
import static java.util.zip.ZipFile.LOCTIM;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Collections;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/* @test
* @bug 8184940
* @summary JDK 9 rejects zip files where the modified day or month is 0
* @author Liam Miller-Cushon
*/
public class ZeroDate {
public static void main(String[] args) throws Exception {
// create a zip file, and read it in as a byte array
Path path = Files.createTempFile("bad", ".zip");
try (OutputStream os = Files.newOutputStream(path);
ZipOutputStream zos = new ZipOutputStream(os)) {
ZipEntry e = new ZipEntry("x");
zos.putNextEntry(e);
zos.write((int) 'x');
}
int len = (int) Files.size(path);
byte[] data = new byte[len];
try (InputStream is = Files.newInputStream(path)) {
is.read(data);
}
Files.delete(path);
// year, month, day are zero
testDate(data.clone(), 0, LocalDate.of(1979, 11, 30));
// only year is zero
testDate(data.clone(), 0 << 25 | 4 << 21 | 5 << 16, LocalDate.of(1980, 4, 5));
}
private static void testDate(byte[] data, int date, LocalDate expected) throws IOException {
// set the datetime
int endpos = data.length - ENDHDR;
int cenpos = u16(data, endpos + ENDOFF);
int locpos = u16(data, cenpos + CENOFF);
writeU32(data, cenpos + CENTIM, date);
writeU32(data, locpos + LOCTIM, date);
// ensure that the archive is still readable, and the date is 1979-11-30
Path path = Files.createTempFile("out", ".zip");
try (OutputStream os = Files.newOutputStream(path)) {
os.write(data);
}
URI uri = URI.create("jar:file://" + path.toAbsolutePath());
try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
Path entry = fs.getPath("x");
Instant actualInstant =
Files.readAttributes(entry, BasicFileAttributes.class)
.lastModifiedTime()
.toInstant();
Instant expectedInstant =
expected.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
if (!actualInstant.equals(expectedInstant)) {
throw new AssertionError(
String.format("actual: %s, expected: %s", actualInstant, expectedInstant));
}
} finally {
Files.delete(path);
}
}
static int u8(byte[] data, int offset) {
return data[offset] & 0xff;
}
static int u16(byte[] data, int offset) {
return u8(data, offset) + (u8(data, offset + 1) << 8);
}
private static void writeU32(byte[] data, int pos, int value) {
data[pos] = (byte) (value & 0xff);
data[pos + 1] = (byte) ((value >> 8) & 0xff);
data[pos + 2] = (byte) ((value >> 16) & 0xff);
data[pos + 3] = (byte) ((value >> 24) & 0xff);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -55,6 +55,9 @@ public class SmallPrimeExponentP {
CertAndKeyGen ckg = new CertAndKeyGen("RSA", "SHA1withRSA");
ckg.setRandom(new MySecureRandom(seed));
String alias = "anything";
int count = 0;
boolean see63 = false;
boolean see65 = false;
while (!see63 || !see65) {
@ -78,12 +81,19 @@ public class SmallPrimeExponentP {
see65 = true;
}
}
ks.setKeyEntry("anything", k, null, new X509Certificate[]{
ks.setKeyEntry(alias, k, null, new X509Certificate[]{
ckg.getSelfCertificate(new X500Name("CN=Me"), 1000)
});
count++;
}
}
ks.store(null, null);
// Because of JDK-8185844, it has to reload the key store after
// deleting an entry.
for (int i = 0; i < count; i++) {
ks.deleteEntry(alias);
ks.load(null, null);
}
}
static class MySecureRandom extends SecureRandom {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
* A custom output stream that redirects the testing outputs to a file, called
* details.out. It also calls another output stream to save some outputs to
* other files.
*/
public class DetailsOutputStream extends FileOutputStream {
private PhaseOutputStream phaseOutputStream = new PhaseOutputStream();
public DetailsOutputStream() throws FileNotFoundException {
super("details.out", true);
}
public void transferPhase() throws IOException {
if (phaseOutputStream.isCorePhase()) {
phaseOutputStream.write(HtmlHelper.endHtml());
phaseOutputStream.write(HtmlHelper.endPre());
}
phaseOutputStream.transfer();
if (phaseOutputStream.isCorePhase()) {
phaseOutputStream.write(HtmlHelper.startHtml());
phaseOutputStream.write(HtmlHelper.startPre());
}
}
@Override
public void write(byte[] b) throws IOException {
super.write(b);
phaseOutputStream.write(b);
}
@Override
public void write(int b) throws IOException {
super.write(b);
phaseOutputStream.write(b);
}
@Override
public void write(byte b[], int off, int len) throws IOException {
super.write(b, off, len);
phaseOutputStream.write(b, off, len);
}
public void writeAnchorName(String name, String text) throws IOException {
super.write((text).getBytes());
super.write('\n');
phaseOutputStream.write(HtmlHelper.anchorName(name, text));
phaseOutputStream.write('\n');
}
}

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* A helper that is used for creating HTML elements.
*/
public class HtmlHelper {
private static final String STYLE
= "style=\"font-family: Courier New; "
+ "font-size: 12px; "
+ "white-space: pre-wrap\"";
public static String htmlRow(String... values) {
StringBuilder row = new StringBuilder();
row.append(startTr());
for (String value : values) {
row.append(startTd());
row.append(value);
row.append(endTd());
}
row.append(endTr());
return row.toString();
}
public static String startHtml() {
return startTag("html");
}
public static String endHtml() {
return endTag("html");
}
public static String startPre() {
return startTag("pre " + STYLE);
}
public static String endPre() {
return endTag("pre");
}
public static String startTable() {
return startTag("table " + STYLE);
}
public static String endTable() {
return endTag("table");
}
public static String startTr() {
return startTag("tr");
}
public static String endTr() {
return endTag("tr");
}
public static String startTd() {
return startTag("td");
}
public static String endTd() {
return endTag("td");
}
public static String startTag(String tag) {
return "<" + tag + ">";
}
public static String endTag(String tag) {
return "</" + tag + ">";
}
public static String anchorName(String name, String text) {
return "<a name=" + name + ">" + text + "</a>";
}
public static String anchorLink(String file, String anchorName,
String text) {
return "<a href=" + file + "#" + anchorName + ">" + text + "</a>";
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
/*
* This class is used for returning some specific JDK information.
*/
public class JdkUtils {
static final String M_JAVA_RUNTIME_VERSION = "javaRuntimeVersion";
static final String M_IS_SUPPORTED_SIGALG = "isSupportedSigalg";
// Returns the JDK build version.
static String javaRuntimeVersion() {
return System.getProperty("java.runtime.version");
}
// Checks if the specified signature algorithm is supported by the JDK.
static boolean isSupportedSigalg(String sigalg) {
boolean isSupported = false;
try {
isSupported = Signature.getInstance(sigalg) != null;
} catch (NoSuchAlgorithmException e) { }
if (!isSupported) {
System.out.println(sigalg + " is not supported yet.");
}
return isSupported;
}
public static void main(String[] args) {
if (M_JAVA_RUNTIME_VERSION.equals(args[0])) {
System.out.print(javaRuntimeVersion());
} else if (M_IS_SUPPORTED_SIGALG.equals(args[0])) {
System.out.print(isSupportedSigalg(args[1]));
}
}
}

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/*
* A custom output stream that saves the testing details to different files
* according to the current testing phase.
*/
public class PhaseOutputStream extends OutputStream {
public enum Phase {
PRE_SIGNING, // before jar signing
SIGNING, // jar signing
VERIFYING, // jar verifying
DELAY_VERIFYING, // jar verifying after certificates expire
POST_VERIFYING; // after jar verifying
}
private OutputStream signingOut = null;
private OutputStream verifyingOut = null;
private OutputStream delayVerifyingOut = null;
private Phase currentPhase = Phase.PRE_SIGNING;
public void transfer() {
switch (currentPhase) {
case PRE_SIGNING:
currentPhase = Phase.SIGNING;
break;
case SIGNING:
currentPhase = Phase.VERIFYING;
break;
case VERIFYING:
currentPhase = Compatibility.DELAY_VERIFY
? Phase.DELAY_VERIFYING
: Phase.POST_VERIFYING;
break;
case DELAY_VERIFYING:
currentPhase = Phase.POST_VERIFYING;
break;
case POST_VERIFYING:
currentPhase = Phase.POST_VERIFYING;
break;
}
}
// The core phases are SIGNING, VERIFYING and DELAY_VERIFYING.
public boolean isCorePhase() {
return currentPhase != PhaseOutputStream.Phase.PRE_SIGNING
&& currentPhase != PhaseOutputStream.Phase.POST_VERIFYING;
}
public Phase currentPhase() {
return currentPhase;
}
@Override
public void write(int b) throws IOException {
OutputStream output = phaseOut();
if (output != null) {
output.write(b);
}
}
@Override
public void write(byte[] b) throws IOException {
OutputStream output = phaseOut();
if (output != null) {
output.write(b);
}
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
OutputStream output = phaseOut();
if (output != null) {
output.write(b, off, len);
}
}
public void write(String str) throws IOException {
write(str.getBytes());
}
private OutputStream phaseOut() throws FileNotFoundException {
switch (currentPhase) {
case SIGNING:
return signingOut == null
? signingOut = createOutput(Phase.SIGNING)
: signingOut;
case VERIFYING:
return verifyingOut == null
? verifyingOut = createOutput(Phase.VERIFYING)
: verifyingOut;
case DELAY_VERIFYING:
return delayVerifyingOut == null
? delayVerifyingOut = createOutput(Phase.DELAY_VERIFYING)
: delayVerifyingOut;
default:
return null;
}
}
@Override
public void flush() throws IOException {
flush(signingOut);
flush(verifyingOut);
flush(delayVerifyingOut);
}
private void flush(OutputStream output) throws IOException {
if (output != null) {
output.flush();
}
}
@Override
public void close() throws IOException {
close(signingOut);
close(verifyingOut);
close(delayVerifyingOut);
}
private void close(OutputStream output) throws IOException {
if (output != null) {
output.close();
}
}
private static OutputStream createOutput(Phase phase)
throws FileNotFoundException {
return new FileOutputStream(fileName(phase), true);
}
public static String fileName(Phase phase) {
return phase.name() + ".html";
}
}

View File

@ -0,0 +1,215 @@
# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
##### Summary #####
This test is used to verify the compatibility on jarsigner cross different JDK
releases. It also can be used to check jar signing (w/ and w/o TSA) and verifying
on some specific key algorithms and digest algorithms.
##### Output #####
The test will generate a report, at JTwork/scratch/report.html, to display the
key parameters for signing and the status of signing and verifying. And it will
generate another report, at JTwork/scratch/failedReport.html, to collect all of
failed cases.
Please note that, the test may output a great deal of logs if the jdk list and
TSA list are big, and that would lead to jtreg output overflow. So, it redirects
stdout and stderr to file JTwork/scratch/details.out.
##### Report Columns #####
Certificate
Certificate identifier. The identifier consists of specific attributes of
the certificate. Generally, the naming convention is:
KeyAlgorithm_DigestAlgorithm_[KeySize][_Expired]
Signer JDK
The JDK version that signs jar.
Signature Algorithm
The signature algorithm used by signing.
TSA Digest
The timestamp digest algorithm used by signing.
TSA
TSA URL index. All of TSA URLs and their indices can be found at the top
of this report.
Signing Status
Signing process result status. The status are the followings:
[1]NONE, no action.
[2]NORMAL, no any error and warning.
[3]WARNING, no any error but some warnings raise.
[4]ERROR, some errors raise.
Verifier JDK
The JDK version that verifies signed jars.
Verifying Status
Verifying process result status. The status are the same as those for
"Status of Signing".
Delay Verifying Status
Delay verifying process result status. The status are the same as those
for "Status of Signing".
Failed
It highlights which case fails. The failed cases (rows) are marked with
letter X.
##### Usages #####
jtreg [-options] \
-jdk:<path/to/testing/JDK>
[-DproxyHost=<host> \
-DproxyPort=<port> \
-DtsaListFile=</url/to/tsaListFile> \
-DtsaList=</path/to/tsa1#/path/to/tsa2#/path/to/tsa3#...> \
-DjdkListFile=</path/to/jdkListFile> \
-DjdkList=</path/to/jdk1#/path/to/jdk2#/path/to/jdk3#...> \
-DjavaSecurityFile=</path/to/java/security/properties/file> \
-DdelayVerify=<true|false> \
-DcertValidity=<[1, 1440]>] \
<JDK_REPO>/jdk/test/sun/security/tools/jarsigner/compatibility/Compatibility.java
Besides the common jtreg options, like -jdk, this test introduces a set of
properties for receiving users' inputs and making the test more flexible. These
properties are:
proxyHost=<host>
This property indicates proxy host.
proxyPort=<port>
This property indicates proxy port. The default value is 80.
tsaListFile=</path/to/tsaListFile>
This property indicates a local file, which contains a set of TSA URLs and
the supported digest algorithms (by optional parameter digests). The format
of the file content looks like the below,
http://path/to/tsa1
http://path/to/tsa2;digests=SHA-1,SHA-256
https://path/to/tsa3
...
If a TSA line does not list the supported digest algorithms, that means
the TSA supports SHA-1, SHA-256 and SHA-512. Because the test only focus
on SHA-1, SHA-256 and SHA-512. So, if other digest algorithms, like SHA-224
and SHA-384, are listed, they just be ignored.
tsaList=</path/to/tsa1#/path/to/tsa2;digests=SHA-1,SHA-256#...>
This property directly lists a set of TSAs in command. "#" is the delimiter.
Note that, if both of tsaListFile and tsaList are specified, only property
jdkListFile is selected. If neither of tsaListFile and tsaList is specified,
the test will fails immediately.
jdkListFile=</path/to/jdkListFile>
This property indicates a local file, which contains a set of local JDK
paths. The style of the file content looks like the below,
/path/to/jdk1
/path/to/jdk2
/path/to/jdk3
...
jdkList=</path/to/jdk1#/path/to/jdk2#/path/to/jdk3#...>
This property directly lists a set of local JDK paths in command. "#" is
the delimiter.
Note that, if both of jdkListFile and jdkList are specified, only property
jdkListFile is selected. If neither of jdkListFile nor jdkList is specified,
the testing JDK, which is specified by jtreg option -jdk will be used as
the only one JDK in the JDK list.
javaSecurityFile=</path/to/java/security/properties/file>
This property indicates an alternative java security properties file. The
default file is the path of file java.scurity that is distributed with
this test.
delayVerify=<true|false>
This property indicates if doing an additional verifying after all of valid
certificates expire. The default value is false.
certValidity=<[1, 1440]>
This property indicates the remaining validity period in minutes for valid
certificates. The value range is [1, 1440]. The default value is 1440.
Note that, if delayVerify is false, this property doesn't take effect.
The testing JDK, which is specified by jtreg option "-jdk", should include the
fix for JDK-8163304. Otherwise, the signature algorithm and timestamp digest
algorithm cannot be extracted from verification output. And this JDK should
support as many as possible signature algorithms. Anyway the latest JDK build
is always recommended.
##### Examples #####
$ cat /path/to/jdkList
/path/to/jdk6u171-b05
/path/to/jdk7u161-b05
/path/to/jdk8u144-b01
/path/to/jdk9-179
$ cat /path/to/tsaList
http://timestamp.comodoca.com/rfc3161
http://sha256timestamp.ws.symantec.com/sha256/timestamp
http://tsa.starfieldtech.com
http://timestamp.entrust.net/TSS/RFC3161sha1TS;digests=SHA-1,SHA-256
http://timestamp.entrust.net/TSS/RFC3161sha2TS;digests=SHA-1,SHA-256
http://rfc3161timestamp.globalsign.com/advanced;digests=SHA-256,SHA-512
http://rfc3161timestamp.globalsign.com/standard
http://timestamp.globalsign.com/scripts/timstamp.dll
http://timestamp.globalsign.com/?signature=sha2;digests=SHA-256,SHA-512
http://timestamp.digicert.com
http://time.certum.pl
http://tsa.swisssign.net
http://zeitstempel.dfn.de
https://tsp.iaik.tugraz.at/tsp/TspRequest
$ jtreg -va -nr -timeout:100 \
-jdk:/path/to/latest/jdk \
-DproxyHost=<proxy> -DproxyPort=<port> \
-DjdkListFile=/path/to/jdkList \
-DtsaListFile=/path/to/tsaList \
-DdelayVerify=true -DcertValidity=60 \
<JDK_REPO>/jdk/test/sun/security/tools/jarsigner/compatibility/Compatibility.java
The above is a comprehensive usage example. File "jdkList" lists the paths of
testing JDK builds, and file "tsaList" lists the URLs of TSA services. Some TSAs,
like http://timestamp.entrust.net/TSS/RFC3161sha1TS, specify the supported digest
algorithms. Other TSAs, which don't specify parameter digests, are regarded to
support SHA-1, SHA-256 and SHA-512. The test uses a proxy to access TSA services.
And it enables delay verifying and set the certificate validity period to 60
minutes. So, after the first verification is done, the test will wait for all
of valid certificates expire and then does verification again.
If don't want to provide such JDK list and TSA list files, the test allows to
specify JDKs and TSAs (via properties jdkList and tsaList respectively) in the
command directly, like the below style,
$ jtreg -va -nr -timeout:100 \
-jdk:/path/to/latest/jdk \
-DproxyHost=<proxy> -DproxyPort=<port> \
-DjdkList=/path/to/jdk6u171-b05#/path/to/jdk7u161-b05#/path/to/jdk8u144-b01#/path/to/jdk9-179 \
-DtsaList=http://timestamp.comodoca.com/rfc3161#http://timestamp.entrust.net/TSS/RFC3161sha1TS;digests=SHA-1,SHA-256 \
-DdelayVerify=true -DcertValidity=60 \
<JDK_REPO>/jdk/test/sun/security/tools/jarsigner/compatibility/Compatibility.java
Furthermore, here introduces one of the simplest usages. It doesn't specify any
JDK list, so the testing JDK, which is specified by jtreg option "-jdk", will
be tested. And it doesn't apply delay verifying, and no proxy is used, and use
only one TSA. Now, the command is pretty simple and looks like the followings,
$ jtreg -va -nr -timeout:100 \
-jdk:/path/to/latest/jdk \
-DtsaList=http://timestamp.comodoca.com/rfc3161 \
<JDK_REPO>/jdk/test/sun/security/tools/jarsigner/compatibility/Compatibility.java

View File

@ -0,0 +1,2 @@
jdk.certpath.disabledAlgorithms=MD2, MD5
jdk.jar.disabledAlgorithms=MD2, MD5