diff --git a/CHANGELOG.md b/CHANGELOG.md index d41332b..fac00ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ -## 4.2.1-wip +## 4.3.0 + +- Added `--quiet` flag to disable request logging. ## 4.2.0 diff --git a/README.md b/README.md index 47e0692..06203e9 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ $ dhttpd --help --path= The path to serve. If not set, the current directory is used. -p, --port= The port to listen on. Provide `0` to use a random port. (defaults to "8080") +-q, --quiet Disable logging. --sslcert= The SSL certificate to use. Also requires sslkey --sslkey= The key of the SSL certificate to use. Also requires sslcert --sslkeypassword= The password for the key of the SSL certificate to use. diff --git a/bin/dhttpd.dart b/bin/dhttpd.dart index 23d2ead..b4d7f4e 100644 --- a/bin/dhttpd.dart +++ b/bin/dhttpd.dart @@ -37,6 +37,7 @@ Future main(List args) async { sslKey: options.sslkey, sslPassword: options.sslkeypassword, listFiles: options.listFiles, + quiet: options.quiet, ); print('Serving ${httpd.path} at ${httpd.urlBase}'); diff --git a/lib/dhttpd.dart b/lib/dhttpd.dart index 4447cb7..51368cc 100644 --- a/lib/dhttpd.dart +++ b/lib/dhttpd.dart @@ -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 start({ String? path, int port = defaultPort, @@ -42,6 +63,7 @@ final class Dhttpd { String? sslKey, String? sslPassword, bool listFiles = false, + bool quiet = false, }) async { path ??= Directory.current.path; @@ -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( @@ -64,7 +91,7 @@ final class Dhttpd { ); final server = await io.serve( - pipeline, + handler, address, port, securityContext: securityContext, diff --git a/lib/src/options.dart b/lib/src/options.dart index 61bf126..1e387cc 100644 --- a/lib/src/options.dart +++ b/lib/src/options.dart @@ -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', @@ -78,6 +81,7 @@ class Options { this.listFiles = false, this.path, required this.port, + this.quiet = false, this.sslcert, this.sslkey, this.sslkeypassword, diff --git a/lib/src/options.g.dart b/lib/src/options.g.dart index 9da5d72..4fbf85a 100644 --- a/lib/src/options.g.dart +++ b/lib/src/options.g.dart @@ -24,6 +24,7 @@ Options _$parseOptionsResult(ArgResults result) => Options( port: int.tryParse(result['port'] as String) ?? _$badNumberFormat(result['port'] as String, 'int', 'port'), + quiet: result['quiet'] as bool, sslcert: result['sslcert'] as String?, sslkey: result['sslkey'] as String?, sslkeypassword: result['sslkeypassword'] as String?, @@ -62,6 +63,7 @@ ArgParser _$populateOptionsParser(ArgParser parser) => parser valueHelp: 'port', defaultsTo: '8080', ) + ..addFlag('quiet', abbr: 'q', help: 'Disable logging.', negatable: false) ..addOption( 'sslcert', help: 'The SSL certificate to use. Also requires sslkey', diff --git a/lib/src/version.dart b/lib/src/version.dart index a712a85..7d799ad 100644 --- a/lib/src/version.dart +++ b/lib/src/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '4.2.1-wip'; +const packageVersion = '4.3.0'; diff --git a/pubspec.yaml b/pubspec.yaml index 4af71b3..3864213 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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 diff --git a/test/command_test.dart b/test/command_test.dart index b6d25d6..4731bb7 100644 --- a/test/command_test.dart +++ b/test/command_test.dart @@ -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 _versionCheck() async { @@ -50,6 +51,7 @@ $ dhttpd --help --path= The path to serve. If not set, the current directory is used. -p, --port= The port to listen on. Provide `0` to use a random port. (defaults to "8080") +-q, --quiet Disable logging. --sslcert= The SSL certificate to use. Also requires sslkey --sslkey= The key of the SSL certificate to use. Also requires sslcert --sslkeypassword= The password for the key of the SSL certificate to use. @@ -121,6 +123,26 @@ Future _outputCheck() async { await process.kill(); } +Future _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 _runApp(List args, {String? workingDirectory}) => TestProcess.start(Platform.resolvedExecutable, [ 'bin/dhttpd.dart',