@@ -27,7 +27,7 @@ var OPERATORS = {
27
27
} ;
28
28
var ESCAPE = { "n" :"\n" , "f" :"\f" , "r" :"\r" , "t" :"\t" , "v" :"\v" , "'" :"'" , '"' :'"' } ;
29
29
30
- function lex ( text ) {
30
+ function lex ( text , csp ) {
31
31
var tokens = [ ] ,
32
32
token ,
33
33
index = 0 ,
@@ -187,7 +187,7 @@ function lex(text){
187
187
if ( OPERATORS . hasOwnProperty ( ident ) ) {
188
188
token . fn = token . json = OPERATORS [ ident ] ;
189
189
} else {
190
- var getter = getterFn ( ident ) ;
190
+ var getter = getterFn ( ident , csp ) ;
191
191
token . fn = extend ( function ( self , locals ) {
192
192
return ( getter ( self , locals ) ) ;
193
193
} , {
@@ -261,10 +261,10 @@ function lex(text){
261
261
262
262
/////////////////////////////////////////
263
263
264
- function parser ( text , json , $filter ) {
264
+ function parser ( text , json , $filter , csp ) {
265
265
var ZERO = valueFn ( 0 ) ,
266
266
value ,
267
- tokens = lex ( text ) ,
267
+ tokens = lex ( text , csp ) ,
268
268
assignment = _assignment ,
269
269
functionCall = _functionCall ,
270
270
fieldAccess = _fieldAccess ,
@@ -532,7 +532,7 @@ function parser(text, json, $filter){
532
532
533
533
function _fieldAccess ( object ) {
534
534
var field = expect ( ) . text ;
535
- var getter = getterFn ( field ) ;
535
+ var getter = getterFn ( field , csp ) ;
536
536
return extend (
537
537
function ( self , locals ) {
538
538
return getter ( object ( self , locals ) , locals ) ;
@@ -685,32 +685,119 @@ function getter(obj, path, bindFnToScope) {
685
685
686
686
var getterFnCache = { } ;
687
687
688
- function getterFn ( path ) {
688
+ /**
689
+ * Implementation of the "Black Hole" variant from:
690
+ * - http://jsperf.com/angularjs-parse-getter/4
691
+ * - http://jsperf.com/path-evaluation-simplified/7
692
+ */
693
+ function cspSafeGetterFn ( key0 , key1 , key2 , key3 , key4 ) {
694
+ return function ( scope , locals ) {
695
+ var pathVal = ( locals && locals . hasOwnProperty ( key0 ) ) ? locals : scope ,
696
+ promise ;
697
+
698
+ if ( ! pathVal ) return pathVal ;
699
+
700
+ pathVal = pathVal [ key0 ] ;
701
+ if ( pathVal && pathVal . then ) {
702
+ if ( ! ( "$$v" in pathVal ) ) {
703
+ promise = pathVal ;
704
+ promise . $$v = undefined ;
705
+ promise . then ( function ( val ) { promise . $$v = val ; } ) ;
706
+ }
707
+ pathVal = pathVal . $$v ;
708
+ }
709
+ if ( ! key1 || ! pathVal ) return pathVal ;
710
+
711
+ pathVal = pathVal [ key1 ] ;
712
+ if ( pathVal && pathVal . then ) {
713
+ if ( ! ( "$$v" in pathVal ) ) {
714
+ promise = pathVal ;
715
+ promise . $$v = undefined ;
716
+ promise . then ( function ( val ) { promise . $$v = val ; } ) ;
717
+ }
718
+ pathVal = pathVal . $$v ;
719
+ }
720
+ if ( ! key2 || ! pathVal ) return pathVal ;
721
+
722
+ pathVal = pathVal [ key2 ] ;
723
+ if ( pathVal && pathVal . then ) {
724
+ if ( ! ( "$$v" in pathVal ) ) {
725
+ promise = pathVal ;
726
+ promise . $$v = undefined ;
727
+ promise . then ( function ( val ) { promise . $$v = val ; } ) ;
728
+ }
729
+ pathVal = pathVal . $$v ;
730
+ }
731
+ if ( ! key3 || ! pathVal ) return pathVal ;
732
+
733
+ pathVal = pathVal [ key3 ] ;
734
+ if ( pathVal && pathVal . then ) {
735
+ if ( ! ( "$$v" in pathVal ) ) {
736
+ promise = pathVal ;
737
+ promise . $$v = undefined ;
738
+ promise . then ( function ( val ) { promise . $$v = val ; } ) ;
739
+ }
740
+ pathVal = pathVal . $$v ;
741
+ }
742
+ if ( ! key4 || ! pathVal ) return pathVal ;
743
+
744
+ pathVal = pathVal [ key4 ] ;
745
+ if ( pathVal && pathVal . then ) {
746
+ if ( ! ( "$$v" in pathVal ) ) {
747
+ promise = pathVal ;
748
+ promise . $$v = undefined ;
749
+ promise . then ( function ( val ) { promise . $$v = val ; } ) ;
750
+ }
751
+ pathVal = pathVal . $$v ;
752
+ }
753
+ return pathVal ;
754
+ } ;
755
+ } ;
756
+
757
+ function getterFn ( path , csp ) {
689
758
if ( getterFnCache . hasOwnProperty ( path ) ) {
690
759
return getterFnCache [ path ] ;
691
760
}
692
761
693
- var fn , code = 'var l, fn, p;\n' ;
694
- forEach ( path . split ( '.' ) , function ( key , index ) {
695
- code += 'if(!s) return s;\n' +
696
- 'l=s;\n' +
697
- 's=' + ( index
698
- // we simply direference 's' on any .dot notation
699
- ? 's'
700
- // but if we are first then we check locals firs, and if so read it first
701
- : '((k&&k.hasOwnProperty("' + key + '"))?k:s)' ) + '["' + key + '"]' + ';\n' +
702
- 'if (s && s.then) {\n' +
703
- ' if (!("$$v" in s)) {\n' +
704
- ' p=s;\n' +
705
- ' p.$$v = undefined;\n' +
706
- ' p.then(function(v) {p.$$v=v;});\n' +
707
- '}\n' +
708
- ' s=s.$$v\n' +
709
- '}\n' ;
710
- } ) ;
711
- code += 'return s;' ;
712
- fn = Function ( 's' , 'k' , code ) ;
713
- fn . toString = function ( ) { return code ; } ;
762
+ var pathKeys = path . split ( '.' ) ,
763
+ pathKeysLength = pathKeys . length ,
764
+ fn ;
765
+
766
+ if ( csp ) {
767
+ fn = ( pathKeysLength < 6 )
768
+ ? cspSafeGetterFn ( pathKeys [ 0 ] , pathKeys [ 1 ] , pathKeys [ 2 ] , pathKeys [ 3 ] , pathKeys [ 4 ] )
769
+ : function ( scope , locals ) {
770
+ var i = 0 , val ;
771
+ do {
772
+ val = cspSafeGetterFn (
773
+ pathKeys [ i ++ ] , pathKeys [ i ++ ] , pathKeys [ i ++ ] , pathKeys [ i ++ ] , pathKeys [ i ++ ]
774
+ ) ( scope , locals ) ;
775
+ locals = undefined ; // clear after first iteration
776
+ } while ( i < pathKeysLength ) ;
777
+ } ;
778
+ } else {
779
+ var code = 'var l, fn, p;\n' ;
780
+ forEach ( pathKeys , function ( key , index ) {
781
+ code += 'if(!s) return s;\n' +
782
+ 'l=s;\n' +
783
+ 's=' + ( index
784
+ // we simply dereference 's' on any .dot notation
785
+ ? 's'
786
+ // but if we are first then we check locals first, and if so read it first
787
+ : '((k&&k.hasOwnProperty("' + key + '"))?k:s)' ) + '["' + key + '"]' + ';\n' +
788
+ 'if (s && s.then) {\n' +
789
+ ' if (!("$$v" in s)) {\n' +
790
+ ' p=s;\n' +
791
+ ' p.$$v = undefined;\n' +
792
+ ' p.then(function(v) {p.$$v=v;});\n' +
793
+ '}\n' +
794
+ ' s=s.$$v\n' +
795
+ '}\n' ;
796
+ } ) ;
797
+ code += 'return s;' ;
798
+ fn = Function ( 's' , 'k' , code ) ; // s=scope, k=locals
799
+ fn . toString = function ( ) { return code ; } ;
800
+ }
714
801
715
802
return getterFnCache [ path ] = fn ;
716
803
}
@@ -719,13 +806,13 @@ function getterFn(path) {
719
806
720
807
function $ParseProvider ( ) {
721
808
var cache = { } ;
722
- this . $get = [ '$filter' , function ( $filter ) {
809
+ this . $get = [ '$filter' , '$sniffer' , function ( $filter , $sniffer ) {
723
810
return function ( exp ) {
724
811
switch ( typeof exp ) {
725
812
case 'string' :
726
813
return cache . hasOwnProperty ( exp )
727
814
? cache [ exp ]
728
- : cache [ exp ] = parser ( exp , false , $filter ) ;
815
+ : cache [ exp ] = parser ( exp , false , $filter , $sniffer . csp ) ;
729
816
case 'function' :
730
817
return exp ;
731
818
default :
0 commit comments