Haskell WAI middleware to remove a header #feedbase #haskell #programming

🕒︎ - 2017-05-13

Fe The website of Feedbase is a Haskell application, built using the Spock framework. It's my first Haskell program that does something non-trivial in the "real" world.

Recently I was mucking about with cookies in another context, and noticed that the Feedbase website sets a cookie, spockcookie.

This is part of Spock's built-in session handling. I don't use sessions, so I'd rather not set the cookie (given the EU's weird cookie rules and what have you).

You can't turn them off in Spock easily, so I started thinking that maybe some "middleware" could be used.

After some searching I found a StackOverflow question, and combined with looking at the source code of the Network.WAI.Middleware.Gzip module I cobbled together my own little "NoCookies" module:

{-# LANGUAGE OverloadedStrings #-}
module NoCookies where

-- Remove all Set-Cookie headers on responses.

import Network.Wai (Middleware) import Network.Wai.Internal (Response(..)) import Network.HTTP.Types (Header)

-- Function to hook into middleware: nocookies :: Middleware nocookies application request sendResponse = application request $ sendResponse . removeHeader

-- Handle all the various kinds of responses: removeHeader :: Response -> Response removeHeader (ResponseFile s h b1 b2) = ResponseFile s (filterSetCookie h) b1 b2 removeHeader (ResponseBuilder s h b) = ResponseBuilder s (filterSetCookie h) b removeHeader (ResponseStream s h b) = ResponseStream s (filterSetCookie h) b removeHeader r@(ResponseRaw _ _) = r

-- Remove Set-Cookie from headers: filterSetCookie :: [Header] -> [Header] filterSetCookie hs = filter notSetCookie hs where notSetCookie (x, _) = x /= "Set-Cookie"

A couple of odd things: the Network.HTTP.Types module defines a bunch of constants for headers, but not hSetCookie.

As you can see, most of my module consists of lines pattern matching the Response type - it seems odd that there should be no smarter way of doing this.

As usual in Haskell the reader of documentation is assumed to always know how to put things together. Unfortunately I don't always know that. So here's how I added my module to the Main.hs of my application:

import NoCookies

app :: SpockCtxM ctx Pg.Connection session state () app = do logger <- liftIO $ mkRequestLogger def { outputFormat = Apache FromFallback } middleware logger middleware $ gzip def middleware (staticPolicy (addBase "static")) middleware nocookies ...

Unfortunately this code does work any more. I haven't figured out why, instead I am removing the header in Apache, which I have in front of my Haskell-based websites:

    Header unset Set-Cookie

- Adam Sjøgren 🕙︎ - 2023-03-12


Add comment

To avoid spam many websites make you fill out a CAPTCHA, or log in via an account at a corporation such as Twitter, Facebook, Google or even Microsoft GitHub.

I have chosen to use a more old school method of spam prevention.

To post a comment here, you need to:

¹ Such as Thunderbird, Pan, slrn, tin or Gnus (part of Emacs).

Or, you can fill in this form: