docs: function cookieSession (options) {
    var opts = options || {}
  
    // cookie name
    var name = opts.name || 'session'
  
    // secrets
    var keys = opts.keys
    if (!keys && opts.secret) keys = [opts.secret]
  
    // defaults
    if (opts.overwrite == null) opts.overwrite = true
    if (opts.httpOnly == null) opts.httpOnly = true
    if (opts.signed == null) opts.signed = true
  
    if (!keys && opts.signed) throw new Error('.keys required.')
  
    debug('session options %j', opts)
  
    return function _cookieSession (req, res, next) {
      var cookies = new Cookies(req, res, {
        keys: keys
      })
      var sess
  
      // to pass to Session()
      req.sessionCookies = cookies
      req.sessionOptions = Object.create(opts)
      req.sessionKey = name
  
      // define req.session getter / setter
      Object.defineProperty(req, 'session', {
        configurable: true,
        enumerable: true,
        get: getSession,
        set: setSession
      })
  
      function getSession () {
        // already retrieved
        if (sess) {
          return sess
        }
  
        // unset
        if (sess === false) {
          return null
        }
  
        // get or create session
        return (sess = tryGetSession(req) || createSession(req))
      }
  
      function setSession (val) {
        if (val == null) {
          // unset session
          sess = false
          return val
        }
  
        if (typeof val === 'object') {
          // create a new session
          sess = Session.create(this, val)
          return sess
        }
  
        throw new Error('req.session can only be set as null or an object.')
      }
  
      onHeaders(res, function setHeaders () {
        if (sess === undefined) {
          // not accessed
          return
        }
  
        try {
          if (sess === false) {
            // remove
            cookies.set(name, '', req.sessionOptions)
          } else if ((!sess.isNew || sess.isPopulated) && sess.isChanged) {
            // save populated or non-new changed session
            sess.save()
          }
        } catch (e) {
          debug('error saving session %s', e.message)
        }
      })
  
      next()
    }
  }