diff --git a/internal/server/http/attachments.go b/internal/server/http/attachments.go index 9e54b0a..e4e906f 100644 --- a/internal/server/http/attachments.go +++ b/internal/server/http/attachments.go @@ -9,18 +9,26 @@ import ( ) // RegisterAttachmentAPI registers attachment list/download/preview endpoints. +// +// Routes are namespaced under a literal `attachments` segment rather than +// `/api/{module}/{eventUuid}/attachments/...`. The previous layout used a +// wildcard at position 2, which collides with module routes like +// `/api/smtp/message/{uuid}/raw` (both 4-segment patterns, neither more +// specific) and made the server panic at startup. func RegisterAttachmentAPI(mux *http.ServeMux, db *sql.DB, store *storage.AttachmentStore) { // SMTP attachments. - mux.HandleFunc("GET /api/smtp/{uuid}/attachments", listAttachments(db, "smtp_attachments")) - mux.HandleFunc("GET /api/smtp/{eventUuid}/attachments/{uuid}", downloadAttachment(db, store, "smtp_attachments")) - mux.HandleFunc("GET /api/smtp/{eventUuid}/attachments/preview/{uuid}", previewAttachment(db, store, "smtp_attachments")) - - // HTTP Dump attachments (support both /http-dump/ and /http-dumps/ paths). - for _, prefix := range []string{"/api/http-dump/", "/api/http-dumps/"} { - mux.HandleFunc("GET "+prefix+"{uuid}/attachments", listAttachments(db, "http_dump_attachments")) - mux.HandleFunc("GET "+prefix+"{eventUuid}/attachments/{uuid}", downloadAttachment(db, store, "http_dump_attachments")) - mux.HandleFunc("GET "+prefix+"{eventUuid}/attachments/preview/{uuid}", previewAttachment(db, store, "http_dump_attachments")) - } + registerAttachmentsForModule(mux, db, store, "/api/smtp/attachments", "smtp_attachments") + + // HTTP Dump attachments (support both /http-dump/ and /http-dumps/ paths + // for backwards compatibility with existing clients). + registerAttachmentsForModule(mux, db, store, "/api/http-dump/attachments", "http_dump_attachments") + registerAttachmentsForModule(mux, db, store, "/api/http-dumps/attachments", "http_dump_attachments") +} + +func registerAttachmentsForModule(mux *http.ServeMux, db *sql.DB, store *storage.AttachmentStore, prefix, table string) { + mux.HandleFunc("GET "+prefix+"/{uuid}", listAttachments(db, table)) + mux.HandleFunc("GET "+prefix+"/{eventUuid}/{uuid}", downloadAttachment(db, store, table)) + mux.HandleFunc("GET "+prefix+"/{eventUuid}/preview/{uuid}", previewAttachment(db, store, table)) } func listAttachments(db *sql.DB, table string) http.HandlerFunc { diff --git a/internal/server/http/attachments_test.go b/internal/server/http/attachments_test.go new file mode 100644 index 0000000..de11143 --- /dev/null +++ b/internal/server/http/attachments_test.go @@ -0,0 +1,41 @@ +package http_test + +import ( + "net/http" + "testing" + + serverhttp "github.com/buggregator/go-buggregator/internal/server/http" + "github.com/buggregator/go-buggregator/internal/storage" + smtpmod "github.com/buggregator/go-buggregator/modules/smtp" +) + +// TestRegisterAttachmentAPI_NoConflictWithSMTPRoutes ensures the attachment +// routes can co-exist on the same mux as the SMTP module's message routes. +// +// Prior layout used `/api/smtp/{eventUuid}/attachments/{uuid}` which collides +// with `/api/smtp/message/{uuid}/raw` (both 4-segment patterns, neither more +// specific), and Go's ServeMux panics at registration time. This test fails +// the same way if the conflict ever returns. +func TestRegisterAttachmentAPI_NoConflictWithSMTPRoutes(t *testing.T) { + db, err := storage.Open(":memory:") + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { db.Close() }) + + attachments := storage.NewAttachmentStore("memory", "") + mux := http.NewServeMux() + + // Order intentionally interleaves attachment + SMTP module routes to + // mirror app startup. + defer func() { + if r := recover(); r != nil { + t.Fatalf("route registration panicked: %v", r) + } + }() + + serverhttp.RegisterAttachmentAPI(mux, db, attachments) + + mod := smtpmod.New(":0", attachments, db) + mod.RegisterRoutes(mux, nil) +} diff --git a/modules/httpdumps/handler.go b/modules/httpdumps/handler.go index 0b630a8..6b11dde 100644 --- a/modules/httpdumps/handler.go +++ b/modules/httpdumps/handler.go @@ -106,7 +106,7 @@ func (h *handler) Handle(r *http.Request) (*event.Incoming, error) { "name": fh.Filename, "size": len(content), "mime": mime, - "uri": "/api/http-dump/" + eventUUID + "/attachments/" + attUUID, + "uri": "/api/http-dump/attachments/" + eventUUID + "/" + attUUID, }) } }