Skip to content

Commit 40da1ce

Browse files
Merge pull request #296 from Ninerian/stable
Adds support for mimetypes
2 parents 13b31b6 + 4389a97 commit 40da1ce

File tree

4 files changed

+213
-8
lines changed

4 files changed

+213
-8
lines changed

Sources/Files.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ public func shareFilesFromDirectory(_ directoryPath: String, defaults: [String]
3535
}
3636
}
3737
if let file = try? (directoryPath + String.pathSeparator + fileRelativePath.value).openForReading() {
38-
return .raw(200, "OK", [:], { writer in
38+
let mimeType = fileRelativePath.value.mimeType();
39+
40+
return .raw(200, "OK", ["Content-Type": mimeType], { writer in
3941
try? writer.write(file)
4042
file.close()
4143
})

Sources/MimeTypes.swift

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
//
2+
// MimeTypes.swift
3+
// Swifter
4+
//
5+
// Created by Daniel Große on 16.02.18.
6+
//
7+
8+
import Foundation
9+
10+
internal let DEFAULT_MIME_TYPE = "application/octet-stream"
11+
12+
internal let mimeTypes = [
13+
"html": "text/html",
14+
"htm": "text/html",
15+
"shtml": "text/html",
16+
"css": "text/css",
17+
"xml": "text/xml",
18+
"gif": "image/gif",
19+
"jpeg": "image/jpeg",
20+
"jpg": "image/jpeg",
21+
"js": "application/javascript",
22+
"atom": "application/atom+xml",
23+
"rss": "application/rss+xml",
24+
"mml": "text/mathml",
25+
"txt": "text/plain",
26+
"jad": "text/vnd.sun.j2me.app-descriptor",
27+
"wml": "text/vnd.wap.wml",
28+
"htc": "text/x-component",
29+
"png": "image/png",
30+
"tif": "image/tiff",
31+
"tiff": "image/tiff",
32+
"wbmp": "image/vnd.wap.wbmp",
33+
"ico": "image/x-icon",
34+
"jng": "image/x-jng",
35+
"bmp": "image/x-ms-bmp",
36+
"svg": "image/svg+xml",
37+
"svgz": "image/svg+xml",
38+
"webp": "image/webp",
39+
"woff": "application/font-woff",
40+
"jar": "application/java-archive",
41+
"war": "application/java-archive",
42+
"ear": "application/java-archive",
43+
"json": "application/json",
44+
"hqx": "application/mac-binhex40",
45+
"doc": "application/msword",
46+
"pdf": "application/pdf",
47+
"ps": "application/postscript",
48+
"eps": "application/postscript",
49+
"ai": "application/postscript",
50+
"rtf": "application/rtf",
51+
"m3u8": "application/vnd.apple.mpegurl",
52+
"xls": "application/vnd.ms-excel",
53+
"eot": "application/vnd.ms-fontobject",
54+
"ppt": "application/vnd.ms-powerpoint",
55+
"wmlc": "application/vnd.wap.wmlc",
56+
"kml": "application/vnd.google-earth.kml+xml",
57+
"kmz": "application/vnd.google-earth.kmz",
58+
"7z": "application/x-7z-compressed",
59+
"cco": "application/x-cocoa",
60+
"jardiff": "application/x-java-archive-diff",
61+
"jnlp": "application/x-java-jnlp-file",
62+
"run": "application/x-makeself",
63+
"pl": "application/x-perl",
64+
"pm": "application/x-perl",
65+
"prc": "application/x-pilot",
66+
"pdb": "application/x-pilot",
67+
"rar": "application/x-rar-compressed",
68+
"rpm": "application/x-redhat-package-manager",
69+
"sea": "application/x-sea",
70+
"swf": "application/x-shockwave-flash",
71+
"sit": "application/x-stuffit",
72+
"tcl": "application/x-tcl",
73+
"tk": "application/x-tcl",
74+
"der": "application/x-x509-ca-cert",
75+
"pem": "application/x-x509-ca-cert",
76+
"crt": "application/x-x509-ca-cert",
77+
"xpi": "application/x-xpinstall",
78+
"xhtml": "application/xhtml+xml",
79+
"xspf": "application/xspf+xml",
80+
"zip": "application/zip",
81+
"bin": "application/octet-stream",
82+
"exe": "application/octet-stream",
83+
"dll": "application/octet-stream",
84+
"deb": "application/octet-stream",
85+
"dmg": "application/octet-stream",
86+
"iso": "application/octet-stream",
87+
"img": "application/octet-stream",
88+
"msi": "application/octet-stream",
89+
"msp": "application/octet-stream",
90+
"msm": "application/octet-stream",
91+
"docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
92+
"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
93+
"pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
94+
"mid": "audio/midi",
95+
"midi": "audio/midi",
96+
"kar": "audio/midi",
97+
"mp3": "audio/mpeg",
98+
"ogg": "audio/ogg",
99+
"m4a": "audio/x-m4a",
100+
"ra": "audio/x-realaudio",
101+
"3gpp": "video/3gpp",
102+
"3gp": "video/3gpp",
103+
"ts": "video/mp2t",
104+
"mp4": "video/mp4",
105+
"mpeg": "video/mpeg",
106+
"mpg": "video/mpeg",
107+
"mov": "video/quicktime",
108+
"webm": "video/webm",
109+
"flv": "video/x-flv",
110+
"m4v": "video/x-m4v",
111+
"mng": "video/x-mng",
112+
"asx": "video/x-ms-asf",
113+
"asf": "video/x-ms-asf",
114+
"wmv": "video/x-ms-wmv",
115+
"avi": "video/x-msvideo"
116+
]
117+
118+
internal func MimeType(ext: String?) -> String {
119+
if ext != nil && mimeTypes.contains(where: { $0.0 == ext!.lowercased() }) {
120+
return mimeTypes[ext!.lowercased()]!
121+
}
122+
return DEFAULT_MIME_TYPE
123+
}
124+
125+
extension NSURL {
126+
public func mimeType() -> String {
127+
return MimeType(ext: self.pathExtension)
128+
}
129+
}
130+
131+
extension NSString {
132+
public func mimeType() -> String {
133+
return MimeType(ext: self.pathExtension)
134+
}
135+
}
136+
137+
extension String {
138+
public func mimeType() -> String {
139+
return (self as NSString).mimeType()
140+
}
141+
}
142+
143+

XCode/Swifter.xcodeproj/project.pbxproj

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@
3030
269B47981D3AAAE20042D137 /* Errno.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C76B2A11D369C9D00D35BFB /* Errno.swift */; };
3131
269B47991D3AAAE20042D137 /* String+BASE64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C76B6F61D2C44F30030FC98 /* String+BASE64.swift */; };
3232
269B47A71D3AAC4F0042D137 /* SwiftertvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 269B47A51D3AAC4F0042D137 /* SwiftertvOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
33+
6A0D4512204E9988000A0726 /* MimeTypesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4511204E9988000A0726 /* MimeTypesTests.swift */; };
34+
6A0D4513204E9988000A0726 /* MimeTypesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4511204E9988000A0726 /* MimeTypesTests.swift */; };
35+
6AE2FF722048013000302EC4 /* MimeTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AE2FF702048011A00302EC4 /* MimeTypes.swift */; };
36+
6AE2FF732048013000302EC4 /* MimeTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AE2FF702048011A00302EC4 /* MimeTypes.swift */; };
37+
6AE2FF742048013100302EC4 /* MimeTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AE2FF702048011A00302EC4 /* MimeTypes.swift */; };
38+
6AE2FF752048013300302EC4 /* MimeTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AE2FF702048011A00302EC4 /* MimeTypes.swift */; };
39+
6AE2FF762048013500302EC4 /* MimeTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AE2FF702048011A00302EC4 /* MimeTypes.swift */; };
3340
7AE893EA1C05127900A29F63 /* SwifteriOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AE893E91C05127900A29F63 /* SwifteriOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
3441
7AE893FE1C0512C400A29F63 /* SwifterMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AE893FD1C0512C400A29F63 /* SwifterMac.h */; settings = {ATTRIBUTES = (Public, ); }; };
3542
7AE8940D1C05151100A29F63 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7AE8940C1C05151100A29F63 /* Launch Screen.storyboard */; };
@@ -150,6 +157,8 @@
150157
269B47A11D3AAAE20042D137 /* Swifter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Swifter.framework; sourceTree = BUILT_PRODUCTS_DIR; };
151158
269B47A41D3AAC4F0042D137 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
152159
269B47A51D3AAC4F0042D137 /* SwiftertvOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwiftertvOS.h; sourceTree = "<group>"; };
160+
6A0D4511204E9988000A0726 /* MimeTypesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MimeTypesTests.swift; sourceTree = "<group>"; };
161+
6AE2FF702048011A00302EC4 /* MimeTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MimeTypes.swift; sourceTree = "<group>"; };
153162
7AE893E71C05127900A29F63 /* Swifter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Swifter.framework; sourceTree = BUILT_PRODUCTS_DIR; };
154163
7AE893E91C05127900A29F63 /* SwifteriOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwifteriOS.h; sourceTree = "<group>"; };
155164
7AE893EB1C05127900A29F63 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -177,7 +186,7 @@
177186
7C76B6F71D2C44F30030FC98 /* String+Misc.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Misc.swift"; sourceTree = "<group>"; };
178187
7C76B6F81D2C44F30030FC98 /* String+SHA1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+SHA1.swift"; sourceTree = "<group>"; };
179188
7C76B6F91D2C44F30030FC98 /* WebSockets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSockets.swift; sourceTree = "<group>"; };
180-
7C839B6E19422CFF003A6950 /* SwifterSampleiOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwifterSampleiOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
189+
7C839B6E19422CFF003A6950 /* .app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = .app; sourceTree = BUILT_PRODUCTS_DIR; };
181190
7CA4813B19A2EA8D0030B30D /* SwifterSampleOSX */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = SwifterSampleOSX; sourceTree = BUILT_PRODUCTS_DIR; };
182191
7CA4813D19A2EA8D0030B30D /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
183192
7CB102DF1A17381D00CBA3B4 /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo.png; sourceTree = "<group>"; };
@@ -298,6 +307,7 @@
298307
7C76B6F91D2C44F30030FC98 /* WebSockets.swift */,
299308
7C76B2A11D369C9D00D35BFB /* Errno.swift */,
300309
7C377E161D964B6A009C6148 /* String+File.swift */,
310+
6AE2FF702048011A00302EC4 /* MimeTypes.swift */,
301311
);
302312
name = Sources;
303313
path = ../Sources;
@@ -323,7 +333,7 @@
323333
7C839B6F19422CFF003A6950 /* Products */ = {
324334
isa = PBXGroup;
325335
children = (
326-
7C839B6E19422CFF003A6950 /* SwifterSampleiOS.app */,
336+
7C839B6E19422CFF003A6950 /* .app */,
327337
7CA4813B19A2EA8D0030B30D /* SwifterSampleOSX */,
328338
7AE893E71C05127900A29F63 /* Swifter.framework */,
329339
7AE893FB1C0512C400A29F63 /* Swifter.framework */,
@@ -367,6 +377,7 @@
367377
7CCD876E1C660B250068099B /* SwifterTestsStringExtensions.swift */,
368378
7C4785E81C71D15600A9FE73 /* SwifterTestsWebSocketSession.swift */,
369379
0858E7F31D68BB2600491CD1 /* IOSafetyTests.swift */,
380+
6A0D4511204E9988000A0726 /* MimeTypesTests.swift */,
370381
);
371382
path = SwifterTestsCommon;
372383
sourceTree = "<group>";
@@ -491,7 +502,7 @@
491502
);
492503
name = SwifterSampleiOS;
493504
productName = Swifter;
494-
productReference = 7C839B6E19422CFF003A6950 /* SwifterSampleiOS.app */;
505+
productReference = 7C839B6E19422CFF003A6950 /* .app */;
495506
productType = "com.apple.product-type.application";
496507
};
497508
7CA4813A19A2EA8D0030B30D /* SwifterSampleOSX */ = {
@@ -671,6 +682,7 @@
671682
269B47951D3AAAE20042D137 /* Files.swift in Sources */,
672683
2659FC1A1DADC077003F3930 /* String+File.swift in Sources */,
673684
269B47961D3AAAE20042D137 /* HttpRouter.swift in Sources */,
685+
6AE2FF742048013100302EC4 /* MimeTypes.swift in Sources */,
674686
269B47971D3AAAE20042D137 /* String+SHA1.swift in Sources */,
675687
7C458EFE1D4A7526006A68E5 /* Socket+Server.swift in Sources */,
676688
269B47981D3AAAE20042D137 /* Errno.swift in Sources */,
@@ -697,6 +709,7 @@
697709
7C76B71D1D2C45820030FC98 /* HttpServerIO.swift in Sources */,
698710
7C76B7111D2C45710030FC98 /* Files.swift in Sources */,
699711
7C76B7191D2C457C0030FC98 /* HttpRouter.swift in Sources */,
712+
6AE2FF722048013000302EC4 /* MimeTypes.swift in Sources */,
700713
7C76B7291D2C45920030FC98 /* String+SHA1.swift in Sources */,
701714
7C458EFC1D4A7526006A68E5 /* Socket+Server.swift in Sources */,
702715
7C76B2A21D369C9D00D35BFB /* Errno.swift in Sources */,
@@ -723,6 +736,7 @@
723736
7C76B71E1D2C45820030FC98 /* HttpServerIO.swift in Sources */,
724737
7C76B7121D2C45710030FC98 /* Files.swift in Sources */,
725738
7C76B71A1D2C457C0030FC98 /* HttpRouter.swift in Sources */,
739+
6AE2FF732048013000302EC4 /* MimeTypes.swift in Sources */,
726740
7C76B72A1D2C45920030FC98 /* String+SHA1.swift in Sources */,
727741
7C458EFD1D4A7526006A68E5 /* Socket+Server.swift in Sources */,
728742
7C76B2A31D369C9D00D35BFB /* Errno.swift in Sources */,
@@ -752,6 +766,8 @@
752766
buildActionMask = 2147483647;
753767
files = (
754768
7CCD87701C660B250068099B /* SwifterTestsHttpParser.swift in Sources */,
769+
6A0D4512204E9988000A0726 /* MimeTypesTests.swift in Sources */,
770+
6AE2FF752048013300302EC4 /* MimeTypes.swift in Sources */,
755771
0858E7F81D68BC2600491CD1 /* PingServer.swift in Sources */,
756772
0858E7F41D68BB2600491CD1 /* IOSafetyTests.swift in Sources */,
757773
7C4785E91C71D15600A9FE73 /* SwifterTestsWebSocketSession.swift in Sources */,
@@ -773,10 +789,12 @@
773789
7CEBB8741D94612D00370A6B /* HttpServer.swift in Sources */,
774790
7CEBB8751D94612D00370A6B /* HttpServerIO.swift in Sources */,
775791
7CEBB8761D94612D00370A6B /* Process.swift in Sources */,
792+
6AE2FF762048013500302EC4 /* MimeTypes.swift in Sources */,
776793
7CEBB8771D94612D00370A6B /* Scopes.swift in Sources */,
777794
7CEBB8781D94612D00370A6B /* Socket.swift in Sources */,
778795
7CEBB8791D94612D00370A6B /* Socket+File.swift in Sources */,
779796
7CEBB87A1D94612D00370A6B /* Socket+Server.swift in Sources */,
797+
6A0D4513204E9988000A0726 /* MimeTypesTests.swift in Sources */,
780798
7CEBB87B1D94612D00370A6B /* String+BASE64.swift in Sources */,
781799
7CEBB87C1D94612D00370A6B /* String+Misc.swift in Sources */,
782800
7CEBB87D1D94612D00370A6B /* String+SHA1.swift in Sources */,
@@ -1112,12 +1130,13 @@
11121130
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
11131131
CLANG_ENABLE_MODULES = YES;
11141132
INFOPLIST_FILE = "$(SRCROOT)/SwifterSampleiOS/Info.plist";
1133+
IPHONEOS_DEPLOYMENT_TARGET = 10.12;
11151134
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
11161135
PRODUCT_BUNDLE_IDENTIFIER = "pl.kolakowski.${PRODUCT_NAME:rfc1034identifier}";
1117-
PRODUCT_NAME = "$(TARGET_NAME)";
1118-
SDKROOT = iphoneos;
1136+
SDKROOT = macosx10.13;
11191137
SWIFT_OBJC_BRIDGING_HEADER = "";
11201138
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
1139+
TARGETED_DEVICE_FAMILY = "1,2";
11211140
};
11221141
name = Debug;
11231142
};
@@ -1127,11 +1146,12 @@
11271146
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
11281147
CLANG_ENABLE_MODULES = YES;
11291148
INFOPLIST_FILE = "$(SRCROOT)/SwifterSampleiOS/Info.plist";
1149+
IPHONEOS_DEPLOYMENT_TARGET = 10.12;
11301150
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
11311151
PRODUCT_BUNDLE_IDENTIFIER = "pl.kolakowski.${PRODUCT_NAME:rfc1034identifier}";
1132-
PRODUCT_NAME = "$(TARGET_NAME)";
1133-
SDKROOT = iphoneos;
1152+
SDKROOT = macosx10.13;
11341153
SWIFT_OBJC_BRIDGING_HEADER = "";
1154+
TARGETED_DEVICE_FAMILY = "1,2";
11351155
};
11361156
name = Release;
11371157
};
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//
2+
// MimeTypesTests.swift
3+
// Swifter
4+
//
5+
// Created by Daniel Große on 06.03.18.
6+
// Copyright © 2018 Damian Kołakowski. All rights reserved.
7+
//
8+
9+
import XCTest
10+
11+
class MimeTypeTests: XCTestCase {
12+
13+
func testTypeExtension() {
14+
XCTAssertNotNil(String.mimeType, "Type String is extended with mimeType")
15+
XCTAssertNotNil(NSURL.mimeType, "Type NSURL is extended with mimeType")
16+
XCTAssertNotNil(NSString.mimeType, "Type NSString is extended with mimeType")
17+
}
18+
19+
func testDefaultValue() {
20+
XCTAssertEqual("file.null".mimeType(), "application/octet-stream")
21+
}
22+
23+
func testCorrectTypes() {
24+
XCTAssertEqual("file.html".mimeType(), "text/html")
25+
XCTAssertEqual("file.css".mimeType(), "text/css")
26+
XCTAssertEqual("file.mp4".mimeType(), "video/mp4")
27+
XCTAssertEqual("file.pptx".mimeType(), "application/vnd.openxmlformats-officedocument.presentationml.presentation")
28+
XCTAssertEqual("file.war".mimeType(), "application/java-archive")
29+
}
30+
31+
func testCaseInsensitivity() {
32+
XCTAssertEqual("file.HTML".mimeType(), "text/html")
33+
XCTAssertEqual("file.cSs".mimeType(), "text/css")
34+
XCTAssertEqual("file.MP4".mimeType(), "video/mp4")
35+
XCTAssertEqual("file.PPTX".mimeType(), "application/vnd.openxmlformats-officedocument.presentationml.presentation")
36+
XCTAssertEqual("FILE.WAR".mimeType(), "application/java-archive")
37+
}
38+
39+
}
40+

0 commit comments

Comments
 (0)