From 26ff1afc44bad02f33e59fae7df1ec8792d218f3 Mon Sep 17 00:00:00 2001 From: Martin Rode Date: Fri, 12 Jul 2024 13:10:23 +0200 Subject: [PATCH] smtp server support improvements, added stuff to readme This allows multiple "header" url parameters to be sent. --- README.md | 2 ++ go.mod | 2 +- go.sum | 2 ++ http_server.go | 2 +- internal/handlerutil/util.go | 2 +- internal/smtp/http.go | 69 ++++++++++++++++-------------------- internal/smtp/server.go | 3 +- 7 files changed, 38 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 6bb5527..9041165 100644 --- a/README.md +++ b/README.md @@ -2964,6 +2964,8 @@ available as JSON in the following schema: } ``` +> You can filter messages by passing one of more query parameters `header`. `header` can either be a JSON array of strings, or just a string. The filter checks that all headers (regexp format) match headers of the filtered email. + Headers that were encoded according to RFC2047 are decoded first. #### /smtp/$idx diff --git a/go.mod b/go.mod index ca10b0c..d1af656 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/moul/http2curl v1.0.0 github.com/pkg/errors v0.9.1 github.com/programmfabrik/go-test-utils v0.0.0-20191114143449-b8e16b04adb1 - github.com/programmfabrik/golib v0.0.0-20240226091422-733aede66819 + github.com/programmfabrik/golib v0.0.0-20240701125551-843bc5e3be55 github.com/sergi/go-diff v1.3.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/afero v1.9.5 diff --git a/go.sum b/go.sum index e631efd..7095796 100644 --- a/go.sum +++ b/go.sum @@ -219,6 +219,8 @@ github.com/programmfabrik/go-test-utils v0.0.0-20191114143449-b8e16b04adb1 h1:Nb github.com/programmfabrik/go-test-utils v0.0.0-20191114143449-b8e16b04adb1/go.mod h1:6Tg7G+t9KYiFa0sU8PpISt9RUgIpgrEI+tXvWz3tSIU= github.com/programmfabrik/golib v0.0.0-20240226091422-733aede66819 h1:lJ+a0MLo4Dn2UTF0Q/nh9msLqP8MaNEL/RbJLop022g= github.com/programmfabrik/golib v0.0.0-20240226091422-733aede66819/go.mod h1:qb4pSUhPsZ/UfvM/MBNwKHb6W7xL85uSi4od9emNHHw= +github.com/programmfabrik/golib v0.0.0-20240701125551-843bc5e3be55 h1:VBYGpSvjwHSa5ARrs6uPlUOJF1+n6rFWn49+++h20IU= +github.com/programmfabrik/golib v0.0.0-20240701125551-843bc5e3be55/go.mod h1:qb4pSUhPsZ/UfvM/MBNwKHb6W7xL85uSi4od9emNHHw= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= diff --git a/http_server.go b/http_server.go index f4a4411..0225014 100644 --- a/http_server.go +++ b/http_server.go @@ -234,7 +234,7 @@ func logH(skipLog bool, next http.Handler) http.Handler { return next } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - logrus.Debugf("http-server: %s: %q", r.Method, r.URL) + // logrus.Debugf("http-server: %s: %q", r.Method, r.URL) next.ServeHTTP(w, r) }) } diff --git a/internal/handlerutil/util.go b/internal/handlerutil/util.go index 9f4b6cd..a1bacd7 100644 --- a/internal/handlerutil/util.go +++ b/internal/handlerutil/util.go @@ -18,7 +18,7 @@ func LogH(skipLogs bool, next http.Handler) http.Handler { return next } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - logrus.Debugf("http-server: %s: %q", r.Method, r.URL) + // logrus.Debugf("http-server: %s: %q", r.Method, r.URL) next.ServeHTTP(w, r) }) } diff --git a/internal/smtp/http.go b/internal/smtp/http.go index f0f9ddc..7046ffd 100644 --- a/internal/smtp/http.go +++ b/internal/smtp/http.go @@ -9,6 +9,7 @@ import ( "io" "net/http" "net/mail" + "net/url" "path" "regexp" "strconv" @@ -17,6 +18,7 @@ import ( "github.com/Masterminds/sprig/v3" "github.com/programmfabrik/apitest/internal/handlerutil" + "github.com/programmfabrik/golib" "github.com/sirupsen/logrus" ) @@ -220,21 +222,14 @@ func (h *smtpHTTPHandler) handleGUIIndex(w http.ResponseWriter, r *http.Request) func (h *smtpHTTPHandler) handleGUIMessage(w http.ResponseWriter, r *http.Request, msg *ReceivedMessage) { metadata := buildMessageFullMeta(msg) - metadataJson, err := json.MarshalIndent(metadata, "", " ") - if err != nil { - handlerutil.RespondWithErr( - w, http.StatusInternalServerError, - fmt.Errorf("could not build metadata JSON: %w", err), - ) - return - } + metadataJson := golib.JsonStringIndent(metadata, "", " ") w.Header().Set("Content-Type", "text/html; charset=utf-8") - err = guiMessageTemplate.Execute(w, map[string]any{ + err := guiMessageTemplate.Execute(w, map[string]any{ "prefix": h.prefix, "metadata": metadata, - "metadataJson": string(metadataJson), + "metadataJson": metadataJson, }) if err != nil { logrus.Error("error rendering GUI Message:", err) @@ -242,7 +237,7 @@ func (h *smtpHTTPHandler) handleGUIMessage(w http.ResponseWriter, r *http.Reques } func (h *smtpHTTPHandler) handleMessageIndex(w http.ResponseWriter, r *http.Request) { - headerSearchRxs, err := extractSearchRegexes(w, r.URL.Query(), "header") + headerSearchRxs, err := extractSearchRegexes(r.URL.Query(), "header") if err != nil { handlerutil.RespondWithErr(w, http.StatusBadRequest, err) return @@ -276,7 +271,7 @@ func (h *smtpHTTPHandler) handleMessageRaw(w http.ResponseWriter, r *http.Reques } func (h *smtpHTTPHandler) handleMultipartIndex(w http.ResponseWriter, r *http.Request, c *ReceivedContent) { - headerSearchRxs, err := extractSearchRegexes(w, r.URL.Query(), "header") + headerSearchRxs, err := extractSearchRegexes(r.URL.Query(), "header") if err != nil { handlerutil.RespondWithErr(w, http.StatusBadRequest, err) return @@ -478,39 +473,35 @@ func buildMultipartMeta(part *ReceivedPart) map[string]any { // extractSearchRegexes tries to extract the regular expression(s) from the // referenced query parameter. If no query parameter is given and otherwise // no error has occurred, this function returns no error. -func extractSearchRegexes( - w http.ResponseWriter, queryParams map[string][]string, paramName string, -) ([]*regexp.Regexp, error) { - filteredParams, ok := queryParams[paramName] - if ok { - if len(filteredParams) != 1 { - return nil, fmt.Errorf( - "expected 1 %q query parameter, got %d (use JSON array for multiple queries)", - paramName, len(filteredParams), - ) +func extractSearchRegexes(qp url.Values, paramName string) (rgs []*regexp.Regexp, err error) { + if !qp.Has(paramName) { + return nil, nil + } + defer func() { + if err == nil { + println(fmt.Sprintf("%v", rgs)) } + }() + sp := []string{} + for _, v := range qp[paramName] { var searchParams []string - err := json.Unmarshal([]byte(filteredParams[0]), &searchParams) - if err != nil { - searchParams = []string{filteredParams[0]} + err := json.Unmarshal([]byte(v), &searchParams) + if err == nil { + sp = append(sp, searchParams...) + } else { + // this is not a JSON string array, assume string + sp = append(sp, v) } + } - out := make([]*regexp.Regexp, len(searchParams)) - - for i, p := range searchParams { - re, err := regexp.Compile(p) - if err != nil { - return nil, fmt.Errorf( - "could not compile %q regex %q: %w", paramName, p, err, - ) - } - - out[i] = re + for _, p := range sp { + re, err := regexp.Compile(p) + if err != nil { + return nil, fmt.Errorf("could not compile %q regex %q: %w", paramName, p, err) } - - return out, nil + rgs = append(rgs, re) } - return nil, nil + return rgs, nil } diff --git a/internal/smtp/server.go b/internal/smtp/server.go index 1a7c2ee..a169a86 100644 --- a/internal/smtp/server.go +++ b/internal/smtp/server.go @@ -141,7 +141,6 @@ func (s *session) Data(r io.Reader) error { idx := len(s.server.receivedMessages) now := s.server.clock() - logrus.Infof("SMTP: Receiving message from %s to %v at %v", s.from, s.rcptTo, now) msg, err := NewReceivedMessage( idx, s.from, s.rcptTo, rawData, now, s.server.maxMessageSize, ) @@ -150,7 +149,7 @@ func (s *session) Data(r io.Reader) error { logrus.Error("SMTP:", errWrapped) // this is logged in our server return errWrapped // this is returned via SMTP } - logrus.Infof("SMTP: Reception successful") + logrus.Debugf("SMTP: Message from %s to %v at %v", s.from, s.rcptTo, now.Format(time.DateTime)) s.server.receivedMessages = append(s.server.receivedMessages, msg)