cryptionhandler_test.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. package handler
  2. import (
  3. "bytes"
  4. "crypto/rand"
  5. "encoding/base64"
  6. "io"
  7. "net/http"
  8. "net/http/httptest"
  9. "strings"
  10. "testing"
  11. "testing/iotest"
  12. "github.com/stretchr/testify/assert"
  13. "github.com/wuntsong-org/go-zero-plus/core/codec"
  14. "github.com/wuntsong-org/go-zero-plus/core/logx/logtest"
  15. )
  16. const (
  17. reqText = "ping"
  18. respText = "pong"
  19. )
  20. var aesKey = []byte(`PdSgVkYp3s6v9y$B&E)H+MbQeThWmZq4`)
  21. func TestCryptionHandlerGet(t *testing.T) {
  22. req := httptest.NewRequest(http.MethodGet, "/any", http.NoBody)
  23. handler := CryptionHandler(aesKey)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  24. _, err := w.Write([]byte(respText))
  25. w.Header().Set("X-Test", "test")
  26. assert.Nil(t, err)
  27. }))
  28. recorder := httptest.NewRecorder()
  29. handler.ServeHTTP(recorder, req)
  30. expect, err := codec.EcbEncrypt(aesKey, []byte(respText))
  31. assert.Nil(t, err)
  32. assert.Equal(t, http.StatusOK, recorder.Code)
  33. assert.Equal(t, "test", recorder.Header().Get("X-Test"))
  34. assert.Equal(t, base64.StdEncoding.EncodeToString(expect), recorder.Body.String())
  35. }
  36. func TestCryptionHandlerGet_badKey(t *testing.T) {
  37. req := httptest.NewRequest(http.MethodGet, "/any", http.NoBody)
  38. handler := CryptionHandler(append(aesKey, aesKey...))(http.HandlerFunc(
  39. func(w http.ResponseWriter, r *http.Request) {
  40. _, err := w.Write([]byte(respText))
  41. w.Header().Set("X-Test", "test")
  42. assert.Nil(t, err)
  43. }))
  44. recorder := httptest.NewRecorder()
  45. handler.ServeHTTP(recorder, req)
  46. assert.Equal(t, http.StatusInternalServerError, recorder.Code)
  47. }
  48. func TestCryptionHandlerPost(t *testing.T) {
  49. var buf bytes.Buffer
  50. enc, err := codec.EcbEncrypt(aesKey, []byte(reqText))
  51. assert.Nil(t, err)
  52. buf.WriteString(base64.StdEncoding.EncodeToString(enc))
  53. req := httptest.NewRequest(http.MethodPost, "/any", &buf)
  54. handler := CryptionHandler(aesKey)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  55. body, err := io.ReadAll(r.Body)
  56. assert.Nil(t, err)
  57. assert.Equal(t, reqText, string(body))
  58. w.Write([]byte(respText))
  59. }))
  60. recorder := httptest.NewRecorder()
  61. handler.ServeHTTP(recorder, req)
  62. expect, err := codec.EcbEncrypt(aesKey, []byte(respText))
  63. assert.Nil(t, err)
  64. assert.Equal(t, http.StatusOK, recorder.Code)
  65. assert.Equal(t, base64.StdEncoding.EncodeToString(expect), recorder.Body.String())
  66. }
  67. func TestCryptionHandlerPostBadEncryption(t *testing.T) {
  68. var buf bytes.Buffer
  69. enc, err := codec.EcbEncrypt(aesKey, []byte(reqText))
  70. assert.Nil(t, err)
  71. buf.Write(enc)
  72. req := httptest.NewRequest(http.MethodPost, "/any", &buf)
  73. handler := CryptionHandler(aesKey)(nil)
  74. recorder := httptest.NewRecorder()
  75. handler.ServeHTTP(recorder, req)
  76. assert.Equal(t, http.StatusBadRequest, recorder.Code)
  77. }
  78. func TestCryptionHandlerWriteHeader(t *testing.T) {
  79. req := httptest.NewRequest(http.MethodGet, "/any", http.NoBody)
  80. handler := CryptionHandler(aesKey)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  81. w.WriteHeader(http.StatusServiceUnavailable)
  82. }))
  83. recorder := httptest.NewRecorder()
  84. handler.ServeHTTP(recorder, req)
  85. assert.Equal(t, http.StatusServiceUnavailable, recorder.Code)
  86. }
  87. func TestCryptionHandlerFlush(t *testing.T) {
  88. req := httptest.NewRequest(http.MethodGet, "/any", http.NoBody)
  89. handler := CryptionHandler(aesKey)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  90. w.Write([]byte(respText))
  91. flusher, ok := w.(http.Flusher)
  92. assert.True(t, ok)
  93. flusher.Flush()
  94. }))
  95. recorder := httptest.NewRecorder()
  96. handler.ServeHTTP(recorder, req)
  97. expect, err := codec.EcbEncrypt(aesKey, []byte(respText))
  98. assert.Nil(t, err)
  99. assert.Equal(t, base64.StdEncoding.EncodeToString(expect), recorder.Body.String())
  100. }
  101. func TestCryptionHandler_Hijack(t *testing.T) {
  102. resp := httptest.NewRecorder()
  103. writer := newCryptionResponseWriter(resp)
  104. assert.NotPanics(t, func() {
  105. writer.Hijack()
  106. })
  107. writer = newCryptionResponseWriter(mockedHijackable{resp})
  108. assert.NotPanics(t, func() {
  109. writer.Hijack()
  110. })
  111. }
  112. func TestCryptionHandler_ContentTooLong(t *testing.T) {
  113. handler := CryptionHandler(aesKey)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  114. }))
  115. svr := httptest.NewServer(handler)
  116. defer svr.Close()
  117. body := make([]byte, maxBytes+1)
  118. _, err := rand.Read(body)
  119. assert.NoError(t, err)
  120. req, err := http.NewRequest(http.MethodPost, svr.URL, bytes.NewReader(body))
  121. assert.Nil(t, err)
  122. resp, err := http.DefaultClient.Do(req)
  123. assert.Nil(t, err)
  124. assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
  125. }
  126. func TestCryptionHandler_BadBody(t *testing.T) {
  127. req, err := http.NewRequest(http.MethodPost, "/foo", iotest.ErrReader(io.ErrUnexpectedEOF))
  128. assert.Nil(t, err)
  129. err = decryptBody(maxBytes, aesKey, req)
  130. assert.ErrorIs(t, err, io.ErrUnexpectedEOF)
  131. }
  132. func TestCryptionHandler_BadKey(t *testing.T) {
  133. var buf bytes.Buffer
  134. enc, err := codec.EcbEncrypt(aesKey, []byte(reqText))
  135. assert.Nil(t, err)
  136. buf.WriteString(base64.StdEncoding.EncodeToString(enc))
  137. req := httptest.NewRequest(http.MethodPost, "/any", &buf)
  138. err = decryptBody(maxBytes, append(aesKey, aesKey...), req)
  139. assert.Error(t, err)
  140. }
  141. func TestCryptionResponseWriter_Flush(t *testing.T) {
  142. body := []byte("hello, world!")
  143. t.Run("half", func(t *testing.T) {
  144. recorder := httptest.NewRecorder()
  145. f := flushableResponseWriter{
  146. writer: &halfWriter{recorder},
  147. }
  148. w := newCryptionResponseWriter(f)
  149. _, err := w.Write(body)
  150. assert.NoError(t, err)
  151. w.flush(aesKey)
  152. b, err := io.ReadAll(recorder.Body)
  153. assert.NoError(t, err)
  154. expected, err := codec.EcbEncrypt(aesKey, body)
  155. assert.NoError(t, err)
  156. assert.True(t, strings.HasPrefix(base64.StdEncoding.EncodeToString(expected), string(b)))
  157. assert.True(t, len(string(b)) < len(base64.StdEncoding.EncodeToString(expected)))
  158. })
  159. t.Run("full", func(t *testing.T) {
  160. recorder := httptest.NewRecorder()
  161. f := flushableResponseWriter{
  162. writer: recorder,
  163. }
  164. w := newCryptionResponseWriter(f)
  165. _, err := w.Write(body)
  166. assert.NoError(t, err)
  167. w.flush(aesKey)
  168. b, err := io.ReadAll(recorder.Body)
  169. assert.NoError(t, err)
  170. expected, err := codec.EcbEncrypt(aesKey, body)
  171. assert.NoError(t, err)
  172. assert.Equal(t, base64.StdEncoding.EncodeToString(expected), string(b))
  173. })
  174. t.Run("bad writer", func(t *testing.T) {
  175. buf := logtest.NewCollector(t)
  176. f := flushableResponseWriter{
  177. writer: new(badWriter),
  178. }
  179. w := newCryptionResponseWriter(f)
  180. _, err := w.Write(body)
  181. assert.NoError(t, err)
  182. w.flush(aesKey)
  183. assert.True(t, strings.Contains(buf.Content(), io.ErrClosedPipe.Error()))
  184. })
  185. }
  186. type flushableResponseWriter struct {
  187. writer io.Writer
  188. }
  189. func (m flushableResponseWriter) Header() http.Header {
  190. panic("implement me")
  191. }
  192. func (m flushableResponseWriter) Write(p []byte) (int, error) {
  193. return m.writer.Write(p)
  194. }
  195. func (m flushableResponseWriter) WriteHeader(statusCode int) {
  196. panic("implement me")
  197. }
  198. type halfWriter struct {
  199. w io.Writer
  200. }
  201. func (t *halfWriter) Write(p []byte) (n int, err error) {
  202. n = len(p) >> 1
  203. return t.w.Write(p[0:n])
  204. }
  205. type badWriter struct {
  206. }
  207. func (b *badWriter) Write(p []byte) (n int, err error) {
  208. return 0, io.ErrClosedPipe
  209. }