Skip to content

Commit 5f4ee23

Browse files
authored
Merge pull request #1 from phadej/updates
Updates. MonadResource in `servant-server` cleans a bit here
2 parents 83b626d + 4913945 commit 5f4ee23

File tree

3 files changed

+125
-55
lines changed

3 files changed

+125
-55
lines changed

.travis.yml

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# This Travis job script has been generated by a script via
2+
#
3+
# make_travis_yml_2.hs 'servant-multipart.cabal'
4+
#
5+
# For more information, see https://github.com/hvr/multi-ghc-travis
6+
#
7+
language: c
8+
sudo: false
9+
10+
git:
11+
submodules: false # whether to recursively clone submodules
12+
13+
cache:
14+
directories:
15+
- $HOME/.cabal/packages
16+
- $HOME/.cabal/store
17+
18+
before_cache:
19+
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
20+
# remove files that are regenerated by 'cabal update'
21+
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*
22+
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json
23+
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache
24+
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar
25+
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx
26+
27+
matrix:
28+
include:
29+
- compiler: "ghc-7.8.4"
30+
# env: TEST=--disable-tests BENCH=--disable-benchmarks
31+
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-7.8.4], sources: [hvr-ghc]}}
32+
- compiler: "ghc-7.10.3"
33+
# env: TEST=--disable-tests BENCH=--disable-benchmarks
34+
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-7.10.3], sources: [hvr-ghc]}}
35+
- compiler: "ghc-8.0.2"
36+
# env: TEST=--disable-tests BENCH=--disable-benchmarks
37+
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.0.2], sources: [hvr-ghc]}}
38+
39+
before_install:
40+
- HC=${CC}
41+
- unset CC
42+
- PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$PATH
43+
- PKGNAME='servant-multipart'
44+
- ROOTDIR=$(pwd)
45+
46+
install:
47+
- cabal --version
48+
- echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
49+
- BENCH=${BENCH---enable-benchmarks}
50+
- TEST=${TEST---enable-tests}
51+
- travis_retry cabal update -v
52+
- sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
53+
- rm -fv cabal.project.local
54+
# Fetch not-released servant
55+
- git clone https://github.com/haskell-servant/servant.git
56+
- cd servant; git checkout 736918a694dd7247fbd3f21a9bc138f6dcc5b3dd; cd ..
57+
- "echo 'packages: . servant/servant/ servant/servant-server/ ' > cabal.project"
58+
- rm -f cabal.project.freeze
59+
- cabal new-build -w ${HC} ${TEST} ${BENCH} --dep -j2
60+
- cabal new-build -w ${HC} --disable-tests --disable-benchmarks --dep -j2
61+
62+
# Here starts the actual work to be performed for the package under test;
63+
# any command which exits with a non-zero exit code causes the build to fail.
64+
script:
65+
- if [ -f configure.ac ]; then autoreconf -i; fi
66+
- rm -rf dist/
67+
- cabal sdist # test that a source-distribution can be generated
68+
- cd dist/
69+
- SRCTAR=(${PKGNAME}-*.tar.gz)
70+
- SRC_BASENAME="${SRCTAR/%.tar.gz}"
71+
- tar -xvf "./$SRC_BASENAME.tar.gz"
72+
- cd "$SRC_BASENAME/"
73+
## from here on, CWD is inside the extracted source-tarball
74+
- rm -fv cabal.project.local
75+
- "echo 'packages: . servant/servant/ servant/servant-server/ ' > cabal.project"
76+
- mv $ROOTDIR/servant .
77+
# this builds all libraries and executables (without tests/benchmarks)
78+
- rm -f cabal.project.freeze
79+
- cabal new-build -w ${HC} --disable-tests --disable-benchmarks
80+
# this builds all libraries and executables (including tests/benchmarks)
81+
# - rm -rf ./dist-newstyle
82+
- cabal new-build -w ${HC} ${TEST} ${BENCH}
83+
84+
# there's no 'cabal new-test' yet, so let's emulate for now
85+
- TESTS=( $(awk 'tolower($0) ~ /^test-suite / { print $2 }' *.cabal) )
86+
- if [ "$TEST" != "--enable-tests" ]; then TESTS=(); fi
87+
- shopt -s globstar;
88+
RC=true; for T in ${TESTS[@]}; do echo "== $T ==";
89+
if dist-newstyle/build/**/$SRC_BASENAME/**/build/$T/$T; then echo "= $T OK =";
90+
else echo "= $T FAILED ="; RC=false; fi; done; $RC
91+
92+
# EOF

servant-multipart.cabal

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: servant-multipart
22
version: 0.1
33
synopsis: multipart/form-data (e.g file upload) support for servant
44
description: Please see README.md
5-
homepage: https://github.com/alpmestan/servant-multipart#readme
5+
homepage: https://github.com/haskell-servant/servant-multipart#readme
66
license: BSD3
77
license-file: LICENSE
88
author: Alp Mestanogullari
@@ -11,6 +11,10 @@ copyright: 2016 Alp Mestanogullari
1111
category: Web
1212
build-type: Simple
1313
cabal-version: >=1.10
14+
tested-with:
15+
GHC==7.8.4,
16+
GHC==7.10.3,
17+
GHC==8.0.2
1418

1519
library
1620
hs-source-dirs: src
@@ -21,9 +25,10 @@ library
2125
directory,
2226
http-media,
2327
resourcet,
24-
servant,
25-
servant-server,
28+
servant >=0.10 && <0.11,
29+
servant-server >=0.10 && <0.11,
2630
text,
31+
transformers >=0.3 && <0.6,
2732
wai,
2833
wai-extra
2934
default-language: Haskell2010
@@ -39,9 +44,10 @@ executable upload
3944
servant-multipart,
4045
servant-server,
4146
text,
47+
transformers,
4248
warp,
4349
wai
4450

4551
source-repository head
4652
type: git
47-
location: https://github.com/alpmestan/servant-multipart
53+
location: https://github.com/haskell-servent/servant-multipart

src/Servant/Multipart.hs

Lines changed: 23 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -244,49 +244,32 @@ instance ( FromMultipart a
244244
-- returning the data as well as the resourcet InternalState
245245
-- that allows us to properly clean up the temporary files
246246
-- later on.
247-
check :: MultipartOptions -> DelayedIO (MultipartData, InternalState)
248-
check opts = withRequest $ \request -> liftIO $ do
249-
st <- createInternalState
250-
rawData <- parseRequestBodyEx parseOpts (tmpBackend opts st) request
251-
return (fromRaw rawData, st)
252-
247+
check :: MultipartOptions -> DelayedIO MultipartData
248+
check opts = withRequest $ \request -> do
249+
st <- liftResourceT getInternalState
250+
rawData <- liftIO $ parseRequestBodyEx parseOpts (tmpBackend opts st) request
251+
return (fromRaw rawData)
253252
where parseOpts = generalOptions opts
254253

255-
-- Perform cleanup of uploaded files in /tmp.
256-
cleanup :: (MultipartData, InternalState) -> IO ()
257-
cleanup (multipartData, internalState) = do
258-
removeFileKeys <- forM (files multipartData) $ \file ->
259-
runInternalState
260-
(register $ do
261-
exists <- doesFileExist (fdFilePath file)
262-
when exists $ removeFile (fdFilePath file)
263-
)
264-
internalState
265-
mapM_ release removeFileKeys
266-
closeInternalState internalState
267-
268254
-- Add multipart extraction support to a Delayed.
269255
addMultipartHandling :: FromMultipart multipart
270256
=> MultipartOptions
271257
-> Delayed env (multipart -> a)
272258
-> Delayed env a
273-
addMultipartHandling opts Delayed{..} =
274-
Delayed { bodyD = withRequest $ \request -> do
275-
fuzzyMultipartCTCheck (contentTypeH request)
276-
b <- bodyD
277-
b' <- check opts
278-
addCleanup (cleanup b')
279-
return (b, b')
280-
, serverD = \cs a (b, (multipartData, _st)) req ->
281-
case fromMultipart multipartData of
282-
Nothing -> FailFatal $
283-
err400 { errBody = "fromMultipart returned Nothing" }
284-
Just x -> fmap ($ x) $
285-
serverD cs a b req
286-
, ..
287-
}
288-
289-
where contentTypeH req = fromMaybe "application/octed-stream" $
259+
addMultipartHandling opts subserver =
260+
addBodyCheck subserver contentCheck bodyCheck
261+
where
262+
contentCheck = withRequest $ \request ->
263+
fuzzyMultipartCTCheck (contentTypeH request)
264+
265+
bodyCheck () = do
266+
mpd <- check opts :: DelayedIO MultipartData
267+
case fromMultipart mpd of
268+
Nothing -> liftRouteResult $ FailFatal
269+
err400 { errBody = "fromMultipart returned Nothing" }
270+
Just x -> return x
271+
272+
contentTypeH req = fromMaybe "application/octet-stream" $
290273
lookup "Content-Type" (requestHeaders req)
291274

292275
-- Check that the content type is one of:
@@ -311,21 +294,10 @@ tmpBackend :: MultipartOptions
311294
-> ignored2
312295
-> IO SBS.ByteString
313296
-> IO FilePath
314-
tmpBackend opts st _ _ popper = do
315-
(hcloseReleaseKey, (fp, h)) <-
316-
flip runInternalState st $ allocate tmpFile (hClose . snd)
317-
fix $ \loop -> do
318-
bs <- popper
319-
unless (SBS.null bs) $ do
320-
SBS.hPut h bs
321-
loop
322-
-- make sure the file is closed by now
323-
release hcloseReleaseKey
324-
return fp
325-
326-
where tmpFile = do
327-
tmpdir <- getTmpDir (tmpOptions opts)
328-
openBinaryTempFile tmpdir $ filenamePat (tmpOptions opts)
297+
tmpBackend opts =
298+
tempFileBackEndOpts (getTmpDir tmpOpts) (filenamePat tmpOpts)
299+
where
300+
tmpOpts = tmpOptions opts
329301

330302
-- | Global options for configuring how the
331303
-- server should handle multipart data.

0 commit comments

Comments
 (0)