From 966974599ab2be60f22d2163907be5ea9973f726 Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Wed, 27 May 2026 19:30:57 +0200 Subject: [PATCH] fix(client): added a guard to avoid the client to panic The client used to panic when hitting an unregistered producer. This now returns an error as we expect clients to explicitly register their content producers. * contributes go-swagger/go-swagger#3192 Signed-off-by: Frederic BIDON --- client/internal/request/request.go | 6 +++++- client/internal/request/request_test.go | 22 ++++++++++++++++++++++ client/runtime.go | 16 +++++++++------- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/client/internal/request/request.go b/client/internal/request/request.go index a736c578..22d3f64c 100644 --- a/client/internal/request/request.go +++ b/client/internal/request/request.go @@ -818,7 +818,11 @@ func (r *Request) writeStreamPayload(mediaType string, producers map[string]runt // The same reasoning applies to the form/multipart branch. func (r *Request) writeNonStreamPayload(mediaType string, producers map[string]runtime.Producer) (io.Reader, error) { r.header.Set(runtime.HeaderContentType, mediaType) - producer := producers[mediaType] + producer, ok := producers[mediaType] + if !ok { + return nil, fmt.Errorf("no producer registered for content type %q (register one with Runtime.Producers)", mediaType) + } + if err := producer.Produce(r.buf, r.payload); err != nil { return nil, err } diff --git a/client/internal/request/request_test.go b/client/internal/request/request_test.go index c5d157eb..6fc7de04 100644 --- a/client/internal/request/request_test.go +++ b/client/internal/request/request_test.go @@ -236,6 +236,28 @@ func TestBuildRequest_BuildHTTP_Payload(t *testing.T) { assert.Equal(t, append(expectedBody, '\n'), actualBody) } +// TestBuildRequest_BuildHTTP_UnregisteredProducer guards against a +// regression of go-swagger/go-swagger#3192: a non-stream payload sent +// with a media type that has no producer registered must surface an +// actionable error rather than panic on a nil-method dispatch. +func TestBuildRequest_BuildHTTP_UnregisteredProducer(t *testing.T) { + bd := []struct{ Name, Hobby string }{{valTom, valOregonTrail}} + reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error { + _ = req.SetBodyParam(bd) + return nil + }) + r := New(http.MethodPost, "/flats/", reqWrtr) + + const unregisteredMime = "application/x-not-registered" + req, cancel, err := r.BuildHTTPContext(t.Context(), unregisteredMime, "", testProducers, nil, nil) + t.Cleanup(cancel) + + require.Error(t, err) + assert.Nil(t, req) + assert.Contains(t, err.Error(), unregisteredMime) + assert.Contains(t, err.Error(), "no producer registered") +} + func TestBuildRequest_BuildHTTP_SetsInAuth(t *testing.T) { bd := []struct{ Name, Hobby string }{{valTom, valOregonTrail}, {valJohn, valBirdWatching}} reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error { diff --git a/client/runtime.go b/client/runtime.go index 604fb0ea..b890f9f4 100644 --- a/client/runtime.go +++ b/client/runtime.go @@ -95,13 +95,15 @@ func New(host, basePath string, schemes []string) *Runtime { // Enhancement proposal: https://github.com/go-openapi/runtime/issues/385 rt.Consumers = map[string]runtime.Consumer{ - runtime.YAMLMime: yamlpc.YAMLConsumer(), - runtime.JSONMime: runtime.JSONConsumer(), - runtime.XMLMime: runtime.XMLConsumer(), - runtime.TextMime: runtime.TextConsumer(), - runtime.HTMLMime: runtime.TextConsumer(), - runtime.CSVMime: runtime.CSVConsumer(), - runtime.DefaultMime: runtime.ByteStreamConsumer(), + runtime.YAMLMime: yamlpc.YAMLConsumer(), + runtime.JSONMime: runtime.JSONConsumer(), + runtime.XMLMime: runtime.XMLConsumer(), + runtime.TextMime: runtime.TextConsumer(), + runtime.HTMLMime: runtime.TextConsumer(), + runtime.CSVMime: runtime.CSVConsumer(), + runtime.MultipartFormMime: runtime.ByteStreamConsumer(), + runtime.URLencodedFormMime: runtime.ByteStreamConsumer(), + runtime.DefaultMime: runtime.ByteStreamConsumer(), } rt.Producers = map[string]runtime.Producer{ runtime.YAMLMime: yamlpc.YAMLProducer(),