ソースを参照

fix(response): 204 responses should not include the Content-Type header

Frédéric Guillot 2 週間 前
コミット
925b05f912

+ 1 - 1
internal/api/api_key_handlers.go

@@ -64,5 +64,5 @@ func (h *handler) deleteAPIKeyHandler(w http.ResponseWriter, r *http.Request) {
 		response.JSONServerError(w, r, err)
 		return
 	}
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }

+ 3 - 3
internal/api/category_handlers.go

@@ -106,7 +106,7 @@ func (h *handler) markCategoryAsReadHandler(w http.ResponseWriter, r *http.Reque
 		return
 	}
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }
 
 func (h *handler) getCategoriesHandler(w http.ResponseWriter, r *http.Request) {
@@ -146,7 +146,7 @@ func (h *handler) removeCategoryHandler(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }
 
 func (h *handler) refreshCategoryHandler(w http.ResponseWriter, r *http.Request) {
@@ -181,5 +181,5 @@ func (h *handler) refreshCategoryHandler(w http.ResponseWriter, r *http.Request)
 
 	go h.pool.Push(jobs)
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }

+ 1 - 1
internal/api/enclosure_handlers.go

@@ -85,5 +85,5 @@ func (h *handler) updateEnclosureByIDHandler(w http.ResponseWriter, r *http.Requ
 		return
 	}
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }

+ 2 - 2
internal/api/entry_handlers.go

@@ -221,7 +221,7 @@ func (h *handler) setEntryStatusHandler(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }
 
 func (h *handler) toggleStarredHandler(w http.ResponseWriter, r *http.Request) {
@@ -236,7 +236,7 @@ func (h *handler) toggleStarredHandler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }
 
 func (h *handler) saveEntryHandler(w http.ResponseWriter, r *http.Request) {

+ 4 - 4
internal/api/feed_handlers.go

@@ -70,7 +70,7 @@ func (h *handler) refreshFeedHandler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }
 
 func (h *handler) refreshAllFeedsHandler(w http.ResponseWriter, r *http.Request) {
@@ -97,7 +97,7 @@ func (h *handler) refreshAllFeedsHandler(w http.ResponseWriter, r *http.Request)
 
 	go h.pool.Push(jobs)
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }
 
 func (h *handler) updateFeedHandler(w http.ResponseWriter, r *http.Request) {
@@ -165,7 +165,7 @@ func (h *handler) markFeedAsReadHandler(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }
 
 func (h *handler) getCategoryFeedsHandler(w http.ResponseWriter, r *http.Request) {
@@ -256,5 +256,5 @@ func (h *handler) removeFeedHandler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }

+ 2 - 2
internal/api/user_handlers.go

@@ -122,7 +122,7 @@ func (h *handler) markUserAsReadHandler(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }
 
 func (h *handler) getIntegrationsStatusHandler(w http.ResponseWriter, r *http.Request) {
@@ -243,5 +243,5 @@ func (h *handler) removeUserHandler(w http.ResponseWriter, r *http.Request) {
 	}
 
 	h.store.RemoveUserAsync(user.ID)
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }

+ 0 - 8
internal/http/response/json.go

@@ -43,14 +43,6 @@ func JSONCreated(w http.ResponseWriter, r *http.Request, body any) {
 	builder.Write()
 }
 
-// JSONNoContent sends a no content response to the client.
-func JSONNoContent(w http.ResponseWriter, r *http.Request) {
-	builder := NewBuilder(w, r)
-	builder.WithStatus(http.StatusNoContent)
-	builder.WithHeader("Content-Type", jsonContentTypeHeader)
-	builder.Write()
-}
-
 // JSONAccepted sends an accepted response to the client.
 func JSONAccepted(w http.ResponseWriter, r *http.Request) {
 	builder := NewBuilder(w, r)

+ 0 - 28
internal/http/response/json_test.go

@@ -68,34 +68,6 @@ func TestJSONCreatedResponse(t *testing.T) {
 	}
 }
 
-func TestJSONNoContentResponse(t *testing.T) {
-	r, err := http.NewRequest("GET", "/", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	w := httptest.NewRecorder()
-
-	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		JSONNoContent(w, r)
-	})
-
-	handler.ServeHTTP(w, r)
-	resp := w.Result()
-
-	if resp.StatusCode != http.StatusNoContent {
-		t.Fatalf(`Unexpected status code, got %d instead of %d`, resp.StatusCode, http.StatusNoContent)
-	}
-
-	if actualBody := w.Body.String(); actualBody != `` {
-		t.Fatalf(`Unexpected body, got %s instead of %s`, actualBody, ``)
-	}
-
-	if actualContentType := resp.Header.Get("Content-Type"); actualContentType != jsonContentTypeHeader {
-		t.Fatalf(`Unexpected content type, got %q instead of %q`, actualContentType, jsonContentTypeHeader)
-	}
-}
-
 func TestJSONAcceptedResponse(t *testing.T) {
 	r, err := http.NewRequest("GET", "/", nil)
 	if err != nil {

+ 9 - 0
internal/http/response/response.go

@@ -3,6 +3,8 @@
 
 package response // import "miniflux.app/v2/internal/http/response"
 
+import "net/http"
+
 // ContentSecurityPolicyForUntrustedContent is the default CSP for untrusted content.
 // default-src 'none' disables all content sources
 // form-action 'none' disables all form submissions
@@ -12,3 +14,10 @@ package response // import "miniflux.app/v2/internal/http/response"
 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox
 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src
 const ContentSecurityPolicyForUntrustedContent = `default-src 'none'; form-action 'none'; sandbox;`
+
+// NoContent sends a no content response to the client.
+func NoContent(w http.ResponseWriter, r *http.Request) {
+	builder := NewBuilder(w, r)
+	builder.WithStatus(http.StatusNoContent)
+	builder.Write()
+}

+ 38 - 0
internal/http/response/response_test.go

@@ -0,0 +1,38 @@
+// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package response // import "miniflux.app/v2/internal/http/response"
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"testing"
+)
+
+func TestNoContentResponse(t *testing.T) {
+	r, err := http.NewRequest("GET", "/", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	w := httptest.NewRecorder()
+
+	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		NoContent(w, r)
+	})
+
+	handler.ServeHTTP(w, r)
+	resp := w.Result()
+
+	if resp.StatusCode != http.StatusNoContent {
+		t.Fatalf(`Unexpected status code, got %d instead of %d`, resp.StatusCode, http.StatusNoContent)
+	}
+
+	if actualBody := w.Body.String(); actualBody != `` {
+		t.Fatalf(`Unexpected body, got %s instead of %s`, actualBody, ``)
+	}
+
+	if actualContentType := resp.Header.Get("Content-Type"); actualContentType != "" {
+		t.Fatalf(`Unexpected content type, got %q instead of empty string`, actualContentType)
+	}
+}

+ 3 - 3
internal/ui/webauthn.go

@@ -335,7 +335,7 @@ func (h *handler) finishLogin(w http.ResponseWriter, r *http.Request) {
 		config.Opts.BasePath(),
 	))
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }
 
 func (h *handler) renameCredential(w http.ResponseWriter, r *http.Request) {
@@ -421,7 +421,7 @@ func (h *handler) deleteCredential(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }
 
 func (h *handler) deleteAllCredentials(w http.ResponseWriter, r *http.Request) {
@@ -430,5 +430,5 @@ func (h *handler) deleteAllCredentials(w http.ResponseWriter, r *http.Request) {
 		response.JSONServerError(w, r, err)
 		return
 	}
-	response.JSONNoContent(w, r)
+	response.NoContent(w, r)
 }