SaturnFramework / Saturn

Opinionated, web development framework for F# which implements the server-side, functional MVC pattern
https://saturnframework.org
MIT License
703 stars 108 forks source link

Controller.file only works correctly with html files #294

Open roboz0r opened 3 years ago

roboz0r commented 3 years ago

The current implementation of Controller.file only works for html files as the called Giraffe code sets the ContentType: here ctx.SetContentType "text/html; charset=utf-8"

Different typed files e.g. css will not work in the browser with the wrong content type set. I propose to change the implementation of Controller.file to:

let file (ctx: HttpContext) (filePath: string) (contentType: string) =
    task {
        let filePath =
            match Path.IsPathRooted filePath with
            | true -> filePath
            | false ->
                let fileProvider = ctx.GetWebHostEnvironment().WebRootFileProvider
                let fileInfo = fileProvider.GetFileInfo(filePath)
                fileInfo.PhysicalPath

        ctx.Response.ContentType <- contentType

        let! file = File.ReadAllBytesAsync filePath
        return! ctx.WriteBytesAsync file
    }

I added another extension to HttpContext: ctx.GetWebHostEnvironment(): IWebHostEnvironment = ctx.GetService()

In my testing on Azure Functions WebRootFileProvider was initially NullFileProvider but could be instantiated like this:

        let webHostEnv = req.HttpContext.GetWebHostEnvironment()
        webHostEnv.WebRootPath <- Path.Combine(context.FunctionAppDirectory, "public")
        webHostEnv.WebRootFileProvider <- new PhysicalFileProvider(webHostEnv.WebRootPath)

Propose that an addition is also made to the Azure Function CE to enable:

azureFunction {
    execution_context context
    // ...
}

Which would automatically instantiate the WebRootFileProvider as above.