enable and fix some lints
diff --git a/analysis_options.yaml b/analysis_options.yaml
index a10d4c5..3d7fdea 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,2 +1,37 @@
 analyzer:
   strong-mode: true
+linter:
+  rules:
+    - avoid_empty_else
+    - avoid_init_to_null
+    - avoid_null_checks_in_equality_operators
+    - await_only_futures
+    - camel_case_types
+    - cancel_subscriptions
+    - constant_identifier_names
+    - control_flow_in_finally
+    - directives_ordering
+    - empty_catches
+    - empty_constructor_bodies
+    - empty_statements
+    - hash_and_equals
+    - implementation_imports
+    - iterable_contains_unrelated_type
+    - library_names
+    - library_prefixes
+    - list_remove_unrelated_type
+    - non_constant_identifier_names
+    - overridden_fields
+    - package_api_docs
+    - package_names
+    - package_prefixed_library_names
+    - prefer_final_fields
+    - prefer_is_not_empty
+    - slash_for_doc_comments
+    - super_goes_last
+    - test_types_in_equals
+    - throw_in_finally
+    - type_init_formals
+    - unnecessary_brace_in_string_interps
+    - unrelated_type_equality_checks
+    - valid_regexps
diff --git a/lib/shelf.dart b/lib/shelf.dart
index 1a5f072..ead9ec5 100644
--- a/lib/shelf.dart
+++ b/lib/shelf.dart
@@ -4,10 +4,10 @@
 
 export 'src/cascade.dart';
 export 'src/handler.dart';
-export 'src/middleware/add_chunked_encoding.dart';
-export 'src/middleware/logger.dart';
 export 'src/hijack_exception.dart';
 export 'src/middleware.dart';
+export 'src/middleware/add_chunked_encoding.dart';
+export 'src/middleware/logger.dart';
 export 'src/pipeline.dart';
 export 'src/request.dart';
 export 'src/response.dart';
diff --git a/lib/shelf_io.dart b/lib/shelf_io.dart
index 9a03532..31ca95b 100644
--- a/lib/shelf_io.dart
+++ b/lib/shelf_io.dart
@@ -106,7 +106,7 @@
     ..writeln("Got a response for hijacked request "
         "${shelfRequest.method} ${shelfRequest.requestedUri}:")
     ..writeln(response.statusCode);
-  response.headers.forEach((key, value) => message.writeln("${key}: ${value}"));
+  response.headers.forEach((key, value) => message.writeln("$key: $value"));
   throw new Exception(message.toString().trim());
 }
 
diff --git a/lib/src/cascade.dart b/lib/src/cascade.dart
index 37e531b..dee3665 100644
--- a/lib/src/cascade.dart
+++ b/lib/src/cascade.dart
@@ -37,7 +37,7 @@
   ///
   /// If [statusCodes] is passed, responses with those status codes are
   /// considered unacceptable. If [shouldCascade] is passed, responses for which
-  /// it returns `true` are considered unacceptable. [statusCode] and
+  /// it returns `true` are considered unacceptable. [statusCodes] and
   /// [shouldCascade] may not both be passed.
   Cascade({Iterable<int> statusCodes, bool shouldCascade(Response response)})
       : _shouldCascade = _computeShouldCascade(statusCodes, shouldCascade),
diff --git a/lib/src/hijack_exception.dart b/lib/src/hijack_exception.dart
index eecf9d8..d7e4cd1 100644
--- a/lib/src/hijack_exception.dart
+++ b/lib/src/hijack_exception.dart
@@ -9,7 +9,7 @@
 /// make sure to pass on HijackExceptions.
 ///
 /// See also [Request.hijack].
-class HijackException {
+class HijackException implements Exception {
   const HijackException();
 
   String toString() =>
diff --git a/lib/src/middleware.dart b/lib/src/middleware.dart
index a270b4e..5a2db6b 100644
--- a/lib/src/middleware.dart
+++ b/lib/src/middleware.dart
@@ -4,10 +4,10 @@
 
 import 'dart:async';
 
-import 'request.dart';
-import 'response.dart';
 import 'handler.dart';
 import 'hijack_exception.dart';
+import 'request.dart';
+import 'response.dart';
 
 /// A function which creates a new [Handler] by wrapping a [Handler].
 ///
@@ -54,7 +54,7 @@
 
   if (responseHandler == null) responseHandler = (response) => response;
 
-  var onError = null;
+  var onError;
   if (errorHandler != null) {
     onError = (error, stackTrace) {
       if (error is HijackException) throw error;
diff --git a/lib/src/middleware/logger.dart b/lib/src/middleware/logger.dart
index b127315..810a927 100644
--- a/lib/src/middleware/logger.dart
+++ b/lib/src/middleware/logger.dart
@@ -53,7 +53,7 @@
 
 String _getMessage(DateTime requestTime, int statusCode, Uri requestedUri,
     String method, Duration elapsedTime) {
-  return '${requestTime}\t$elapsedTime\t$method\t[${statusCode}]\t'
+  return '$requestTime\t$elapsedTime\t$method\t[$statusCode]\t'
       '${requestedUri.path}${_formatQuery(requestedUri.query)}';
 }
 
@@ -66,7 +66,7 @@
         .terse;
   }
 
-  var msg = '${requestTime}\t$elapsedTime\t$method\t${requestedUri.path}'
+  var msg = '$requestTime\t$elapsedTime\t$method\t${requestedUri.path}'
       '${_formatQuery(requestedUri.query)}\n$error';
   if (chain == null) return msg;
 
diff --git a/lib/src/request.dart b/lib/src/request.dart
index b297879..f208cf6 100644
--- a/lib/src/request.dart
+++ b/lib/src/request.dart
@@ -51,7 +51,7 @@
   ///
   /// [handlerPath] is always a root-relative URL path; that is, it always
   /// starts with `/`. It will also end with `/` whenever [url]'s path is
-  /// non-empty, or if [requestUri]'s path ends with `/`.
+  /// non-empty, or if [requestedUri]'s path ends with `/`.
   ///
   /// [handlerPath] and [url]'s path combine to create [requestedUri]'s path.
   final String handlerPath;
@@ -295,7 +295,7 @@
 
 /// Computes `url` from the provided [Request] constructor arguments.
 ///
-/// If [url] is `null`, the value is inferred from [requestedUrl] and
+/// If [url] is `null`, the value is inferred from [requestedUri] and
 /// [handlerPath] if available. Otherwise [url] is returned.
 Uri _computeUrl(Uri requestedUri, String handlerPath, Uri url) {
   if (handlerPath != null &&
@@ -345,7 +345,7 @@
 
 /// Computes `handlerPath` from the provided [Request] constructor arguments.
 ///
-/// If [handlerPath] is `null`, the value is inferred from [requestedUrl] and
+/// If [handlerPath] is `null`, the value is inferred from [requestedUri] and
 /// [url] if available. Otherwise [handlerPath] is returned.
 String _computeHandlerPath(Uri requestedUri, String handlerPath, Uri url) {
   if (handlerPath != null &&
diff --git a/lib/src/server_handler.dart b/lib/src/server_handler.dart
index eb5f6fd..420ec17 100644
--- a/lib/src/server_handler.dart
+++ b/lib/src/server_handler.dart
@@ -6,8 +6,8 @@
 
 import 'package:async/async.dart';
 
-import 'request.dart';
 import 'handler.dart';
+import 'request.dart';
 import 'server.dart';
 
 /// A connected pair of a [Server] and a [Handler].
diff --git a/test/cascade_test.dart b/test/cascade_test.dart
index e935472..714f632 100644
--- a/test/cascade_test.dart
+++ b/test/cascade_test.dart
@@ -45,7 +45,7 @@
         "doesn't", () {
       return new Future.sync(() {
         return handler(
-            new Request('GET', LOCALHOST_URI, headers: {'one': 'false'}));
+            new Request('GET', localhostUri, headers: {'one': 'false'}));
       }).then((response) {
         expect(response.statusCode, equals(200));
         expect(response.readAsString(), completion(equals('handler 2')));
@@ -56,7 +56,7 @@
         "the third response should be returned if it matches and the first "
         "two don't", () {
       return new Future.sync(() {
-        return handler(new Request('GET', LOCALHOST_URI,
+        return handler(new Request('GET', localhostUri,
             headers: {'one': 'false', 'two': 'false'}));
       }).then((response) {
         expect(response.statusCode, equals(200));
@@ -66,7 +66,7 @@
 
     test("the third response should be returned if no response matches", () {
       return new Future.sync(() {
-        return handler(new Request('GET', LOCALHOST_URI,
+        return handler(new Request('GET', localhostUri,
             headers: {'one': 'false', 'two': 'false', 'three': 'false'}));
       }).then((response) {
         expect(response.statusCode, equals(404));
diff --git a/test/hijack_test.dart b/test/hijack_test.dart
index 4b24ea8..47ae4ba 100644
--- a/test/hijack_test.dart
+++ b/test/hijack_test.dart
@@ -11,14 +11,14 @@
 
 void main() {
   test('hijacking a non-hijackable request throws a StateError', () {
-    expect(() => new Request('GET', LOCALHOST_URI).hijack((_) => null),
+    expect(() => new Request('GET', localhostUri).hijack((_) => null),
         throwsStateError);
   });
 
   test(
       'hijacking a hijackable request throws a HijackException and calls '
       'onHijack', () {
-    var request = new Request('GET', LOCALHOST_URI,
+    var request = new Request('GET', localhostUri,
         onHijack: expectAsync1((void callback(a, b)) {
       var streamController = new StreamController<List<int>>();
       streamController.add([1, 2, 3]);
@@ -41,7 +41,7 @@
 
   test('hijacking a hijackable request twice throws a StateError', () {
     // Assert that the [onHijack] callback is only called once.
-    var request = new Request('GET', LOCALHOST_URI,
+    var request = new Request('GET', localhostUri,
         onHijack: expectAsync1((_) => null, count: 1));
 
     expect(() => request.hijack((_) => null),
@@ -52,7 +52,7 @@
 
   group('calling change', () {
     test('hijacking a non-hijackable request throws a StateError', () {
-      var request = new Request('GET', LOCALHOST_URI);
+      var request = new Request('GET', localhostUri);
       var newRequest = request.change();
       expect(() => newRequest.hijack((_) => null), throwsStateError);
     });
@@ -60,7 +60,7 @@
     test(
         'hijacking a hijackable request throws a HijackException and calls '
         'onHijack', () {
-      var request = new Request('GET', LOCALHOST_URI,
+      var request = new Request('GET', localhostUri,
           onHijack: expectAsync1((callback(a, b)) {
         var streamController = new StreamController<List<int>>();
         streamController.add([1, 2, 3]);
@@ -87,7 +87,7 @@
         'hijacking the original request after calling change throws a '
         'StateError', () {
       // Assert that the [onHijack] callback is only called once.
-      var request = new Request('GET', LOCALHOST_URI,
+      var request = new Request('GET', localhostUri,
           onHijack: expectAsync1((_) => null, count: 1));
 
       var newRequest = request.change();
diff --git a/test/message_change_test.dart b/test/message_change_test.dart
index fec0d9b..e3c5b76 100644
--- a/test/message_change_test.dart
+++ b/test/message_change_test.dart
@@ -15,7 +15,7 @@
 void main() {
   group('Request', () {
     _testChange(({body, headers, context}) {
-      return new Request('GET', LOCALHOST_URI,
+      return new Request('GET', localhostUri,
           body: body, headers: headers, context: context);
     });
   });
diff --git a/test/message_test.dart b/test/message_test.dart
index ac120ce..86a7a79 100644
--- a/test/message_test.dart
+++ b/test/message_test.dart
@@ -85,10 +85,10 @@
       var request = _createMessage(body: controller.stream);
       expect(request.readAsString(), completion(equals("hello, world")));
 
-      controller.add(HELLO_BYTES);
+      controller.add(helloBytes);
       return new Future(() {
         controller
-          ..add(WORLD_BYTES)
+          ..add(worldBytes)
           ..close();
       });
     });
@@ -130,19 +130,19 @@
       var controller = new StreamController();
       var request = _createMessage(body: controller.stream);
       expect(request.read().toList(),
-          completion(equals([HELLO_BYTES, WORLD_BYTES])));
+          completion(equals([helloBytes, worldBytes])));
 
-      controller.add(HELLO_BYTES);
+      controller.add(helloBytes);
       return new Future(() {
         controller
-          ..add(WORLD_BYTES)
+          ..add(worldBytes)
           ..close();
       });
     });
 
     test("supports a List<int> body", () {
-      var request = _createMessage(body: HELLO_BYTES);
-      expect(request.read().toList(), completion(equals([HELLO_BYTES])));
+      var request = _createMessage(body: helloBytes);
+      expect(request.read().toList(), completion(equals([helloBytes])));
     });
 
     test("throws when calling read()/readAsString() multiple times", () {
diff --git a/test/request_test.dart b/test/request_test.dart
index 2d371fc..bcd3701 100644
--- a/test/request_test.dart
+++ b/test/request_test.dart
@@ -11,19 +11,19 @@
 import 'test_util.dart';
 
 Request _request({Map<String, String> headers, body, Encoding encoding}) {
-  return new Request("GET", LOCALHOST_URI,
+  return new Request("GET", localhostUri,
       headers: headers, body: body, encoding: encoding);
 }
 
 void main() {
   group('constructor', () {
     test('protocolVersion defaults to "1.1"', () {
-      var request = new Request('GET', LOCALHOST_URI);
+      var request = new Request('GET', localhostUri);
       expect(request.protocolVersion, '1.1');
     });
 
     test('provide non-default protocolVersion', () {
-      var request = new Request('GET', LOCALHOST_URI, protocolVersion: '1.0');
+      var request = new Request('GET', localhostUri, protocolVersion: '1.0');
       expect(request.protocolVersion, '1.0');
     });
 
@@ -229,10 +229,10 @@
       expect(copy.context, same(request.context));
       expect(copy.readAsString(), completion('hello, world'));
 
-      controller.add(HELLO_BYTES);
+      controller.add(helloBytes);
       return new Future(() {
         controller
-          ..add(WORLD_BYTES)
+          ..add(worldBytes)
           ..close();
       });
     });
diff --git a/test/response_test.dart b/test/response_test.dart
index 17e73e3..f236f0e 100644
--- a/test/response_test.dart
+++ b/test/response_test.dart
@@ -18,7 +18,7 @@
     });
 
     test("read", () {
-      var helloWorldBytes = new List.from(HELLO_BYTES)..addAll(WORLD_BYTES);
+      var helloWorldBytes = new List.from(helloBytes)..addAll(worldBytes);
 
       var response = new Response.ok("hello, world");
       expect(response.read().toList(), completion(equals([helloWorldBytes])));
@@ -103,10 +103,10 @@
       expect(copy.encoding, request.encoding);
       expect(copy.context, same(request.context));
 
-      controller.add(HELLO_BYTES);
+      controller.add(helloBytes);
       return new Future(() {
         controller
-          ..add(WORLD_BYTES)
+          ..add(worldBytes)
           ..close();
       });
     });
diff --git a/test/server_handler_test.dart b/test/server_handler_test.dart
index e9fbdc8..a98dd75 100644
--- a/test/server_handler_test.dart
+++ b/test/server_handler_test.dart
@@ -11,13 +11,13 @@
 
 void main() {
   test("passes the URL to the server", () {
-    var serverHandler = new ServerHandler(LOCALHOST_URI);
-    expect(serverHandler.server.url, equals(LOCALHOST_URI));
+    var serverHandler = new ServerHandler(localhostUri);
+    expect(serverHandler.server.url, equals(localhostUri));
   });
 
   test("pipes a request from ServerHandler.handler to a mounted handler",
       () async {
-    var serverHandler = new ServerHandler(LOCALHOST_URI);
+    var serverHandler = new ServerHandler(localhostUri);
     serverHandler.server.mount(asyncHandler);
 
     var response = await makeSimpleRequest(serverHandler.handler);
@@ -27,7 +27,7 @@
 
   test("waits until the server's handler is mounted to service a request",
       () async {
-    var serverHandler = new ServerHandler(LOCALHOST_URI);
+    var serverHandler = new ServerHandler(localhostUri);
     var future = makeSimpleRequest(serverHandler.handler);
     await new Future.delayed(Duration.ZERO);
 
@@ -38,7 +38,7 @@
   });
 
   test("stops servicing requests after Server.close is called", () {
-    var serverHandler = new ServerHandler(LOCALHOST_URI);
+    var serverHandler = new ServerHandler(localhostUri);
     serverHandler.server.mount(expectAsync1((_) {}, count: 0));
     serverHandler.server.close();
 
@@ -48,7 +48,7 @@
   test("calls onClose when Server.close is called", () async {
     var onCloseCalled = false;
     var completer = new Completer();
-    var serverHandler = new ServerHandler(LOCALHOST_URI, onClose: () {
+    var serverHandler = new ServerHandler(localhostUri, onClose: () {
       onCloseCalled = true;
       return completer.future;
     });
@@ -68,7 +68,7 @@
   });
 
   test("doesn't allow Server.mount to be called multiple times", () {
-    var serverHandler = new ServerHandler(LOCALHOST_URI);
+    var serverHandler = new ServerHandler(localhostUri);
     serverHandler.server.mount((_) {});
     expect(() => serverHandler.server.mount((_) {}), throwsStateError);
     expect(() => serverHandler.server.mount((_) {}), throwsStateError);
diff --git a/test/shelf_io_test.dart b/test/shelf_io_test.dart
index 56dd27f..44c2f87 100644
--- a/test/shelf_io_test.dart
+++ b/test/shelf_io_test.dart
@@ -270,7 +270,7 @@
       try {
         return await http.get('http://localhost:${server.port}');
       } finally {
-        server.close();
+        await server.close();
       }
     });
 
diff --git a/test/test_util.dart b/test/test_util.dart
index e3863ed..c38b3a2 100644
--- a/test/test_util.dart
+++ b/test/test_util.dart
@@ -7,10 +7,10 @@
 import 'package:shelf/shelf.dart';
 
 // "hello,"
-const HELLO_BYTES = const [104, 101, 108, 108, 111, 44];
+const helloBytes = const [104, 101, 108, 108, 111, 44];
 
 // " world"
-const WORLD_BYTES = const [32, 119, 111, 114, 108, 100];
+const worldBytes = const [32, 119, 111, 114, 108, 100];
 
 /// A simple, synchronous handler for [Request].
 ///
@@ -31,6 +31,6 @@
 Future<Response> makeSimpleRequest(Handler handler) =>
     new Future.sync(() => handler(_request));
 
-final _request = new Request('GET', LOCALHOST_URI);
+final _request = new Request('GET', localhostUri);
 
-final LOCALHOST_URI = Uri.parse('http://localhost/');
+final localhostUri = Uri.parse('http://localhost/');