haskell-servant / haskell-servant/servant

Raw files served from root override other routes.

Open
#1,435 7 comments 0 reactions 0 assignees View on GitHub
Dominant language
Haskell
Stars
2k
Forks
427
Avg merge
2d 23h
Merged PRs (30d)
5

Description

I run into 405 `Only GET or HEAD is supported` errors when trying to setup a Raw file service directly on root.

I'm not sure whether this is expected from `Raw` as an escape hatch, or whether it's an issue, but it's pretty surprising.

Minimum reproduction example:

In this example, `Raw` is served directly from root.
There is a second run-of-the-mill `Post` route.
`Post` is called with an empty list as a body.
This nets a 405 `Only GET or HEAD is supported` error.

```haskell
{-# language TypeOperators, DataKinds #-}
module Lib
( api
) where

import Servant.API (Raw, Post, ReqBody, JSON, (:>), (:<|>)(..))
import Servant.Server.StaticFiles (serveDirectoryWebApp)
import Servant.Server (serve)
import Data.Proxy (Proxy(Proxy))
import Data.Aeson (Value)

type Api
= Raw -- serve files from parent directory
:<|> "reports" :> ReqBody '[JSON] Value :> Post '[JSON] ()

appServer
= serveDirectoryWebApp "../"
:<|> \body -> pure ()

api = serve (Proxy :: Proxy Api) appServer
```
Running this gives:
```
POST /reports
Request Body: []
Accept: application/json
Status: 405 Method Not Allowed 0.00001707s
```

In this second example, the raw files are behind a path parameter (`"example"`)
The `Post` method is not changed.
It is still called with an empty list as a body.
This nets a 200 ok.

```haskell
{-# language TypeOperators, DataKinds #-}
module Lib
( api
) where

import Servant.API (Raw, Post, ReqBody, JSON, (:>), (:<|>)(..))
import Servant.Server.StaticFiles (serveDirectoryWebApp)
import Servant.Server (serve)
import Data.Proxy (Proxy(Proxy))
import Data.Aeson (Value)

type Api
= "example" :> Raw -- serve files from parent directory
:<|> "reports" :> ReqBody '[JSON] Value :> Post '[JSON] ()

appServer
= serveDirectoryWebApp "../"
:<|> \body -> pure ()

api = serve (Proxy :: Proxy Api) appServer
```
Running this gives:
```
POST /reports
Request Body: []
Accept: application/json
Status: 200 OK 0.000114646s
```

Swapping the two endpoints also works.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.