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

Commit

Permalink
fix(resource_url_resolver): IE/Safari compatible HTML parsing
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
chirayuk committed Oct 10, 2014
1 parent f8d0123 commit ecb7db2
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 15 deletions.
38 changes: 38 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,44 @@ env:
- JOB=e2e-dev
CHANNEL=dev
BROWSERS=DartiumWithWebPlatform,SL_Chrome

# Temporary jobs to test IE and Safari to be removed in the next commit.
- JOB=unit-stable-ie10
CHANNEL=stable
TESTS=dart2js
BROWSERS=SL_IE10
- JOB=unit-dev-ie10
CHANNEL=dev
TESTS=dart2js
BROWSERS=SL_IE10

- JOB=unit-stable-ie11
CHANNEL=stable
TESTS=dart2js
BROWSERS=SL_IE11
- JOB=unit-dev-ie11
CHANNEL=dev
TESTS=dart2js
BROWSERS=SL_IE11

- JOB=unit-stable-safari6
CHANNEL=stable
TESTS=dart2js
BROWSERS=SL_Safari6
- JOB=unit-dev-safari6
CHANNEL=dev
TESTS=dart2js
BROWSERS=SL_Safari6

- JOB=unit-stable-safari7
CHANNEL=stable
TESTS=dart2js
BROWSERS=SL_Safari7
- JOB=unit-dev-safari7
CHANNEL=dev
TESTS=dart2js
BROWSERS=SL_Safari7

global:
- secure: AKoqpZ699egF0i4uT/FQ5b4jIc0h+KVbhtVCql0uFxwFIl2HjOYgDayrUCAf6USfpW0LghZxJJhBamWOl/505eNSe9HvEd8JLg/to+1Fo9xi9llsu5ehmNH31/5pue4EvsrVuEap1qqL6/BNwI2cAryayU0p5tV0g8gL5h4IxG8=
- LOGS_DIR=/tmp/angular-build/logs
Expand Down
17 changes: 6 additions & 11 deletions lib/core_dom/resource_url_resolver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,28 @@ class _NullTreeSanitizer implements NodeTreeSanitizer {

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

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

final TypeToUriMapper _uriMapper;
final ResourceResolverConfig _config;

ResourceUrlResolver(this._uriMapper, this._config);

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

static Node _parseHtmlString(String html) {
HtmlDocument doc = new DomParser().parseFromString(
"<!doctype html><html><body>$html</body></html>", "text/html");
if (doc != null) {
return doc.body;
}
// Workaround for Safari (can't parse HTML documents via the DomParser)
doc = document.implementation.createHtmlDocument("");
doc.body.setInnerHtml(html, treeSanitizer: _nullTreeSanitizer);
return doc.body;
var div = docForParsing.createElement('div');
div.setInnerHtml(html, treeSanitizer: _nullTreeSanitizer);
return div;
}

String resolveHtml(String html, [Uri baseUri]) {
Expand Down
41 changes: 37 additions & 4 deletions test/core_dom/resource_url_resolver_spec.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
library angular.test.core_dom.uri_resolver_spec;

import 'dart:html';
import 'package:angular/core_dom/resource_url_resolver.dart';
import 'package:angular/core_dom/type_to_uri_mapper.dart';
import 'package:angular/core_dom/type_to_uri_mapper_dynamic.dart';
import '../_specs.dart';

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

_run_resolver({useRelativeUrls}) {
describe("resolveUrls=$useRelativeUrls", () {
Expand Down Expand Up @@ -45,9 +47,12 @@ _run_resolver({useRelativeUrls}) {

String urlInImport(cssEscapedUrl) => '<style>@import $cssEscapedUrl</style>';
String urlInBackgroundImg(cssEscapedUrl) => '<style>body { background-image: $cssEscapedUrl }</style>';
String urlInImgSrc(htmlEscapedUrl) => '<template><img src=\"$htmlEscapedUrl\"></template>';
String urlInHref(htmlEscapedUrl) => '<template><a href=\"$htmlEscapedUrl\"></template>';
String urlInAction(htmlEscapedUrl) => '<template><form action=\"$htmlEscapedUrl\"></template>';
String urlInTemplateImgSrc(htmlEscapedUrl) => '<template><img src=\"$htmlEscapedUrl\"></template>';
String urlInTemplateHref(htmlEscapedUrl) => '<template><a href=\"$htmlEscapedUrl\"></a></template>';
String urlInTemplateAction(htmlEscapedUrl) => '<template><form action=\"$htmlEscapedUrl\"></form></template>';
String urlInImgSrc(htmlEscapedUrl) => '<div><img src=\"$htmlEscapedUrl\"></div>';
String urlInHref(htmlEscapedUrl) => '<div><a href=\"$htmlEscapedUrl\"></a></div>';
String urlInAction(htmlEscapedUrl) => '<div><form action=\"$htmlEscapedUrl\"></form></div>';

escapeUrlForCss(String unEscapedUrl) {
return unEscapedUrl..replaceAll("\\", "\\\\")
Expand All @@ -68,10 +73,38 @@ _run_resolver({useRelativeUrls}) {
}

testOnHtmlTemplate(htmlEscapedUrl, htmlEscapedExpected, typeOrIncludeUri) {
it('within an img src attribute', () {
it('should rewrite img[src]', () {
var html = resourceResolver.resolveHtml(urlInImgSrc(htmlEscapedUrl), typeOrIncludeUri);
expect(html).toEqual(urlInImgSrc(htmlEscapedExpected));
});

it('should rewrite a[href]', () {
var html = resourceResolver.resolveHtml(urlInHref(htmlEscapedUrl), typeOrIncludeUri);
expect(html).toEqual(urlInHref(htmlEscapedExpected));
});

it('should rewrite form[action]', () {
var html = resourceResolver.resolveHtml(urlInAction(htmlEscapedUrl), typeOrIncludeUri);
expect(html).toEqual(urlInAction(htmlEscapedExpected));
});

// IE does not support the template tag.
if (!isBrowserInternetExplorer) {
it('should rewrite img[src] in template tag', () {
var html = resourceResolver.resolveHtml(urlInTemplateImgSrc(htmlEscapedUrl), typeOrIncludeUri);
expect(html).toEqual(urlInTemplateImgSrc(htmlEscapedExpected));
});

it('should rewrite a[href] in template tag', () {
var html = resourceResolver.resolveHtml(urlInTemplateHref(htmlEscapedUrl), typeOrIncludeUri);
expect(html).toEqual(urlInTemplateHref(htmlEscapedExpected));
});

it('should rewrite form[action] in template tag', () {
var html = resourceResolver.resolveHtml(urlInTemplateAction(htmlEscapedUrl), typeOrIncludeUri);
expect(html).toEqual(urlInTemplateAction(htmlEscapedExpected));
});
}
}

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

0 comments on commit ecb7db2

Please sign in to comment.