blob: 8c5591a76b97229f88fd45a750b5bd005d4d7b2b [file] [edit]
// 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>();
},
);
});
}