Version 1.13.0-dev.7.3
Cherry-pick f80bd4203de33faecad89983ec8d3fd35ceba4a4 to dev
Cherry-pick efc1d4b224821d4cbc64796c0348a6f019fa0649 to dev
Cherry-pick 4653701a7656136d2725b76497cf1a67a15dd4f4 to dev
Cherry-pick e562934defd630f77755d77c6f9108552977e4a0 to dev
Cherry-pick 1a1820bbe3bf3b393105a342b414730f9ba105d3 to dev
Cherry-pick 208e3f981a3e724dce8510332e1c0a576d89e3be to dev
Cherry-pick a9362610ee429a0b69653635039696f86976f564 to dev
Cherry-pick f145f89ccb4b807641914a0631e9c77995a29b20 to dev
Cherry-pick 58937b50ef2f81f441318f1dcdadf5a107b33533 to dev
Cherry-pick be1fcb944176bed2bf1294c78cd39844df67dda6 to dev
Cherry-pick cc0a9c3e7eb32588c219f7f16a1a806e88a397d3 to dev
Cherry-pick f9551da8e3f55734442be679369c00b234c19fa5 to dev
Cherry-pick 10915a849b324e3a9f3e2a37fc245709d0eda370 to dev
Cherry-pick b519e4c0001a0e84a7b45634057d0b4b51f0dd57 to dev
Cherry-pick 6bb8ce37391f0609bc26ead96f35badff9dd2840 to dev
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index d085d03..3c6eea7 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -1232,7 +1232,7 @@
null,
dartUnit,
errorInfo.errors);
- scheduleIndexOperation(this, file, context, dartUnit);
+ scheduleIndexOperation(this, file, dartUnit);
}
} else {
schedulePerformAnalysisOperation(context);
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 3e72ad5..6e9af6d 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -623,7 +623,7 @@
}
/**
- * Resursively adds all Dart and HTML files to the [changeSet].
+ * Recursively adds all Dart and HTML files to the [changeSet].
*/
void _addPreviouslyExcludedSources(ContextInfo info, ChangeSet changeSet,
Folder folder, List<String> oldExcludedPaths) {
@@ -670,7 +670,7 @@
}
/**
- * Resursively adds all Dart and HTML files to the [changeSet].
+ * Recursively adds all Dart and HTML files to the [changeSet].
*/
void _addSourceFiles(ChangeSet changeSet, Folder folder, ContextInfo info) {
if (info.excludesResource(folder) || folder.shortName.startsWith('.')) {
@@ -877,13 +877,16 @@
*/
void _createContexts(
ContextInfo parent, Folder folder, bool withPackageSpecOnly) {
+ if (folder.shortName.startsWith('.') || folder.shortName == 'packages') {
+ return;
+ }
// Decide whether a context needs to be created for [folder] here, and if
// so, create it.
File packageSpec = _findPackageSpecFile(folder);
bool createContext = packageSpec.exists || !withPackageSpecOnly;
if (withPackageSpecOnly &&
packageSpec.exists &&
- (parent != null) &&
+ parent != null &&
parent.ignored(packageSpec.path)) {
// Don't create a context if the package spec is required and ignored.
createContext = false;
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 973b831..1e430d5 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -64,9 +64,10 @@
/**
* Schedules indexing of the given [file] using the resolved [dartUnit].
*/
-void scheduleIndexOperation(AnalysisServer server, String file,
- AnalysisContext context, CompilationUnit dartUnit) {
+void scheduleIndexOperation(
+ AnalysisServer server, String file, CompilationUnit dartUnit) {
if (server.index != null) {
+ AnalysisContext context = dartUnit.element.context;
server.addOperation(new _DartIndexOperation(context, file, dartUnit));
}
}
@@ -414,7 +415,7 @@
try {
CompilationUnit dartUnit = notice.resolvedDartUnit;
if (dartUnit != null) {
- server.addOperation(new _DartIndexOperation(context, file, dartUnit));
+ scheduleIndexOperation(server, file, dartUnit);
}
} catch (exception, stackTrace) {
server.sendServerErrorNotification(exception, stackTrace);
@@ -459,6 +460,7 @@
ServerPerformanceStatistics.indexOperation.makeCurrentWhile(() {
try {
Index index = server.index;
+ AnalysisContext context = unit.element.context;
index.index(context, unit);
} catch (exception, stackTrace) {
server.sendServerErrorNotification(exception, stackTrace);
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index dc41509..0a43e34 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -942,6 +942,26 @@
_checkPackageMap(projPath, equals(packageMapProvider.packageMap));
}
+ void test_setRoots_noContext_inDotFolder() {
+ String pubspecPath = posix.join(projPath, '.pub', 'pubspec.yaml');
+ resourceProvider.newFile(pubspecPath, 'name: test');
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // verify
+ expect(callbacks.currentContextPaths, hasLength(1));
+ expect(callbacks.currentContextPaths, contains(projPath));
+ expect(callbacks.currentContextFilePaths[projPath], hasLength(0));
+ }
+
+ void test_setRoots_noContext_inPackagesFolder() {
+ String pubspecPath = posix.join(projPath, 'packages', 'pubspec.yaml');
+ resourceProvider.newFile(pubspecPath, 'name: test');
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // verify
+ expect(callbacks.currentContextPaths, hasLength(1));
+ expect(callbacks.currentContextPaths, contains(projPath));
+ expect(callbacks.currentContextFilePaths[projPath], hasLength(0));
+ }
+
void test_setRoots_packageResolver() {
Uri uri = Uri.parse('package:foo/foo.dart');
Source source = new TestSource();
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index b2c2471..6f7aeb7 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -656,6 +656,9 @@
@override
Object /*V*/ computeResult(
AnalysisTarget target, ResultDescriptor /*<V>*/ descriptor) {
+ // Make sure we are not trying to invoke the task model in a reentrant
+ // fashion.
+ assert(!driver.isTaskRunning);
CacheEntry entry = getCacheEntry(target);
CacheState state = entry.getState(descriptor);
if (state == CacheState.FLUSHED || state == CacheState.INVALID) {
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 9e7aeb4..de92b6a 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -7492,6 +7492,57 @@
this._imports = imports;
}
+ /** Given an update to this library which may have added or deleted edges
+ * in the import/export graph originating from this node only, remove any
+ * cached library cycles in the element model which may have been invalidated.
+ */
+ void invalidateLibraryCycles() {
+ if (_libraryCycle == null) {
+ // We have already invalidated this node, or we have never computed
+ // library cycle information for it. In the former case, we're done. In
+ // the latter case, this node cannot be reachable from any node for which
+ // we have computed library cycle information. Therefore, any edges added
+ // or deleted in the update causing this invalidation can only be edges to
+ // nodes which either have no library cycle information (and hence do not
+ // need invalidation), or which do not reach this node by any path.
+ // In either case, no further invalidation is needed.
+ return;
+ }
+ // If we have pre-computed library cycle information, then we must
+ // invalidate the information both on this element, and on certain
+ // other elements. Edges originating at this node may have been
+ // added or deleted. A deleted edge that points outside of this cycle
+ // cannot change the cycle information for anything outside of this cycle,
+ // and so it is sufficient to delete the cached library information on this
+ // cycle. An added edge which points to another node within the cycle
+ // only invalidates the cycle. An added edge which points to a node earlier
+ // in the topological sort of cycles induces no invalidation (since there
+ // are by definition no back edges from earlier cycles in the topological
+ // order, and hence no possible cycle can have been introduced. The only
+ // remaining case is that we have added an edge to a node which is later
+ // in the topological sort of cycles. This can induce cycles, since it
+ // represents a new back edge. It would be sufficient to invalidate the
+ // cycle information for all nodes that are between the target and the
+ // node in the topological order. For simplicity, we simply invalidate
+ // all nodes which are reachable from the the source node.
+ // Note that in the invalidation phase, we do not cut off when we encounter
+ // a node with no library cycle information, since we do not know whether
+ // we are in the case where invalidation has already been performed, or we
+ // are in the case where library cycles have simply never been computed from
+ // a newly reachable node.
+ Set<LibraryElementImpl> active = new HashSet();
+ void invalidate(LibraryElementImpl library) {
+ if (!active.add(library)) return;
+ if (library._libraryCycle != null) {
+ library._libraryCycle.forEach(invalidate);
+ library._libraryCycle = null;
+ }
+ library.exportedLibraries.forEach(invalidate);
+ library.importedLibraries.forEach(invalidate);
+ }
+ invalidate(this);
+ }
+
@override
bool get isBrowserApplication =>
entryPoint != null && isOrImportsBrowserLibrary;
@@ -7602,52 +7653,10 @@
@override
FunctionElement get loadLibraryFunction {
- if (_loadLibraryFunction == null) {
- FunctionElementImpl function =
- new FunctionElementImpl(FunctionElement.LOAD_LIBRARY_NAME, -1);
- function.synthetic = true;
- function.enclosingElement = this;
- function.returnType = loadLibraryReturnType;
- function.type = new FunctionTypeImpl(function);
- _loadLibraryFunction = function;
- }
+ assert(_loadLibraryFunction != null);
return _loadLibraryFunction;
}
- /**
- * Return the object representing the type 'Future' from the 'dart:async'
- * library, or the type 'void' if the type 'Future' cannot be accessed.
- */
- DartType get loadLibraryReturnType {
- try {
- Source asyncSource = context.sourceFactory.forUri(DartSdk.DART_ASYNC);
- if (asyncSource == null) {
- AnalysisEngine.instance.logger
- .logError("Could not create a source for dart:async");
- return VoidTypeImpl.instance;
- }
- LibraryElement asyncElement = context.computeLibraryElement(asyncSource);
- if (asyncElement == null) {
- AnalysisEngine.instance.logger
- .logError("Could not build the element model for dart:async");
- return VoidTypeImpl.instance;
- }
- ClassElement futureElement = asyncElement.getType("Future");
- if (futureElement == null) {
- AnalysisEngine.instance.logger
- .logError("Could not find type Future in dart:async");
- return VoidTypeImpl.instance;
- }
- InterfaceType futureType = futureElement.type;
- return futureType.substitute4(<DartType>[DynamicTypeImpl.instance]);
- } on AnalysisException catch (exception, stackTrace) {
- AnalysisEngine.instance.logger.logError(
- "Could not build the element model for dart:async",
- new CaughtException(exception, stackTrace));
- return VoidTypeImpl.instance;
- }
- }
-
@override
List<CompilationUnitElement> get parts => _parts;
@@ -7706,6 +7715,20 @@
@override
accept(ElementVisitor visitor) => visitor.visitLibraryElement(this);
+ /**
+ * Create the [FunctionElement] to be returned by [loadLibraryFunction],
+ * using types provided by [typeProvider].
+ */
+ void createLoadLibraryFunction(TypeProvider typeProvider) {
+ FunctionElementImpl function =
+ new FunctionElementImpl(FunctionElement.LOAD_LIBRARY_NAME, -1);
+ function.synthetic = true;
+ function.enclosingElement = this;
+ function.returnType = typeProvider.futureDynamicType;
+ function.type = new FunctionTypeImpl(function);
+ _loadLibraryFunction = function;
+ }
+
@override
ElementImpl getChild(String identifier) {
if ((_definingCompilationUnit as CompilationUnitElementImpl).identifier ==
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 84f0f6b..e52fd11 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -8171,6 +8171,7 @@
: typeResolverVisitorFactory(library, source, _typeProvider);
library.getAST(source).accept(visitor);
}
+ library.libraryElement.createLoadLibraryFunction(_typeProvider);
}
});
}
@@ -8857,6 +8858,7 @@
nameScope: library.libraryScope);
ast.accept(visitor);
}
+ library.libraryElement.createLoadLibraryFunction(_typeProvider);
}
});
}
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index dc484ed..aff5bca 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -834,6 +834,9 @@
//
libraryElement.imports = imports;
libraryElement.exports = exports;
+ // See commentary in the computation of the LIBRARY_CYCLE result
+ // for details on library cycle invalidation.
+ libraryElement.invalidateLibraryCycles();
//
// Record outputs.
//
@@ -1842,6 +1845,33 @@
@override
void internalPerform() {
+ // The computation of library cycles is necessarily non-local, since we
+ // in general have to look at all of the reachable libraries
+ // in order to find the strongly connected components. Repeating this
+ // computation for every node would be quadratic. The libraryCycle getter
+ // will avoid this by computing the library cycles for every reachable
+ // library and recording it in the element model. This means that this
+ // task implicitly produces the output for many other targets. This
+ // can't be expressed in the task model right now: instead, we just
+ // run tasks for those other targets, and they pick up the recorded
+ // version off of the element model. Unfortunately, this means that
+ // the task model will not handle the invalidation of the recorded
+ // results for us. Instead, we must explicitly invalidate the recorded
+ // library cycle information when we add or subtract edges from the
+ // import/export graph. Any update that changes the
+ // import/export graph will induce a recomputation of the LIBRARY_ELEMENT2
+ // result for the changed node. This recomputation is responsible for
+ // conservatively invalidating the library cycle information recorded
+ // in the element model. The LIBRARY_CYCLE results that have been cached
+ // by the task model are conservatively invalidated by the
+ // IMPORT_EXPORT_SOURCE_CLOSURE dependency below. If anything reachable
+ // from a node is changed, its LIBRARY_CYCLE results will be re-computed
+ // here (possibly re-using the result from the element model if invalidation
+ // did not cause it to be erased). In summary, task model dependencies
+ // on the import/export source closure ensure that this method will be
+ // re-run if anything reachable from this target has been invalidated,
+ // and the invalidation code (invalidateLibraryCycles) will ensure that
+ // element model results will be re-used here only if they are still valid.
if (context.analysisOptions.strongMode) {
LibraryElementImpl library = getRequiredInput(LIBRARY_ELEMENT_INPUT);
List<LibraryElement> component = library.libraryCycle;
@@ -1856,7 +1886,6 @@
l.importedLibraries.forEach(addLibrary);
l.exportedLibraries.forEach(addLibrary);
}
-
//
// Record outputs.
//
@@ -3783,6 +3812,11 @@
static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
/**
+ * The name of the [TYPE_PROVIDER] input.
+ */
+ static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+ /**
* The task descriptor describing this kind of task.
*/
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
@@ -3800,7 +3834,18 @@
@override
void internalPerform() {
+ //
+ // Prepare inputs.
+ //
LibraryElement library = getRequiredInput(LIBRARY_INPUT);
+ TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+ //
+ // Create the synthetic element for `loadLibrary`.
+ //
+ (library as LibraryElementImpl).createLoadLibraryFunction(typeProvider);
+ //
+ // Record outputs.
+ //
outputs[LIBRARY_ELEMENT5] = library;
}
@@ -3814,7 +3859,8 @@
return <String, TaskInput>{
'resolvedUnit': UNITS.of(source).toList((Source unit) =>
RESOLVED_UNIT3.of(new LibrarySpecificUnit(source, unit))),
- LIBRARY_INPUT: LIBRARY_ELEMENT4.of(source)
+ LIBRARY_INPUT: LIBRARY_ELEMENT4.of(source),
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
};
}
diff --git a/pkg/analyzer/lib/src/task/dart_work_manager.dart b/pkg/analyzer/lib/src/task/dart_work_manager.dart
index 61f92e5..62a25ea 100644
--- a/pkg/analyzer/lib/src/task/dart_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/dart_work_manager.dart
@@ -400,7 +400,7 @@
unitTargets.forEach(partition.remove);
for (Source dartSource in dartSources) {
CacheEntry entry = partition.get(dartSource);
- if (dartSource != null) {
+ if (entry != null) {
// TODO(scheglov) we invalidate too much.
// Would be nice to invalidate just URLs resolution.
entry.setState(PARSED_UNIT, CacheState.INVALID);
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
index 3231454..b725042 100644
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ b/pkg/analyzer/lib/src/task/driver.dart
@@ -473,6 +473,14 @@
*/
class InfiniteTaskLoopException extends AnalysisException {
/**
+ * A concrete cyclic path of [TargetedResults] within the [dependencyCycle],
+ * `null` if no such path exists. All nodes in the path are in the
+ * dependencyCycle, but the path is not guaranteed to cover the
+ * entire cycle.
+ */
+ final List<TargetedResult> cyclicPath;
+
+ /**
* If a dependency cycle was found while computing the inputs for the task,
* the set of [WorkItem]s contained in the cycle (if there are overlapping
* cycles, this is the set of all [WorkItem]s in the entire strongly
@@ -484,7 +492,8 @@
* Initialize a newly created exception to represent a failed attempt to
* perform the given [task] due to the given [dependencyCycle].
*/
- InfiniteTaskLoopException(AnalysisTask task, this.dependencyCycle)
+ InfiniteTaskLoopException(AnalysisTask task, this.dependencyCycle,
+ [this.cyclicPath])
: super(
'Infinite loop while performing task ${task.descriptor.name} for ${task.target}');
}
diff --git a/pkg/analyzer/lib/src/task/html_work_manager.dart b/pkg/analyzer/lib/src/task/html_work_manager.dart
index 218b48a..b0e52bb 100644
--- a/pkg/analyzer/lib/src/task/html_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/html_work_manager.dart
@@ -231,7 +231,7 @@
scriptTargets.forEach(partition.remove);
for (Source htmlSource in htmlSources) {
CacheEntry entry = partition.get(htmlSource);
- if (htmlSource != null) {
+ if (entry != null) {
entry.setState(HTML_ERRORS, CacheState.INVALID);
if (invalidateUris) {
entry.setState(REFERENCED_LIBRARIES, CacheState.INVALID);
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index 9d949c3..cf3cce8 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -214,6 +214,50 @@
String toString() => description;
/**
+ * Given a strongly connected component, find and return a list of
+ * [TargetedResult]s that describes a cyclic path within the cycle. Returns
+ * null if no cyclic path is found.
+ */
+ List<TargetedResult> _findCyclicPath(List<WorkItem> cycle) {
+ WorkItem findInCycle(AnalysisTarget target, ResultDescriptor descriptor) {
+ for (WorkItem item in cycle) {
+ if (target == item.target && descriptor == item.spawningResult) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ HashSet<WorkItem> active = new HashSet<WorkItem>();
+ List<TargetedResult> path = null;
+ bool traverse(WorkItem item) {
+ if (!active.add(item)) {
+ // We've found a cycle
+ path = <TargetedResult>[];
+ return true;
+ }
+ for (TargetedResult result in item.inputTargetedResults) {
+ WorkItem item = findInCycle(result.target, result.result);
+ // Ignore edges that leave the cycle.
+ if (item != null) {
+ if (traverse(item)) {
+ // This edge is in a cycle (or leads to a cycle) so add it to the
+ // path
+ path.add(result);
+ return true;
+ }
+ }
+ }
+ // There was no cycle.
+ return false;
+ }
+ if (cycle.length > 0) {
+ traverse(cycle[0]);
+ }
+ return path;
+ }
+
+ /**
* Perform this analysis task, ensuring that all exceptions are wrapped in an
* [AnalysisException].
*
@@ -250,7 +294,8 @@
//
try {
if (dependencyCycle != null && !handlesDependencyCycles) {
- throw new InfiniteTaskLoopException(this, dependencyCycle);
+ throw new InfiniteTaskLoopException(
+ this, dependencyCycle, _findCyclicPath(dependencyCycle));
}
internalPerform();
} finally {
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index e3615fe..5c4f251 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -1471,6 +1471,109 @@
enableStrongMode();
}
+ void test_library_cycle_incremental() {
+ enableStrongMode();
+ Source lib1Source = newSource(
+ '/my_lib1.dart',
+ '''
+library my_lib1;
+''');
+ Source lib2Source = newSource(
+ '/my_lib2.dart',
+ '''
+library my_lib2;
+import 'my_lib1.dart';
+''');
+ Source lib3Source = newSource(
+ '/my_lib3.dart',
+ '''
+library my_lib3;
+import 'my_lib2.dart';
+''');
+ AnalysisTarget lib1Target = new LibrarySpecificUnit(lib1Source, lib1Source);
+ AnalysisTarget lib2Target = new LibrarySpecificUnit(lib2Source, lib2Source);
+ AnalysisTarget lib3Target = new LibrarySpecificUnit(lib3Source, lib3Source);
+ computeResult(lib1Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(1));
+ computeResult(lib2Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(1));
+ computeResult(lib3Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(1));
+
+ // complete the cycle
+ context.setContents(
+ lib1Source,
+ '''
+library my_lib1;
+import 'my_lib3.dart';
+''');
+ computeResult(lib1Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(3));
+ computeResult(lib2Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(3));
+ computeResult(lib3Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(3));
+
+ // break the cycle again
+ context.setContents(
+ lib1Source,
+ '''
+library my_lib1;
+''');
+ computeResult(lib1Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(1));
+ computeResult(lib2Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(1));
+ computeResult(lib3Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(1));
+ }
+
+ void test_library_cycle_incremental_partial() {
+ enableStrongMode();
+ Source lib1Source = newSource(
+ '/my_lib1.dart',
+ '''
+library my_lib1;
+''');
+ Source lib2Source = newSource(
+ '/my_lib2.dart',
+ '''
+library my_lib2;
+import 'my_lib1.dart';
+''');
+ Source lib3Source = newSource(
+ '/my_lib3.dart',
+ '''
+library my_lib3;
+import 'my_lib2.dart';
+''');
+ AnalysisTarget lib1Target = new LibrarySpecificUnit(lib1Source, lib1Source);
+ AnalysisTarget lib2Target = new LibrarySpecificUnit(lib2Source, lib2Source);
+ AnalysisTarget lib3Target = new LibrarySpecificUnit(lib3Source, lib3Source);
+ computeResult(lib1Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(1));
+ computeResult(lib2Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(1));
+ // lib3 is not reachable, so we have not yet computed its library
+ // cycles
+
+ // complete the cycle, via lib3
+ context.setContents(
+ lib1Source,
+ '''
+library my_lib1;
+import 'my_lib3.dart';
+''');
+ // Ensure that invalidation correctly invalidated everything reachable
+ // through lib3
+ computeResult(lib1Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(3));
+ computeResult(lib2Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(3));
+ computeResult(lib3Target, LIBRARY_CYCLE);
+ expect(outputs[LIBRARY_CYCLE], hasLength(3));
+ }
+
void test_library_cycle_linear() {
List<Source> sources = newSources({
'/a.dart': '''
@@ -3208,6 +3311,7 @@
ClassElement classC = library.getType('C');
expect(classC.supertype.displayName, 'A');
}
+ expect(library.loadLibraryFunction, isNotNull);
}
test_perform_external() {
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index edaf69c..ce8b6a7 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -2137,14 +2137,14 @@
MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS,
"Js-interop class '#{cls}' cannot extend from the non js-interop "
"class '#{superclass}'.",
- howToFix: "Annotate the superclass with @Js.",
+ howToFix: "Annotate the superclass with @JS.",
examples: const [
"""
import 'package:js/js.dart';
class Foo { }
- @Js()
+ @JS()
class Bar extends Foo { }
main() {
@@ -2161,7 +2161,7 @@
"""
import 'package:js/js.dart';
- @Js()
+ @JS()
class Foo {
bar() {}
}
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 8370d13..1e4e925 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -2065,7 +2065,7 @@
typedArrayClass = findClass('NativeTypedArray');
typedArrayOfIntClass = findClass('NativeTypedArrayOfInt');
} else if (uri == PACKAGE_JS) {
- jsAnnotationClass = find(library, 'Js');
+ jsAnnotationClass = find(library, 'JS');
}
annotations.onLibraryScanned(library);
});
diff --git a/pkg/compiler/lib/src/patch_parser.dart b/pkg/compiler/lib/src/patch_parser.dart
index a0ad4d9..1b9e8f3 100644
--- a/pkg/compiler/lib/src/patch_parser.dart
+++ b/pkg/compiler/lib/src/patch_parser.dart
@@ -465,13 +465,13 @@
}
}
-/// Annotation handler for pre-resolution detection of `@Js(...)`
+/// Annotation handler for pre-resolution detection of `@JS(...)`
/// annotations.
class JsInteropAnnotationHandler implements EagerAnnotationHandler<bool> {
const JsInteropAnnotationHandler();
bool hasJsNameAnnotation(MetadataAnnotation annotation) =>
- annotation.beginToken != null && annotation.beginToken.next.value == 'Js';
+ annotation.beginToken != null && annotation.beginToken.next.value == 'JS';
bool apply(Compiler compiler,
Element element,
@@ -493,7 +493,7 @@
JavaScriptBackend backend = compiler.backend;
if (constant.getType(compiler.coreTypes).element !=
backend.jsAnnotationClass) {
- compiler.reporter.internalError(annotation, 'Invalid @Js(...) annotation.');
+ compiler.reporter.internalError(annotation, 'Invalid @JS(...) annotation.');
}
}
}
diff --git a/pkg/js/lib/js.dart b/pkg/js/lib/js.dart
index c31794b..4cb53c5 100644
--- a/pkg/js/lib/js.dart
+++ b/pkg/js/lib/js.dart
@@ -1,11 +1,8 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-/**
- * The js library allows Dart library authors to export their APIs to JavaScript
- * and to define Dart interfaces for JavaScript objects.
- */
+/// Allows interoperability with Javascript APIs.
library js;
export 'dart:js' show allowInterop, allowInteropCaptureThis;
@@ -17,52 +14,7 @@
/// Specifying [name] customizes the JavaScript name to use. By default the
/// dart name is used. It is not valid to specify a custom [name] for class
/// instance members.
-///
-/// Example 1:
-///
-/// @Js('google.maps')
-/// library maps;
-///
-/// external Map get map;
-///
-/// @Js("LatLng")
-/// class Location {
-/// external Location(num lat, num lng);
-/// }
-///
-/// @Js()
-/// class Map {
-/// external Map(Location location);
-/// external Location getLocation();
-/// }
-///
-/// In this example the top level map getter will invoke the JavaScript getter
-/// google.maps.map
-/// Calls to the Map constructor will be translated to calls to the JavaScript
-/// new google.maps.Map(location)
-/// Calls to the Location constructor willbe translated to calls to the
-/// JavaScript
-/// new google.maps.LatLng(lat, lng)
-/// because a custom JavaScript name for the Location class.
-/// In general, we recommend against using custom JavaScript names whenever
-/// possible as it is easier for users if the JavaScript names and Dart names
-/// are consistent.
-///
-/// Example 2:
-/// library utils;
-///
-/// @Js("JSON.stringify")
-/// external String stringify(obj);
-///
-/// @Js()
-/// void debugger();
-///
-/// In this example no custom JavaScript namespace is specified.
-/// Calls to debugger map to calls to JavaScript
-/// self.debugger()
-/// Calls to stringify map to calls to
-/// JSON.stringify(obj)
-class Js {
+class JS {
final String name;
- const Js([this.name]);
+ const JS([this.name]);
}
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index d29e7cf..4d3c679 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -433,7 +433,7 @@
directory = NULL;
} else {
Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Directory argument to SecurityContext.usePrivateKey is not "
+ "Directory argument to SecurityContext.setTrustedCertificates is not "
"a String or null"));
}
@@ -910,9 +910,12 @@
SSL_set_ex_data(ssl_, filter_ssl_index, this);
if (is_server_) {
- // Do not request a client certificate.
- // TODO(24069): Allow server to request a client certificate, when desired.
- SSL_set_verify(ssl_, SSL_VERIFY_NONE, NULL);
+ int certificate_mode =
+ request_client_certificate ? SSL_VERIFY_PEER : SSL_VERIFY_NONE;
+ if (require_client_certificate) {
+ certificate_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ }
+ SSL_set_verify(ssl_, certificate_mode, NULL);
} else {
SetAlpnProtocolList(protocols_handle, ssl_, NULL, false);
status = SSL_set_tlsext_host_name(ssl_, hostname);
@@ -948,19 +951,6 @@
if (SSL_LOG_STATUS) Log::Print("SSL_connect error: %d\n", error);
}
}
- if (is_server_) {
- if (request_client_certificate) {
- // TODO(24069): Handle client certificates on server side.
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "requestClientCertificate not implemented."));
- }
- } else { // Client.
- if (send_client_certificate) {
- // TODO(24070): Handle client certificates on client side.
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "sendClientCertificate not implemented."));
- }
- }
Handshake();
}
diff --git a/runtime/vm/os_thread_android.cc b/runtime/vm/os_thread_android.cc
index 8cbb03e..fa87896 100644
--- a/runtime/vm/os_thread_android.cc
+++ b/runtime/vm/os_thread_android.cc
@@ -167,7 +167,8 @@
void OSThread::Join(ThreadJoinId id) {
- ASSERT(pthread_join(id, NULL) == 0);
+ int result = pthread_join(id, NULL);
+ ASSERT(result == 0);
}
diff --git a/runtime/vm/os_thread_linux.cc b/runtime/vm/os_thread_linux.cc
index 4955cb4..9fb0b23 100644
--- a/runtime/vm/os_thread_linux.cc
+++ b/runtime/vm/os_thread_linux.cc
@@ -169,7 +169,8 @@
void OSThread::Join(ThreadJoinId id) {
- ASSERT(pthread_join(id, NULL) == 0);
+ int result = pthread_join(id, NULL);
+ ASSERT(result == 0);
}
diff --git a/runtime/vm/os_thread_macos.cc b/runtime/vm/os_thread_macos.cc
index 827f749..e7c7c90 100644
--- a/runtime/vm/os_thread_macos.cc
+++ b/runtime/vm/os_thread_macos.cc
@@ -161,7 +161,8 @@
void OSThread::Join(ThreadJoinId id) {
- ASSERT(pthread_join(id, NULL) == 0);
+ int result = pthread_join(id, NULL);
+ ASSERT(result == 0);
}
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index e8b0a6b..8b3020a 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -3179,8 +3179,9 @@
*/
interceptedTypeCheck(value, property) {
if (value == null) return value;
- if ((identical(JS('String', 'typeof #', value), 'object'))
- && JS('bool', '#[#]', getInterceptor(value), property)) {
+ if ((JS('bool', 'typeof # === "object"', value) ||
+ JS('bool', 'typeof # === "function"', value)) &&
+ JS('bool', '#[#]', getInterceptor(value), property)) {
return value;
}
propertyTypeError(value, property);
@@ -3192,9 +3193,10 @@
* prototype at load time.
*/
interceptedTypeCast(value, property) {
- if (value == null
- || ((JS('bool', 'typeof # === "object"', value))
- && JS('bool', '#[#]', getInterceptor(value), property))) {
+ if (value == null ||
+ ((JS('bool', 'typeof # === "object"', value) ||
+ JS('bool', 'typeof # === "function"', value)) &&
+ JS('bool', '#[#]', getInterceptor(value), property))) {
return value;
}
propertyTypeCastError(value, property);
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 6d84226..73e0a05 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -1107,32 +1107,14 @@
********** **********
******************************************************************************/
-// List of known tagName to DartClass for custom elements, used for upgrade.
-var _knownCustomElements = new Map<String, Map<Type, String>>();
-
-void _addCustomElementType(String tagName, Type dartClass, [String extendTag]) {
- _knownCustomElements[tagName] =
- {'type': dartClass, 'extends': extendTag != null ? extendTag : "" };
-}
-
-Type _getCustomElementType(object) {
- var entry = _knownCustomElements[_getCustomElementName(object)];
- if (entry != null) {
- return entry['type'];
- }
- return null;
-}
-
String _getCustomElementExtends(object) {
- var entry = _knownCustomElements[_getCustomElementName(object)];
+ var entry = getCustomElementEntry(object);
if (entry != null) {
return entry['extends'];
}
return null;
}
-_getCustomElement(object) => _knownCustomElements[_getCustomElementName(object)];
-
// Return the tag name or is attribute of the custom element or data binding.
String _getCustomElementName(element) {
var jsObject;
@@ -1162,13 +1144,6 @@
return tag;
}
-Rectangle make_dart_rectangle(r) =>
- r == null ? null : new Rectangle(
- js.JsNative.getProperty(r, 'left'),
- js.JsNative.getProperty(r, 'top'),
- js.JsNative.getProperty(r, 'width'),
- js.JsNative.getProperty(r, 'height'));
-
/// An abstract class for all DOM objects we wrap in dart:html and related
/// libraries.
class DartHtmlDomObject {
@@ -1178,247 +1153,14 @@
}
-// Flag to disable JS interop asserts. Setting to false will speed up the
-// wrap_jso calls.
-bool __interop_checks = true;
-
-/** Expando for JsObject, used by every Dart class associated with a Javascript
- * class (e.g., DOM, WebAudio, etc.).
- */
-
-/**
- * Return the JsObject associated with a Dart class [dartClass_instance].
- */
-unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance);
-
-/**
- * Create Dart class that maps to the JS Type, add the JsObject as an expando
- * on the Dart class and return the created Dart class.
- */
-wrap_jso(jsObject) {
- try {
- if (jsObject is! js.JsObject || jsObject == null) {
- // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
- // or it's a simple type.
- return jsObject;
- }
-
- var wrapper = js.getDartHtmlWrapperFor(jsObject);
- // if we have a wrapper return the Dart instance.
- if (wrapper != null) {
- if (wrapper.runtimeType == HtmlElement && !wrapper._isBadUpgrade) {
- // We're a Dart instance but we need to upgrade.
- var customElementClass = _getCustomElementType(wrapper);
- if (customElementClass != null) {
- var dartClass_instance;
- try {
- dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
- } finally {
- dartClass_instance.blink_jsObject = jsObject;
- jsObject['dart_class'] = dartClass_instance;
- js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
- return dartClass_instance;
- }
- }
- }
-
- return wrapper;
- }
-
- if (jsObject is js.JsArray) {
- var wrappingList = new _DartHtmlWrappingList(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrappingList);
- return wrappingList;
- }
-
- // Try the most general type conversions on it.
- // TODO(alanknight): We may be able to do better. This maintains identity,
- // which is useful, but expensive. And if we nest something that only
- // this conversion handles, how does that work? e.g. a list of maps of elements.
- var converted = convertNativeToDart_SerializedScriptValue(jsObject);
- if (!identical(converted, jsObject)) {
- return converted;
- }
-
- var constructor = js.JsNative.getProperty(jsObject, 'constructor');
- if (constructor == null) {
- // Perfectly valid case for JavaScript objects where __proto__ has
- // intentionally been set to null.
- js.setDartHtmlWrapperFor(jsObject, jsObject);
- return jsObject;
- }
- var jsTypeName = js.JsNative.getProperty(constructor, 'name');
- if (jsTypeName is! String || jsTypeName.length == 0) {
- // Not an html type.
- js.setDartHtmlWrapperFor(jsObject, jsObject);
- return jsObject;
- }
-
- var dartClass_instance;
- if (jsObject.hasProperty('dart_class')) {
- // Got a dart_class (it's a custom element) use it it's already set up
- // make sure it's upgraded.
- dartClass_instance = _upgradeHtmlElement(jsObject['dart_class']);
- } else {
- var customElementClass = null;
- var extendsTag = "";
- var custom = _getCustomElement(jsObject);
- if (custom != null) {
- customElementClass = custom['type'];
- extendsTag = custom['extends'];
- }
- // Custom Element to upgrade.
- if (jsTypeName == 'HTMLElement' && customElementClass != null && extendsTag == "") {
- try {
- dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
- } finally {
- dartClass_instance.blink_jsObject = jsObject;
- jsObject['dart_class'] = dartClass_instance;
- js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
- }
- } else {
- // TODO(terry): Verify with jakemacd that this is right?
- // If we every get an auto-binding we're matching previous non-JS Interop
- // did to return a TemplateElement.
- if (jsTypeName == 'auto-binding') {
- jsTypeName = "HTMLTemplateElement";
- }
-
- var func = getHtmlCreateFunction(jsTypeName);
- if (func == null) {
- // One last ditch effort could be a JS custom element.
- if (jsObject.toString() == "[object HTMLElement]") {
- func = getHtmlCreateFunction("HTMLElement");
- }
- }
- if (func != null) {
- dartClass_instance = func();
- dartClass_instance.blink_jsObject = jsObject;
- js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
- }
- }
- }
- // TODO(jacobr): cache that this is not a dart:html JS class.
- return dartClass_instance;
- } catch(e, stacktrace){
- if (__interop_checks) {
- if (e is DebugAssertException)
- window.console.log("${e.message}\n ${stacktrace}");
- else
- window.console.log("${stacktrace}");
- }
- }
-
- return null;
-}
-
-/**
- * Create Dart class that maps to the JS Type, add the JsObject as an expando
- * on the Dart class and return the created Dart class.
- */
-wrap_jso_no_SerializedScriptvalue(jsObject) {
- try {
- if (jsObject is! js.JsObject || jsObject == null) {
- // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
- // or it's a simple type.
- return jsObject;
- }
-
- // TODO(alanknight): With upgraded custom elements this causes a failure because
- // we need a new wrapper after the type changes. We could possibly invalidate this
- // if the constructor name didn't match?
- var wrapper = js.getDartHtmlWrapperFor(jsObject);
- if (wrapper != null) {
- return wrapper;
- }
-
- if (jsObject is js.JsArray) {
- var wrappingList = new _DartHtmlWrappingList(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrappingList);
- return wrappingList;
- }
-
- var constructor = js.JsNative.getProperty(jsObject, 'constructor');
- if (constructor == null) {
- // Perfectly valid case for JavaScript objects where __proto__ has
- // intentionally been set to null.
- js.setDartHtmlWrapperFor(jsObject, jsObject);
- return jsObject;
- }
- var jsTypeName = js.JsNative.getProperty(constructor, 'name');
- if (jsTypeName is! String || jsTypeName.length == 0) {
- // Not an html type.
- js.setDartHtmlWrapperFor(jsObject, jsObject);
- return jsObject;
- }
-
- var func = getHtmlCreateFunction(jsTypeName);
- if (func != null) {
- var dartClass_instance = func();
- dartClass_instance.blink_jsObject = jsObject;
- js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
- return dartClass_instance;
- }
- return jsObject;
- } catch(e, stacktrace){
- if (__interop_checks) {
- if (e is DebugAssertException)
- window.console.log("${e.message}\n ${stacktrace}");
- else
- window.console.log("${stacktrace}");
- }
- }
-
- return null;
-}
-
-/**
- * Create Dart class that maps to the JS Type that is the JS type being
- * extended using JS interop createCallback (we need the base type of the
- * custom element) not the Dart created constructor.
- */
-wrap_jso_custom_element(jsObject) {
- try {
- if (jsObject is! js.JsObject) {
- // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
- return jsObject;
- }
-
- // Find out what object we're extending.
- var objectName = jsObject.toString();
- // Expect to see something like '[object HTMLElement]'.
- if (!objectName.startsWith('[object ')) {
- return jsObject;
- }
-
- var extendsClass = objectName.substring(8, objectName.length - 1);
- var func = getHtmlCreateFunction(extendsClass);
- if (__interop_checks)
- debug_or_assert("func != null name = ${extendsClass}", func != null);
- var dartClass_instance = func();
- dartClass_instance.blink_jsObject = jsObject;
- return dartClass_instance;
- } catch(e, stacktrace){
- if (__interop_checks) {
- if (e is DebugAssertException)
- window.console.log("${e.message}\n ${stacktrace}");
- else
- window.console.log("${stacktrace}");
- }
-
- // Problem?
- return null;
- }
-}
-
-// Upgrade a Dart HtmlElement to the user's Dart custom element class.
+/// Upgrade a Dart HtmlElement to the user's Dart custom element class.
_upgradeHtmlElement(dartInstance) {
// Only try upgrading HtmlElement (Dart class) if there is a failure then
// don't try it again - one failure is enough.
- if (dartInstance.runtimeType == HtmlElement && !dartInstance._isBadUpgrade) {
+ if (dartInstance.runtimeType == HtmlElement && !dartInstance.isBadUpgrade) {
// Must be exactly HtmlElement not something derived from it.
- var customElementClass = _getCustomElementType(dartInstance);
+ var customElementClass = getCustomElementType(dartInstance);
// Custom Element to upgrade.
if (customElementClass != null) {
@@ -1429,7 +1171,6 @@
dartInstance._badUpgrade();
} finally {
dartInstance.blink_jsObject = jsObject;
- jsObject['dart_class'] = dartInstance;
js.setDartHtmlWrapperFor(jsObject, dartInstance);
}
}
@@ -1475,53 +1216,10 @@
return result;
}
-// Converts a flat Dart map into a JavaScript object with properties this is
-// is the Dartium only version it uses dart:js.
-// TODO(alanknight): This could probably be unified with the dart2js conversions
-// code in html_common and be more general.
-convertDartToNative_Dictionary(Map dict) {
- if (dict == null) return null;
- var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object'));
- dict.forEach((String key, value) {
- if (value is List) {
- var jsArray = new js.JsArray();
- value.forEach((elem) {
- jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem);
- });
- jsObject[key] = jsArray;
- } else {
- jsObject[key] = value;
- }
- });
- return jsObject;
-}
-
-// Converts a Dart list into a JsArray. For the Dartium version only.
-convertDartToNative_List(List input) => new js.JsArray()..addAll(input);
-
-// Conversion function place holder (currently not used in dart2js or dartium).
-List convertDartToNative_StringArray(List<String> input) => input;
-
-/**
- * Wraps a JsArray and will call wrap_jso on its entries.
- */
-class _DartHtmlWrappingList extends ListBase implements NativeFieldWrapperClass2 {
- _DartHtmlWrappingList(this.blink_jsObject);
-
- final js.JsArray blink_jsObject;
-
- operator [](int index) => wrap_jso(js.JsNative.getArrayIndex(blink_jsObject, index));
-
- operator []=(int index, value) => blink_jsObject[index] = value;
-
- int get length => blink_jsObject.length;
- int set length(int newLength) => blink_jsObject.length = newLength;
-}
-
/**
* Upgrade the JS HTMLElement to the Dart class. Used by Dart's Polymer.
*/
-createCustomUpgrader(Type customElementClass, $this) {
+_createCustomUpgrader(Type customElementClass, $this) {
var dartClass;
try {
dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
@@ -9327,7 +9025,7 @@
}
// Need for identity.
- e.blink_jsObject['dart_class'] = e;
+ js.setDartHtmlWrapperFor(e.blink_jsObject, e);
return e;
}
@@ -20322,12 +20020,28 @@
return isElement ? jsClassName : null;
}
+ // Get the first class that's a super of a dart.dom library.
+ ClassMirror _getDartHtmlClassName(ClassMirror classMirror) {
+ while (classMirror.superclass != null) {
+ var fullName = classMirror.superclass.qualifiedName;
+ var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
+ if (domLibrary) {
+ return classMirror.superclass;
+ }
+
+ classMirror = classMirror.superclass;
+ }
+
+ return null;
+ }
+
/**
* Get the class that immediately derived from a class in dart:html or
* dart:svg (has an attribute DomName of either HTML* or SVG*).
*/
ClassMirror _getDomSuperClass(ClassMirror classMirror) {
var isElement = false;
+ var foundSuperElement = null;
while (classMirror.superclass != null) {
var fullName = classMirror.superclass.qualifiedName;
@@ -20335,6 +20049,9 @@
var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
if (domLibrary) {
+ if (foundSuperElement == null) {
+ foundSuperElement = classMirror.superclass;
+ }
// Lookup JS class (if not found).
var metadatas = classMirror.metadata;
for (var metadata in metadatas) {
@@ -20342,7 +20059,7 @@
var metaType = reflectClass(metaDataMirror.runtimeType);
if (MirrorSystem.getName(metaType.simpleName) == 'DomName' &&
(metaDataMirror.name.startsWith('HTML') || metaDataMirror.name.startsWith('SVG'))) {
- if (isElement) return classMirror;
+ if (isElement) return foundSuperElement;
}
}
}
@@ -20463,6 +20180,25 @@
throw new DomException.jsInterop("HierarchyRequestError: Only HTML elements can be customized.");
}
+ var customClassType = _getDartHtmlClassName(classMirror);
+
+ if (extendsTag != null) {
+ var nativeElement = document.createElement(extendsTag);
+
+ // Trying to extend a native element is it the Dart class consistent with the
+ // extendsTag?
+ if (nativeElement.runtimeType != customClassType.reflectedType) {
+ var nativeElementClassMirror = reflectClass(nativeElement.runtimeType);
+ var customClassNativeElement = MirrorSystem.getName(customClassType.simpleName);
+ var extendsNativeElement = MirrorSystem.getName(nativeElementClassMirror.simpleName);
+ throw new DomException.jsInterop("HierarchyRequestError: Custom class type ($customClassNativeElement) and extendsTag class ($extendsNativeElement) don't match .");
+ }
+ } else if (customClassType.reflectedType != HtmlElement && customClassType.reflectedType != svg.SvgElement) {
+ var customClassName = MirrorSystem.getName(classMirror.simpleName);
+ var customClassElement = MirrorSystem.getName(customClassType.simpleName);
+ throw new DomException.jsInterop("HierarchyRequestError: Custom element $customClassName is a native $customClassElement should be derived from HtmlElement or SvgElement.");
+ }
+
if (_hasCreatedConstructor(classMirror)) {
// Start the hookup the JS way create an <x-foo> element that extends the
// <x-base> custom element. Inherit its prototype and signal what tag is
@@ -20478,7 +20214,7 @@
var elemProto = js.JsNative.callMethod(js.JsNative.getProperty(js.context, 'Object'), "create", [js.JsNative.getProperty(baseElement, 'prototype')]);
// Remember for any upgrading done in wrap_jso.
- _addCustomElementType(tag, customElementClass, extendsTag);
+ addCustomElementType(tag, customElementClass, extendsTag);
// TODO(terry): Hack to stop recursion re-creating custom element when the
// created() constructor of the custom element does e.g.,
@@ -20499,9 +20235,26 @@
var dartClass;
try {
+ if (extendsTag != null) {
+ // If we're extending a native element then create that element.
+ // Then upgrade that element to the customElementClass through
+ // normal flow.
+ dartClass = document.createElement(extendsTag);
+ js.setDartHtmlWrapperFor($this, dartClass);
+ dartClass.blink_jsObject = $this;
+ }
+
+ // Upgrade to the CustomElement Dart class.
dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
} catch (e) {
+ // Got a problem make it an HtmlElement and rethrow the error.
dartClass = HtmlElement.internalCreateHtmlElement();
+ // We need to remember the JS object (because constructElement failed
+ // it normally sets up the blink_jsObject.
+ dartClass.blink_jsObject = $this;
+
+ // Mark to only try this once don't try upgrading from HtmlElement
+ // to the user's Dart class - we had a problem.
dartClass._badUpgrade();
throw e;
} finally {
@@ -21239,10 +20992,17 @@
@Experimental() // untriaged
ElementStream<Event> get onWaiting => waitingEvent.forElement(this);
- // Flags to only try upgrading once if there's a failure don't try upgrading
+ // Flags to only try upgrading once. If there's a failure don't try upgrading
// anymore.
bool _badUpgradeOccurred = false;
- bool get _isBadUpgrade => _badUpgradeOccurred;
+
+ /// Required for SDK Infrastructure. Internal use only.
+ ///
+ /// Did this encounter a failure attempting to upgrade to
+ /// a custom element.
+ @Deprecated("Required for SDK Infrastructure. Internal use only.")
+ bool get isBadUpgrade => _badUpgradeOccurred;
+
void _badUpgrade() { _badUpgradeOccurred = true; }
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -37202,10 +36962,10 @@
if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(unwrap_jso(blob_OR_source_OR_stream));
}
- if ((blob_OR_source_OR_stream is MediaStream)) {
+ if ((blob_OR_source_OR_stream is MediaSource)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(unwrap_jso(blob_OR_source_OR_stream));
}
- if ((blob_OR_source_OR_stream is MediaSource)) {
+ if ((blob_OR_source_OR_stream is MediaStream)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(unwrap_jso(blob_OR_source_OR_stream));
}
throw new ArgumentError("Incorrect number or type of arguments");
@@ -47163,9 +46923,11 @@
class _VMElementUpgrader implements ElementUpgrader {
final Type _type;
final Type _nativeType;
+ final String _extendsTag;
_VMElementUpgrader(Document document, Type type, String extendsTag) :
_type = type,
+ _extendsTag = extendsTag,
_nativeType = _validateCustomType(type).reflectedType {
if (extendsTag == null) {
@@ -47183,20 +46945,39 @@
Element upgrade(element) {
var jsObject;
- var tag = _getCustomElementName(element);
+ var tag;
+ var isNativeElementExtension = false;
+
+ try {
+ tag = _getCustomElementName(element);
+ } catch (e) {
+ isNativeElementExtension = element.localName == _extendsTag;
+ }
+
if (element.runtimeType == HtmlElement || element.runtimeType == TemplateElement) {
+ if (tag != _extendsTag) {
+ throw new UnsupportedError('$tag is not registered.');
+ }
jsObject = unwrap_jso(element);
} else if (element.runtimeType == js.JsObjectImpl) {
// It's a Polymer core element (written in JS).
jsObject = element;
- } else {
+ } else if (isNativeElementExtension) {
+ // Extending a native element.
+ jsObject = element.blink_jsObject;
+
+ // Element to extend is the real tag.
+ tag = element.localName;
+ } else if (tag != null && element.localName != tag) {
+ throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected native Html or Svg element to extend.');
+ } else if (tag == null) {
throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObjectImpl.');
}
// Remember Dart class to tagName for any upgrading done in wrap_jso.
- _addCustomElementType(tag, _type);
+ addCustomElementType(tag, _type, _extendsTag);
- return createCustomUpgrader(_nativeType, jsObject);
+ return _createCustomUpgrader(_type, jsObject);
}
}
diff --git a/sdk/lib/html/html_common/conversions_dart2js.dart b/sdk/lib/html/html_common/conversions_dart2js.dart
index ac5b755..3b3a8ad 100644
--- a/sdk/lib/html/html_common/conversions_dart2js.dart
+++ b/sdk/lib/html/html_common/conversions_dart2js.dart
@@ -91,3 +91,9 @@
var newPromise = JS('', '#.then(#).catch(#)', promise, then, error);
return completer.future;
}
+
+/// Wrap a JS object with an instance of the matching dart:html class. Used only in Dartium.
+wrap_jso(jsObject) => jsObject;
+
+/// Find the underlying JS object for a dart:html Dart object.
+unwrap_jso(dartClass_instance) => dartClass_instance;
diff --git a/sdk/lib/html/html_common/conversions_dartium.dart b/sdk/lib/html/html_common/conversions_dartium.dart
index d6e6064..1ed1e13 100644
--- a/sdk/lib/html/html_common/conversions_dartium.dart
+++ b/sdk/lib/html/html_common/conversions_dartium.dart
@@ -66,3 +66,331 @@
convertDartToNative_DateTime(DateTime date) {
return new js.JsObject(js.context["Date"], [date.millisecondsSinceEpoch]);
}
+
+/// Creates a Dart Rectangle from a Javascript object with properties
+/// left, top, width and height. Used internally in Dartium.
+Rectangle make_dart_rectangle(r) =>
+ r == null ? null : new Rectangle(
+ js.JsNative.getProperty(r, 'left'),
+ js.JsNative.getProperty(r, 'top'),
+ js.JsNative.getProperty(r, 'width'),
+ js.JsNative.getProperty(r, 'height'));
+
+// Converts a flat Dart map into a JavaScript object with properties this is
+// is the Dartium only version it uses dart:js.
+// TODO(alanknight): This could probably be unified with the dart2js conversions
+// code in html_common and be more general.
+convertDartToNative_Dictionary(Map dict) {
+ if (dict == null) return null;
+ var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object'));
+ dict.forEach((String key, value) {
+ if (value is List) {
+ var jsArray = new js.JsArray();
+ value.forEach((elem) {
+ jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem);
+ });
+ jsObject[key] = jsArray;
+ } else {
+ jsObject[key] = value;
+ }
+ });
+ return jsObject;
+}
+
+// Conversion function place holder (currently not used in dart2js or dartium).
+List convertDartToNative_StringArray(List<String> input) => input;
+
+// Converts a Dart list into a JsArray. For the Dartium version only.
+convertDartToNative_List(List input) => new js.JsArray()..addAll(input);
+
+/// Find the underlying JS object for a dart:html Dart object.
+unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance);
+
+// Flag to disable JS interop asserts. Setting to false will speed up the
+// wrap_jso calls.
+bool interop_checks = false;
+
+/// Wrap a JS object with an instance of the matching dart:html class. Used only in Dartium.
+wrap_jso(jsObject) {
+ try {
+ if (jsObject is! js.JsObject || jsObject == null) {
+ // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
+ // or it's a simple type.
+ return jsObject;
+ }
+
+ var wrapper = js.getDartHtmlWrapperFor(jsObject);
+ // if we have a wrapper return the Dart instance.
+ if (wrapper != null) {
+ var customElementClass = getCustomElementType(wrapper.blink_jsObject);
+ if (wrapper.runtimeType != customElementClass && customElementClass != null) {
+ if (wrapper.runtimeType == HtmlElement && !wrapper.isBadUpgrade) {
+ // We're a Dart instance if it's HtmlElement and we have a customElement
+ // class then we need to upgrade.
+ if (customElementClass != null) {
+ var dartClass_instance;
+ try {
+ dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
+ } finally {
+ dartClass_instance.blink_jsObject = jsObject;
+ return dartClass_instance;
+ }
+ }
+ }
+ }
+
+ return wrapper;
+ }
+
+ if (jsObject is js.JsArray) {
+ var wrappingList = new DartHtmlWrappingList(jsObject);
+ js.setDartHtmlWrapperFor(jsObject, wrappingList);
+ return wrappingList;
+ }
+
+ // Try the most general type conversions on it.
+ // TODO(alanknight): We may be able to do better. This maintains identity,
+ // which is useful, but expensive. And if we nest something that only
+ // this conversion handles, how does that work? e.g. a list of maps of elements.
+ var converted = convertNativeToDart_SerializedScriptValue(jsObject);
+ if (!identical(converted, jsObject)) {
+ return converted;
+ }
+
+ var constructor = js.JsNative.getProperty(jsObject, 'constructor');
+ if (constructor == null) {
+ // Perfectly valid case for JavaScript objects where __proto__ has
+ // intentionally been set to null.
+ js.setDartHtmlWrapperFor(jsObject, jsObject);
+ return jsObject;
+ }
+ var jsTypeName = js.JsNative.getProperty(constructor, 'name');
+ if (jsTypeName is! String || jsTypeName.length == 0) {
+ // Not an html type.
+ js.setDartHtmlWrapperFor(jsObject, jsObject);
+ return jsObject;
+ }
+
+ var dartClass_instance;
+ var customElementClass = null;
+ var extendsTag = "";
+ var custom = getCustomElementEntry(jsObject);
+ if (custom != null) {
+ customElementClass = custom['type'];
+ extendsTag = custom['extends'];
+ }
+
+ // Custom Element to upgrade.
+ // Only allow custome elements to be created in the html or svg default
+ // namespace.
+ var defaultNS = jsObject['namespaceURI'] == 'http://www.w3.org/1999/xhtml' ||
+ jsObject['namespaceURI'] == 'http://www.w3.org/2000/svg';
+ if (customElementClass != null && extendsTag == "" && defaultNS) {
+ try {
+ dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
+ } finally {
+ dartClass_instance.blink_jsObject = jsObject;
+ js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+ }
+ } else {
+ var func = getHtmlCreateFunction(jsTypeName);
+ if (func == null) {
+ if (jsTypeName == 'auto-binding') {
+ func = getHtmlCreateFunction("HTMLTemplateElement");
+ } else if (jsObject.toString() == "[object HTMLElement]") {
+ // One last ditch effort could be a JS custom element.
+ func = getHtmlCreateFunction("HTMLElement");
+ }
+ }
+ if (func != null) {
+ dartClass_instance = func();
+ dartClass_instance.blink_jsObject = jsObject;
+ js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+ }
+ }
+
+ // TODO(jacobr): cache that this is not a dart:html JS class.
+ return dartClass_instance;
+ } catch(e, stacktrace){
+ if (interop_checks) {
+ if (e is DebugAssertException)
+ window.console.log("${e.message}\n ${stacktrace}");
+ else
+ window.console.log("${stacktrace}");
+ }
+ }
+
+ return null;
+}
+
+/**
+ * Create Dart class that maps to the JS Type, add the JsObject as an expando
+ * on the Dart class and return the created Dart class.
+ */
+wrap_jso_no_SerializedScriptvalue(jsObject) {
+ try {
+ if (jsObject is! js.JsObject || jsObject == null) {
+ // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
+ // or it's a simple type.
+ return jsObject;
+ }
+
+ // TODO(alanknight): With upgraded custom elements this causes a failure because
+ // we need a new wrapper after the type changes. We could possibly invalidate this
+ // if the constructor name didn't match?
+ var wrapper = js.getDartHtmlWrapperFor(jsObject);
+ if (wrapper != null) {
+ return wrapper;
+ }
+
+ if (jsObject is js.JsArray) {
+ var wrappingList = new DartHtmlWrappingList(jsObject);
+ js.setDartHtmlWrapperFor(jsObject, wrappingList);
+ return wrappingList;
+ }
+
+ var constructor = js.JsNative.getProperty(jsObject, 'constructor');
+ if (constructor == null) {
+ // Perfectly valid case for JavaScript objects where __proto__ has
+ // intentionally been set to null.
+ js.setDartHtmlWrapperFor(jsObject, jsObject);
+ return jsObject;
+ }
+ var jsTypeName = js.JsNative.getProperty(constructor, 'name');
+ if (jsTypeName is! String || jsTypeName.length == 0) {
+ // Not an html type.
+ js.setDartHtmlWrapperFor(jsObject, jsObject);
+ return jsObject;
+ }
+
+ var func = getHtmlCreateFunction(jsTypeName);
+ if (func != null) {
+ var dartClass_instance = func();
+ dartClass_instance.blink_jsObject = jsObject;
+ js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+ return dartClass_instance;
+ }
+ return jsObject;
+ } catch(e, stacktrace){
+ if (interop_checks) {
+ if (e is DebugAssertException)
+ window.console.log("${e.message}\n ${stacktrace}");
+ else
+ window.console.log("${stacktrace}");
+ }
+ }
+
+ return null;
+}
+
+/**
+ * Create Dart class that maps to the JS Type that is the JS type being
+ * extended using JS interop createCallback (we need the base type of the
+ * custom element) not the Dart created constructor.
+ */
+wrap_jso_custom_element(jsObject) {
+ try {
+ if (jsObject is! js.JsObject) {
+ // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
+ return jsObject;
+ }
+
+ // Find out what object we're extending.
+ var objectName = jsObject.toString();
+ // Expect to see something like '[object HTMLElement]'.
+ if (!objectName.startsWith('[object ')) {
+ return jsObject;
+ }
+
+ var extendsClass = objectName.substring(8, objectName.length - 1);
+ var func = getHtmlCreateFunction(extendsClass);
+ if (interop_checks)
+ debug_or_assert("func != null name = ${extendsClass}", func != null);
+ var dartClass_instance = func();
+ dartClass_instance.blink_jsObject = jsObject;
+ return dartClass_instance;
+ } catch(e, stacktrace){
+ if (interop_checks) {
+ if (e is DebugAssertException)
+ window.console.log("${e.message}\n ${stacktrace}");
+ else
+ window.console.log("${stacktrace}");
+ }
+
+ // Problem?
+ return null;
+ }
+}
+
+getCustomElementEntry(element) {
+ var hasAttribute = false;
+
+ var jsObject;
+ var tag = "";
+ var runtimeType = element.runtimeType;
+ if (runtimeType == HtmlElement) {
+ tag = element.localName;
+ } else if (runtimeType == TemplateElement) {
+ // Data binding with a Dart class.
+ tag = element.attributes['is'];
+ } else if (runtimeType == js.JsObjectImpl) {
+ // It's a Polymer core element (written in JS).
+ // Make sure it's an element anything else we can ignore.
+ if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
+ if (js.JsNative.callMethod(element, 'hasAttribute', ['is'])) {
+ hasAttribute = true;
+ // It's data binding use the is attribute.
+ tag = js.JsNative.callMethod(element, 'getAttribute', ['is']);
+ } else {
+ // It's a custom element we want the local name.
+ tag = element['localName'];
+ }
+ }
+ } else {
+ throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObjectImpl.');
+ }
+
+ var entry = _knownCustomElements[tag];
+ if (entry != null) {
+ // If there's an 'is' attribute then check if the extends tag registered
+ // matches the tag if so then return the entry that's registered for this
+ // extendsTag or if there's no 'is' tag then return the entry found.
+ if ((hasAttribute && entry['extends'] == tag) || !hasAttribute) {
+ return entry;
+ }
+ }
+
+ return null;
+}
+
+// List of known tagName to DartClass for custom elements, used for upgrade.
+var _knownCustomElements = new Map<String, Map<Type, String>>();
+
+void addCustomElementType(String tagName, Type dartClass, [String extendTag]) {
+ _knownCustomElements[tagName] =
+ {'type': dartClass, 'extends': extendTag != null ? extendTag : "" };
+}
+
+Type getCustomElementType(object) {
+ var entry = getCustomElementEntry(object);
+ if (entry != null) {
+ return entry['type'];
+ }
+ return null;
+}
+
+/**
+ * Wraps a JsArray and will call wrap_jso on its entries.
+ */
+class DartHtmlWrappingList extends ListBase implements NativeFieldWrapperClass2 {
+ DartHtmlWrappingList(this.blink_jsObject);
+
+ final js.JsArray blink_jsObject;
+
+ operator [](int index) => wrap_jso(js.JsNative.getArrayIndex(blink_jsObject, index));
+
+ operator []=(int index, value) => blink_jsObject[index] = value;
+
+ int get length => blink_jsObject.length;
+ int set length(int newLength) => blink_jsObject.length = newLength;
+}
diff --git a/sdk/lib/html/html_common/html_common.dart b/sdk/lib/html/html_common/html_common.dart
index dfdfa27..c2e1644 100644
--- a/sdk/lib/html/html_common/html_common.dart
+++ b/sdk/lib/html/html_common/html_common.dart
@@ -9,6 +9,7 @@
import 'dart:html';
import 'dart:js' as js;
import 'dart:_internal' show WhereIterable;
+import 'dart:nativewrappers';
import 'dart:typed_data';
import 'dart:web_gl' as gl;
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart
index 13e7012..f2ab9c4 100644
--- a/sdk/lib/js/dartium/js_dartium.dart
+++ b/sdk/lib/js/dartium/js_dartium.dart
@@ -92,6 +92,7 @@
import 'dart:math' as math;
import 'dart:mirrors' as mirrors;
import 'dart:html' as html;
+import 'dart:html_common' as html_common;
import 'dart:indexed_db' as indexed_db;
import 'dart:typed_data';
@@ -258,7 +259,7 @@
String _getJsName(mirrors.DeclarationMirror mirror) {
for (var annotation in mirror.metadata) {
- if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == "Js") {
+ if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == "JS") {
mirrors.LibraryMirror library = annotation.type.owner;
var uri = library.uri;
// make sure the annotation is from package://js
@@ -700,7 +701,7 @@
}
_maybeWrap(o) {
- var wrapped = html.wrap_jso_no_SerializedScriptvalue(o);
+ var wrapped = html_common.wrap_jso_no_SerializedScriptvalue(o);
if (identical(wrapped, o)) return o;
return (wrapped is html.Blob
|| wrapped is html.Event
@@ -819,7 +820,7 @@
static JsObject _jsify(object) native "JsObject_jsify";
- static JsObject _fromBrowserObject(object) => html.unwrap_jso(object);
+ static JsObject _fromBrowserObject(object) => html_common.unwrap_jso(object);
/**
* Returns the value associated with [property] from the proxied JavaScript
@@ -858,7 +859,7 @@
operator ==(other) {
var is_JsObject = other is JsObject;
if (!is_JsObject) {
- other = html.unwrap_jso(other);
+ other = html_common.unwrap_jso(other);
is_JsObject = other is JsObject;
}
return is_JsObject && _identityEquality(this, other);
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index 26d20f4..b9ce88a 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -24,15 +24,13 @@
LayoutTests/fast/xpath/attr-namespace_t01: RuntimeError # Dartium JsInterop failure
LayoutTests/fast/xpath/py-dom-xpath/abbreviations_t01: RuntimeError # Dartium JSInterop failure
LayoutTests/fast/xpath/py-dom-xpath/axes_t01: RuntimeError # Dartium JSInterop failure
-WebPlatformTest/custom-elements/instantiating/isAttribute_A02_t01: RuntimeError # Dartium JSInterop failure
WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-001_t01: Pass, RuntimeError # Flaky with Dartium JsInterop. Seems like timing issues in the test.
LibTest/html/IFrameElement/IFrameElement.created_A01_t01: RuntimeError # Issue 24568
LibTest/html/Window/document_A01_t01: RuntimeError # Issue 24585
+LibTest/html/Window/requestFileSystem_A02_t01: Skip # Issue 24585.
[ $compiler == none && $runtime == dartium && $checked ]
LayoutTests/fast/css/style-scoped/style-scoped-scoping-nodes-different-order_t01: RuntimeError # Dartium JSInterop failure
-LibTest/html/Window/requestFileSystem_A02_t01: Skip # Times out. Issue 24585. This also has an untriaged dartium failure, in the section below.
-WebPlatformTest/html/browsers/browsing-the-web/read-text/load-text-plain_t01: RuntimeError # Issue 24585
[ $compiler == none && ($runtime == dartium || $runtime == ContentShellOnAndroid) ]
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba4444_t01: Skip # Issue 20540
@@ -241,7 +239,6 @@
LibTest/html/Window/moveTo_A01_t01: RuntimeError, Pass # co19-roll r706. Please triage this failure.
LibTest/html/Window/moveTo_A02_t01: RuntimeError # co19-roll r706. Please triage this failure.
LibTest/html/Window/postMessage_A01_t01: RuntimeError # co19-roll r706. Please triage this failure.
-LibTest/html/Window/requestFileSystem_A02_t01: RuntimeError, Pass # co19-roll r706. Please triage this failure.
LibTest/html/Window/resizeBy_A01_t01: RuntimeError # co19-roll r706. Please triage this failure.
LibTest/html/Window/resizeTo_A01_t01: RuntimeError # co19-roll r706. Please triage this failure.
LibTest/isolate/SendPort/send_A01_t01: RuntimeError # co19-roll r706. Please triage this failure.
diff --git a/tests/html/html.status b/tests/html/html.status
index 0741675..893d8ee 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -13,8 +13,6 @@
mirrors_js_typed_interop_test: Skip # Dartium JSInterop failure
cross_domain_iframe_test: RuntimeError # Dartium JSInterop failure
-custom/document_register_type_extensions_test/registration: RuntimeError # Dartium JSInterop failure
-custom/element_upgrade_test: RuntimeError # Dartium JSInterop failure
indexeddb_2_test: Fail # Dartium JSInterop failure. Identity preservation on array deferred copy.
js_test/transferrables: RuntimeError # Dartium JSInterop failure
js_test/JsArray: RuntimeError # Dartium JSInterop failure
@@ -24,7 +22,6 @@
[ $compiler == none && ($runtime == drt || $runtime == dartium ) ]
worker_api_test: Fail # Issue 10223
resource_http_test: Fail # Issue 24203
-js_dart_to_string_test: RuntimeError # 24584
[ $compiler == none && $mode == debug && ($runtime == drt || $runtime == dartium ) ]
datalistelement_test: Skip # Issue 20540
diff --git a/tests/html/js_array_test.dart b/tests/html/js_array_test.dart
index 58d42db..598cadf 100644
--- a/tests/html/js_array_test.dart
+++ b/tests/html/js_array_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-@Js("ArrayTest.Util")
+@JS("ArrayTest.Util")
library js_array_test;
import 'dart:html';
@@ -159,7 +159,7 @@
""");
}
-@Js()
+@JS()
class PropertyDescriptor {
external get value;
external bool get writable;
@@ -167,14 +167,14 @@
external bool get configurable;
}
-@Js()
+@JS()
class SimpleJsLiteralClass {
external get foo;
}
class Foo {}
-@Js()
+@JS()
external callJsMethod(List array, String methodName, List args);
callIndexOf(List array, value) => callJsMethod(array, "indexOf", [value]);
@@ -189,73 +189,73 @@
callListMethodOnObject(object, String methodName, List args) =>
callListMethodOnTarget([], object, methodName, args);
-@Js()
+@JS()
external jsEnumerateIndices(obj);
-@Js()
+@JS()
external bool checkIsArray(obj);
-@Js()
+@JS()
external concatValues(obj);
-@Js()
+@JS()
external concatOntoArray(obj);
-@Js()
+@JS()
external repeatedConcatOntoArray(obj);
-@Js()
+@JS()
external bool everyGreaterThanZero(obj);
-@Js()
+@JS()
external bool everyGreaterThanZeroCheckThisArg(obj);
-@Js()
+@JS()
external filterGreater42(obj);
-@Js()
+@JS()
external forEachCollectResult(List array);
-@Js()
+@JS()
external someEqual42(List array);
-@Js()
+@JS()
external sortNumbersBackwards(List array);
-@Js()
+@JS()
external List spliceDummyItems(List array);
-@Js()
+@JS()
external List spliceTestStringArgs(List array);
-@Js()
+@JS()
external List splicePastEnd(List array);
-@Js()
+@JS()
external String callJsToString(List array);
-@Js()
+@JS()
external mapAddIndexToEachElement(List array);
-@Js()
+@JS()
external reduceSumDoubledElements(List array);
// TODO(jacobr): add a test that distinguishes reduce from reduceRight.
-@Js()
+@JS()
external reduceRightSumDoubledElements(List array);
-@Js()
+@JS()
external PropertyDescriptor getOwnPropertyDescriptor(obj, property);
-@Js("setLength")
+@JS("setLength")
external callSetLength(List array, length);
-@Js()
+@JS()
external getValue(obj, index);
-@Js()
+@JS()
external setValue(obj, index, value);
-@Js()
+@JS()
external callListMethodOnTarget(List target, object, String methodName, List args);
-@Js()
+@JS()
external newArray();
-@Js()
+@JS()
external newLiteral();
main() {
diff --git a/tests/html/js_dart_to_string_test.dart b/tests/html/js_dart_to_string_test.dart
index f702d6b..5293053 100644
--- a/tests/html/js_dart_to_string_test.dart
+++ b/tests/html/js_dart_to_string_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-@Js()
+@JS()
library js_typed_interop_test;
import 'dart:html';
@@ -22,7 +22,7 @@
""");
}
-@Js()
+@JS()
external String jsToStringViaCoercion(obj);
class ExampleClassWithCustomToString {
diff --git a/tests/html/js_typed_interop_test.dart b/tests/html/js_typed_interop_test.dart
index fb69069..04915d2 100644
--- a/tests/html/js_typed_interop_test.dart
+++ b/tests/html/js_typed_interop_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-@Js()
+@JS()
library js_typed_interop_test;
import 'dart:html';
@@ -92,7 +92,7 @@
var a;
}
-@Js()
+@JS()
class ClassWithConstructor {
external ClassWithConstructor(aParam, bParam);
external getA();
@@ -100,7 +100,7 @@
external get b;
}
-@Js()
+@JS()
class Foo {
external int get x;
external set x(int v);
@@ -114,7 +114,7 @@
}
-@Js()
+@JS()
class ExampleLiteral {
external factory ExampleLiteral({int x, String y, num z});
@@ -123,12 +123,12 @@
external num get z;
}
-@Js('Foob')
+@JS('Foob')
class Foob extends Foo {
external String get y;
}
-@Js('Bar')
+@JS('Bar')
class Bar
{
external String get x;
@@ -136,7 +136,7 @@
external Foo getFoo();
}
-// No @Js is required for these external methods as the library is
+// No @JS is required for these external methods as the library is
// annotated with Js.
external Foo get foo;
external Foob get foob;
@@ -149,17 +149,17 @@
external Function get returnLastArg;
const STRINGIFY_LOCATION = "JSON.stringify";
-@Js(STRINGIFY_LOCATION)
+@JS(STRINGIFY_LOCATION)
external String stringify(obj);
-@Js()
+@JS()
class StringWrapper {
external StringWrapper(String str);
external int charCodeAt(int i);
}
// Defeat JS type inference by calling through JavaScript interop.
-@Js()
+@JS()
external confuse(obj);
main() {
diff --git a/tests/html/json_helper.dart b/tests/html/json_helper.dart
index 15f92c0..7d037ae 100644
--- a/tests/html/json_helper.dart
+++ b/tests/html/json_helper.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-@Js("JSON")
+@JS("JSON")
library json_helper;
import 'package:js/js.dart';
diff --git a/tests/html/mirrors_js_typed_interop_test.dart b/tests/html/mirrors_js_typed_interop_test.dart
index 1989ba9..a34bf1b 100644
--- a/tests/html/mirrors_js_typed_interop_test.dart
+++ b/tests/html/mirrors_js_typed_interop_test.dart
@@ -23,10 +23,10 @@
""");
}
-@Js()
+@JS()
external Foo get foo;
-@Js()
+@JS()
class Foo {
external int get x;
external set x(v);
diff --git a/tests/html/wrapping_collections_test.dart b/tests/html/wrapping_collections_test.dart
index dc84508..176bcad 100644
--- a/tests/html/wrapping_collections_test.dart
+++ b/tests/html/wrapping_collections_test.dart
@@ -1,6 +1,7 @@
library wrapping_collection_test;
import 'dart:html';
+import 'dart:html_common';
import 'dart:js' as js;
import 'package:unittest/unittest.dart';
import 'package:unittest/html_config.dart';
diff --git a/tests/standalone/io/certificates/client1.pem b/tests/standalone/io/certificates/client1.pem
new file mode 100644
index 0000000..9b4601d
--- /dev/null
+++ b/tests/standalone/io/certificates/client1.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBzCCAe+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9jbGll
+bnRhdXRob3JpdHkwHhcNMTUxMDE5MTE1NTEzWhcNMjUxMDE2MTE1NTEzWjAQMQ4w
+DAYDVQQDDAV1c2VyMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKTH
+xIsQGP4MxyAt8Jv4TgOXEvWAEBjMglmw0xULTUDXZ+tj9+1M6kwU11E/DNXjnPep
+zEgq6nX2BgQWCba6TBilOqjU/hiiz1Gm5+9jaW82SByMj+9FpsVyp3Gu3ujwYFYz
+wU5PmRUCR4WTFhy06cdq4F0+ci7q0s1gIJ6UHKS41/39srKkdmNiPeIai6ZIuv8v
+lgBxMv3HShxde4w7yDkJ7mzuchSHgGyH3EpjycbqfZOLeuGqdWfVOPsM/38y+NeC
+DwowrqA5SrdWGtJhpsN5GGmVYO0qQZZtCu1oruwduqTx6nMBWkyFCQCMJ8HwShpG
+q2X0DSfT5BQNrGyTHqECAwEAAaNiMGAwCQYDVR0TBAIwADAdBgNVHQ4EFgQUpiY9
+3N5Ylof6MW814xa/CyDxokswHwYDVR0jBBgwFoAU/ZBUqBvh6hb/ZNWYS43nch78
+vz8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAJDBCztQ
+xGY+QGycWrIEPC66ss2WgjPp9cU/56IggfX5YN0YG03vItYlFqm4wufL9PF5YJ2y
+hd5by0tzUmL+Y6ZKYAdzffBjHk//8hdGxsNy/6KLLDbwRycWXq0Ywo5BnGTwJcpV
+m4VTaddYUk8nDTWCf6JYQMdFfF0LUziVUsyJF21CDiAXPCTSA4aSAy5/OhRTUzXn
+1MX8yZRgY//7sNz2nqEvuHD3uJWmDHm6//qzVI9fPlwh8++0NM7WKUmDf4Ehx1ix
+Fen2k/uWJUDqb95T3IeF/COJ9FAsO3pd+cpqwzYcd2H5ZMGZI63Za0r3ypSTzSGc
+tO8Mp8b4fDVltvc=
+-----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/client1_key.pem b/tests/standalone/io/certificates/client1_key.pem
new file mode 100644
index 0000000..d319a72
--- /dev/null
+++ b/tests/standalone/io/certificates/client1_key.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE5TAcBgoqhkiG9w0BDAEBMA4ECGrn0qDVIUHAAgIIAASCBMNOid1sDMpZtXY5
+hySSdhyUB0Q+GEJZCJQoNIQBvlStUX3rUqUyWy+8Mb0igbUQznLALrmfDCFrPAbe
+lY9hiJKO5R4vhwWUOckT6LcejgG1U91EZF8s4iu0Be9haCHeu1gbhGNZw4exXIHZ
+aL/o0r+A6uQTGY4pTWcMajWu3cx9XiQ/dUDNBZjjUZg5qBYzQgNcNwzIxcD5M/qT
+C7Is3ngJWyEFESwo8PiZ0PsiudNXk2aRYdKSU+ncugUCvyYArxRgysLTJX+eP4ak
+s1za71JxXBpqNHSEHyexeJODf7V1NT16aHXuAzz/Tszdy8vv/SqrrV04NeQmJd8K
+2SPOfRAU8Kh8OvdSor9SWujwlEuawCxn7rCyjAA/brR2SQHvMkbkkwO80X1gLvGI
+haF06C/mVcV5xaa9I2UiTb8VBgEEodANIjbeYq+DyWOLXKkcJhdqG3DTljnebp+9
+7/P9m/VnvfZz7//2y+U9HOrpPQs0+FsUD2S1/XdjRozOPY2+knTtwvX+tmnooll8
+dGFRPYnWl/4AzgGp0KzbfGnCiwtGCJNbLzgH0jAR3Znu5xPrOtU3rCPy+rskuNQB
+JVcjdudPiGT/aABs4QWZauqAiaUE7BKhperORAhoFFkvboyvIjSLCOTn8f2+YEaW
+bIGS7EYCVdSRchOMubf7EM1CYugCZw4gN2NifP1PBfnSJoZrbAWK5ZqK++THGP8l
+uIIDdelIsZ5lB1OVTfVrdRC2LA6kUdus8a+ATcHhmgHOAaGH5Sj6hEJjtBSVF4Tm
+JdI6PIIS6MFWrIEP1AHU1zXztpOZkm4f5poyuFfWROiFQbua6y6H1tBiqh8xEs6x
+2pDFlSmGdswC9ejvokea5tOMC86U4syRfkE3Mw3kmAOTdNvZsWGv/C6yBcbMw8UO
+aLWjZI3Uwh+Lh1PMayckk2sxm+bnfsa75ITJc8E4fZC8UYF+dUjgpQU8Tb61lo+J
+sZaGQTYmai8p0FKcKvikQbEKOsmQQAAGuvNgaWlP/gSMzR3JjOf4ULVBfFIaW9qA
+UwvgbUEh3YQlQW4aHs5tGWyUjkHOEPCv9V1zDeEfNQ/f76xK826jVg2EEFahUNAI
+ZP+Isl0QVjPPMVo61U4FHWYo4NdRaHD27tVh25wAjXe/7sCPHrgn4A6qtSWbVuFw
+CJUGiC1zt9qCe3M801hQOJc1Re/hjcZ7sk08dYp3GGP0+ixGzwtAaStOVKLnCq79
+Uv+BWcu/NxUqDpynoO3uh+yGx5WChySXkhY+m9zgXrZelwErGuOYUG58Z4zRKkiz
+Qxnp9yxl9iBabpoPbR+4VjJbIO2cKKtWfaDtf35z6bbsddrKS2BPKtsFTCn06b80
+eCJpn9ewF4MASyCgQjSFVTMvNZWB1fLTb6Jl6/+deh8Sd2AF1Ks45j+ckxWMGF4L
+KIn8hK6Bi9KdgqJna8pKKB4h0U2s9K3IFB11YXQ5uDHO4TXmXz2LXLQNgjriF0RM
+ZUSphNRNC5JX/2uwmiO3HqrBjoiDDWWkt0TALDGjspaiYGSjfOnuI0SSM28RP/NZ
+f4KPRO8QhMBo8Mg5LrK7uHu+vVeIeC3qEeTBtiy33QypxKZpd0k1UwBDeGOZPgM6
+dwOrZv5D4qob
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/standalone/io/certificates/client2.pem b/tests/standalone/io/certificates/client2.pem
new file mode 100644
index 0000000..2898b7a
--- /dev/null
+++ b/tests/standalone/io/certificates/client2.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBzCCAe+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9jbGll
+bnRhdXRob3JpdHkwHhcNMTUxMDE5MTE1NTEzWhcNMjUxMDE2MTE1NTEzWjAQMQ4w
+DAYDVQQDDAV1c2VyMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPXU
+3aFyhBspz7k2QfrykxkMR07uC7uulmXgRJvNjNcJ6GrA5d+oRGqXH+czO6Wd2KdV
+mrwxCR3mpzNViwUC8DeG22+QagkVG/MY3lq2oxADpCNEXUdWnieG6bZ7/bk1xGU9
+Kees4Dac0evBZoZINTulat28pwms/+k4hCEqIh9ikR5hOwyVTVXryTrpnUwrRKWc
+LDrtOhcTnsKD0ooJLl4X/OGkjTGmDlppLgiumF+gJC0fG0ztScFC/m+u3dlMNNTq
+tLFV7jpuknY9mZeIVHHNLGZG2ndWHpzAHj+suvQxYwiUs5zY90ZsDbdYms4GIF8V
+Bf26/nns7MkD9+yl8WcCAwEAAaNiMGAwCQYDVR0TBAIwADAdBgNVHQ4EFgQUAuH/
+tf79clRyfVDepfCubNTGudwwHwYDVR0jBBgwFoAU/ZBUqBvh6hb/ZNWYS43nch78
+vz8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAEbWKUUT
+U6nK4ZfRo2x8vOHLK802aKHaiCjtG2JGH5iEl1hHwS1Qtf33Sv86V4SqpM+gwN1k
+2eWd5Yb2WsVmOsoxGwazYcH/G2G43/WImUk4oyeDKEW/ZSyXhyovHADkeI5nfJKL
+hcjLApVtw2RRVbG7qlGEOMS1FbDdbY0D8lFeX137Kqrbb4iV2+PQYM9TBrm/Tb6k
+2t4VS+0+QOkYH5vehUJAxOrJgIelcM4XsdKdVdhOZBPoxv+wptsBh+XhfxyHo8ff
+hcx+AbjxAxBo/uffngQW7ae5LbZIEUG7ERPmnuuFtJ1GgITA3Se0wJnPE8pEnbIc
+HJJsyEEspfKp09w=
+-----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/client2_key.pem b/tests/standalone/io/certificates/client2_key.pem
new file mode 100644
index 0000000..029ee6e
--- /dev/null
+++ b/tests/standalone/io/certificates/client2_key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIGKwU47HxW3UCAggA
+MBQGCCqGSIb3DQMHBAg92EmnGIvChwSCBMindKIgxnxh823tDdWq1TkjJg82SFNs
+4SX2T/TIuSEwZTTfDLxStdFfu/O88x4ZfOc1H1u4ph7geJgHadf8+oCQLXcofzPS
+86iNvaaJLoycWAUkgGKS3PqtvZ+QJYnKnOs0YlocZUk1C/gfWB+xApoWDzHUgsVC
+HQcAako8scbj15dofplgUSiN2a79WfZqbxupLkky9Kz97dC4cgcSOmPA2eSQ4Kct
+exRyR8M8tv6d5l4avmzONf7T++zFkM4EiG5+F8+skDZchuYrEYAsej5hKDAIMnFB
+rwZPxcyYTABuS4zoobAAts5S0f2Vy/OoaxsFNu6pvUncZ7Kmqkkopn9+5W1PeYyO
+p0d8607AbLCLcr16qnda87gpcaXX7rZ2WROgZrZcubg1N3jjYM44ZlsZYr4gHIdY
+kUwrgJqjdjJ0EZp9RQCkdnC50H24aMG4oq0LuuhLRbgwDny5T+NNVvfgVxCgNg+4
+hCTGBud3PCfDUoFGq1M6J2e1kfgw0FikJL41LGGOpvIo22MDR0lPHOkl6ZeO2ARt
+hlhtMl7wGKJE/ToxhbfRCLz9lSsG2wbGgB1wSAXAZcDlVN4QB9/Xtn71LObs6zE3
+kG8MfRzqiFZWAsLgTiprJagq4ylFvrGLW+pptnaI8A4IVeNy8nYe4I/UslvaXYrZ
+qh4U1rx2HuOUQQo4KtKnLN2zEW86bOEFHb284TW+aavFf2lq3zU31MboSEB7X/xd
+kRDKSqrVmZbnZRSVhhqtush1vAnETbSjGxZrUvHcaHU3RcIg1pAnBFGDWosNH7MD
+Sd2pDnGrJp8P04ftR+B97CNIBmgG+5SKt196oCO0gq+ROyspSYknlcnvGruQBANk
+qMzEBsjKgcDKc0XbnSM8gB6Rwv1/mxsZy+xd27DwdEfxNZqvbugZqr1gy4HowssN
+vhbfKUE7STcur4SDGuDYSC6U2jaebgV2SIHYod+kG0AI0Xo6CwpRHQjNPwOjwzKc
+U2pRpBRtHNBATj0jeP5p05+bUGd1RYj76Qy8oeN4C6DAd/XAGgVMgCpBUsSzDMVA
+sX7b9WYrgKF4JXKQrCBKcxJKzAGwASVjdfWDtxjvN1wqy2aj4ToW+ImMvgPf0g+L
+8JqAj7elkUOs2t6LxvQEViMFHmIxXweCLtAovEKVSMdYSPEwzBmqU5l++xZHx7kr
+KYowT6sfUEJ0A6JH7SMYJndNwKyYr2FLGTfkL0qcxwlOmrCVYy2yFN3F3bdQIfNa
+2FKu3hPR6LgD1Vl11HQyu015cv/LGTukkHZUAMruyYQTBGlY/Fym0xrj8tvsU8sP
+ZHhauOhg8kg7GR4FoRLc9sS5M3bY9JHd390PISFnGenE1iVqEp7BzMV4mUelFIP7
+OzWzufiRmsAzlIt2sR44cv4BKZfgsO4l7qsQTYdn+3e/dEfWXZ0aOd5jJ/M+T2Y5
+7lAdLnY2tapxEQy/KRasdGPbzCQH8l84zGV3uoAfIxpIkFaQpRRd0053e9cZWras
+3Dj4J59Q4SUsKJeH5muXCKoFUBPkVS1g8qIJk4Y7I2XRKICskK0DYvmL62tP0Aas
+rC6qjEv8HOV6kRBt6VCzt3nFYqodPFUNdmGYh9tuidaAFPt9CBg6I78IpiB9JoxS
+YrY=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/standalone/io/certificates/client_authority.pem b/tests/standalone/io/certificates/client_authority.pem
new file mode 100644
index 0000000..4bd5d3b
--- /dev/null
+++ b/tests/standalone/io/certificates/client_authority.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDKjCCAhKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9jbGll
+bnRhdXRob3JpdHkwHhcNMTUxMDE5MTE1NTEyWhcNMjUxMDE2MTE1NTEyWjAaMRgw
+FgYDVQQDEw9jbGllbnRhdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDDUuYMDCw7aXr++mXOcSr57uKhpriDN4He73Lz6r1jRg43nx/yCj+I
+rlOUd4kAZcMOv67W3oitzTlLER2pIFWLvG9GwLcgXtoiWD9wyHOod75cc4qjdRz1
+QRTPBqPXOHfe20Q3csR06Z6TM70cGFad+q4QIKK0Q4M4OnD3Rn935dtd4JbfiWXM
+w8h2XagjEqDWhZCIWJr06D7Wn6b1H3ch7o7M/TvjvUoyRnrfmTWHuIiETcpHXQXX
+nNfyrmaNyvJTE+HFknirVEkyMUzNao7CLecWD74NDRDZBQieSJQsu7oiucAvhBZY
+GblIv3Mv15cs2QkIN5JNN1+jl8LCImQBAgMBAAGjezB5MBIGA1UdEwEB/wQIMAYB
+Af8CAQAwHQYDVR0OBBYEFP2QVKgb4eoW/2TVmEuN53Ie/L8/MB8GA1UdIwQYMBaA
+FP2QVKgb4eoW/2TVmEuN53Ie/L8/MA4GA1UdDwEB/wQEAwICBDATBgNVHSUEDDAK
+BggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAWBF95hJRPEfV4S2wAAupnr4s
+8nQeVb2ANnALEX1prwr/xQM6DY+cLasHH84Vp47KH10DOiCxJGH7xlUVlVx+PWzu
+EGNDiZINVyFkXytkpiKG0/jd+0jR1lnmUp1WU1Zli7uRNxFRsy0G+tsgaoD2gvk7
+14zx2en1/1beGL4lRoMLJ5yVdiSRjt/H37ZPjVtCHiHLRfernCPy6rj1KtmdL+gC
+C8Jr3I+haXvEFr9vMbNUY6PwkdJ1xITs7CTjXFZ2bka/Glnfqzg1KavkI3WsYq8R
+mFniNvRw74z/kNrcxT/W956vsD+74OFI6BoeNi8acw7J+zvYjIWUo5h3BcG8Eg==
+-----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/server_chain.pem b/tests/standalone/io/certificates/server_chain.pem
index c653fca..ff6e568 100644
--- a/tests/standalone/io/certificates/server_chain.pem
+++ b/tests/standalone/io/certificates/server_chain.pem
@@ -1,57 +1,59 @@
-----BEGIN CERTIFICATE-----
-MIIDPDCCAiSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVpbnRl
-cm1lZGlhdGVhdXRob3JpdHkwHhcNMTUxMDEzMTQzNDQ0WhcNMjUxMDEwMTQzNDQ0
+MIIDZDCCAkygAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVpbnRl
+cm1lZGlhdGVhdXRob3JpdHkwHhcNMTUxMDE5MTE1NTEyWhcNMjUxMDE2MTE1NTEy
WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQDgGEoJKUJIo0nICRkMHWmXyZcQa4j4TIRndtH7HS6Z/GDQpo849zKU
-l8lAql+BuOv0ridXz5qnaspNFyw2QgxH6Yc69V1CM5pBfF0QwJccG/Z4WbVZTSK7
-+ED7t4qm3VPTvjHFjKaPXhwQFItPwkUq5vPomNeCYEKaDWHHuffwFLwN0kjv+6YI
-3vyZmcij7Rhf76K3EV4kJowKcIfSQ8qs9Ts8PkRmJRtYXp0sHuRhgl+cmn6i6yNp
-ebVZN2oD4EYQzijPCF9amUwjkOKqyHqXdf8tq+h0sVVQJddUf/abLa3UB4km6pvF
-QLm3jbhq0isP6zVjMVO47vnX5AjrJM9LAgMBAAGjgYwwgYkwPAYDVR0RBDUwM4IJ
+ggEKAoIBAQDca2l3VIWhnlTqazrA07hiHjgXACUYS/nVox+a2Jar383kBz2kzN6B
+u4K7IwD2msym2IOBp1YT9OKPh9/KkSGvpPelu7ToCoehala32W+0ozh53CR8IpzQ
+tmh7J9oHtN2PcbLgEzHfAWyrY3xp9RpWUONjxoG8xXPedNsZL0Rj65Z3fKAjOypl
++XJsgrqrNNAi3x0OMdhextMmLrYl+YQjgdND8UpykTSc8Q0vwngDZuLH/Nhx0cAA
+Ade0ZfXS6snwWVxrWke+zGF6yANoiV00gsBhq+WZZ50SmE2mz5LT9uj4t5WpcOI/
+2TlbV9HSjdOEAFD8cJIrK5FkEmz383E1AgMBAAGjgbQwgbEwPAYDVR0RBDUwM4IJ
bG9jYWxob3N0ggkxMjcuMC4wLjGCAzo6MYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAA
-ATAJBgNVHRMEAjAAMB0GA1UdDgQWBBRZ8+LQg9nfOOv1RaqPI9nrvbBufjAfBgNV
-HSMEGDAWgBRqwKMjCmov/0owT8uQJYA+aHX5QTANBgkqhkiG9w0BAQsFAAOCAQEA
-TJA1aeexRpyq2G81igrhtVysyCA2xBq3GEPHZNf6+YM65rJs8ngyLQ533JURy9QY
-hRHYYh4O387d6QUBpCH7QMCoO/IyhFnYaUsFuDi4Xfg0BY05uRj9oJlyhtOoPR73
-yFu3bK6CKyRjQ69HX+QpaJUADgRjuyDV6BAhq3oCfDghql1HBplCEJelcoZUs2xj
-Ao5Hw90mm03JgmPMkftEFIlsbBejPTIN7IhdNRJy3mJfY5r0g1MLAR8UHtCRTsxy
-AQkZjpVKPe8kKR1wCY9xsOYpIvruLUcbVayzM6iXVDwWApgT2x1qgIlRb9ZzTjdj
-WJVFf3HhnyLstIpI4Vw+UQ==
+ATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQO+6Atr6tkTBmPasN4oTDUlbxQ1zAf
+BgNVHSMEGDAWgBRrkK4hOni2neySWQNmMfb9imn/+DAOBgNVHQ8BAf8EBAMCA6gw
+EwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBACdVUzrhfXoW
+wG0zI9aT6CxD7T0i0WK4fC6Yrx0Pqz53xnuiwBfvuAJ/PRXKYsJMxa2LuHGJKU/A
+nImCXGJHoUwL6x4Eor6fg7L9nPNqtIrQ6tzubxNtVPpLj4tK6Ps3IM+FICYUSX0b
+FLSfnv74afUp/2+0OHsoUVsL1rCTO2WgEkEShLERdJvdcvUSTWHfC5IQORS9vfzG
++cZGOOPebfm8TY2DJxMYj/t7CHs1Sk550x590sKb/prwtJAYtQxGe7v0m9rihiM3
+dFKZiNh99yXbQ1ELYyhkFP8WAdK8ZTnynGqgAYJmV89Dg8k2uU8z+dahlE3foORD
+Y/Gn0CZE1NY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDAzCCAeugAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
-YXV0aG9yaXR5MB4XDTE1MTAxMzE0MzQ0NFoXDTI1MTAxMDE0MzQ0NFowIDEeMBwG
+MIIDLjCCAhagAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNTUxMloXDTI1MTAxNjExNTUxMlowIDEeMBwG
A1UEAwwVaW50ZXJtZWRpYXRlYXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAuas8jPtdCT4lahfVYHBrmUlFAvfKa5odZ7XqJ6TRMfzuoV6a
-51H6L90GToMFBOvcf7qzsdw9y07rS61mGfK4c7BifsiMbm+2DNvnKwVqH7d6FVYN
-oHYgn3FqBzCebsE8f8LD+YE+XC3JPp84QnE5jhv422rPp4FnugjK5xIpQuhRa0GH
-CVBpEe9Sq/KQXHW0lKcVLAL4eHrupdRdNJjDaVT3ZzCwUVHeBdQtkc8ZH/64H0KA
-+G+W+Bl4NPCqdLUCUwSn8RGxYj2Su7RZNvD2leyW1GtIbztztaSLbKZ48ZnjNnzg
-C5J3T6kqNXsJExDm6gh5GxIndUjaQ20SB+XfWwIDAQABo1AwTjAMBgNVHRMEBTAD
-AQH/MB0GA1UdDgQWBBRqwKMjCmov/0owT8uQJYA+aHX5QTAfBgNVHSMEGDAWgBQf
-nG+qRtaEj/s3oh1Yrf94203UFzANBgkqhkiG9w0BAQsFAAOCAQEAYr/qbcG6WybE
-TB+8UU1eN06tXvSGL1mtNlMcjyFc2PZDsdo+XjehXBqyF3k6raCJAdttiyjHlalj
-58D6F1IK1x/c8CNS5WxOEBjkTwy8KMK1vpggYO+lvkjJQL9RGns0fKrsdYexCPtn
-iKmcRWgfJWs/mT5LmxBsufYxIvAAuzjJNMrmrxAbComJvcjbJPf8rPqMLmnYoV20
-ufSK5euF3CCbtKUXQuqR2XY4kX+hmzuu7UGyOvlUXSa2J6aGTsutU0KRWlsisiTh
-ts7qtG/pzVEEYs71dTL6OmXGjxQFmtsVHZog/ybNVYP4Mvz5eA+SkaiUPrM/x46F
-YzNX6fPCwA==
+AQ8AMIIBCgKCAQEA1OV9iea75DPQ18NppXxEFW26J7IfjUvp4wVnj9m7pOhsByqd
+wwS6hpjlkpEwCyugKD/t7u/VGwp2BB+BeaX7FPj6rnYY82bOJQlyB/vvDmOZfAe2
+84ug9O7QcsQHSQ7YQFuvYKaeYCKdrGjzQPVYkoVdv2js2dYTDG3QSIxpbi305Vef
+ia6Zfs5CAW/SfL36+ETo2pXNlD1ZBGRL8H3z+mMnIEj1Tbaipf+1Npr2l3xqIs1k
+RWsM3X+9xMkWGyvsDdbLIGiTTVxM9kOF0aNLdQIKb2tZsg4jRrFIgiO+5TXwp0FW
+4ldc5/GhtaoPDcsIALyIQc7CJ/PpPm9hnxIy7QIDAQABo3sweTASBgNVHRMBAf8E
+CDAGAQH/AgEAMB0GA1UdDgQWBBRrkK4hOni2neySWQNmMfb9imn/+DAfBgNVHSME
+GDAWgBRpz+jRK9iGqijrL/4WCsGsIjxoETAOBgNVHQ8BAf8EBAMCAgQwEwYDVR0l
+BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBACcwiLJUPzYGIeGIYGlo
+XlP4++adiPlXvsyTxLdGVSFWJMBV5EhtiXQXaUsOs2PyC7SWxiiUdAgE8Y2tMsF3
+Bh5LY/kKxZQXZuFa+RN1kPlhlYJWdiPyqcBziSPFBtqwudWLDUVSaVAQDhYYVB3K
+5+pFaeQKfhYmPvJKR9U2nTvukOhN1fZM8GUBnm2uaiA3giQ0wxXyQIuqC9S52qbh
+x4D4ZdbshQAgThPkHBoZVmd/NF1TNzitZZy7uaU7GpGrS1dcevN7pEUwm3+KIkIT
+AOSLB2FbFOwPUg6a/lWkFPotT3gl0tdyCaqkfneGCHzVciT0JTS/AqpdYEtuxEMe
+PJk=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIC+zCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
-YXV0aG9yaXR5MB4XDTE1MTAxMzE0MzQ0NFoXDTI1MTAxMDE0MzQ0NFowGDEWMBQG
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNTUxMloXDTI1MTAxNjExNTUxMlowGDEWMBQG
A1UEAwwNcm9vdGF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBALLIFA1JvTuzPd0uD8uOxdGZmwlaRXyytqkQF66UGM+HLCmH6Vro5TpRL7Ka
-4fgEpbhS5purJqjpUiZkavxxBKQkdpxM0nH1lLX6NnR6UVh/Z3Tv6s8cR3o9L60J
-iH4N7hGdQH9Anz/PBXbshoMJqU+lZkOoqcmk4Tk27uxNlbpTLFoarm67hzqe4v/e
-xAfh4HoBZRVdnpWezM/7aX1hw2B2iFiU8pgyrVKZnXRhh4I6Ba1XTd37lc2d1fuf
-LaUICoAruR/ZhvRQaOtAN05dAHSOB9612WBBaEEiWzz/piEDEownZQ7NBWC5ANj4
-xRp7JPNtQtxYoju6j9MIJ4JoOQUCAwEAAaNQME4wHQYDVR0OBBYEFB+cb6pG1oSP
-+zeiHVit/3jbTdQXMB8GA1UdIwQYMBaAFB+cb6pG1oSP+zeiHVit/3jbTdQXMAwG
-A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAC8PKipPvbQ0TXBKCMnCZiPI
-Vs7IfZuEzOgV6VByqveXuN8WJA2+ax9+2t1xuyIgftjj/uNJgm82AceVZqAtkGF0
-n29mPyoPC2tcrPHV2QUXy26+Rfb2JTQkkHXUnRtgU+gqnqugh+r9CCjoM0XkvR26
-/OrOmy7JIHtGPq5JEH9L73UryKKdQ3HS0ZkOMfxRyMNBa0y2/hYW8QDz/m0a1U9z
-q1rLvtYXZKWhz6dJJrphF6iBDzm+r6zo+uyCU7mps5wlGB9h4Ez8nx/Af1iT0HPE
-cl5zOR0RA5qefGx0hIuaxq0mHEYDY/coJ2rptvHwcnwgtSXBaQLe6MMNP+ElYDE=
+ggEBAMDzkcftGzdNJz5vXEAZSCAO2J6bCPz896pK3qtaViR/aF8I2vHZQm0IEoJc
+Y1NUMF3F50d6fMYCkEoORAkC0d7iAwTprhBdIg35+TxwGObcStrohDtEgwFmFRzg
+LtYeXiU0t0dBWOOQ9k2f9VGqbzKwZ2dbhOHSTXMTFoEcMStbeFc++oiOLY+QSq/J
+Xd/BXqvwVM3Mt+OwLvyUu45Kw18ENo77qubIPJUwoyaf+N2nFRqcc7bmNy0Wvk2Q
+StvQXy6DpN3KOoZx/sR7Ff8hYuHXcxbSsJ1hOO+tIJyOZyEJvU2BBOYVlKr4E4JU
+mkex0CM1IfIFqfcEkbvjwLjaojsCAwEAAaNQME4wHQYDVR0OBBYEFGnP6NEr2Iaq
+KOsv/hYKwawiPGgRMB8GA1UdIwQYMBaAFGnP6NEr2IaqKOsv/hYKwawiPGgRMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJKl4RCEaXwtosNeurZlS3b9
+owXdsXDRdnfEawcc//AbRkrS4bHCQyOJNp/3DibEKkeAXCJrJ5cvXRjE5gb3Q+rl
+0AqziLY15xuMAxUK3zv0e8Zir21PQzQ9x8zbmlucEoT/jn7KvMSSqfEoer77cXev
+BpmQDQzE3FNgKohmHIzIDoTPiU3ahv6x8IhJ1e47UmRsSPFgtqglHcdCYIEclXpY
+bHvctT6+pFZuJfIs9+BATMXPJWSX7NhlMcnyP+xdDxDKuF/nwVFy6xA+njuWnnZT
+TyiGCnx+u/VpKzOrwMfzv2DW8Db80UERoox5n6QNQLnXNWPMddUL92/p9lMzWJY=
-----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/server_key.pem b/tests/standalone/io/certificates/server_key.pem
index 4486e44..29a9e32 100644
--- a/tests/standalone/io/certificates/server_key.pem
+++ b/tests/standalone/io/certificates/server_key.pem
@@ -1,29 +1,29 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
-MIIE5TAcBgoqhkiG9w0BDAEBMA4ECHTqlBo01lkOAgIIAASCBMM6W9ZnVX28yt1o
-m1qzZCpCpn7B116hWgk/qWnSBEeT2i+wUeG22fDn17/XrcWIJT58k0/FGWiQn4yT
-Cya55z9J3JKwC22+BVlUErBmlanfwEXbJOjivEvMqSLd98smmA+nw8fUZnFBqH+O
-3sokCiRxK5t/PrC8ahWk+H800e9cvAViewxBwZkUGClVivs/oPAmAhgd4aqWS8Aw
-G4Bi58mUK8dL51cxapWXBR0oxBnedyhElNwgiSoBxUqgEB4yjS8SMAAEy+UReRnf
-kkkc0jyQi7aDhyRvRIm6OX7x/KPys1n4ZdckgaThh+VHitj2rb5xu/g0fxCRL+8W
-o4hcgDgsbYhs61ATO/7xqEFGTUqiRGQa3IgCey2gRHFRKh24OvUBJJK30jGDpT8X
-M0jcIeQGbclzqODPoSfxL51F8wVpbwv5VnsvnsPunNCYCpB3rXNSHQBFs9aiEdfF
-YNGH8wk9AYuya8Ji92XZ6pMheAfhbR5E5JeEZfo1gv1ZDEYLKhrFX30YjekU8L2h
-lyJpr0+nGhIAeKuw1FxQnTiIdv5Hs8wmBsGuMDK/gYPklLONHRw/G99sqqd1wB0l
-CLEZ8PVO/63dpXqoTrDJIRCsVa9/wanoX8XD5zDGFA2OLGuz24u9xJbcERegM5us
-DEKTZz/4XE2t3dFUzsf9EtBl4CkxKT4o7R+Q2akADGWp6x72XW/1LiGhRtFOjhsl
-enS5DONUCXndG2Sc3GemO63hWjlBsUAcz1mvJhd8zVK5Wg/FM0j8lhf9yFnPKd/f
-+6gGnnhASjeoX/FlQl0Jm5J8++hmH0bXqfcQXIE+klUcSJOs0aP8byXndvfWmtKZ
-VoUFZL55MW2TeO1MC1jkVWu6QfTHWSC0g6Lz48MN3ASejsDa0/Wu+Z/Wowexd/ky
-Z+CHG5LMMULSl9LAAZzFLld0tt1Z/fPRsyWCl2km9+NIRHlKC3d8btkip6+3X8Io
-AVvLugD2HIM5Mkad7+CwQuS014aA69fCGl11Ei8slSvP7YlN4f9qX8ledWUFTSAb
-qTvHT3AkdDI9iuLXgjTE4/uxJy2vIe/OioxzdgrRMyJm+nP/yeYoudyAtFYwHTii
-omh4zoWeAWDFmI7MCwAGYI526QjFTcf3fg0Dg+dx1lqcjw5aTzqCnJ6TEQTXE/UH
-xpOtRuJUnA2dYNgtanoInu18HPxpKpJimpf2N64ZmAYuAdpaYuj7uV/7coYTINCP
-LbL0FTq5J2hRXBtCiTViTwPKHXvomiHuD38jRYJK87vWfcHrfus6AnFJ2w+S6DUw
-cHziCh0MvQG774nDAcpZAfumx7tA4qX92EwtETifRf5vA/AWzkkeu+su8Gyze3al
-3J9plGmZ+4V81rh188mWHFTBBThiIi6Tqm7iLO/YGDyI+9PWQT9nLSb/pCKk//ZV
-v0VXUEpLwW0Os7cMAkfgaddrjakuON4rQ9b1ixb8es7bJiYhyhUuPoopJ0nHNtNa
-+Wtt5LRe1M8lqt++Xy+pmL95woCdGhvATYI0W6JJWJVIluequkhI/iQp0TdG7LlX
-A67qzWPCUIjYl8w/ydPLXo0803UKUZWYJ01eWdDKB16BYFBkT7uJlek/DZAOOb7q
-6Wo1KF3SnMiD
+MIIE5TAcBgoqhkiG9w0BDAEBMA4ECKAry4fwmB/TAgIIAASCBMNsKbVVvIs/l6/N
+/1J9WXSiA1gnRTd2n58GJUV6mkiaRUMiWu3fK+V7iHpIi7KeLeD+JGsDeqxw0bB5
+lmS/RJy0wNBP0PL0oiI8VUe3wxTUU2b5wW9fomeOTGWOIUL5VZXHkTCf5KMcFWMY
+GMnDpIN/f/m9zvz/3FogxIZlIAxG7gKKrfEcKExIShAJ5wYDbDSFZWfNcjMODGPn
+xz3W04aRsJGf3KlOQvSuNtcBpsuwXuAXezzuFETM20xrWW3iJIsO5UmqJ1OJcdet
+A+k5k0K+1/WwLkceWJYSd19O+7LNULsZhKUJ515ZSO1TJGgfd5DznkgRXYUx5ucS
+tvJLYvShGbaYulsVKn8q2nkIxnQCov3my1hIRk/qCKb+uOvRD9dIkjSlNubqaRb6
+geEOfTh1g5PCeKPlSTkVueLQqWxKMye4eWYqUxExkUNuGJ0d2ndBGJRo6bulnc7I
+kt44DzEufV5OLvyTufimpohqRm3Yzq87DWSSThCKOGkhfGutn8B7cJR8ZPrG2euT
+J7Bv4EuFjhpKDieqDi8yoXgIkWSgyzFNMsewV4lxFNP/wbvoKPFrKsU4ny6jRfzy
+WTjMN1UOTBvsyZbVvjLII79cBKLqlowHAZQ7YwuxtbjeB9FRH+ZwkzYeyn4GNHdf
+QoVwOMKAiOMjzAK9qdW7isVXy/7v9EXaZplRmwMRhCZevC9zeY2Rueahq8qpHpH1
+GPjrew5elPkBRQhxX6IiL7kI7upE65UI5hnnTnrdrZkRmMYOFEZLyLbTU4wMCxui
+4BmEiGp6qCWe3UND1b8YhG+gsRYzHK5oEJV+Ck7m+e9iU3/axggUfAhZeBmdlgqd
+bUajlzcgbtfaSgZ08XXU1YPw0aLlmJGzb+oWMFwBJHAUYpOV2uqDHiXZZt4SoAF9
+gJQaXvqMGzY8JyP5ZQauljVtPGcopA+jbix3Rbwf97lLqJHSpWoHpcCa6FrfaMqG
+dx8oQsO67WN0gm5DIN3kB2jHOj9Nf7kr3HGjyC5tPq8s1+aT6baZcHWzVfyVr10c
+9X13Pz5XzEa1oiaO7JDPkzb9T7aPJZwskATNB8h6tWfqdGyUY5eURtsCnVrtG/1p
+pAXyY/0vAksfDPjMChKLKxZ7rBbscoNzr2f7Vw4CTnIpaxA4eLEx6UdpG4/5RzYJ
+0YuR+SzCkuNti7uZGi9DCGkZkYl6VndatW+Pk/+JVBexdKt6MsER6aVsS8ev9UbW
+JG+2C8bjMlfKy21644KwYOtZbVcE9jwlsz8w+e6YbOzBvbwiPmoCi0xcMxRJPa2y
+cKMrs2hSKmhUP6uIH0b0qNcHEPA32mVzGC0MToC5R+yb6OdyvoEsisqS7tEAMfTJ
+0yowcZr2lPehaMr4efSB8JY6DuofitfgI6X6bmiIPQ9v//djxhkxkRAbpTRGmFZx
+1YIKDa72S8jUxHWlVvmoqTWI8T+jltF2pYBctS6IMKEot/CcBCHb5l1zfMyo5a0x
+73ooh5tq+vRWJGaLRMj66VVSWGQoJmfAGwWpjBpTLa0UQoHO0/J1IbfjFOj5HV3J
+bscmoGWhVwuJM5ActB0MOvXGQe9mf2X4p/1Rp+yBuipH1SJzFEzbOZ3kE50Z6aXH
+CoJJOKkcuf43
-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/standalone/io/certificates/server_trusted.pem b/tests/standalone/io/certificates/server_trusted.pem
new file mode 100644
index 0000000..96649c0
--- /dev/null
+++ b/tests/standalone/io/certificates/server_trusted.pem
@@ -0,0 +1,57 @@
+-----BEGIN CERTIFICATE-----
+MIIDLjCCAhagAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNTUxMloXDTI1MTAxNjExNTUxMlowIDEeMBwG
+A1UEAwwVaW50ZXJtZWRpYXRlYXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA1OV9iea75DPQ18NppXxEFW26J7IfjUvp4wVnj9m7pOhsByqd
+wwS6hpjlkpEwCyugKD/t7u/VGwp2BB+BeaX7FPj6rnYY82bOJQlyB/vvDmOZfAe2
+84ug9O7QcsQHSQ7YQFuvYKaeYCKdrGjzQPVYkoVdv2js2dYTDG3QSIxpbi305Vef
+ia6Zfs5CAW/SfL36+ETo2pXNlD1ZBGRL8H3z+mMnIEj1Tbaipf+1Npr2l3xqIs1k
+RWsM3X+9xMkWGyvsDdbLIGiTTVxM9kOF0aNLdQIKb2tZsg4jRrFIgiO+5TXwp0FW
+4ldc5/GhtaoPDcsIALyIQc7CJ/PpPm9hnxIy7QIDAQABo3sweTASBgNVHRMBAf8E
+CDAGAQH/AgEAMB0GA1UdDgQWBBRrkK4hOni2neySWQNmMfb9imn/+DAfBgNVHSME
+GDAWgBRpz+jRK9iGqijrL/4WCsGsIjxoETAOBgNVHQ8BAf8EBAMCAgQwEwYDVR0l
+BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBACcwiLJUPzYGIeGIYGlo
+XlP4++adiPlXvsyTxLdGVSFWJMBV5EhtiXQXaUsOs2PyC7SWxiiUdAgE8Y2tMsF3
+Bh5LY/kKxZQXZuFa+RN1kPlhlYJWdiPyqcBziSPFBtqwudWLDUVSaVAQDhYYVB3K
+5+pFaeQKfhYmPvJKR9U2nTvukOhN1fZM8GUBnm2uaiA3giQ0wxXyQIuqC9S52qbh
+x4D4ZdbshQAgThPkHBoZVmd/NF1TNzitZZy7uaU7GpGrS1dcevN7pEUwm3+KIkIT
+AOSLB2FbFOwPUg6a/lWkFPotT3gl0tdyCaqkfneGCHzVciT0JTS/AqpdYEtuxEMe
+PJk=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC+zCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNTUxMloXDTI1MTAxNjExNTUxMlowGDEWMBQG
+A1UEAwwNcm9vdGF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMDzkcftGzdNJz5vXEAZSCAO2J6bCPz896pK3qtaViR/aF8I2vHZQm0IEoJc
+Y1NUMF3F50d6fMYCkEoORAkC0d7iAwTprhBdIg35+TxwGObcStrohDtEgwFmFRzg
+LtYeXiU0t0dBWOOQ9k2f9VGqbzKwZ2dbhOHSTXMTFoEcMStbeFc++oiOLY+QSq/J
+Xd/BXqvwVM3Mt+OwLvyUu45Kw18ENo77qubIPJUwoyaf+N2nFRqcc7bmNy0Wvk2Q
+StvQXy6DpN3KOoZx/sR7Ff8hYuHXcxbSsJ1hOO+tIJyOZyEJvU2BBOYVlKr4E4JU
+mkex0CM1IfIFqfcEkbvjwLjaojsCAwEAAaNQME4wHQYDVR0OBBYEFGnP6NEr2Iaq
+KOsv/hYKwawiPGgRMB8GA1UdIwQYMBaAFGnP6NEr2IaqKOsv/hYKwawiPGgRMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJKl4RCEaXwtosNeurZlS3b9
+owXdsXDRdnfEawcc//AbRkrS4bHCQyOJNp/3DibEKkeAXCJrJ5cvXRjE5gb3Q+rl
+0AqziLY15xuMAxUK3zv0e8Zir21PQzQ9x8zbmlucEoT/jn7KvMSSqfEoer77cXev
+BpmQDQzE3FNgKohmHIzIDoTPiU3ahv6x8IhJ1e47UmRsSPFgtqglHcdCYIEclXpY
+bHvctT6+pFZuJfIs9+BATMXPJWSX7NhlMcnyP+xdDxDKuF/nwVFy6xA+njuWnnZT
+TyiGCnx+u/VpKzOrwMfzv2DW8Db80UERoox5n6QNQLnXNWPMddUL92/p9lMzWJY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDKjCCAhKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9jbGll
+bnRhdXRob3JpdHkwHhcNMTUxMDE5MTE1NTEyWhcNMjUxMDE2MTE1NTEyWjAaMRgw
+FgYDVQQDEw9jbGllbnRhdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDDUuYMDCw7aXr++mXOcSr57uKhpriDN4He73Lz6r1jRg43nx/yCj+I
+rlOUd4kAZcMOv67W3oitzTlLER2pIFWLvG9GwLcgXtoiWD9wyHOod75cc4qjdRz1
+QRTPBqPXOHfe20Q3csR06Z6TM70cGFad+q4QIKK0Q4M4OnD3Rn935dtd4JbfiWXM
+w8h2XagjEqDWhZCIWJr06D7Wn6b1H3ch7o7M/TvjvUoyRnrfmTWHuIiETcpHXQXX
+nNfyrmaNyvJTE+HFknirVEkyMUzNao7CLecWD74NDRDZBQieSJQsu7oiucAvhBZY
+GblIv3Mv15cs2QkIN5JNN1+jl8LCImQBAgMBAAGjezB5MBIGA1UdEwEB/wQIMAYB
+Af8CAQAwHQYDVR0OBBYEFP2QVKgb4eoW/2TVmEuN53Ie/L8/MB8GA1UdIwQYMBaA
+FP2QVKgb4eoW/2TVmEuN53Ie/L8/MA4GA1UdDwEB/wQEAwICBDATBgNVHSUEDDAK
+BggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAWBF95hJRPEfV4S2wAAupnr4s
+8nQeVb2ANnALEX1prwr/xQM6DY+cLasHH84Vp47KH10DOiCxJGH7xlUVlVx+PWzu
+EGNDiZINVyFkXytkpiKG0/jd+0jR1lnmUp1WU1Zli7uRNxFRsy0G+tsgaoD2gvk7
+14zx2en1/1beGL4lRoMLJ5yVdiSRjt/H37ZPjVtCHiHLRfernCPy6rj1KtmdL+gC
+C8Jr3I+haXvEFr9vMbNUY6PwkdJ1xITs7CTjXFZ2bka/Glnfqzg1KavkI3WsYq8R
+mFniNvRw74z/kNrcxT/W956vsD+74OFI6BoeNi8acw7J+zvYjIWUo5h3BcG8Eg==
+-----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/trusted_certs.pem b/tests/standalone/io/certificates/trusted_certs.pem
index b037014..05470f6 100644
--- a/tests/standalone/io/certificates/trusted_certs.pem
+++ b/tests/standalone/io/certificates/trusted_certs.pem
@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC+zCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
-YXV0aG9yaXR5MB4XDTE1MTAxMzE0MzQ0NFoXDTI1MTAxMDE0MzQ0NFowGDEWMBQG
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNTUxMloXDTI1MTAxNjExNTUxMlowGDEWMBQG
A1UEAwwNcm9vdGF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBALLIFA1JvTuzPd0uD8uOxdGZmwlaRXyytqkQF66UGM+HLCmH6Vro5TpRL7Ka
-4fgEpbhS5purJqjpUiZkavxxBKQkdpxM0nH1lLX6NnR6UVh/Z3Tv6s8cR3o9L60J
-iH4N7hGdQH9Anz/PBXbshoMJqU+lZkOoqcmk4Tk27uxNlbpTLFoarm67hzqe4v/e
-xAfh4HoBZRVdnpWezM/7aX1hw2B2iFiU8pgyrVKZnXRhh4I6Ba1XTd37lc2d1fuf
-LaUICoAruR/ZhvRQaOtAN05dAHSOB9612WBBaEEiWzz/piEDEownZQ7NBWC5ANj4
-xRp7JPNtQtxYoju6j9MIJ4JoOQUCAwEAAaNQME4wHQYDVR0OBBYEFB+cb6pG1oSP
-+zeiHVit/3jbTdQXMB8GA1UdIwQYMBaAFB+cb6pG1oSP+zeiHVit/3jbTdQXMAwG
-A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAC8PKipPvbQ0TXBKCMnCZiPI
-Vs7IfZuEzOgV6VByqveXuN8WJA2+ax9+2t1xuyIgftjj/uNJgm82AceVZqAtkGF0
-n29mPyoPC2tcrPHV2QUXy26+Rfb2JTQkkHXUnRtgU+gqnqugh+r9CCjoM0XkvR26
-/OrOmy7JIHtGPq5JEH9L73UryKKdQ3HS0ZkOMfxRyMNBa0y2/hYW8QDz/m0a1U9z
-q1rLvtYXZKWhz6dJJrphF6iBDzm+r6zo+uyCU7mps5wlGB9h4Ez8nx/Af1iT0HPE
-cl5zOR0RA5qefGx0hIuaxq0mHEYDY/coJ2rptvHwcnwgtSXBaQLe6MMNP+ElYDE=
+ggEBAMDzkcftGzdNJz5vXEAZSCAO2J6bCPz896pK3qtaViR/aF8I2vHZQm0IEoJc
+Y1NUMF3F50d6fMYCkEoORAkC0d7iAwTprhBdIg35+TxwGObcStrohDtEgwFmFRzg
+LtYeXiU0t0dBWOOQ9k2f9VGqbzKwZ2dbhOHSTXMTFoEcMStbeFc++oiOLY+QSq/J
+Xd/BXqvwVM3Mt+OwLvyUu45Kw18ENo77qubIPJUwoyaf+N2nFRqcc7bmNy0Wvk2Q
+StvQXy6DpN3KOoZx/sR7Ff8hYuHXcxbSsJ1hOO+tIJyOZyEJvU2BBOYVlKr4E4JU
+mkex0CM1IfIFqfcEkbvjwLjaojsCAwEAAaNQME4wHQYDVR0OBBYEFGnP6NEr2Iaq
+KOsv/hYKwawiPGgRMB8GA1UdIwQYMBaAFGnP6NEr2IaqKOsv/hYKwawiPGgRMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJKl4RCEaXwtosNeurZlS3b9
+owXdsXDRdnfEawcc//AbRkrS4bHCQyOJNp/3DibEKkeAXCJrJ5cvXRjE5gb3Q+rl
+0AqziLY15xuMAxUK3zv0e8Zir21PQzQ9x8zbmlucEoT/jn7KvMSSqfEoer77cXev
+BpmQDQzE3FNgKohmHIzIDoTPiU3ahv6x8IhJ1e47UmRsSPFgtqglHcdCYIEclXpY
+bHvctT6+pFZuJfIs9+BATMXPJWSX7NhlMcnyP+xdDxDKuF/nwVFy6xA+njuWnnZT
+TyiGCnx+u/VpKzOrwMfzv2DW8Db80UERoox5n6QNQLnXNWPMddUL92/p9lMzWJY=
-----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/untrusted_server_chain.pem b/tests/standalone/io/certificates/untrusted_server_chain.pem
index 132c1f4..d2b585a 100644
--- a/tests/standalone/io/certificates/untrusted_server_chain.pem
+++ b/tests/standalone/io/certificates/untrusted_server_chain.pem
@@ -1,57 +1,59 @@
-----BEGIN CERTIFICATE-----
-MIIDPDCCAiSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVpbnRl
-cm1lZGlhdGVhdXRob3JpdHkwHhcNMTUxMDEzMTQzNDMzWhcNMjUxMDEwMTQzNDMz
+MIIDZDCCAkygAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVpbnRl
+cm1lZGlhdGVhdXRob3JpdHkwHhcNMTUxMDE5MTE0NjA3WhcNMjUxMDE2MTE0NjA3
WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQDHQhbVk4kfjfIBK19ALltfqiF5Swiq3qx0FRnwOKyKsDsxk1PCYcON
-rFO74V62AwVSfbxBPAKOTVTDcCVlxMDq8rbFb5KAcqer+ayAl6545Bk0h2E9QPFD
-DuuGX0sHBuME54HjUC7KclyGU9MNxLe7hR8EkSbdSJD/UktWjLA/BkBpjCbKpy2D
-qgCmUEM6ViL/QjNNgNnTzkllhgK6UuwUTmqmS+7mImFA1Xd+5TU64Mlw/K4rRdXK
-36kCwpqR3+uz+QcXkto81JRTuzeviZiJe5P3ea+hYvAra3h0gRF0sX+Ypwj3svvr
-K3aoxLMy63s2e4m+qSP61jJKmUPfMfBvAgMBAAGjgYwwgYkwPAYDVR0RBDUwM4IJ
+ggEKAoIBAQC9KksWuXwx2Zh0JiU1QDj6lBZ3qJ5LNgYi/U4+yfP6KFcDw0nExUHe
+glLbdEZ3sAwthrpQaWBqA8ZvMb3My+ZSYyDhHUBaTGKxgQZylALN5Xb108OFrxLm
+xbu7YTpS1zHFaVkAGD5dhWwdP/00p0P4iVHkcefsSBltkkJRT096O0jD/cY7/Fe6
+U+ry7fCYKYpJ8x+DGf5g7mPjWW2MC9sfknUGXknHbxArzvFFIrnay2ya/0Nvoi7I
+Ch8TrkAY91mdlAiCzSFMVRulGipOqN+s5hXLd8ANDWYImH8wIxChT9YPHloAZm0P
+m/UuKW1dxfS64nub9gfUFCyxzqHxa5xTAgMBAAGjgbQwgbEwPAYDVR0RBDUwM4IJ
bG9jYWxob3N0ggkxMjcuMC4wLjGCAzo6MYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAA
-ATAJBgNVHRMEAjAAMB0GA1UdDgQWBBSimSv95R8Wzx8/eAb1V4+4G5QZhjAfBgNV
-HSMEGDAWgBRLBvtUNk6xwJifFnkGMNsp1ereMjANBgkqhkiG9w0BAQsFAAOCAQEA
-HrxC2/kUj5GGnWcihZZgmbuo9DS1qpu6K6w+Bed0PYN0A++ov4PXWj7FGDwA4Xz4
-WKlx75eX7H5SCpwmWVX+W+uZ7h3Zmvv/e7oQBcvciMSlHayfqaa266WAF4XYpDrg
-Vaf6KRZko6ovtBUQdcjEJisvk/SO0I1PqQvTrWEkF4LJmiiAzhpr7eobpxkuEe2G
-ggFELDM6HviEsJMDIkmvCIJWwJVccSQYz+TLxIYNQIwKS2yCvNg7Vf7EtffXi51Y
-0medhTHokJDzhifAL6z30L0kQu9KjPCpxgQ3V/v3rIoyvpyfW42jT4TnzWDZqjEL
-Tl4nFwH5ckHcm2RMaPTTcQ==
+ATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTSkaw7Ct7VZ6/s/WLtKkNo3vXF8zAf
+BgNVHSMEGDAWgBTicNglV5Pq//6VpIWaOwJyKKr4EjAOBgNVHQ8BAf8EBAMCA6gw
+EwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAEuIlec3o/Dr
+0kfWCSwA+ImHkaKyEVW4RALKEnaYBSWOyk9oIzS/k7ygz4QI+ay4EW9KoJMwIxAK
+fliM/lsD+Vj78imGbLeYI1OxQDznZcsUloamivhPe5MQf7jR9q4aTZ7f0n1kZulf
+8VfSexCCvKeB8DIGS4zDtu0Fs4QOJGHtnSwwBNjYmyIyXY7SsG1+Ka95ttrMV2HF
+ZB7SQ+HdPHyn3sBcPbSbqkIwC5IGiqPZS2hiPpgE4nYU1e8brL8rrlUL/INsYnFb
+slKJApx/wi/jBBKZ6C5S9a/4LDIgQeNH2KdlD40JA920w2PAKbk95At2vy1lr3kQ
+7iIgRvcraSo=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDAzCCAeugAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
-YXV0aG9yaXR5MB4XDTE1MTAxMzE0MzQzMloXDTI1MTAxMDE0MzQzMlowIDEeMBwG
+MIIDLjCCAhagAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNDYwN1oXDTI1MTAxNjExNDYwN1owIDEeMBwG
A1UEAwwVaW50ZXJtZWRpYXRlYXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAsOz8JUXytrHdpO4xZ1Rn2ON7JF5JeA6U8GddgV8Y4KPm9SAh
-6aHVI556z/oqCWlVnI/1aJRvPrI2rTBwcT49dkOlBcj3tzAcmSHepA5R37P1S5/p
-Wg+dPYmItmMxxW25YS4iPk1A/WQN83riRTwZhit4Asa8Gk5l3Rs5L4dleXk4vxN6
-FVL/uWMSVA3H3ELk66ieOrQLGgjIb/yPuOlzKDwzTRJ6nkG5X5lsQYPmN7t85oy6
-vuqBBdZ/s0S8qUbAIDa81pAyiBBN9gvfWQ8BJ9rJc4Tf4r3TupucJLCswLg9yT7y
-RE2FiyLsUSEg+YqhhfiCZDXO94Y4ek0fIbkajwIDAQABo1AwTjAMBgNVHRMEBTAD
-AQH/MB0GA1UdDgQWBBRLBvtUNk6xwJifFnkGMNsp1ereMjAfBgNVHSMEGDAWgBQv
-7fUg7ltvey4S1EAIQ5vX/kgEFTANBgkqhkiG9w0BAQsFAAOCAQEAIWN2IrusjYc7
-OBm2dM38h0v8QtTzQIergzeZPNIXbvNicJ+QTvRWNFxUY9B1dR4n1E8WOaUjuAuE
-BaoijJwGzZrVUlvNyGaO8v9ODe2i5hYcy2U2mMGCfdElmU9F5xw9g1iZE+7TorF8
-KkGIolhQ6r2VMDI8AU/YUAoTkPni6IL9qZZV2C/uQ5emW8rySv7VKlb+ze/JNsyo
-U4ubR6IVzza5ky/o/EhxqzbpnF8J+m5lYUqlYIs4M7KZOH0fGPebST+mYR+vV0CZ
-q93BD4B+N73Id1VQEFPofQtAw8Kh8C/MzDGZpuMs97phtN7cYhrQcqvnRaCyPT/q
-Jt202WYG+w==
+AQ8AMIIBCgKCAQEA2mNFVzURk/dREoJiWUrxNjMSOtIMCl1ep/CJqC7g4QL1aOEp
++4vJ7s+NFG6K4aafLg9UwdQ9mPLwkCkX4ETBCJDU7atD0AM7OhlGTC9q22kMDdSz
+IeT4HQ7QQntDkg4TPBz/uoUwlrDsfLUObx1VB1G/eag0wFE+1HmtwXnusT8L6xzs
+Nfbjn6NrkXIoww1F+s1Bc8AtZVlib7KSR56idhgZGo5PAIBygQT21H4W5HYlossn
+8sfj/HtHtNk+qgeqK0uIAiW3RAj1mKm7OoY/zcgTvRJPYqkRbahB5pPyPQfXlfvj
+8pBl8xBzeBNGXf2pqU8nter+2cCBT3E8MwhkOQIDAQABo3sweTASBgNVHRMBAf8E
+CDAGAQH/AgEAMB0GA1UdDgQWBBTicNglV5Pq//6VpIWaOwJyKKr4EjAfBgNVHSME
+GDAWgBQzJoFbvQyxUqLv02M/SqkjAAAk9DAOBgNVHQ8BAf8EBAMCAgQwEwYDVR0l
+BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAEZg1NvkzRFh1OA5eBeP
+bgIfYRhcOJlwxBgjYa8+h6NlIrnYvJC0OCyV/2tvYkrNcJmI4AAGlchsdlPZGkP4
+gyPP/aml6f/Ys6fMggLNaT2PjO9ZozF/o9JM2H1j1/OGBa7EmMYCG4EDEzqpDrYa
+pQFjr6ULc0pvXJIHDaIWQgzqSYrvaIzO1V59zQymK0GUMFydPQreljFUHW5zi8x6
+jYvd3kgJGe0R96+ktLPF41JJwRqUJENyTqESYYd2Tu0GS7bFqEmQ0zT5aVYkr/VR
+GNhOE92EOJNymB11NWNjEfAp5nVMPsySJBIO50nlQY0igAiZZfhFz0cykrwGhuN7
+dRY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIC+zCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
-YXV0aG9yaXR5MB4XDTE1MTAxMzE0MzQzMloXDTI1MTAxMDE0MzQzMlowGDEWMBQG
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNDYwNloXDTI1MTAxNjExNDYwNlowGDEWMBQG
A1UEAwwNcm9vdGF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAM4Wx84AS3CwNP+Lm8YeQT3zg679qGfjrtE87qyvBipV4nPRz4ggls4nY99s
-VkoGcoZedL3E42/zR1RFQ5DZzzpf5NVYwwYtlDrhVQGb6k8zH6PK4KEou2JkV6oq
-GFy101vNAoxSeSlPetAU5MmHz/EO0alpvJZ5NKnUVTUD19U/CmTFMHL1RSsgWsPf
-UrFH58lt4v311i8vxvM3qFA7wO0Q2tptP6sf1PGSaS00W5HBFwNa8J3ewCN7opFt
-JxCbqrsG6ExG9o7gCDpY+tW2/ML24xrJfilGdhyM3H7qA6Y7ubTD/BbY+MoJxo4W
-XEEgNhMcw7uKaZngTS+DPaAP5NMCAwEAAaNQME4wHQYDVR0OBBYEFC/t9SDuW297
-LhLUQAhDm9f+SAQVMB8GA1UdIwQYMBaAFC/t9SDuW297LhLUQAhDm9f+SAQVMAwG
-A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAMpYu2n0fFULWM0dU06AH1yL
-anz1CywTTjFk0lwAmer+fexNrcc4VkWGp+XyOEZFMGRWfdixJ+F8SiOGrz83gKh+
-Z9FYJY6Ooj1y7KK8UQ78fOVUgVdPIdc3NjZFXnMz46oNXyYuOGnAyLSr8CeOQQNn
-h5TnNR82b6gun/Zu1qDPgTBfyMifdYp20GJpJMnAjx5NG/iJ/OMQCOfWfydOfLHH
-O1yxFOFfnzmeFAb9kz19bYp7UOK2C8XNyYoEuIgJo6tvlR5jIg6dT422jRSMOBtt
-55VZiS33SkH/hu1c3PoBF8QK9BPdv1QStz8k86nHMmbGk3tLmxQrYQ7SGQ6DDGo=
+ggEBAOICaW5E0IzpRZSO3RcMT7Qsj9gIBbYPkCUT9nA4YXbW+ZPPnupmgikWjfz1
+bhSm1J/32AUqg9LngXulq0CLBVUoVGgR9yPFSUuawHKvqliKwdUiGhvAh7iKE1hZ
+x7fIqhwMm8Cbn7LmK8gbzpRkTLIMyOUFVnMMwTtttfLQpXegT9HukZ2JuvqPCpAW
+aBBCZufpime3xcNyh4AEo34sNyDPfMjaiB3j5AQIehOm2phZia9DsGmKofhhNiWU
+xuQsHMubE8ODXeWEipuz3SRzwc4znIxeCiaDDBgIaRVY/7t/JdMFhI4AfktGn3fp
+AhevaZ1AnOqJ/3fDwMWrn31USHsCAwEAAaNQME4wHQYDVR0OBBYEFDMmgVu9DLFS
+ou/TYz9KqSMAACT0MB8GA1UdIwQYMBaAFDMmgVu9DLFSou/TYz9KqSMAACT0MAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJvF47StRunE0dEvD6rx9ALO
+0GRXAB7v4iyZP+PIfbIwVLY0jjMPh9jzuyzOtkPSwEUX+mtTe83o8r9Srkf7oJEQ
+GH/tfJpzJcSsOtGkw8s33I436IT7lKAr1k2V9S0/9u+k7N4Iuo9JeYj+8BSM4cpO
+i3uN98qx5IIHI7mZ77Iv1ZXN324mBzP/isppagbw2jl8VyHfy3rUNLQaMT41nNof
+pCw/z6JpQhz6WHA+GkKlJ2sAiNhLtSOBzk2wx1080eZb3GbEkDKLXCKdR/cQf9vS
+feky5cPaFQnfnfFv0b9Ygx3DopWCZ5hg5SxwxwTQv6Cy6XlIfaaFwNkrTzuhFoE=
-----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/untrusted_server_key.pem b/tests/standalone/io/certificates/untrusted_server_key.pem
index a72f6c9..a432114 100644
--- a/tests/standalone/io/certificates/untrusted_server_key.pem
+++ b/tests/standalone/io/certificates/untrusted_server_key.pem
@@ -1,29 +1,29 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
-MIIE5TAcBgoqhkiG9w0BDAEBMA4ECMRqdkj+7kZPAgIIAASCBMOpU0aPEIY0+mrz
-ZjdJkd+yrsehwoRBsnevLvs07xY1yJzyQbOpJCSN/dCkTLaee+ob8dtgs9ZJNZJ+
-e05o86J7B+zPncKNS3A97QcKy9XlTRTU0IPynxka6U65gDT4w2qDRnRohsYNgf8s
-iLD+duupiN8fimd0TnL48Qimk6VJfcZ62wPQGL2IZmcuNKG0o2wOpbg4NGviTGSl
-9Cm2mOYO3dU2MVBXZa4KUMG7ZXdG0eCzC+Vs6blYnc4TiYskQ3fILr1kKAWvzhZX
-qbaApIIVzMOosH/UUNxMh8ReJJN0CGNIlzPFtNlwKPzv0gUuwt8IpcayNPgDfycr
-Uj+hvURrRZ5Ah/WpY6dW4WnSYXH5uieufvH/G3/f96deuXsCsS4nLnDRTH2Z3GJe
-OjkzmUesFDYtOhz5KyMGb0SDsqSlVoGt3vd3bR2MjYCBl3EugzfbBTLV7rBF7Pe5
-l3rALKCAhJsf/RWXvkObgH+zfLGzW0vPpLQOR7errXYgumXABK8hKJrs1fwV4KJt
-DKgOkCqVun3diXt6CSwotJCn1RCbc4qk4rNaXbF5uRNiiAvCdashSCEPhT6JGGy8
-o4/qoTc8mYIgsT1nbH9cFb8x2e+a0W/NaaO9VSWEj1v8h9pyVqBk1q5PKl1vhCnE
-5HkkpxEs2NYtuv6c+wsf1IZiGBKdkVJArl351WKkiUFhg5asEYN9y28/UL2AmXhC
-QwPeNu/I/GGf2bFLsVSi7PvvtRT8//CfVmoKxf+SjSU6jQfB4r+1gMEJlY0XIbw8
-Mie+QR7L+NXEEqrZs+w/eEUN6sTPwkUdvULyJm8Y21Qc9hyDl7KECKSfJ/qaj7aE
-41JCHBLfv4TpCOpmG/5RxCqLcIAdX7q8li9OcaHwCGuWt1ANYaRp1t3d69t10Vtq
-uu41Bo7ZgKZC7yTbhEEEywXBRzi6OZoOxEDpMmKiVakaDRV5aim0PWo4srdyMwpm
-n75+X6mNrsRiDKHzH3/SRA8u6LHVPKSisA0fIW9qOvZSV9T93+hsYwQsH/JQX7FS
-6dBQeMn/LHMDyi8FEAeSYvsNpZ3HFH0yCMxdmlV+WNJRGNuYe/DXqYtHnW8hmrXQ
-73jsfh1M72rNY4kLpuskuxzQ0fN0x8No6IYHReY7bA/YuTlwkPQZso0zqfSwCvaQ
-Vx0bf7ZKEAOAEJQwQDzCPK27CNHt5DqTXD2P1LZmA3S+XunrtgkPCcpeUwng0xXV
-cujmb5ND+kkA94F+jAXNOtMBCSDcYNOCXwNJ2vr4cOWsC31c/LgoUl+8oDbwIi5e
-s8HKhmUKNbo6wE9oN07zqPqP68Afy2LmwjxUt7ODF8gAAo+RbudrVrUm7IgiE2uo
-Cy3u9rbx9kJlTKvrMEgc+51+Oz9ZeUUG6I8mMltX6CpWqdpz2w8hrf9w8nIIK6ba
-iUJnrlaIJdqjAue0X9YFr+QDpF5Pua65vromGwleHmSHU4YhR780JlYxMpikg+i+
-uaPDuZOEwNlb+vlwk2m4pARYDlx7TQRZGdFcWevaco3dWQ2Uo1UPT5Wh4ZDXHNDs
-lUn/aqNAIuOgeT9hJZcPgj+K0cAH8g42VW1Ewl87HPyM+MfB/RGkRUOncVvc9Gms
-ipieyen0TlrX
+MIIE4jAcBgoqhkiG9w0BDAEBMA4ECM5Q9vG4KGZGAgIIAASCBMBiQm5+L2fG6oTd
+F4NPWJQj2ud4FjIp98E0HHmqZZjWxkTJHdHjPvHNGIrAYpyM54Hj1Av6RsOCtyEk
+/XfmlXuf6MzoY54rYSrFKxSssrRvPu6PT5BpWB0ErEs/gksRXRMXDVCVv14rvIAl
+f37j/aqaUYNQSsy7n5t/7PZ6w4icVIPYFZlKcIzYM0M6yy/vN3EarInQtgIc0U5/
+m8/87oyH83AzxtVH07Y6iYOEdTqmNFgGLnLmRaGnG6bsa/O8u8FKtP+9D468qxPD
+Te58rrkicvHPNNtKSvi1acN7jtHQ1+0asQwny/ElYrrfUr1K6ypfGWUmIL0LBxYK
+5QLYWqQTmUlisirGDmKJ29H0PyF3enUpOyKBFTzrqfGrIPLpmbHN29DlmliOcRjU
+ftbPFVH8n2dLf9Xtnhgzk9H1JoL228aYdd2nO3Lb8Kn4DV2iRS6y/4RXTbSdlRBf
+eB6FT1WgcU1Rtl+2ekxncVBrTV/akM7S/Y6XtpzwUpi41JXpUtV3aRltYH7HLXQR
+qZKfkUcma+WiBwgjjiBs9be0h2Ow6n4SX++I9xgEhGEkq8ob/HQTiIC2frH/EqVN
+/zl20GgQWmkresmJxKaesNYocsqr7cvq2yx8PbItXW6nugtm1U29YyQSEtXypIXl
+VY4PcccfaKH1iF1ia5sF7yhHQEeuG6c1WBJCXog2t1Nrru2Df3AVMgqcltTGo+K3
+6R/7BveklhFcQkAjn3HUEy8/mlq9nrblWT9YfcP7gqR4szCAZoALGXG7DYVyrheg
+yZwSraFunzlBbfVvMAhtEPakNNT9tadhEZObkQfCB1g7UeXtgZ1u7v8wtq+5xKHe
+RtECM9Jitk5Tn9HPvumdkzuM9zyagJs90WxsAUxInzB6zCWaBduiZIjEK/WZRocY
+0lK9yDEEnwZ/8uiif9Y52fvdI6cHBy041VYvXSxal08ToEye3NBbXTwhMbI6hbfp
+1drJcb0ARYIFzX16cy85YF64iwPqSBt5cQBPhwF1sDcjBPeYFeZ43qNw4KnO1M2w
+jGCmFvFcapwGhuJfFQMt9gEX3jx/8460/GUxTYm/gLvXL4Ae8OkWLRW6TMvDNw39
+esRdO/gQcfj2P5YZuBjptU0B//a9f7OaJNyyr39Hj3l5TgkDv5iV5HLZYXkn6nMT
+SiKMtYDq4qKyqeMcGVACCm0/Z1xUtPQsBYoL7+1v+ewyZpqNs9XYZJGSDpUddBzD
+EHEqUEIIUslV2fRFDnfIKDovjIfaaox3g1cpoZLzFmzQ/GYo2bFp6zMFTvqlWFTN
+RTElsHnKbX/0nlQHMNGmEwbowuPerDd1LehexSWm8GWutWCUH5SfE1k0F8UTnqwF
+AvySfhx28xY24neoj5OfM4O6j2mY9d392NrUo5xXhIWfFkXi97uFpkVvx2N7EfGF
+pjZRbnQUmf/HZ3p2N7EUnUV9q+AKume2EeFwTBS6fZdrhHvD4aYkbm41tBoNoS75
+DKpQJ7OTIdgy2uOrY4xSnKOJGuh+iJysQe5axeKKEEIr84VF23SpfqTiNFDDFec0
+749mgVHS/+tCw6UsgS/3vS+3AqMW8DgNKYkhcaDQVFYbVJLmlLGYmLZfkKBbUzy3
+Vv6uVhro
-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/standalone/io/create_sample_certificates.sh b/tests/standalone/io/create_sample_certificates.sh
index c9baee7..eaa62f0 100755
--- a/tests/standalone/io/create_sample_certificates.sh
+++ b/tests/standalone/io/create_sample_certificates.sh
@@ -36,26 +36,61 @@
openssl x509 -req -in intermediate_authority_request.pem \
-out intermediate_authority.pem -set_serial 1 \
-CA root_authority.pem -CAkey root_authority_key.pem \
- -passin $password -extfile ../intermediate_authority_v3_extensions \
- -days 3650
+ -passin $password -extfile ../sample_certificate_v3_extensions \
+ -extensions intermediate_authority -days 3650
# Create a certificate request for the server certificate
openssl req -subj /CN=localhost -batch -verbose -passout $password -new \
-keyout localhost_key.pem -out localhost_request.pem
-# Sign the server certificate with the intermediate authority. Add the
+# Sign the server certificate with the intermediate authority. Add the
# certificate extensions for SubjectAltName and that it is not a CA itself.
openssl x509 -req -in localhost_request.pem -out localhost.pem -set_serial 1 \
-CA intermediate_authority.pem -CAkey intermediate_authority_key.pem \
- -passin $password -extfile ../localhost_v3_extensions -days 3650
+ -passin $password -extfile ../sample_certificate_v3_extensions \
+ -extensions localhost -days 3650
+# Create a self-signed client certificate authority.
+openssl req -subj /CN=clientauthority -set_serial 1 -batch -verbose \
+ -passout $password -new -x509 -keyout client_authority_key.pem \
+ -out client_authority.pem -config ../sample_certificate_v3_extensions \
+ -extensions client_authority -days 3650
+
+# Create certificate requests for the client certificates
+openssl req -subj /CN=user1 -batch -verbose -passout $password -new \
+ -keyout client1_key.pem -out client1_request.pem
+openssl req -subj /CN=user2 -batch -verbose -passout $password -new \
+ -keyout client2_key.pem -out client2_request.pem
+
+# Sign the certificate requests with the client authority
+openssl x509 -req -in client1_request.pem -out client1.pem -set_serial 1 \
+ -CA client_authority.pem -CAkey client_authority_key.pem \
+ -passin $password -extfile ../sample_certificate_v3_extensions \
+ -extensions client_certificate -days 3650
+openssl x509 -req -in client2_request.pem -out client2.pem -set_serial 1 \
+ -CA client_authority.pem -CAkey client_authority_key.pem \
+ -passin $password -extfile ../sample_certificate_v3_extensions \
+ -extensions client_certificate -days 3650
+
+# Copy the certificates we will use to the 'certificates' directory.
+CERTS=../certificates
cat localhost.pem intermediate_authority.pem root_authority.pem \
- > ../certificates/server_chain.pem
+ > $CERTS/server_chain.pem
+
+cat intermediate_authority.pem root_authority.pem client_authority.pem \
+ > $CERTS/server_trusted.pem
# BoringSSL only accepts private keys signed with the PBE-SHA1-RC4-128 cipher.
-openssl pkcs8 -in localhost_key.pem -out ../certificates/server_key.pem \
+openssl pkcs8 -in localhost_key.pem -out $CERTS/server_key.pem \
+ -topk8 -v1 PBE-SHA1-RC4-128 -passin $password -passout $password
+openssl pkcs8 -in client1_key.pem -out $CERTS/client1_key.pem \
+ -topk8 -v1 PBE-SHA1-RC4-128 -passin $password -passout $password
+openssl pkcs8 -in client2_key.pem -out $CERTS/client2_key.pem \
-topk8 -v1 PBE-SHA1-RC4-128 -passin $password -passout $password
-cp root_authority.pem ../certificates/trusted_certs.pem
+cp root_authority.pem $CERTS/trusted_certs.pem
+cp client_authority.pem $CERTS
+cp client1.pem $CERTS
+cp client2.pem $CERTS
cd ..
diff --git a/tests/standalone/io/intermediate_authority_v3_extensions b/tests/standalone/io/intermediate_authority_v3_extensions
deleted file mode 100644
index 8d0f70c..0000000
--- a/tests/standalone/io/intermediate_authority_v3_extensions
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-# OpenSSL configuration file giving the v3 extensions for an intermediate
-# certificate authority.
-
-basicConstraints = CA:true
-subjectKeyIdentifier=hash
-authorityKeyIdentifier=keyid:always,issuer
-
diff --git a/tests/standalone/io/localhost_v3_extensions b/tests/standalone/io/localhost_v3_extensions
deleted file mode 100644
index 99cc4d1..0000000
--- a/tests/standalone/io/localhost_v3_extensions
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-# OpenSSL configuration file giving the v3 extensions for the localhost
-# server certificate
-subjectAltName = @alt_names
-basicConstraints = CA:false
-subjectKeyIdentifier=hash
-authorityKeyIdentifier=keyid,issuer
-
-[alt_names]
-DNS.1 = localhost
-DNS.2 = 127.0.0.1
-DNS.3 = ::1
-IP.1 = 127.0.0.1
-IP.2 = ::1
-
diff --git a/tests/standalone/io/sample_certificate_v3_extensions b/tests/standalone/io/sample_certificate_v3_extensions
new file mode 100644
index 0000000..f9e741e
--- /dev/null
+++ b/tests/standalone/io/sample_certificate_v3_extensions
@@ -0,0 +1,46 @@
+# Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# OpenSSL configuration file giving the v3 extensions for the sample
+# certificates created by create_sample_certificates.sh
+
+default_bits = 2048
+distinguished_name = name_section
+[name_section]
+CN = foo
+
+[localhost]
+subjectAltName = @alt_names
+basicConstraints = critical,CA:false
+subjectKeyIdentifier = hash
+authorityKeyIdentifier=keyid,issuer
+keyUsage=critical, digitalSignature, keyEncipherment, keyAgreement
+extendedKeyUsage=serverAuth
+
+[alt_names]
+DNS.1 = localhost
+DNS.2 = 127.0.0.1
+DNS.3 = ::1
+IP.1 = 127.0.0.1
+IP.2 = ::1
+
+[intermediate_authority]
+basicConstraints = critical, CA:true, pathlen:0
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always, issuer
+keyUsage=critical, keyCertSign
+extendedKeyUsage=serverAuth
+
+[client_authority]
+basicConstraints = critical,CA:true,pathlen:0
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always, issuer
+keyUsage=critical, keyCertSign
+extendedKeyUsage=clientAuth
+
+[client_certificate]
+basicConstraints = CA:false
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always, issuer
+extendedKeyUsage=clientAuth
diff --git a/tests/standalone/io/secure_server_client_certificate_test.dart b/tests/standalone/io/secure_server_client_certificate_test.dart
index 3f34d93..81f0995 100644
--- a/tests/standalone/io/secure_server_client_certificate_test.dart
+++ b/tests/standalone/io/secure_server_client_certificate_test.dart
@@ -15,75 +15,62 @@
SecurityContext serverContext = new SecurityContext()
..useCertificateChain(localFile('certificates/server_chain.pem'))
..usePrivateKey(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ password: 'dartdart')
+ ..setTrustedCertificates(file: localFile('certificates/client_authority.pem'))
+ ..setClientAuthorities(localFile('certificates/client_authority.pem'));
-SecurityContext clientContext = new SecurityContext()
+SecurityContext clientCertContext = new SecurityContext()
+ ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'))
+ ..useCertificateChain(localFile('certificates/client1.pem'))
+ ..usePrivateKey(localFile('certificates/client1_key.pem'),
+ password: 'dartdart');
+
+SecurityContext clientNoCertContext = new SecurityContext()
..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
-Future testClientCertificate() {
- var completer = new Completer();
- SecureServerSocket.bind(HOST,
- 0,
- serverContext,
- requestClientCertificate: true).then((server) {
- var clientEndFuture = SecureSocket.connect(HOST,
- server.port,
- context: clientContext,
- sendClientCertificate: true);
- server.listen((serverEnd) {
- X509Certificate certificate = serverEnd.peerCertificate;
- Expect.isNotNull(certificate);
- Expect.equals("CN=localhost", certificate.subject);
- Expect.equals("CN=myauthority", certificate.issuer);
- clientEndFuture.then((clientEnd) {
- X509Certificate certificate = clientEnd.peerCertificate;
- Expect.isNotNull(certificate);
- Expect.equals("CN=localhost", certificate.subject);
- Expect.equals("CN=myauthority", certificate.issuer);
- clientEnd.close();
- serverEnd.close();
- server.close();
- completer.complete();
- });
- });
- });
- return completer.future;
+Future testClientCertificate({bool required, bool sendCert}) async {
+ var server = await SecureServerSocket.bind(HOST, 0, serverContext,
+ requestClientCertificate: true, requireClientCertificate: required);
+ var clientContext = sendCert ? clientCertContext : clientNoCertContext;
+ var clientEndFuture = SecureSocket.connect(HOST, server.port,
+ context: clientContext, sendClientCertificate: true);
+ if (required && !sendCert) {
+ try {
+ await server.first;
+ } catch (e) {
+ try {
+ await clientEndFuture;
+ } catch (e) {
+ return;
+ }
+ }
+ Expect.fail("Connection succeeded with no required client certificate");
+ }
+ var serverEnd = await server.first;
+ var clientEnd = await clientEndFuture;
+
+ X509Certificate clientCertificate = serverEnd.peerCertificate;
+ if (sendCert) {
+ Expect.isNotNull(clientCertificate);
+ Expect.equals("/CN=user1", clientCertificate.subject);
+ Expect.equals("/CN=clientauthority", clientCertificate.issuer);
+ } else {
+ Expect.isNull(clientCertificate);
+ }
+ X509Certificate serverCertificate = clientEnd.peerCertificate;
+ Expect.isNotNull(serverCertificate);
+ Expect.equals("/CN=localhost", serverCertificate.subject);
+ Expect.equals("/CN=intermediateauthority", serverCertificate.issuer);
+ clientEnd.close();
+ serverEnd.close();
}
-Future testRequiredClientCertificate() {
- var completer = new Completer();
- SecureServerSocket.bind(HOST,
- 0,
- serverContext,
- requireClientCertificate: true).then((server) {
- var clientEndFuture = SecureSocket.connect(HOST,
- server.port,
- context: clientContext,
- sendClientCertificate: true);
- server.listen((serverEnd) {
- X509Certificate certificate = serverEnd.peerCertificate;
- Expect.isNotNull(certificate);
- Expect.equals("CN=localhost", certificate.subject);
- Expect.equals("CN=myauthority", certificate.issuer);
- clientEndFuture.then((clientEnd) {
- X509Certificate certificate = clientEnd.peerCertificate;
- Expect.isNotNull(certificate);
- Expect.equals("CN=localhost", certificate.subject);
- Expect.equals("CN=myauthority", certificate.issuer);
- clientEnd.close();
- serverEnd.close();
- server.close();
- completer.complete();
- });
- });
- });
- return completer.future;
-}
-
-void main() {
+main() async {
asyncStart();
- InternetAddress.lookup("localhost").then((hosts) => HOST = hosts.first)
- .then((_) => testClientCertificate())
- .then((_) => testRequiredClientCertificate())
- .then((_) => asyncEnd());
+ HOST = (await InternetAddress.lookup("localhost")).first;
+ await testClientCertificate(required: false, sendCert: true);
+ await testClientCertificate(required: true, sendCert: true);
+ await testClientCertificate(required: false, sendCert: false);
+ await testClientCertificate(required: true, sendCert: false);
+ asyncEnd();
}
diff --git a/tests/standalone/io/secure_server_client_no_certificate_test.dart b/tests/standalone/io/secure_server_client_no_certificate_test.dart
deleted file mode 100644
index 97a422b..0000000
--- a/tests/standalone/io/secure_server_client_no_certificate_test.dart
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:async";
-import "dart:io";
-
-import "package:async_helper/async_helper.dart";
-import "package:expect/expect.dart";
-
-InternetAddress HOST;
-String localFile(path) => Platform.script.resolve(path).toFilePath();
-
-SecurityContext serverContext = new SecurityContext()
- ..useCertificateChain(localFile('certificates/server_chain.pem'))
- ..usePrivateKey(localFile('certificates/server_key.pem'),
- password: 'dartdart');
-
-SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
-
-Future testNoClientCertificate() {
- var completer = new Completer();
- SecureServerSocket.bind(HOST,
- 0,
- serverContext,
- requestClientCertificate: true).then((server) {
- var clientEndFuture = SecureSocket.connect(HOST,
- server.port,
- context: clientContext);
- server.listen((serverEnd) {
- X509Certificate certificate = serverEnd.peerCertificate;
- Expect.isNull(certificate);
- clientEndFuture.then((clientEnd) {
- clientEnd.close();
- serverEnd.close();
- server.close();
- completer.complete();
- });
- });
- });
- return completer.future;
-}
-
-Future testNoRequiredClientCertificate() {
- var completer = new Completer();
- bool clientError = false;
- SecureServerSocket.bind(HOST,
- 0,
- serverContext,
- requireClientCertificate: true).then((server) {
- Future clientDone =
- SecureSocket.connect(HOST, server.port, context: clientContext)
- .catchError((e) { clientError = true; });
- server.listen((serverEnd) {
- Expect.fail("Got a unverifiable connection");
- },
- onError: (e) {
- clientDone.then((_) {
- Expect.isTrue(clientError);
- server.close();
- completer.complete();
- });
- });
- });
- return completer.future;
-}
-
-void main() {
- asyncStart();
- InternetAddress.lookup("localhost").then((hosts) => HOST = hosts.first)
- .then((_) => testNoRequiredClientCertificate())
- .then((_) => testNoClientCertificate())
- .then((_) => asyncEnd());
-}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 125523a..2831a9c 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -206,8 +206,6 @@
[ $runtime == vm ]
# Failures in secure networking while NSS is replaced with BoringSSL
io/https_client_certificate_test: RuntimeError # Issue 24070
-io/secure_server_client_certificate_test: RuntimeError # Issue 24069
-io/secure_server_client_no_certificate_test: RuntimeError # Issue 24069
io/secure_socket_renegotiate_test: RuntimeError
io/secure_socket_bad_data_test: RuntimeError # An error in a secure connection just puts a READ_CLOSED on the stream, rather than signaling an error on the stream.
diff --git a/tools/VERSION b/tools/VERSION
index fb4794f..f633fa3 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 13
PATCH 0
PRERELEASE 7
-PRERELEASE_PATCH 1
+PRERELEASE_PATCH 2
diff --git a/tools/dom/src/dartium_CustomElementSupport.dart b/tools/dom/src/dartium_CustomElementSupport.dart
index 85ff4d6..aec7b4a 100644
--- a/tools/dom/src/dartium_CustomElementSupport.dart
+++ b/tools/dom/src/dartium_CustomElementSupport.dart
@@ -8,9 +8,11 @@
class _VMElementUpgrader implements ElementUpgrader {
final Type _type;
final Type _nativeType;
+ final String _extendsTag;
_VMElementUpgrader(Document document, Type type, String extendsTag) :
_type = type,
+ _extendsTag = extendsTag,
_nativeType = _validateCustomType(type).reflectedType {
if (extendsTag == null) {
@@ -28,20 +30,39 @@
Element upgrade(element) {
var jsObject;
- var tag = _getCustomElementName(element);
+ var tag;
+ var isNativeElementExtension = false;
+
+ try {
+ tag = _getCustomElementName(element);
+ } catch (e) {
+ isNativeElementExtension = element.localName == _extendsTag;
+ }
+
if (element.runtimeType == HtmlElement || element.runtimeType == TemplateElement) {
+ if (tag != _extendsTag) {
+ throw new UnsupportedError('$tag is not registered.');
+ }
jsObject = unwrap_jso(element);
} else if (element.runtimeType == js.JsObjectImpl) {
// It's a Polymer core element (written in JS).
jsObject = element;
- } else {
+ } else if (isNativeElementExtension) {
+ // Extending a native element.
+ jsObject = element.blink_jsObject;
+
+ // Element to extend is the real tag.
+ tag = element.localName;
+ } else if (tag != null && element.localName != tag) {
+ throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected native Html or Svg element to extend.');
+ } else if (tag == null) {
throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObjectImpl.');
}
// Remember Dart class to tagName for any upgrading done in wrap_jso.
- _addCustomElementType(tag, _type);
+ addCustomElementType(tag, _type, _extendsTag);
- return createCustomUpgrader(_nativeType, jsObject);
+ return _createCustomUpgrader(_type, jsObject);
}
}
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index 22158c9..4dc5fc9 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -352,32 +352,14 @@
********** **********
******************************************************************************/
-// List of known tagName to DartClass for custom elements, used for upgrade.
-var _knownCustomElements = new Map<String, Map<Type, String>>();
-
-void _addCustomElementType(String tagName, Type dartClass, [String extendTag]) {
- _knownCustomElements[tagName] =
- {'type': dartClass, 'extends': extendTag != null ? extendTag : "" };
-}
-
-Type _getCustomElementType(object) {
- var entry = _knownCustomElements[_getCustomElementName(object)];
- if (entry != null) {
- return entry['type'];
- }
- return null;
-}
-
String _getCustomElementExtends(object) {
- var entry = _knownCustomElements[_getCustomElementName(object)];
+ var entry = getCustomElementEntry(object);
if (entry != null) {
return entry['extends'];
}
return null;
}
-_getCustomElement(object) => _knownCustomElements[_getCustomElementName(object)];
-
// Return the tag name or is attribute of the custom element or data binding.
String _getCustomElementName(element) {
var jsObject;
@@ -407,13 +389,6 @@
return tag;
}
-Rectangle make_dart_rectangle(r) =>
- r == null ? null : new Rectangle(
- js.JsNative.getProperty(r, 'left'),
- js.JsNative.getProperty(r, 'top'),
- js.JsNative.getProperty(r, 'width'),
- js.JsNative.getProperty(r, 'height'));
-
/// An abstract class for all DOM objects we wrap in dart:html and related
/// libraries.
class DartHtmlDomObject {
@@ -423,247 +398,14 @@
}
-// Flag to disable JS interop asserts. Setting to false will speed up the
-// wrap_jso calls.
-bool __interop_checks = true;
-
-/** Expando for JsObject, used by every Dart class associated with a Javascript
- * class (e.g., DOM, WebAudio, etc.).
- */
-
-/**
- * Return the JsObject associated with a Dart class [dartClass_instance].
- */
-unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance);
-
-/**
- * Create Dart class that maps to the JS Type, add the JsObject as an expando
- * on the Dart class and return the created Dart class.
- */
-wrap_jso(jsObject) {
- try {
- if (jsObject is! js.JsObject || jsObject == null) {
- // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
- // or it's a simple type.
- return jsObject;
- }
-
- var wrapper = js.getDartHtmlWrapperFor(jsObject);
- // if we have a wrapper return the Dart instance.
- if (wrapper != null) {
- if (wrapper.runtimeType == HtmlElement && !wrapper._isBadUpgrade) {
- // We're a Dart instance but we need to upgrade.
- var customElementClass = _getCustomElementType(wrapper);
- if (customElementClass != null) {
- var dartClass_instance;
- try {
- dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
- } finally {
- dartClass_instance.blink_jsObject = jsObject;
- jsObject['dart_class'] = dartClass_instance;
- js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
- return dartClass_instance;
- }
- }
- }
-
- return wrapper;
- }
-
- if (jsObject is js.JsArray) {
- var wrappingList = new _DartHtmlWrappingList(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrappingList);
- return wrappingList;
- }
-
- // Try the most general type conversions on it.
- // TODO(alanknight): We may be able to do better. This maintains identity,
- // which is useful, but expensive. And if we nest something that only
- // this conversion handles, how does that work? e.g. a list of maps of elements.
- var converted = convertNativeToDart_SerializedScriptValue(jsObject);
- if (!identical(converted, jsObject)) {
- return converted;
- }
-
- var constructor = js.JsNative.getProperty(jsObject, 'constructor');
- if (constructor == null) {
- // Perfectly valid case for JavaScript objects where __proto__ has
- // intentionally been set to null.
- js.setDartHtmlWrapperFor(jsObject, jsObject);
- return jsObject;
- }
- var jsTypeName = js.JsNative.getProperty(constructor, 'name');
- if (jsTypeName is! String || jsTypeName.length == 0) {
- // Not an html type.
- js.setDartHtmlWrapperFor(jsObject, jsObject);
- return jsObject;
- }
-
- var dartClass_instance;
- if (jsObject.hasProperty('dart_class')) {
- // Got a dart_class (it's a custom element) use it it's already set up
- // make sure it's upgraded.
- dartClass_instance = _upgradeHtmlElement(jsObject['dart_class']);
- } else {
- var customElementClass = null;
- var extendsTag = "";
- var custom = _getCustomElement(jsObject);
- if (custom != null) {
- customElementClass = custom['type'];
- extendsTag = custom['extends'];
- }
- // Custom Element to upgrade.
- if (jsTypeName == 'HTMLElement' && customElementClass != null && extendsTag == "") {
- try {
- dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
- } finally {
- dartClass_instance.blink_jsObject = jsObject;
- jsObject['dart_class'] = dartClass_instance;
- js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
- }
- } else {
- // TODO(terry): Verify with jakemacd that this is right?
- // If we every get an auto-binding we're matching previous non-JS Interop
- // did to return a TemplateElement.
- if (jsTypeName == 'auto-binding') {
- jsTypeName = "HTMLTemplateElement";
- }
-
- var func = getHtmlCreateFunction(jsTypeName);
- if (func == null) {
- // One last ditch effort could be a JS custom element.
- if (jsObject.toString() == "[object HTMLElement]") {
- func = getHtmlCreateFunction("HTMLElement");
- }
- }
- if (func != null) {
- dartClass_instance = func();
- dartClass_instance.blink_jsObject = jsObject;
- js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
- }
- }
- }
- // TODO(jacobr): cache that this is not a dart:html JS class.
- return dartClass_instance;
- } catch(e, stacktrace){
- if (__interop_checks) {
- if (e is DebugAssertException)
- window.console.log("${e.message}\n ${stacktrace}");
- else
- window.console.log("${stacktrace}");
- }
- }
-
- return null;
-}
-
-/**
- * Create Dart class that maps to the JS Type, add the JsObject as an expando
- * on the Dart class and return the created Dart class.
- */
-wrap_jso_no_SerializedScriptvalue(jsObject) {
- try {
- if (jsObject is! js.JsObject || jsObject == null) {
- // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
- // or it's a simple type.
- return jsObject;
- }
-
- // TODO(alanknight): With upgraded custom elements this causes a failure because
- // we need a new wrapper after the type changes. We could possibly invalidate this
- // if the constructor name didn't match?
- var wrapper = js.getDartHtmlWrapperFor(jsObject);
- if (wrapper != null) {
- return wrapper;
- }
-
- if (jsObject is js.JsArray) {
- var wrappingList = new _DartHtmlWrappingList(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrappingList);
- return wrappingList;
- }
-
- var constructor = js.JsNative.getProperty(jsObject, 'constructor');
- if (constructor == null) {
- // Perfectly valid case for JavaScript objects where __proto__ has
- // intentionally been set to null.
- js.setDartHtmlWrapperFor(jsObject, jsObject);
- return jsObject;
- }
- var jsTypeName = js.JsNative.getProperty(constructor, 'name');
- if (jsTypeName is! String || jsTypeName.length == 0) {
- // Not an html type.
- js.setDartHtmlWrapperFor(jsObject, jsObject);
- return jsObject;
- }
-
- var func = getHtmlCreateFunction(jsTypeName);
- if (func != null) {
- var dartClass_instance = func();
- dartClass_instance.blink_jsObject = jsObject;
- js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
- return dartClass_instance;
- }
- return jsObject;
- } catch(e, stacktrace){
- if (__interop_checks) {
- if (e is DebugAssertException)
- window.console.log("${e.message}\n ${stacktrace}");
- else
- window.console.log("${stacktrace}");
- }
- }
-
- return null;
-}
-
-/**
- * Create Dart class that maps to the JS Type that is the JS type being
- * extended using JS interop createCallback (we need the base type of the
- * custom element) not the Dart created constructor.
- */
-wrap_jso_custom_element(jsObject) {
- try {
- if (jsObject is! js.JsObject) {
- // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
- return jsObject;
- }
-
- // Find out what object we're extending.
- var objectName = jsObject.toString();
- // Expect to see something like '[object HTMLElement]'.
- if (!objectName.startsWith('[object ')) {
- return jsObject;
- }
-
- var extendsClass = objectName.substring(8, objectName.length - 1);
- var func = getHtmlCreateFunction(extendsClass);
- if (__interop_checks)
- debug_or_assert("func != null name = ${extendsClass}", func != null);
- var dartClass_instance = func();
- dartClass_instance.blink_jsObject = jsObject;
- return dartClass_instance;
- } catch(e, stacktrace){
- if (__interop_checks) {
- if (e is DebugAssertException)
- window.console.log("${e.message}\n ${stacktrace}");
- else
- window.console.log("${stacktrace}");
- }
-
- // Problem?
- return null;
- }
-}
-
-// Upgrade a Dart HtmlElement to the user's Dart custom element class.
+/// Upgrade a Dart HtmlElement to the user's Dart custom element class.
_upgradeHtmlElement(dartInstance) {
// Only try upgrading HtmlElement (Dart class) if there is a failure then
// don't try it again - one failure is enough.
- if (dartInstance.runtimeType == HtmlElement && !dartInstance._isBadUpgrade) {
+ if (dartInstance.runtimeType == HtmlElement && !dartInstance.isBadUpgrade) {
// Must be exactly HtmlElement not something derived from it.
- var customElementClass = _getCustomElementType(dartInstance);
+ var customElementClass = getCustomElementType(dartInstance);
// Custom Element to upgrade.
if (customElementClass != null) {
@@ -674,7 +416,6 @@
dartInstance._badUpgrade();
} finally {
dartInstance.blink_jsObject = jsObject;
- jsObject['dart_class'] = dartInstance;
js.setDartHtmlWrapperFor(jsObject, dartInstance);
}
}
@@ -720,53 +461,10 @@
return result;
}
-// Converts a flat Dart map into a JavaScript object with properties this is
-// is the Dartium only version it uses dart:js.
-// TODO(alanknight): This could probably be unified with the dart2js conversions
-// code in html_common and be more general.
-convertDartToNative_Dictionary(Map dict) {
- if (dict == null) return null;
- var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object'));
- dict.forEach((String key, value) {
- if (value is List) {
- var jsArray = new js.JsArray();
- value.forEach((elem) {
- jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem);
- });
- jsObject[key] = jsArray;
- } else {
- jsObject[key] = value;
- }
- });
- return jsObject;
-}
-
-// Converts a Dart list into a JsArray. For the Dartium version only.
-convertDartToNative_List(List input) => new js.JsArray()..addAll(input);
-
-// Conversion function place holder (currently not used in dart2js or dartium).
-List convertDartToNative_StringArray(List<String> input) => input;
-
-/**
- * Wraps a JsArray and will call wrap_jso on its entries.
- */
-class _DartHtmlWrappingList extends ListBase implements NativeFieldWrapperClass2 {
- _DartHtmlWrappingList(this.blink_jsObject);
-
- final js.JsArray blink_jsObject;
-
- operator [](int index) => wrap_jso(js.JsNative.getArrayIndex(blink_jsObject, index));
-
- operator []=(int index, value) => blink_jsObject[index] = value;
-
- int get length => blink_jsObject.length;
- int set length(int newLength) => blink_jsObject.length = newLength;
-}
-
/**
* Upgrade the JS HTMLElement to the Dart class. Used by Dart's Polymer.
*/
-createCustomUpgrader(Type customElementClass, $this) {
+_createCustomUpgrader(Type customElementClass, $this) {
var dartClass;
try {
dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
@@ -786,12 +484,6 @@
$else
class DartHtmlDomObject extends NativeFieldWrapperClass2 {}
-unwrap_jso(dartClass_instance) => dartClass_instance;
-wrap_jso(jsObject) => jsObject;
-make_dart_rectangle(r) => r;
-convertDartToNative_Dictionary(Map dict) => dict;
-List convertDartToNative_StringArray(List<String> input) => input;
-convertDartToNative_List(List input) => input;
-createCustomUpgrader(Type customElementClass, $this) => $this;
+_createCustomUpgrader(Type customElementClass, $this) => $this;
$endif
diff --git a/tools/dom/templates/html/impl/impl_CustomEvent.darttemplate b/tools/dom/templates/html/impl/impl_CustomEvent.darttemplate
index c4de5c6..e16b74a 100644
--- a/tools/dom/templates/html/impl/impl_CustomEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_CustomEvent.darttemplate
@@ -36,7 +36,7 @@
$if DARTIUM
// Need for identity.
- e.blink_jsObject['dart_class'] = e;
+ js.setDartHtmlWrapperFor(e.blink_jsObject, e);
$endif
return e;
diff --git a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
index 3c6e3a4..1df549e 100644
--- a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
@@ -223,12 +223,28 @@
return isElement ? jsClassName : null;
}
+ // Get the first class that's a super of a dart.dom library.
+ ClassMirror _getDartHtmlClassName(ClassMirror classMirror) {
+ while (classMirror.superclass != null) {
+ var fullName = classMirror.superclass.qualifiedName;
+ var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
+ if (domLibrary) {
+ return classMirror.superclass;
+ }
+
+ classMirror = classMirror.superclass;
+ }
+
+ return null;
+ }
+
/**
* Get the class that immediately derived from a class in dart:html or
* dart:svg (has an attribute DomName of either HTML* or SVG*).
*/
ClassMirror _getDomSuperClass(ClassMirror classMirror) {
var isElement = false;
+ var foundSuperElement = null;
while (classMirror.superclass != null) {
var fullName = classMirror.superclass.qualifiedName;
@@ -236,6 +252,9 @@
var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
if (domLibrary) {
+ if (foundSuperElement == null) {
+ foundSuperElement = classMirror.superclass;
+ }
// Lookup JS class (if not found).
var metadatas = classMirror.metadata;
for (var metadata in metadatas) {
@@ -243,7 +262,7 @@
var metaType = reflectClass(metaDataMirror.runtimeType);
if (MirrorSystem.getName(metaType.simpleName) == 'DomName' &&
(metaDataMirror.name.startsWith('HTML') || metaDataMirror.name.startsWith('SVG'))) {
- if (isElement) return classMirror;
+ if (isElement) return foundSuperElement;
}
}
}
@@ -369,6 +388,25 @@
throw new DomException.jsInterop("HierarchyRequestError: Only HTML elements can be customized.");
}
+ var customClassType = _getDartHtmlClassName(classMirror);
+
+ if (extendsTag != null) {
+ var nativeElement = document.createElement(extendsTag);
+
+ // Trying to extend a native element is it the Dart class consistent with the
+ // extendsTag?
+ if (nativeElement.runtimeType != customClassType.reflectedType) {
+ var nativeElementClassMirror = reflectClass(nativeElement.runtimeType);
+ var customClassNativeElement = MirrorSystem.getName(customClassType.simpleName);
+ var extendsNativeElement = MirrorSystem.getName(nativeElementClassMirror.simpleName);
+ throw new DomException.jsInterop("HierarchyRequestError: Custom class type ($customClassNativeElement) and extendsTag class ($extendsNativeElement) don't match .");
+ }
+ } else if (customClassType.reflectedType != HtmlElement && customClassType.reflectedType != svg.SvgElement) {
+ var customClassName = MirrorSystem.getName(classMirror.simpleName);
+ var customClassElement = MirrorSystem.getName(customClassType.simpleName);
+ throw new DomException.jsInterop("HierarchyRequestError: Custom element $customClassName is a native $customClassElement should be derived from HtmlElement or SvgElement.");
+ }
+
if (_hasCreatedConstructor(classMirror)) {
// Start the hookup the JS way create an <x-foo> element that extends the
// <x-base> custom element. Inherit its prototype and signal what tag is
@@ -384,7 +422,7 @@
var elemProto = js.JsNative.callMethod(js.JsNative.getProperty(js.context, 'Object'), "create", [js.JsNative.getProperty(baseElement, 'prototype')]);
// Remember for any upgrading done in wrap_jso.
- _addCustomElementType(tag, customElementClass, extendsTag);
+ addCustomElementType(tag, customElementClass, extendsTag);
// TODO(terry): Hack to stop recursion re-creating custom element when the
// created() constructor of the custom element does e.g.,
@@ -405,9 +443,26 @@
var dartClass;
try {
+ if (extendsTag != null) {
+ // If we're extending a native element then create that element.
+ // Then upgrade that element to the customElementClass through
+ // normal flow.
+ dartClass = document.createElement(extendsTag);
+ js.setDartHtmlWrapperFor($this, dartClass);
+ dartClass.blink_jsObject = $this;
+ }
+
+ // Upgrade to the CustomElement Dart class.
dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
} catch (e) {
+ // Got a problem make it an HtmlElement and rethrow the error.
dartClass = HtmlElement.internalCreateHtmlElement();
+ // We need to remember the JS object (because constructElement failed
+ // it normally sets up the blink_jsObject.
+ dartClass.blink_jsObject = $this;
+
+ // Mark to only try this once don't try upgrading from HtmlElement
+ // to the user's Dart class - we had a problem.
dartClass._badUpgrade();
throw e;
} finally {
diff --git a/tools/dom/templates/html/impl/impl_HTMLElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLElement.darttemplate
index fdc305f..1d12631 100644
--- a/tools/dom/templates/html/impl/impl_HTMLElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLElement.darttemplate
@@ -8,10 +8,17 @@
$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS {
$!MEMBERS
$if DARTIUM
- // Flags to only try upgrading once if there's a failure don't try upgrading
+ // Flags to only try upgrading once. If there's a failure don't try upgrading
// anymore.
bool _badUpgradeOccurred = false;
- bool get _isBadUpgrade => _badUpgradeOccurred;
+
+ /// Required for SDK Infrastructure. Internal use only.
+ ///
+ /// Did this encounter a failure attempting to upgrade to
+ /// a custom element.
+ @Deprecated("Required for SDK Infrastructure. Internal use only.")
+ bool get isBadUpgrade => _badUpgradeOccurred;
+
void _badUpgrade() { _badUpgradeOccurred = true; }
$endif
}