Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit ecb7db2

Browse files
committed
fix(resource_url_resolver): IE/Safari compatible HTML parsing
On Internet Explorer (e.g. IE10 on Win7), the following weird bug occurs with template elements. FYI, IE does not support template element, but this bug appears to only hit template elements and but not other unknown elements. var doc = new DOMParser().parseFromString("<!doctype html><html><body><template>CONTENTS</template></body></html>", "text/html"); // Prints "<template>CONTENTS</template>" as expected. console.log(doc.body.innerHTML); // This should be a no-op. doc.body.querySelectorAll("div"); // Prints "<template></template>" - completely losing "CONTENTS". console.log(doc.body.innerHTML); This commit uses an alternate parsing method compatible with supported browsers, and also fixes a RegExp for IE compatibility.
1 parent f8d0123 commit ecb7db2

File tree

3 files changed

+81
-15
lines changed

3 files changed

+81
-15
lines changed

.travis.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,44 @@ env:
3434
- JOB=e2e-dev
3535
CHANNEL=dev
3636
BROWSERS=DartiumWithWebPlatform,SL_Chrome
37+
38+
# Temporary jobs to test IE and Safari to be removed in the next commit.
39+
- JOB=unit-stable-ie10
40+
CHANNEL=stable
41+
TESTS=dart2js
42+
BROWSERS=SL_IE10
43+
- JOB=unit-dev-ie10
44+
CHANNEL=dev
45+
TESTS=dart2js
46+
BROWSERS=SL_IE10
47+
48+
- JOB=unit-stable-ie11
49+
CHANNEL=stable
50+
TESTS=dart2js
51+
BROWSERS=SL_IE11
52+
- JOB=unit-dev-ie11
53+
CHANNEL=dev
54+
TESTS=dart2js
55+
BROWSERS=SL_IE11
56+
57+
- JOB=unit-stable-safari6
58+
CHANNEL=stable
59+
TESTS=dart2js
60+
BROWSERS=SL_Safari6
61+
- JOB=unit-dev-safari6
62+
CHANNEL=dev
63+
TESTS=dart2js
64+
BROWSERS=SL_Safari6
65+
66+
- JOB=unit-stable-safari7
67+
CHANNEL=stable
68+
TESTS=dart2js
69+
BROWSERS=SL_Safari7
70+
- JOB=unit-dev-safari7
71+
CHANNEL=dev
72+
TESTS=dart2js
73+
BROWSERS=SL_Safari7
74+
3775
global:
3876
- secure: AKoqpZ699egF0i4uT/FQ5b4jIc0h+KVbhtVCql0uFxwFIl2HjOYgDayrUCAf6USfpW0LghZxJJhBamWOl/505eNSe9HvEd8JLg/to+1Fo9xi9llsu5ehmNH31/5pue4EvsrVuEap1qqL6/BNwI2cAryayU0p5tV0g8gL5h4IxG8=
3977
- LOGS_DIR=/tmp/angular-build/logs

lib/core_dom/resource_url_resolver.dart

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,28 @@ class _NullTreeSanitizer implements NodeTreeSanitizer {
2121

2222
@Injectable()
2323
class ResourceUrlResolver {
24-
static final RegExp cssUrlRegexp = new RegExp(r'''(\burl\((?:[\s]+)?)(['"]?)([^]*)(\2(?:[\s]+)?\))''');
24+
static final RegExp cssUrlRegexp = new RegExp(r'''(\burl\((?:[\s]+)?)(['"]?)([\S]*)(\2(?:[\s]+)?\))''');
2525
static final RegExp cssImportRegexp = new RegExp(r'(@import[\s]+(?!url\())([^;]*)(;)');
2626
static const List<String> urlAttrs = const ['href', 'src', 'action'];
2727
static final String urlAttrsSelector = '[${urlAttrs.join('],[')}]';
2828
static final RegExp urlTemplateSearch = new RegExp('{{.*}}');
2929
static final RegExp quotes = new RegExp("[\"\']");
3030

3131
// Ensures that Uri.base is http/https.
32-
final _baseUri = Uri.base.origin + ("/");
32+
final _baseUri = Uri.base.origin + ('/');
3333

3434
final TypeToUriMapper _uriMapper;
3535
final ResourceResolverConfig _config;
3636

3737
ResourceUrlResolver(this._uriMapper, this._config);
3838

3939
static final NodeTreeSanitizer _nullTreeSanitizer = new _NullTreeSanitizer();
40+
static final docForParsing = document.implementation.createHtmlDocument('');
4041

4142
static Node _parseHtmlString(String html) {
42-
HtmlDocument doc = new DomParser().parseFromString(
43-
"<!doctype html><html><body>$html</body></html>", "text/html");
44-
if (doc != null) {
45-
return doc.body;
46-
}
47-
// Workaround for Safari (can't parse HTML documents via the DomParser)
48-
doc = document.implementation.createHtmlDocument("");
49-
doc.body.setInnerHtml(html, treeSanitizer: _nullTreeSanitizer);
50-
return doc.body;
43+
var div = docForParsing.createElement('div');
44+
div.setInnerHtml(html, treeSanitizer: _nullTreeSanitizer);
45+
return div;
5146
}
5247

5348
String resolveHtml(String html, [Uri baseUri]) {

test/core_dom/resource_url_resolver_spec.dart

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
library angular.test.core_dom.uri_resolver_spec;
22

3+
import 'dart:html';
34
import 'package:angular/core_dom/resource_url_resolver.dart';
45
import 'package:angular/core_dom/type_to_uri_mapper.dart';
56
import 'package:angular/core_dom/type_to_uri_mapper_dynamic.dart';
67
import '../_specs.dart';
78

9+
final bool isBrowserInternetExplorer = window.navigator.userAgent.indexOf(" MSIE ") > 0;
810

911
_run_resolver({useRelativeUrls}) {
1012
describe("resolveUrls=$useRelativeUrls", () {
@@ -45,9 +47,12 @@ _run_resolver({useRelativeUrls}) {
4547

4648
String urlInImport(cssEscapedUrl) => '<style>@import $cssEscapedUrl</style>';
4749
String urlInBackgroundImg(cssEscapedUrl) => '<style>body { background-image: $cssEscapedUrl }</style>';
48-
String urlInImgSrc(htmlEscapedUrl) => '<template><img src=\"$htmlEscapedUrl\"></template>';
49-
String urlInHref(htmlEscapedUrl) => '<template><a href=\"$htmlEscapedUrl\"></template>';
50-
String urlInAction(htmlEscapedUrl) => '<template><form action=\"$htmlEscapedUrl\"></template>';
50+
String urlInTemplateImgSrc(htmlEscapedUrl) => '<template><img src=\"$htmlEscapedUrl\"></template>';
51+
String urlInTemplateHref(htmlEscapedUrl) => '<template><a href=\"$htmlEscapedUrl\"></a></template>';
52+
String urlInTemplateAction(htmlEscapedUrl) => '<template><form action=\"$htmlEscapedUrl\"></form></template>';
53+
String urlInImgSrc(htmlEscapedUrl) => '<div><img src=\"$htmlEscapedUrl\"></div>';
54+
String urlInHref(htmlEscapedUrl) => '<div><a href=\"$htmlEscapedUrl\"></a></div>';
55+
String urlInAction(htmlEscapedUrl) => '<div><form action=\"$htmlEscapedUrl\"></form></div>';
5156

5257
escapeUrlForCss(String unEscapedUrl) {
5358
return unEscapedUrl..replaceAll("\\", "\\\\")
@@ -68,10 +73,38 @@ _run_resolver({useRelativeUrls}) {
6873
}
6974

7075
testOnHtmlTemplate(htmlEscapedUrl, htmlEscapedExpected, typeOrIncludeUri) {
71-
it('within an img src attribute', () {
76+
it('should rewrite img[src]', () {
7277
var html = resourceResolver.resolveHtml(urlInImgSrc(htmlEscapedUrl), typeOrIncludeUri);
7378
expect(html).toEqual(urlInImgSrc(htmlEscapedExpected));
7479
});
80+
81+
it('should rewrite a[href]', () {
82+
var html = resourceResolver.resolveHtml(urlInHref(htmlEscapedUrl), typeOrIncludeUri);
83+
expect(html).toEqual(urlInHref(htmlEscapedExpected));
84+
});
85+
86+
it('should rewrite form[action]', () {
87+
var html = resourceResolver.resolveHtml(urlInAction(htmlEscapedUrl), typeOrIncludeUri);
88+
expect(html).toEqual(urlInAction(htmlEscapedExpected));
89+
});
90+
91+
// IE does not support the template tag.
92+
if (!isBrowserInternetExplorer) {
93+
it('should rewrite img[src] in template tag', () {
94+
var html = resourceResolver.resolveHtml(urlInTemplateImgSrc(htmlEscapedUrl), typeOrIncludeUri);
95+
expect(html).toEqual(urlInTemplateImgSrc(htmlEscapedExpected));
96+
});
97+
98+
it('should rewrite a[href] in template tag', () {
99+
var html = resourceResolver.resolveHtml(urlInTemplateHref(htmlEscapedUrl), typeOrIncludeUri);
100+
expect(html).toEqual(urlInTemplateHref(htmlEscapedExpected));
101+
});
102+
103+
it('should rewrite form[action] in template tag', () {
104+
var html = resourceResolver.resolveHtml(urlInTemplateAction(htmlEscapedUrl), typeOrIncludeUri);
105+
expect(html).toEqual(urlInTemplateAction(htmlEscapedExpected));
106+
});
107+
}
75108
}
76109

77110
// testOnAllTemplates will insert the url to be resolved into three different types

0 commit comments

Comments
 (0)