mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-19 17:16:16 +00:00
Prevent loops for proxied requests on unknown endpoints (#166)
Follow-up for https://github.com/gesellix/Bose-SoundTouch/issues/161
This commit is contained in:
@@ -15,6 +15,13 @@ import (
|
||||
|
||||
// HandleProxyRequest handles requests to the logging proxy.
|
||||
func (s *Server) HandleProxyRequest(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get("X-Bose-Proxy-Hop") != "" {
|
||||
log.Printf("[PROXY_LOOP] Loop detected for %s %s, breaking loop", r.Method, r.URL.Path)
|
||||
http.Error(w, "Loop detected", http.StatusNotFound)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
targetURLStr := strings.TrimPrefix(r.URL.Path, "/proxy/")
|
||||
if targetURLStr == "" {
|
||||
http.Error(w, "Target URL is required", http.StatusBadRequest)
|
||||
@@ -65,6 +72,8 @@ func (s *Server) ServeProxy(target *url.URL) http.HandlerFunc {
|
||||
pr.Out.URL.Path = target.Path
|
||||
}
|
||||
|
||||
pr.Out.Header.Set("X-Bose-Proxy-Hop", "1")
|
||||
|
||||
lp.LogRequest(pr.Out)
|
||||
},
|
||||
Transport: &http.Transport{
|
||||
@@ -101,6 +110,13 @@ func (s *Server) HandleNotFound(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// HandleBoseProxy proxies the request to the Bose upstream.
|
||||
func (s *Server) HandleBoseProxy(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get("X-Bose-Proxy-Hop") != "" {
|
||||
log.Printf("[PROXY_LOOP] Loop detected for %s %s, breaking loop", r.Method, r.URL.Path)
|
||||
http.Error(w, "Loop detected", http.StatusNotFound)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
host := r.Host
|
||||
if host == "" {
|
||||
host = "streaming.bose.com"
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gesellix/bose-soundtouch/pkg/service/datastore"
|
||||
)
|
||||
|
||||
func TestHandleBoseProxy_LoopPrevention(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "proxy-loop-test")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
ds := datastore.NewDataStore(filepath.Join(tmpDir, "test.db"))
|
||||
server := NewServer(ds, nil, "http://localhost", false, false, false)
|
||||
|
||||
t.Run("first hop should be allowed", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/unknown-endpoint", nil)
|
||||
req.Host = "localhost"
|
||||
w := httptest.NewRecorder()
|
||||
server.HandleBoseProxy(w, req)
|
||||
if w.Code == http.StatusNotFound {
|
||||
t.Errorf("Expected first hop to be allowed (even if it fails later), but got 404")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("second hop should be blocked", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/unknown-endpoint", nil)
|
||||
req.Host = "localhost"
|
||||
req.Header.Set("X-Bose-Proxy-Hop", "1")
|
||||
w := httptest.NewRecorder()
|
||||
server.HandleBoseProxy(w, req)
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("Expected second hop to be blocked with 404, but got %d", w.Code)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("HandleProxyRequest loop detection", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/proxy/http://example.com", nil)
|
||||
req.Header.Set("X-Bose-Proxy-Hop", "1")
|
||||
w := httptest.NewRecorder()
|
||||
server.HandleProxyRequest(w, req)
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("Expected HandleProxyRequest loop to be blocked with 404, but got %d", w.Code)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user