body_dump.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. package middleware
  2. import (
  3. "bufio"
  4. "bytes"
  5. "io"
  6. "io/ioutil"
  7. "net"
  8. "net/http"
  9. "github.com/labstack/echo"
  10. )
  11. type (
  12. // BodyDumpConfig defines the config for BodyDump middleware.
  13. BodyDumpConfig struct {
  14. // Skipper defines a function to skip middleware.
  15. Skipper Skipper
  16. // Handler receives request and response payload.
  17. // Required.
  18. Handler BodyDumpHandler
  19. }
  20. // BodyDumpHandler receives the request and response payload.
  21. BodyDumpHandler func(echo.Context, []byte, []byte)
  22. bodyDumpResponseWriter struct {
  23. io.Writer
  24. http.ResponseWriter
  25. }
  26. )
  27. var (
  28. // DefaultBodyDumpConfig is the default BodyDump middleware config.
  29. DefaultBodyDumpConfig = BodyDumpConfig{
  30. Skipper: DefaultSkipper,
  31. }
  32. )
  33. // BodyDump returns a BodyDump middleware.
  34. //
  35. // BodyLimit middleware captures the request and response payload and calls the
  36. // registered handler.
  37. func BodyDump(handler BodyDumpHandler) echo.MiddlewareFunc {
  38. c := DefaultBodyDumpConfig
  39. c.Handler = handler
  40. return BodyDumpWithConfig(c)
  41. }
  42. // BodyDumpWithConfig returns a BodyDump middleware with config.
  43. // See: `BodyDump()`.
  44. func BodyDumpWithConfig(config BodyDumpConfig) echo.MiddlewareFunc {
  45. // Defaults
  46. if config.Handler == nil {
  47. panic("echo: body-dump middleware requires a handler function")
  48. }
  49. if config.Skipper == nil {
  50. config.Skipper = DefaultBodyDumpConfig.Skipper
  51. }
  52. return func(next echo.HandlerFunc) echo.HandlerFunc {
  53. return func(c echo.Context) (err error) {
  54. if config.Skipper(c) {
  55. return next(c)
  56. }
  57. // Request
  58. reqBody := []byte{}
  59. if c.Request().Body != nil { // Read
  60. reqBody, _ = ioutil.ReadAll(c.Request().Body)
  61. }
  62. c.Request().Body = ioutil.NopCloser(bytes.NewBuffer(reqBody)) // Reset
  63. // Response
  64. resBody := new(bytes.Buffer)
  65. mw := io.MultiWriter(c.Response().Writer, resBody)
  66. writer := &bodyDumpResponseWriter{Writer: mw, ResponseWriter: c.Response().Writer}
  67. c.Response().Writer = writer
  68. if err = next(c); err != nil {
  69. c.Error(err)
  70. }
  71. // Callback
  72. config.Handler(c, reqBody, resBody.Bytes())
  73. return
  74. }
  75. }
  76. }
  77. func (w *bodyDumpResponseWriter) WriteHeader(code int) {
  78. w.ResponseWriter.WriteHeader(code)
  79. }
  80. func (w *bodyDumpResponseWriter) Write(b []byte) (int, error) {
  81. return w.Writer.Write(b)
  82. }
  83. func (w *bodyDumpResponseWriter) Flush() {
  84. w.ResponseWriter.(http.Flusher).Flush()
  85. }
  86. func (w *bodyDumpResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  87. return w.ResponseWriter.(http.Hijacker).Hijack()
  88. }
  89. func (w *bodyDumpResponseWriter) CloseNotify() <-chan bool {
  90. return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
  91. }