| // Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| /// Returns `true` if [origin] is a valid origin that is allowed to connect. | |
| /// | |
| /// Loopback addresses (localhost, 127.0.0.1, ::1) are always allowed. | |
| /// | |
| /// If [allowedUris] is provided, connections matching the host and port of any | |
| /// URI in the list are allowed. | |
| /// | |
| /// If [allowedHosts] and [allowedPort] are provided, connections matching any | |
| /// host in [allowedHosts] with the specified [allowedPort] are allowed. | |
| bool isAllowedOrigin( | |
| String origin, { | |
| List<String> allowedHosts = const [], | |
| int? allowedPort, | |
| List<Uri> allowedUris = const [], | |
| }) { | |
| Uri uri; | |
| try { | |
| // The Origin/Host headers are user-controlled and could contain | |
| // malformed URIs, so we must guard against parsing failures. | |
| // | |
| // Note: If origin doesn't start with a scheme, Uri.parse might not parse it | |
| // correctly as a URI with a host. However, Origin headers always have a | |
| // scheme (http:// or https://), and we prepend one when validating Host | |
| // headers. | |
| uri = Uri.parse(origin); | |
| } catch (_) { | |
| return false; | |
| } | |
| final host = uri.host; | |
| // Loopback is always allowed. | |
| if (host == 'localhost' || host == '127.0.0.1' || host == '::1') { | |
| return true; | |
| } | |
| // Check allowed URIs. | |
| for (final allowedUri in allowedUris) { | |
| if (host == allowedUri.host && uri.port == allowedUri.port) { | |
| return true; | |
| } | |
| } | |
| // Check allowed hosts with specific port. | |
| if (allowedPort != null) { | |
| for (final allowedHost in allowedHosts) { | |
| if (host == allowedHost && uri.port == allowedPort) { | |
| return true; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| /// Returns `true` if [hostHeader] is a valid host header value that is allowed. | |
| bool isAllowedHost( | |
| String hostHeader, { | |
| List<String> allowedHosts = const [], | |
| int? allowedPort, | |
| List<Uri> allowedUris = const [], | |
| }) { | |
| // Host header might not have a scheme, so prepend http:// to parse it as | |
| // an origin. | |
| return isAllowedOrigin( | |
| 'http://$hostHeader', | |
| allowedHosts: allowedHosts, | |
| allowedPort: allowedPort, | |
| allowedUris: allowedUris, | |
| ); | |
| } |