Agnishom Chattopadhyay
Agnishom Chattopadhyay

Reputation: 2041

How to configure servant-multipart to allow longer file names?

I have some servant-multipart endpoint which is defined with something like MultipartForm Mem (MultipartData Mem). However, this endpoint does not let me upload long-named files because of defaultParseRequestBodyOptions.

Somehow, I want to replace Mem with some Mem' which is associated with noLimitParseRequestBodyOptions, but I am not able to figure out how to do this. How do I use servant-multipart endpoints with this option from Network.Wai.Parse?

The Multipart type in the form is parametrised by tag, which has two implemented values in the Servant.Multipart module, Tmp and Mem. Now, Mem is an instance of MultipartBackend which has an associated type MultipartBackendOptions. I am guessing I have to modify something here to tweak the relevant ParseRequestBodyOptions.

Upvotes: 1

Views: 223

Answers (1)

Alp Mestanogullari
Alp Mestanogullari

Reputation: 1022

You don't need to define an alternative to Mem. Given the way servant-multipart is currently written, you do not by default have to specify any multipart options. However, you can specify them, using serveWithContext and a suitable Context that contains your options. Below is a complete example that just overrides the maximum filename length to be 512. Of particular interest is ctxt, which contains multipartOpts, our custom options.

{-# LANGUAGE DataKinds, TypeOperators #-}
import Data.Proxy
import Network.Wai.Handler.Warp
import Network.Wai.Parse
import Servant
import Servant.Multipart

type API = MultipartForm Tmp (MultipartData Tmp) :> Post '[PlainText] String

api :: Proxy API
api = Proxy

server :: MultipartData Tmp -> Handler String
server multipartData = return str

  where str = "The form was submitted with "
           ++ show nInputs ++ " textual inputs and "
           ++ show nFiles  ++ " files."
        nInputs = length (inputs multipartData)
        nFiles  = length (files multipartData)

main :: IO ()
main = run 8080 (serveWithContext api ctxt server)

  where ctxt = multipartOpts :. EmptyContext
        multipartOpts = (defaultMultipartOptions (Proxy :: Proxy Tmp))
          { generalOptions = setMaxRequestKeyLength 512 defaultParseRequestBodyOptions
          }

EDIT: If you're a Nix user, you can put the following at the top of the haskell file with this code, make it executable and then just launch it, letting Nix fetch all the deps etc.

#!/usr/bin/env nix-shell
#!nix-shell -i runhaskell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [servant-server servant-multipart wai-extra warp ])"

Upvotes: 3

Related Questions