on 19ecd74 help sign in
51 files changed+310−572
since splitsnapshots
unifiedsplit
.azure/azure-linux-template.yml+22−8 .azure/azure-osx-template.yml+12−2 .azure/azure-windows-template.yml+3−4 .gitignore−1 stack-lts-11.yaml+6−3 stack-lts-12.yaml+6−3 stack-lts-6.yaml+35 stack-lts-9.yaml+31 stack-nightly.yaml−20 stack.yaml+7−3 wai-app-static/ChangeLog.md−10 wai-app-static/Network/Wai/Application/Static.hs+8−10 wai-app-static/WaiAppStatic/CmdLine.hs−1 wai-app-static/WaiAppStatic/Listing.hs+1−1 wai-app-static/WaiAppStatic/Storage/Embedded/TH.hs+1 wai-app-static/WaiAppStatic/Types.hs−2 wai-app-static/test/WaiAppStaticTest.hs+9−9 wai-app-static/wai-app-static.cabal+1−1 wai-conduit/Network/Wai/Conduit.hs+6−5 wai-extra/ChangeLog.md−12 wai-extra/Network/Wai/EventSource.hs+1−19 wai-extra/Network/Wai/EventSource/EventStream.hs+1−1 wai-extra/Network/Wai/Middleware/Gzip.hs−3 wai-extra/Network/Wai/Middleware/Rewrite.hs+1−1 wai-extra/Network/Wai/Test.hs+14−22 wai-extra/example/Main.hs−11 wai-extra/test/Network/Wai/TestSpec.hs+11−41 wai-extra/wai-extra.cabal+3−3 wai-websockets/server.lhs+1−7 wai-websockets/wai-websockets.cabal−1 warp-tls/ChangeLog.md−22 warp-tls/Network/Wai/Handler/WarpTLS.hs+15−27 warp-tls/warp-tls.cabal+5−5 warp/ChangeLog.md+1−50 warp/Network/Wai/Handler/Warp.hs+1−51 warp/Network/Wai/Handler/Warp/File.hs+4−7 warp/Network/Wai/Handler/Warp/HTTP2.hs+16−25 warp/Network/Wai/Handler/Warp/HTTP2/File.hs+2−6 warp/Network/Wai/Handler/Warp/HTTP2/Request.hs+6−7 warp/Network/Wai/Handler/Warp/HTTP2/Response.hs+1−2 warp/Network/Wai/Handler/Warp/Header.hs−2 warp/Network/Wai/Handler/Warp/Recv.hs+4−25 warp/Network/Wai/Handler/Warp/Request.hs+19−21 warp/Network/Wai/Handler/Warp/Response.hs+16−19 warp/Network/Wai/Handler/Warp/Run.hs+25−41 warp/Network/Wai/Handler/Warp/Settings.hs+5−31 warp/Network/Wai/Handler/Warp/Types.hs−10 warp/test/FileSpec.hs+1−1 warp/test/RequestSpec.hs+7−11 warp/test/ResponseSpec.hs+1−1 warp/warp.cabal+1−4
.azure/azure-linux-template.yml+22−8
@@ -5,6 +5,16 @@ jobs:
55 vmImage: ${{ parameters.vmImage }}
66 strategy:
77 matrix:
8+ stack-def:
9+ BUILD: stack
10+ stack-lts-6:
11+ BUILD: stack
12+ STACK_YAML: stack-lts-6.yaml
13+ ARGS: "--resolver lts-6"
14+ stack-lts-9:
15+ BUILD: stack
16+ STACK_YAML: stack-lts-9.yaml
17+ ARGS: "--resolver lts-9"
818 stack-lts-11:
919 BUILD: stack
1020 STACK_YAML: stack-lts-11.yaml
@@ -13,13 +23,17 @@ jobs:
1323 BUILD: stack
1424 STACK_YAML: stack-lts-12.yaml
1525 ARGS: "--resolver lts-12"
16− stack-lts-14:
26+ stack-lts-13:
1727 BUILD: stack
18− ARGS: "--resolver lts-14"
19− stack-nightly:
20− BUILD: stack
21− STACK_YAML: stack-nightly.yaml
22− ARGS: "--resolver nightly"
28+ ARGS: "--resolver lts-13"
29+ cabal-7.10.3:
30+ BUILD: cabal
31+ GHCVER: 7.10.3
32+ CABALVER: 1.22
33+ cabal-8.0.2:
34+ BUILD: cabal
35+ GHCVER: 8.0.2
36+ CABALVER: 1.24
2337 cabal-8.2.2:
2438 BUILD: cabal
2539 GHCVER: 8.4.4
@@ -28,9 +42,9 @@ jobs:
2842 BUILD: cabal
2943 GHCVER: 8.4.4
3044 CABALVER: 2.2
31− cabal-8.6.5:
45+ cabal-8.6.4:
3246 BUILD: cabal
33− GHCVER: 8.6.5
47+ GHCVER: 8.6.4
3448 CABALVER: 2.4
3549 maxParallel: 6
3650 steps:
.azure/azure-osx-template.yml+12−2
@@ -5,6 +5,16 @@ jobs:
55 vmImage: ${{ parameters.vmImage }}
66 strategy:
77 matrix:
8+ stack-def:
9+ BUILD: stack
10+ stack-lts-6:
11+ BUILD: stack
12+ STACK_YAML: stack-lts-6.yaml
13+ ARGS: "--resolver lts-6"
14+ stack-lts-9:
15+ BUILD: stack
16+ STACK_YAML: stack-lts-9.yaml
17+ ARGS: "--resolver lts-9"
818 stack-lts-11:
919 BUILD: stack
1020 STACK_YAML: stack-lts-11.yaml
@@ -13,9 +23,9 @@ jobs:
1323 BUILD: stack
1424 STACK_YAML: stack-lts-12.yaml
1525 ARGS: "--resolver lts-12"
16− stack-lts-14:
26+ stack-lts-13:
1727 BUILD: stack
18− ARGS: "--resolver lts-14"
28+ ARGS: "--resolver lts-13"
1929 maxParallel: 3
2030 steps:
2131 - script: |
.azure/azure-windows-template.yml+3−4
@@ -5,9 +5,9 @@ jobs:
55 vmImage: ${{ parameters.vmImage }}
66 strategy:
77 matrix:
8− stack-lts-14:
8+ stack-lts-13:
99 BUILD: stack
10− ARGS: "--resolver lts-14"
10+ ARGS: "--resolver lts-13"
1111 maxParallel: 3
1212 steps:
1313 - bash: |
@@ -16,8 +16,7 @@ jobs:
1616 unzip -o /usr/bin/stack.zip -d /usr/bin/
1717 stack setup $ARGS > /dev/null
1818 stack --install-ghc $ARGS test --bench --only-dependencies
19− stack $ARGS test --bench --no-run-benchmarks --no-run-tests
20− stack $ARGS test --bench --no-run-benchmarks --jobs 1 # non-parallel test execution
19+ stack $ARGS test --bench --no-run-benchmarks
2120 env:
2221 OS_NAME: ${{ parameters.os }}
2322 displayName: 'Installation ${{parameters.os}} & Test'
.gitignore−1
@@ -9,4 +9,3 @@ tarballs/
99cabal.sandbox.config
1010.stack-work/
1111*~
12−stack*.yaml.lock
stack-lts-11.yaml+6−3
@@ -17,11 +17,14 @@ extra-deps:
1717- streaming-commons-0.2.1.0@sha256:163af02944f374f316e35257c1afbffefd2c2852a85a151d1ea0ad22152cf28d,4990
1818- http2-2.0.0
1919- network-byte-order-0.1.1.0
20−- tls-1.5.3
21−- tls-session-manager-0.0.4
22−- x509-1.7.5
2320nix:
2421 enable: false
2522 packages:
2623 - fcgi
2724 - zlib
25+image:
26+ containers:
27+ - base: "fpco/pid1"
28+ name: "yesodweb/warp"
29+ executables:
30+ - warp
stack-lts-12.yaml+6−3
@@ -18,9 +18,12 @@ nix:
1818 packages:
1919 - fcgi
2020 - zlib
21+image:
22+ containers:
23+ - base: "fpco/pid1"
24+ name: "yesodweb/warp"
25+ executables:
26+ - warp
2127extra-deps:
2228- http2-2.0.0
2329- network-byte-order-0.1.1.0
24−- tls-1.5.3
25−- tls-session-manager-0.0.4
26−- x509-1.7.5
stack-lts-6.yamlnew file+35
@@ -0,0 +1,35 @@
1+resolver: lts-6.35
2+packages:
3+- ./auto-update
4+- ./mime-types
5+- ./wai
6+- ./wai-extra
7+- ./warp
8+- ./warp-tls
9+- ./wai-app-static
10+- ./wai-websockets
11+- ./wai-conduit
12+- ./time-manager
13+extra-deps:
14+- bsb-http-chunked-0.0.0.2@sha256:0571ef33ec5530104503d32eaf24f2d7c221f350e5fc475a6dd8e84311bc0ca1,1792
15+- streaming-commons-0.2.1.0@sha256:163af02944f374f316e35257c1afbffefd2c2852a85a151d1ea0ad22152cf28d,4990
16+- tls-session-manager-0.0.0.2@sha256:e3d3f8a026196df46746a19d3d7d31211b2fca3aefed9074e951b2dcc1b8833c,872
17+- wai-logger-2.3.2@sha256:7f5dbc72c0753bd3e0e73f8f542d9d159d1d70f8ff3a3ec16d0b74b500534fc6,1572
18+- gauge-0.2.3@sha256:ce41cb66ebf730a5050181db0338b1a4b3f76ac71331bf5070089bcd4352ff46,3777
19+- psqueues-0.2.7.0@sha256:189970837d0aae01f48cd2a8aac6ce314191939e118cc0488aee1fb12da1956a,4757
20+- basement-0.0.7@rev:0
21+- http-client-0.5.13.1@rev:0
22+- http-types-0.12.3@rev:0
23+- http2-2.0.0
24+- network-byte-order-0.1.1.0
25+nix:
26+ enable: false
27+ packages:
28+ - fcgi
29+ - zlib
30+image:
31+ containers:
32+ - base: "fpco/pid1"
33+ name: "yesodweb/warp"
34+ executables:
35+ - warp
stack-lts-9.yamlnew file+31
@@ -0,0 +1,31 @@
1+resolver: lts-9.21
2+packages:
3+- ./auto-update
4+- ./mime-types
5+- ./wai
6+- ./wai-extra
7+- ./warp
8+- ./warp-tls
9+- ./wai-app-static
10+- ./wai-websockets
11+- ./wai-conduit
12+- ./time-manager
13+extra-deps:
14+- bsb-http-chunked-0.0.0.2@sha256:0571ef33ec5530104503d32eaf24f2d7c221f350e5fc475a6dd8e84311bc0ca1,1792
15+- streaming-commons-0.2.1.0@sha256:163af02944f374f316e35257c1afbffefd2c2852a85a151d1ea0ad22152cf28d,4990
16+- wai-logger-2.3.2@sha256:7f5dbc72c0753bd3e0e73f8f542d9d159d1d70f8ff3a3ec16d0b74b500534fc6,1572
17+- http-client-0.5.13.1@rev:0
18+- http-types-0.12.3@rev:0
19+- http2-2.0.0
20+- network-byte-order-0.1.1.0
21+nix:
22+ enable: false
23+ packages:
24+ - fcgi
25+ - zlib
26+image:
27+ containers:
28+ - base: "fpco/pid1"
29+ name: "yesodweb/warp"
30+ executables:
31+ - warp
stack-nightly.yamldeleted−20
@@ -1,20 +0,0 @@
1−resolver: nightly-2020-01-08
2−packages:
3−- ./auto-update
4−- ./mime-types
5−- ./wai
6−- ./wai-extra
7−- ./warp
8−- ./warp-tls
9−- ./wai-app-static
10−- ./wai-websockets
11−- ./wai-conduit
12−- ./time-manager
13−flags:
14− wai-extra:
15− build-example: true
16−nix:
17− enable: false
18− packages:
19− - fcgi
20− - zlib
stack.yaml+7−3
@@ -1,4 +1,4 @@
1−resolver: lts-14.22
1+resolver: lts-13.14
22packages:
33- ./auto-update
44- ./mime-types
@@ -18,8 +18,12 @@ nix:
1818 packages:
1919 - fcgi
2020 - zlib
21+image:
22+ containers:
23+ - base: "fpco/pid1"
24+ name: "yesodweb/warp"
25+ executables:
26+ - warp
2127extra-deps:
2228- http2-2.0.0
2329- network-byte-order-0.1.1.0
24−- tls-1.5.3
25−- tls-session-manager-0.0.4
wai-app-static/ChangeLog.md−10
@@ -1,13 +1,3 @@
1−# wai-app-static changelog
2−
3−## 3.1.7.1
4−
5−* Update the test suite too
6−
7−## 3.1.7
8−
9−* Use 302 instead of 301 redirect, to avoid caching the presence of an index.html file
10−
111## 3.1.6.3
122
133* The executable warp obeys `-h` option properly for host
wai-app-static/Network/Wai/Application/Static.hs+8−10
@@ -164,13 +164,11 @@ serveFile StaticSettings {..} req file
164164 -- Didn't match, but we have a hash value. Send the file contents
165165 -- with an ETag header.
166166 --
167− -- RFC7232 (HTTP 1.1):
168− -- > A recipient MUST ignore If-Modified-Since if the request contains an
169− -- > If-None-Match header field; the condition in If-None-Match is
170− -- > considered to be a more accurate replacement for the condition in
171− -- > If-Modified-Since, and the two are only combined for the sake of
172− -- > interoperating with older intermediaries that might not implement
173− -- > If-None-Match.
167+ -- Note: It would be arguably better to next check
168+ -- if-modified-since and return a 304 if that indicates a match as
169+ -- well. However, the circumstances under which such a situation
170+ -- could arise would be very anomolous, and should likely warrant a
171+ -- new file being sent anyway.
174172 (Just hash, _) -> respond [("ETag", hash)]
175173
176174 -- No hash value available, fall back to last modified support.
@@ -245,7 +243,7 @@ staticAppPieces ss rawPieces req sendResponse = liftIO $ do
245243 response :: StaticResponse -> IO W.ResponseReceived
246244 response (FileResponse file ch) = do
247245 mimetype <- ssGetMimeType ss file
248− -- let filesize = fileGetSize file
246+ let filesize = fileGetSize file
249247 let headers = ("Content-Type", mimetype)
250248 -- Let Warp provide the content-length, since it takes
251249 -- range requests into account
@@ -269,13 +267,13 @@ staticAppPieces ss rawPieces req sendResponse = liftIO $ do
269267 Just hash -> replace "etag" (Just hash) (W.queryString req)
270268 Nothing -> remove "etag" (W.queryString req)
271269
272− sendResponse $ W.responseLBS H.status302
270+ sendResponse $ W.responseLBS H.status301
273271 [ ("Content-Type", "text/plain")
274272 , ("Location", S8.append loc $ H.renderQuery True qString)
275273 ] "Redirect"
276274
277275 response (RawRedirect path) =
278− sendResponse $ W.responseLBS H.status302
276+ sendResponse $ W.responseLBS H.status301
279277 [ ("Content-Type", "text/plain")
280278 , ("Location", path)
281279 ] "Redirect"
wai-app-static/WaiAppStatic/CmdLine.hs−1
@@ -39,7 +39,6 @@ data Args = Args
3939 }
4040
4141#if MIN_VERSION_optparse_applicative(0, 10, 0)
42−option' :: Mod OptionFields Int -> Parser Int
4342option' = option auto
4443#else
4544option' = option
wai-app-static/WaiAppStatic/Listing.hs+1−1
@@ -64,7 +64,7 @@ defaultListing pieces (Folder contents) = do
6464
6565 -- Add a link to the root of the tree
6666 showFolder' :: Bool -> Pieces -> H.Html
67− showFolder' hasTrailingSlash pieces' = showFolder hasTrailingSlash (unsafeToPiece "root" : pieces')
67+ showFolder' hasTrailingSlash pieces = showFolder hasTrailingSlash (unsafeToPiece "root" : pieces)
6868
6969 showFolder :: Bool -> Pieces -> H.Html
7070 showFolder _ [] = "/" -- won't happen
wai-app-static/WaiAppStatic/Storage/Embedded/TH.hs+1
@@ -7,6 +7,7 @@ module WaiAppStatic.Storage.Embedded.TH(
77
88import Data.ByteString.Builder.Extra (byteStringInsert)
99import Codec.Compression.GZip (compress)
10+import Control.Applicative
1011import Data.ByteString.Unsafe (unsafePackAddressLen)
1112import Data.Either (lefts, rights)
1213import GHC.Exts (Int(..))
wai-app-static/WaiAppStatic/Types.hs−2
@@ -59,8 +59,6 @@ toPieces :: [Text] -> Maybe Pieces
5959toPieces = mapM toPiece
6060
6161-- | Request coming from a user. Corresponds to @pathInfo@.
62−--
63−-- The root path is the empty list.
6462type Pieces = [Piece]
6563
6664-- | Values for the max-age component of the cache-control response header.
wai-app-static/test/WaiAppStaticTest.hs+9−9
@@ -57,22 +57,22 @@ spec = do
5757 assertStatus 200 =<<
5858 request (setRawPathInfo defRequest path)
5959
60− it "404 for non-existent files" $ webApp $
60+ it "404 for non-existant files" $ webApp $
6161 assertStatus 404 =<<
6262 request (setRawPathInfo defRequest "doesNotExist")
6363
64− it "302 redirect when multiple slashes" $ webApp $ do
64+ it "301 redirect when multiple slashes" $ webApp $ do
6565 req <- request (setRawPathInfo defRequest "a//b/c")
66− assertStatus 302 req
66+ assertStatus 301 req
6767 assertHeader "Location" "../../a/b/c" req
6868
6969 let absoluteApp = flip runSession $ staticApp $ (defaultWebAppSettings "test") {
7070 ssMkRedirect = \_ u -> S8.append "http://www.example.com" u
7171 }
72− it "302 redirect when multiple slashes" $ absoluteApp $
72+ it "301 redirect when multiple slashes" $ absoluteApp $
7373 flip mapM_ ["/a//b/c", "a//b/c"] $ \path -> do
7474 req <- request (setRawPathInfo defRequest path)
75− assertStatus 302 req
75+ assertStatus 301 req
7676 assertHeader "Location" "http://www.example.com/a/b/c" req
7777
7878 describe "webApp when requesting a static asset" $ do
@@ -131,10 +131,10 @@ spec = do
131131 assertStatus 304 req
132132 assertNoHeader "Cache-Control" req
133133
134− context "302 redirect to add a trailing slash on directories if missing" $ do
134+ context "301 redirect to add a trailing slash on directories if missing" $ do
135135 it "works at the root" $ fileServerApp $ do
136136 req <- request (setRawPathInfo defRequest "/a")
137− assertStatus 302 req
137+ assertStatus 301 req
138138 assertHeader "Location" "/a/" req
139139
140140 it "works when an index.html is delivered" $ do
@@ -144,7 +144,7 @@ spec = do
144144 inTempDirectory $ fileServerAppWithSettings settings $ do
145145 liftIO $ touch "foo/index.html"
146146 req <- request (setRawPathInfo defRequest "/foo")
147− assertStatus 302 req
147+ assertStatus 301 req
148148 assertHeader "Location" "/foo/" req
149149
150150 let urlMapApp = flip runSession $ \req send ->
@@ -158,7 +158,7 @@ spec = do
158158 "urlMapApp: only works at subPath"
159159 it "works with subpath at the root of the file server" $ urlMapApp $ do
160160 req <- request (setRawPathInfo defRequest "/subPath")
161− assertStatus 302 req
161+ assertStatus 301 req
162162 assertHeader "Location" "/subPath/" req
163163
164164 context "with defaultWebAppSettings" $ do
wai-app-static/wai-app-static.cabal+1−1
@@ -1,5 +1,5 @@
11name: wai-app-static
2−version: 3.1.7.1
2+version: 3.1.6.3
33license: MIT
44license-file: LICENSE
55author: Michael Snoyman <michael@snoyman.com>
wai-conduit/Network/Wai/Conduit.hs+6−5
@@ -17,16 +17,17 @@ import qualified Data.ByteString as S
1717import Control.Monad (unless)
1818import Network.HTTP.Types
1919import Data.ByteString.Builder (Builder)
20+import Data.IORef
2021import qualified Data.Conduit.List as CL
2122
2223-- | Stream the request body.
2324--
2425-- Since 3.0.0
25−sourceRequestBody :: MonadIO m => Request -> ConduitT () ByteString m ()
26+sourceRequestBody :: MonadIO m => Request -> Source m ByteString
2627sourceRequestBody req =
2728 loop
2829 where
29− go = liftIO (getRequestBodyChunk req)
30+ go = liftIO (requestBody req)
3031
3132 loop = do
3233 bs <- go
@@ -37,9 +38,9 @@ sourceRequestBody req =
3738-- | Create an HTTP response out of a @Source@.
3839--
3940-- Since 3.0.0
40−responseSource :: Status -> ResponseHeaders -> ConduitT () (Flush Builder) IO () -> Response
41+responseSource :: Status -> ResponseHeaders -> Source IO (Flush Builder) -> Response
4142responseSource s hs src = responseStream s hs $ \send flush ->
42− runConduit $ src .| CL.mapM_ (\mbuilder ->
43+ src $$ CL.mapM_ (\mbuilder ->
4344 case mbuilder of
4445 Chunk b -> send b
4546 Flush -> flush)
@@ -49,7 +50,7 @@ responseSource s hs src = responseStream s hs $ \send flush ->
4950--
5051-- Since 3.0.0
5152responseRawSource :: (MonadIO m, MonadIO n)
52− => (ConduitT () ByteString m () -> ConduitT ByteString Void n () -> IO ())
53+ => (Source m ByteString -> Sink ByteString n () -> IO ())
5354 -> Response
5455 -> Response
5556responseRawSource app =
wai-extra/ChangeLog.md−12
@@ -1,17 +1,5 @@
11# Changelog for wai-extra
22
3−## 3.0.29.1
4−
5−* Fix `Network.Wai.Test.request` always sending an empty request body [#794](https://github.com/yesodweb/wai/pull/794)
6−
7−## 3.0.29
8−
9−* Export `Network.Wai.EventSource.eventStreamAppRaw` [#786](https://github.com/yesodweb/wai/pull/786)
10−
11−## 3.0.28
12−
13−* Add `Network.Wai.EventSource.eventStreamAppRaw` [#767](https://github.com/yesodweb/wai/pull/767)
14−
153## 3.0.27
164
175* Add custom request log formatter which includes response headers [#762](https://github.com/yesodweb/wai/pull/762)
wai-extra/Network/Wai/EventSource.hs+1−19
@@ -5,14 +5,11 @@
55 headers:
66
77 > [ ("X-Accel-Buffering", "no"), ("Cache-Control", "no-cache")]
8−
9− There is a small example using these functions in the @example@ directory.
108-}
119module Network.Wai.EventSource (
1210 ServerEvent(..),
1311 eventSourceAppChan,
14− eventSourceAppIO,
15− eventStreamAppRaw
12+ eventSourceAppIO
1613 ) where
1714
1815import Data.Function (fix)
@@ -42,18 +39,3 @@ eventSourceAppIO src _ sendResponse =
4239 case eventToBuilder se of
4340 Nothing -> return ()
4441 Just b -> sendChunk b >> flush >> loop
45−
46−-- | Make a new WAI EventSource application with a handler that emits events.
47−--
48−-- @since 3.0.28
49−eventStreamAppRaw :: ((ServerEvent -> IO()) -> IO () -> IO ()) -> Application
50−eventStreamAppRaw handler _ sendResponse =
51− sendResponse $ responseStream
52− status200
53− [(hContentType, "text/event-stream")]
54− $ \sendChunk flush -> handler (sendEvent sendChunk) flush
55− where
56− sendEvent sendChunk event =
57− case eventToBuilder event of
58− Nothing -> return ()
59− Just b -> sendChunk b
wai-extra/Network/Wai/EventSource/EventStream.hs+1−1
@@ -1,5 +1,5 @@
11{-# LANGUAGE CPP #-}
2−{- code adapted by Mathias Billman originally from Chris Smith https://github.com/cdsmith/gloss-web -}
2+{- code adapted by Mathias Billman originaly from Chris Smith https://github.com/cdsmith/gloss-web -}
33
44{-|
55 Internal module, usually you don't need to use it.
wai-extra/Network/Wai/Middleware/Gzip.hs−3
@@ -89,9 +89,6 @@ defaultCheckMime bs =
8989-- if gzip is supported.
9090--
9191-- File responses will be compressed according to the 'GzipFiles' setting.
92−--
93−-- Will only be applied based on the 'gzipCheckMime' setting. For default
94−-- behavior, see 'defaultCheckMime'.
9592gzip :: GzipSettings -> Middleware
9693gzip set app env sendResponse = app env $ \res ->
9794 case res of
wai-extra/Network/Wai/Middleware/Rewrite.hs+1−1
@@ -169,7 +169,7 @@ import Control.Applicative
169169--
170170-- as the following example demonstrates.
171171--
172−-- Old versions of the library could only handle path pieces, not queries.
172+-- Old versions of the libary could only handle path pieces, not queries.
173173-- This could have been supplied to 'rewritePure'.
174174--
175175-- @
wai-extra/Network/Wai/Test.hs+14−22
@@ -99,10 +99,6 @@ runSession session app = ST.evalStateT (runReaderT session app) initState
9999data SRequest = SRequest
100100 { simpleRequest :: Request
101101 , simpleRequestBody :: L.ByteString
102− -- ^ Request body that will override the one set in 'simpleRequest'.
103− --
104− -- This is usually simpler than setting the body as a stateful IO-action
105− -- in 'simpleRequest'.
106102 }
107103data SResponse = SResponse
108104 { simpleStatus :: H.Status
@@ -110,16 +106,8 @@ data SResponse = SResponse
110106 , simpleBody :: L.ByteString
111107 }
112108 deriving (Show, Eq)
113−
114109request :: Request -> Session SResponse
115−request req = do
116− app <- ask
117− req' <- addCookiesToRequest req
118− response <- liftIO $ do
119− ref <- newIORef $ error "runResponse gave no result"
120− ResponseReceived <- app req' (runResponse ref)
121− readIORef ref
122− extractSetCookieFromSResponse response
110+request = srequest . flip SRequest L.empty
123111
124112-- | Set whole path (request path + query string).
125113setPath :: Request -> S8.ByteString -> Request
@@ -178,18 +166,22 @@ extractSetCookieFromSResponse response = do
178166 (Map.fromList [(Cookie.setCookieName c, c) | c <- newClientCookies ]))
179167 return response
180168
181−-- | Similar to 'request', but allows setting the request body as a plain
182−-- 'L.ByteString'.
183169srequest :: SRequest -> Session SResponse
184170srequest (SRequest req bod) = do
171+ app <- ask
185172 refChunks <- liftIO $ newIORef $ L.toChunks bod
186− request $
187− req
188− { requestBody = atomicModifyIORef refChunks $ \bss ->
189− case bss of
190− [] -> ([], S.empty)
191− x:y -> (y, x)
192− }
173+ let req' = req
174+ { requestBody = atomicModifyIORef refChunks $ \bss ->
175+ case bss of
176+ [] -> ([], S.empty)
177+ x:y -> (y, x)
178+ }
179+ req'' <- addCookiesToRequest req'
180+ response <- liftIO $ do
181+ ref <- newIORef $ error "runResponse gave no result"
182+ ResponseReceived <- app req'' (runResponse ref)
183+ readIORef ref
184+ extractSetCookieFromSResponse response
193185
194186runResponse :: IORef SResponse -> Response -> IO ResponseReceived
195187runResponse ref res = do
wai-extra/example/Main.hs−11
@@ -37,17 +37,6 @@ eventIO = do
3737 Nothing
3838 [string8 . show $ time]
3939
40−eventRaw :: (ServerEvent -> IO ()) -> IO () -> IO ()
41−eventRaw = handle 0
42− where
43− handle counter emit flush = do
44− threadDelay 1000000
45− _ <- emit $ ServerEvent (Just $ string8 "raw")
46− Nothing
47− [string8 . show $ counter]
48− _ <- flush
49− handle (counter + 1) emit flush
50−
5140main :: IO ()
5241main = do
5342 chan <- newChan
wai-extra/test/Network/Wai/TestSpec.hs+11−41
@@ -3,8 +3,6 @@ module Network.Wai.TestSpec (main, spec) where
33
44import Control.Monad (void)
55
6−import qualified Data.IORef as IORef
7−
86import qualified Data.Text.Encoding as TE
97
108import Data.Time.Calendar (fromGregorian)
@@ -55,53 +53,25 @@ spec = do
5553 it "sets rawQueryString to empty string" $ do
5654 rawQueryString (setPath defaultRequest "/foo/bar/baz") `shouldBe` ""
5755
58− describe "srequest" $ do
59−
60− let echoApp req respond = do
61− reqBody <- L8.fromStrict <$> getRequestBodyChunk req
62− let reqHeaders = requestHeaders req
63− respond $
64− responseLBS
65− status200
66− reqHeaders
67− reqBody
68−
69− it "returns the response body of an echo app" $ do
70− sresp <- flip runSession echoApp $
71− srequest $ SRequest defaultRequest "request body"
72− simpleBody sresp `shouldBe` "request body"
73−
7456 describe "request" $ do
7557
76− let echoApp req respond = do
77− reqBody <- L8.fromStrict <$> getRequestBodyChunk req
78− let reqHeaders = requestHeaders req
58+ let simpleApp _req respond =
7959 respond $
8060 responseLBS
8161 status200
82− reqHeaders
83− reqBody
62+ [("foo", "bar")]
63+ "simple"
8464
85− it "returns the status code of an echo app on default request" $ do
86− sresp <- runSession (request defaultRequest) echoApp
65+ it "returns the status code of a simple app on default request" $ do
66+ sresp <- runSession (request defaultRequest) simpleApp
8767 simpleStatus sresp `shouldBe` status200
8868
89− it "returns the response body of an echo app" $ do
90− bodyRef <- IORef.newIORef "request body"
91− let getBodyChunk = IORef.atomicModifyIORef bodyRef $ \leftover -> ("", leftover)
92− sresp <- flip runSession echoApp $
93− request $
94− defaultRequest
95− { requestBody = getBodyChunk
96− }
97− simpleBody sresp `shouldBe` "request body"
98−
99− it "returns the response headers of an echo app" $ do
100− sresp <- flip runSession echoApp $
101− request $
102− defaultRequest
103− { requestHeaders = [("foo", "bar")]
104− }
69+ it "returns the response body of a simple app on default request" $ do
70+ sresp <- runSession (request defaultRequest) simpleApp
71+ simpleBody sresp `shouldBe` "simple"
72+
73+ it "returns the response headers of a simple app on default request" $ do
74+ sresp <- runSession (request defaultRequest) simpleApp
10575 simpleHeaders sresp `shouldBe` [("foo", "bar")]
10676
10777 let cookieApp req respond =
wai-extra/wai-extra.cabal+3−3
@@ -1,5 +1,5 @@
11Name: wai-extra
2−Version: 3.0.29.1
2+Version: 3.0.27
33Synopsis: Provides some basic WAI handlers and middleware.
44description:
55 Provides basic WAI handler and middleware functionality:
@@ -99,8 +99,8 @@ Library
9999 , text >= 0.7
100100 , case-insensitive >= 0.2
101101 , data-default-class
102− , fast-logger >= 2.4.5
103− , wai-logger >= 2.3.2
102+ , fast-logger >= 2.4.5 && < 2.5
103+ , wai-logger >= 2.3.2 && < 2.4
104104 , ansi-terminal
105105 , resourcet >= 0.4.6 && < 1.3
106106 , void >= 0.5
wai-websockets/server.lhs+1−7
@@ -8,8 +8,6 @@ this example, keep the [reference](http://jaspervdj.be/websockets/reference)
88nearby to check out the functions we use.
99
1010> {-# LANGUAGE OverloadedStrings, TemplateHaskell #-}
11−> {-# LANGUAGE CPP #-}
12−> {-# OPTIONS_GHC -Wno-unused-top-binds #-} -- for numClients
1311> import Data.Char (isPunctuation, isSpace)
1412> import Data.Monoid (mappend)
1513> import Data.Text (Text)
@@ -101,13 +99,9 @@ stays alive on some browsers.
10199
102100> application state pending = do
103101> conn <- WS.acceptRequest pending
104−#if __GLASGOW_HASKELL__ >= 806
105−> WS.withPingThread conn 30 (return ()) $ do
106−#else
107102> WS.forkPingThread conn 30
108−#endif
109103
110−When a client is successfully connected, we read the first message. This should
104+When a client is succesfully connected, we read the first message. This should
111105be in the format of "Hi! I am Jasper", where Jasper is the requested username.
112106
113107> msg <- WS.receiveData conn
wai-websockets/wai-websockets.cabal−1
@@ -45,7 +45,6 @@ Executable wai-websockets-example
4545 , text
4646 , file-embed
4747 , http-types
48− other-modules: Network.Wai.Handler.WebSockets
4948 else
5049 buildable: False
5150
warp-tls/ChangeLog.md−22
@@ -1,25 +1,3 @@
1−## 3.2.11
2−
3−* Ignoring an exception from shutdown (gracefulClose).
4−
5−## 3.2.10
6−
7−* Passing client certificate, if any, to Warp
8− [#783](https://github.com/yesodweb/wai/pull/783)
9−
10−## 3.2.9
11−
12−* Cooperating setGracefulCloseTimeout1 and setGracefulCloseTimeout2 of Warp.
13− [#782](https://github.com/yesodweb/wai/pull/782)
14−
15−## 3.2.8
16−
17−* Using gracefullClose of network 3.1.1 or later if available.
18−
19−## 3.2.7
20−
21−* Relaxing version constraint.
22−
231## 3.2.6
242
253* Using the Strict and StrictData language extensions for GHC >8.
warp-tls/Network/Wai/Handler/WarpTLS.hs+15−27
@@ -53,9 +53,6 @@ import qualified Data.IORef as I
5353import Data.Streaming.Network (bindPortTCP, safeRecv)
5454import Data.Typeable (Typeable)
5555import Network.Socket (Socket, close, withSocketsDo, SockAddr, accept)
56−#if MIN_VERSION_network(3,1,1)
57−import Network.Socket (gracefulClose)
58−#endif
5956import Network.Socket.ByteString (sendAll)
6057import qualified Network.TLS as TLS
6158import qualified Crypto.PubKey.DH as DH
@@ -281,7 +278,7 @@ runTLSSocket' :: TLSSettings -> Settings -> TLS.Credential -> TLS.SessionManager
281278runTLSSocket' tlsset@TLSSettings{..} set credential mgr sock app =
282279 runSettingsConnectionMakerSecure set get app
283280 where
284− get = getter tlsset set sock params
281+ get = getter tlsset sock params
285282 params = def { -- TLS.ServerParams
286283 TLS.serverWantClientCert = tlsWantClientCert
287284 , TLS.serverCACertificates = []
@@ -322,55 +319,49 @@ alpn xs
322319
323320----------------------------------------------------------------
324321
325−getter :: TLS.TLSParams params => TLSSettings -> Settings -> Socket -> params -> IO (IO (Connection, Transport), SockAddr)
326−getter tlsset@TLSSettings{..} set sock params = do
322+getter :: TLS.TLSParams params => TLSSettings -> Socket -> params -> IO (IO (Connection, Transport), SockAddr)
323+getter tlsset@TLSSettings{..} sock params = do
327324#if WINDOWS
328325 (s, sa) <- windowsThreadBlockHack $ accept sock
329326#else
330327 (s, sa) <- accept sock
331328#endif
332329 setSocketCloseOnExec s
333− return (mkConn tlsset set s params, sa)
330+ return (mkConn tlsset s params, sa)
334331
335−mkConn :: TLS.TLSParams params => TLSSettings -> Settings -> Socket -> params -> IO (Connection, Transport)
336−mkConn tlsset set s params = switch `onException` close s
332+mkConn :: TLS.TLSParams params => TLSSettings -> Socket -> params -> IO (Connection, Transport)
333+mkConn tlsset s params = switch `onException` close s
337334 where
338335 switch = do
339336 firstBS <- safeRecv s 4096
340337 if not (S.null firstBS) && S.head firstBS == 0x16 then
341− httpOverTls tlsset set s firstBS params
338+ httpOverTls tlsset s firstBS params
342339 else
343− plainHTTP tlsset set s firstBS
340+ plainHTTP tlsset s firstBS
344341
345342----------------------------------------------------------------
346343
347−httpOverTls :: TLS.TLSParams params => TLSSettings -> Settings -> Socket -> S.ByteString -> params -> IO (Connection, Transport)
348−httpOverTls TLSSettings{..} _set s bs0 params = do
344+httpOverTls :: TLS.TLSParams params => TLSSettings -> Socket -> S.ByteString -> params -> IO (Connection, Transport)
345+httpOverTls TLSSettings{..} s bs0 params = do
349346 recvN <- makePlainReceiveN s bs0
350347 ctx <- TLS.contextNew (backend recvN) params
351348 TLS.contextHookSetLogging ctx tlsLogging
352349 TLS.handshake ctx
353− h2 <- (== Just "h2") <$> TLS.getNegotiatedProtocol ctx
354− isH2 <- I.newIORef h2
355350 writeBuf <- allocateBuffer bufferSize
356351 -- Creating a cache for leftover input data.
357352 ref <- I.newIORef ""
358353 tls <- getTLSinfo ctx
359− return (conn ctx writeBuf ref isH2, tls)
354+ return (conn ctx writeBuf ref, tls)
360355 where
361356 backend recvN = TLS.Backend {
362357 TLS.backendFlush = return ()
363−#if MIN_VERSION_network(3,1,1)
364− , TLS.backendClose = gracefulClose s 5000 `E.catch` \(SomeException _) -> return ()
365−#else
366358 , TLS.backendClose = close s
367−#endif
368359 , TLS.backendSend = sendAll' s
369360 , TLS.backendRecv = recvN
370361 }
371362 sendAll' sock bs = sendAll sock bs `E.catch` \(SomeException _) ->
372363 throwIO ConnectionClosedByPeer
373− conn ctx writeBuf ref isH2 = Connection {
364+ conn ctx writeBuf ref = Connection {
374365 connSendMany = TLS.sendData ctx . L.fromChunks
375366 , connSendAll = sendall
376367 , connSendFile = sendfile
@@ -380,7 +371,6 @@ httpOverTls TLSSettings{..} _set s bs0 params = do
380371 , connRecvBuf = recvBuf ref
381372 , connWriteBuffer = writeBuf
382373 , connBufferSize = bufferSize
383− , connHTTP2 = isH2
384374 }
385375 where
386376 sendall = TLS.sendData ctx . L.fromChunks . return
@@ -468,13 +458,11 @@ getTLSinfo ctx = do
468458#if MIN_VERSION_tls(1,5,0)
469459 TLS.TLS13 -> (3,4)
470460#endif
471− clientCert <- TLS.getClientCertificateChain ctx
472461 return TLS {
473462 tlsMajorVersion = major
474463 , tlsMinorVersion = minor
475464 , tlsNegotiatedProtocol = proto
476465 , tlsChiperID = TLS.cipherID infoCipher
477− , tlsClientCertificate = clientCert
478466 }
479467
480468tryIO :: IO a -> IO (Either IOException a)
@@ -482,10 +470,10 @@ tryIO = try
482470
483471----------------------------------------------------------------
484472
485−plainHTTP :: TLSSettings -> Settings -> Socket -> S.ByteString -> IO (Connection, Transport)
486−plainHTTP TLSSettings{..} set s bs0 = case onInsecure of
473+plainHTTP :: TLSSettings -> Socket -> S.ByteString -> IO (Connection, Transport)
474+plainHTTP TLSSettings{..} s bs0 = case onInsecure of
487475 AllowInsecure -> do
488− conn' <- socketConnection set s
476+ conn' <- socketConnection s
489477 cachedRef <- I.newIORef bs0
490478 let conn'' = conn'
491479 { connRecv = recvPlain cachedRef (connRecv conn')
warp-tls/warp-tls.cabal+5−5
@@ -1,5 +1,5 @@
11Name: warp-tls
2−Version: 3.2.11
2+Version: 3.2.7
33Synopsis: HTTP over TLS support for Warp via the TLS package
44License: MIT
55License-file: LICENSE
@@ -18,16 +18,16 @@ description: SSLv1 and SSLv2 are obsoleted by IETF.
1818extra-source-files: ChangeLog.md README.md
1919
2020Library
21− Build-Depends: base >= 4.10 && < 5
21+ Build-Depends: base >= 4.8 && < 5
2222 , bytestring >= 0.9
2323 , wai >= 3.2 && < 3.3
24− , warp >= 3.3.6 && < 3.4
24+ , warp >= 3.2.17 && < 3.4
2525 , data-default-class >= 0.0.1
26− , tls >= 1.5.3
26+ , tls >= 1.3.10
2727 , cryptonite >= 0.12
2828 , network >= 2.2.1
2929 , streaming-commons
30− , tls-session-manager >= 0.0.4
30+ , tls-session-manager >= 0.0.0.1
3131 Exposed-modules: Network.Wai.Handler.WarpTLS
3232 ghc-options: -Wall
3333 if os(windows)
warp/ChangeLog.md+1−50
@@ -1,56 +1,7 @@
1−## 3.3.9
2−
3−* Don't insert Last-Modified: if exists.
4− [#791](https://github.com/yesodweb/wai/pull/791)
5−
6−## 3.3.8
7−
8−* Maximum header size is configurable.
9− [#781](https://github.com/yesodweb/wai/pull/781)
10−* Ignoring an exception from shutdown (gracefulClose).
11−
12−## 3.3.7
13−
14−* InvalidArgument (Bad file descriptor) is ignored in `receive`.
15− [#787](https://github.com/yesodweb/wai/pull/787)
16−
17−## 3.3.6
18−
19−* Fixing a bug of thread killed in the case of event source with
20− HTTP/2 (fixing #692 and #785)
21−* New APIs: clientCertificate to get client's certificate
22− [#783](https://github.com/yesodweb/wai/pull/783)
23−
24−## 3.3.5
25−
26−* New APIs: setGracefulCloseTimeout1 and setGracefulCloseTimeout2.
27− For HTTP/1.x, connections are closed immediately by default.
28− gracefullClose is used for HTTP/2 by default.
29− [#782](https://github.com/yesodweb/wai/pull/782)
30−
31−## 3.3.4
32−
33−* Setting isSecure of HTTP/2 correctly.
34−
35−## 3.3.3
36−
37−* Calling setOnException in HTTP/2.
38− [#771](https://github.com/yesodweb/wai/pull/771)
39−
40−## 3.3.2
41−
42−* Fixing a bug of HTTP/2 without fd cache.
43−
44−## 3.3.1
45−
46−* Using gracefullClose of network 3.1.1 or later if available.
47−* If the first line of an HTTP request is really invalid,
48− don't send an error response
49−
501## 3.3.0
512
523* Switching from the original implementation to HTTP/2 server library.
53− [#754](https://github.com/yesodweb/wai/pull/754)
4+ [#752](https://github.com/yesodweb/wai/pull/752)
545* Breaking change: The type of `http2dataTrailers` is now
556 `HTTP2Data -> TrailersMaker`.
567
warp/Network/Wai/Handler/Warp.hs+1−51
@@ -72,9 +72,6 @@ module Network.Wai.Handler.Warp (
7272 , setLogger
7373 , setServerPushLogger
7474 , setGracefulShutdownTimeout
75− , setGracefulCloseTimeout1
76− , setGracefulCloseTimeout2
77− , setMaxTotalHeaderLength
7875 -- ** Getters
7976 , getPort
8077 , getHost
@@ -82,8 +79,6 @@ module Network.Wai.Handler.Warp (
8279 , getOnClose
8380 , getOnException
8481 , getGracefulShutdownTimeout
85− , getGracefulCloseTimeout1
86− , getGracefulCloseTimeout2
8782 -- ** Exception handler
8883 , defaultOnException
8984 , defaultShouldDisplayException
@@ -98,7 +93,6 @@ module Network.Wai.Handler.Warp (
9893 , pauseTimeout
9994 , FileInfo(..)
10095 , getFileInfo
101− , clientCertificate
10296 , withApplication
10397 , withApplicationSettings
10498 , testWithApplication
@@ -127,7 +121,6 @@ module Network.Wai.Handler.Warp (
127121import Control.Exception (SomeException, throwIO)
128122import Data.Streaming.Network (HostPreference)
129123import qualified Data.Vault.Lazy as Vault
130−import Data.X509
131124import qualified Network.HTTP.Types as H
132125import Network.Socket (SockAddr)
133126import Network.Wai (Request, Response, vault)
@@ -385,7 +378,7 @@ setProxyProtocolRequired y = y { settingsProxyProtocol = ProxyProtocolRequired }
385378--
386379-- WARNING: This is contrary to the PROXY protocol specification and
387380-- using it can indicate a security problem with your
388−-- architecture if the web server is directly accessible
381+-- architecture if the web server is directly accessable
389382-- to the public, since it would allow easy IP address
390383-- spoofing. However, it can be useful in some cases,
391384-- such as if a load balancer health check uses regular
@@ -437,13 +430,6 @@ setGracefulShutdownTimeout :: Maybe Int
437430 -> Settings -> Settings
438431setGracefulShutdownTimeout time y = y { settingsGracefulShutdownTimeout = time }
439432
440−-- | Set the maximum header size that Warp will tolerate when using HTTP/1.x.
441−--
442−-- Since 3.3.8
443−setMaxTotalHeaderLength :: Int -> Settings -> Settings
444−setMaxTotalHeaderLength maxTotalHeaderLength settings = settings
445− { settingsMaxTotalHeaderLength = maxTotalHeaderLength }
446−
447433-- | Explicitly pause the slowloris timeout.
448434--
449435-- This is useful for cases where you partially consume a request body. For
@@ -471,39 +457,3 @@ pauseTimeout = fromMaybe (return ()) . Vault.lookup pauseTimeoutKey . vault
471457-- Since 3.1.10
472458getFileInfo :: Request -> FilePath -> IO FileInfo
473459getFileInfo = fromMaybe (\_ -> throwIO (userError "getFileInfo")) . Vault.lookup getFileInfoKey . vault
474−
475−-- | A timeout to limit the time (in milliseconds) waiting for
476−-- FIN for HTTP/1.x. 0 means uses immediate close.
477−-- Default: 0.
478−--
479−-- Since 3.3.5
480−setGracefulCloseTimeout1 :: Int -> Settings -> Settings
481−setGracefulCloseTimeout1 x y = y { settingsGracefulCloseTimeout1 = x }
482−
483−-- | A timeout to limit the time (in milliseconds) waiting for
484−-- FIN for HTTP/1.x. 0 means uses immediate close.
485−--
486−-- Since 3.3.5
487−getGracefulCloseTimeout1 :: Settings -> Int
488−getGracefulCloseTimeout1 = settingsGracefulCloseTimeout1
489−
490−-- | A timeout to limit the time (in milliseconds) waiting for
491−-- FIN for HTTP/2. 0 means uses immediate close.
492−-- Default: 2000.
493−--
494−-- Since 3.3.5
495−setGracefulCloseTimeout2 :: Int -> Settings -> Settings
496−setGracefulCloseTimeout2 x y = y { settingsGracefulCloseTimeout2 = x }
497−
498−-- | A timeout to limit the time (in milliseconds) waiting for
499−-- FIN for HTTP/2. 0 means uses immediate close.
500−--
501−-- Since 3.3.5
502−getGracefulCloseTimeout2 :: Settings -> Int
503−getGracefulCloseTimeout2 = settingsGracefulCloseTimeout2
504−
505−-- | Getting information of client certificate.
506−--
507−-- Since 3.3.5
508−clientCertificate :: Request -> Maybe CertificateChain
509−clientCertificate = join . Vault.lookup getClientCertificateKey . vault
warp/Network/Wai/Handler/Warp/File.hs+4−7
@@ -34,15 +34,12 @@ data RspFileInfo = WithoutBody H.Status
3434----------------------------------------------------------------
3535
3636conditionalRequest :: I.FileInfo
37− -> H.ResponseHeaders
38− -> IndexedHeader -- ^ Response
39− -> IndexedHeader -- ^ Request
37+ -> H.ResponseHeaders -> IndexedHeader
4038 -> RspFileInfo
41−conditionalRequest finfo hs0 rspidx reqidx = case condition of
39+conditionalRequest finfo hs0 reqidx = case condition of
4240 nobody@(WithoutBody _) -> nobody
43− WithBody s _ off len -> let !hs1 = addContentHeaders hs0 off len size
44− !hasLM = isJust $ rspidx ! fromEnum ResLastModified
45− !hs = [ (H.hLastModified,date) | not hasLM ] ++ hs1
41+ WithBody s _ off len -> let !hs = (H.hLastModified,date) :
42+ addContentHeaders hs0 off len size
4643 in WithBody s hs off len
4744 where
4845 !mtime = I.fileInfoTime finfo
warp/Network/Wai/Handler/Warp/HTTP2.hs+16−25
@@ -6,7 +6,6 @@
66
77module Network.Wai.Handler.Warp.HTTP2 (http2) where
88
9−import qualified Data.IORef as I
109import qualified Control.Exception as E
1110import qualified Network.HTTP2.Server as H2
1211import Network.Socket (SockAddr)
@@ -24,46 +23,38 @@ import Network.Wai.Handler.Warp.Types
2423
2524----------------------------------------------------------------
2625
27−http2 :: Connection -> Transport -> InternalInfo -> SockAddr -> S.Settings -> (BufSize -> IO ByteString) -> (ByteString -> IO ()) -> Application -> IO ()
28−http2 conn transport ii addr settings readN send app =
26+http2 :: Connection -> InternalInfo -> SockAddr -> S.Settings -> (BufSize -> IO ByteString) -> Application -> IO ()
27+http2 conn ii addr settings readN app =
2928 H2.run conf http2server
3029 where
3130 conf = H2.Config {
3231 confWriteBuffer = connWriteBuffer conn
3332 , confBufferSize = connBufferSize conn
34− , confSendAll = send
33+ , confSendAll = connSendAll conn
3534 , confReadN = readN
3635 , confPositionReadMaker = pReadMaker ii
3736 }
3837
3938 http2server h2req aux response = do
4039 req <- toWAIRequest h2req aux
41− ref <- I.newIORef Nothing
42− eResponseReceived <- E.try $ app req $ \rsp -> do
40+ ResponseReceived <- app req $ \rsp -> do
4341 h2rsp <- fromResponse settings ii req rsp
4442 pps <- fromPushPromises ii req
45− I.writeIORef ref $ Just (h2rsp, pps)
46− _ <- response h2rsp pps
43+ ex <- E.try $ response h2rsp pps
44+ case ex of
45+ Right () -> do
46+ logResponse h2rsp req
47+ mapM_ (logPushPromise req) pps
48+ Left e@(E.SomeException _)
49+ -- killed by the local worker manager
50+ | Just E.ThreadKilled <- E.fromException e -> return ()
51+ -- killed by the local timeout manager
52+ | Just T.TimeoutThread <- E.fromException e -> return ()
53+ | otherwise -> S.settingsOnException settings (Just req) e
4754 return ResponseReceived
48− case eResponseReceived of
49− Right ResponseReceived -> do
50− Just (h2rsp, pps) <- I.readIORef ref
51− logResponse h2rsp req
52− mapM_ (logPushPromise req) pps
53− Left e@(E.SomeException _)
54− -- killed by the local worker manager
55− | Just E.ThreadKilled <- E.fromException e -> return ()
56− -- killed by the local timeout manager
57− | Just T.TimeoutThread <- E.fromException e -> return ()
58− | otherwise -> do
59− S.settingsOnException settings (Just req) e
60− let ersp = S.settingsOnExceptionResponse settings e
61− h2rsp' <- fromResponse settings ii req ersp
62− _ <- response h2rsp' []
63− logResponse h2rsp' req
6455 return ()
6556
66− toWAIRequest h2req aux = toRequest ii settings addr hdr bdylen bdy th transport
57+ toWAIRequest h2req aux = toRequest ii settings addr hdr bdylen bdy th
6758 where
6859 !hdr = H2.requestHeaders h2req
6960 !bdy = H2.getRequestBodyChunk h2req
warp/Network/Wai/Handler/Warp/HTTP2/File.hs+2−6
@@ -15,12 +15,8 @@ import Network.Wai.Handler.Warp.SendFile (positionRead)
1515
1616pReadMaker :: InternalInfo -> PositionReadMaker
1717pReadMaker ii path = do
18− (mfd, refresh) <- getFd ii path
19− case mfd of
20− Just fd -> return (pread fd, Refresher refresh)
21− Nothing -> do
22− fd <- openFile path
23− return (pread fd, Closer $ closeFile fd)
18+ (Just fd, refresh) <- getFd ii path
19+ return (pread fd, Refresher refresh)
2420 where
2521 pread :: Fd -> PositionRead
2622 pread fd off bytes buf = fromIntegral <$> positionRead fd buf bytes' off'
warp/Network/Wai/Handler/Warp/HTTP2/Request.hs+6−7
@@ -22,23 +22,23 @@ import qualified System.TimeManager as T
2222
2323import Network.Wai.Handler.Warp.HTTP2.Types
2424import Network.Wai.Handler.Warp.Imports
25−import Network.Wai.Handler.Warp.Request (getFileInfoKey, pauseTimeoutKey, getClientCertificateKey)
25+import Network.Wai.Handler.Warp.Request (getFileInfoKey, pauseTimeoutKey)
2626import qualified Network.Wai.Handler.Warp.Settings as S (Settings, settingsNoParsePath)
2727import Network.Wai.Handler.Warp.Types
2828
29−type ToReq = (TokenHeaderList,ValueTable) -> Maybe Int -> IO ByteString -> T.Handle -> Transport -> IO Request
29+type ToReq = (TokenHeaderList,ValueTable) -> Maybe Int -> IO ByteString -> T.Handle -> IO Request
3030
3131----------------------------------------------------------------
3232
3333toRequest :: InternalInfo -> S.Settings -> SockAddr -> ToReq
34−toRequest ii settings addr ht bodylen body th transport = do
34+toRequest ii settings addr ht bodylen body th = do
3535 ref <- newIORef Nothing
36− toRequest' ii settings addr ref ht bodylen body th transport
36+ toRequest' ii settings addr ref ht bodylen body th
3737
3838toRequest' :: InternalInfo -> S.Settings -> SockAddr
3939 -> IORef (Maybe HTTP2Data)
4040 -> ToReq
41−toRequest' ii settings addr ref (reqths,reqvt) bodylen body th transport = return req
41+toRequest' ii settings addr ref (reqths,reqvt) bodylen body th = return req
4242 where
4343 !req = Request {
4444 requestMethod = colonMethod
@@ -48,7 +48,7 @@ toRequest' ii settings addr ref (reqths,reqvt) bodylen body th transport = retur
4848 , rawQueryString = query
4949 , queryString = H.parseQuery query
5050 , requestHeaders = headers
51− , isSecure = isTransportSecure transport
51+ , isSecure = True
5252 , remoteHost = addr
5353 , requestBody = body
5454 , vault = vaultValue
@@ -83,7 +83,6 @@ toRequest' ii settings addr ref (reqths,reqvt) bodylen body th transport = retur
8383 $ Vault.insert setHTTP2DataKey (writeIORef ref)
8484 $ Vault.insert modifyHTTP2DataKey (modifyIORef' ref)
8585 $ Vault.insert pauseTimeoutKey (T.pause th)
86− $ Vault.insert getClientCertificateKey (tlsClientCertificate transport)
8786 Vault.empty
8887
8988getHTTP2DataKey :: Vault.Key (IO (Maybe HTTP2Data))
warp/Network/Wai/Handler/Warp/HTTP2/Response.hs+1−2
@@ -72,8 +72,7 @@ responseFile _ rsphdr isHead path Nothing ii reqhdr = do
7272 Left (_ex :: E.IOException) -> return $ response404 rsphdr
7373 Right finfo -> do
7474 let reqidx = indexRequestHeader reqhdr
75− rspidx = indexResponseHeader rsphdr
76− case conditionalRequest finfo rsphdr rspidx reqidx of
75+ case conditionalRequest finfo rsphdr reqidx of
7776 WithoutBody s -> return $ responseNoBody s rsphdr
7877 WithBody s rsphdr' off bytes -> do
7978 let !off' = fromIntegral off
warp/Network/Wai/Handler/Warp/Header.hs−2
@@ -69,7 +69,6 @@ indexResponseHeader hdr = traverseHeader hdr responseMaxIndex responseKeyIndex
6969data ResponseHeaderIndex = ResContentLength
7070 | ResServer
7171 | ResDate
72− | ResLastModified
7372 deriving (Enum,Bounded)
7473
7574-- | The size for 'IndexedHeader' for HTTP Response.
@@ -80,7 +79,6 @@ responseKeyIndex :: HeaderName -> Int
8079responseKeyIndex hn = case BS.length bs of
8180 4 -> if bs == "date" then fromEnum ResDate else -1
8281 6 -> if bs == "server" then fromEnum ResServer else -1
83− 13 -> if bs == "last-modified" then fromEnum ResLastModified else -1
8482 14 -> if bs == "content-length" then fromEnum ResContentLength else -1
8583 _ -> -1
8684 where
warp/Network/Wai/Handler/Warp/Recv.hs+4−25
@@ -17,14 +17,7 @@ import Foreign.C.Types
1717import Foreign.ForeignPtr (withForeignPtr)
1818import Foreign.Ptr (Ptr, castPtr, plusPtr)
1919import GHC.Conc (threadWaitRead)
20−import qualified GHC.IO.Exception as E
21−import Network.Socket (Socket)
22−import qualified System.IO.Error as E
23−#if MIN_VERSION_network(3,1,0)
24−import Network.Socket (withFdSocket)
25−#else
26−import Network.Socket (fdSocket)
27−#endif
20+import Network.Socket (Socket, fdSocket)
2821import System.Posix.Types (Fd(..))
2922
3023import Network.Wai.Handler.Warp.Buffer
@@ -96,31 +89,19 @@ spell init0 siz0 recv recvBuf
9689 siz' = siz - len
9790 loop bss' siz'
9891
99−-- The timeout manager may close the socket.
100−-- In that case, an error of "Bad file descriptor" occurs.
101−-- We ignores it because we expect TimeoutThread.
10292receive :: Socket -> BufferPool -> Recv
103−receive sock pool = E.handle handler $ withBufferPool pool $ \ (ptr, size) -> do
104−#if MIN_VERSION_network(3,1,0)
105− withFdSocket sock $ \fd -> do
106−#elif MIN_VERSION_network(3,0,0)
93+receive sock pool = withBufferPool pool $ \ (ptr, size) -> do
94+#if MIN_VERSION_network(3,0,0)
10795 fd <- fdSocket sock
10896#else
10997 let fd = fdSocket sock
11098#endif
11199 let size' = fromIntegral size
112100 fromIntegral <$> receiveloop fd ptr size'
113− where
114− handler :: E.IOException -> IO ByteString
115− handler e
116− | E.ioeGetErrorType e == E.InvalidArgument = return ""
117− | otherwise = E.throwIO e
118101
119102receiveBuf :: Socket -> RecvBuf
120103receiveBuf sock buf0 siz0 = do
121−#if MIN_VERSION_network(3,1,0)
122− withFdSocket sock $ \fd -> do
123−#elif MIN_VERSION_network(3,0,0)
104+#if MIN_VERSION_network(3,0,0)
124105 fd <- fdSocket sock
125106#else
126107 let fd = fdSocket sock
@@ -153,8 +134,6 @@ receiveloop sock ptr size = do
153134 else
154135 return bytes
155136
156−#ifndef mingw32_HOST_OS
157137-- fixme: the type of the return value
158138foreign import ccall unsafe "recv"
159139 c_recv :: CInt -> Ptr CChar -> CSize -> CInt -> IO CInt
160−#endif
warp/Network/Wai/Handler/Warp/Request.hs+19−21
@@ -9,7 +9,6 @@ module Network.Wai.Handler.Warp.Request (
99 , headerLines
1010 , pauseTimeoutKey
1111 , getFileInfoKey
12− , getClientCertificateKey
1312 , NoKeepAliveRequest (..)
1413 ) where
1514
@@ -22,7 +21,6 @@ import qualified Data.CaseInsensitive as CI
2221import qualified Data.IORef as I
2322import Data.Typeable (Typeable)
2423import qualified Data.Vault.Lazy as Vault
25−import Data.X509
2624import qualified Network.HTTP.Types as H
2725import Network.Socket (SockAddr)
2826import Network.Wai
@@ -38,7 +36,13 @@ import Network.Wai.Handler.Warp.Header
3836import Network.Wai.Handler.Warp.Imports hiding (readInt, lines)
3937import Network.Wai.Handler.Warp.ReadInt
4038import Network.Wai.Handler.Warp.RequestHeader
41−import Network.Wai.Handler.Warp.Settings (Settings, settingsNoParsePath, settingsMaxTotalHeaderLength)
39+import Network.Wai.Handler.Warp.Settings (Settings, settingsNoParsePath)
40+
41+----------------------------------------------------------------
42+
43+-- FIXME come up with good values here
44+maxTotalHeaderLength :: Int
45+maxTotalHeaderLength = 50 * 1024
4246
4347----------------------------------------------------------------
4448
@@ -51,7 +55,6 @@ recvRequest :: Bool -- ^ first request on this connection?
5155 -> Timeout.Handle
5256 -> SockAddr -- ^ Peer's address.
5357 -> Source -- ^ Where HTTP request comes from.
54− -> Transport
5558 -> IO (Request
5659 ,Maybe (I.IORef Int)
5760 ,IndexedHeader
@@ -61,8 +64,8 @@ recvRequest :: Bool -- ^ first request on this connection?
6164 -- 'IndexedHeader' of HTTP request for internal use,
6265 -- Body producing action used for flushing the request body
6366
64−recvRequest firstRequest settings conn ii th addr src transport = do
65− hdrlines <- headerLines (settingsMaxTotalHeaderLength settings) firstRequest src
67+recvRequest firstRequest settings conn ii th addr src = do
68+ hdrlines <- headerLines firstRequest src
6669 (method, unparsedPath, path, query, httpversion, hdr) <- parseHeaderLines hdrlines
6770 let idxhdr = indexRequestHeader hdr
6871 expect = idxhdr ! fromEnum ReqExpect
@@ -72,7 +75,6 @@ recvRequest firstRequest settings conn ii th addr src transport = do
7275 rawPath = if settingsNoParsePath settings then unparsedPath else path
7376 vaultValue = Vault.insert pauseTimeoutKey (Timeout.pause th)
7477 $ Vault.insert getFileInfoKey (getFileInfo ii)
75− $ Vault.insert getClientCertificateKey (tlsClientCertificate transport)
7678 Vault.empty
7779 (rbody, remainingRef, bodyLength) <- bodyAndSource src cl te
7880 -- body producing function which will produce '100-continue', if needed
@@ -87,7 +89,7 @@ recvRequest firstRequest settings conn ii th addr src transport = do
8789 , rawQueryString = query
8890 , queryString = H.parseQuery query
8991 , requestHeaders = hdr
90− , isSecure = isTransportSecure transport
92+ , isSecure = False
9193 , remoteHost = addr
9294 , requestBody = rbody'
9395 , vault = vaultValue
@@ -101,8 +103,8 @@ recvRequest firstRequest settings conn ii th addr src transport = do
101103
102104----------------------------------------------------------------
103105
104−headerLines :: Int -> Bool -> Source -> IO [ByteString]
105−headerLines maxTotalHeaderLength firstRequest src = do
106+headerLines :: Bool -> Source -> IO [ByteString]
107+headerLines firstRequest src = do
106108 bs <- readSource src
107109 if S.null bs
108110 -- When we're working on a keep-alive connection and trying to
@@ -110,7 +112,7 @@ headerLines maxTotalHeaderLength firstRequest src = do
110112 -- lack of data as a real exception. See the http1 function in
111113 -- the Run module for more details.
112114 then if firstRequest then throwIO ConnectionClosedByPeer else throwIO NoKeepAliveRequest
113− else push maxTotalHeaderLength src (THStatus 0 id id) bs
115+ else push src (THStatus 0 id id) bs
114116
115117data NoKeepAliveRequest = NoKeepAliveRequest
116118 deriving (Show, Typeable)
@@ -220,8 +222,8 @@ close :: Sink ByteString IO a
220222close = throwIO IncompleteHeaders
221223-}
222224
223−push :: Int -> Source -> THStatus -> ByteString -> IO [ByteString]
224−push maxTotalHeaderLength src (THStatus len lines prepend) bs'
225+push :: Source -> THStatus -> ByteString -> IO [ByteString]
226+push src (THStatus len lines prepend) bs'
225227 -- Too many bytes
226228 | len > maxTotalHeaderLength = throwIO OverLargeHeader
227229 | otherwise = push' mnl
@@ -249,13 +251,13 @@ push maxTotalHeaderLength src (THStatus len lines prepend) bs'
249251 push' Nothing = do
250252 bst <- readSource' src
251253 when (S.null bst) $ throwIO IncompleteHeaders
252− push maxTotalHeaderLength src status bst
254+ push src status bst
253255 where
254256 len' = len + bsLen
255257 prepend' = S.append bs
256258 status = THStatus len' lines prepend'
257259 -- Found a newline, but next line continues as a multiline header
258− push' (Just (end, True)) = push maxTotalHeaderLength src status rest
260+ push' (Just (end, True)) = push src status rest
259261 where
260262 rest = S.drop (end + 1) bs
261263 prepend' = S.append (SU.unsafeTake (checkCR bs end) bs)
@@ -274,12 +276,12 @@ push maxTotalHeaderLength src (THStatus len lines prepend) bs'
274276 in if start < bsLen then
275277 -- more bytes in this chunk, push again
276278 let bs'' = SU.unsafeDrop start bs
277− in push maxTotalHeaderLength src status bs''
279+ in push src status bs''
278280 else do
279281 -- no more bytes in this chunk, ask for more
280282 bst <- readSource' src
281283 when (S.null bs) $ throwIO IncompleteHeaders
282− push maxTotalHeaderLength src status bst
284+ push src status bst
283285 where
284286 start = end + 1 -- start of next chunk
285287 line = SU.unsafeTake (checkCR bs end) bs
@@ -297,7 +299,3 @@ pauseTimeoutKey = unsafePerformIO Vault.newKey
297299getFileInfoKey :: Vault.Key (FilePath -> IO FileInfo)
298300getFileInfoKey = unsafePerformIO Vault.newKey
299301{-# NOINLINE getFileInfoKey #-}
300−
301−getClientCertificateKey :: Vault.Key (Maybe CertificateChain)
302−getClientCertificateKey = unsafePerformIO Vault.newKey
303−{-# NOINLINE getClientCertificateKey #-}
warp/Network/Wai/Handler/Warp/Response.hs+16−19
@@ -116,14 +116,14 @@ sendResponse settings conn ii th req reqidxhdr src response = do
116116 -- and status, the response to HEAD is processed here.
117117 --
118118 -- See definition of rsp below for proper body stripping.
119− (ms, mlen) <- sendRsp conn ii ver s hs rspidxhdr rsp
119+ (ms, mlen) <- sendRsp conn ii ver s hs rsp
120120 case ms of
121121 Nothing -> return ()
122122 Just realStatus -> logger req realStatus mlen
123123 T.tickle th
124124 return ret
125125 else do
126− _ <- sendRsp conn ii ver s hs rspidxhdr RspNoBody
126+ _ <- sendRsp conn ii ver s hs RspNoBody
127127 logger req s Nothing
128128 T.tickle th
129129 return isPersist
@@ -196,13 +196,12 @@ sendRsp :: Connection
196196 -> H.HttpVersion
197197 -> H.Status
198198 -> H.ResponseHeaders
199− -> IndexedHeader -- Response
200199 -> Rsp
201200 -> IO (Maybe H.Status, Maybe Integer)
202201
203202----------------------------------------------------------------
204203
205−sendRsp conn _ ver s hs _ RspNoBody = do
204+sendRsp conn _ ver s hs RspNoBody = do
206205 -- Not adding Content-Length.
207206 -- User agents treats it as Content-Length: 0.
208207 composeHeader ver s hs >>= connSendAll conn
@@ -210,7 +209,7 @@ sendRsp conn _ ver s hs _ RspNoBody = do
210209
211210----------------------------------------------------------------
212211
213−sendRsp conn _ ver s hs _ (RspBuilder body needsChunked) = do
212+sendRsp conn _ ver s hs (RspBuilder body needsChunked) = do
214213 header <- composeHeaderBuilder ver s hs needsChunked
215214 let hdrBdy
216215 | needsChunked = header <> chunkedTransferEncoding body
@@ -223,7 +222,7 @@ sendRsp conn _ ver s hs _ (RspBuilder body needsChunked) = do
223222
224223----------------------------------------------------------------
225224
226−sendRsp conn _ ver s hs _ (RspStream streamingBody needsChunked th) = do
225+sendRsp conn _ ver s hs (RspStream streamingBody needsChunked th) = do
227226 header <- composeHeaderBuilder ver s hs needsChunked
228227 (recv, finish) <- newByteStringBuilderRecv $ reuseBufferStrategy
229228 $ toBuilderBuffer (connWriteBuffer conn) (connBufferSize conn)
@@ -247,7 +246,7 @@ sendRsp conn _ ver s hs _ (RspStream streamingBody needsChunked th) = do
247246
248247----------------------------------------------------------------
249248
250−sendRsp conn _ _ _ _ _ (RspRaw withApp src tickle) = do
249+sendRsp conn _ _ _ _ (RspRaw withApp src tickle) = do
251250 withApp recv send
252251 return (Nothing, Nothing)
253252 where
@@ -261,8 +260,8 @@ sendRsp conn _ _ _ _ _ (RspRaw withApp src tickle) = do
261260
262261-- Sophisticated WAI applications.
263262-- We respect s0. s0 MUST be a proper value.
264−sendRsp conn ii ver s0 hs0 rspidxhdr (RspFile path (Just part) _ isHead hook) =
265− sendRspFile2XX conn ii ver s0 hs rspidxhdr path beg len isHead hook
263+sendRsp conn ii ver s0 hs0 (RspFile path (Just part) _ isHead hook) =
264+ sendRspFile2XX conn ii ver s0 hs path beg len isHead hook
266265 where
267266 beg = filePartOffset part
268267 len = filePartByteCount part
@@ -272,17 +271,17 @@ sendRsp conn ii ver s0 hs0 rspidxhdr (RspFile path (Just part) _ isHead hook) =
272271
273272-- Simple WAI applications.
274273-- Status is ignored
275−sendRsp conn ii ver _ hs0 rspidxhdr (RspFile path Nothing reqidxhdr isHead hook) = do
274+sendRsp conn ii ver _ hs0 (RspFile path Nothing idxhdr isHead hook) = do
276275 efinfo <- E.try $ getFileInfo ii path
277276 case efinfo of
278277 Left (_ex :: E.IOException) ->
279278#ifdef WARP_DEBUG
280279 print _ex >>
281280#endif
282− sendRspFile404 conn ii ver hs0 rspidxhdr
283− Right finfo -> case conditionalRequest finfo hs0 rspidxhdr reqidxhdr of
284− WithoutBody s -> sendRsp conn ii ver s hs0 rspidxhdr RspNoBody
285− WithBody s hs beg len -> sendRspFile2XX conn ii ver s hs rspidxhdr path beg len isHead hook
281+ sendRspFile404 conn ii ver hs0
282+ Right finfo -> case conditionalRequest finfo hs0 idxhdr of
283+ WithoutBody s -> sendRsp conn ii ver s hs0 RspNoBody
284+ WithBody s hs beg len -> sendRspFile2XX conn ii ver s hs path beg len isHead hook
286285
287286----------------------------------------------------------------
288287
@@ -291,15 +290,14 @@ sendRspFile2XX :: Connection
291290 -> H.HttpVersion
292291 -> H.Status
293292 -> H.ResponseHeaders
294− -> IndexedHeader
295293 -> FilePath
296294 -> Integer
297295 -> Integer
298296 -> Bool
299297 -> IO ()
300298 -> IO (Maybe H.Status, Maybe Integer)
301−sendRspFile2XX conn ii ver s hs rspidxhdr path beg len isHead hook
302− | isHead = sendRsp conn ii ver s hs rspidxhdr RspNoBody
299+sendRspFile2XX conn ii ver s hs path beg len isHead hook
300+ | isHead = sendRsp conn ii ver s hs RspNoBody
303301 | otherwise = do
304302 lheader <- composeHeader ver s hs
305303 (mfd, fresher) <- getFd ii path
@@ -312,9 +310,8 @@ sendRspFile404 :: Connection
312310 -> InternalInfo
313311 -> H.HttpVersion
314312 -> H.ResponseHeaders
315− -> IndexedHeader
316313 -> IO (Maybe H.Status, Maybe Integer)
317−sendRspFile404 conn ii ver hs0 rspidxhdr = sendRsp conn ii ver s hs rspidxhdr (RspBuilder body True)
314+sendRspFile404 conn ii ver hs0 = sendRsp conn ii ver s hs (RspBuilder body True)
318315 where
319316 s = H.notFound404
320317 hs = replaceHeader H.hContentType "text/plain; charset=utf-8" hs0
warp/Network/Wai/Handler/Warp/Run.hs+25−41
@@ -17,15 +17,12 @@ import qualified Control.Concurrent as Conc (yield)
1717import Control.Exception as E
1818import qualified Data.ByteString as S
1919import Data.Char (chr)
20−import Data.IORef (IORef, newIORef, readIORef, writeIORef)
20+import Data.IORef (IORef, newIORef, readIORef, writeIORef, atomicModifyIORef')
2121import Data.Streaming.Network (bindPortTCP)
2222import Foreign.C.Error (Errno(..), eCONNABORTED)
2323import GHC.IO.Exception (IOException(..))
2424import qualified Network.HTTP2 as H2
2525import Network.Socket (Socket, close, accept, withSocketsDo, SockAddr(SockAddrInet, SockAddrInet6), setSocketOption, SocketOption(..))
26−#if MIN_VERSION_network(3,1,1)
27−import Network.Socket (gracefulClose)
28−#endif
2926import qualified Network.Socket.ByteString as Sock
3027import Network.Wai
3128import Network.Wai.Internal (ResponseReceived (ResponseReceived))
@@ -58,38 +55,21 @@ import Network.Socket (fdSocket)
5855#endif
5956
6057-- | Creating 'Connection' for plain HTTP based on a given socket.
61−socketConnection :: Settings -> Socket -> IO Connection
62−#if MIN_VERSION_network(3,1,1)
63−socketConnection set s = do
64−#else
65−socketConnection _ s = do
66−#endif
58+socketConnection :: Socket -> IO Connection
59+socketConnection s = do
6760 bufferPool <- newBufferPool
6861 writeBuf <- allocateBuffer bufferSize
6962 let sendall = Sock.sendAll s
70− isH2 <- newIORef False -- HTTP/1.x
7163 return Connection {
7264 connSendMany = Sock.sendMany s
7365 , connSendAll = sendall
7466 , connSendFile = sendFile s writeBuf bufferSize sendall
75−#if MIN_VERSION_network(3,1,1)
76− , connClose = do
77− h2 <- readIORef isH2
78− let tm = if h2 then settingsGracefulCloseTimeout2 set
79− else settingsGracefulCloseTimeout1 set
80− if tm == 0 then
81− close s
82− else
83− gracefulClose s tm `E.catch` \(E.SomeException _) -> return ()
84−#else
8567 , connClose = close s
86−#endif
8768 , connFree = freeBuffer writeBuf
8869 , connRecv = receive s bufferPool
8970 , connRecvBuf = receiveBuf s
9071 , connWriteBuffer = writeBuf
9172 , connBufferSize = bufferSize
92− , connHTTP2 = isH2
9373 }
9474
9575-- | Run an 'Application' on the given port.
@@ -151,7 +131,7 @@ runSettingsSocket set socket app = do
151131 setSocketCloseOnExec s
152132 -- NoDelay causes an error for AF_UNIX.
153133 setSocketOption s NoDelay 1 `E.catch` \(E.SomeException _) -> return ()
154− conn <- socketConnection set s
134+ conn <- socketConnection s
155135 return (conn, sa)
156136
157137 closeListenSocket = close socket
@@ -286,7 +266,10 @@ fork :: Settings
286266fork set mkConn addr app counter ii = settingsFork set $ \unmask ->
287267 -- Call the user-supplied on exception code if any
288268 -- exceptions are thrown.
289− handle (settingsOnException set Nothing) $
269+ handle (settingsOnException set Nothing) .
270+ -- Allocate a new IORef indicating whether the connection has been
271+ -- closed, to avoid double-freeing a connection
272+ withClosedRef $ \ref ->
290273 -- Run the connection maker to get a new connection, and ensure
291274 -- that the connection is closed. If the mkConn call throws an
292275 -- exception, we will leak the connection. If the mkConn call is
@@ -297,13 +280,21 @@ fork set mkConn addr app counter ii = settingsFork set $ \unmask ->
297280 -- We grab the connection before registering timeouts since the
298281 -- timeouts will be useless during connection creation, due to the
299282 -- fact that async exceptions are still masked.
300− bracket mkConn cleanUp (serve unmask)
283+ bracket mkConn (cleanUp ref) (serve unmask ref)
301284 where
302− cleanUp (conn, _) = connClose conn `finally` connFree conn
285+ withClosedRef inner = newIORef False >>= inner
286+
287+ closeConn ref conn = do
288+ isClosed <- atomicModifyIORef' ref $ \x -> (True, x)
289+ unless isClosed $ connClose conn
290+
291+ cleanUp ref (conn, _) = closeConn ref conn `finally` connFree conn
303292
304293 -- We need to register a timeout handler for this thread, and
305− -- cancel that handler as soon as we exit.
306− serve unmask (conn, transport) = bracket register cancel $ \th -> do
294+ -- cancel that handler as soon as we exit. We additionally close
295+ -- the connection immediately in case the child thread catches the
296+ -- async exception or performs some long-running cleanup action.
297+ serve unmask ref (conn, transport) = bracket register cancel $ \th -> do
307298 -- We now have fully registered a connection close handler in
308299 -- the case of all exceptions, so it is safe to once again
309300 -- allow async exceptions.
@@ -315,7 +306,8 @@ fork set mkConn addr app counter ii = settingsFork set $ \unmask ->
315306 -- above ensures the connection is closed.
316307 when goingon $ serveConnection conn ii th addr transport set app
317308 where
318− register = T.registerKillThread (timeoutManager ii) (connClose conn)
309+ register = T.registerKillThread (timeoutManager ii)
310+ (closeConn ref conn)
319311 cancel = T.cancel
320312
321313 onOpen adr = increase counter >> settingsOnOpen set adr
@@ -342,19 +334,10 @@ serveConnection conn ii th origAddr transport settings app = do
342334 istatus <- newIORef False
343335 if settingsHTTP2Enabled settings && h2 then do
344336 rawRecvN <- makeReceiveN bs (connRecv conn) (connRecvBuf conn)
345− -- This thread becomes the sender in http2 library.
346− -- In the case of event source, one request comes and one
347− -- worker gets busy. But it is likely that the receiver does
348− -- not receive any data at all while the sender is sending
349− -- output data from the worker. It's not good enough to tickle
350− -- the time handler in the receiver only. So, we should tickle
351− -- the time handler in both the receiver and the sender.
352337 let recvN = wrappedRecvN th istatus (settingsSlowlorisSize settings) rawRecvN
353− sendBS x = connSendAll conn x >> T.tickle th
354338 -- fixme: origAddr
355339 checkTLS
356− setConnHTTP2 conn True
357− http2 conn transport ii origAddr settings recvN sendBS app
340+ http2 conn ii origAddr settings recvN app
358341 else do
359342 src <- mkSource (wrappedRecv conn th istatus (settingsSlowlorisSize settings))
360343 writeIORef istatus True
@@ -429,7 +412,8 @@ serveConnection conn ii th origAddr transport settings app = do
429412 errorResponse e = settingsOnExceptionResponse settings e
430413
431414 http1 firstRequest addr istatus src = do
432− (req, mremainingRef, idxhdr, nextBodyFlush) <- recvRequest firstRequest settings conn ii th addr src transport
415+ (req', mremainingRef, idxhdr, nextBodyFlush) <- recvRequest firstRequest settings conn ii th addr src
416+ let req = req' { isSecure = isTransportSecure transport }
433417 keepAlive <- processRequest istatus src req mremainingRef idxhdr nextBodyFlush
434418 `E.catch` \e -> do
435419 settingsOnException settings (Just req) e
warp/Network/Wai/Handler/Warp/Settings.hs+5−31
@@ -76,13 +76,6 @@ data Settings = Settings
7676 --
7777 -- Since 2.0.3
7878 , settingsInstallShutdownHandler :: IO () -> IO ()
79− -- ^ An action to install a handler (e.g. Unix signal handler)
80− -- to close a listen socket.
81− -- The first argument is an action to close the listen socket.
82− --
83− -- Default: no action
84− --
85− -- Since 3.0.1
8679 , settingsServerName :: ByteString
8780 -- ^ Default server name if application does not set one.
8881 --
@@ -94,44 +87,28 @@ data Settings = Settings
9487 , settingsProxyProtocol :: ProxyProtocol
9588 -- ^ Specify usage of the PROXY protocol.
9689 --
97− -- Since 3.0.5
90+ -- Since 3.0.5.
9891 , settingsSlowlorisSize :: Int
9992 -- ^ Size of bytes read to prevent Slowloris protection. Default value: 2048
10093 --
101− -- Since 3.1.2
94+ -- Since 3.1.2.
10295 , settingsHTTP2Enabled :: Bool
10396 -- ^ Whether to enable HTTP2 ALPN/upgrades. Default: True
10497 --
105− -- Since 3.1.7
98+ -- Since 3.1.7.
10699 , settingsLogger :: Request -> H.Status -> Maybe Integer -> IO ()
107100 -- ^ A log function. Default: no action.
108101 --
109− -- Since 3.1.10
102+ -- Since 3.X.X.
110103 , settingsServerPushLogger :: Request -> ByteString -> Integer -> IO ()
111104 -- ^ A HTTP/2 server push log function. Default: no action.
112105 --
113− -- Since 3.2.7
106+ -- Since 3.X.X.
114107 , settingsGracefulShutdownTimeout :: Maybe Int
115108 -- ^ An optional timeout to limit the time (in seconds) waiting for
116109 -- a graceful shutdown of the web server.
117110 --
118111 -- Since 3.2.8
119− , settingsGracefulCloseTimeout1 :: Int
120− -- ^ A timeout to limit the time (in milliseconds) waiting for
121− -- FIN for HTTP/1.x. 0 means uses immediate close.
122− -- Default: 0.
123− --
124− -- Since 3.3.5
125− , settingsGracefulCloseTimeout2 :: Int
126− -- ^ A timeout to limit the time (in milliseconds) waiting for
127− -- FIN for HTTP/2. 0 means uses immediate close.
128− -- Default: 2000.
129− --
130− -- Since 3.3.5
131− , settingsMaxTotalHeaderLength :: Int
132− -- ^ Determines the maximum header size that Warp will tolerate when using HTTP/1.x.
133− --
134− -- Since 3.3.8
135112 }
136113
137114-- | Specify usage of the PROXY protocol.
@@ -168,9 +145,6 @@ defaultSettings = Settings
168145 , settingsLogger = \_ _ _ -> return ()
169146 , settingsServerPushLogger = \_ _ _ -> return ()
170147 , settingsGracefulShutdownTimeout = Nothing
171− , settingsGracefulCloseTimeout1 = 0
172− , settingsGracefulCloseTimeout2 = 2000
173− , settingsMaxTotalHeaderLength = 50 * 1024
174148 }
175149
176150-- | Apply the logic provided by 'defaultOnException' to determine if an
warp/Network/Wai/Handler/Warp/Types.hs−10
@@ -8,7 +8,6 @@ import Control.Exception
88import qualified Data.ByteString as S
99import Data.IORef (IORef, readIORef, writeIORef, newIORef)
1010import Data.Typeable (Typeable)
11−import Data.X509
1211import Foreign.Ptr (Ptr)
1312import System.Posix.Types (Fd)
1413import qualified System.TimeManager as T
@@ -123,16 +122,8 @@ data Connection = Connection {
123122 , connWriteBuffer :: Buffer
124123 -- | The size of the write buffer.
125124 , connBufferSize :: BufSize
126− -- | Is this connection HTTP/2?
127− , connHTTP2 :: IORef Bool
128125 }
129126
130−getConnHTTP2 :: Connection -> IO Bool
131−getConnHTTP2 conn = readIORef (connHTTP2 conn)
132−
133−setConnHTTP2 :: Connection -> Bool -> IO ()
134−setConnHTTP2 conn b = writeIORef (connHTTP2 conn) b
135−
136127----------------------------------------------------------------
137128
138129data InternalInfo = InternalInfo {
@@ -180,7 +171,6 @@ data Transport = TCP -- ^ Plain channel: TCP
180171 , tlsMinorVersion :: Int
181172 , tlsNegotiatedProtocol :: Maybe ByteString -- ^ The result of Application Layer Protocol Negociation in RFC 7301
182173 , tlsChiperID :: Word16
183− , tlsClientCertificate :: Maybe CertificateChain
184174 } -- ^ Encrypted channel: TLS or SSL
185175
186176isTransportSecure :: Transport -> Bool
warp/test/FileSpec.hs+1−1
@@ -21,7 +21,7 @@ testFileRange desc reqhs file ans = it desc $ do
2121 let WithBody s hs off len = ans
2222 hs' = ("Last-Modified",fileInfoDate finfo) : hs
2323 ans' = WithBody s hs' off len
24− conditionalRequest finfo [] (indexResponseHeader hs) (indexRequestHeader reqhs) `shouldBe` ans'
24+ conditionalRequest finfo [] (indexRequestHeader reqhs) `shouldBe` ans'
2525
2626spec :: Spec
2727spec = do
warp/test/RequestSpec.hs+7−11
@@ -7,7 +7,6 @@ module RequestSpec (main, spec) where
77import Network.Wai.Handler.Warp.File (parseByteRanges)
88import Network.Wai.Handler.Warp.Request
99import Network.Wai.Handler.Warp.Types
10−import Network.Wai.Handler.Warp.Settings (settingsMaxTotalHeaderLength, defaultSettings)
1110import Test.Hspec
1211import Test.Hspec.QuickCheck
1312import qualified Data.ByteString as S
@@ -18,9 +17,6 @@ import Data.IORef
1817main :: IO ()
1918main = hspec spec
2019
21−defaultMaxTotalHeaderLength :: Int
22−defaultMaxTotalHeaderLength = settingsMaxTotalHeaderLength defaultSettings
23−
2420spec :: Spec
2521spec = do
2622 describe "headerLines" $ do
@@ -67,29 +63,29 @@ spec = do
6763 describe "headerLines" $ do
6864 it "can handle a nomarl case" $ do
6965 src <- mkSourceFunc ["Status: 200\r\nContent-Type: text/plain\r\n\r\n"] >>= mkSource
70− x <- headerLines defaultMaxTotalHeaderLength True src
66+ x <- headerLines True src
7167 x `shouldBe` ["Status: 200", "Content-Type: text/plain"]
7268
7369 it "can handle a nasty case (1)" $ do
7470 src <- mkSourceFunc ["Status: 200", "\r\nContent-Type: text/plain", "\r\n\r\n"] >>= mkSource
75− x <- headerLines defaultMaxTotalHeaderLength True src
71+ x <- headerLines True src
7672 x `shouldBe` ["Status: 200", "Content-Type: text/plain"]
7773
7874 it "can handle a nasty case (1)" $ do
7975 src <- mkSourceFunc ["Status: 200", "\r", "\nContent-Type: text/plain", "\r", "\n\r\n"] >>= mkSource
80− x <- headerLines defaultMaxTotalHeaderLength True src
76+ x <- headerLines True src
8177 x `shouldBe` ["Status: 200", "Content-Type: text/plain"]
8278
8379 it "can handle a nasty case (1)" $ do
8480 src <- mkSourceFunc ["Status: 200", "\r", "\n", "Content-Type: text/plain", "\r", "\n", "\r", "\n"] >>= mkSource
85− x <- headerLines defaultMaxTotalHeaderLength True src
81+ x <- headerLines True src
8682 x `shouldBe` ["Status: 200", "Content-Type: text/plain"]
8783
8884 it "can handle an illegal case (1)" $ do
8985 src <- mkSourceFunc ["\nStatus:", "\n 200", "\nContent-Type: text/plain", "\r\n\r\n"] >>= mkSource
90− x <- headerLines defaultMaxTotalHeaderLength True src
86+ x <- headerLines True src
9187 x `shouldBe` []
92− y <- headerLines defaultMaxTotalHeaderLength True src
88+ y <- headerLines True src
9389 y `shouldBe` ["Status: 200", "Content-Type: text/plain"]
9490
9591 where
@@ -115,7 +111,7 @@ headerLinesList' orig = do
115111 writeIORef ref z
116112 return y
117113 src' <- mkSource src
118− res <- headerLines defaultMaxTotalHeaderLength True src'
114+ res <- headerLines True src'
119115 return (res, src')
120116
121117consumeLen :: Int -> Source -> IO S8.ByteString
warp/test/ResponseSpec.hs+1−1
@@ -83,7 +83,7 @@ spec = do
8383 it "discards empty lines" $ do
8484 sanitizeHeaderValue "foo\r\n\r\nbar" `shouldBe` "foo\r\n bar"
8585
86− context "when sanitizing single occurrences of \n" $ do
86+ context "when sanitizing single occurences of \n" $ do
8787 it "replaces \n with \r\n" $ do
8888 sanitizeHeaderValue "foo\n bar" `shouldBe` "foo\r\n bar"
8989
warp/warp.cabal+1−4
@@ -1,5 +1,5 @@
11Name: warp
2−Version: 3.3.9
2+Version: 3.3.0
33Synopsis: A fast, light-weight web server for WAI applications.
44License: MIT
55License-file: LICENSE
@@ -56,7 +56,6 @@ Library
5656 , vault >= 0.3
5757 , wai >= 3.2 && < 3.3
5858 , word8
59− , x509
6059 if impl(ghc < 8)
6160 Build-Depends: semigroups
6261 if flag(network-bytestring)
@@ -212,7 +211,6 @@ Test-Suite spec
212211 , vault
213212 , wai >= 3.2 && < 3.3
214213 , word8
215− , x509
216214 -- Build-Tool-Depends: hspec-discover:hspec-discover
217215 if impl(ghc < 8)
218216 Build-Depends: semigroups
@@ -251,7 +249,6 @@ Benchmark parser
251249 , network
252250 , time-manager
253251 , unix-compat
254− , x509
255252 if impl(ghc < 8)
256253 Build-Depends: semigroups
257254