This commit is contained in:
Phil Race 2017-11-29 09:07:01 -08:00
commit 586b13cdb6
41 changed files with 3018 additions and 267 deletions

View File

@ -47,7 +47,7 @@ ifeq ($(HAS_SPEC),)
# Make control variables, handled by Init.gmk
INIT_CONTROL_VARIABLES += LOG CONF CONF_NAME SPEC JOBS TEST_JOBS CONF_CHECK \
COMPARE_BUILD JTREG GTEST
COMPARE_BUILD JTREG GTEST TEST_OPTS TEST_VM_OPTS
# All known make control variables
MAKE_CONTROL_VARIABLES := $(INIT_CONTROL_VARIABLES) TEST JDK_FILTER

View File

@ -32,11 +32,42 @@ include FindTests.gmk
# We will always run multiple tests serially
.NOTPARALLEL:
################################################################################
# Parse global control variables
################################################################################
ifneq ($(TEST_VM_OPTS), )
ifneq ($(TEST_OPTS), )
TEST_OPTS := $(TEST_OPTS);VM_OPTIONS=$(TEST_VM_OPTS)
else
TEST_OPTS := VM_OPTIONS=$(TEST_VM_OPTS)
endif
endif
$(eval $(call ParseKeywordVariable, TEST_OPTS, \
KEYWORDS := JOBS TIMEOUT, \
STRING_KEYWORDS := VM_OPTIONS, \
))
# Helper function to propagate TEST_OPTS values.
#
# Note: No spaces are allowed around the arguments.
# Arg $1 The variable in TEST_OPTS to propagate
# Arg $2 The control variable to propagate it to
define SetTestOpt
ifneq ($$(TEST_OPTS_$1), )
$2_$1 := $$(TEST_OPTS_$1)
endif
endef
################################################################################
# Hook to include the corresponding custom file, if present.
$(eval $(call IncludeCustomExtension, RunTests.gmk))
################################################################################
TEST_RESULTS_DIR := $(OUTPUTDIR)/test-results
TEST_SUPPORT_DIR := $(OUTPUTDIR)/test-support
TEST_SUMMARY := $(TEST_RESULTS_DIR)/test-summary.txt
ifeq ($(CUSTOM_ROOT), )
JTREG_TOPDIR := $(TOPDIR)
@ -48,6 +79,17 @@ endif
# Parse control variables
################################################################################
ifneq ($(TEST_OPTS), )
# Inform the user
$(info Running tests using TEST_OPTS control variable '$(TEST_OPTS)')
$(eval $(call SetTestOpt,VM_OPTIONS,JTREG))
$(eval $(call SetTestOpt,VM_OPTIONS,GTEST))
$(eval $(call SetTestOpt,JOBS,JTREG))
$(eval $(call SetTestOpt,TIMEOUT,JTREG))
endif
$(eval $(call ParseKeywordVariable, JTREG, \
KEYWORDS := JOBS TIMEOUT TEST_MODE ASSERT VERBOSE RETAIN MAX_MEM, \
STRING_KEYWORDS := OPTIONS JAVA_OPTIONS VM_OPTIONS, \
@ -60,7 +102,7 @@ endif
$(eval $(call ParseKeywordVariable, GTEST, \
KEYWORDS := REPEAT, \
STRING_KEYWORDS := OPTIONS, \
STRING_KEYWORDS := OPTIONS VM_OPTIONS, \
))
ifneq ($(GTEST), )
@ -280,7 +322,7 @@ define SetupRunGtestTestBody
$$(FIXPATH) $$(TEST_IMAGE_DIR)/hotspot/gtest/server/gtestLauncher \
-jdk $(JDK_IMAGE_DIR) $$($1_GTEST_FILTER) \
--gtest_output=xml:$$($1_TEST_RESULTS_DIR)/gtest.xml \
$$($1_GTEST_REPEAT) $$(GTEST_OPTIONS) \
$$($1_GTEST_REPEAT) $$(GTEST_OPTIONS) $$(GTEST_VM_OPTIONS) \
> >($(TEE) $$($1_TEST_RESULTS_DIR)/gtest.txt) || true )
$1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/gtest.txt
@ -289,15 +331,24 @@ define SetupRunGtestTestBody
$$(call LogWarn, Finished running test '$$($1_TEST)')
$$(call LogWarn, Test report is stored in $$(strip \
$$(subst $$(TOPDIR)/, , $$($1_TEST_RESULTS_DIR))))
$$(eval $1_TOTAL := $$(shell $$(AWK) '/==========.* tests? from .* \
test cases? ran/ { print $$$$2 }' $$($1_RESULT_FILE)))
$$(eval $1_PASSED := $$(shell $$(AWK) '/\[ PASSED \] .* tests?./ \
{ print $$$$4 }' $$($1_RESULT_FILE)))
$$(eval $1_FAILED := $$(shell $$(AWK) '/\[ FAILED \] .* tests?, \
listed below/ { print $$$$4 }' $$($1_RESULT_FILE)))
$$(if $$($1_FAILED), , $$(eval $1_FAILED := 0))
$$(eval $1_ERROR := $$(shell \
$$(EXPR) $$($1_TOTAL) - $$($1_PASSED) - $$($1_FAILED)))
$$(if $$(wildcard $$($1_RESULT_FILE)), \
$$(eval $1_TOTAL := $$(shell $$(AWK) '/==========.* tests? from .* \
test cases? ran/ { print $$$$2 }' $$($1_RESULT_FILE))) \
$$(if $$($1_TOTAL), , $$(eval $1_TOTAL := 0)) \
$$(eval $1_PASSED := $$(shell $$(AWK) '/\[ PASSED \] .* tests?./ \
{ print $$$$4 }' $$($1_RESULT_FILE))) \
$$(if $$($1_PASSED), , $$(eval $1_PASSED := 0)) \
$$(eval $1_FAILED := $$(shell $$(AWK) '/\[ FAILED \] .* tests?, \
listed below/ { print $$$$4 }' $$($1_RESULT_FILE))) \
$$(if $$($1_FAILED), , $$(eval $1_FAILED := 0)) \
$$(eval $1_ERROR := $$(shell \
$$(EXPR) $$($1_TOTAL) - $$($1_PASSED) - $$($1_FAILED))) \
, \
$$(eval $1_PASSED := 0) \
$$(eval $1_FAILED := 0) \
$$(eval $1_ERROR := 1) \
$$(eval $1_TOTAL := 1) \
)
$1: run-test-$1 parse-test-$1
@ -521,42 +572,46 @@ endif
TEST_FAILURE := false
run-test: $(TARGETS)
# Print a table of the result of all tests run and their result
$(ECHO)
$(ECHO) ==============================
$(ECHO) Test summary
$(ECHO) ==============================
$(PRINTF) "%2s %-49s %5s %5s %5s %5s %2s\n" " " TEST \
TOTAL PASS FAIL ERROR " "
# Create and print a table of the result of all tests run
$(RM) $(TEST_SUMMARY).old 2> /dev/null
$(MV) $(TEST_SUMMARY) $(TEST_SUMMARY).old 2> /dev/null || true
$(ECHO) >> $(TEST_SUMMARY) ==============================
$(ECHO) >> $(TEST_SUMMARY) Test summary
$(ECHO) >> $(TEST_SUMMARY) ==============================
$(PRINTF) >> $(TEST_SUMMARY) "%2s %-49s %5s %5s %5s %5s %2s\n" " " \
TEST TOTAL PASS FAIL ERROR " "
$(foreach test, $(TESTS_TO_RUN), \
$(eval TEST_ID := $(shell $(ECHO) $(strip $(test)) | \
$(TR) -cs '[a-z][A-Z][0-9]\n' '_')) \
$(eval NAME_PATTERN := $(shell $(ECHO) $(test) | $(TR) -c \\n _)) \
$(if $(filter __________________________________________________%, $(NAME_PATTERN)), \
$(eval TEST_NAME := ) \
$(PRINTF) "%2s %-49s\n" " " "$(test)" $(NEWLINE) \
$(PRINTF) >> $(TEST_SUMMARY) "%2s %-49s\n" " " "$(test)" $(NEWLINE) \
, \
$(eval TEST_NAME := $(test)) \
) \
$(if $(filter $($(TEST_ID)_PASSED), $($(TEST_ID)_TOTAL)), \
$(PRINTF) "%2s %-49s %5d %5d %5d %5d %2s\n" " " "$(TEST_NAME)" \
$($(TEST_ID)_TOTAL) $($(TEST_ID)_PASSED) $($(TEST_ID)_FAILED) \
$($(TEST_ID)_ERROR) " " $(NEWLINE) \
$(PRINTF) >> $(TEST_SUMMARY) "%2s %-49s %5d %5d %5d %5d %2s\n" \
" " "$(TEST_NAME)" $($(TEST_ID)_TOTAL) $($(TEST_ID)_PASSED) \
$($(TEST_ID)_FAILED) $($(TEST_ID)_ERROR) " " $(NEWLINE) \
, \
$(PRINTF) "%2s %-49s %5d %5d %5d %5d %2s\n" ">>" "$(TEST_NAME)" \
$($(TEST_ID)_TOTAL) $($(TEST_ID)_PASSED) $($(TEST_ID)_FAILED) \
$($(TEST_ID)_ERROR) "<<" $(NEWLINE) \
$(PRINTF) >> $(TEST_SUMMARY) "%2s %-49s %5d %5d %5d %5d %2s\n" \
">>" "$(TEST_NAME)" $($(TEST_ID)_TOTAL) $($(TEST_ID)_PASSED) \
$($(TEST_ID)_FAILED) $($(TEST_ID)_ERROR) "<<" $(NEWLINE) \
$(eval TEST_FAILURE := true) \
) \
)
$(ECHO) ==============================
$(ECHO) >> $(TEST_SUMMARY) ==============================
$(if $(filter true, $(TEST_FAILURE)), \
$(ECHO) TEST FAILURE $(NEWLINE) \
$(ECHO) >> $(TEST_SUMMARY) TEST FAILURE $(NEWLINE) \
$(MKDIR) -p $(MAKESUPPORT_OUTPUTDIR) $(NEWLINE) \
$(TOUCH) $(MAKESUPPORT_OUTPUTDIR)/exit-with-error \
, \
$(ECHO) TEST SUCCESS \
$(ECHO) >> $(TEST_SUMMARY) TEST SUCCESS \
)
$(ECHO)
$(CAT) $(TEST_SUMMARY)
$(ECHO)
################################################################################

View File

@ -115,11 +115,11 @@
</target>
<!-- check minimum ant version required to be 1.8.4 -->
<!-- check minimum ant version required to be 1.9.5 -->
<target name="check-ant-version">
<property name="ant.version.required" value="1.8.4"/>
<property name="ant.version.required" value="1.9.5"/>
<antversion property="ant.current.version" />
<fail message="The current ant version, ${ant.current.version}, is too old. Please use 1.8.4 or above.">
<fail message="The current ant version, ${ant.current.version}, is too old. Please use 1.9.5 or above.">
<condition>
<not>
<antversion atleast="${ant.version.required}"/>

View File

@ -1813,7 +1813,7 @@ public abstract class ClassLoader {
}
/**
* Returns the platform class loader for delegation. All
* Returns the platform class loader. All
* <a href="#builtinLoaders">platform classes</a> are visible to
* the platform class loader.
*
@ -1843,7 +1843,7 @@ public abstract class ClassLoader {
}
/**
* Returns the system class loader for delegation. This is the default
* Returns the system class loader. This is the default
* delegation parent for new {@code ClassLoader} instances, and is
* typically the class loader used to start the application.
*
@ -1884,7 +1884,7 @@ public abstract class ClassLoader {
* the application module path then the class path defaults to
* the current working directory.
*
* @return The system {@code ClassLoader} for delegation
* @return The system {@code ClassLoader}
*
* @throws SecurityException
* If a security manager is present, and the caller's class loader

View File

@ -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
@ -32,9 +32,12 @@ import java.security.*;
*
* <p>The {@code initialize} methods may each be called any number
* of times. If no {@code initialize} method is called on a
* DSAKeyPairGenerator, the default is to generate 1024-bit keys, using
* precomputed p, q and g parameters and an instance of SecureRandom as
* the random bit source.
* DSAKeyPairGenerator, each provider that implements this interface
* should supply (and document) a default initialization. Note that
* defaults may vary across different providers. Additionally, the default
* value for a provider may change in a future version. Therefore, it is
* recommended to explicitly initialize the DSAKeyPairGenerator instead
* of relying on provider-specific defaults.
*
* <p>Users wishing to indicate DSA-specific parameters, and to generate a key
* pair suitable for use with the DSA algorithm typically
@ -45,12 +48,13 @@ import java.security.*;
* KeyPairGenerator {@code getInstance} method with "DSA"
* as its argument.
*
* <li>Initialize the generator by casting the result to a DSAKeyPairGenerator
* and calling one of the
* {@code initialize} methods from this DSAKeyPairGenerator interface.
* <li>Check if the returned key pair generator is an instance of
* DSAKeyPairGenerator before casting the result to a DSAKeyPairGenerator
* and calling one of the {@code initialize} methods from this
* DSAKeyPairGenerator interface.
*
* <li>Generate a key pair by calling the {@code generateKeyPair}
* method from the KeyPairGenerator class.
* method of the KeyPairGenerator class.
*
* </ol>
*
@ -63,7 +67,7 @@ import java.security.*;
* parameters.
*
* <p>Note: Some earlier implementations of this interface may not support
* larger sizes of DSA parameters such as 2048 and 3072-bit.
* larger values of DSA parameters such as 3072-bit.
*
* @since 1.1
* @see java.security.KeyPairGenerator
@ -97,8 +101,7 @@ public interface DSAKeyPairGenerator {
* p, q and g parameters. If it is false, the method uses precomputed
* parameters for the modulus length requested. If there are no
* precomputed parameters for that modulus length, an exception will be
* thrown. It is guaranteed that there will always be
* default parameters for modulus lengths of 512 and 1024 bits.
* thrown.
*
* @param modlen the modulus length in bits. Valid values are any
* multiple of 64 between 512 and 1024, inclusive, 2048, and 3072.

View File

@ -257,7 +257,7 @@ public class TypeKindVisitor6<R, P> extends SimpleTypeVisitor6<R, P> {
*
* @implSpec This implementation dispatches to the visit method for
* the specific {@linkplain TypeKind kind} of pseudo-type:
* {@code VOID}, {@code PACKAGE}, or {@code NONE}.
* {@code VOID}, {@code PACKAGE}, {@code MODULE}, or {@code NONE}.
*
* @param t {@inheritDoc}
* @param p {@inheritDoc}
@ -273,6 +273,9 @@ public class TypeKindVisitor6<R, P> extends SimpleTypeVisitor6<R, P> {
case PACKAGE:
return visitNoTypeAsPackage(t, p);
case MODULE:
return visitNoTypeAsModule(t, p);
case NONE:
return visitNoTypeAsNone(t, p);
@ -307,6 +310,21 @@ public class TypeKindVisitor6<R, P> extends SimpleTypeVisitor6<R, P> {
return defaultAction(t, p);
}
/**
* Visits a {@link TypeKind#MODULE MODULE} pseudo-type.
*
* @implSpec This implementation calls {@code visitUnknown}.
*
* @param t the type to visit
* @param p a visitor-specified parameter
* @return the result of {@code visitUnknown}
*
* @since 10
*/
public R visitNoTypeAsModule(NoType t, P p) {
return visitUnknown(t, p);
}
/**
* Visits a {@link TypeKind#NONE NONE} pseudo-type.
*

View File

@ -93,4 +93,20 @@ public class TypeKindVisitor9<R, P> extends TypeKindVisitor8<R, P> {
protected TypeKindVisitor9(R defaultValue) {
super(defaultValue);
}
/**
* {@inheritDoc}
*
* @implSpec This implementation calls {@code defaultAction}.
*
* @param t {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of {@code defaultAction}
*
* @since 10
*/
@Override
public R visitNoTypeAsModule(NoType t, P p) {
return defaultAction(t, p);
}
}

View File

@ -63,6 +63,7 @@ import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Options;
import com.sun.tools.javac.util.Position;
import java.util.EnumSet;
import java.util.HashMap;
@ -305,7 +306,7 @@ public class Analyzer {
JCMethodDecl md = (JCMethodDecl)decls(oldTree.def).head;
List<JCVariableDecl> params = md.params;
JCBlock body = md.body;
JCLambda newTree = make.Lambda(params, body);
JCLambda newTree = make.at(oldTree).Lambda(params, body);
return List.of(newTree);
}
@ -418,7 +419,7 @@ public class Analyzer {
List<JCEnhancedForLoop> rewrite(JCEnhancedForLoop oldTree) {
JCEnhancedForLoop newTree = copier.copy(oldTree);
newTree.var = rewriteVarType(oldTree.var);
newTree.body = make.Block(0, List.nil());
newTree.body = make.at(oldTree.body).Block(0, List.nil());
return List.of(newTree);
}
@Override
@ -551,7 +552,8 @@ public class Analyzer {
JCStatement treeToAnalyze = (JCStatement)rewriting.originalTree;
if (rewriting.env.info.scope.owner.kind == Kind.TYP) {
//add a block to hoist potential dangling variable declarations
treeToAnalyze = make.Block(Flags.SYNTHETIC, List.of((JCStatement)rewriting.originalTree));
treeToAnalyze = make.at(Position.NOPOS)
.Block(Flags.SYNTHETIC, List.of((JCStatement)rewriting.originalTree));
}
//TODO: to further refine the analysis, try all rewriting combinations

View File

@ -57,6 +57,7 @@ import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.DiagnosticSource;
import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
@ -98,6 +99,7 @@ public class ArgumentAttr extends JCTree.Visitor {
protected static final Context.Key<ArgumentAttr> methodAttrKey = new Context.Key<>();
private final DeferredAttr deferredAttr;
private final JCDiagnostic.Factory diags;
private final Attr attr;
private final Symtab syms;
private final Log log;
@ -121,6 +123,7 @@ public class ArgumentAttr extends JCTree.Visitor {
protected ArgumentAttr(Context context) {
context.put(methodAttrKey, this);
deferredAttr = DeferredAttr.instance(context);
diags = JCDiagnostic.Factory.instance(context);
attr = Attr.instance(context);
syms = Symtab.instance(context);
log = Log.instance(context);
@ -482,18 +485,14 @@ public class ArgumentAttr extends JCTree.Visitor {
List<JCReturn> returnExpressions() {
return returnExpressions.orElseGet(() -> {
final List<JCReturn> res;
if (speculativeTree.getBodyKind() == BodyKind.EXPRESSION) {
res = List.of(attr.make.Return((JCExpression)speculativeTree.body));
} else {
ListBuffer<JCReturn> returnExpressions = new ListBuffer<>();
new LambdaReturnScanner() {
@Override
public void visitReturn(JCReturn tree) {
returnExpressions.add(tree);
}
}.scan(speculativeTree.body);
res = returnExpressions.toList();
}
ListBuffer<JCReturn> buf = new ListBuffer<>();
new LambdaReturnScanner() {
@Override
public void visitReturn(JCReturn tree) {
buf.add(tree);
}
}.scan(speculativeTree.body);
res = buf.toList();
returnExpressions = Optional.of(res);
return res;
});
@ -519,16 +518,38 @@ public class ArgumentAttr extends JCTree.Visitor {
private void checkLambdaCompatible(Type descriptor, ResultInfo resultInfo) {
CheckContext checkContext = resultInfo.checkContext;
ResultInfo bodyResultInfo = attr.lambdaBodyResult(speculativeTree, descriptor, resultInfo);
for (JCReturn ret : returnExpressions()) {
Type t = getReturnType(ret);
if (speculativeTree.getBodyKind() == BodyKind.EXPRESSION || !t.hasTag(VOID)) {
checkSpeculative(ret.expr, t, bodyResultInfo);
}
switch (speculativeTree.getBodyKind()) {
case EXPRESSION:
checkSpeculative(speculativeTree.body, speculativeTree.body.type, bodyResultInfo);
break;
case STATEMENT:
for (JCReturn ret : returnExpressions()) {
checkReturnInStatementLambda(ret, bodyResultInfo);
}
break;
}
attr.checkLambdaCompatible(speculativeTree, descriptor, checkContext);
}
/**
* This is an inlined version of {@link Attr#visitReturn(JCReturn)}.
*/
void checkReturnInStatementLambda(JCReturn ret, ResultInfo resultInfo) {
if (resultInfo.pt.hasTag(VOID) && ret.expr != null) {
//fail - if the function type's result is void, the lambda body must be a void-compatible block.
resultInfo.checkContext.report(speculativeTree.pos(),
diags.fragment("unexpected.ret.val"));
} else if (!resultInfo.pt.hasTag(VOID)) {
if (ret.expr == null) {
//fail - if the function type's result is non-void, the lambda body must be a value-compatible block.
resultInfo.checkContext.report(speculativeTree.pos(),
diags.fragment("missing.ret.val"));
}
checkSpeculative(ret.expr, ret.expr.type, resultInfo);
}
}
/** Get the type associated with given return expression. */
Type getReturnType(JCReturn ret) {
if (ret.expr == null) {

View File

@ -3557,18 +3557,19 @@ public class Check {
Scope staticallyImportedSoFar, Scope topLevelScope,
Symbol sym, boolean staticImport) {
Filter<Symbol> duplicates = candidate -> candidate != sym && !candidate.type.isErroneous();
Symbol clashing = ordinallyImportedSoFar.findFirst(sym.name, duplicates);
if (clashing == null && !staticImport) {
clashing = staticallyImportedSoFar.findFirst(sym.name, duplicates);
Symbol ordinaryClashing = ordinallyImportedSoFar.findFirst(sym.name, duplicates);
Symbol staticClashing = null;
if (ordinaryClashing == null && !staticImport) {
staticClashing = staticallyImportedSoFar.findFirst(sym.name, duplicates);
}
if (clashing != null) {
if (staticImport)
log.error(pos, Errors.AlreadyDefinedStaticSingleImport(clashing));
if (ordinaryClashing != null || staticClashing != null) {
if (ordinaryClashing != null)
log.error(pos, Errors.AlreadyDefinedSingleImport(ordinaryClashing));
else
log.error(pos, Errors.AlreadyDefinedSingleImport(clashing));
log.error(pos, Errors.AlreadyDefinedStaticSingleImport(staticClashing));
return false;
}
clashing = topLevelScope.findFirst(sym.name, duplicates);
Symbol clashing = topLevelScope.findFirst(sym.name, duplicates);
if (clashing != null) {
log.error(pos, Errors.AlreadyDefinedThisUnit(clashing));
return false;

View File

@ -91,6 +91,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.Namespace;
import jdk.dynalink.Operation;
@ -189,85 +190,126 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
assertParameterCount(callSiteDescriptor, isFixedKey ? 1 : 2);
final LinkerServices linkerServices = req.linkerServices;
final MethodType callSiteType = callSiteDescriptor.getMethodType();
final Class<?> declaredType = callSiteType.parameterType(0);
final GuardedInvocationComponent nextComponent = getNextComponent(req);
final GuardedInvocationComponentAndCollectionType gicact = guardedInvocationComponentAndCollectionType(
callSiteType, linkerServices, MethodHandles::arrayElementGetter, GET_LIST_ELEMENT, GET_MAP_ELEMENT);
if (gicact == null) {
// Can't retrieve elements for objects that are neither arrays, nor list, nor maps.
return nextComponent;
}
final Object typedName = getTypedName(name, gicact.collectionType == CollectionType.MAP, linkerServices);
if (typedName == INVALID_NAME) {
return nextComponent;
}
return guardComponentWithRangeCheck(gicact, linkerServices,
callSiteDescriptor, nextComponent, new Binder(linkerServices, callSiteType, typedName),
isFixedKey ? NULL_GETTER_1 : NULL_GETTER_2);
}
private static class GuardedInvocationComponentAndCollectionType {
final GuardedInvocationComponent gic;
final CollectionType collectionType;
GuardedInvocationComponentAndCollectionType(final GuardedInvocationComponent gic, final CollectionType collectionType) {
this.gic = gic;
this.collectionType = collectionType;
}
}
private GuardedInvocationComponentAndCollectionType guardedInvocationComponentAndCollectionType(
final MethodType callSiteType, final LinkerServices linkerServices,
final Function<Class<?>, MethodHandle> arrayMethod, final MethodHandle listMethod, final MethodHandle mapMethod) {
final Class<?> declaredType = callSiteType.parameterType(0);
// If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing
// is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're
// dealing with an array, or a list or map, but hey...
// Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
// in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
final GuardedInvocationComponent gic;
final CollectionType collectionType;
if(declaredType.isArray()) {
gic = createInternalFilteredGuardedInvocationComponent(MethodHandles.arrayElementGetter(declaredType), linkerServices);
collectionType = CollectionType.ARRAY;
return new GuardedInvocationComponentAndCollectionType(
createInternalFilteredGuardedInvocationComponent(arrayMethod.apply(declaredType), linkerServices),
CollectionType.ARRAY);
} else if(List.class.isAssignableFrom(declaredType)) {
gic = createInternalFilteredGuardedInvocationComponent(GET_LIST_ELEMENT, linkerServices);
collectionType = CollectionType.LIST;
return new GuardedInvocationComponentAndCollectionType(
createInternalFilteredGuardedInvocationComponent(listMethod, linkerServices),
CollectionType.LIST);
} else if(Map.class.isAssignableFrom(declaredType)) {
gic = createInternalFilteredGuardedInvocationComponent(GET_MAP_ELEMENT, linkerServices);
collectionType = CollectionType.MAP;
return new GuardedInvocationComponentAndCollectionType(
createInternalFilteredGuardedInvocationComponent(mapMethod, linkerServices),
CollectionType.MAP);
} else if(clazz.isArray()) {
gic = getClassGuardedInvocationComponent(linkerServices.filterInternalObjects(MethodHandles.arrayElementGetter(clazz)), callSiteType);
collectionType = CollectionType.ARRAY;
return new GuardedInvocationComponentAndCollectionType(
getClassGuardedInvocationComponent(linkerServices.filterInternalObjects(arrayMethod.apply(clazz)), callSiteType),
CollectionType.ARRAY);
} else if(List.class.isAssignableFrom(clazz)) {
gic = createInternalFilteredGuardedInvocationComponent(GET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class, ValidationType.INSTANCE_OF,
linkerServices);
collectionType = CollectionType.LIST;
return new GuardedInvocationComponentAndCollectionType(
createInternalFilteredGuardedInvocationComponent(listMethod, Guards.asType(LIST_GUARD, callSiteType),
List.class, ValidationType.INSTANCE_OF, linkerServices),
CollectionType.LIST);
} else if(Map.class.isAssignableFrom(clazz)) {
gic = createInternalFilteredGuardedInvocationComponent(GET_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType), Map.class, ValidationType.INSTANCE_OF,
linkerServices);
collectionType = CollectionType.MAP;
} else {
// Can't retrieve elements for objects that are neither arrays, nor list, nor maps.
return nextComponent;
return new GuardedInvocationComponentAndCollectionType(
createInternalFilteredGuardedInvocationComponent(mapMethod, Guards.asType(MAP_GUARD, callSiteType),
Map.class, ValidationType.INSTANCE_OF, linkerServices),
CollectionType.MAP);
}
return null;
}
private static final Object INVALID_NAME = new Object();
private static Object getTypedName(final Object name, final boolean isMap, final LinkerServices linkerServices) throws Exception {
// Convert the key to a number if we're working with a list or array
final Object typedName;
if (collectionType != CollectionType.MAP && isFixedKey) {
if (!isMap && name != null) {
final Integer integer = convertKeyToInteger(name, linkerServices);
if (integer == null || integer.intValue() < 0) {
// key is not a non-negative integer, it can never address an
// array or list element
return nextComponent;
return INVALID_NAME;
}
typedName = integer;
} else {
typedName = name;
return integer;
}
return name;
}
final GuardedInvocation gi = gic.getGuardedInvocation();
final Binder binder = new Binder(linkerServices, callSiteType, typedName);
final MethodHandle invocation = gi.getInvocation();
private static GuardedInvocationComponent guardComponentWithRangeCheck(
final GuardedInvocationComponentAndCollectionType gicact, final LinkerServices linkerServices,
final CallSiteDescriptor callSiteDescriptor, final GuardedInvocationComponent nextComponent, final Binder binder,
final MethodHandle noOp) {
final MethodType callSiteType = callSiteDescriptor.getMethodType();
final MethodHandle checkGuard;
switch(collectionType) {
case LIST:
checkGuard = convertArgToNumber(RANGE_CHECK_LIST, linkerServices, callSiteDescriptor);
break;
case MAP:
checkGuard = linkerServices.filterInternalObjects(CONTAINS_MAP);
break;
case ARRAY:
checkGuard = convertArgToNumber(RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
break;
default:
throw new AssertionError();
switch(gicact.collectionType) {
case LIST:
checkGuard = convertArgToNumber(RANGE_CHECK_LIST, linkerServices, callSiteDescriptor);
break;
case MAP:
checkGuard = linkerServices.filterInternalObjects(CONTAINS_MAP);
break;
case ARRAY:
checkGuard = convertArgToNumber(RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
break;
default:
throw new AssertionError();
}
// If there's no next component, produce a fixed null-returning one
// If there's no next component, produce a fixed no-op one
final GuardedInvocationComponent finalNextComponent;
if (nextComponent != null) {
finalNextComponent = nextComponent;
} else {
final MethodHandle nullGetterHandle = isFixedKey ? NULL_GETTER_1 : NULL_GETTER_2;
finalNextComponent = createGuardedInvocationComponentAsType(nullGetterHandle, callSiteType, linkerServices);
finalNextComponent = createGuardedInvocationComponentAsType(noOp, callSiteType, linkerServices);
}
final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation),
final GuardedInvocationComponent gic = gicact.gic;
final GuardedInvocation gi = gic.getGuardedInvocation();
final MethodPair matchedInvocations = matchReturnTypes(binder.bind(gi.getInvocation()),
finalNextComponent.getGuardedInvocation().getInvocation());
return finalNextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(),
gic.getValidatorClass(), gic.getValidationType());
}
@ -435,90 +477,37 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
assertParameterCount(callSiteDescriptor, isFixedKey ? 2 : 3);
final LinkerServices linkerServices = req.linkerServices;
final MethodType callSiteType = callSiteDescriptor.getMethodType();
final Class<?> declaredType = callSiteType.parameterType(0);
final GuardedInvocationComponent gic;
// If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing
// is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're
// dealing with an array, or a list or map, but hey...
// Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
// in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
final CollectionType collectionType;
if(declaredType.isArray()) {
gic = createInternalFilteredGuardedInvocationComponent(MethodHandles.arrayElementSetter(declaredType), linkerServices);
collectionType = CollectionType.ARRAY;
} else if(List.class.isAssignableFrom(declaredType)) {
gic = createInternalFilteredGuardedInvocationComponent(SET_LIST_ELEMENT, linkerServices);
collectionType = CollectionType.LIST;
} else if(Map.class.isAssignableFrom(declaredType)) {
gic = createInternalFilteredGuardedInvocationComponent(PUT_MAP_ELEMENT, linkerServices);
collectionType = CollectionType.MAP;
} else if(clazz.isArray()) {
gic = getClassGuardedInvocationComponent(linkerServices.filterInternalObjects(
MethodHandles.arrayElementSetter(clazz)), callSiteType);
collectionType = CollectionType.ARRAY;
} else if(List.class.isAssignableFrom(clazz)) {
gic = createInternalFilteredGuardedInvocationComponent(SET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class, ValidationType.INSTANCE_OF,
linkerServices);
collectionType = CollectionType.LIST;
} else if(Map.class.isAssignableFrom(clazz)) {
gic = createInternalFilteredGuardedInvocationComponent(PUT_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType),
Map.class, ValidationType.INSTANCE_OF, linkerServices);
collectionType = CollectionType.MAP;
} else {
// Can't set elements for objects that are neither arrays, nor list, nor maps.
gic = null;
collectionType = null;
final GuardedInvocationComponentAndCollectionType gicact = guardedInvocationComponentAndCollectionType(
callSiteType, linkerServices, MethodHandles::arrayElementSetter, SET_LIST_ELEMENT, PUT_MAP_ELEMENT);
if(gicact == null) {
return getNextComponent(req);
}
final boolean isMap = gicact.collectionType == CollectionType.MAP;
// In contrast to, say, getElementGetter, we only compute the nextComponent if the target object is not a map,
// as maps will always succeed in setting the element and will never need to fall back to the next component
// operation.
final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getNextComponent(req);
if(gic == null) {
final GuardedInvocationComponent nextComponent = isMap ? null : getNextComponent(req);
final Object typedName = getTypedName(name, isMap, linkerServices);
if (typedName == INVALID_NAME) {
return nextComponent;
}
// Convert the key to a number if we're working with a list or array
final Object typedName;
if (collectionType != CollectionType.MAP && isFixedKey) {
final Integer integer = convertKeyToInteger(name, linkerServices);
if (integer == null || integer.intValue() < 0) {
// key is not a non-negative integer, it can never address an
// array or list element
return nextComponent;
}
typedName = integer;
} else {
typedName = name;
}
final GuardedInvocationComponent gic = gicact.gic;
final GuardedInvocation gi = gic.getGuardedInvocation();
final Binder binder = new Binder(linkerServices, callSiteType, typedName);
final MethodHandle invocation = gi.getInvocation();
if (collectionType == CollectionType.MAP) {
assert nextComponent == null;
if (isMap) {
return gic.replaceInvocation(binder.bind(invocation));
}
assert collectionType == CollectionType.LIST || collectionType == CollectionType.ARRAY;
final MethodHandle checkGuard = convertArgToNumber(collectionType == CollectionType.LIST ? RANGE_CHECK_LIST :
RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
// If there's no next component, produce a no-op one.
final GuardedInvocationComponent finalNextComponent;
if (nextComponent != null) {
finalNextComponent = nextComponent;
} else {
final MethodHandle noOpSetterHandle = isFixedKey ? NO_OP_SETTER_2 : NO_OP_SETTER_3;
finalNextComponent = createGuardedInvocationComponentAsType(noOpSetterHandle, callSiteType, linkerServices);
}
final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation),
finalNextComponent.getGuardedInvocation().getInvocation());
return finalNextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(),
gic.getValidatorClass(), gic.getValidationType());
return guardComponentWithRangeCheck(gicact, linkerServices, callSiteDescriptor,
nextComponent, binder, isFixedKey ? NO_OP_SETTER_2 : NO_OP_SETTER_3);
}
private static final MethodHandle GET_COLLECTION_LENGTH = Lookup.PUBLIC.findVirtual(Collection.class, "size",

View File

@ -1,10 +1,16 @@
/* Javadoc style sheet */
/*
Overall document style
*/
/*
* Javadoc style sheet
*/
@import url('resources/fonts/dejavu.css');
/*
* Styles for individual HTML elements.
*
* These are styles that are specific to individual HTML elements. Changing them affects the style of a particular
* HTML element throughout the page.
*/
body {
background-color:#ffffff;
color:#353833;
@ -41,9 +47,6 @@ a[name]:before, a[name]:target, a[id]:before, a[id]:target {
padding-top:129px;
margin-top:-129px;
}
.searchTagResult:before, .searchTagResult:target {
color:red;
}
pre {
font-family:'DejaVu Sans Mono', monospace;
font-size:14px;
@ -91,9 +94,16 @@ table tr td dt code {
sup {
font-size:8px;
}
/*
Document title and Copyright styles
*/
* Styles for HTML generated by javadoc.
*
* These are style classes that are used by the standard doclet to generate HTML documentation.
*/
/*
* Styles for document title and copyright.
*/
.clear {
clear:both;
height:0px;
@ -124,8 +134,8 @@ Document title and Copyright styles
font-weight:bold;
}
/*
Navigation bar styles
*/
* Styles for navigation bar.
*/
.bar {
background-color:#4D7A97;
color:#FFFFFF;
@ -233,8 +243,8 @@ ul.subNavList li {
overflow:hidden;
}
/*
Page header and footer styles
*/
* Styles for page header and footer.
*/
.header, .footer {
clear:both;
margin:0 20px;
@ -277,8 +287,8 @@ Page header and footer styles
font-size:13px;
}
/*
Heading styles
*/
* Styles for headings.
*/
div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 {
background-color:#dee3e9;
border:1px solid #d0d9e0;
@ -299,8 +309,8 @@ ul.blockList li.blockList h2 {
padding:0px 0 20px 0;
}
/*
Page layout container styles
*/
* Styles for page layout containers.
*/
.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer {
clear:both;
padding:10px 20px;
@ -346,8 +356,8 @@ Page layout container styles
display:inline;
}
/*
List styles
*/
* Styles for lists.
*/
li.circle {
list-style:circle;
}
@ -403,8 +413,8 @@ table tr td dl, table tr td dl dt, table tr td dl dd {
margin-bottom:1px;
}
/*
Table styles
*/
* Styles for tables.
*/
.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary,
.requiresSummary, .packagesSummary, .providesSummary, .usesSummary {
width:100%;
@ -529,7 +539,6 @@ Table styles
position:relative;
background-color:#4D7A97;
float:left;
}
.rowColor th, .altColor th {
font-weight:normal;
@ -601,8 +610,8 @@ th.colDeprecatedItemName a:link, th.colDeprecatedItemName a:visited,
background-color:#EEEEEF;
}
/*
Content styles
*/
* Styles for contents.
*/
.description pre {
margin-top:0;
}
@ -613,27 +622,22 @@ Content styles
.docSummary {
padding:0;
}
ul.blockList ul.blockList ul.blockList li.blockList h3 {
font-style:normal;
}
div.block {
font-size:14px;
font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
}
td.colLast div {
padding-top:0px;
}
td.colLast a {
padding-bottom:3px;
}
/*
Formatting effect styles
*/
* Styles for formatting effect.
*/
.sourceLineNo {
color:green;
padding:0 30px 0 0;
@ -668,18 +672,16 @@ h1.hidden {
margin-right:10px;
display:inline-block;
}
div.block div.deprecationComment, div.block div.block span.emphasizedPhrase,
div.block div.block span.interfaceName {
font-style:normal;
}
div.contentContainer ul.blockList li.blockList h2 {
padding-bottom:0px;
}
/*
IFRAME specific styles
*/
* Styles for IFRAME.
*/
.mainContainer {
margin:0 auto;
padding:0;
@ -733,11 +735,14 @@ IFRAME specific styles
margin-bottom:30px;
}
/*
HTML5 specific styles
*/
* Styles specific to HTML5 elements.
*/
main, nav, header, footer, section {
display:block;
}
/*
* Styles for javadoc search.
*/
.ui-autocomplete-category {
font-weight:bold;
font-size:15px;
@ -802,7 +807,9 @@ ul.ui-autocomplete li {
font-style:italic;
font-size:12px;
}
.searchTagResult:before, .searchTagResult:target {
color:red;
}
.moduleGraph span {
display:none;
position:absolute;
@ -838,20 +845,17 @@ table.striped {
margin-top: 10px;
margin-bottom: 10px;
}
table.borderless > caption,
table.plain > caption,
table.striped > caption {
font-weight: bold;
font-size: smaller;
}
table.borderless th, table.borderless td,
table.plain th, table.plain td,
table.striped th, table.striped td {
padding: 2px 5px;
}
table.borderless,
table.borderless > thead > tr > th, table.borderless > tbody > tr > th, table.borderless > tr > th,
table.borderless > thead > tr > td, table.borderless > tbody > tr > td, table.borderless > tr > td {
@ -860,7 +864,6 @@ table.borderless > thead > tr > td, table.borderless > tbody > tr > td, table.bo
table.borderless > thead > tr, table.borderless > tbody > tr, table.borderless > tr {
background-color: transparent;
}
table.plain {
border-collapse: collapse;
border: 1px solid black;
@ -872,7 +875,6 @@ table.plain > thead > tr > th, table.plain > tbody > tr > th, table.plain > tr >
table.plain > thead > tr > td, table.plain > tbody > tr > td, table.plain > tr > td {
border: 1px solid black;
}
table.striped {
border-collapse: collapse;
border: 1px solid black;

View File

@ -306,10 +306,10 @@ final class SplitIntoFunctions extends NodeVisitor<BlockLexicalContext> {
@Override
public boolean enterVarNode(final VarNode varNode) {
if (!inSplitNode()) {
// ES6 block scoped declarations are already placed at their proper position by splitter
if (!inSplitNode() || varNode.isBlockScoped()) {
return super.enterVarNode(varNode);
}
assert !varNode.isBlockScoped(); //TODO: we must handle these too, but we currently don't
final Expression init = varNode.getInit();

View File

@ -41,6 +41,7 @@ import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.Splittable;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
@ -201,8 +202,9 @@ final class Splitter extends SimpleNodeVisitor implements Loggable {
for (final Statement statement : block.getStatements()) {
final long weight = WeighNodes.weigh(statement, weightCache);
final boolean isBlockScopedVarNode = isBlockScopedVarNode(statement);
if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) {
if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal() || isBlockScopedVarNode) {
if (!statements.isEmpty()) {
splits.add(createBlockSplitNode(block, function, statements, statementsWeight));
statements = new ArrayList<>();
@ -210,7 +212,7 @@ final class Splitter extends SimpleNodeVisitor implements Loggable {
}
}
if (statement.isTerminal()) {
if (statement.isTerminal() || isBlockScopedVarNode) {
splits.add(statement);
} else {
statements.add(statement);
@ -243,6 +245,10 @@ final class Splitter extends SimpleNodeVisitor implements Loggable {
return new SplitNode(name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
}
private boolean isBlockScopedVarNode(final Statement statement) {
return statement instanceof VarNode && ((VarNode) statement).isBlockScoped();
}
@Override
public boolean enterBlock(final Block block) {
if (block.isCatchBlock()) {

View File

@ -25,6 +25,7 @@
package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
/**
@ -37,6 +38,7 @@ public final class SplitReturn extends Statement {
private static final long serialVersionUID = 1L;
/** The sole instance of this AST node. */
@Ignore
public static final SplitReturn INSTANCE = new SplitReturn();
private SplitReturn() {

View File

@ -0,0 +1,265 @@
/*
* 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.
*/
/*
* The certificates and corresponding private keys used by the test.
* All of certificates uses relative weak key size and hash algorithm, then
* all JDK releases can load them. Accordingly, a custom java.security file is
* provided to make sure such weak key sizes and algorithms are not blocked by
* any JDK build.
*/
public enum Cert {
// This certificate is generated by the below command:
// openssl req -x509 -newkey rsa:1024 -days 7300 \
// -subj "/CN=RSA_SHA1_1024" -sha1 \
// -keyout key.pem -out cert.pem
RSA_SHA1_1024(
SignatureAlgorithm.RSA,
"-----BEGIN CERTIFICATE-----\n" +
"MIIB/jCCAWegAwIBAgIJANPuKkD7/jxkMA0GCSqGSIb3DQEBBQUAMBgxFjAUBgNV\n" +
"BAMMDVJTQV9TSEExXzEwMjQwHhcNMTcwOTA3MDIwNTM0WhcNMzcwOTAyMDIwNTM0\n" +
"WjAYMRYwFAYDVQQDDA1SU0FfU0hBMV8xMDI0MIGfMA0GCSqGSIb3DQEBAQUAA4GN\n" +
"ADCBiQKBgQC3v7UeIxD5bdv4mqwcpah7sNxpI3IxUFzI2ao1g1jVzDPZt9Zawa3K\n" +
"H+m9al1Fg2X1dyNeRlbiXavcIZOQwZqNj08zJEwAdICP8iOnXQ2HUv5cpzArOPTu\n" +
"GY3flhf39xgiWsSdfb+cP0QsWNagNU8EtebbHndv8W+2K5JEdlpwQQIDAQABo1Aw\n" +
"TjAdBgNVHQ4EFgQU32KqdiGyzg39chNt/OwQzGOlUyAwHwYDVR0jBBgwFoAU32Kq\n" +
"diGyzg39chNt/OwQzGOlUyAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOB\n" +
"gQAWx8y45IIWWhy44cuQs0qcSDQihIvhXB3pvlpCNdfsSrVoaaH8lrOVjTC718ip\n" +
"fE1sF8I9niLHUg8WrAzdQRDsKyUhDUhEEJ7w1ffxwf8bcI9+NgWwEix0Dazzkub8\n" +
"2IRXuZ3dGwzoI54XtxvKMFH86nJEj4M/XQGrc9bnlhcn4g==\n" +
"-----END CERTIFICATE-----",
"30820278020100300d06092a864886f70d0101010500048202623082025e0201" +
"0002818100b7bfb51e2310f96ddbf89aac1ca5a87bb0dc69237231505cc8d9aa" +
"358358d5cc33d9b7d65ac1adca1fe9bd6a5d458365f577235e4656e25dabdc21" +
"9390c19a8d8f4f33244c0074808ff223a75d0d8752fe5ca7302b38f4ee198ddf" +
"9617f7f718225ac49d7dbf9c3f442c58d6a0354f04b5e6db1e776ff16fb62b92" +
"44765a7041020301000102818100b2c5afdf5c5a9d72c73b7eb0c9465b3fcc79" +
"0549d946255bc0861555ef2eb503f1c67757f400cfa7019996123020fb906d5b" +
"b66b789ffba90b16270cbd1fbfcf285a821dcdc78fd8f17f399eb231ce9724db" +
"af60f9dd20f3e57bb4c0f9fdc9069589b82d442dd868d48c031eb782e27f9e70" +
"8469f9b3d5b1b23cee5bf1b41781024100dec184ea77c2126c6bc0c01ba727b4" +
"642587d63811240932334dc80c7976e0f715f156e52b352a25e5c52542af2b5f" +
"68a29a9b68858f313c4375cc78ec03d859024100d32be8375f52cbe904002321" +
"6977aee83fa88bf536d4052d2ed578727d7b7e5aeef91fc52b34c1b6638c00f0" +
"4c6985fdaaa2d6e72adbcc7d10ed8bafff69da29024100ae8210acd6f13519b7" +
"38a3c7862636ce1610daa3c5d9e3526e9acad3eafc54b57d7d3a44029b7dcf7e" +
"b7f9beca1842806892929949b8aa2bb9f5b9202a55c0d1024100887dc0c2c9a2" +
"429a823374818c2207b3a631d304d443867505e884c9bbc1ae9228146e2c8b18" +
"b67ca52b411010d3c3ff89e366f454076dcd08bc01a5e8790ac102402321988a" +
"2003e19c878791d402a7c0acdd1b6dd27203ed88f86a0e3a390ee57c0cd277f3" +
"ea5df6440dbc8bdb4c8b3c28fc77e6991bc4ed3f4dc0619a5b953e8e"),
// This certificate is generated by the below command:
// openssl req -x509 -newkey rsa:1024 -days 7300 \
// -subj "/CN=www.example.com" -sha1 \
// -keyout key.pem -out cert.pem
RSA_EXAMPLE_SHA1_1024(
SignatureAlgorithm.RSA,
"-----BEGIN CERTIFICATE-----\n" +
"MIICAjCCAWugAwIBAgIJAK6TC9eDtZg4MA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNV\n" +
"BAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNzExMDIwNTA5NDRaFw0zNzEwMjgwNTA5\n" +
"NDRaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEF\n" +
"AAOBjQAwgYkCgYEAtt5kxFTzJuoxJR2UgeXUxCw7TfL3FeK3lCrU3vruBe3XKKvF\n" +
"oyCxf/B5ucm22gzMfOvJBWRg6KrNTrXGI1LtlmAYNDM5J0lK2N/neKOm3Qxe0d1W\n" +
"AZ1lwgrMNirsWu+r4UPNMq5UohL5nqVU9WwVa12t0GF3er3k32tMTBqSclcCAwEA\n" +
"AaNQME4wHQYDVR0OBBYEFNc8tKGfZdFyaY0ZslwGLt1kpRYAMB8GA1UdIwQYMBaA\n" +
"FNc8tKGfZdFyaY0ZslwGLt1kpRYAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF\n" +
"BQADgYEAc71ZO83YEw9WvhxDEng9tMYUhJnNZJss6+gfWjZ487aiEGnS+VgKsHWz\n" +
"DBLBrYe9Ag5L9f1HtPNheUbnhhBbQ607jOG/wfmpi4VoU3myB5uxOfeAZdXDOB5x\n" +
"bv3t7KcEhgmPjB/e123jrBK8qnAYmDlQVlkZScctB3I1OuA2Po4=\n" +
"-----END CERTIFICATE-----",
"30820277020100300d06092a864886f70d0101010500048202613082025d0201" +
"0002818100b6de64c454f326ea31251d9481e5d4c42c3b4df2f715e2b7942ad4" +
"defaee05edd728abc5a320b17ff079b9c9b6da0ccc7cebc9056460e8aacd4eb5" +
"c62352ed96601834333927494ad8dfe778a3a6dd0c5ed1dd56019d65c20acc36" +
"2aec5aefabe143cd32ae54a212f99ea554f56c156b5dadd061777abde4df6b4c" +
"4c1a927257020301000102818048af52bc1acbdededd13d4930fa28b9441c47c" +
"b222f5c6fc92df07676db3a815a61c9b51de0a03a347b10a609bd6459a0dd926" +
"38877261686a5c6bb1ca9e8ea2373870af7685e7d6cebd66faba65af2ef04bd9" +
"1244ae56900fcd6ce11207d8c4040176e4ba9fef3d563741a1027b229134cfe1" +
"c0a90d9c8eba9ce6349835e769024100e82494b6f777c784ffc29298d033e11d" +
"af46f0d464c4dbd950d46bcd697d0f0b49a77699f0111d408e8748f2b461ab8f" +
"210071c9c20d8ecee3ae229cb9c3954b024100c9a976f0011fcdc0ca7fb2f679" +
"974fa85d420c604ca7ff64fe4667a44f73088eef290d22195474039760e99325" +
"3ca45ee444588b150467d14451d3c45dab0ba5024019df39d3ca70c703c39d63" +
"c9342b1403c2ed1d1a0ec101df8e6a9e391e7099a4a068d187068261c8381a4b" +
"bf00eb81bb49ea4ac439a4592e25a1daa9acea67510241008c4640007497bdd4" +
"94473da26b33d06a29ecae9531dd4e2edf1cf42cfc42e53a1fac2b8183a3164c" +
"053999600c6fe15a4c682a3b1cb482ceb33a4416fc9ce52d024100e4f08cd10a" +
"5c8face0b20db86443d0a42e34dfdde236dae4f042a06dd3aff7ca159f8aa3b7" +
"854df41d510148096155204f2bf46c4a96e271747a4126a66ade6c"),
// This certificate is generated by the below commands:
// openssl dsaparam -genkey 1024 -out key.pem
// openssl req -x509 -new -key key.pem -days 7300 \
// -subj "/CN=DSA_SHA1_1024" -sha1 -out cert.pem
DSA_SHA1_1024(
SignatureAlgorithm.DSA,
"-----BEGIN CERTIFICATE-----\n" +
"MIICuzCCAnugAwIBAgIJAMAMLRrhQWQFMAkGByqGSM44BAMwGDEWMBQGA1UEAwwN\n" +
"RFNBX1NIQTFfMTAyNDAeFw0xNzExMDIwNjA4MDRaFw0zNzEwMjgwNjA4MDRaMBgx\n" +
"FjAUBgNVBAMMDURTQV9TSEExXzEwMjQwggG2MIIBKwYHKoZIzjgEATCCAR4CgYEA\n" +
"8CspE1sE84pJ4YxzVHFEDNJvBaIxsbax03pDwNHr/ogP9PVwF9z1jT6hpC5WluHG\n" +
"g5n5gqpF2XpBhX2fKm1qqZWRxNvHKo0+zzAhUqMrvRJqcjlL4ijXndHldt67/VKS\n" +
"0eTKi9m64c+yJx80YYphCO5b93d2sTM29z8QZOlrbD8CFQCmttKnPAOk4uz8Z8cV\n" +
"uPGeGOMB9wKBgCItgPpAjW0srIwCaDysDNpydX6hB+1NTy1gFYl24n8edLGbR0mZ\n" +
"isteBd6LjMtgicRmtKZzKxW7igxoVvR3WHpTucFjms5NRNjPaj5wt3DxoXn4hyWk\n" +
"LzMvDeBvi+jKJiO0jnQ3+1NDOlAQy6ukeH59/gxZ3UmcNxDlAQ/IYHcpA4GEAAKB\n" +
"gEgvi72gL+zax7Y2hg4PL1PqZx2jFp0XlTIugiTrcsGytrAnn+/s2+3xVyVyvVMn\n" +
"0z5yL5eP9cdGA7qV1+7n6KJ8jNAhLCBSiC6x5ekd88aTlqnmt5lstk4w0Q0zSa58\n" +
"Hp6dCFg2Irk6Z9ERKaXJJBBS6reaFeATVROhN/LEEzzvo1AwTjAdBgNVHQ4EFgQU\n" +
"jb+HHABclGNR4lpf19nHFZpfwPQwHwYDVR0jBBgwFoAUjb+HHABclGNR4lpf19nH\n" +
"FZpfwPQwDAYDVR0TBAUwAwEB/zAJBgcqhkjOOAQDAy8AMCwCFDB3F/m6jsZdHaoy\n" +
"1xTp2U8uHBO+AhQYzeJuJd8/qRSDVLs8mesE8TQg2g==\n" +
"-----END CERTIFICATE-----",
"3082014a0201003082012b06072a8648ce3804013082011e02818100f02b2913" +
"5b04f38a49e18c735471440cd26f05a231b1b6b1d37a43c0d1ebfe880ff4f570" +
"17dcf58d3ea1a42e5696e1c68399f982aa45d97a41857d9f2a6d6aa99591c4db" +
"c72a8d3ecf302152a32bbd126a72394be228d79dd1e576debbfd5292d1e4ca8b" +
"d9bae1cfb2271f34618a6108ee5bf77776b13336f73f1064e96b6c3f021500a6" +
"b6d2a73c03a4e2ecfc67c715b8f19e18e301f7028180222d80fa408d6d2cac8c" +
"02683cac0cda72757ea107ed4d4f2d60158976e27f1e74b19b4749998acb5e05" +
"de8b8ccb6089c466b4a6732b15bb8a0c6856f477587a53b9c1639ace4d44d8cf" +
"6a3e70b770f1a179f88725a42f332f0de06f8be8ca2623b48e7437fb53433a50" +
"10cbaba4787e7dfe0c59dd499c3710e5010fc8607729041602146ef9db36045f" +
"bcd8c7fd82ba29c5c5057ed11c7f"),
// This certificate is generated by the below commands:
// openssl dsaparam -genkey 1024 -out key.pem
// openssl req -x509 -new -key key.pem -days 7300 \
// -subj "/CN=www.example.com" -sha1 -out cert.pem
DSA_EXAMPLE_SHA1_1024(
SignatureAlgorithm.DSA,
"-----BEGIN CERTIFICATE-----\n" +
"MIICwDCCAoCgAwIBAgIJAI5mKbdK5ZqyMAkGByqGSM44BAMwGjEYMBYGA1UEAwwP\n" +
"d3d3LmV4YW1wbGUuY29tMB4XDTE3MTEwMjA1NDczOVoXDTM3MTAyODA1NDczOVow\n" +
"GjEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMIIBtzCCASwGByqGSM44BAEwggEf\n" +
"AoGBANVGWRSlxVZQKlVrTDcU/6Mr8QFlR3kGKmkvdbTHH1EhcP7YlZ7CJ30VBDbN\n" +
"LS2HvN3HHNooJ7hHBheL5Yz8EZIUa95TzPukZ1TmCo9fufR5i9HWj9Z8jLhyqx3l\n" +
"iUZOYN9H0MSn4ftK6dr5oTz2ZGYDblXDCq6R8qZfuw1URFqrAhUArx0nmGEI/1S/\n" +
"qyxnV4I6ItOntxMCgYEAxZKIZ/7aOGfzaQG2wRFdD/viHBZkkcxCsgmPUroQVUIw\n" +
"dqmUnfYk8cb02LCevhhSwcjfocQsA3y1jufIUdWaHuIB9W3EsFJQNd/Byh9j/pRD\n" +
"7zH/8lnBzJh2S7y10Vg840STVo5+ekZb4E+W7KK5gUaEQ6kAtUIIB0xjNz7RWs4D\n" +
"gYQAAoGAPVQKWqJSlMrbU4XEsx50Ur8P84CwMnS7WcQNLnih1ScaK2BijgVj5Fny\n" +
"9JZxITwj7XD7FWriq3kTjbydi3iAvrgVWij79x5Z7fTRCuoBVmtnAFkVGalwbGr2\n" +
"ghz70y6hep2Evb1pRCrHjRkMaJFE5Y2CA7VbpKoat+j47/LkXJ2jUDBOMB0GA1Ud\n" +
"DgQWBBSVjWy3SpaDfnFo+37mZJqX2aybzTAfBgNVHSMEGDAWgBSVjWy3SpaDfnFo\n" +
"+37mZJqX2aybzTAMBgNVHRMEBTADAQH/MAkGByqGSM44BAMDLwAwLAIUd5NOlcfX\n" +
"5rakT9H8UzlFcFQLr0MCFGrEYvlFUf/HJOH4FwXS2jEholBB\n" +
"-----END CERTIFICATE-----",
"3082014c0201003082012c06072a8648ce3804013082011f02818100d5465914" +
"a5c556502a556b4c3714ffa32bf101654779062a692f75b4c71f512170fed895" +
"9ec2277d150436cd2d2d87bcddc71cda2827b84706178be58cfc1192146bde53" +
"ccfba46754e60a8f5fb9f4798bd1d68fd67c8cb872ab1de589464e60df47d0c4" +
"a7e1fb4ae9daf9a13cf66466036e55c30aae91f2a65fbb0d54445aab021500af" +
"1d27986108ff54bfab2c6757823a22d3a7b71302818100c5928867feda3867f3" +
"6901b6c1115d0ffbe21c166491cc42b2098f52ba1055423076a9949df624f1c6" +
"f4d8b09ebe1852c1c8dfa1c42c037cb58ee7c851d59a1ee201f56dc4b0525035" +
"dfc1ca1f63fe9443ef31fff259c1cc98764bbcb5d1583ce34493568e7e7a465b" +
"e04f96eca2b981468443a900b54208074c63373ed15ace0417021500abf47692" +
"88c6ac41e2802e7eb7addba367339318"),
// This certificate is generated by the below commands:
// openssl ecparam -name prime256v1 -genkey -out key.pem
// openssl req -new -key key.pem -x509 -nodes -days 7300 \
// -subj "/CN=ECDSA_SHA1_prime256v1" -sha1 -out cert.pem
ECDSA_SHA1_PRIME256V1(
SignatureAlgorithm.ECDSA,
"-----BEGIN CERTIFICATE-----\n" +
"MIIBhDCCASygAwIBAgIJAKW4wuujp9JbMAkGByqGSM49BAEwIDEeMBwGA1UEAwwV\n" +
"RUNEU0FfU0hBMV9wcmltZTI1NnYxMB4XDTE3MDkwNzAyMTA0MVoXDTM3MDkwMjAy\n" +
"MTA0MVowIDEeMBwGA1UEAwwVRUNEU0FfU0hBMV9wcmltZTI1NnYxMFkwEwYHKoZI\n" +
"zj0CAQYIKoZIzj0DAQcDQgAEdbE+AMwsFBf73YXRVwsvsx2dMt1xgDxj/4pN+BfY\n" +
"LWnO94beeZcrCJ1/N8CHmDOce7KRDR6/9kpi20wFAVXZ3KNQME4wHQYDVR0OBBYE\n" +
"FA/hB2ODDNdz1JF08u2uhknhlsVoMB8GA1UdIwQYMBaAFA/hB2ODDNdz1JF08u2u\n" +
"hknhlsVoMAwGA1UdEwQFMAMBAf8wCQYHKoZIzj0EAQNHADBEAiBNxv2L2FW+6+w/\n" +
"QtDe+YSUNRj3F8QrpLkfGk7rVaOiHQIgVF2pWJ5ytg0pbCuO8Bh+UZ7zfZUD03s8\n" +
"ZuIYW7RtMe0=\n" +
"-----END CERTIFICATE-----",
"308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
"010104204d901d5efd0e3def78d5307788a4c760115effce4b9e2c31ae5860b6" +
"c11915aca1440342000475b13e00cc2c1417fbdd85d1570b2fb31d9d32dd7180" +
"3c63ff8a4df817d82d69cef786de79972b089d7f37c08798339c7bb2910d1ebf" +
"f64a62db4c050155d9dc"),
// This certificate is generated by the below commands:
// openssl ecparam -name prime256v1 -genkey -out key.pem
// openssl req -new -key key.pem -x509 -nodes -days 7300 \
// -subj "/CN=www.example.com" -sha1 -out cert.pem
ECDSA_EXAMPLE_SHA1_PRIME256V1(
SignatureAlgorithm.ECDSA,
"-----BEGIN CERTIFICATE-----\n" +
"MIIBeDCCASCgAwIBAgIJAMxOXBpiJ5mDMAkGByqGSM49BAEwGjEYMBYGA1UEAwwP\n" +
"d3d3LmV4YW1wbGUuY29tMB4XDTE3MTEwMjA1MTg0MVoXDTM3MTAyODA1MTg0MVow\n" +
"GjEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D\n" +
"AQcDQgAER9IyuwyrJ7X9DmIqGC3YNTlWBt4Fo/Y3RnlcxhTVxb/ZAYVNhqe4MbSM\n" +
"2nsVnYMjjXXDav1plNKvmgGDf9s/saNQME4wHQYDVR0OBBYEFHNUTaIIEA89uNKH\n" +
"OOUgJ981Qj5HMB8GA1UdIwQYMBaAFHNUTaIIEA89uNKHOOUgJ981Qj5HMAwGA1Ud\n" +
"EwQFMAMBAf8wCQYHKoZIzj0EAQNHADBEAiBCW59S1nE15j8euO6/q9bM6J9Ci5xJ\n" +
"WWAVznGGxnS/HgIgFaFKC31uxTXoBN7QN0yW/umQgJ0nsjwj7Pnxc0wNyw8=\n" +
"-----END CERTIFICATE-----",
"308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
"010104209aa3784cd0c1fe0553e59b3c7b8f08c8fdaffd94f34e2c1683243a79" +
"7b64b673a1440342000447d232bb0cab27b5fd0e622a182dd835395606de05a3" +
"f63746795cc614d5c5bfd901854d86a7b831b48cda7b159d83238d75c36afd69" +
"94d2af9a01837fdb3fb1");
public final SignatureAlgorithm signatureAlgorithm;
public final String certMaterials;
public final String privKeyMaterials;
private Cert(
SignatureAlgorithm signatureAlgorithm,
String certMaterials,
String privKeyMaterials) {
this.signatureAlgorithm = signatureAlgorithm;
this.certMaterials = certMaterials;
this.privKeyMaterials = privKeyMaterials;
}
// Two certificates (mainCert and exampleCert) are selected to respect the
// specified cipher suite. SNI-associated cases specify exampleCert as desired.
public static Cert[] getCerts(String cipherSuite) {
Cert mainCert = Cert.DSA_SHA1_1024;
Cert exampleCert = Cert.DSA_EXAMPLE_SHA1_1024;
if (cipherSuite.contains("_ECDHE_RSA_")) {
mainCert = Cert.RSA_SHA1_1024;
exampleCert = Cert.RSA_EXAMPLE_SHA1_1024;
} else if (cipherSuite.contains("_EC")) {
mainCert = Cert.ECDSA_SHA1_PRIME256V1;
exampleCert = Cert.ECDSA_EXAMPLE_SHA1_PRIME256V1;
} else if (cipherSuite.contains("_RSA")) {
mainCert = Cert.RSA_SHA1_1024;
exampleCert = Cert.RSA_EXAMPLE_SHA1_1024;
}
System.out.printf("mainCert=%s, exampleCert=%s%n",
mainCert, exampleCert);
return new Cert[] { mainCert, exampleCert };
}
}
enum SignatureAlgorithm {
RSA, DSA, ECDSA;
}

View File

@ -0,0 +1,206 @@
/*
* 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.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
/*
* A simple SSL socket client.
*/
public class Client {
private final SSLSocket socket;
public Client(SSLContext context) throws Exception {
SSLSocketFactory socketFactory = context.getSocketFactory();
socket = (SSLSocket) socketFactory.createSocket();
socket.setSoTimeout(Utils.TIMEOUT);
}
public Client(Cert... certs) throws Exception {
this(Utils.createSSLContext(certs));
}
private SSLSession getSession() {
return socket.getSession();
}
private void setEnabledCipherSuites(String... cipherSuites) {
socket.setEnabledCipherSuites(cipherSuites);
}
private void setEnabledProtocols(String... protocols) {
socket.setEnabledProtocols(protocols);
}
@SuppressWarnings(value = { "unchecked", "rawtypes" })
private void setServerName(String hostname) {
List serverNames = new ArrayList();
serverNames.add(createSNIHostName(hostname));
SSLParameters params = socket.getSSLParameters();
params.setServerNames(serverNames);
socket.setSSLParameters(params);
}
// Create SNIHostName via reflection due to pre-8 JDK builds don't support
// SNI. Those JDK builds cannot find classes SNIServerName and SNIHostName.
private Object createSNIHostName(String hostname) {
try {
Class<?> clazz = Class.forName("javax.net.ssl.SNIHostName");
return clazz.getConstructor(String.class).newInstance(hostname);
} catch (Exception e) {
throw new RuntimeException("Creates SNIHostName failed!", e);
}
}
private void setApplicationProtocols(String... protocols) {
SSLParameters params = socket.getSSLParameters();
params.setApplicationProtocols(protocols);
socket.setSSLParameters(params);
}
private String getNegotiatedApplicationProtocol() {
return socket.getApplicationProtocol();
}
private void oneTimeConnect(String host, int port) throws IOException {
socket.connect(new InetSocketAddress(host, port));
OutputStream out = socket.getOutputStream();
out.write('C');
out.flush();
InputStream in = socket.getInputStream();
in.read();
}
public void close() throws IOException {
socket.close();
}
public static void main(String[] args) throws IOException {
System.out.println("----- Client start -----");
int port = Integer.valueOf(System.getProperty(Utils.PROP_PORT));
String protocol = System.getProperty(Utils.PROP_PROTOCOL);
String cipherSuite = System.getProperty(Utils.PROP_CIPHER_SUITE);
String serverName = System.getProperty(Utils.PROP_SERVER_NAME);
String appProtocols = System.getProperty(Utils.PROP_APP_PROTOCOLS);
boolean supportsSNIOnServer
= Utils.getBoolProperty(Utils.PROP_SUPPORTS_SNI_ON_SERVER);
boolean supportsSNIOnClient
= Utils.getBoolProperty(Utils.PROP_SUPPORTS_SNI_ON_CLIENT);
boolean supportsALPNOnServer
= Utils.getBoolProperty(Utils.PROP_SUPPORTS_ALPN_ON_SERVER);
boolean supportsALPNOnClient
= Utils.getBoolProperty(Utils.PROP_SUPPORTS_ALPN_ON_CLIENT);
boolean negativeCase
= Utils.getBoolProperty(Utils.PROP_NEGATIVE_CASE_ON_CLIENT);
System.out.println(Utils.join(Utils.PARAM_DELIMITER,
"ClientJDK=" + System.getProperty(Utils.PROP_CLIENT_JDK),
"Protocol=" + protocol,
"CipherSuite=" + cipherSuite,
"ServerName=" + serverName,
"AppProtocols=" + appProtocols));
Status status = Status.SUCCESS;
Client client = null;
try {
client = new Client(Cert.getCerts(cipherSuite));
client.setEnabledProtocols(protocol);
client.setEnabledCipherSuites(cipherSuite);
if (serverName != null) {
if (supportsSNIOnClient) {
client.setServerName(serverName);
} else {
System.out.println(
"Ignored due to client doesn't support SNI.");
}
}
if (appProtocols != null) {
if (supportsALPNOnClient) {
client.setApplicationProtocols(
Utils.split(appProtocols, Utils.VALUE_DELIMITER));
} else {
System.out.println(
"Ignored due to client doesn't support ALPN.");
}
}
client.oneTimeConnect("localhost", port);
if (serverName != null && supportsSNIOnServer
&& supportsSNIOnClient) {
X509Certificate cert
= (X509Certificate) client.getSession().getPeerCertificates()[0];
String subject
= cert.getSubjectX500Principal().getName();
if (!subject.contains(serverName)) {
System.out.println("Unexpected server: " + subject);
status = Status.FAIL;
}
}
if (appProtocols != null && supportsALPNOnServer
&& supportsALPNOnClient) {
String negoAppProtocol
= client.getNegotiatedApplicationProtocol();
String expectedNegoAppProtocol
= System.getProperty(Utils.PROP_NEGO_APP_PROTOCOL);
if (!expectedNegoAppProtocol.equals(negoAppProtocol)) {
System.out.println("Unexpected negotiated app protocol: "
+ negoAppProtocol);
status = Status.FAIL;
}
}
if (status != Status.FAIL) {
status = negativeCase
? Status.UNEXPECTED_SUCCESS
: Status.SUCCESS;
}
} catch (Exception exception) {
status = Utils.handleException(exception, negativeCase);
} finally {
if (client != null) {
client.close();
}
}
System.out.println("STATUS: " + status);
System.out.println("----- Client end -----");
}
}

View File

@ -0,0 +1,338 @@
/*
* 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.
*/
/*
* @test
* @summary This test is used to check the interop compatibility on JSSE among
* different JDK releases.
* Note that, this is a manual test. For more details about the test and
* its usages, please look through README.
*
* @library /test/lib
* @compile -source 1.6 -target 1.6 JdkUtils.java Parameter.java Server.java Client.java
* @run main/manual Compatibility
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import jdk.test.lib.process.OutputAnalyzer;
public class Compatibility {
public static void main(String[] args) throws Throwable {
String javaSecurityFile
= System.getProperty("test.src") + "/java.security";
boolean debug = Utils.getBoolProperty("debug");
Set<JdkInfo> jdkInfos = jdkInfoList();
System.out.println("Test start");
List<TestCase> testCases = new ArrayList<>();
ExecutorService executor = Executors.newCachedThreadPool();
PrintStream origStdOut = System.out;
PrintStream origStdErr = System.err;
try (PrintStream printStream = new PrintStream(
new FileOutputStream(Utils.TEST_LOG, true))) {
System.setOut(printStream);
System.setErr(printStream);
System.out.println(Utils.startHtml());
System.out.println(Utils.startPre());
for (UseCase useCase : UseCase.getAllUseCases()) {
for (JdkInfo serverJdk : jdkInfos) {
if (useCase.ignoredByJdk(serverJdk)) {
continue;
}
Map<String, String> props = new LinkedHashMap<>();
if (debug) {
props.put("javax.net.debug", "ssl");
}
props.put("java.security.properties", javaSecurityFile);
props.put(Utils.PROP_PROTOCOL, useCase.protocol.version);
props.put(Utils.PROP_CIPHER_SUITE, useCase.cipherSuite.name());
props.put(Utils.PROP_CLIENT_AUTH, useCase.clientAuth.name());
if (useCase.appProtocol != AppProtocol.NONE) {
props.put(Utils.PROP_APP_PROTOCOLS,
Utils.join(Utils.VALUE_DELIMITER,
useCase.appProtocol.appProtocols));
props.put(Utils.PROP_NEGO_APP_PROTOCOL,
useCase.appProtocol.negoAppProtocol);
}
props.put(Utils.PROP_SERVER_JDK, serverJdk.version);
props.put(Utils.PROP_SUPPORTS_SNI_ON_SERVER,
serverJdk.supportsSNI + "");
props.put(Utils.PROP_SUPPORTS_ALPN_ON_SERVER,
serverJdk.supportsALPN + "");
for (JdkInfo clientJdk : jdkInfos) {
if (useCase.ignoredByJdk(clientJdk)) {
continue;
}
TestCase testCase = new TestCase(serverJdk, clientJdk,
useCase);
System.out.println(Utils.anchorName(testCase.toString(),
"----- Case start -----"));
System.out.println(testCase.toString());
props.put(Utils.PROP_NEGATIVE_CASE_ON_SERVER,
testCase.negativeCaseOnServer + "");
props.put(Utils.PROP_NEGATIVE_CASE_ON_CLIENT,
testCase.negativeCaseOnClient + "");
Future<OutputAnalyzer> serverFuture = executor.submit(() -> {
return runServer(serverJdk.jdkPath, props);
});
int port = waitForServerStarted();
System.out.println("port=" + port);
props.put(Utils.PROP_PORT, port + "");
props.put(Utils.PROP_CLIENT_JDK, clientJdk.version);
props.put(Utils.PROP_SUPPORTS_SNI_ON_CLIENT,
clientJdk.supportsSNI + "");
props.put(Utils.PROP_SUPPORTS_ALPN_ON_CLIENT,
clientJdk.supportsALPN + "");
if (useCase.serverName != ServerName.NONE) {
props.put(Utils.PROP_SERVER_NAME,
useCase.serverName.name);
}
Status clientStatus = null;
if (port != -1) {
String clientOutput = runClient(clientJdk.jdkPath,
props).getOutput();
clientStatus = getStatus(clientOutput);
}
String serverOutput = serverFuture.get().getOutput();
Status serverStatus = getStatus(serverOutput);
testCase.setStatus(caseStatus(serverStatus, clientStatus));
testCases.add(testCase);
System.out.printf(
"ServerStatus=%s, ClientStatus=%s, CaseStatus=%s%n",
serverStatus, clientStatus, testCase.getStatus());
// Confirm the server has stopped.
if(new File(Utils.PORT_LOG).exists()) {
throw new RuntimeException("Server doesn't stop.");
}
System.out.println("----- Case end -----");
}
}
}
System.out.println(Utils.endPre());
System.out.println(Utils.endHtml());
}
System.setOut(origStdOut);
System.setErr(origStdErr);
executor.shutdown();
System.out.println("Test end");
System.out.println("Report is being generated...");
boolean failed = generateReport(testCases);
System.out.println("Report is generated.");
if (failed) {
throw new RuntimeException("At least one case failed. "
+ "Please check logs for more details.");
}
}
private static Status getStatus(String log) {
if (log.contains(Status.UNEXPECTED_SUCCESS.name())) {
return Status.UNEXPECTED_SUCCESS;
} else if (log.contains(Status.SUCCESS.name())) {
return Status.SUCCESS;
} else if (log.contains(Status.EXPECTED_FAIL.name())) {
return Status.EXPECTED_FAIL;
} else if (log.contains(Status.TIMEOUT.name())) {
return Status.TIMEOUT;
} else {
return Status.FAIL;
}
}
private static Status caseStatus(Status serverStatus, Status clientStatus) {
if (clientStatus == null || clientStatus == Status.TIMEOUT) {
return serverStatus == Status.EXPECTED_FAIL
? Status.EXPECTED_FAIL
: Status.FAIL;
} else if (serverStatus == Status.TIMEOUT) {
return clientStatus == Status.EXPECTED_FAIL
? Status.EXPECTED_FAIL
: Status.FAIL;
} else {
return serverStatus == clientStatus
? serverStatus
: Status.FAIL;
}
}
// Retrieves JDK info from the file which is specified by jdkListFile.
// If no such file or no JDK is specified by the file, the current testing
// JDK will be used.
private static Set<JdkInfo> jdkInfoList() throws Throwable {
List<String> jdkList = jdkList("jdkListFile");
if (jdkList.size() == 0) {
jdkList.add(System.getProperty("test.jdk"));
}
Set<JdkInfo> jdkInfoList = new LinkedHashSet<>();
for (String jdkPath : jdkList) {
JdkInfo jdkInfo = new JdkInfo(jdkPath);
// JDK version must be unique.
if (!jdkInfoList.add(jdkInfo)) {
System.out.println("The JDK version is duplicate: " + jdkPath);
}
}
return jdkInfoList;
}
private static List<String> jdkList(String listFileProp) throws IOException {
String listFile = System.getProperty(listFileProp);
System.out.println(listFileProp + "=" + listFile);
if (listFile != null && new File(listFile).exists()) {
return Files.lines(Paths.get(listFile))
.filter(line -> { return !line.trim().isEmpty(); })
.collect(Collectors.toList());
} else {
return new ArrayList<>();
}
}
// Checks if server is already launched, and returns server port.
private static int waitForServerStarted()
throws IOException, InterruptedException {
System.out.print("Waiting for server");
long deadline = System.currentTimeMillis() + Utils.TIMEOUT;
int port;
while ((port = getServerPort()) == -1
&& System.currentTimeMillis() < deadline) {
System.out.print(".");
TimeUnit.SECONDS.sleep(1);
}
System.out.println();
return port;
}
// Retrieves the latest server port from port.log.
private static int getServerPort() throws IOException {
if (!new File(Utils.PORT_LOG).exists()) {
return -1;
}
return Integer.valueOf(
Files.lines(Paths.get(Utils.PORT_LOG)).findFirst().get());
}
private static OutputAnalyzer runServer(String jdkPath,
Map<String, String> props) {
return ProcessUtils.java(jdkPath, props, Server.class);
}
private static OutputAnalyzer runClient(String jdkPath,
Map<String, String> props) {
return ProcessUtils.java(jdkPath, props, Client.class);
}
// Generates the test result report.
private static boolean generateReport(List<TestCase> testCases)
throws IOException {
boolean failed = false;
StringBuilder report = new StringBuilder();
report.append(Utils.startHtml());
report.append(Utils.tableStyle());
report.append(Utils.startTable());
report.append(Utils.row(
"No.",
"ServerJDK",
"ClientJDK",
"Protocol",
"CipherSuite",
"ClientAuth",
"SNI",
"ALPN",
"Status"));
for (int i = 0, size = testCases.size(); i < size; i++) {
TestCase testCase = testCases.get(i);
report.append(Utils.row(
Utils.anchorLink(
Utils.TEST_LOG,
testCase.toString(),
i + ""),
testCase.serverJdk.version,
testCase.clientJdk.version,
testCase.useCase.protocol.version,
testCase.useCase.cipherSuite,
Utils.boolToStr(
testCase.useCase.clientAuth == ClientAuth.TRUE),
Utils.boolToStr(
testCase.useCase.serverName == ServerName.EXAMPLE),
Utils.boolToStr(
testCase.useCase.appProtocol == AppProtocol.EXAMPLE),
testCase.getStatus()));
failed = failed
|| testCase.getStatus() == Status.FAIL
|| testCase.getStatus() == Status.UNEXPECTED_SUCCESS;
}
report.append(Utils.endTable());
report.append(Utils.endHtml());
generateFile("report.html", report.toString());
return failed;
}
private static void generateFile(String path, String content)
throws IOException {
try(FileWriter writer = new FileWriter(new File(path))) {
writer.write(content);
}
}
}

View File

@ -0,0 +1,92 @@
/*
* 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.
*/
/*
* It represents a JDK with some specific attributes.
* If two JdkInfo instances have the same version value, the instances are
* regarded as equivalent.
*/
public class JdkInfo {
public final String jdkPath;
public final String version;
public final boolean supportsECKey;
public final boolean supportsSNI;
public final boolean supportsALPN;
public JdkInfo(String jdkPath) throws Throwable {
this.jdkPath = jdkPath;
String output = jdkAttributes(jdkPath);
if (output == null || output.trim().isEmpty()) {
throw new RuntimeException(
"Cannot determine the JDK attributes: " + jdkPath);
}
String[] attributes = Utils.split(output, Utils.PARAM_DELIMITER);
version = attributes[0].replaceAll(".*=", "");
supportsECKey = Boolean.valueOf(attributes[1].replaceAll(".*=", ""));
supportsSNI = Boolean.valueOf(attributes[2].replaceAll(".*=", ""));
supportsALPN = Boolean.valueOf(attributes[3].replaceAll(".*=", ""));
}
// Determines the specific attributes for the specified JDK.
private static String jdkAttributes(String jdkPath) throws Throwable {
return ProcessUtils.java(jdkPath, null, JdkUtils.class).getOutput();
}
@Override
public int hashCode() {
return version == null ? 0 : version.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
JdkInfo other = (JdkInfo) obj;
if (version == null) {
if (other.version != null) {
return false;
}
} else if (!version.equals(other.version)) {
return false;
}
return true;
}
public boolean supportsCipherSuite(CipherSuite cipherSuite) {
JdkRelease jdkRelease = JdkRelease.getRelease(version);
return cipherSuite.startJdk.sequence <= jdkRelease.sequence
&& (cipherSuite.endJdk == null
|| cipherSuite.endJdk.sequence >= jdkRelease.sequence);
}
}

View File

@ -0,0 +1,58 @@
/*
* 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.
*/
/*
* JDK major versions.
*/
public enum JdkRelease {
JDK6(6, "1.6"),
JDK7(7, "1.7"),
JDK8(8, "1.8"),
JDK9(9, "9"),
JDK10(10, "10");
public final int sequence;
public final String release;
private JdkRelease(int sequence, String release) {
this.sequence = sequence;
this.release = release;
}
public static JdkRelease getRelease(String jdkVersion) {
if (jdkVersion.startsWith(JDK6.release)) {
return JDK6;
} else if (jdkVersion.startsWith(JDK7.release)) {
return JDK7;
} else if (jdkVersion.startsWith(JDK8.release)) {
return JDK8;
} else if (jdkVersion.startsWith(JDK9.release)) {
return JDK9;
} else if (jdkVersion.startsWith(JDK10.release)) {
return JDK10;
}
return null;
}
}

View File

@ -0,0 +1,88 @@
/*
* 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.KeyFactory;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.SSLParameters;
/*
* This class is used for returning some specific JDK information.
*/
public class JdkUtils {
public static final String JAVA_RUNTIME_VERSION = "javaRuntimeVersion";
public static final String SUPPORTS_EC_KEY = "supportsECKey";
public static final String SUPPORTS_SNI = "supportsSNI";
public static final String SUPPORTS_ALPN = "supportsALPN";
// Returns the JDK build version.
public static String javaRuntimeVersion() {
return System.getProperty("java.runtime.version");
}
// Checks if EC key algorithm is supported by the JDK build.
private static boolean supportsECKey() {
boolean isSupported = true;
try {
KeyFactory.getInstance("EC");
} catch (NoSuchAlgorithmException e) {
isSupported = false;
}
return isSupported;
}
// Checks if SNI is supported by the JDK build.
private static boolean supportsSNI() {
boolean isSupported = true;
try {
SSLParameters.class.getMethod("getServerNames");
} catch (NoSuchMethodException e) {
isSupported = false;
}
return isSupported;
}
// Checks if ALPN is supported by the JDK build.
private static boolean supportsALPN() {
boolean isSupported = true;
try {
SSLParameters.class.getMethod("getApplicationProtocols");
} catch (NoSuchMethodException e) {
isSupported = false;
}
return isSupported;
}
public static void main(String[] args) {
System.out.print(Utils.join(Utils.PARAM_DELIMITER,
attr(JAVA_RUNTIME_VERSION, javaRuntimeVersion()),
attr(SUPPORTS_EC_KEY, supportsECKey()),
attr(SUPPORTS_SNI, supportsSNI()),
attr(SUPPORTS_ALPN, supportsALPN())));
}
private static String attr(String name, Object value) {
return name + "=" + String.valueOf(value);
}
}

View File

@ -0,0 +1,252 @@
/*
* 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 tagging interface that all TLS communication parameters must implement.
*/
public interface Parameter { }
/* The followings are TLS communication parameters. */
enum Protocol implements Parameter {
SSLV3_0(3, "SSLv3"),
TLSV1_0(4, "TLSv1"),
TLSV1_1(5, "TLSv1.1"),
TLSV1_2(6, "TLSv1.2");
public final int sequence;
public final String version;
private Protocol(int sequence, String version) {
this.sequence = sequence;
this.version = version;
}
static Protocol getProtocol(String version) {
for (Protocol protocol : values()) {
if (protocol.version.equals(version)) {
return protocol;
}
}
return null;
}
static Protocol[] getMandatoryValues() {
return new Protocol[] { TLSV1_0, TLSV1_1, TLSV1_2 };
}
}
enum CipherSuite implements Parameter {
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_RSA_WITH_AES_256_CBC_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA(),
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(),
TLS_RSA_WITH_AES_256_CBC_SHA(),
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA(),
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA(),
TLS_DHE_RSA_WITH_AES_256_CBC_SHA(),
TLS_DHE_DSS_WITH_AES_256_CBC_SHA(),
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_RSA_WITH_AES_128_CBC_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK7),
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA(),
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(),
TLS_RSA_WITH_AES_128_CBC_SHA(),
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA(),
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA(
Protocol.SSLV3_0, JdkRelease.JDK7),
TLS_DHE_RSA_WITH_AES_128_CBC_SHA(),
TLS_DHE_DSS_WITH_AES_128_CBC_SHA(),
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_RSA_WITH_AES_256_GCM_SHA384(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_RSA_WITH_AES_128_GCM_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(
Protocol.TLSV1_2, JdkRelease.JDK8),
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA(),
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA(),
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA(),
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA(),
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA(),
TLS_ECDHE_RSA_WITH_RC4_128_SHA(),
TLS_ECDH_ECDSA_WITH_RC4_128_SHA(),
TLS_ECDH_RSA_WITH_RC4_128_SHA(),
SSL_RSA_WITH_RC4_128_SHA(),
SSL_RSA_WITH_3DES_EDE_CBC_SHA(),
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA(
Protocol.SSLV3_0, JdkRelease.JDK6),
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA(
Protocol.SSLV3_0, JdkRelease.JDK6),
SSL_RSA_WITH_RC4_128_MD5(
Protocol.SSLV3_0, JdkRelease.JDK6);
private static final boolean FULL_CIPHER_SUITES
= Utils.getBoolProperty("fullCipherSuites");
final Protocol startProtocol;
final Protocol endProtocol;
final JdkRelease startJdk;
final JdkRelease endJdk;
private CipherSuite(
Protocol startProtocol, Protocol endProtocol,
JdkRelease startJdk, JdkRelease endJdk) {
this.startProtocol = startProtocol;
this.endProtocol = endProtocol;
this.startJdk = startJdk;
this.endJdk = endJdk;
}
private CipherSuite(Protocol startProtocol, JdkRelease startJdk) {
this(startProtocol, null, startJdk, null);
}
private CipherSuite() {
this(Protocol.TLSV1_0, null, JdkRelease.JDK6, null);
}
boolean supportedByProtocol(Protocol protocol) {
return startProtocol.sequence <= protocol.sequence
&& (endProtocol == null || endProtocol.sequence >= protocol.sequence);
}
static CipherSuite[] getMandatoryValues() {
return FULL_CIPHER_SUITES
? values()
: new CipherSuite[] {
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 };
}
static CipherSuite getCipherSuite(String name) {
for (CipherSuite cipherSuite : values()) {
if (cipherSuite.name().equals(name)) {
return cipherSuite;
}
}
return null;
}
}
enum ClientAuth implements Parameter {
FALSE,
TRUE;
static ClientAuth[] getMandatoryValues() {
return new ClientAuth[] { TRUE };
}
}
enum ServerName implements Parameter {
NONE(null),
EXAMPLE("www.example.com");
final String name;
private ServerName(String name) {
this.name = name;
}
static ServerName[] getMandatoryValues() {
return new ServerName[] { EXAMPLE };
}
}
enum AppProtocol implements Parameter {
NONE(null, null),
EXAMPLE(new String[] { Utils.HTTP_2, Utils.HTTP_1_1 }, Utils.HTTP_2);
final String[] appProtocols;
// Expected negotiated application protocol
final String negoAppProtocol;
private AppProtocol(String[] appProtocols, String negoAppProtocol) {
this.appProtocols = appProtocols;
this.negoAppProtocol = negoAppProtocol;
}
static AppProtocol[] getMandatoryValues() {
return new AppProtocol[] { EXAMPLE };
}
}

View File

@ -0,0 +1,59 @@
/*
* 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.util.ArrayList;
import java.util.List;
import java.util.Map;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
/*
* Utilities for executing java process.
*/
public class ProcessUtils {
private static final String TEST_CLASSES = System.getProperty("test.classes");
public static OutputAnalyzer java(String jdkPath, Map<String, String> props,
Class<?> clazz) {
List<String> cmds = new ArrayList<>();
cmds.add(jdkPath + "/bin/java");
if (props != null) {
for (Map.Entry<String, String> prop : props.entrySet()) {
cmds.add("-D" + prop.getKey() + "=" + prop.getValue());
}
}
cmds.add("-cp");
cmds.add(TEST_CLASSES);
cmds.add(clazz.getName());
try {
return ProcessTools.executeCommand(
cmds.toArray(new String[cmds.size()]));
} catch (Throwable e) {
throw new RuntimeException("Execute command failed: " + cmds, e);
}
}
}

View File

@ -0,0 +1,130 @@
# 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 check the interop compatibility on JSSE among different
JDK releases. The oldest version supported by the test is JDK 6. Some of Java
source files, JdkUtils.java, Parameter.java, Server.java, and Client.java, use
only JDK 6-compliant language features and APIs, in order to allowing different
JDK releases can load and run associated classes.
##### Output #####
The test can generate a report at $JTREG_WORKDIR/scratch/report.html to display
the key information for each case. It also outputs all of details on both of
server and client sides to a separated file at $JTREG_WORKDIR/scratch/test.html.
##### Report Columns #####
No.
A sequence number. It contains a hyper link to the corresponding details
in $JTREG_WORKDIR/scratch/test.html.
ServerJDK
The version of the JDK that acts as server.
ClientJDK
The version of the JDK that acts as client.
Protocol
The TLS protocol version.
CipherSuite
The only enabled cipher suite on both of server and client.
ClientAuth
If the client authentication is checked, the value is "Y"; otherwise, "N".
SNI
If the SNI is checked, the value is "Y"; otherwise, "N".
ALPN
If the ALPN is checked, the value is "Y"; otherwise, "N".
Status
It indicates the communication status for a test case.
There are three status:
SUCCESS: Communication succeed as expected.
UNEXPECTED_SUCCESS: Communication succeed as unexpected.
FAIL: Communication fails with unexpected failure.
EXPECTED_FAIL: Communication fails with expected failure.
Please note that, if a case finishes as status UNEXPECTED_SUCCESS or FAIL,
that means the case fails. Any failed case results in the test goes to fail.
##### Usage #####
jtreg [-options] \
[-Ddebug=<true|false>] \
[-DfullCases=<true|false>] \
[-DfullCipherSuites=<true|false>] \
[-DjdkListFile=</path/to/jdkListFile>] \
$JDK_WORKSPACE/test/jdk/javax/net/ssl/compatibility/Compatibility.java
Besides the common jtreg options, like -jdk, this test introduces some more
properties:
debug
It indicates if the test enable -Djavax.net.ssl=debug. This is a boolean
property, and the default value is false.
It is not mandatory.
fullCases
It indicates if testing the full or mandatory set of parameter values.
Every parameter provides a mandatory value set that must be covered.
For more details about the parameter value sets, please see Parameter.java.
This is a boolean property, and the default value is false.
It is not mandatory.
fullCipherSuites
It indicates if testing the full or mandatory set of cipher suites.
For more details about the specific cipher suite sets, see CipherSuite in
Parameter.java.
This is a boolean property, and the default value is false.
It is not mandatory.
jdkListFile
It indicate the path of a file, which lists the absolute paths of different
JDK builds. If no this property, the current testing JDK, specified by JTREG
option -jdk, is used as the testing JDK.
It is not mandatory.
##### Usage Examples #####
Example 1
$ jtreg -jdk:/path/to/latest/jdk \
$JDK_WS/jdk/test/javax/net/ssl/compatibility/Compatibility.java
This example doesn't specify any property introduced by the test. That means
it uses the current testing JDK, namely /path/to/latest/jdk, as server and
client. It doesn't output any debug log, and tests only mandatory parameter
value sets.
Example 2
$ cat /path/to/jdkList
/path/to/jdk6
/path/to/jdk7
/path/to/jdk8
/path/to/jdk9
/path/to/jdk10
$ jtreg -jdk:/path/to/latest/jdk \
-Ddebug=true \
-DfullCipherSuites=true \
-DjdkListFile=/path/to/jdkList \
$JDK_WS/jdk/test/javax/net/ssl/compatibility/Compatibility.java
The above example uses a file "/path/to/jdkList" to contain the paths of local
different JDK builds through 6 to 10. The execution uses each of JDK builds as
server and client respectively. And it enables SSL debug flag, and tests the
full parameter value set.

View File

@ -0,0 +1,171 @@
/*
* 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.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
/*
* A simple SSL socket server.
*/
public class Server {
private final SSLServerSocket serverSocket;
public Server(SSLContext context, int port) throws Exception {
SSLServerSocketFactory serverFactory = context.getServerSocketFactory();
serverSocket = (SSLServerSocket) serverFactory.createServerSocket(port);
serverSocket.setSoTimeout(Utils.TIMEOUT);
}
public Server(Cert[] certs, int port) throws Exception {
this(Utils.createSSLContext(certs), port);
}
public Server(Cert[] certs) throws Exception {
this(certs, 0);
}
private void setEnabledCipherSuites(String... cipherSuites) {
serverSocket.setEnabledCipherSuites(cipherSuites);
}
private void setEnabledProtocols(String... protocols) {
serverSocket.setEnabledProtocols(protocols);
}
private void setNeedClientAuth(boolean needClientAuth) {
serverSocket.setNeedClientAuth(needClientAuth);
}
private void setApplicationProtocols(String... protocols) {
SSLParameters params = serverSocket.getSSLParameters();
params.setApplicationProtocols(protocols);
serverSocket.setSSLParameters(params);
}
public int getPort() {
return serverSocket.getLocalPort();
}
private void accept() throws IOException {
SSLSocket socket = null;
try {
socket = (SSLSocket) serverSocket.accept();
InputStream in = socket.getInputStream();
in.read();
OutputStream out = socket.getOutputStream();
out.write('S');
out.flush();
} finally {
if (socket != null) {
socket.close();
}
}
}
public void close() throws IOException {
serverSocket.close();
}
public static void main(String[] args) throws IOException {
System.out.println("----- Server start -----");
String protocol = System.getProperty(Utils.PROP_PROTOCOL);
String cipherSuite = System.getProperty(Utils.PROP_CIPHER_SUITE);
boolean clientAuth
= Utils.getBoolProperty(Utils.PROP_CLIENT_AUTH);
String appProtocols = System.getProperty(Utils.PROP_APP_PROTOCOLS);
boolean supportsALPN
= Utils.getBoolProperty(Utils.PROP_SUPPORTS_ALPN_ON_SERVER);
boolean negativeCase
= Utils.getBoolProperty(Utils.PROP_NEGATIVE_CASE_ON_SERVER);
System.out.println(Utils.join(Utils.PARAM_DELIMITER,
"ServerJDK=" + System.getProperty(Utils.PROP_SERVER_JDK),
"Protocol=" + protocol,
"CipherSuite=" + cipherSuite,
"ClientAuth=" + clientAuth,
"AppProtocols=" + appProtocols));
Status status = Status.SUCCESS;
Server server = null;
try {
server = new Server(Cert.getCerts(cipherSuite));
System.out.println("port=" + server.getPort());
server.setNeedClientAuth(clientAuth);
server.setEnabledProtocols(protocol);
server.setEnabledCipherSuites(cipherSuite);
if (appProtocols != null) {
if (supportsALPN) {
server.setApplicationProtocols(
Utils.split(appProtocols, Utils.VALUE_DELIMITER));
} else {
System.out.println(
"Ignored due to server doesn't support ALPN.");
}
}
savePort(server.getPort());
server.accept();
status = negativeCase ? Status.UNEXPECTED_SUCCESS : Status.SUCCESS;
} catch (Exception exception) {
status = Utils.handleException(exception, negativeCase);
} finally {
if (server != null) {
server.close();
}
// Cleanups port.log.
File file = new File(Utils.PORT_LOG);
if (file.exists()) {
file.delete();
}
}
System.out.println("STATUS: " + status);
System.out.println("----- Server end -----");
}
private static void savePort(int port) throws IOException {
FileWriter writer = null;
try {
writer = new FileWriter(new File(Utils.PORT_LOG));
writer.write(port + "");
} finally {
if (writer != null) {
writer.close();
}
}
}
}

View File

@ -0,0 +1,30 @@
/*
* 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.
*/
/*
* Test case result status.
*/
public enum Status {
SUCCESS, UNEXPECTED_SUCCESS, FAIL, EXPECTED_FAIL, TIMEOUT;
}

View File

@ -0,0 +1,64 @@
/*
* 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 test case for a specific TLS communication use case between two JDKs.
*/
public class TestCase {
public final JdkInfo serverJdk;
public final JdkInfo clientJdk;
public final UseCase useCase;
public final boolean negativeCaseOnServer;
public final boolean negativeCaseOnClient;
private Status status;
public TestCase(JdkInfo serverJdk, JdkInfo clientJdk, UseCase useCase) {
this.serverJdk = serverJdk;
this.clientJdk = clientJdk;
this.useCase = useCase;
negativeCaseOnServer = useCase.negativeCase
|| !serverJdk.supportsCipherSuite(useCase.cipherSuite);
negativeCaseOnClient = useCase.negativeCase
|| !clientJdk.supportsCipherSuite(useCase.cipherSuite);
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
@Override
public String toString() {
return Utils.join(Utils.PARAM_DELIMITER,
"ServerJDK=" + serverJdk.version,
"ClientJDK=" + clientJdk.version,
useCase.toString());
}
}

View File

@ -0,0 +1,107 @@
/*
* 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.util.ArrayList;
import java.util.List;
/*
* The TLS communication use case.
*/
public class UseCase {
private static final boolean FULL_CASES
= Utils.getBoolProperty("fullCases");
private static final Parameter[][] PARAMS = new Parameter[][] {
FULL_CASES ? Protocol.values() : Protocol.getMandatoryValues(),
FULL_CASES ? CipherSuite.values() : CipherSuite.getMandatoryValues(),
FULL_CASES ? ClientAuth.values() : ClientAuth.getMandatoryValues(),
FULL_CASES ? ServerName.values() : ServerName.getMandatoryValues(),
FULL_CASES ? AppProtocol.values() : AppProtocol.getMandatoryValues() };
public final Protocol protocol;
public final CipherSuite cipherSuite;
public final ClientAuth clientAuth;
public final ServerName serverName;
public final AppProtocol appProtocol;
public final boolean negativeCase;
public UseCase(
Protocol protocol,
CipherSuite cipherSuite,
ClientAuth clientAuth,
ServerName serverName,
AppProtocol appProtocol) {
this.protocol = protocol;
this.cipherSuite = cipherSuite;
this.clientAuth = clientAuth;
this.serverName = serverName;
this.appProtocol = appProtocol;
negativeCase = !cipherSuite.supportedByProtocol(protocol);
}
// JDK 6 doesn't support EC key algorithm.
public boolean ignoredByJdk(JdkInfo jdkInfo) {
return cipherSuite.name().contains("_EC") && !jdkInfo.supportsECKey;
}
@Override
public String toString() {
return Utils.join(Utils.PARAM_DELIMITER,
"Protocol=" + protocol.version,
"CipherSuite=" + cipherSuite,
"ClientAuth=" + clientAuth,
"ServerName=" + serverName,
"AppProtocols=" + appProtocol);
}
public static List<UseCase> getAllUseCases() {
List<UseCase> useCases = new ArrayList<>();
getUseCases(PARAMS, 0, new Parameter[PARAMS.length], useCases);
return useCases;
}
private static void getUseCases(Parameter[][] params, int index,
Parameter[] currentValues, List<UseCase> useCases) {
if (index == params.length) {
Protocol protocol = (Protocol) currentValues[0];
CipherSuite cipherSuite = (CipherSuite) currentValues[1];
UseCase useCase = new UseCase(
protocol,
cipherSuite,
(ClientAuth) currentValues[2],
(ServerName) currentValues[3],
(AppProtocol) currentValues[4]);
useCases.add(useCase);
} else {
Parameter[] values = params[index];
for (int i = 0; i < values.length; i++) {
currentValues[index] = values[i];
getUseCases(params, index + 1, currentValues, useCases);
}
}
}
}

View File

@ -0,0 +1,282 @@
/*
* 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.ByteArrayInputStream;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManagerFactory;
/*
* Utilities for testing.
*/
public class Utils {
/* ***** Properties ***** */
public static final String PROP_PORT = "test.port";
public static final String PROP_PROTOCOL = "test.protocol";
public static final String PROP_CIPHER_SUITE = "test.cipher.suite";
public static final String PROP_CLIENT_AUTH = "test.client.auth";
public static final String PROP_SERVER_JDK = "test.server.jdk";
public static final String PROP_CLIENT_JDK = "test.client.jdk";
public static final String PROP_SERVER_NAME = "test.server.name";
public static final String PROP_APP_PROTOCOLS
= "test.app.protocols";
public static final String PROP_NEGO_APP_PROTOCOL
= "test.negotiated.app.protocol";
public static final String PROP_SUPPORTS_SNI_ON_SERVER
= "test.supports.sni.on.server";
public static final String PROP_SUPPORTS_SNI_ON_CLIENT
= "test.supports.sni.on.client";
public static final String PROP_SUPPORTS_ALPN_ON_SERVER
= "test.supports.alpn.on.server";
public static final String PROP_SUPPORTS_ALPN_ON_CLIENT
= "test.supports.alpn.on.client";
public static final String PROP_NEGATIVE_CASE_ON_SERVER
= "test.negative.case.on.server";
public static final String PROP_NEGATIVE_CASE_ON_CLIENT
= "test.negative.case.on.client";
public static final int TIMEOUT = 10000;
public static final char[] PASSWORD = "testpass".toCharArray();
public static final String TEST_LOG = "test.html";
public static final String PORT_LOG = "port";
public static final String HTTP_2 = "h2";
public static final String HTTP_1_1 = "http/1.1";
public static final String PARAM_DELIMITER = ";";
public static final String VALUE_DELIMITER = ",";
/*
* Creates SSL context with the specified certificate.
*/
public static SSLContext createSSLContext(Cert... certs) throws Exception {
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(null, null);
for (int i = 0; i < certs.length; i++) {
trustStore.setCertificateEntry("trust-" + certs[i].name(),
createCert(certs[i]));
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(trustStore);
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
for (int i = 0; i < certs.length; i++) {
PrivateKey privKey = createKey(certs[i]);
keyStore.setKeyEntry("cert-" + certs[i].name(), privKey, PASSWORD,
new Certificate[] { createCert(certs[i]) });
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
kmf.init(keyStore, PASSWORD);
SSLContext context = SSLContext.getInstance("TLS");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return context;
}
private static Certificate createCert(Cert cert) throws IOException {
try {
CertificateFactory certFactory
= CertificateFactory.getInstance("X.509");
return certFactory.generateCertificate(
new ByteArrayInputStream(cert.certMaterials.getBytes()));
} catch (Exception e) {
throw new RuntimeException("Create key failed: " + cert, e);
}
}
private static PrivateKey createKey(Cert cert)
throws NoSuchAlgorithmException, InvalidKeySpecException {
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(
hexToBytes(cert.privKeyMaterials));
KeyFactory keyFactory = KeyFactory.getInstance(
getKeyAlgorithm(cert.signatureAlgorithm));
PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);
return privKey;
}
private static String getKeyAlgorithm(
SignatureAlgorithm signatureAlgorithm) {
String signatureAlogrithmName = signatureAlgorithm.name();
return signatureAlogrithmName.equals(SignatureAlgorithm.ECDSA.name())
? "EC"
: signatureAlogrithmName;
}
public static byte[] hexToBytes(String hex) {
if (hex == null) {
return null;
}
int length = hex.length();
if (length % 2 != 0) {
throw new IllegalArgumentException("Hex format is wrong.");
}
byte[] bytes = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
bytes[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
+ Character.digit(hex.charAt(i + 1), 16));
}
return bytes;
}
public static String join(String delimiter, String... values) {
StringBuilder result = new StringBuilder();
if (values != null && values.length > 0) {
for (int i = 0; i < values.length - 1; i++) {
result.append(values[i]).append(delimiter);
}
result.append(values[values.length - 1]);
}
return result.toString();
}
public static String[] split(String str, String delimiter) {
return str == null ? new String[0] : str.split(delimiter);
}
public static String boolToStr(boolean bool) {
return bool ? "Y" : "N";
}
public static boolean getBoolProperty(String prop) {
return Boolean.valueOf(System.getProperty(prop));
}
public static Status handleException(Exception exception,
boolean negativeCase) {
Status status;
if ((exception instanceof SSLHandshakeException
|| exception instanceof IllegalArgumentException)
&& negativeCase) {
System.out.println("Expected exception: " + exception);
status = Status.EXPECTED_FAIL;
} else if (exception instanceof SocketTimeoutException) {
status = Status.TIMEOUT;
} else {
exception.printStackTrace(System.out);
status = Status.FAIL;
}
return status;
}
/* The HTML-related constants and methods. */
private static final String STYLE
= "style=\"font-family: Courier New; "
+ "font-size: 12px; "
+ "white-space: pre-wrap\"";
private static final String TABLE_STYLE
= "#test { font-family: \"Courier New\"; font-size: 12px; border-collapse: collapse; }\n"
+ "#test td { border: 1px solid #ddd; padding: 4px; }\n"
+ "#test tr:nth-child(odd) { background-color: #f2f2f2; }";
public static String row(Object... values) {
StringBuilder row = new StringBuilder();
row.append(startTr());
for (Object 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 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>";
}
public static String tableStyle() {
return startTag("style") + TABLE_STYLE +endTag("style");
}
public static String startTable() {
return startTag("table id=\"test\"");
}
public static String endTable() {
return endTag("table");
}
private static String startTr() {
return startTag("tr");
}
private static String endTr() {
return endTag("tr");
}
private static String startTd() {
return startTag("td");
}
private static String endTd() {
return endTag("td");
}
private static String startTag(String tag) {
return "<" + tag + ">";
}
private static String endTag(String tag) {
return "</" + tag + ">";
}
}

View File

@ -0,0 +1,2 @@
jdk.certpath.disabledAlgorithms=
jdk.tls.disabledAlgorithms=

View File

@ -24,7 +24,7 @@
/*
* @test
* @bug 4494033 7028815 7052425 8007338 8023608 8008164 8016549 8072461 8154261 8162363 8160196 8151743 8177417
* 8175218 8176452 8181215 8182263 8183511 8169819 8183037
* 8175218 8176452 8181215 8182263 8183511 8169819 8183037 8185369
* @summary Run tests on doclet stylesheet.
* @author jamieh
* @library ../lib
@ -50,16 +50,6 @@ public class TestStylesheet extends JavadocTester {
// TODO: most of this test seems a bit silly, since javadoc is simply
// copying in the stylesheet from the source directory
checkOutput("stylesheet.css", true,
"/* Javadoc style sheet */",
"/*\n"
+ "Overall document style\n"
+ "*/",
"/*\n"
+ "Heading styles\n"
+ "*/",
"/*\n"
+ "Navigation bar styles\n"
+ "*/",
"body {\n"
+ " background-color:#ffffff;\n"
+ " color:#353833;\n"
@ -173,8 +163,8 @@ public class TestStylesheet extends JavadocTester {
+ " position:relative;\n"
+ " padding-top:129px;\n"
+ " margin-top:-129px;\n"
+ "}\n"
+ ".searchTagResult:before, .searchTagResult:target {\n"
+ "}",
".searchTagResult:before, .searchTagResult:target {\n"
+ " color:red;\n"
+ "}",
"a[href]:hover, a[href]:focus {\n"

View File

@ -188,7 +188,7 @@ public class ForwardReferenceImportTest extends KullaTesting {
DiagCheck.DIAG_ERROR,
added(VALID),
ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null)));
assertDeclareFail("A.list = Arrays.asList(1, 2, 3);", "compiler.err.already.defined.static.single.import");
assertDeclareFail("A.list = Arrays.asList(1, 2, 3);", "compiler.err.already.defined.single.import");
assertActiveKeys();
assertDrop(list,
ste(list, VALID, DROPPED, true, null),

View File

@ -1,14 +1,14 @@
/*
* @test /nodynamiccopyright/
* @bug 7101822
* @bug 7101822 8133616
* @summary Check the when clashing types are imported through an ordinary and static import,
* the compile-time error is properly reported.
* @compile/fail/ref=NonStatic2StaticImportClash.out -XDrawDiagnostics NonStatic2StaticImportClash.java p1/A1.java p2/A2.java
*
*/
import p1.A1.f;
import static p2.A2.f;
import static p1.A1.f;
import p2.A2.f;
public class NonStatic2StaticImportClash {
}

View File

@ -1,14 +1,14 @@
/*
* @test /nodynamiccopyright/
* @bug 7101822
* @bug 7101822 8133616
* @summary Check the when clashing types are imported through an ordinary and static import,
* the compile-time error is properly reported.
* @compile/fail/ref=Static2NonStaticImportClash.out -XDrawDiagnostics Static2NonStaticImportClash.java p1/A1.java p2/A2.java
*
*/
import static p2.A2.f;
import p1.A1.f;
import p2.A2.f;
import static p1.A1.f;
public class Static2NonStaticImportClash {
}

View File

@ -0,0 +1,17 @@
/**
* @test /nodynamiccopyright/
* @bug 8191981
* @compile/fail/ref=LambdaWithMethod.out -Werror -XDrawDiagnostics -XDfind=lambda LambdaWithMethod.java
*/
public class LambdaWithMethod {
public static void run(Runnable r) {
run(new Runnable() {
public void run() {
put(get());
}
});
}
private static String get() { return null; }
private static void put(String i) {}
}

View File

@ -0,0 +1,4 @@
LambdaWithMethod.java:9:28: compiler.warn.potential.lambda.found
- compiler.err.warnings.and.werror
1 error
1 warning

View File

@ -23,5 +23,5 @@
// key: compiler.err.already.defined.static.single.import
import p.E1.A;
import static p.E2.A;
import static p.E1.A;
import p.E2.A;

View File

@ -0,0 +1,57 @@
/*
* 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. 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.
*/
/*
* @test
* @bug 8178427
* @summary NPE in Infer$CheckUpperBounds
* @compile T8178427.java
*/
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.function.*;
import java.util.stream.*;
abstract class X {
public interface N<K, V> {
Stream<V> getValues();
}
abstract <K, V> N<K, V> c();
abstract <T, K, V, M extends N<K, V>> Collector<T, ?, M> f(
Function<? super T, ? extends K> k,
Function<? super T, ? extends Stream<? extends V>> v,
Supplier<M> multimapSupplier);
void m(Map<String, N<?, ?>> c, ExecutorService s) {
s.submit(() -> {
return c.entrySet().parallelStream()
.collect(f(Map.Entry::getKey, e -> e.getValue().getValues(), this::c));
});
}
}

View File

@ -0,0 +1,196 @@
/*
* Copyright (c) 2013, 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.
*/
/*
* @test
* @bug 8191234
* @summary Test TypeKind visitors on pseudo types.
* @library /tools/javac/lib
* @modules java.compiler
* @build JavacTestingAbstractProcessor TestTypeKindVisitors
* @compile -processor TestTypeKindVisitors -proc:only TestTypeKindVisitors.java
*/
import java.lang.annotation.Annotation;
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.*;
import static javax.lang.model.SourceVersion.*;
public class TestTypeKindVisitors extends JavacTestingAbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> tes,
RoundEnvironment round) {
if (round.processingOver())
return true;
List<NoType> tradNoTypes = List.of(types.getNoType(TypeKind.NONE),
types.getNoType(TypeKind.VOID),
getPackageNoType());
NoType moduleNoType = getModuleNoType();
// For KindVisitors based on 6, 7, and 8
for (TypeVisitor<TypeKind, String> visitor : getVisitors()) {
System.out.println(visitor.getClass().getSuperclass().getName());
for (NoType noType : tradNoTypes) {
System.out.println("\t" + noType.toString());
checkTypeKind(noType.getKind(), visitor.visit(noType));
}
if (RELEASE_9.compareTo(visitor.getClass().getSuperclass().
getAnnotation(SupportedSourceVersion.class).
value()) > 0) {
try {
System.out.println("\t" + moduleNoType.toString());
visitor.visit(moduleNoType);
} catch (UnknownTypeException ute) {
; // Expected
}
} else {
checkTypeKind(moduleNoType.getKind(), visitor.visit(moduleNoType));
}
}
return true;
}
private NoType getPackageNoType() {
TypeMirror type = elements.getPackageElement("java.lang").asType();
checkTypeKind(TypeKind.PACKAGE, type.getKind());
return (NoType) type;
}
private NoType getModuleNoType() {
TypeMirror type = elements.getModuleElement("java.base").asType();
checkTypeKind(TypeKind.MODULE, type.getKind());
return (NoType) type;
}
private void checkTypeKind(TypeKind expected, TypeKind retreived) {
if (retreived != expected)
throw new AssertionError("Unexpected type kind " + retreived);
}
List<TypeVisitor<TypeKind, String>> getVisitors() {
return List.of(new TypeKindVisitor6<>(null) {
@Override
protected TypeKind defaultAction(TypeMirror e, String p) {
throw new AssertionError("Should not reach");
}
@Override
public TypeKind visitNoTypeAsVoid(NoType t, String p) {
return t.getKind();
}
@Override
public TypeKind visitNoTypeAsNone(NoType t, String p) {
return t.getKind();
}
@Override
public TypeKind visitNoTypeAsPackage(NoType t, String p) {
return t.getKind();
}
// Leave default behavior for a NoType module
},
new TypeKindVisitor7<>(null){
@Override
protected TypeKind defaultAction(TypeMirror e, String p) {
throw new AssertionError("Should not reach");
}
@Override
public TypeKind visitNoTypeAsVoid(NoType t, String p) {
return t.getKind();
}
@Override
public TypeKind visitNoTypeAsNone(NoType t, String p) {
return t.getKind();
}
@Override
public TypeKind visitNoTypeAsPackage(NoType t, String p) {
return t.getKind();
}
// Leave default behavior for a NoType module
},
new TypeKindVisitor8<>(null){
@Override
protected TypeKind defaultAction(TypeMirror e, String p) {
throw new AssertionError("Should not reach");
}
@Override
public TypeKind visitNoTypeAsVoid(NoType t, String p) {
return t.getKind();
}
@Override
public TypeKind visitNoTypeAsNone(NoType t, String p) {
return t.getKind();
}
@Override
public TypeKind visitNoTypeAsPackage(NoType t, String p) {
return t.getKind();
}
// Leave default behavior for a NoType module
},
new TypeKindVisitor9<>(null){
@Override
protected TypeKind defaultAction(TypeMirror e, String p) {
throw new AssertionError("Should not reach");
}
@Override
public TypeKind visitNoTypeAsVoid(NoType t, String p) {
return t.getKind();
}
@Override
public TypeKind visitNoTypeAsNone(NoType t, String p) {
return t.getKind();
}
@Override
public TypeKind visitNoTypeAsPackage(NoType t, String p) {
return t.getKind();
}
@Override
public TypeKind visitNoTypeAsModule(NoType t, String p) {
return t.getKind();
}
});
}
}

View File

@ -240,17 +240,26 @@ public class MultiReleaseJar {
cmds[0] = cmdPath.resolve(cmds[0]).toString();
ProcessBuilder pb = new ProcessBuilder(cmds);
pb.directory(mrjar.toFile());
Process p = pb.start();
p.waitFor(10, TimeUnit.SECONDS);
String out;
try (InputStream is = p.getInputStream()) {
out = new String(is.readAllBytes());
Process p = null;
try {
p = pb.start();
p.waitFor();
String out;
try (InputStream is = p.getInputStream()) {
out = new String(is.readAllBytes());
}
String err;
try (InputStream is = p.getErrorStream()) {
err = new String(is.readAllBytes());
}
return new Result(cmd, p.exitValue(), out, err);
} catch (Throwable t) {
if (p != null) {
p.destroyForcibly().waitFor();
}
throw t;
}
String err;
try (InputStream is = p.getErrorStream()) {
err = new String(is.readAllBytes());
}
return new Result(cmd, p.exitValue(), out, err);
}
void checkResult(Result r) throws Exception {

View File

@ -0,0 +1,219 @@
/*
* 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.
*/
/**
* JDK-8059835: Optimistic splitting doesn't work with let and const
*
* @test
* @run
* @option --language=es6
* @option -Dnashorn.compiler.splitter.threshold=100
* @fork
*/
function f() {
let sum = 0;
const c = 13;
if (true) {
let x = 0;
const y = 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
sum += x;
sum += y;
}
outer: while (true) {
let x = 0;
const y = 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
sum += x;
sum += y;
sum += c;
let i = 0;
const k = 1;
while (true) {
x += k;
if (++i === 10) {
break outer;
}
}
x += k;
}
return sum;
}
function g() {
let sum = 0;
const c = 13;
if (true) {
let x = 0;
const y = 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
sum += x;
sum += y;
}
outer: while (true) {
let x = 0;
const y = 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
x += 1;
sum += x;
sum += y;
sum += c;
let i = 0;
const k = 1;
while (true) {
x += k;
if (++i === 10) return 'abc';
}
x += k;
}
return sum;
}
Assert.assertTrue(f() === 80);
Assert.assertTrue(g() === 'abc');