<commit_before>/**
 * Copyright IBM Corporation 2016
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

// MARK: StaticFileServer

public class StaticFileServer: RouterMiddleware {
    public enum Options {
        case possibleExtensions([String])
        case serveIndexForDir(Bool)
        case addLastModifiedHeader(Bool)
        case maxAgeCacheControlHeader(Int)
        case redirect(Bool)
        case customResponseHeadersSetter(ResponseHeadersSetter)
        case generateETag(Bool)
    }

    let fileServer: FileServer

    public convenience init (options: [Options]) {
        self.init(path: "./public", options: options)
    }

    public convenience init () {
        self.init(path: "./public")
    }

    ///
    /// Initializes a StaticFileServer instance
    ///
    public init (path: String, options: [Options] = [Options]()) {
        var path = path
        if path.hasSuffix("/") {
            path = String(path.characters.dropLast())
        }

        // If we received a path with a tlde (~) in the front, expand it.
#if os(Linux)
        path = path.bridge().stringByExpandingTildeInPath
#else
        path = path.bridge().expandingTildeInPath
#endif

        var possibleExtensions = [String]()
        var serveIndexForDirectory = true
        var addLastModifiedHeader = true
        var maxAgeCacheControlHeader = 0
        var redirect = true
        var generateETag = true
        var customResponseHeadersSetter: ResponseHeadersSetter?

        for option in options {
            switch option {
            case .possibleExtensions(let value):
                possibleExtensions = value
            case .serveIndexForDir(let value):
                serveIndexForDirectory = value
            case .addLastModifiedHeader(let value):
                addLastModifiedHeader = value
            case .maxAgeCacheControlHeader(let value):
                maxAgeCacheControlHeader = value
            case .redirect(let value):
                redirect = value
            case .customResponseHeadersSetter(let value):
                customResponseHeadersSetter = value
            case .generateETag (let value):
                generateETag = value
            }
        }

        let cacheRelatedHeadersSetter =
            CacheRelatedHeadersSetter(addLastModifiedHeader: addLastModifiedHeader,
                                      maxAgeCacheControlHeader: maxAgeCacheControlHeader,
                                      generateETag: generateETag)

        let responseHeadersSetter = CompositeRelatedHeadersSetter(setters: cacheRelatedHeadersSetter, customResponseHeadersSetter)

        fileServer = FileServer(serveIndexForDirectory: serveIndexForDirectory, redirect: redirect,
                                servingFilesPath: path, possibleExtensions: possibleExtensions,
                                responseHeadersSetter: responseHeadersSetter)
    }

    ///
    /// Handle the request
    ///
    /// - Parameter request: the router request
    /// - Parameter response: the router response
    /// - Parameter next: the closure for the next execution block
    ///
    public func handle (request: RouterRequest, response: RouterResponse, next: () -> Void) {
        guard request.serverRequest.method == "GET" || request.serverRequest.method == "HEAD" else {
            return next()
        }

        guard let filePath = fileServer.getFilePath(from: request) else {
            return next()
        }

        guard let requestPath = request.parsedURL.path else {
            return next()
        }

        fileServer.serveFile(filePath, requestPath: requestPath, response: response)
        next()
    }
}
<commit_msg>IBM-Swift/Kitura#505 replaced Options enum with Options struct<commit_after>/**
 * Copyright IBM Corporation 2016
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

// MARK: StaticFileServer

public class StaticFileServer: RouterMiddleware {
    public struct Options {
        let possibleExtensions: [String]
        let serveIndexForDirectory: Bool
        let addLastModifiedHeader: Bool
        let maxAgeCacheControlHeader: Int
        let redirect: Bool
        let generateETag: Bool

        init(possibleExtensions: [String] = [], serveIndexForDirectory: Bool = true,
             addLastModifiedHeader: Bool = true, maxAgeCacheControlHeader: Int = 0,
             redirect: Bool = true, generateETag: Bool = true) {
            self.possibleExtensions = possibleExtensions
            self.serveIndexForDirectory = serveIndexForDirectory
            self.addLastModifiedHeader = addLastModifiedHeader
            self.maxAgeCacheControlHeader = maxAgeCacheControlHeader
            self.redirect = redirect
            self.generateETag = generateETag
        }
    }

    let fileServer: FileServer

    ///
    /// Initializes a StaticFileServer instance
    ///
    public init (path: String = "./public", options: Options = Options(),
                 customResponseHeadersSetter: ResponseHeadersSetter? = nil) {
        var path = path
        if path.hasSuffix("/") {
            path = String(path.characters.dropLast())
        }

        // If we received a path with a tlde (~) in the front, expand it.
#if os(Linux)
        path = path.bridge().stringByExpandingTildeInPath
#else
        path = path.bridge().expandingTildeInPath
#endif

        let cacheRelatedHeadersSetter =
            CacheRelatedHeadersSetter(addLastModifiedHeader: options.addLastModifiedHeader,
                                      maxAgeCacheControlHeader: options.maxAgeCacheControlHeader,
                                      generateETag: options.generateETag)

        let responseHeadersSetter = CompositeRelatedHeadersSetter(setters: cacheRelatedHeadersSetter,
                                                                  customResponseHeadersSetter)

        fileServer = FileServer(serveIndexForDirectory: options.serveIndexForDirectory,
                                redirect: options.redirect, servingFilesPath: path,
                                possibleExtensions: options.possibleExtensions,
                                responseHeadersSetter: responseHeadersSetter)
    }

    ///
    /// Handle the request
    ///
    /// - Parameter request: the router request
    /// - Parameter response: the router response
    /// - Parameter next: the closure for the next execution block
    ///
    public func handle (request: RouterRequest, response: RouterResponse, next: () -> Void) {
        guard request.serverRequest.method == "GET" || request.serverRequest.method == "HEAD" else {
            return next()
        }

        guard let filePath = fileServer.getFilePath(from: request) else {
            return next()
        }

        guard let requestPath = request.parsedURL.path else {
            return next()
        }

        fileServer.serveFile(filePath, requestPath: requestPath, response: response)
        next()
    }
}

{'fraction_non_alphanumeric': 0.07567771084337349, 'fraction_numerical': 0.0026355421686746986, 'mean_word_length': 2.2726899383983574, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7316533', 'n_tokens_mistral': 1953, 'n_tokens_neox': 1831, 'n_words': 584}