Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 8 additions & 0 deletions lib/src/options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ 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 +85,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
17 changes: 17 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,21 @@ 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