platform/lib/angel_cors.dart

101 lines
3.2 KiB
Dart
Raw Normal View History

2016-12-05 02:16:54 +00:00
/// Angel CORS middleware.
library angel_cors;
2019-02-07 16:46:47 +00:00
import 'dart:async';
2016-12-05 02:16:54 +00:00
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.
2019-02-07 16:46:47 +00:00
typedef bool _CorsFilter(String origin);
2016-12-05 02:16:54 +00:00
2019-02-07 16:46:47 +00:00
bool _isOriginAllowed(String origin, [allowedOrigin]) {
2017-11-18 17:30:39 +00:00
allowedOrigin ??= [];
2019-02-07 16:46:47 +00:00
if (allowedOrigin is Iterable) {
2016-12-05 02:16:54 +00:00
return allowedOrigin.any((x) => _isOriginAllowed(origin, x));
} else if (allowedOrigin is String) {
return origin == allowedOrigin;
} else if (allowedOrigin is RegExp) {
2017-11-18 17:30:39 +00:00
return origin != null && allowedOrigin.hasMatch(origin);
2019-02-07 16:46:47 +00:00
} else if (origin != null && allowedOrigin is _CorsFilter) {
2016-12-05 02:16:54 +00:00
return allowedOrigin(origin);
} else {
return allowedOrigin != false;
}
}
2019-02-07 16:46:47 +00:00
/// On-the-fly configures the [cors] handler. Use this when the context of the surrounding request
/// is necessary to decide how to handle an incoming request.
Future<bool> Function(RequestContext, ResponseContext) dynamicCors(
FutureOr<CorsOptions> Function(RequestContext, ResponseContext) f) {
return (req, res) async {
var opts = await f(req, res);
var handler = cors(opts);
return await handler(req, res);
};
}
2016-12-05 02:16:54 +00:00
/// Applies the given [CorsOptions].
2019-02-07 16:46:47 +00:00
Future<bool> Function(RequestContext, ResponseContext) cors(
[CorsOptions options]) {
options ??= CorsOptions();
2016-12-05 02:16:54 +00:00
2019-02-07 16:46:47 +00:00
return (req, res) async {
// access-control-allow-credentials
if (options.credentials == true) {
res.headers['access-control-allow-credentials'] = 'true';
2016-12-05 02:16:54 +00:00
}
2019-02-07 16:46:47 +00:00
// access-control-allow-headers
if (req.method == 'OPTIONS' && options.allowedHeaders.isNotEmpty) {
res.headers['access-control-allow-headers'] =
options.allowedHeaders.join(',');
} else if (req.headers['access-control-request-headers'] != null) {
res.headers['access-control-allow-headers'] =
req.headers.value('access-control-request-headers');
2016-12-05 02:16:54 +00:00
}
2019-02-07 16:46:47 +00:00
// access-control-expose-headers
if (options.exposedHeaders.isNotEmpty) {
res.headers['access-control-expose-headers'] =
options.exposedHeaders.join(',');
2016-12-05 02:16:54 +00:00
}
2019-02-07 16:46:47 +00:00
// access-control-allow-methods
if (req.method == 'OPTIONS' && options.methods.isNotEmpty) {
res.headers['access-control-allow-methods'] = options.methods.join(',');
2016-12-05 02:16:54 +00:00
}
2019-02-07 16:46:47 +00:00
// access-control-max-age
if (req.method == 'OPTIONS' && options.maxAge != null) {
res.headers['access-control-max-age'] = options.maxAge.toString();
2016-12-05 02:16:54 +00:00
}
2019-02-07 16:46:47 +00:00
// access-control-allow-origin
if (options.origin == false || options.origin == '*') {
res.headers['access-control-allow-origin'] = '*';
} else if (options.origin is String) {
2016-12-05 02:16:54 +00:00
res
2019-02-07 16:46:47 +00:00
..headers['access-control-allow-origin'] = options.origin as String
..headers['vary'] = 'origin';
2016-12-05 02:16:54 +00:00
} else {
bool isAllowed =
2019-02-07 16:46:47 +00:00
_isOriginAllowed(req.headers.value('origin'), options.origin);
2016-12-05 02:16:54 +00:00
2019-02-07 16:46:47 +00:00
res.headers['access-control-allow-origin'] =
isAllowed ? req.headers.value('origin') : false.toString();
2016-12-05 02:16:54 +00:00
if (isAllowed) {
2019-02-07 16:46:47 +00:00
res.headers['vary'] = 'origin';
2016-12-05 02:16:54 +00:00
}
}
2019-02-07 16:46:47 +00:00
if (req.method != 'OPTIONS') return true;
res.statusCode = options.successStatus ?? 204;
res.contentLength = 0;
await res.close();
return options.preflightContinue;
2016-12-05 02:16:54 +00:00
};
}