Repository: getsentry/sentry-go (Go)

Issue:
Fiber integration: nil pointer dereference with malformed URLs when tracing enabled
### How do you use Sentry?

Sentry SaaS (sentry.io)

### SDK version

0.34.1

### Go version

1.23.0

### Are you using Go Modules?

yes

### Steps to reproduce

**Reproduction:**
```bash
curl "http://localhost:3000/%zz"
```

### Expected result

`{"message":"Catch-all route","params":"%zz","path":"/%zz"}`

### Actual result

**Stack Trace:**
```bash
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x38 pc=0x10844b4]

goroutine 7 [running]:
github.com/getsentry/sentry-go.NewRequest(0xc000074b40)
        F:/kodning/GO/sentry-fiber/sentry-go/interfaces.go:258 +0x114
github.com/getsentry/sentry-go.(*Scope).ApplyToEvent(0xc00017e2c0, 0xc000154588, 0x0, 0xc00021c000)
        F:/kodning/GO/sentry-fiber/sentry-go/scope.go:456 +0xc45
github.com/getsentry/sentry-go.(*Client).prepareEvent(0xc00021c000, 0xc000154588, 0x0, {0x12736c0, 0xc00017e2c0})
        F:/kodning/GO/sentry-fiber/sentry-go/client.go:724 +0x446
github.com/getsentry/sentry-go.(*Client).processEvent(0xc00021c000, 0xc00002f788?, 0x0, {0x12736c0, 0xc00017e2c0})
        F:/kodning/GO/sentry-fiber/sentry-go/client.go:647 +0x12e
github.com/getsentry/sentry-go.(*Client).CaptureEvent(...)
        F:/kodning/GO/sentry-fiber/sentry-go/client.go:447
github.com/getsentry/sentry-go.(*Hub).CaptureEvent(0xc0001b2150, 0xc000154588)
        F:/kodning/GO/sentry-fiber/sentry-go/hub.go:225 +0x6d
github.com/getsentry/sentry-go.(*Span).doFinish(0xc000074c80)
        F:/kodning/GO/sentry-fiber/sentry-go/tracing.go:374 +0x137
sync.(*Once).doSlow(0xc000074c80?, 0x11d4992?)
        C:/Program Files/Go/src/sync/once.go:76 +0xb4
sync.(*Once).Do(...)
        C:/Program Files/Go/src/sync/once.go:67
github.com/getsentry/sentry-go.(*Span).Finish(...)
        F:/kodning/GO/sentry-fiber/sentry-go/tracing.go:213
github.com/getsentry/sentry-go/fiber.(*handler).handle.func1()
        C:/Users/emanuel/go/pkg/mod/github.com/getsentry/sentry-go/fiber@v0.34.1/sentryfiber.go:92 +0x174
github.com/getsentry/sentry-go/fiber.(*handler).handle(0xc00020a100, 0xc000158608)
        C:/Users/emanuel/go/pkg/mod/github.com/getsentry/sentry-go/fiber@v0.34.1/sentryfiber.go:104 +0x502
github.com/gofiber/fiber/v2.(*Ctx).Next(0xc0002141e0?)
        C:/Users/emanuel/go/pkg/mod/github.com/gofiber/fiber/v2@v2.52.5/ctx.go:1031 +0x3d
github.com/gofiber/fiber/v2/middleware/logger.New.func3(0xc000158608)
        C:/Users/emanuel/go/pkg/mod/github.com/gofiber/fiber/v2@v2.52.5/middleware/logger/logger.go:119 +0x2ed
github.com/gofiber/fiber/v2.(*App).next(0xc00023c008, 0xc000158608)
        C:/Users/emanuel/go/pkg/mod/github.com/gofiber/fiber/v2@v2.52.5/router.go:145 +0x1be
github.com/gofiber/fiber/v2.(*App).handler(0xc00023c008, 0xe540ef?)
        C:/Users/emanuel/go/pkg/mod/github.com/gofiber/fiber/v2@v2.52.5/router.go:172 +0x69
github.com/valyala/fasthttp.(*Server).serveConn(0xc000246008, {0x12788b0, 0xc00005e168})
        C:/Users/emanuel/go/pkg/mod/github.com/valyala/fasthttp@v1.57.0/server.go:2385 +0xed1
github.com/valyala/fasthttp.(*workerPool).workerFunc(0xc000254090, 0xc000062b20)
        C:/Users/emanuel/go/pkg/mod/github.com/valyala/fasthttp@v1.57.0/workerpool.go:225 +0x92
github.com/valyala/fasthttp.(*workerPool).getCh.func1()
        C:/Users/emanuel/go/pkg/mod/github.com/valyala/fasthttp@v1.57.0/workerpool.go:197 +0x32
created by github.com/valyala/fasthttp.(*workerPool).getCh in goroutine 1
        C:/Users/emanuel/go/pkg/mod/github.com/valyala/fasthttp@v1.57.0/workerpool.go:196 +0x194
exit status 2
```` 


Discussion:

Patch:
diff --git a/fasthttp/sentryfasthttp.go b/fasthttp/sentryfasthttp.go
index 86b444ddc..9a078d958 100644
--- a/fasthttp/sentryfasthttp.go
+++ b/fasthttp/sentryfasthttp.go
@@ -152,9 +152,11 @@ func convert(ctx *fasthttp.RequestCtx) *http.Request {
 	r.Method = string(ctx.Method())
 
 	uri := ctx.URI()
-	url, err := url.Parse(fmt.Sprintf("%s://%s%s", uri.Scheme(), uri.Host(), uri.Path()))
-	if err == nil {
-		r.URL = url
+	r.URL = &url.URL{Path: string(uri.Path())}
+	r.URL.RawQuery = string(uri.QueryString())
+
+	if parsedURL, err := url.Parse(fmt.Sprintf("%s://%s%s", uri.Scheme(), uri.Host(), uri.Path())); err == nil {
+		r.URL = parsedURL
 		r.URL.RawQuery = string(uri.QueryString())
 	}
 
diff --git a/fiber/sentryfiber.go b/fiber/sentryfiber.go
index f8ce16dca..c26df18b3 100644
--- a/fiber/sentryfiber.go
+++ b/fiber/sentryfiber.go
@@ -152,9 +152,11 @@ func convert(ctx *fiber.Ctx) *http.Request {
 	r.Method = utils.CopyString(ctx.Method())
 
 	uri := ctx.Request().URI()
-	url, err := url.Parse(fmt.Sprintf("%s://%s%s", uri.Scheme(), uri.Host(), uri.Path()))
-	if err == nil {
-		r.URL = url
+	r.URL = &url.URL{Path: string(uri.Path())}
+	r.URL.RawQuery = string(uri.QueryString())
+
+	if parsedURL, err := url.Parse(fmt.Sprintf("%s://%s%s", uri.Scheme(), uri.Host(), uri.Path())); err == nil {
+		r.URL = parsedURL
 		r.URL.RawQuery = string(uri.QueryString())
 	}
 


Test patch:
diff --git a/fasthttp/sentryfasthttp_test.go b/fasthttp/sentryfasthttp_test.go
index 5600c42d3..c59b438f9 100644
--- a/fasthttp/sentryfasthttp_test.go
+++ b/fasthttp/sentryfasthttp_test.go
@@ -571,3 +571,35 @@ func TestSetHubOnContext(t *testing.T) {
 		t.Fatalf("expected hub to be %v, but got %v", hub, retrievedHub)
 	}
 }
+
+// TestMalformedURLNoPanic verifies that malformed URLs don't cause panics
+// when tracing is enabled
+func TestMalformedURLNoPanic(t *testing.T) {
+	err := sentry.Init(sentry.ClientOptions{
+		EnableTracing:    true,
+		TracesSampleRate: 1.0,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	sentryHandler := sentryfasthttp.New(sentryfasthttp.Options{})
+
+	handler := sentryHandler.Handle(func(ctx *fasthttp.RequestCtx) {
+		ctx.SetStatusCode(fasthttp.StatusOK)
+		ctx.SetBodyString("OK")
+	})
+
+	ctx := &fasthttp.RequestCtx{}
+	ctx.Request.SetRequestURI("http://localhost/%zz")
+	ctx.Request.Header.SetMethod("GET")
+	ctx.Request.SetHost("localhost")
+	ctx.Request.Header.Set("User-Agent", "fasthttp")
+
+	handler(ctx)
+
+	// Should complete successfully without panic
+	if ctx.Response.StatusCode() != fasthttp.StatusOK {
+		t.Errorf("Expected 200, got %d", ctx.Response.StatusCode())
+	}
+}
diff --git a/fiber/sentryfiber_test.go b/fiber/sentryfiber_test.go
index 842215e57..bf41fe6b2 100644
--- a/fiber/sentryfiber_test.go
+++ b/fiber/sentryfiber_test.go
@@ -4,6 +4,7 @@ import (
 	"errors"
 	"fmt"
 	"net/http"
+	"net/url"
 	"reflect"
 	"strings"
 	"testing"
@@ -594,3 +595,40 @@ func TestSetHubOnContext(t *testing.T) {
 		t.Fatalf("Expected status code %d, got %d", http.StatusOK, resp.StatusCode)
 	}
 }
+
+// TestMalformedURLNoPanic verifies that malformed URLs don't cause panics
+// when tracing is enabled,
+func TestMalformedURLNoPanic(t *testing.T) {
+	err := sentry.Init(sentry.ClientOptions{
+		EnableTracing:    true,
+		TracesSampleRate: 1.0,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	app := fiber.New()
+	app.Use(sentryfiber.New(sentryfiber.Options{Timeout: 3 * time.Second, WaitForDelivery: true}))
+
+	app.Get("/*", func(c *fiber.Ctx) error {
+		return c.SendString("OK")
+	})
+
+	req := &http.Request{
+		Method: "GET",
+		URL:    &url.URL{Scheme: "http", Host: "localhost", Path: "/%zz"},
+		Header: make(http.Header),
+		Host:   "localhost",
+	}
+	req.Header.Set("User-Agent", "fiber")
+
+	resp, err := app.Test(req)
+	if err != nil {
+		t.Fatalf("Request failed: %v", err)
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode != http.StatusOK {
+		t.Errorf("Expected 200, got %d", resp.StatusCode)
+	}
+}