mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-14 05:18:54 +00:00
fix(media): strip alias key on audio speech path
This commit is contained in:
@@ -124,6 +124,16 @@ func (g *Gateway) handleAudioSpeech(w http.ResponseWriter, r *http.Request, u *u
|
||||
return
|
||||
}
|
||||
req["model"] = upstreamModel
|
||||
// gatewayAliasKey must never reach the real provider, mirroring
|
||||
// openaiAdapter.imagesGeneration's identical delete
|
||||
// (provider_openai.go): routes_media.go never sets this key itself
|
||||
// for a media route, but a client independently sending a literal
|
||||
// "__alias" field of its own would otherwise survive the re-marshal
|
||||
// below and leak straight through as an unrecognized request field.
|
||||
// Unconditional, not conditional on whether the gateway set it — the
|
||||
// same defensive posture chatCompletion/embeddings/imagesGeneration
|
||||
// already take.
|
||||
delete(req, gatewayAliasKey)
|
||||
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
|
||||
@@ -373,6 +373,40 @@ func TestHandleAudioSpeech_OpenAI_StreamsBinary_WithFlushes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandleAudioSpeech_StripsClientSuppliedAliasKey mirrors
|
||||
// TestHandleImagesGenerations_StripsClientSuppliedAliasKey: a client
|
||||
// independently including a literal "__alias" field in its own JSON body
|
||||
// (never one the gateway itself injects for a media route —
|
||||
// routes_media.go never sets gatewayAliasKey here) must never reach the
|
||||
// upstream provider. handleAudioSpeech re-marshals req into the []byte
|
||||
// body it hands openaiAdapter.audioSpeech, so the delete has to happen
|
||||
// in routes_media.go itself rather than in the adapter (audioSpeech's
|
||||
// interface method takes []byte, not a map, unlike imagesGeneration).
|
||||
func TestHandleAudioSpeech_StripsClientSuppliedAliasKey(t *testing.T) {
|
||||
var gotBody map[string]any
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_ = json.NewDecoder(r.Body).Decode(&gotBody)
|
||||
w.Header().Set("Content-Type", "audio/mpeg")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("fake-audio-bytes"))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
gw := newMediaTestGateway(t, newMediaTestConfig(srv.URL, "tts-test"))
|
||||
|
||||
body := map[string]any{"model": "tts-test", "input": "hello", gatewayAliasKey: "sneaky-client-value"}
|
||||
req := newUnifiedRequest(t, http.MethodPost, audioSpeechPath, "sk-alice", body)
|
||||
rec := httptest.NewRecorder()
|
||||
gw.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, want 200, body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if _, leaked := gotBody[gatewayAliasKey]; leaked {
|
||||
t.Errorf("upstream request body leaked client-supplied %q: %v", gatewayAliasKey, gotBody)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAudioSpeech_MissingModel_400(t *testing.T) {
|
||||
gw := newMediaTestGateway(t, newMediaTestConfig("http://127.0.0.1:1", "tts-test"))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user