Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
## 4.2.1-wip
## 4.3.0

- Added `--quiet` flag to disable request logging.

## 4.2.0

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ $ dhttpd --help
--path=<path> The path to serve. If not set, the current directory is used.
-p, --port=<port> The port to listen on. Provide `0` to use a random port.
(defaults to "8080")
-q, --quiet Disable logging.
--sslcert=<sslcert> The SSL certificate to use. Also requires sslkey
--sslkey=<sslkey> The key of the SSL certificate to use. Also requires sslcert
--sslkeypassword=<sslkeypassword> The password for the key of the SSL certificate to use.
Expand Down
1 change: 1 addition & 0 deletions bin/dhttpd.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Future<void> main(List<String> args) async {
sslKey: options.sslkey,
sslPassword: options.sslkeypassword,
listFiles: options.listFiles,
quiet: options.quiet,
);

print('Serving ${httpd.path} at ${httpd.urlBase}');
Expand Down
39 changes: 33 additions & 6 deletions lib/dhttpd.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,37 @@ final class Dhttpd {

bool get isSSL => _securityContext != null;

/// [address] can either be a [String] or an
/// Starts an HTTP server serving static files from a directory.
///
/// The [path] specifies the directory to serve. If omitted, the current
/// working directory is used.
///
/// The server will listen on the specified [port], which defaults to
/// [defaultPort] (`8080`). If [port] is `0`, a random available port
/// will be chosen.
///
/// The [address] can either be a [String] or an
/// [InternetAddress]. If [address] is a [String], [start] will
/// perform a [InternetAddress.lookup] and use the first value in the
/// list. To listen on the loopback adapter, which will allow only
/// incoming connections from the local host, use the value
/// [InternetAddress.loopbackIPv4] or
/// [InternetAddress.loopbackIPv6]. To allow for incoming
/// connection from the network use either one of the values
/// connections from the network, use either one of the values
/// [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
/// bind to all interfaces or the IP address of a specific interface.
/// bind to all interfaces, or use the IP address of a specific interface.
///
/// HTTP headers provided in [headers] will be applied to every response
/// returned by the server.
///
/// To serve over HTTPS, provide both [sslCert] and [sslKey]. These should
/// be paths to the certificate chain and private key, respectively. If the
/// private key is password-protected, [sslPassword] must also be provided.
///
/// If [listFiles] is `true`, a directory listing will be displayed when
/// navigating to a directory that does not contain an `index.html` file.
///
/// If [quiet] is `true`, request logging will be disabled.
static Future<Dhttpd> start({
String? path,
int port = defaultPort,
Expand All @@ -42,6 +63,7 @@ final class Dhttpd {
String? sslKey,
String? sslPassword,
bool listFiles = false,
bool quiet = false,
}) async {
path ??= Directory.current.path;

Expand All @@ -52,8 +74,13 @@ final class Dhttpd {
..usePrivateKey(sslKey, password: sslPassword);
}

final pipeline = const Pipeline()
.addMiddleware(logRequests())
var pipeline = const Pipeline();

if (!quiet) {
pipeline = pipeline.addMiddleware(logRequests());
}

final handler = pipeline
.addMiddleware(_headersMiddleware(headers))
.addHandler(
createStaticHandler(
Expand All @@ -64,7 +91,7 @@ final class Dhttpd {
);

final server = await io.serve(
pipeline,
handler,
address,
port,
securityContext: securityContext,
Expand Down
4 changes: 4 additions & 0 deletions lib/src/options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class Options {
)
final int port;

@CliOption(abbr: 'q', negatable: false, help: 'Disable logging.')
final bool quiet;

@CliOption(
valueHelp: 'sslcert',
help: 'The SSL certificate to use. Also requires sslkey',
Expand Down Expand Up @@ -78,6 +81,7 @@ class Options {
this.listFiles = false,
this.path,
required this.port,
this.quiet = false,
this.sslcert,
this.sslkey,
this.sslkeypassword,
Expand Down
2 changes: 2 additions & 0 deletions lib/src/options.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/src/version.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: dhttpd
version: 4.2.1-wip
version: 4.3.0

description: A static HTTP file server for easy local hosting of a directory.
repository: https://github.com/kevmoo/dhttpd
Expand Down
22 changes: 22 additions & 0 deletions test/command_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ void main() {
test('serves on specified port', _outputCheck);
test('handles custom headers', _headersCheck);
test('rejects invalid headers', _invalidHeadersCheck);
test('does not log requests when quiet', _quietCheck);
}

Future<void> _versionCheck() async {
Expand Down Expand Up @@ -50,6 +51,7 @@ $ dhttpd --help
--path=<path> The path to serve. If not set, the current directory is used.
-p, --port=<port> The port to listen on. Provide `0` to use a random port.
(defaults to "8080")
-q, --quiet Disable logging.
--sslcert=<sslcert> The SSL certificate to use. Also requires sslkey
--sslkey=<sslkey> The key of the SSL certificate to use. Also requires sslcert
--sslkeypassword=<sslkeypassword> The password for the key of the SSL certificate to use.
Expand Down Expand Up @@ -121,6 +123,26 @@ Future<void> _outputCheck() async {
await process.kill();
}

Future<void> _quietCheck() async {
await d.file('index.html', 'Hello World').create();

final process = await _runApp([
'--port=8002',
'--path',
d.sandbox,
'--quiet',
]);
final line = await process.stdout.next;
expect(line, 'Serving ${d.sandbox} at http://localhost:8002');

final response = await http.get(Uri.parse('http://localhost:8002'));
expect(response.statusCode, 200);
expect(response.body, 'Hello World');

await process.kill();
expect(await process.stdout.rest.toList(), isEmpty);
}

Future<TestProcess> _runApp(List<String> args, {String? workingDirectory}) =>
TestProcess.start(Platform.resolvedExecutable, [
'bin/dhttpd.dart',
Expand Down
Loading