From 1e330cf17579b6205a2a923ffc9aa77411e2e3af Mon Sep 17 00:00:00 2001 From: Alexander Dahmen Date: Mon, 9 Dec 2024 10:08:53 +0100 Subject: [PATCH] fix(debug printer): Handle HTML encodings correctly Signed-off-by: Alexander Dahmen --- internal/pkg/print/debug.go | 20 ++++++++++++++++---- internal/pkg/print/debug_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/internal/pkg/print/debug.go b/internal/pkg/print/debug.go index d0927d8df..60962ba7b 100644 --- a/internal/pkg/print/debug.go +++ b/internal/pkg/print/debug.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net/http" + "net/url" "slices" "sort" "strings" @@ -141,13 +142,18 @@ func BuildDebugStrFromHTTPRequest(req *http.Request, includeHeaders []string) ([ return nil, fmt.Errorf("request is invalid") } - status := fmt.Sprintf("request to %s: %s %s", req.URL, req.Method, req.Proto) + // unescape url in order to get rid of e.g. %40 + unescapedURL, err := url.PathUnescape(req.URL.String()) + if err != nil { + return nil, fmt.Errorf("unescape request url: %w", err) + } + + status := fmt.Sprintf("request to %s: %s %s", unescapedURL, req.Method, req.Proto) headersMap := buildHeaderMap(req.Header, includeHeaders) headers := fmt.Sprintf("request headers: %v", BuildDebugStrFromMap(headersMap)) var save io.ReadCloser - var err error save, req.Body, err = drainBody(req.Body) if err != nil { @@ -184,13 +190,19 @@ func BuildDebugStrFromHTTPResponse(resp *http.Response, includeHeaders []string) return nil, fmt.Errorf("response is invalid") } - status := fmt.Sprintf("response from %s: %s %s", resp.Request.URL, resp.Proto, resp.Status) + var err error + // unescape url in order to get rid of e.g. %40 + unescapedURL, err := url.PathUnescape(resp.Request.URL.String()) + if err != nil { + return nil, fmt.Errorf("unescape response url: %w", err) + } + + status := fmt.Sprintf("response from %s: %s %s", unescapedURL, resp.Proto, resp.Status) headersMap := buildHeaderMap(resp.Header, includeHeaders) headers := fmt.Sprintf("response headers: %v", BuildDebugStrFromMap(headersMap)) var save io.ReadCloser - var err error save, resp.Body, err = drainBody(resp.Body) if err != nil { diff --git a/internal/pkg/print/debug_test.go b/internal/pkg/print/debug_test.go index 35c3dfb6a..45ef90482 100644 --- a/internal/pkg/print/debug_test.go +++ b/internal/pkg/print/debug_test.go @@ -78,6 +78,28 @@ func fixtureHTTPRequest(mods ...func(req *http.Request)) *http.Request { return request } +func fixtureHTTPRequestUnescaped(mods ...func(req *http.Request)) *http.Request { + testBody, err := json.Marshal(map[string]string{"key": "value"}) + if err != nil { + return nil + } + + request, err := http.NewRequest("GET", "http://example.com/v2/projects?limit=50&member=User.Name%40stackit.cloud", bytes.NewReader(testBody)) + if err != nil { + return nil + } + + request.Header.Set("Content-Type", "application/json") + request.Header.Set("Accept", "application/json") + request.Header.Set("Content-Length", "15") + + for _, mod := range mods { + mod(request) + } + + return request +} + func fixtureHTTPResponse(mods ...func(resp *http.Response)) *http.Response { testBody, err := json.Marshal(map[string]string{"key": "value"}) if err != nil { @@ -402,6 +424,16 @@ func TestBuildDebugStrFromHTTPRequest(t *testing.T) { }, isValid: true, }, + { + description: "unescaped test", + inputReq: fixtureHTTPRequestUnescaped(), + expected: []string{ + "request to http://example.com/v2/projects?limit=50&member=User.Name@stackit.cloud: GET HTTP/1.1", + "request headers: [Accept: application/json, Content-Length: 15, Content-Type: application/json]", + "request body: [key: value]", + }, + isValid: true, + }, } for _, tt := range tests {