2016-12-05 02:16:54 +00:00
|
|
|
/// Angel CORS middleware.
|
|
|
|
library angel_cors;
|
|
|
|
|
|
|
|
import 'package:angel_framework/angel_framework.dart';
|
|
|
|
import 'src/cors_options.dart';
|
|
|
|
export 'src/cors_options.dart';
|
|
|
|
|
|
|
|
/// Determines if a request origin is CORS-able.
|
|
|
|
typedef bool CorsFilter(String origin);
|
|
|
|
|
|
|
|
bool _isOriginAllowed(String origin, allowedOrigin) {
|
|
|
|
if (allowedOrigin is List) {
|
|
|
|
return allowedOrigin.any((x) => _isOriginAllowed(origin, x));
|
|
|
|
} else if (allowedOrigin is String) {
|
|
|
|
return origin == allowedOrigin;
|
|
|
|
} else if (allowedOrigin is RegExp) {
|
|
|
|
return allowedOrigin.hasMatch(origin);
|
|
|
|
} else if (allowedOrigin is CorsFilter) {
|
|
|
|
return allowedOrigin(origin);
|
|
|
|
} else {
|
|
|
|
return allowedOrigin != false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Applies the given [CorsOptions].
|
|
|
|
RequestMiddleware cors([CorsOptions options]) {
|
|
|
|
final opts = options ?? new CorsOptions();
|
|
|
|
|
2016-12-05 02:48:35 +00:00
|
|
|
/*
|
|
|
|
print(opts.credentials);
|
|
|
|
print(opts.allowedHeaders);
|
|
|
|
print(opts.methods);
|
|
|
|
print(opts.exposedHeaders);
|
|
|
|
print(opts.maxAge);
|
|
|
|
print(opts.origin);
|
|
|
|
*/
|
|
|
|
|
2016-12-05 02:16:54 +00:00
|
|
|
return (RequestContext req, ResponseContext res) async {
|
|
|
|
// Access-Control-Allow-Credentials
|
|
|
|
if (opts.credentials == true) {
|
|
|
|
res.header('Access-Control-Allow-Credentials', 'true');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Access-Control-Allow-Headers
|
2016-12-05 05:15:28 +00:00
|
|
|
if (req.method == 'OPTIONS' && opts.allowedHeaders.isNotEmpty) {
|
2016-12-05 02:16:54 +00:00
|
|
|
res.header('Access-Control-Allow-Headers', opts.allowedHeaders.join(','));
|
2016-12-05 05:15:28 +00:00
|
|
|
} else if (req.method == 'OPTIONS') {
|
2016-12-05 02:48:35 +00:00
|
|
|
res.header('Access-Control-Allow-Headers',
|
|
|
|
req.headers.value('Access-Control-Allow-Headers'));
|
2016-12-05 02:16:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Access-Control-Expose-Headers
|
|
|
|
if (opts.exposedHeaders.isNotEmpty) {
|
|
|
|
res.header(
|
|
|
|
'Access-Control-Expose-Headers', opts.exposedHeaders.join(','));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Access-Control-Allow-Methods
|
2016-12-05 05:15:28 +00:00
|
|
|
if (req.method == 'OPTIONS' && opts.methods.isNotEmpty) {
|
2016-12-05 02:16:54 +00:00
|
|
|
res.header('Access-Control-Allow-Methods', opts.methods.join(','));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Access-Control-Max-Age
|
2016-12-05 05:15:28 +00:00
|
|
|
if (req.method == 'OPTIONS' && opts.maxAge != null) {
|
2016-12-05 02:16:54 +00:00
|
|
|
res.header('Access-Control-Max-Age', opts.maxAge.toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Access-Control-Allow-Origin
|
|
|
|
if (opts.origin == false || opts.origin == '*') {
|
|
|
|
res.header('Access-Control-Allow-Origin', '*');
|
|
|
|
} else if (opts.origin is String) {
|
|
|
|
res
|
|
|
|
..header('Access-Control-Allow-Origin', opts.origin)
|
|
|
|
..header('Vary', 'Origin');
|
|
|
|
} else {
|
|
|
|
bool isAllowed =
|
|
|
|
_isOriginAllowed(req.headers.value('Origin'), opts.origin);
|
|
|
|
|
|
|
|
res.header('Access-Control-Allow-Origin',
|
|
|
|
isAllowed ? req.headers.value('Origin') : false.toString());
|
|
|
|
|
|
|
|
if (isAllowed) {
|
|
|
|
res.header('Vary', 'Origin');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-05 05:15:28 +00:00
|
|
|
return req.method != 'OPTIONS' || opts.preflightContinue;
|
2016-12-05 02:16:54 +00:00
|
|
|
};
|
|
|
|
}
|