builder_test.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. // Copyright 2018 Frédéric Guillot. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. package response // import "miniflux.app/http/response"
  5. import (
  6. "errors"
  7. "net/http"
  8. "net/http/httptest"
  9. "strings"
  10. "testing"
  11. "time"
  12. )
  13. func TestResponseHasCommonHeaders(t *testing.T) {
  14. r, err := http.NewRequest("GET", "/", nil)
  15. if err != nil {
  16. t.Fatal(err)
  17. }
  18. w := httptest.NewRecorder()
  19. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  20. New(w, r).Write()
  21. })
  22. handler.ServeHTTP(w, r)
  23. resp := w.Result()
  24. headers := map[string]string{
  25. "X-XSS-Protection": "1; mode=block",
  26. "X-Content-Type-Options": "nosniff",
  27. "X-Frame-Options": "DENY",
  28. }
  29. for header, expected := range headers {
  30. actual := resp.Header.Get(header)
  31. if actual != expected {
  32. t.Fatalf(`Unexpected header value, got %q instead of %q`, actual, expected)
  33. }
  34. }
  35. }
  36. func TestBuildResponseWithCustomStatusCode(t *testing.T) {
  37. r, err := http.NewRequest("GET", "/", nil)
  38. if err != nil {
  39. t.Fatal(err)
  40. }
  41. w := httptest.NewRecorder()
  42. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  43. New(w, r).WithStatus(http.StatusNotAcceptable).Write()
  44. })
  45. handler.ServeHTTP(w, r)
  46. resp := w.Result()
  47. expectedStatusCode := http.StatusNotAcceptable
  48. if resp.StatusCode != expectedStatusCode {
  49. t.Fatalf(`Unexpected status code, got %d instead of %d`, resp.StatusCode, expectedStatusCode)
  50. }
  51. }
  52. func TestBuildResponseWithCustomHeader(t *testing.T) {
  53. r, err := http.NewRequest("GET", "/", nil)
  54. if err != nil {
  55. t.Fatal(err)
  56. }
  57. w := httptest.NewRecorder()
  58. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  59. New(w, r).WithHeader("X-My-Header", "Value").Write()
  60. })
  61. handler.ServeHTTP(w, r)
  62. resp := w.Result()
  63. expected := "Value"
  64. actual := resp.Header.Get("X-My-Header")
  65. if actual != expected {
  66. t.Fatalf(`Unexpected header value, got %q instead of %q`, actual, expected)
  67. }
  68. }
  69. func TestBuildResponseWithAttachment(t *testing.T) {
  70. r, err := http.NewRequest("GET", "/", nil)
  71. if err != nil {
  72. t.Fatal(err)
  73. }
  74. w := httptest.NewRecorder()
  75. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  76. New(w, r).WithAttachment("my_file.pdf").Write()
  77. })
  78. handler.ServeHTTP(w, r)
  79. resp := w.Result()
  80. expected := "attachment; filename=my_file.pdf"
  81. actual := resp.Header.Get("Content-Disposition")
  82. if actual != expected {
  83. t.Fatalf(`Unexpected header value, got %q instead of %q`, actual, expected)
  84. }
  85. }
  86. func TestBuildResponseWithError(t *testing.T) {
  87. r, err := http.NewRequest("GET", "/", nil)
  88. if err != nil {
  89. t.Fatal(err)
  90. }
  91. w := httptest.NewRecorder()
  92. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  93. New(w, r).WithBody(errors.New("Some error")).Write()
  94. })
  95. handler.ServeHTTP(w, r)
  96. expectedBody := `Some error`
  97. actualBody := w.Body.String()
  98. if actualBody != expectedBody {
  99. t.Fatalf(`Unexpected body, got %s instead of %s`, actualBody, expectedBody)
  100. }
  101. }
  102. func TestBuildResponseWithByteBody(t *testing.T) {
  103. r, err := http.NewRequest("GET", "/", nil)
  104. if err != nil {
  105. t.Fatal(err)
  106. }
  107. w := httptest.NewRecorder()
  108. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  109. New(w, r).WithBody([]byte("body")).Write()
  110. })
  111. handler.ServeHTTP(w, r)
  112. expectedBody := `body`
  113. actualBody := w.Body.String()
  114. if actualBody != expectedBody {
  115. t.Fatalf(`Unexpected body, got %s instead of %s`, actualBody, expectedBody)
  116. }
  117. }
  118. func TestBuildResponseWithCachingEnabled(t *testing.T) {
  119. r, err := http.NewRequest("GET", "/", nil)
  120. if err != nil {
  121. t.Fatal(err)
  122. }
  123. w := httptest.NewRecorder()
  124. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  125. New(w, r).WithCaching("etag", 1*time.Minute, func(b *Builder) {
  126. b.WithBody("cached body")
  127. b.Write()
  128. })
  129. })
  130. handler.ServeHTTP(w, r)
  131. resp := w.Result()
  132. expectedStatusCode := http.StatusOK
  133. if resp.StatusCode != expectedStatusCode {
  134. t.Fatalf(`Unexpected status code, got %d instead of %d`, resp.StatusCode, expectedStatusCode)
  135. }
  136. expectedBody := `cached body`
  137. actualBody := w.Body.String()
  138. if actualBody != expectedBody {
  139. t.Fatalf(`Unexpected body, got %s instead of %s`, actualBody, expectedBody)
  140. }
  141. expectedHeader := "public"
  142. actualHeader := resp.Header.Get("Cache-Control")
  143. if actualHeader != expectedHeader {
  144. t.Fatalf(`Unexpected cache control header, got %q instead of %q`, actualHeader, expectedHeader)
  145. }
  146. if resp.Header.Get("Expires") == "" {
  147. t.Fatalf(`Expires header should not be empty`)
  148. }
  149. }
  150. func TestBuildResponseWithCachingAndEtag(t *testing.T) {
  151. r, err := http.NewRequest("GET", "/", nil)
  152. r.Header.Set("If-None-Match", "etag")
  153. if err != nil {
  154. t.Fatal(err)
  155. }
  156. w := httptest.NewRecorder()
  157. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  158. New(w, r).WithCaching("etag", 1*time.Minute, func(b *Builder) {
  159. b.WithBody("cached body")
  160. b.Write()
  161. })
  162. })
  163. handler.ServeHTTP(w, r)
  164. resp := w.Result()
  165. expectedStatusCode := http.StatusNotModified
  166. if resp.StatusCode != expectedStatusCode {
  167. t.Fatalf(`Unexpected status code, got %d instead of %d`, resp.StatusCode, expectedStatusCode)
  168. }
  169. expectedBody := ``
  170. actualBody := w.Body.String()
  171. if actualBody != expectedBody {
  172. t.Fatalf(`Unexpected body, got %s instead of %s`, actualBody, expectedBody)
  173. }
  174. expectedHeader := "public"
  175. actualHeader := resp.Header.Get("Cache-Control")
  176. if actualHeader != expectedHeader {
  177. t.Fatalf(`Unexpected cache control header, got %q instead of %q`, actualHeader, expectedHeader)
  178. }
  179. if resp.Header.Get("Expires") == "" {
  180. t.Fatalf(`Expires header should not be empty`)
  181. }
  182. }
  183. func TestBuildResponseWithGzipCompression(t *testing.T) {
  184. body := strings.Repeat("a", compressionThreshold+1)
  185. r, err := http.NewRequest("GET", "/", nil)
  186. r.Header.Set("Accept-Encoding", "gzip, deflate, br")
  187. if err != nil {
  188. t.Fatal(err)
  189. }
  190. w := httptest.NewRecorder()
  191. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  192. New(w, r).WithBody(body).Write()
  193. })
  194. handler.ServeHTTP(w, r)
  195. resp := w.Result()
  196. expected := "gzip"
  197. actual := resp.Header.Get("Content-Encoding")
  198. if actual != expected {
  199. t.Fatalf(`Unexpected header value, got %q instead of %q`, actual, expected)
  200. }
  201. }
  202. func TestBuildResponseWithDeflateCompression(t *testing.T) {
  203. body := strings.Repeat("a", compressionThreshold+1)
  204. r, err := http.NewRequest("GET", "/", nil)
  205. r.Header.Set("Accept-Encoding", "deflate")
  206. if err != nil {
  207. t.Fatal(err)
  208. }
  209. w := httptest.NewRecorder()
  210. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  211. New(w, r).WithBody(body).Write()
  212. })
  213. handler.ServeHTTP(w, r)
  214. resp := w.Result()
  215. expected := "deflate"
  216. actual := resp.Header.Get("Content-Encoding")
  217. if actual != expected {
  218. t.Fatalf(`Unexpected header value, got %q instead of %q`, actual, expected)
  219. }
  220. }
  221. func TestBuildResponseWithCompressionDisabled(t *testing.T) {
  222. body := strings.Repeat("a", compressionThreshold+1)
  223. r, err := http.NewRequest("GET", "/", nil)
  224. r.Header.Set("Accept-Encoding", "deflate")
  225. if err != nil {
  226. t.Fatal(err)
  227. }
  228. w := httptest.NewRecorder()
  229. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  230. New(w, r).WithBody(body).WithoutCompression().Write()
  231. })
  232. handler.ServeHTTP(w, r)
  233. resp := w.Result()
  234. expected := ""
  235. actual := resp.Header.Get("Content-Encoding")
  236. if actual != expected {
  237. t.Fatalf(`Unexpected header value, got %q instead of %q`, actual, expected)
  238. }
  239. }
  240. func TestBuildResponseWithDeflateCompressionAndSmallPayload(t *testing.T) {
  241. body := strings.Repeat("a", compressionThreshold)
  242. r, err := http.NewRequest("GET", "/", nil)
  243. r.Header.Set("Accept-Encoding", "deflate")
  244. if err != nil {
  245. t.Fatal(err)
  246. }
  247. w := httptest.NewRecorder()
  248. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  249. New(w, r).WithBody(body).Write()
  250. })
  251. handler.ServeHTTP(w, r)
  252. resp := w.Result()
  253. expected := ""
  254. actual := resp.Header.Get("Content-Encoding")
  255. if actual != expected {
  256. t.Fatalf(`Unexpected header value, got %q instead of %q`, actual, expected)
  257. }
  258. }
  259. func TestBuildResponseWithoutCompressionHeader(t *testing.T) {
  260. body := strings.Repeat("a", compressionThreshold+1)
  261. r, err := http.NewRequest("GET", "/", nil)
  262. if err != nil {
  263. t.Fatal(err)
  264. }
  265. w := httptest.NewRecorder()
  266. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  267. New(w, r).WithBody(body).Write()
  268. })
  269. handler.ServeHTTP(w, r)
  270. resp := w.Result()
  271. expected := ""
  272. actual := resp.Header.Get("Content-Encoding")
  273. if actual != expected {
  274. t.Fatalf(`Unexpected header value, got %q instead of %q`, actual, expected)
  275. }
  276. }