packages feed

kawaii (empty) → 0.0.1.0

raw patch · 11 files changed

+813/−0 lines, 11 filesdep +QuickCheckdep +basedep +bytestringsetup-changed

Dependencies added: QuickCheck, base, bytestring, containers, data-default, hakyll, hakyll-serve, hspec, lens, lifted-base, monad-control, monad-logger, mtl, optparse-applicative, safe, streaming-commons, text, wai, wai-app-static, wai-extra, warp, warp-tls

Files

+ LICENSE view
@@ -0,0 +1,13 @@+Copyright 2016 Eduardo Trujillo <ed@chromabits.com>++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++  http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.<Paste>
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ kawaii.cabal view
@@ -0,0 +1,81 @@+-- This file has been generated from package.yaml by hpack version 0.14.0.+--+-- see: https://github.com/sol/hpack++name:           kawaii+version:        0.0.1.0+synopsis:       Utilities for serving static sites and blogs with Wai/Warp+category:       Web+homepage:       https://phabricator.chromabits.com/diffusion/KWAI/+maintainer:     Eduardo Trujillo <ed@chromabits.com>+license:        Apache+license-file:   LICENSE+build-type:     Simple+cabal-version:  >= 1.10++library+  hs-source-dirs:+      src+  default-extensions: LambdaCase+  ghc-options: -Wall+  build-depends:+      base >= 4.7 && < 5+    , safe == 0.3.*+    , text+    , lens+    , bytestring+    , hakyll+    , optparse-applicative+    , warp == 3.*+    , warp-tls == 3.*+    , wai == 3.*+    , wai-extra >= 3.0.14+    , wai-app-static == 3.*+    , streaming-commons == 0.1.*+    , containers+    , data-default+    , lifted-base+    , mtl+    , monad-logger+    , monad-control+  exposed-modules:+      Hakyll.Serve.Main+      Network.Wai.Serve+      Network.Wai.Serve.Applications+      Network.Wai.Serve.Listeners+      Network.Wai.Serve.Main+      Network.Wai.Serve.Middleware+      Network.Wai.Serve.Types+  default-language: Haskell2010++test-suite wai-static-extra-spec+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  hs-source-dirs:+      test+  default-extensions: LambdaCase+  ghc-options: -Wall+  build-depends:+      base >= 4.7 && < 5+    , safe == 0.3.*+    , text+    , lens+    , bytestring+    , hakyll+    , optparse-applicative+    , warp == 3.*+    , warp-tls == 3.*+    , wai == 3.*+    , wai-extra >= 3.0.14+    , wai-app-static == 3.*+    , streaming-commons == 0.1.*+    , containers+    , data-default+    , lifted-base+    , mtl+    , monad-logger+    , monad-control+    , hakyll-serve+    , hspec+    , QuickCheck+  default-language: Haskell2010
+ src/Hakyll/Serve/Main.hs view
@@ -0,0 +1,117 @@+{-# LANGUAGE Arrows            #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell   #-}++-- |+--+-- Copyright: (c) Eduardo Trujillo, 2016+-- License: Apache+-- Stability: experimental+--+-- The Main module contains a wrapper function that can be used as your+-- program's main function. It encapsulates both the Hakyll commands and the+-- server functionality into a single application.+--+-- Since this module mainly provides some glue for putting this two+-- applications together, the actual documentation for the server part is+-- available on 'Network.Wai.Serve'.+--+module Hakyll.Serve.Main+  ( -- * Main wrappers+    hakyllServe+  , hakyllServeWith+    -- * Configuration+  , HakyllServeConfiguration(..)+  , -- * Lenses+    hscHakyllConfiguration+  , hscServeConfiguration+  ) where++import Options.Applicative+import System.Environment  (getArgs, withArgs)++import Control.Lens               (makeLenses)+import Data.Default               (Default, def)+import Hakyll                     (defaultConfiguration, hakyllWith)+import Hakyll.Core.Configuration  (Configuration)+import Hakyll.Core.Rules          (Rules)+import Options.Applicative.Arrows+import Safe                       (tailDef)++import Network.Wai.Serve.Main  (serve)+import Network.Wai.Serve.Types (ServeConfiguration (..))++-- | The configuration for the server process.+--+-- The different transforms can be used to specify how the configuration+-- changes depending on the stage. While starting up, the server process will+-- take the base configuration, check the stage and pass the configuration+-- through the appropriate transformer.+--+data HakyllServeConfiguration = HakyllServeConfiguration+  { _hscHakyllConfiguration :: Configuration+  , _hscServeConfiguration  :: ServeConfiguration+  }++instance Default HakyllServeConfiguration where+  def = HakyllServeConfiguration+    { _hscHakyllConfiguration = defaultConfiguration+    , _hscServeConfiguration = def+    }++data HakyllServeCommand+  = HakyllCommand HakyllCommandOptions+  | ServeCommand+  deriving (Show)++data HakyllCommandOptions = HakyllCommandOptions String Bool Bool Bool+  deriving (Show)++data HakyllServeOptions = HakyllServeOptions+  { hsCommand :: HakyllServeCommand+  } deriving (Show)++hakyllServeOptions :: Parser HakyllServeOptions+hakyllServeOptions = runA $ proc () -> do+  cmd <- (asA . hsubparser) hakyllServeCommand -< ()+  A helper -< HakyllServeOptions cmd++hakyllServeCommand :: Mod CommandFields HakyllServeCommand+hakyllServeCommand+  = command "hakyll"+    (info hakyllCommandOptions (progDesc "Access hakyll commands"))+  <> command "serve"+    (info (pure ServeCommand) (progDesc "Start a server hosting the site"))++hakyllCommandOptions :: Parser HakyllServeCommand+hakyllCommandOptions = HakyllCommand+  <$> (HakyllCommandOptions+    <$> strArgument (metavar "SUBCOMMAND")+    <*> switch (long "verbose")+    <*> switch (long "internal-links")+    <*> switch (long "no-server"))++pinfo :: ParserInfo HakyllServeOptions+pinfo = info hakyllServeOptions+  $ progDesc "Hakyll static site compiler and server"++-- | The __serve__ cousin of @Hakyll.hakyllWith@. It provides a wrapper of the+-- usual Hakyll commands and a command for serving the built site.+hakyllServeWith :: HakyllServeConfiguration -> Rules a -> IO ()+hakyllServeWith conf rules = do+  r <- execParser pinfo++  case hsCommand r of+    HakyllCommand _ -> do+      args <- getArgs++      withArgs (tailDef [] args)+        $ hakyllWith (_hscHakyllConfiguration conf) rules+    ServeCommand -> serve (_hscServeConfiguration conf)++-- | The __serve__ cousin of `Hakyll.hakyll`. It provides a wrapper of the+-- usual Hakyll commands and a command for serving the built site.+hakyllServe :: Rules a -> IO ()+hakyllServe = hakyllServeWith def++makeLenses ''HakyllServeConfiguration
+ src/Network/Wai/Serve.hs view
@@ -0,0 +1,128 @@+-- |+--+-- Copyright: (c) Eduardo Trujillo, 2016+-- License: Apache+-- Stability: experimental+--+-- Serve provides utilities for building custom servers for serving+-- static websites and blogs.+--+-- If you are looking to setup a simple but custom static server,+-- "Network.Wai.Serve.Main" is a good starting point.+--+-- The following is an example of the server code used for serving+-- <https://chromabits.com chromabits.com>. It makes use of most of the+-- middleware provided by this package.+--+-- > {-# LANGUAGE OverloadedStrings #-}+-- >+-- > import Data.Maybe         (fromMaybe)+-- > import Data.Monoid        ((<>))+-- > import System.Environment (lookupEnv)+-- >+-- > import Control.Lens+-- > import Data.Default                 (def)+-- > import Network.Wai.Serve.Listeners  (TLSSettings, tlsSettingsChain)+-- > import Network.Wai.Serve.Main       (serve)+-- > import Network.Wai.Serve.Middleware (cspHeadersMiddleware,+-- >                                      deindexifyMiddleware, domainMiddleware,+-- >                                      forceSSLMiddleware, gzipMiddleware,+-- >                                      loggerMiddleware,+-- >                                      securityHeadersMiddleware,+-- >                                      stsHeadersMiddleware, (<#>))+-- > import Network.Wai.Serve.Types      (Directive (..), Stage (..),+-- >                                      TLSConfiguration (..), scDevTransform,+-- >                                      scMiddleware, scPath, scPort,+-- >                                      scProdTransform, scStage,+-- >                                      scStagingTransform, scTlsConfiguration,+-- >                                      tlsPort, tlsSettings)+-- >+-- > directives :: [Directive]+-- > directives =+-- >   [ DefaultSrc ["'self'"]+-- >   , ScriptSrc [+-- >       "'self'", "'unsafe-inline'", "https://use.typekit.net",+-- >       "https://cdn.mathkax.org", "https://connect.facebook.net",+-- >       "https://*.twitter.com", "https://cdn.syndication.twimg.com",+-- >       "https://gist.github.com"+-- >     ]+-- >   , ImgSrc ["'self'", "https:", "data:", "platform.twitter.com"]+-- >   , FontSrc [+-- >       "'self'", "data:", "https://use.typekit.net",+-- >       "https://cdn.mathjax.org", "https://fonts.typekit.net"+-- >     ]+-- >   , StyleSrc [+-- >       "'self'", "'unsafe-inline'", "https://use.typekit.net",+-- >       "platform.twitter.com", "https://assets-cdn.github.com"+-- >     ]+-- >   , FrameSrc [+-- >       "https://www.youtube.com", "https://www.slideshare.net",+-- >       "staticxx.facebook.com", "www.facebook.com"+-- >     ]+-- >   ]+-- >+-- > getTLSSettings :: IO TLSSettings+-- > getTLSSettings = do+-- >   certPath <- lookupEnv "BLOG_TLS_CERT"+-- >   chainPath <- lookupEnv "BLOG_TLS_CHAIN"+-- >   keyPath <- lookupEnv "BLOG_TLS_KEY"+-- >+-- >   return $ tlsSettingsChain+-- >     (fromMaybe "cert.pem" certPath)+-- >     [fromMaybe "fullchain.pem" chainPath]+-- >     (fromMaybe "privkey.pem" keyPath)+-- >+-- > -- | The entry point of the server application.+-- > main :: IO ()+-- > main = do+-- >   rawStage <- lookupEnv "BLOG_STAGE"+-- >   rawPath <- lookupEnv "BLOG_PATH"+-- >+-- >   tlsSettings <- getTLSSettings+-- >+-- >   let liveMiddleware+-- >         = mempty+-- >         <#> loggerMiddleware+-- >         <#> cspHeadersMiddleware directives+-- >         <#> securityHeadersMiddleware+-- >         <#> domainMiddleware "chromabits.com"+-- >         <#> forceSSLMiddleware+-- >         <#> deindexifyMiddleware+-- >         <#> gzipMiddleware+-- >       prodMiddlware = (mempty <#> stsHeadersMiddleware) <> liveMiddleware+-- >+-- >   let tlsConf = TLSConfiguration (const liveMiddleware) tlsSettings 8443+-- >+-- >   serve $ def+-- >     & scStage .~ case rawStage of+-- >       Just "live" -> Production+-- >       Just "staging" -> Staging+-- >       _ -> Development+-- >     & scPort .~ 9090+-- >     & scMiddleware .~ mempty+-- >       <#> loggerMiddleware+-- >       <#> securityHeadersMiddleware+-- >       <#> deindexifyMiddleware+-- >       <#> gzipMiddleware+-- >     & scPath .~ rawPath+-- >     & scStagingTransform .~+-- >       ( (set scTlsConfiguration $ Just tlsConf)+-- >       . (set scMiddleware liveMiddleware)+-- >       . (set scPort 8080)+-- >       )+-- >     & scProdTransform .~+-- >       ( (set scTlsConfiguration $ Just (tlsConf & tlsPort .~ 443))+-- >       . (set scMiddleware prodMiddlware)+-- >       . (set scPort 80)+-- >       )+-- >+--+module Network.Wai.Serve+  ( module X+  ) where++import Network.Wai.Serve.Applications as X+import Network.Wai.Serve.Listeners    as X+import Network.Wai.Serve.Main         as X+import Network.Wai.Serve.Middleware   as X+import Network.Wai.Serve.Types        as X
+ src/Network/Wai/Serve/Applications.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE OverloadedStrings #-}++-- |+--+-- Copyright: (c) Eduardo Trujillo, 2016+-- License: Apache+-- Stability: experimental+--+-- Utility Wai applications.+module Network.Wai.Serve.Applications where++import Data.Maybe  (fromMaybe, mapMaybe)+import Data.String (fromString)++import Data.Text                      (pack)+import Network.Wai                    (Application)+import Network.Wai.Application.Static (defaultWebAppSettings, ss404Handler,+                                       ssAddTrailingSlash, ssIndices, ssMaxAge,+                                       ssRedirectToIndex, staticApp)+import Network.Wai.Middleware.Vhost   (redirectTo)+import WaiAppStatic.Types             (MaxAge (MaxAgeSeconds), toPiece)++-- | An application for static websites.+--+-- It serves files from the provided path. It defaults to `_site` which is the+-- default location for Hakyll websites.+staticSite :: Maybe FilePath -> Application+staticSite path = staticApp+  (defaultWebAppSettings . fromString $ fromMaybe "_site" path)+  { ssIndices = mapMaybe (toPiece . pack) ["index.html"]+  , ssRedirectToIndex = False+  , ssAddTrailingSlash = True+  , ss404Handler = Just redirectHome+  , ssMaxAge = MaxAgeSeconds 604801+  }++-- | Handler for redirecting requests to the root of the site.+--+-- Useful for 404 handlers.+redirectHome :: Application+redirectHome _ sendResponse = sendResponse $ redirectTo "/"
+ src/Network/Wai/Serve/Listeners.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell   #-}++-- |+--+-- Copyright: (c) Eduardo Trujillo, 2016+-- License: Apache+-- Stability: experimental+--+-- The Listeners module includes wrappers for starting TLS and non-TLS Warp+-- servers, with support for IPv4 and IPv6.+module Network.Wai.Serve.Listeners+  ( -- * Listeners+    listen+  , listenTLS+    -- * Re-exports+  , TLSSettings+  , tlsSettingsChain+  ) where++import           Control.Monad.Logger        (MonadLogger, logDebug)+import           Control.Monad.Trans         (MonadIO, liftIO)+import qualified Data.Text                   as T+import           Network.Wai                 (Application)+import           Network.Wai.Handler.Warp    (defaultSettings, runSettings,+                                              setHost, setPort)+import           Network.Wai.Handler.WarpTLS (TLSSettings, runTLS,+                                              tlsSettingsChain)++-- | Serves a WAI Application on the specified port.+-- The target port is printed to stdout before hand, which can be useful for+-- debugging purposes.+listen :: (MonadLogger m, MonadIO m) => Int -> Application -> m ()+listen port app = do+  let settings = setHost "*6" (setPort port defaultSettings)++  -- Inform which port we will be listening on.+  $(logDebug) $ mconcat ["Listening on port ", T.pack $ show port, "..."]++  -- Serve the WAI app using Warp+  liftIO $ runSettings settings app++-- | Serves a WAI Application on the specified port.+-- The target port is printed to stdout before hand, which can be useful for+-- debugging purposes.+listenTLS+  :: (MonadLogger m, MonadIO m)+  => TLSSettings+  -> Int+  -> Application+  -> m ()+listenTLS tlsSettings port app = do+  let settings = setHost "*6" (setPort port defaultSettings)++  -- Inform which port we will be listening on.+  $(logDebug) $ mconcat ["Listening on port ", T.pack $ show port, " (TLS)..."]++  -- Serve the WAI app using Warp+  liftIO $ runTLS tlsSettings settings app
+ src/Network/Wai/Serve/Main.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RecordWildCards  #-}++-- |+--+-- Copyright: (c) Eduardo Trujillo, 2016+-- License: Apache+-- Stability: experimental+--+-- The Main module contains an implementation of a configurable static web+-- server with support for a middleware stack and different environments+-- (development, staging, production).+--+-- Take a look at 'ServeConfiguration' for all the possible configuration+-- options or simply use it's 'Data.Default.Default' instance for a basic+-- server.+--+module Network.Wai.Serve.Main+  ( serve+  , serve'+  ) where++import Control.Concurrent.Lifted   (fork)+import Control.Monad.Logger        (runStdoutLoggingT)+import Control.Monad.Trans         (MonadIO)+import Control.Monad.Trans.Control (MonadBaseControl)++import Network.Wai.Serve.Applications (staticSite)+import Network.Wai.Serve.Listeners    (listen, listenTLS)+import Network.Wai.Serve.Middleware   (wrap)+import Network.Wai.Serve.Types        (ServeConfiguration (..), Stage (..),+                                       TLSConfiguration (..))++-- | Starts a server with the provided @ServeConfiguration@. If TLS settings+-- are provided, an additional server is started for handling secure requests.+serve :: (MonadIO m, MonadBaseControl IO m) => ServeConfiguration -> m ()+serve = serve' . transform++-- | Starts a server with the provided @ServeConfiguration@. If TLS settings+-- are provided, an additional server is started for handling secure requests.+-- Unlike $serve'$, stage transforms are not applied on the provided+-- configuration.+serve' :: (MonadIO m, MonadBaseControl IO m) => ServeConfiguration -> m ()+serve' ServeConfiguration{..} = runStdoutLoggingT $ do+  let site = staticSite _scPath++  _ <- fork $ case _scTlsConfiguration of+    Just TLSConfiguration{..} -> listenTLS+      _tlsSettings+      _tlsPort+      (_tlsMiddleware _scMiddleware `wrap` site)+    Nothing -> pure ()++  listen _scPort (_scMiddleware `wrap` site)++-- | Applies the respective configuration transform to the current stage.+transform :: ServeConfiguration -> ServeConfiguration+transform conf@ServeConfiguration{..} = transformer conf+  where+    transformer = case _scStage of+      Development -> _scDevTransform+      Staging -> _scStagingTransform+      Production -> _scProdTransform
+ src/Network/Wai/Serve/Middleware.hs view
@@ -0,0 +1,156 @@+{-# LANGUAGE OverloadedStrings #-}++-- |+--+-- Copyright: (c) Eduardo Trujillo, 2016+-- License: Apache+-- Stability: experimental+--+-- A collection of middleware useful for static websites.+module Network.Wai.Serve.Middleware+  ( -- * Middleware Stacks+    MiddlewareStack(..)+  , (<#>)+  , flatten+  , wrap+    -- * Middleware+  , loggerMiddleware+  , forceSSLMiddleware+  , gzipMiddleware+  , domainMiddleware+  , securityHeadersMiddleware+  , stsHeadersMiddleware+  , cspHeadersMiddleware+  , deindexifyMiddleware+  ) where++import Data.ByteString (ByteString)+import Data.Monoid     ((<>))+import Prelude         hiding (unwords)++import           Data.Text                            (Text, intercalate,+                                                       unwords)+import qualified Data.Text                            as T (concat)+import           Data.Text.Encoding                   (encodeUtf8)+import           Network.Wai                          (Application, Middleware,+                                                       pathInfo)+import           Network.Wai.Middleware.AddHeaders    (addHeaders)+import           Network.Wai.Middleware.ForceDomain   (forceDomain)+import           Network.Wai.Middleware.ForceSSL      (forceSSL)+import           Network.Wai.Middleware.Gzip          (GzipFiles (GzipCompress),+                                                       def, gzip, gzipFiles)+import           Network.Wai.Middleware.RequestLogger (logStdout)+import           Network.Wai.Middleware.Vhost         (redirectTo)+import           Safe                                 (lastMay)++import Network.Wai.Serve.Types++infixl 5 <#>+-- | A combinator for adding a middleware to the bottom of a stack.+(<#>) :: MiddlewareStack -> Middleware -> MiddlewareStack+(<#>) (MiddlewareStack s) m = MiddlewareStack (s ++ [m])++-- | Combines the entire stack into a single middleware.+flatten :: MiddlewareStack -> Middleware+flatten (MiddlewareStack s) = foldr (.) id s++-- | Wraps a WAI application in the stack. (Alias of 'flatten')+wrap :: MiddlewareStack -> Application -> Application+wrap = flatten++dt :: Text -> [Text] -> Text+dt prefix [] = prefix+dt prefix xs = unwords (prefix : xs)++showDirective :: Directive -> Text+showDirective (BaseURI xs) = dt "base-uri" xs+showDirective (ChildSrc xs) = dt "child-src" xs+showDirective (ConnectSrc xs) = dt "connect-src" xs+showDirective (DefaultSrc xs) = dt "default-src" xs+showDirective (FontSrc xs) = dt "font-src" xs+showDirective (FormAction xs) = dt "form-action" xs+showDirective (FrameAncestors xs) = dt "frame-ancestors" xs+showDirective (FrameSrc xs) = dt "frame-src" xs+showDirective (ImgSrc xs) = dt "img-src" xs+showDirective (ManifestSrc xs) = dt "manifest-src" xs+showDirective (MediaSrc xs) = dt "media-src" xs+showDirective (ObjectSrc xs) = dt "object-src" xs+showDirective (PluginTypes xs) = dt "plugin-types" xs+showDirective (Referrer x) = dt "referrer" [x]+showDirective (ReflectedXSS x) = dt "reflected-xss" [x]+showDirective (ReportURI x) = dt "report-uri" [x]+showDirective (Sandbox x) = dt "sandbox" [x]+showDirective (ScriptSrc xs) = dt "script-src" xs+showDirective (StyleSrc xs) = dt "style-src" xs+showDirective UpgradeInsecureRequests = dt "upgrade-insecure-requests" []++-- | Logger middleware.+loggerMiddleware :: Middleware+loggerMiddleware = logStdout++-- | Middleware for forcing requests to be done through SSL.+forceSSLMiddleware :: Middleware+forceSSLMiddleware = forceSSL++-- | Gzip compression middleware.+gzipMiddleware :: Middleware+gzipMiddleware = gzip $ def {gzipFiles = GzipCompress}++-- | Domain redirection middleware.+--+-- When the site is live, we want to redirect users to the right domain name+-- regarles of whether they arrive from a www. domain, the server's IP address+-- or a spoof domain which is pointing to this server.+domainMiddleware :: Domain -> Middleware+domainMiddleware target = forceDomain+  $ \domain -> if domain `elem` [target, "localhost"]+    then Nothing+    else Just target++-- | Common security headers middleware.+securityHeadersMiddleware :: Middleware+securityHeadersMiddleware = addHeaders+  [ ("X-Frame-Options", "SAMEORIGIN")+  , ("X-XSS-Protection", "1; mode=block")+  , ("X-Content-Type-Options", "nosniff")+  ]++-- | Strict Transport Security middleware.+stsHeadersMiddleware :: Middleware+stsHeadersMiddleware = addHeaders+  [("Strict-Transport-Security", "max-age=31536000; includeSubdomains")]++-- | Content Security Policy middleware.+--+-- Here we add the CSP header which includes the policies for this blog.+cspHeadersMiddleware :: [Directive] -> Middleware+cspHeadersMiddleware directives = addHeaders+  [("Content-Security-Policy", encodeUtf8 $ glue directives)]+  where+    glue :: [Directive] -> Text+    glue [] = showDirective $ DefaultSrc ["'none'"]+    glue xs = intercalate "; " (map showDirective xs)++-- | De-indexify middleware.+--+-- Redirects any path ending in `/index.html` to just `/`.+deindexifyMiddleware :: Middleware+deindexifyMiddleware app req sendResponse+  = if lastMay (pathInfo req) == Just "index.html"+    then sendResponse $ redirectTo newPath+    else app req sendResponse++    where+      newPath :: ByteString+      newPath = encodeUtf8 $ processPath oldPath++      processPath :: [Text] -> Text+      processPath xs = case xs of+        [] -> "/"+        _ -> T.concat $ map prefixSlash xs++      oldPath :: [Text]+      oldPath = init $ pathInfo req++      prefixSlash :: Text -> Text+      prefixSlash = (<>) "/"
+ src/Network/Wai/Serve/Types.hs view
@@ -0,0 +1,151 @@+{-# LANGUAGE TemplateHaskell #-}++-- |+--+-- Copyright: (c) Eduardo Trujillo, 2016+-- License: Apache+-- Stability: experimental+--+-- Types used by the Kawaii package.+module Network.Wai.Serve.Types+  ( -- * Middleware Stack+    MiddlewareStack(..)+  , -- * Server configuration+    ServeConfiguration(..)+  , TLSConfiguration(..)+  , -- * CSP+    SourceList+  , TypeList+  , Directive(..)+  , -- * Miscellaneous types+    Domain+  , Stage(..)+  , -- * Lenses+    scMiddleware+  , scDevTransform+  , scStagingTransform+  , scProdTransform+  , scTlsConfiguration+  , scPort+  , scStage+  , scPath+  , tlsMiddleware+  , tlsSettings+  , tlsPort+  ) where++import Data.ByteString (ByteString)++import Control.Lens                (makeLenses)+import Data.Default                (Default, def)+import Data.Text                   (Text)+import Network.Wai                 (Middleware)+import Network.Wai.Handler.WarpTLS (TLSSettings)++type Domain = ByteString++type SourceList = [Text]+type TypeList = [Text]++data Directive+  = BaseURI SourceList+  | ChildSrc SourceList+  | ConnectSrc SourceList+  | DefaultSrc SourceList+  | FontSrc SourceList+  | FormAction SourceList+  | FrameAncestors SourceList+  | FrameSrc SourceList+  | ImgSrc SourceList+  | ManifestSrc SourceList+  | MediaSrc SourceList+  | ObjectSrc SourceList+  | PluginTypes TypeList+  | Referrer Text+  | ReflectedXSS Text+  | ReportURI Text+  | Sandbox Text+  | ScriptSrc SourceList+  | StyleSrc SourceList+  | UpgradeInsecureRequests++-- | A middleware stack is a simple container of Wai middleware. The top of the+-- stack is considered to be the outermost layer of middleware while the bottom+-- of the stack is the innermost layer of middleware.+--+-- The stack is a 'Monoid', so it can be combined with other stacks using+-- 'Data.Monoid.<>', and an empty one can be obtained using 'mempty'.+--+data MiddlewareStack+  -- | The constructor takes a list of middleware, where the left-most item in+  -- the list will end up at the top of the stack, and the right-most at the+  -- bottom.+  = MiddlewareStack [Middleware]++instance Monoid MiddlewareStack where+  mempty = MiddlewareStack []+  mappend (MiddlewareStack x) (MiddlewareStack y) = MiddlewareStack (x ++ y)++-- | The development stage an application is executing in.+--+-- This is used to alter the behavior of the server depending on the stage of+-- development. For example, a local development server might only have an+-- HTTP listener and a smaller middleware stack, while a production server+-- also listens for TLS connections and has additional middlewares that only+-- make sense on a public server.+--+data Stage = Development | Staging | Production deriving (Show)++-- | The configuration for the server process.+--+-- The different transforms can be used to specify how the configuration+-- changes depending on the stage. While starting up, the server process will+-- take the base configuration, check the stage and pass the configuration+-- through the appropriate transformer.+--+data ServeConfiguration = ServeConfiguration+  { -- | Base middleware stack.+    _scMiddleware       :: MiddlewareStack+    -- | @Developer@ stage configuration transformer.+  , _scDevTransform     :: ServeConfiguration -> ServeConfiguration+    -- | @Staging@ stage configuration transfomer.+  , _scStagingTransform :: ServeConfiguration -> ServeConfiguration+    -- | @Production@ stage configuration transfomer.+  , _scProdTransform    :: ServeConfiguration -> ServeConfiguration+    -- | TLS/SSL configuration. If it's not provided, a TLS listener will not+    -- be started.+  , _scTlsConfiguration :: Maybe TLSConfiguration+    -- | Port to start the non-TLS server.+  , _scPort             :: Int+    -- | The current stage. This selects which transformer is used before+    -- starting the server.+  , _scStage            :: Stage+    -- | Path where the source of built site is located. Defaults to `_site`.+  , _scPath             :: Maybe FilePath+  }++instance Default ServeConfiguration where+  def = ServeConfiguration+    { _scMiddleware = mempty+    , _scDevTransform = id+    , _scStagingTransform = id+    , _scProdTransform = id+    , _scTlsConfiguration = Nothing+    , _scPort = 9119+    , _scStage = Development+    , _scPath = Nothing+    }++-- | The configuration for the TLS/HTTPS server.+data TLSConfiguration = TLSConfiguration+  { -- | A function for modifying or completely replacing the middleware stack+    -- for the TLS server.+    _tlsMiddleware :: MiddlewareStack -> MiddlewareStack+    -- | Warp @TLSSettings@, which can be used to provide certificates.+  , _tlsSettings   :: TLSSettings+    -- | Port to start the TLS server.+  , _tlsPort       :: Int+  }++makeLenses ''ServeConfiguration+makeLenses ''TLSConfiguration
+ test/Spec.hs view
@@ -0,0 +1,2 @@+main :: IO ()+main = putStrLn "Test suite not yet implemented"