mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-19 09:06:14 +00:00
Fix Content-Type and status code in Marge AddRecent handler
- Reorder header setting and WriteHeader calls in HandleMargeAddRecent to ensure Content-Type is correctly sent. - Update HandleMargeAddRecent to explicitly use 201 Created status code. - Improve parity mismatch logging to correctly capture headers from local handlers. - Enhance mirroring logic to support local testing of upstream parity.
This commit is contained in:
@@ -300,6 +300,7 @@ func (s *Server) HandleMargeAddRecent(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/vnd.bose.streaming-v1.2+xml")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
_, _ = w.Write(data)
|
||||
}
|
||||
|
||||
|
||||
@@ -320,8 +320,8 @@ func TestMargeAddRecentRoute(t *testing.T) {
|
||||
|
||||
defer func() { _ = res.Body.Close() }()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Errorf("Expected status OK, got %v", res.Status)
|
||||
if res.StatusCode != http.StatusCreated {
|
||||
t.Errorf("Expected status Created, got %v", res.Status)
|
||||
}
|
||||
|
||||
// Verify file was saved
|
||||
@@ -389,9 +389,9 @@ func TestMargeNativeStreamingRoutes(t *testing.T) {
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
if res.StatusCode != http.StatusCreated {
|
||||
body, _ := io.ReadAll(res.Body)
|
||||
t.Errorf("Expected status OK, got %v: %s", res.Status, string(body))
|
||||
t.Errorf("Expected status Created, got %v: %s", res.Status, string(body))
|
||||
}
|
||||
|
||||
if ct := res.Header.Get("Content-Type"); ct != "application/vnd.bose.streaming-v1.2+xml" {
|
||||
|
||||
@@ -116,26 +116,42 @@ type parityResponseWriter struct {
|
||||
}
|
||||
|
||||
func (p *parityResponseWriter) Header() http.Header {
|
||||
return p.ResponseWriter.Header()
|
||||
return p.recorder.Header()
|
||||
}
|
||||
|
||||
func (p *parityResponseWriter) Write(b []byte) (int, error) {
|
||||
if p.recorder.status == 0 {
|
||||
p.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
p.recorder.body.Write(b)
|
||||
|
||||
return p.ResponseWriter.Write(b)
|
||||
}
|
||||
|
||||
func (p *parityResponseWriter) WriteHeader(statusCode int) {
|
||||
p.recorder.status = statusCode
|
||||
// Copy headers to the real response writer before writing the header
|
||||
for k, vv := range p.recorder.headers {
|
||||
for _, v := range vv {
|
||||
p.ResponseWriter.Header().Add(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
p.ResponseWriter.WriteHeader(statusCode)
|
||||
}
|
||||
|
||||
func (s *Server) performMirror(r *http.Request) *mirrorResponseRecorder {
|
||||
host := r.Host
|
||||
if host == "" || host == "localhost" || strings.HasPrefix(host, "127.0.0.1") {
|
||||
if host == "" || host == "localhost" {
|
||||
host = "streaming.bose.com"
|
||||
}
|
||||
|
||||
scheme := "https"
|
||||
if strings.HasPrefix(host, "127.0.0.1") || strings.HasPrefix(host, "localhost") {
|
||||
scheme = "http"
|
||||
}
|
||||
|
||||
targetURL := scheme + "://" + host
|
||||
|
||||
target, err := url.Parse(targetURL)
|
||||
@@ -231,12 +247,14 @@ func (s *Server) saveParityMismatch(req *http.Request, local, upstream *mirrorRe
|
||||
"path": req.URL.Path,
|
||||
"reasons": reasons,
|
||||
"local": map[string]interface{}{
|
||||
"status": local.status,
|
||||
"body": local.body.String(),
|
||||
"status": local.status,
|
||||
"headers": local.headers,
|
||||
"body": local.body.String(),
|
||||
},
|
||||
"upstream": map[string]interface{}{
|
||||
"status": upstream.status,
|
||||
"body": upstream.body.String(),
|
||||
"status": upstream.status,
|
||||
"headers": upstream.headers,
|
||||
"body": upstream.body.String(),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
@@ -57,7 +58,8 @@ func TestMirroring(t *testing.T) {
|
||||
_ = os.WriteFile(filepath.Join(deviceDir, "Sources.xml"), []byte("<sources/>"), 0644)
|
||||
|
||||
t.Run("Mirrored Endpoint", func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", ts.URL+"/streaming/account/"+account+"/device/"+deviceID+"/recent", nil)
|
||||
path := "/streaming/account/" + account + "/device/" + deviceID + "/recent"
|
||||
req, _ := http.NewRequest("GET", ts.URL+path, nil)
|
||||
// We set the host to our mock upstream so performMirror finds it
|
||||
req.Host = strings.TrimPrefix(boseUpstream.URL, "http://")
|
||||
|
||||
@@ -91,6 +93,50 @@ func TestMirroring(t *testing.T) {
|
||||
t.Errorf("Expected to find mirrored interaction in logs (category: mirror). Found: %v", files)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Parity Mismatch Header Capture", func(t *testing.T) {
|
||||
// The previous test already triggered a mismatch because the bodies and content-types differ
|
||||
// local: <recents/> (from file), content-type: text/xml (default)
|
||||
// upstream: <bose-response/>, content-type: application/vnd.bose.streaming-v1.2+xml
|
||||
|
||||
matchesMismatch, _ := filepath.Glob(filepath.Join(tempDir, "parity_mismatches", "*.json"))
|
||||
if len(matchesMismatch) == 0 {
|
||||
t.Fatal("Expected to find parity mismatch JSON file")
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(matchesMismatch[0])
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read mismatch file: %v", err)
|
||||
}
|
||||
|
||||
var record struct {
|
||||
Local struct {
|
||||
Headers http.Header `json:"headers"`
|
||||
} `json:"local"`
|
||||
Upstream struct {
|
||||
Headers http.Header `json:"headers"`
|
||||
} `json:"upstream"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &record); err != nil {
|
||||
t.Fatalf("Failed to unmarshal mismatch record: %v", err)
|
||||
}
|
||||
|
||||
if len(record.Local.Headers) == 0 {
|
||||
t.Error("Expected local headers in parity mismatch, got none")
|
||||
}
|
||||
if len(record.Upstream.Headers) == 0 {
|
||||
t.Error("Expected upstream headers in parity mismatch, got none")
|
||||
}
|
||||
|
||||
// Check specifically for Content-Type
|
||||
if ct := record.Local.Headers.Get("Content-Type"); ct == "" {
|
||||
t.Error("Expected Content-Type in local headers")
|
||||
}
|
||||
if ct := record.Upstream.Headers.Get("Content-Type"); ct != "application/vnd.bose.streaming-v1.2+xml" {
|
||||
t.Errorf("Expected Upstream Content-Type application/vnd.bose.streaming-v1.2+xml, got %s", ct)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// SetRecordEnabled is a helper for testing
|
||||
|
||||
Reference in New Issue
Block a user