index.js 1.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. 'use strict'
  2. /**
  3. * Module dependencies.
  4. */
  5. const calculate = require('etag')
  6. const Stream = require('stream')
  7. const promisify = require('util').promisify
  8. const fs = require('fs')
  9. const stat = promisify(fs.stat)
  10. /**
  11. * Expose `etag`.
  12. *
  13. * Add ETag header field.
  14. * @param {object} [options] see https://github.com/jshttp/etag#options
  15. * @param {boolean} [options.weak]
  16. * @return {Function}
  17. * @api public
  18. */
  19. module.exports = function etag (options) {
  20. return async function etag (ctx, next) {
  21. await next()
  22. const entity = await getResponseEntity(ctx)
  23. setEtag(ctx, entity, options)
  24. }
  25. }
  26. async function getResponseEntity (ctx) {
  27. // no body
  28. const body = ctx.body
  29. if (!body || ctx.response.get('etag')) return
  30. // type
  31. const status = ctx.status / 100 | 0
  32. // 2xx
  33. if (status !== 2) return
  34. if (body instanceof Stream) {
  35. if (!body.path) return
  36. return await stat(body.path)
  37. } else if ((typeof body === 'string') || Buffer.isBuffer(body)) {
  38. return body
  39. } else {
  40. return JSON.stringify(body)
  41. }
  42. }
  43. function setEtag (ctx, entity, options) {
  44. if (!entity) return
  45. ctx.response.etag = calculate(entity, options)
  46. }