Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

nodeName_ does not properly canonicalize element names when using XHTML #3987

Closed
ysulyma opened this issue Sep 12, 2013 · 19 comments
Closed

Comments

@ysulyma
Copy link
Contributor

ysulyma commented Sep 12, 2013

Angular code assumes that element names will be uppercase. I am using Angular with XHTML5 (with application/xhtml+xml MIME type), where this is not the case. The code in question is the following:

if (msie < 9) {
  nodeName_ = function(element) {
    element = element.nodeName ? element : element[0];
    return (element.scopeName && element.scopeName != 'HTML')
      ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
  };
} else {
  nodeName_ = function(element) {
    return element.nodeName ? element.nodeName : element[0].nodeName;
  };
}

I was able to remedy this in my situation by simply wrapping the return value of the else block in a call to uppercase(); however, before committing this as a fix I'd like some insight from someone who knows the internals better than me.

Specifically, I'm not sure if/how the msie < 9 block should be changed. I'm guessing the return value should be wrapped again, but does element.scopeName also need to be canonicalized? Is this a moot point since IE doesn't support XHTML anyway?

@ysulyma
Copy link
Contributor Author

ysulyma commented Sep 12, 2013

This was causing SCE to throw an error on an interpolated value in ng:src on an img element.

@petebacondarwin
Copy link
Contributor

Here is some background info: http://ejohn.org/blog/nodename-case-sensitivity/

@petebacondarwin
Copy link
Contributor

The concern I have is one of performance. It seems that wasteful to be running uppercase() all the time when the vast majority of cases do not need it.
Perhaps there could be some check of the document type, as well as browser type?

@ysulyma
Copy link
Contributor Author

ysulyma commented Sep 16, 2013

Another possible option would be to define variables IMG, OPTION, etc. which are set either to "IMG" or "img" depending on the document/browser type. Checks like nodeName_(node) != "IMG" would then be rewritten to nodeName_(node) != IMG.

@petebacondarwin
Copy link
Contributor

@yuri0 - that solution wouldn't really scale so well as new elements are defined?

@petebacondarwin
Copy link
Contributor

What does jQuery do?

@petebacondarwin
Copy link
Contributor

This doesn't look good: http://jsperf.com/jquery-is-vs-node-name-tolowercase

@petebacondarwin
Copy link
Contributor

Actually, nodeName_ is only used in a small number of places: by the SCE stuff, jqLite.val(), a check that we are not interpolating in the multiple attribute of the select element and most importantly when normalizing a directive name.

Interestingly, this last case is the only one that is not doing a direct comparison to a constant string. And in this case it is called lowercase() on the string anyway. So, if one is going to force a case then it should be lower to prevent an unnecessary lowercase(uppercase(name)) thing going on.

@ysulyma
Copy link
Contributor Author

ysulyma commented Sep 16, 2013

@petebacondarwin by my count, these types of checks are done in only 9 places throughout the code, and only on HTML, PRE, IMG, SELECT, TITLE.

@petebacondarwin
Copy link
Contributor

and A

@petebacondarwin
Copy link
Contributor

@petebacondarwin
Copy link
Contributor

Then we wouldn't need to call lowercase() when normalizing directive names and just simple check against lowercase constants. But I am still unsure of the performance impact. Some of this code is very "hot"

@petebacondarwin
Copy link
Contributor

This line: https://github.com/angular/angular.js/blob/master/src/jqLite.js#L502 could be changed to:

if (element.multiple && nodeName_(element) === 'select') {

which would be faster than it is now for the majority of cases.

@petebacondarwin
Copy link
Contributor

These lines: https://github.com/angular/angular.js/blob/master/src/ng/compile.js#L366-L370 could be changed to:

nodeName = nodeName_(this.$$element);

// sanitize a[href] and img[src] values
if ((nodeName === 'a' && key === 'href') ||
  (nodeName === 'img' && key === 'src')) {

$set is not a particular hot function.

@petebacondarwin
Copy link
Contributor

This line https://github.com/angular/angular.js/blob/master/src/ng/compile.js#L619 is made simpler:

directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);

@petebacondarwin
Copy link
Contributor

Lines https://github.com/angular/angular.js/blob/master/src/ng/compile.js#L1284 and https://github.com/angular/angular.js/blob/master/src/ng/compile.js#L1298 would simple change to

(nodeName_(node) != "img" && (attrNormalizedName == "src" ||

and

if (name === "multiple" && nodeName_(node) === "select") {

@petebacondarwin
Copy link
Contributor

There are a few places that also use node.nodeName directly. These ought to be converted to using nodeName_()

@petebacondarwin
Copy link
Contributor

@yuri0 - fancy putting a PR together?

@ysulyma
Copy link
Contributor Author

ysulyma commented Nov 13, 2013

Sorry for taking so long (mainly, not making the 1.2 release), I'd never done a PR before and then forgot about it.

petebacondarwin pushed a commit to petebacondarwin/angular.js that referenced this issue Jun 20, 2014
XHTML uses lowercase node names, while HTML often uses uppercase.  The
generally accepted convention is to always lowercase them.

Fixes angular#3987
caguillen214 pushed a commit to caguillen214/angular.js that referenced this issue Jun 30, 2014
XHTML uses lowercase node names, while HTML often uses uppercase.  The
generally accepted convention is to always lowercase them.

Fixes angular#3987
ckknight pushed a commit to ckknight/angular.js that referenced this issue Jul 16, 2014
XHTML uses lowercase node names, while HTML often uses uppercase.  The
generally accepted convention is to always lowercase them.

Fixes angular#3987
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants