diff --git a/FlyingFox/Sources/Handlers/FileHTTPHandler.swift b/FlyingFox/Sources/Handlers/FileHTTPHandler.swift index 34831fa5..fd78922f 100644 --- a/FlyingFox/Sources/Handlers/FileHTTPHandler.swift +++ b/FlyingFox/Sources/Handlers/FileHTTPHandler.swift @@ -31,6 +31,9 @@ import FlyingSocks import Foundation +#if canImport(UniformTypeIdentifiers) +import UniformTypeIdentifiers +#endif public struct FileHTTPHandler: HTTPHandler { @@ -48,8 +51,26 @@ public struct FileHTTPHandler: HTTPHandler { } static func makeContentType(for filename: String) -> String { - // TODO: UTTypeCreatePreferredIdentifierForTag / UTTypeCopyPreferredTagWithClass let pathExtension = (filename.lowercased() as NSString).pathExtension +#if canImport(UniformTypeIdentifiers) + if #available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *) { + switch pathExtension { + case "wasm": + return "application/wasm" + case "properties": + return "text/plain" + default: + return UTType(filenameExtension: pathExtension)?.preferredMIMEType ?? legacyMakeContentType(for: pathExtension) + } + } else { + return legacyMakeContentType(for: pathExtension) + } +#else + return legacyMakeContentType(for: pathExtension) +#endif + } + + private static func legacyMakeContentType(for pathExtension: String) -> String { switch pathExtension { case "json": return "application/json" @@ -58,13 +79,15 @@ public struct FileHTTPHandler: HTTPHandler { case "css": return "text/css" case "js", "javascript": - return "application/javascript" + return "text/javascript" case "png": return "image/png" case "jpeg", "jpg": return "image/jpeg" - case "m4v", "mp4": + case "mp4": return "video/mp4" + case "m4v": + return "video/x-m4v" case "pdf": return "application/pdf" case "svg": @@ -72,13 +95,17 @@ public struct FileHTTPHandler: HTTPHandler { case "txt": return "text/plain" case "ico": - return "image/x-icon" + return "image/vnd.microsoft.icon" case "wasm": return "application/wasm" case "webp": return "image/webp" case "jp2": return "image/jp2" + case "properties": + return "text/plain" + case "xml": + return "application/xml" default: return "application/octet-stream" } diff --git a/FlyingFox/Tests/Handlers/HTTPHandlerTests.swift b/FlyingFox/Tests/Handlers/HTTPHandlerTests.swift index 1c509977..5e761efb 100644 --- a/FlyingFox/Tests/Handlers/HTTPHandlerTests.swift +++ b/FlyingFox/Tests/Handlers/HTTPHandlerTests.swift @@ -135,10 +135,10 @@ struct HTTPHandlerTests { FileHTTPHandler.makeContentType(for: "fish.css") == "text/css" ) #expect( - FileHTTPHandler.makeContentType(for: "fish.js") == "application/javascript" + FileHTTPHandler.makeContentType(for: "fish.js") == "text/javascript" ) #expect( - FileHTTPHandler.makeContentType(for: "fish.javascript") == "application/javascript" + FileHTTPHandler.makeContentType(for: "fish.javascript") == "text/javascript" ) #expect( FileHTTPHandler.makeContentType(for: "fish.png") == "image/png" @@ -162,10 +162,10 @@ struct HTTPHandlerTests { FileHTTPHandler.makeContentType(for: "fish.mp4") == "video/mp4" ) #expect( - FileHTTPHandler.makeContentType(for: "fish.m4v") == "video/mp4" + FileHTTPHandler.makeContentType(for: "fish.m4v") == "video/x-m4v" ) #expect( - FileHTTPHandler.makeContentType(for: "fish.ico") == "image/x-icon" + FileHTTPHandler.makeContentType(for: "fish.ico") == "image/vnd.microsoft.icon" ) #expect( FileHTTPHandler.makeContentType(for: "fish.wasm") == "application/wasm" @@ -176,6 +176,12 @@ struct HTTPHandlerTests { #expect( FileHTTPHandler.makeContentType(for: "fish.jp2") == "image/jp2" ) + #expect( + FileHTTPHandler.makeContentType(for: "fish.properties") == "text/plain" + ) + #expect( + FileHTTPHandler.makeContentType(for: "fish.xml") == "application/xml" + ) #expect( FileHTTPHandler.makeContentType(for: "fish.somefile") == "application/octet-stream" ) diff --git a/FlyingFox/XCTests/Handlers/HTTPHandlerTests.swift b/FlyingFox/XCTests/Handlers/HTTPHandlerTests.swift index 9ded634e..6ed36a6c 100644 --- a/FlyingFox/XCTests/Handlers/HTTPHandlerTests.swift +++ b/FlyingFox/XCTests/Handlers/HTTPHandlerTests.swift @@ -126,11 +126,11 @@ final class HTTPHandlerTests: XCTestCase { ) XCTAssertEqual( FileHTTPHandler.makeContentType(for: "fish.js"), - "application/javascript" + "text/javascript" ) XCTAssertEqual( FileHTTPHandler.makeContentType(for: "fish.javascript"), - "application/javascript" + "text/javascript" ) XCTAssertEqual( FileHTTPHandler.makeContentType(for: "fish.png"), @@ -154,7 +154,7 @@ final class HTTPHandlerTests: XCTestCase { ) XCTAssertEqual( FileHTTPHandler.makeContentType(for: "fish.ico"), - "image/x-icon" + "image/vnd.microsoft.icon" ) XCTAssertEqual( FileHTTPHandler.makeContentType(for: "fish.wasm"), @@ -168,6 +168,18 @@ final class HTTPHandlerTests: XCTestCase { FileHTTPHandler.makeContentType(for: "fish.jp2"), "image/jp2" ) + XCTAssertEqual( + FileHTTPHandler.makeContentType(for: "fish.m4v"), + "video/x-m4v" + ) + XCTAssertEqual( + FileHTTPHandler.makeContentType(for: "fish.properties"), + "text/plain" + ) + XCTAssertEqual( + FileHTTPHandler.makeContentType(for: "fish.xml"), + "application/xml" + ) XCTAssertEqual( FileHTTPHandler.makeContentType(for: "fish.somefile"), "application/octet-stream"