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
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
- Support multiple `--headers` flags and more robust header value parsing.
For example: `--headers="header1=value1;header2=value2"` or
`--headers="header1=value1" --headers="header2=value2"`
- Add `--list-files` flag to show a directory listing when no `index.html` is
- Added `--list-files` flag to show a directory listing when no `index.html` is
present.
- Add clickable link to serve output.
- Added `--version` flag.
- Added clickable link to serve output.
- Require `sdk: ^3.10.0`.

## 4.1.0
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,18 @@ See the Dart documentation of [SecurityContext.usePrivateKey](https://api.dart.d

```console
$ dhttpd --help
-p, --port=<port> The port to listen on. Provide `0` to use a random port.
(defaults to "8080")
--path=<path> The path to serve. If not set, the current directory is used.
--headers=<headers> HTTP headers to apply to each response. Can be used multiple times. Format: header=value;header2=value
--headers=<headers> HTTP headers to apply to each response. Can be used multiple times. Format: header=value;header2=value
--host=<host> The hostname to listen on.
(defaults to "localhost")
-l, --list-files List the files in the directory if no index.html is present.
--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")
--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.
-h, --help Displays the help.
-l, --list-files List the files in the directory if no index.html is present.
--version Prints the version of dhttpd.
```

[path]: https://dart.dev/tools/pub/cmd/pub-global#running-a-script-from-your-path
6 changes: 6 additions & 0 deletions bin/dhttpd.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:io';
import 'package:dhttpd/dhttpd.dart';
import 'package:dhttpd/src/options.dart';
import 'package:dhttpd/src/utils.dart';
import 'package:dhttpd/src/version.dart';

Future<void> main(List<String> args) async {
final Options options;
Expand All @@ -22,6 +23,11 @@ Future<void> main(List<String> args) async {
return;
}

if (options.version) {
print(packageVersion);
return;
}

final httpd = await Dhttpd.start(
path: options.path,
port: options.port,
Expand Down
54 changes: 29 additions & 25 deletions lib/src/options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,6 @@ const String defaultHost = 'localhost';

@CliOptions()
class Options {
@CliOption(
abbr: 'p',
valueHelp: 'port',
defaultsTo: defaultPort,
help: 'The port to listen on. Provide `0` to use a random port.',
)
final int port;

@CliOption(
valueHelp: 'path',
help:
'The path to serve.'
' If not set, the current directory is used.',
)
final String? path;

@CliOption(
valueHelp: 'headers',
help:
Expand All @@ -41,6 +25,29 @@ class Options {
)
final String host;

@CliOption(
abbr: 'l',
negatable: false,
help: 'List the files in the directory if no index.html is present.',
)
final bool listFiles;

@CliOption(
valueHelp: 'path',
help:
'The path to serve.'
' If not set, the current directory is used.',
)
final String? path;

@CliOption(
abbr: 'p',
valueHelp: 'port',
defaultsTo: defaultPort,
help: 'The port to listen on. Provide `0` to use a random port.',
)
final int port;

@CliOption(
valueHelp: 'sslcert',
help: 'The SSL certificate to use. Also requires sslkey',
Expand All @@ -62,22 +69,19 @@ class Options {
@CliOption(abbr: 'h', negatable: false, help: 'Displays the help.')
final bool help;

@CliOption(
abbr: 'l',
negatable: false,
help: 'List the files in the directory if no index.html is present.',
)
final bool listFiles;
@CliOption(negatable: false, help: 'Prints the version of dhttpd.')
final bool version;

Options({
required this.port,
this.path,
required this.headers,
required this.host,
this.listFiles = false,
this.path,
required this.port,
this.sslcert,
this.sslkey,
this.sslkeypassword,
required this.help,
this.listFiles = false,
this.version = false,
});
}
46 changes: 24 additions & 22 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: 2 additions & 0 deletions lib/src/version.dart

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

1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dev_dependencies:
build_cli: ^2.1.2
build_runner: ^2.0.0
build_verify: ^3.0.0
build_version: ^2.1.1
dart_flutter_team_lints: ^3.0.0
http: ^1.1.0
path: ^1.8.0
Expand Down
20 changes: 15 additions & 5 deletions test/command_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,27 @@
import 'dart:async';
import 'dart:io';

import 'package:dhttpd/src/version.dart';
import 'package:http/http.dart' as http;
import 'package:test/test.dart';
import 'package:test_descriptor/test_descriptor.dart' as d;
import 'package:test_process/test_process.dart';

void main() {
test('prints version', _versionCheck);
test('prints help', () => _readmeCheck(['--help']));
test('serves on specified port', _outputCheck);
test('handles custom headers', _headersCheck);
test('rejects invalid headers', _invalidHeadersCheck);
}

Future<void> _versionCheck() async {
final process = await _runApp(['--version']);
final output = (await process.stdoutStream().join('\n')).trim();
await process.shouldExit(0);
expect(output, packageVersion);
}

Future<void> _readmeCheck(List<String> args) async {
final process = await _runApp(args);
final output = (await process.stdoutStream().join('\n')).trim();
Expand All @@ -34,17 +43,18 @@ $output

expect(expected, r'''```console
$ dhttpd --help
-p, --port=<port> The port to listen on. Provide `0` to use a random port.
(defaults to "8080")
--path=<path> The path to serve. If not set, the current directory is used.
--headers=<headers> HTTP headers to apply to each response. Can be used multiple times. Format: header=value;header2=value
--headers=<headers> HTTP headers to apply to each response. Can be used multiple times. Format: header=value;header2=value
--host=<host> The hostname to listen on.
(defaults to "localhost")
-l, --list-files List the files in the directory if no index.html is present.
--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")
--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.
-h, --help Displays the help.
-l, --list-files List the files in the directory if no index.html is present.
--version Prints the version of dhttpd.
```''');

expect(readme.readAsStringSync(), contains(expected));
Expand Down
Loading