| // 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. |
| |
| import 'dart:io'; |
| |
| import 'package:dart_runtime_service/dart_runtime_service.dart'; |
| import 'package:test/test.dart'; |
| |
| import 'utils/utilities.dart'; |
| |
| void main() { |
| group('Host and Origin security:', () { |
| late DartRuntimeService service; |
| late HttpClient client; |
| |
| setUp(() async { |
| service = await createDartRuntimeServiceForTest( |
| config: const DartRuntimeServiceOptions( |
| enableLogging: true, |
| disableAuthCodes: true, |
| ), |
| ); |
| client = HttpClient(); |
| }); |
| |
| tearDown(() { |
| client.close(); |
| }); |
| |
| test('allows requests with loopback Host header', () async { |
| final request = await client.getUrl(service.httpUri); |
| request.headers.set(HttpHeaders.hostHeader, 'localhost'); |
| final response = await request.close(); |
| expect(response.statusCode, isNot(equals(HttpStatus.forbidden))); |
| await response.drain<void>(); |
| }); |
| |
| test('allows requests with matching Host header', () async { |
| final request = await client.getUrl(service.httpUri); |
| request.headers.set( |
| HttpHeaders.hostHeader, |
| '${service.uri.host}:${service.uri.port}', |
| ); |
| final response = await request.close(); |
| expect(response.statusCode, isNot(equals(HttpStatus.forbidden))); |
| await response.drain<void>(); |
| }); |
| |
| test('forbids requests with invalid Host header', () async { |
| final request = await client.getUrl(service.httpUri); |
| request.headers.set(HttpHeaders.hostHeader, 'evil.example.com'); |
| final response = await request.close(); |
| expect(response.statusCode, equals(HttpStatus.forbidden)); |
| await response.drain<void>(); |
| }); |
| |
| test('allows requests with loopback Origin header', () async { |
| final request = await client.getUrl(service.httpUri); |
| request.headers.set('Origin', 'http://localhost'); |
| final response = await request.close(); |
| expect(response.statusCode, isNot(equals(HttpStatus.forbidden))); |
| await response.drain<void>(); |
| }); |
| |
| test('allows requests with matching Origin header', () async { |
| final request = await client.getUrl(service.httpUri); |
| request.headers.set('Origin', service.httpUri.toString()); |
| final response = await request.close(); |
| expect(response.statusCode, isNot(equals(HttpStatus.forbidden))); |
| await response.drain<void>(); |
| }); |
| |
| test('forbids requests with invalid Origin header', () async { |
| final request = await client.getUrl(service.httpUri); |
| request.headers.set('Origin', 'http://evil.example.com'); |
| final response = await request.close(); |
| expect(response.statusCode, equals(HttpStatus.forbidden)); |
| await response.drain<void>(); |
| }); |
| |
| test( |
| 'allows invalid Host and Origin when origin checks are disabled', |
| () async { |
| final noCheckService = await createDartRuntimeServiceForTest( |
| config: const DartRuntimeServiceOptions( |
| enableLogging: true, |
| disableAuthCodes: true, |
| disableOriginCheck: true, |
| ), |
| ); |
| |
| final request = await client.getUrl(noCheckService.httpUri); |
| request.headers.set(HttpHeaders.hostHeader, 'evil.example.com'); |
| request.headers.set('Origin', 'http://evil.example.com'); |
| final response = await request.close(); |
| expect(response.statusCode, isNot(equals(HttpStatus.forbidden))); |
| await response.drain<void>(); |
| }, |
| ); |
| }); |
| } |