Merge https://github.com/dart-lang/shelf_static/pull/19
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 53c712c..a86aabd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.5
+
+* Add an optional `contentTypeResolver` argument to `createStaticHandler`.
+
 ## 0.2.4
 
 * Add support for "sniffing" the content of the file for the content-type via an optional
diff --git a/lib/src/static_handler.dart b/lib/src/static_handler.dart
index a2a1b5c..a2e3e71 100644
--- a/lib/src/static_handler.dart
+++ b/lib/src/static_handler.dart
@@ -32,11 +32,15 @@
 ///
 /// If [useHeaderBytesForContentType] is `true`, the contents of the
 /// file will be used along with the file path to determine the content type.
+///
+/// Specify a custom [contentTypeResolver] to customize automatic content type
+/// detection.
 Handler createStaticHandler(String fileSystemPath,
     {bool serveFilesOutsidePath: false,
     String defaultDocument,
     bool listDirectories: false,
-    bool useHeaderBytesForContentType: false}) {
+    bool useHeaderBytesForContentType: false,
+    mime.MimeTypeResolver contentTypeResolver}) {
   var rootDir = new Directory(fileSystemPath);
   if (!rootDir.existsSync()) {
     throw new ArgumentError('A directory corresponding to fileSystemPath '
@@ -51,6 +55,8 @@
     }
   }
 
+  contentTypeResolver ??= new mime.MimeTypeResolver();
+
   return (Request request) async {
     var segs = [fileSystemPath]..addAll(request.url.pathSegments);
 
@@ -110,15 +116,15 @@
     String contentType;
     if (useHeaderBytesForContentType) {
       var length =
-          math.min(mime.defaultMagicNumbersMaxLength, file.lengthSync());
+          math.min(contentTypeResolver.magicNumbersMaxLength, file.lengthSync());
 
       var byteSink = new ByteAccumulatorSink();
 
       await file.openRead(0, length).listen(byteSink.add).asFuture();
 
-      contentType = mime.lookupMimeType(file.path, headerBytes: byteSink.bytes);
+      contentType = contentTypeResolver.lookup(file.path, headerBytes: byteSink.bytes);
     } else {
-      contentType = mime.lookupMimeType(file.path);
+      contentType = contentTypeResolver.lookup(file.path);
     }
 
     if (contentType != null) {
diff --git a/pubspec.yaml b/pubspec.yaml
index f1cc8d4..2618b35 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: shelf_static
-version: 0.2.4
+version: 0.2.5
 author: Dart Team <misc@dartlang.org>
 description: Static file server support for Shelf
 homepage: https://github.com/dart-lang/shelf_static
diff --git a/test/basic_file_test.dart b/test/basic_file_test.dart
index b9a1982..97b5929 100644
--- a/test/basic_file_test.dart
+++ b/test/basic_file_test.dart
@@ -5,6 +5,7 @@
 import 'dart:io';
 import 'dart:convert';
 import 'package:http_parser/http_parser.dart';
+import 'package:mime/mime.dart' as mime;
 import 'package:path/path.dart' as p;
 import 'package:scheduled_test/descriptor.dart' as d;
 import 'package:scheduled_test/scheduled_test.dart';
@@ -34,10 +35,13 @@
         r"OJE7pB/VXmF3CdseucmjxaAruR41Pl9p/Gbyoq5B9FeL2OR7zJ+3aC/X8QdQCyIArPs"
         r"HkQAAAABJRU5ErkJggg==";
 
+    var webpBytesContent = r"UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAQAcJaQAA3AA/v3AgAA=";
+
     d.dir('files', [
       d.file('test.txt', 'test txt content'),
       d.file('with space.txt', 'with space content'),
-      d.binaryFile('header_bytes_test_image', BASE64.decode(pngBytesContent))
+      d.binaryFile('header_bytes_test_image', BASE64.decode(pngBytesContent)),
+      d.binaryFile('header_bytes_test_webp', BASE64.decode(webpBytesContent))
     ]).create();
 
     currentSchedule.onComplete.schedule(() {
@@ -207,9 +211,9 @@
       });
     });
 
-    test('magic_bytes_test_image should be image/png', () {
+    test('header_bytes_test_image should be image/png', () {
       schedule(() {
-        var handler = createStaticHandler(d.defaultRoot,
+        final dynamic handler = createStaticHandler(d.defaultRoot,
             useHeaderBytesForContentType: true);
 
         return makeRequest(handler, '/files/header_bytes_test_image')
@@ -218,5 +222,21 @@
         });
       });
     });
+
+    test('header_bytes_test_webp should be image/webp', () {
+      schedule(() {
+        final mime.MimeTypeResolver resolver = new mime.MimeTypeResolver();
+        resolver.addMagicNumber(<int>[0x52,0x49,0x46,0x46,0x00,0x00,0x00,0x00,0x57,0x45,0x42,0x50], "image/webp",
+                                mask: <int>[0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF]);
+        final dynamic handler = createStaticHandler(d.defaultRoot,
+            useHeaderBytesForContentType: true, contentTypeResolver: resolver);
+
+        return makeRequest(handler, '/files/header_bytes_test_webp')
+            .then((response) {
+          expect(response.mimeType, "image/webp");
+        });
+      });
+    });
+
   });
 }