Fix an issue with range support, prepare for release (#62)

Removed content-length header when sending a 4xx response
Added corresponding test

Also cleaned up the implementation by DRYing up access to regex matches
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 60be005..a885d2a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
-## 1.1.0-dev
+## 1.1.0
 
 * Correctly handle `HEAD` requests.
+* Support HTTP range requests.
 
 ## 1.0.0
 
diff --git a/lib/src/static_handler.dart b/lib/src/static_handler.dart
index 533fe93..c290d95 100644
--- a/lib/src/static_handler.dart
+++ b/lib/src/static_handler.dart
@@ -189,7 +189,6 @@
   }
 
   final headers = {
-    HttpHeaders.contentLengthHeader: stat.size.toString(),
     HttpHeaders.lastModifiedHeader: formatHttpDate(stat.modified),
     HttpHeaders.acceptRangesHeader: 'bytes',
   };
@@ -202,52 +201,59 @@
     // We only support one range, where the standard support several.
     final matches = RegExp(r'^bytes=(\d*)\-(\d*)$').firstMatch(range);
     // If the range header have the right format, handle it.
-    if (matches != null && (matches[1]!.isNotEmpty || matches[2]!.isNotEmpty)) {
-      // Serve sub-range.
-      int start; // First byte position - inclusive.
-      int end; // Last byte position - inclusive.
-      if (matches[1]!.isEmpty) {
-        start = length - int.parse(matches[2]!);
-        if (start < 0) start = 0;
-        end = length - 1;
-      } else {
-        start = int.parse(matches[1]!);
-        end = matches[2]!.isEmpty ? length - 1 : int.parse(matches[2]!);
-      }
-      // If the range is syntactically invalid the Range header
-      // MUST be ignored (RFC 2616 section 14.35.1).
-      if (start <= end) {
-        if (end >= length) {
+    if (matches != null) {
+      final startMatch = matches[1]!;
+      final endMatch = matches[2]!;
+      if (startMatch.isNotEmpty || endMatch.isNotEmpty) {
+        // Serve sub-range.
+        int start; // First byte position - inclusive.
+        int end; // Last byte position - inclusive.
+        if (startMatch.isEmpty) {
+          start = length - int.parse(endMatch);
+          if (start < 0) start = 0;
           end = length - 1;
-        }
-        if (start >= length) {
-          return Response(
-            HttpStatus.requestedRangeNotSatisfiable,
-            headers: headers,
-          );
-        }
-
-        // Override Content-Length with the actual bytes sent.
-        headers[HttpHeaders.contentLengthHeader] = (end - start + 1).toString();
-
-        // Set 'Partial Content' status code.
-        headers[HttpHeaders.contentRangeHeader] = 'bytes $start-$end/$length';
-        // Pipe the 'range' of the file.
-        if (request.method == 'HEAD') {
-          return Response(
-            HttpStatus.partialContent,
-            headers: headers,
-          );
         } else {
-          return Response(
-            HttpStatus.partialContent,
-            body: file.openRead(start, end + 1),
-            headers: headers,
-          );
+          start = int.parse(startMatch);
+          end = endMatch.isEmpty ? length - 1 : int.parse(endMatch);
+        }
+        // If the range is syntactically invalid the Range header
+        // MUST be ignored (RFC 2616 section 14.35.1).
+        if (start <= end) {
+          if (end >= length) {
+            end = length - 1;
+          }
+          if (start >= length) {
+            return Response(
+              HttpStatus.requestedRangeNotSatisfiable,
+              headers: headers,
+            );
+          }
+
+          // Override Content-Length with the actual bytes sent.
+          headers[HttpHeaders.contentLengthHeader] =
+              (end - start + 1).toString();
+
+          // Set 'Partial Content' status code.
+          headers[HttpHeaders.contentRangeHeader] = 'bytes $start-$end/$length';
+          // Pipe the 'range' of the file.
+          if (request.method == 'HEAD') {
+            return Response(
+              HttpStatus.partialContent,
+              headers: headers,
+            );
+          } else {
+            return Response(
+              HttpStatus.partialContent,
+              body: file.openRead(start, end + 1),
+              headers: headers,
+            );
+          }
         }
       }
     }
   }
+  headers[HttpHeaders.contentLengthHeader] = stat.size.toString();
+
   return Response.ok(
     request.method == 'HEAD' ? null : file.openRead(),
     headers: headers,
diff --git a/pubspec.yaml b/pubspec.yaml
index a8fdc56..824b2d6 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: shelf_static
-version: 1.1.0-dev
+version: 1.1.0
 description: Static file server support for the shelf package and ecosystem
 repository: https://github.com/dart-lang/shelf_static
 
diff --git a/test/create_file_handler_test.dart b/test/create_file_handler_test.dart
index 8544bb8..907e3b4 100644
--- a/test/create_file_handler_test.dart
+++ b/test/create_file_handler_test.dart
@@ -81,13 +81,14 @@
       );
       expect(response.statusCode, equals(HttpStatus.partialContent));
       expect(
-        response.headers[HttpHeaders.acceptRangesHeader],
-        'bytes',
+        response.headers,
+        containsPair(HttpHeaders.acceptRangesHeader, 'bytes'),
       );
       expect(
-        response.headers[HttpHeaders.contentRangeHeader],
-        'bytes 0-4/8',
+        response.headers,
+        containsPair(HttpHeaders.contentRangeHeader, 'bytes 0-4/8'),
       );
+      expect(response.headers, containsPair('content-length', '5'));
     });
     test('at the end of has overflow from 0 to 9', () async {
       final handler = createFileHandler(p.join(d.sandbox, 'file.txt'));
@@ -101,13 +102,14 @@
         equals(HttpStatus.partialContent),
       );
       expect(
-        response.headers[HttpHeaders.acceptRangesHeader],
-        'bytes',
+        response.headers,
+        containsPair(HttpHeaders.acceptRangesHeader, 'bytes'),
       );
       expect(
-        response.headers[HttpHeaders.contentRangeHeader],
-        'bytes 0-7/8',
+        response.headers,
+        containsPair(HttpHeaders.contentRangeHeader, 'bytes 0-7/8'),
       );
+      expect(response.headers, containsPair('content-length', '8'));
     });
     test('at the start of has overflow from 8 to 9', () async {
       final handler = createFileHandler(p.join(d.sandbox, 'file.txt'));
@@ -116,13 +118,14 @@
         '/file.txt',
         headers: {'range': 'bytes=8-9'},
       );
+      expect(response.headers, containsPair('content-length', '0'));
       expect(
-        response.headers[HttpHeaders.acceptRangesHeader],
-        'bytes',
+        response.headers,
+        containsPair(HttpHeaders.acceptRangesHeader, 'bytes'),
       );
       expect(
         response.statusCode,
-        equals(HttpStatus.requestedRangeNotSatisfiable),
+        HttpStatus.requestedRangeNotSatisfiable,
       );
     });
   });