@@ -538,6 +538,7 @@ function Framework() {
538538 sitemap : null ,
539539 web : [ ] ,
540540 files : [ ] ,
541+ cors : [ ] ,
541542 websockets : [ ] ,
542543 middleware : { } ,
543544 redirects : { } ,
@@ -607,6 +608,7 @@ function Framework() {
607608 head : 0 ,
608609 post : 0 ,
609610 put : 0 ,
611+ path : 0 ,
610612 upload : 0 ,
611613 blocked : 0 ,
612614 'delete' : 0 ,
@@ -657,6 +659,7 @@ function Framework() {
657659 this . _length_files = 0 ;
658660 this . _length_wait = 0 ;
659661 this . _length_themes = 0 ;
662+ this . _length_cors = 0 ;
660663
661664 this . isVirtualDirectory = false ;
662665 this . isTheme = false ;
@@ -1078,6 +1081,77 @@ Framework.prototype.restful = function(url, flags, onQuery, onGet, onSave, onDel
10781081 return self ;
10791082} ;
10801083
1084+ /**
1085+ * Register cors
1086+ * @param {String } url
1087+ * @param {String Array or String } origin
1088+ * @param {String Array or String } methods
1089+ * @param {String Array or String } headers
1090+ * @param {Boolean } credentials
1091+ * @return {Framework }
1092+ */
1093+ Framework . prototype . cors = function ( url , origin , methods , credentials , headers ) {
1094+
1095+ var self = this ;
1096+ var route = { } ;
1097+ var tmp ;
1098+
1099+ if ( typeof ( credentials ) === STRING || credentials instanceof Array ) {
1100+ tmp = headers ;
1101+ headers = credentials ;
1102+ credentials = tmp ;
1103+ }
1104+
1105+ if ( typeof ( origin ) === STRING )
1106+ origin = origin . split ( ',' ) . trim ( ) ;
1107+ if ( typeof ( methods ) === STRING )
1108+ methods = methods . split ( ',' ) . trim ( ) ;
1109+ if ( typeof ( headers ) === STRING )
1110+ headers = headers . split ( ',' ) . trim ( ) ;
1111+
1112+ if ( ! headers )
1113+ headers = [ '*' ] ;
1114+ if ( ! origin )
1115+ origin = [ '*' ] ;
1116+ if ( ! methods )
1117+ methods = [ '*' ] ;
1118+
1119+ route . isASTERIX = url . lastIndexOf ( '*' ) !== - 1 ;
1120+
1121+ if ( route . isASTERIX )
1122+ url = url . replace ( '*' , '' ) ;
1123+
1124+ for ( var i = 0 , length = origin . length ; i < length ; i ++ )
1125+ origin [ i ] = origin [ i ] . toLowerCase ( ) ;
1126+
1127+ for ( var i = 0 , length = headers . length ; i < length ; i ++ )
1128+ headers [ i ] = headers [ i ] . toLowerCase ( ) ;
1129+
1130+ for ( var i = 0 , length = methods . length ; i < length ; i ++ )
1131+ methods [ i ] = methods [ i ] . toUpperCase ( ) ;
1132+
1133+ route . url = framework_internal . routeSplitCreate ( framework_internal . encodeUnicodeURL ( url . trim ( ) ) ) ;
1134+ route . origin = origin . indexOf ( '*' ) === - 1 ? origin : null ;
1135+ route . methods = methods . indexOf ( '*' ) === - 1 ? methods : [ 'GET' , 'POST' , 'PUT' , 'DELETE' , 'OPTIONS' , 'PATH' , 'HEAD' , 'OPTIONS' ] ;
1136+ route . headers = headers . indexOf ( '*' ) === - 1 ? headers : null ;
1137+ route . credentials = credentials ;
1138+
1139+ self . routes . cors . push ( route ) ;
1140+ self . _length_cors = self . routes . cors . length ;
1141+
1142+ self . routes . cors . sort ( function ( a , b ) {
1143+ var al = a . url . length ;
1144+ var bl = b . url . length ;
1145+ if ( al > bl )
1146+ return - 1 ;
1147+ if ( al < bl )
1148+ return 1 ;
1149+ return a . isASTERIX && b . isASTERIX ? 1 : 0 ;
1150+ } ) ;
1151+
1152+ return self ;
1153+ } ;
1154+
10811155/**
10821156 * Add a route
10831157 * @param {String } url
@@ -6254,39 +6328,94 @@ Framework.prototype._request_continue = function(req, res, headers, protocol) {
62546328 }
62556329 }
62566330
6331+ var skipCors = ! req . headers [ 'origin' ] || ! self . _length_cors ;
62576332 req . flags = flags ;
6258-
6259- // call event request
62606333 self . emit ( 'request-begin' , req , res ) ;
62616334
62626335 switch ( first ) {
62636336 case 'G' :
62646337 self . stats . request . get ++ ;
6265- new Subscribe ( self , req , res , 0 ) . end ( ) ;
6338+
6339+ if ( skipCors ) {
6340+ new Subscribe ( self , req , res , 0 ) . end ( ) ;
6341+ return self ;
6342+ }
6343+
6344+ self . _cors ( req , res , function ( req , res ) {
6345+ new Subscribe ( framework , req , res , 0 ) . end ( ) ;
6346+ } ) ;
62666347 return self ;
6348+
62676349 case 'O' :
62686350 self . stats . request . options ++ ;
6269- new Subscribe ( self , req , res , 0 ) . end ( ) ;
6351+
6352+ if ( skipCors ) {
6353+ new Subscribe ( framework , req , res , 0 ) . end ( ) ;
6354+ return self ;
6355+ }
6356+
6357+ self . _cors ( req , res ) ;
62706358 return self ;
6359+
62716360 case 'H' :
62726361 self . stats . request . head ++ ;
6273- new Subscribe ( self , req , res , 0 ) . end ( ) ;
6362+
6363+ if ( skipCors ) {
6364+ new Subscribe ( self , req , res , 0 ) . end ( ) ;
6365+ return self ;
6366+ }
6367+
6368+ self . _cors ( req , res , function ( req , res ) {
6369+ new Subscribe ( framework , req , res , 0 ) . end ( ) ;
6370+ } ) ;
6371+
62746372 return self ;
6373+
62756374 case 'D' :
62766375 self . stats . request [ 'delete' ] ++ ;
6277- new Subscribe ( self , req , res , 1 ) . urlencoded ( ) ;
6376+
6377+ if ( skipCors ) {
6378+ new Subscribe ( self , req , res , 1 ) . urlencoded ( ) ;
6379+ return self ;
6380+ }
6381+
6382+ self . _cors ( req , res , function ( req , res ) {
6383+ new Subscribe ( framework , req , res , 1 ) . urlencoded ( ) ;
6384+ } ) ;
6385+
62786386 return self ;
62796387 case 'P' :
62806388 if ( self . _request_check_POST ) {
62816389 if ( multipart ) {
62826390 self . stats . request . upload ++ ;
6283- new Subscribe ( self , req , res , 2 ) . multipart ( multipart ) ;
6391+
6392+ if ( skipCors ) {
6393+ new Subscribe ( self , req , res , 2 ) . multipart ( multipart ) ;
6394+ return self ;
6395+ }
6396+
6397+ self . _cors ( req , res , function ( req , res , multipart ) {
6398+ new Subscribe ( self , req , res , 2 ) . multipart ( multipart ) ;
6399+ } , multipart ) ;
6400+
6401+ return self ;
6402+
62846403 } else {
62856404 if ( method === 'PUT' )
62866405 self . stats . request . put ++ ;
6406+ else if ( method === 'PATH' )
6407+ self . stats . request . path ++ ;
62876408 else
62886409 self . stats . request . post ++ ;
6289- new Subscribe ( self , req , res , 1 ) . urlencoded ( ) ;
6410+
6411+ if ( skipCors ) {
6412+ new Subscribe ( self , req , res , 1 ) . urlencoded ( ) ;
6413+ return self ;
6414+ }
6415+
6416+ self . _cors ( req , res , function ( req , res ) {
6417+ new Subscribe ( self , req , res , 1 ) . urlencoded ( ) ;
6418+ } ) ;
62906419 }
62916420 return self ;
62926421 }
@@ -6301,6 +6430,142 @@ Framework.prototype._request_continue = function(req, res, headers, protocol) {
63016430 return self ;
63026431} ;
63036432
6433+ Framework . prototype . _cors = function ( req , res , fn , arg ) {
6434+
6435+ var self = this ;
6436+ var cors ;
6437+ var is = false ;
6438+
6439+ for ( var i = 0 ; i < self . _length_cors ; i ++ ) {
6440+ cors = self . routes . cors [ i ] ;
6441+ if ( ! framework_internal . routeCompare ( req . path , cors . url , false , cors . isASTERIX ) )
6442+ continue ;
6443+ is = true ;
6444+ break ;
6445+ }
6446+
6447+ if ( ! is ) {
6448+ fn = null ;
6449+ self . emit ( 'request-end' , req , res ) ;
6450+ self . _request_stats ( false , false ) ;
6451+ self . stats . request . blocked ++ ;
6452+ res . writeHead ( 404 ) ;
6453+ res . end ( ) ;
6454+ return ;
6455+ }
6456+
6457+ is = false ;
6458+
6459+ // compare
6460+ var isAllowed = false ;
6461+ var headers = req . headers ;
6462+
6463+ if ( cors . headers ) {
6464+
6465+ for ( var i = 0 , length = cors . headers . length ; i < length ; i ++ ) {
6466+ if ( headers [ cors . headers [ i ] ] ) {
6467+ isAllowed = true ;
6468+ break ;
6469+ }
6470+ }
6471+
6472+ if ( ! isAllowed ) {
6473+ fn = null ;
6474+ self . emit ( 'request-end' , req , res ) ;
6475+ self . _request_stats ( false , false ) ;
6476+ self . stats . request . blocked ++ ;
6477+ res . writeHead ( 404 ) ;
6478+ res . end ( ) ;
6479+ return ;
6480+ }
6481+
6482+ isAllowed = false ;
6483+ }
6484+
6485+ if ( cors . methods ) {
6486+
6487+ var current = headers [ 'access-control-request-method' ] || req . method ;
6488+ if ( current !== 'OPTIONS' ) {
6489+ for ( var i = 0 , length = cors . methods . length ; i < length ; i ++ ) {
6490+ if ( current . indexOf ( cors . methods [ i ] ) !== - 1 )
6491+ isAllowed = true ;
6492+ }
6493+
6494+ if ( ! isAllowed ) {
6495+ fn = null ;
6496+ self . emit ( 'request-end' , req , res ) ;
6497+ self . _request_stats ( false , false ) ;
6498+ self . stats . request . blocked ++ ;
6499+ res . writeHead ( 404 ) ;
6500+ res . end ( ) ;
6501+ return ;
6502+ }
6503+ }
6504+
6505+ isAllowed = false ;
6506+ }
6507+
6508+ var origin = headers [ 'origin' ] . toLowerCase ( ) ;
6509+
6510+ if ( cors . origin ) {
6511+ for ( var i = 0 , length = cors . origin . length ; i < length ; i ++ ) {
6512+ if ( cors . origin [ i ] . indexOf ( origin ) !== - 1 ) {
6513+ isAllowed = true ;
6514+ break ;
6515+ }
6516+ }
6517+
6518+ if ( ! isAllowed ) {
6519+ fn = null ;
6520+ self . emit ( 'request-end' , req , res ) ;
6521+ self . _request_stats ( false , false ) ;
6522+ self . stats . request . blocked ++ ;
6523+ res . writeHead ( 404 ) ;
6524+ res . end ( ) ;
6525+ return ;
6526+ }
6527+ }
6528+
6529+ var tmp ;
6530+ var name ;
6531+ var isOPTIONS = req . method === 'OPTIONS' ;
6532+
6533+ res . setHeader ( 'Access-Control-Allow-Origin' , cors . origin ? cors . origin : '*' ) ;
6534+
6535+ if ( cors . credentials )
6536+ res . setHeader ( 'Access-Control-Allow-Credentials' , 'true' ) ;
6537+
6538+ name = 'Access-Control-Allow-Methods' ;
6539+
6540+ if ( cors . methods ) {
6541+ res . setHeader ( name , cors . methods . join ( ', ' ) ) ;
6542+ } else if ( isOPTIONS ) {
6543+ tmp = headers [ 'access-control-request-method' ] ;
6544+ if ( tmp )
6545+ res . setHeader ( name , tmp ) ;
6546+ }
6547+
6548+ name = 'Access-Control-Allow-Headers' ;
6549+
6550+ if ( cors . headers ) {
6551+ res . setHeader ( name , cors . headers . join ( ', ' ) ) ;
6552+ } else if ( isOPTIONS ) {
6553+ tmp = headers [ 'access-control-request-headers' ] ;
6554+ if ( tmp )
6555+ res . setHeader ( name , tmp ) ;
6556+ }
6557+
6558+ if ( ! isOPTIONS )
6559+ return fn ( req , res , arg ) ;
6560+
6561+ fn = null ;
6562+ self . emit ( 'request-end' , req , res ) ;
6563+ self . _request_stats ( false , false ) ;
6564+ res . writeHead ( 200 ) ;
6565+ res . end ( ) ;
6566+ return self ;
6567+ } ;
6568+
63046569/**
63056570 * Upgrade HTTP (WebSocket)
63066571 * @param {HttpRequest } req
@@ -9921,7 +10186,6 @@ Controller.prototype.cors = function(allow, method, header, credentials) {
992110186
992210187 var self = this ;
992310188 var origin = self . req . headers [ 'origin' ] ;
9924- var isOPTIONS = self . req . method . toUpperCase ( ) === 'OPTIONS' ;
992510189
992610190 if ( origin === undefined )
992710191 return true ;
@@ -10002,6 +10266,7 @@ Controller.prototype.cors = function(allow, method, header, credentials) {
1000210266 if ( ! isAllowed )
1000310267 return false ;
1000410268
10269+ var isOPTIONS = self . req . method . toUpperCase ( ) === 'OPTIONS' ;
1000510270 var tmp ;
1000610271 var name ;
1000710272
0 commit comments