From eb08b7c66cb12f109ab816940511a920a7f68016 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 30 Oct 2023 14:10:36 -0500 Subject: [PATCH] Prevent all courier HTTP requests from accessing local networks --- attachments.go | 2 +- backend.go | 6 +++ backends/rapidpro/backend.go | 35 ++++++++++++++ config.go | 56 +++++++++++++++++----- go.mod | 2 +- go.sum | 4 +- handlers/africastalking/handler.go | 2 +- handlers/arabiacell/handler.go | 2 +- handlers/bandwidth/handler.go | 2 +- handlers/base.go | 32 +++++++++++++ handlers/{http_test.go => base_test.go} | 12 +++-- handlers/bongolive/handler.go | 2 +- handlers/burstsms/handler.go | 2 +- handlers/clickatell/handler.go | 2 +- handlers/clickmobile/handler.go | 2 +- handlers/clicksend/handler.go | 2 +- handlers/dart/handler.go | 2 +- handlers/dialog360/handler.go | 24 +++++----- handlers/discord/handler.go | 2 +- handlers/dmark/handler.go | 2 +- handlers/external/handler.go | 2 +- handlers/facebook_legacy/handler.go | 6 +-- handlers/facebook_legacy/handler_test.go | 1 + handlers/firebase/handler.go | 2 +- handlers/freshchat/handler.go | 2 +- handlers/globe/handler.go | 2 +- handlers/highconnection/handler.go | 2 +- handlers/hormuud/handler.go | 4 +- handlers/http.go | 38 --------------- handlers/i2sms/handler.go | 2 +- handlers/infobip/handler.go | 2 +- handlers/jasmin/handler.go | 2 +- handlers/jiochat/handler.go | 6 +-- handlers/justcall/handler.go | 2 +- handlers/kaleyra/handler.go | 6 +-- handlers/kannel/handler.go | 4 +- handlers/line/handler.go | 4 +- handlers/m3tech/handler.go | 2 +- handlers/macrokiosk/handler.go | 2 +- handlers/mblox/handler.go | 2 +- handlers/messagebird/handler.go | 2 +- handlers/messangi/handler.go | 2 +- handlers/meta/facebook_test.go | 2 +- handlers/meta/handlers.go | 26 +++++------ handlers/meta/instagram_test.go | 2 +- handlers/mtarget/handler.go | 2 +- handlers/mtn/handler.go | 4 +- handlers/nexmo/handler.go | 2 +- handlers/novo/handler.go | 2 +- handlers/playmobile/handler.go | 2 +- handlers/plivo/handler.go | 2 +- handlers/redrabbit/handler.go | 2 +- handlers/rocketchat/handler.go | 2 +- handlers/shaqodoon/handler.go | 2 +- handlers/slack/handler.go | 22 ++++----- handlers/slack/handler_test.go | 1 + handlers/smscentral/handler.go | 2 +- handlers/start/handler.go | 2 +- handlers/telegram/handler.go | 4 +- handlers/telesom/handler.go | 2 +- handlers/thinq/handler.go | 4 +- handlers/twiml/handlers.go | 2 +- handlers/twitter/handler.go | 21 ++++----- handlers/viber/handler.go | 10 ++-- handlers/vk/handler.go | 41 ++++++++-------- handlers/vk/handler_test.go | 1 + handlers/wavy/handler.go | 2 +- handlers/wechat/handler.go | 6 +-- handlers/whatsapp_legacy/handler.go | 20 ++++---- handlers/yo/handler.go | 2 +- handlers/zenvia/handlers.go | 2 +- server.go | 3 -- test/backend.go | 12 ++++- test/server.go | 59 ++++++++++++++++++++++++ utils/http.go | 51 -------------------- utils/http_test.go | 24 ---------- 76 files changed, 346 insertions(+), 289 deletions(-) rename handlers/{http_test.go => base_test.go} (85%) delete mode 100644 handlers/http.go create mode 100644 test/server.go delete mode 100644 utils/http.go delete mode 100644 utils/http_test.go diff --git a/attachments.go b/attachments.go index 829ed0957..caa5935c4 100644 --- a/attachments.go +++ b/attachments.go @@ -93,7 +93,7 @@ func FetchAndStoreAttachment(ctx context.Context, b Backend, channel Channel, at return nil, errors.Wrap(err, "unable to create attachment request") } - trace, err := httpx.DoTrace(utils.GetHTTPClient(), attRequest, nil, nil, maxAttBodyReadBytes) + trace, err := httpx.DoTrace(b.HttpClient(true), attRequest, nil, b.HttpAccess(), maxAttBodyReadBytes) if trace != nil { clog.HTTP(trace) diff --git a/backend.go b/backend.go index 2ab025e2a..0479ffb0a 100644 --- a/backend.go +++ b/backend.go @@ -3,9 +3,11 @@ package courier import ( "context" "fmt" + "net/http" "strings" "github.com/gomodule/redigo/redis" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" ) @@ -88,6 +90,10 @@ type Backend interface { // ResolveMedia resolves an outgoing attachment URL to a media object ResolveMedia(context.Context, string) (Media, error) + // HttpClient returns an HTTP client for making external requests + HttpClient(bool) *http.Client + HttpAccess() *httpx.AccessConfig + // Health returns a string describing any health problems the backend has, or empty string if all is well Health() string diff --git a/backends/rapidpro/backend.go b/backends/rapidpro/backend.go index 7ee1dfb74..3a8f0a5eb 100644 --- a/backends/rapidpro/backend.go +++ b/backends/rapidpro/backend.go @@ -3,10 +3,12 @@ package rapidpro import ( "bytes" "context" + "crypto/tls" "database/sql" "encoding/json" "fmt" "log/slog" + "net/http" "net/url" "path" "path/filepath" @@ -23,6 +25,7 @@ import ( "github.com/nyaruka/courier/queue" "github.com/nyaruka/gocommon/analytics" "github.com/nyaruka/gocommon/dbutil" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/jsonx" "github.com/nyaruka/gocommon/storage" "github.com/nyaruka/gocommon/syncx" @@ -66,6 +69,10 @@ type backend struct { stopChan chan bool waitGroup *sync.WaitGroup + httpClient *http.Client + httpClientInsecure *http.Client + httpAccess *httpx.AccessConfig + mediaCache *redisx.IntervalHash mediaMutexes syncx.HashMutex @@ -85,9 +92,26 @@ type backend struct { // NewBackend creates a new RapidPro backend func newBackend(cfg *courier.Config) courier.Backend { + transport := http.DefaultTransport.(*http.Transport).Clone() + transport.MaxIdleConns = 64 + transport.MaxIdleConnsPerHost = 8 + transport.IdleConnTimeout = 15 * time.Second + + insecureTransport := http.DefaultTransport.(*http.Transport).Clone() + insecureTransport.MaxIdleConns = 64 + insecureTransport.MaxIdleConnsPerHost = 8 + insecureTransport.IdleConnTimeout = 15 * time.Second + insecureTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + + disallowedIPs, disallowedNets, _ := cfg.ParseDisallowedNetworks() + return &backend{ config: cfg, + httpClient: &http.Client{Transport: transport, Timeout: 30 * time.Second}, + httpClientInsecure: &http.Client{Transport: insecureTransport, Timeout: 30 * time.Second}, + httpAccess: httpx.NewAccessConfig(10*time.Second, disallowedIPs, disallowedNets), + stopChan: make(chan bool), waitGroup: &sync.WaitGroup{}, @@ -720,6 +744,17 @@ func (b *backend) ResolveMedia(ctx context.Context, mediaUrl string) (courier.Me return media, nil } +func (b *backend) HttpClient(secure bool) *http.Client { + if secure { + return b.httpClient + } + return b.httpClientInsecure +} + +func (b *backend) HttpAccess() *httpx.AccessConfig { + return b.httpAccess +} + // Health returns the health of this backend as a string, returning "" if all is well func (b *backend) Health() string { // test redis diff --git a/config.go b/config.go index ea5056fa0..e546cdb53 100644 --- a/config.go +++ b/config.go @@ -1,7 +1,15 @@ package courier import ( + "encoding/csv" + "io" + "net" + "strings" + + "github.com/nyaruka/courier/utils" "github.com/nyaruka/ezconf" + "github.com/nyaruka/gocommon/httpx" + "github.com/pkg/errors" ) // Config is our top level configuration object @@ -30,15 +38,16 @@ type Config struct { FacebookWebhookSecret string `help:"the secret for Facebook webhook URL verification"` WhatsappAdminSystemUserToken string `help:"the token of the admin system user for WhatsApp"` - MediaDomain string `help:"the domain on which we'll try to resolve outgoing media URLs"` - MaxWorkers int `help:"the maximum number of go routines that will be used for sending (set to 0 to disable sending)"` - LibratoUsername string `help:"the username that will be used to authenticate to Librato"` - LibratoToken string `help:"the token that will be used to authenticate to Librato"` - StatusUsername string `help:"the username that is needed to authenticate against the /status endpoint"` - StatusPassword string `help:"the password that is needed to authenticate against the /status endpoint"` - AuthToken string `help:"the authentication token need to access non-channel endpoints"` - LogLevel string `help:"the logging level courier should use"` - Version string `help:"the version that will be used in request and response headers"` + DisallowedNetworks string `help:"comma separated list of IP addresses and networks which we disallow fetching attachments from"` + MediaDomain string `help:"the domain on which we'll try to resolve outgoing media URLs"` + MaxWorkers int `help:"the maximum number of go routines that will be used for sending (set to 0 to disable sending)"` + LibratoUsername string `help:"the username that will be used to authenticate to Librato"` + LibratoToken string `help:"the token that will be used to authenticate to Librato"` + StatusUsername string `help:"the username that is needed to authenticate against the /status endpoint"` + StatusPassword string `help:"the password that is needed to authenticate against the /status endpoint"` + AuthToken string `help:"the authentication token need to access non-channel endpoints"` + LogLevel string `help:"the logging level courier should use"` + Version string `help:"the version that will be used in request and response headers"` // IncludeChannels is the list of channels to enable, empty means include all IncludeChannels []string @@ -73,9 +82,10 @@ func NewConfig() *Config { FacebookWebhookSecret: "missing_facebook_webhook_secret", WhatsappAdminSystemUserToken: "missing_whatsapp_admin_system_user_token", - MaxWorkers: 32, - LogLevel: "error", - Version: "Dev", + DisallowedNetworks: `127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16,fe80::/10`, + MaxWorkers: 32, + LogLevel: "error", + Version: "Dev", } } @@ -91,3 +101,25 @@ func LoadConfig(filename string) *Config { loader.MustLoad() return config } + +// Validate validates the config +func (c *Config) Validate() error { + if err := utils.Validate(c); err != nil { + return err + } + + if _, _, err := c.ParseDisallowedNetworks(); err != nil { + return errors.Wrap(err, "unable to parse 'DisallowedNetworks'") + } + return nil +} + +// ParseDisallowedNetworks parses the list of IPs and IP networks (written in CIDR notation) +func (c *Config) ParseDisallowedNetworks() ([]net.IP, []*net.IPNet, error) { + addrs, err := csv.NewReader(strings.NewReader(c.DisallowedNetworks)).Read() + if err != nil && err != io.EOF { + return nil, nil, err + } + + return httpx.ParseNetworks(addrs...) +} diff --git a/go.mod b/go.mod index 82af11240..82a51bd56 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.9 github.com/nyaruka/ezconf v0.2.1 - github.com/nyaruka/gocommon v1.42.1 + github.com/nyaruka/gocommon v1.42.2 github.com/nyaruka/null/v3 v3.0.0 github.com/nyaruka/redisx v0.5.0 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index 3d0ea5ae1..5fc6d4c03 100644 --- a/go.sum +++ b/go.sum @@ -69,8 +69,8 @@ github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nyaruka/ezconf v0.2.1 h1:TDXWoqjqYya1uhou1mAJZg7rgFYL98EB0Tb3+BWtUh0= github.com/nyaruka/ezconf v0.2.1/go.mod h1:ey182kYkw2MIi4XiWe1FR/mzI33WCmTWuceDYYxgnQw= -github.com/nyaruka/gocommon v1.42.1 h1:BIS+RpgG06Vl4nzrPLxuFFVF+KTP7PZ+V1xJE1ksLBo= -github.com/nyaruka/gocommon v1.42.1/go.mod h1:JuphjZr/q+GYycaXSQ1WmXzJdbqkbm0iMBlqxxVcF8M= +github.com/nyaruka/gocommon v1.42.2 h1:VGJ/h7WNmCyQ6wNYClJfFkXkU7ZZn+Aiz9xoKJHVRH4= +github.com/nyaruka/gocommon v1.42.2/go.mod h1:JuphjZr/q+GYycaXSQ1WmXzJdbqkbm0iMBlqxxVcF8M= github.com/nyaruka/librato v1.1.1 h1:0nTYtJLl3Sn7lX3CuHsLf+nXy1k/tGV0OjVxLy3Et4s= github.com/nyaruka/librato v1.1.1/go.mod h1:fme1Fu1PT2qvkaBZyw8WW+SrnFe2qeeCWpvqmAaKAKE= github.com/nyaruka/null/v2 v2.0.3 h1:rdmMRQyVzrOF3Jff/gpU/7BDR9mQX0lcLl4yImsA3kw= diff --git a/handlers/africastalking/handler.go b/handlers/africastalking/handler.go index 1726947b8..697e1e8db 100644 --- a/handlers/africastalking/handler.go +++ b/handlers/africastalking/handler.go @@ -150,7 +150,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.Header.Set("apikey", apiKey) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/arabiacell/handler.go b/handlers/arabiacell/handler.go index 5b708fde4..ce0f33417 100644 --- a/handlers/arabiacell/handler.go +++ b/handlers/arabiacell/handler.go @@ -96,7 +96,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/xml") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/bandwidth/handler.go b/handlers/bandwidth/handler.go index 51aa15f31..2441270f0 100644 --- a/handlers/bandwidth/handler.go +++ b/handlers/bandwidth/handler.go @@ -227,7 +227,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - resp, respBody, _ := handlers.RequestHTTP(req, clog) + resp, respBody, _ := h.RequestHTTP(req, clog) response := &mtResponse{} err = json.Unmarshal(respBody, response) diff --git a/handlers/base.go b/handlers/base.go index d76e873f2..a0fe32797 100644 --- a/handlers/base.go +++ b/handlers/base.go @@ -2,10 +2,12 @@ package handlers import ( "context" + "fmt" "net/http" "github.com/go-chi/chi" "github.com/nyaruka/courier" + "github.com/nyaruka/gocommon/httpx" ) var defaultRedactConfigKeys = []string{courier.ConfigAuthToken, courier.ConfigAPIKey, courier.ConfigSecret, courier.ConfigPassword, courier.ConfigSendAuthorization} @@ -98,6 +100,36 @@ func (h *BaseHandler) GetChannel(ctx context.Context, r *http.Request) (courier. return h.backend.GetChannel(ctx, h.ChannelType(), uuid) } +// RequestHTTP does the given request, logging the trace, and returns the response +func (h *BaseHandler) RequestHTTP(req *http.Request, clog *courier.ChannelLog) (*http.Response, []byte, error) { + return h.RequestHTTPWithClient(h.backend.HttpClient(true), req, clog) +} + +// RequestHTTP does the given request, logging the trace, and returns the response +func (h *BaseHandler) RequestHTTPInsecure(req *http.Request, clog *courier.ChannelLog) (*http.Response, []byte, error) { + return h.RequestHTTPWithClient(h.backend.HttpClient(false), req, clog) +} + +// RequestHTTP does the given request using the given client, logging the trace, and returns the response +func (h *BaseHandler) RequestHTTPWithClient(client *http.Client, req *http.Request, clog *courier.ChannelLog) (*http.Response, []byte, error) { + var resp *http.Response + var body []byte + + req.Header.Set("User-Agent", fmt.Sprintf("Courier/%s", h.server.Config().Version)) + + trace, err := httpx.DoTrace(client, req, nil, h.backend.HttpAccess(), 0) + if trace != nil { + clog.HTTP(trace) + resp = trace.Response + body = trace.ResponseBody + } + if err != nil { + return nil, nil, err + } + + return resp, body, nil +} + // WriteStatusSuccessResponse writes a success response for the statuses func (h *BaseHandler) WriteStatusSuccessResponse(ctx context.Context, w http.ResponseWriter, statuses []courier.StatusUpdate) error { return courier.WriteStatusSuccess(w, statuses) diff --git a/handlers/http_test.go b/handlers/base_test.go similarity index 85% rename from handlers/http_test.go rename to handlers/base_test.go index 1e9257b9b..bc6934a12 100644 --- a/handlers/http_test.go +++ b/handlers/base_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestDoHTTPRequest(t *testing.T) { +func TestRequestHTTP(t *testing.T) { httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{ "https://api.messages.com/send.json": { httpx.NewMockResponse(200, nil, []byte(`{"status":"success"}`)), @@ -26,8 +26,14 @@ func TestDoHTTPRequest(t *testing.T) { mm := mb.NewOutgoingMsg(mc, 123, urns.URN("tel:+1234"), "Hello World", false, nil, "", "", courier.MsgOriginChat, nil) clog := courier.NewChannelLogForSend(mm, nil) + config := courier.NewConfig() + server := test.NewMockServer(config, mb) + + h := handlers.NewBaseHandler("NX", "Test") + h.SetServer(server) + req, _ := http.NewRequest("POST", "https://api.messages.com/send.json", nil) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) assert.NoError(t, err) assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, []byte(`{"status":"success"}`), respBody) @@ -38,7 +44,7 @@ func TestDoHTTPRequest(t *testing.T) { assert.Equal(t, "https://api.messages.com/send.json", hlog1.URL) req, _ = http.NewRequest("POST", "https://api.messages.com/send.json", nil) - resp, _, err = handlers.RequestHTTP(req, clog) + resp, _, err = h.RequestHTTP(req, clog) assert.NoError(t, err) assert.Equal(t, 400, resp.StatusCode) assert.Len(t, clog.HTTPLogs(), 2) diff --git a/handlers/bongolive/handler.go b/handlers/bongolive/handler.go index a697dea84..eead3510d 100644 --- a/handlers/bongolive/handler.go +++ b/handlers/bongolive/handler.go @@ -165,7 +165,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, err := handlers.RequestHTTPInsecure(req, clog) + resp, respBody, err := h.RequestHTTPInsecure(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/burstsms/handler.go b/handlers/burstsms/handler.go index 8a4fe17c3..9f8a244de 100644 --- a/handlers/burstsms/handler.go +++ b/handlers/burstsms/handler.go @@ -84,7 +84,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/clickatell/handler.go b/handlers/clickatell/handler.go index 7ffbafe95..a5ad4be5b 100644 --- a/handlers/clickatell/handler.go +++ b/handlers/clickatell/handler.go @@ -180,7 +180,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/clickmobile/handler.go b/handlers/clickmobile/handler.go index 441e71b4d..c0ac4b0cf 100644 --- a/handlers/clickmobile/handler.go +++ b/handlers/clickmobile/handler.go @@ -156,7 +156,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/clicksend/handler.go b/handlers/clicksend/handler.go index a238232e0..ce8f1610d 100644 --- a/handlers/clicksend/handler.go +++ b/handlers/clicksend/handler.go @@ -93,7 +93,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.SetBasicAuth(username, password) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/dart/handler.go b/handlers/dart/handler.go index 8bc5a8eeb..9e91bfead 100644 --- a/handlers/dart/handler.go +++ b/handlers/dart/handler.go @@ -186,7 +186,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/dialog360/handler.go b/handlers/dialog360/handler.go index 742c9606f..dafe6623f 100644 --- a/handlers/dialog360/handler.go +++ b/handlers/dialog360/handler.go @@ -149,21 +149,21 @@ func (h *handler) processWhatsAppPayload(ctx context.Context, channel courier.Ch text = msg.Text.Body } else if msg.Type == "audio" && msg.Audio != nil { text = msg.Audio.Caption - mediaURL, err = resolveMediaURL(channel, msg.Audio.ID, clog) + mediaURL, err = h.resolveMediaURL(channel, msg.Audio.ID, clog) } else if msg.Type == "voice" && msg.Voice != nil { text = msg.Voice.Caption - mediaURL, err = resolveMediaURL(channel, msg.Voice.ID, clog) + mediaURL, err = h.resolveMediaURL(channel, msg.Voice.ID, clog) } else if msg.Type == "button" && msg.Button != nil { text = msg.Button.Text } else if msg.Type == "document" && msg.Document != nil { text = msg.Document.Caption - mediaURL, err = resolveMediaURL(channel, msg.Document.ID, clog) + mediaURL, err = h.resolveMediaURL(channel, msg.Document.ID, clog) } else if msg.Type == "image" && msg.Image != nil { text = msg.Image.Caption - mediaURL, err = resolveMediaURL(channel, msg.Image.ID, clog) + mediaURL, err = h.resolveMediaURL(channel, msg.Image.ID, clog) } else if msg.Type == "video" && msg.Video != nil { text = msg.Video.Caption - mediaURL, err = resolveMediaURL(channel, msg.Video.ID, clog) + mediaURL, err = h.resolveMediaURL(channel, msg.Video.ID, clog) } else if msg.Type == "location" && msg.Location != nil { mediaURL = fmt.Sprintf("geo:%f,%f", msg.Location.Latitude, msg.Location.Longitude) } else if msg.Type == "interactive" && msg.Interactive.Type == "button_reply" { @@ -244,14 +244,13 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, // set the access token as the authorization header req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) - req.Header.Set("User-Agent", utils.HTTPUserAgent) req.Header.Set(d3AuthorizationKey, token) return req, nil } var _ courier.AttachmentRequestBuilder = (*handler)(nil) -func resolveMediaURL(channel courier.Channel, mediaID string, clog *courier.ChannelLog) (string, error) { +func (h *handler) resolveMediaURL(channel courier.Channel, mediaID string, clog *courier.ChannelLog) (string, error) { // sometimes WA will send an attachment with status=undownloaded and no ID if mediaID == "" { return "", nil @@ -272,10 +271,9 @@ func resolveMediaURL(channel courier.Channel, mediaID string, clog *courier.Chan mediaURL := url.ResolveReference(mediaPath).String() req, _ := http.NewRequest(http.MethodGet, mediaURL, nil) - req.Header.Set("User-Agent", utils.HTTPUserAgent) req.Header.Set(d3AuthorizationKey, token) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return "", fmt.Errorf("failed to request media URL for D3C channel: %s", err) } @@ -509,7 +507,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch zeroIndex = true } payloadAudio = whatsapp.SendRequest{MessagingProduct: "whatsapp", RecipientType: "individual", To: msg.URN().Path(), Type: "audio", Audio: &whatsapp.Media{Link: attURL}} - status, err := requestD3C(payloadAudio, accessToken, status, sendURL, zeroIndex, clog) + status, err := h.requestD3C(payloadAudio, accessToken, status, sendURL, zeroIndex, clog) if err != nil { return status, nil } @@ -578,7 +576,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch zeroIndex = true } - status, err := requestD3C(payload, accessToken, status, sendURL, zeroIndex, clog) + status, err := h.requestD3C(payload, accessToken, status, sendURL, zeroIndex, clog) if err != nil { return status, err } @@ -590,7 +588,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch return status, nil } -func requestD3C(payload whatsapp.SendRequest, accessToken string, status courier.StatusUpdate, wacPhoneURL *url.URL, zeroIndex bool, clog *courier.ChannelLog) (courier.StatusUpdate, error) { +func (h *handler) requestD3C(payload whatsapp.SendRequest, accessToken string, status courier.StatusUpdate, wacPhoneURL *url.URL, zeroIndex bool, clog *courier.ChannelLog) (courier.StatusUpdate, error) { jsonBody := jsonx.MustMarshal(payload) req, err := http.NewRequest(http.MethodPost, wacPhoneURL.String(), bytes.NewReader(jsonBody)) @@ -602,7 +600,7 @@ func requestD3C(payload whatsapp.SendRequest, accessToken string, status courier req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - _, respBody, _ := handlers.RequestHTTP(req, clog) + _, respBody, _ := h.RequestHTTP(req, clog) respPayload := &whatsapp.SendResponse{} err = json.Unmarshal(respBody, respPayload) if err != nil { diff --git a/handlers/discord/handler.go b/handlers/discord/handler.go index ef238dd68..a7a6c0b35 100644 --- a/handlers/discord/handler.go +++ b/handlers/discord/handler.go @@ -197,7 +197,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Authorization", authorization) } - resp, _, err := handlers.RequestHTTP(req, clog) + resp, _, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/dmark/handler.go b/handlers/dmark/handler.go index fa00d86d1..02b442047 100644 --- a/handlers/dmark/handler.go +++ b/handlers/dmark/handler.go @@ -134,7 +134,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Token %s", auth)) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/external/handler.go b/handlers/external/handler.go index c7a494c3f..99aecfd24 100644 --- a/handlers/external/handler.go +++ b/handlers/external/handler.go @@ -364,7 +364,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set(hKey, fmt.Sprint(hValue)) } - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/facebook_legacy/handler.go b/handlers/facebook_legacy/handler.go index 6c075869a..45683f28b 100644 --- a/handlers/facebook_legacy/handler.go +++ b/handlers/facebook_legacy/handler.go @@ -119,7 +119,7 @@ func (h *handler) subscribeToEvents(ctx context.Context, channel courier.Channel req, _ := http.NewRequest(http.MethodPost, subscribeURL, strings.NewReader(form.Encode())) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) // log if we get any kind of error success, _ := jsonparser.GetBoolean(respBody, "success") @@ -545,7 +545,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -627,7 +627,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn u.RawQuery = query.Encode() req, _ := http.NewRequest(http.MethodGet, u.String(), nil) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to look up contact data") } diff --git a/handlers/facebook_legacy/handler_test.go b/handlers/facebook_legacy/handler_test.go index 81d2f524c..58c7cfe31 100644 --- a/handlers/facebook_legacy/handler_test.go +++ b/handlers/facebook_legacy/handler_test.go @@ -632,6 +632,7 @@ func TestDescribeURN(t *testing.T) { channel := testChannels[0] handler := newHandler() + handler.Initialize(test.NewMockServer(courier.NewConfig(), test.NewMockBackend())) clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, handler.RedactValues(channel)) tcs := []struct { diff --git a/handlers/firebase/handler.go b/handlers/firebase/handler.go index 672cbc6cb..a38276673 100644 --- a/handlers/firebase/handler.go +++ b/handlers/firebase/handler.go @@ -197,7 +197,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("key=%s", fcmKey)) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/freshchat/handler.go b/handlers/freshchat/handler.go index 8cfd0cb4a..827aaa76b 100644 --- a/handlers/freshchat/handler.go +++ b/handlers/freshchat/handler.go @@ -159,7 +159,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch var bearer = "Bearer " + authToken req.Header.Set("Authorization", bearer) - resp, _, err := handlers.RequestHTTP(req, clog) + resp, _, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/globe/handler.go b/handlers/globe/handler.go index de7548084..2f39be542 100644 --- a/handlers/globe/handler.go +++ b/handlers/globe/handler.go @@ -157,7 +157,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, _, err := handlers.RequestHTTP(req, clog) + resp, _, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/highconnection/handler.go b/handlers/highconnection/handler.go index 70286e849..77cf30c68 100644 --- a/handlers/highconnection/handler.go +++ b/handlers/highconnection/handler.go @@ -166,7 +166,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch return nil, err } - resp, _, err := handlers.RequestHTTP(req, clog) + resp, _, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/hormuud/handler.go b/handlers/hormuud/handler.go index 88f8390a6..2e650a2aa 100644 --- a/handlers/hormuud/handler.go +++ b/handlers/hormuud/handler.go @@ -107,7 +107,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -162,7 +162,7 @@ func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg c req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return "", errors.Wrapf(err, "error making token request") } diff --git a/handlers/http.go b/handlers/http.go deleted file mode 100644 index 0aed1a72c..000000000 --- a/handlers/http.go +++ /dev/null @@ -1,38 +0,0 @@ -package handlers - -import ( - "net/http" - - "github.com/nyaruka/courier" - "github.com/nyaruka/courier/utils" - "github.com/nyaruka/gocommon/httpx" -) - -// RequestHTTP does the given request, logging the trace, and returns the response -func RequestHTTP(req *http.Request, clog *courier.ChannelLog) (*http.Response, []byte, error) { - return RequestHTTPWithClient(utils.GetHTTPClient(), req, clog) -} - -// RequestHTTPInsecure does the given request using an insecure client that does not validate SSL certificates, -// logging the trace, and returns the response -func RequestHTTPInsecure(req *http.Request, clog *courier.ChannelLog) (*http.Response, []byte, error) { - return RequestHTTPWithClient(utils.GetInsecureHTTPClient(), req, clog) -} - -// RequestHTTP does the given request using the given client, logging the trace, and returns the response -func RequestHTTPWithClient(client *http.Client, req *http.Request, clog *courier.ChannelLog) (*http.Response, []byte, error) { - var resp *http.Response - var body []byte - - trace, err := httpx.DoTrace(client, req, nil, nil, 0) - if trace != nil { - clog.HTTP(trace) - resp = trace.Response - body = trace.ResponseBody - } - if err != nil { - return nil, nil, err - } - - return resp, body, nil -} diff --git a/handlers/i2sms/handler.go b/handlers/i2sms/handler.go index ce3eda937..543139963 100644 --- a/handlers/i2sms/handler.go +++ b/handlers/i2sms/handler.go @@ -117,7 +117,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/infobip/handler.go b/handlers/infobip/handler.go index 0ceed91ec..1f6ab666b 100644 --- a/handlers/infobip/handler.go +++ b/handlers/infobip/handler.go @@ -211,7 +211,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/jasmin/handler.go b/handlers/jasmin/handler.go index 4ae2e1977..b54365a83 100644 --- a/handlers/jasmin/handler.go +++ b/handlers/jasmin/handler.go @@ -162,7 +162,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/jiochat/handler.go b/handlers/jiochat/handler.go index eb3c1b6c1..058343edc 100644 --- a/handlers/jiochat/handler.go +++ b/handlers/jiochat/handler.go @@ -186,7 +186,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) - resp, _, err := handlers.RequestHTTP(req, clog) + resp, _, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -216,7 +216,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn req, _ := http.NewRequest(http.MethodGet, reqURL.String(), nil) req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken)) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to look up contact data") } @@ -304,7 +304,7 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel, req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return "", 0, err } diff --git a/handlers/justcall/handler.go b/handlers/justcall/handler.go index c42aa1f95..2f89150f7 100644 --- a/handlers/justcall/handler.go +++ b/handlers/justcall/handler.go @@ -190,7 +190,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("%s:%s", apiKey, apiSecret)) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/kaleyra/handler.go b/handlers/kaleyra/handler.go index f52fcc4c1..13d116934 100644 --- a/handlers/kaleyra/handler.go +++ b/handlers/kaleyra/handler.go @@ -158,7 +158,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch // download media req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) - resp, attBody, err := handlers.RequestHTTP(req, clog) + resp, attBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { kwaErr = errors.New("unable to fetch media") break @@ -203,7 +203,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch // send multipart form req, _ = http.NewRequest(http.MethodPost, sendURL, body) req.Header.Set("Content-Type", writer.FormDataContentType()) - kwaResp, kwaRespBody, kwaErr = handlers.RequestHTTP(req, clog) + kwaResp, kwaRespBody, kwaErr = h.RequestHTTP(req, clog) } } else { form := url.Values{} @@ -219,7 +219,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req, _ := http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - kwaResp, kwaRespBody, kwaErr = handlers.RequestHTTP(req, clog) + kwaResp, kwaRespBody, kwaErr = h.RequestHTTP(req, clog) } if kwaErr != nil || kwaResp.StatusCode/100 != 2 { diff --git a/handlers/kannel/handler.go b/handlers/kannel/handler.go index b29f1bef4..c249a6fef 100644 --- a/handlers/kannel/handler.go +++ b/handlers/kannel/handler.go @@ -201,9 +201,9 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch var resp *http.Response if verifySSL { - resp, _, err = handlers.RequestHTTP(req, clog) + resp, _, err = h.RequestHTTP(req, clog) } else { - resp, _, err = handlers.RequestHTTPInsecure(req, clog) + resp, _, err = h.RequestHTTPInsecure(req, clog) } status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) diff --git a/handlers/line/handler.go b/handlers/line/handler.go index e802b922e..fce0a690e 100644 --- a/handlers/line/handler.go +++ b/handlers/line/handler.go @@ -360,7 +360,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch return status, err } - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err == nil && resp.StatusCode/100 == 2 { batch = []string{} @@ -382,7 +382,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch return status, err } - resp, respBody, _ := handlers.RequestHTTP(req, clog) + resp, respBody, _ := h.RequestHTTP(req, clog) respPayload := &mtResponse{} err = json.Unmarshal(respBody, respPayload) diff --git a/handlers/m3tech/handler.go b/handlers/m3tech/handler.go index bfb51dcbf..8cdfb39db 100644 --- a/handlers/m3tech/handler.go +++ b/handlers/m3tech/handler.go @@ -113,7 +113,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch return nil, err } - resp, _, err := handlers.RequestHTTP(req, clog) + resp, _, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { break } diff --git a/handlers/macrokiosk/handler.go b/handlers/macrokiosk/handler.go index 60897611f..aa4ffb5dd 100644 --- a/handlers/macrokiosk/handler.go +++ b/handlers/macrokiosk/handler.go @@ -189,7 +189,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/mblox/handler.go b/handlers/mblox/handler.go index a49683da1..3d1254c6d 100644 --- a/handlers/mblox/handler.go +++ b/handlers/mblox/handler.go @@ -141,7 +141,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", password)) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/messagebird/handler.go b/handlers/messagebird/handler.go index 1981be45e..401e1a008 100644 --- a/handlers/messagebird/handler.go +++ b/handlers/messagebird/handler.go @@ -228,7 +228,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch var bearer = "AccessKey " + authToken req.Header.Set("Authorization", bearer) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/messangi/handler.go b/handlers/messangi/handler.go index 9fb69961b..8fb105c58 100644 --- a/handlers/messangi/handler.go +++ b/handlers/messangi/handler.go @@ -96,7 +96,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch return nil, err } - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/meta/facebook_test.go b/handlers/meta/facebook_test.go index 36ef60036..b3b7be0e1 100644 --- a/handlers/meta/facebook_test.go +++ b/handlers/meta/facebook_test.go @@ -281,7 +281,7 @@ func TestFacebookDescribeURN(t *testing.T) { channel := facebookTestChannels[0] handler := newHandler("FBA", "Facebook") - handler.Initialize(courier.NewServer(courier.NewConfig(), nil)) + handler.Initialize(test.NewMockServer(courier.NewConfig(), test.NewMockBackend())) clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, handler.RedactValues(channel)) tcs := []struct { diff --git a/handlers/meta/handlers.go b/handlers/meta/handlers.go index f70e32ccf..9d39c3bdc 100644 --- a/handlers/meta/handlers.go +++ b/handlers/meta/handlers.go @@ -188,7 +188,7 @@ func (h *handler) receiveVerify(ctx context.Context, channel courier.Channel, w return nil, err } -func resolveMediaURL(mediaID string, token string, clog *courier.ChannelLog) (string, error) { +func (h *handler) resolveMediaURL(mediaID string, token string, clog *courier.ChannelLog) (string, error) { if token == "" { return "", fmt.Errorf("missing token for WA channel") } @@ -202,7 +202,7 @@ func resolveMediaURL(mediaID string, token string, clog *courier.ChannelLog) (st //req.Header.Set("User-Agent", utils.HTTPUserAgent) req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return "", errors.New("error resolving media URL") } @@ -297,21 +297,21 @@ func (h *handler) processWhatsAppPayload(ctx context.Context, channel courier.Ch text = msg.Text.Body } else if msg.Type == "audio" && msg.Audio != nil { text = msg.Audio.Caption - mediaURL, err = resolveMediaURL(msg.Audio.ID, token, clog) + mediaURL, err = h.resolveMediaURL(msg.Audio.ID, token, clog) } else if msg.Type == "voice" && msg.Voice != nil { text = msg.Voice.Caption - mediaURL, err = resolveMediaURL(msg.Voice.ID, token, clog) + mediaURL, err = h.resolveMediaURL(msg.Voice.ID, token, clog) } else if msg.Type == "button" && msg.Button != nil { text = msg.Button.Text } else if msg.Type == "document" && msg.Document != nil { text = msg.Document.Caption - mediaURL, err = resolveMediaURL(msg.Document.ID, token, clog) + mediaURL, err = h.resolveMediaURL(msg.Document.ID, token, clog) } else if msg.Type == "image" && msg.Image != nil { text = msg.Image.Caption - mediaURL, err = resolveMediaURL(msg.Image.ID, token, clog) + mediaURL, err = h.resolveMediaURL(msg.Image.ID, token, clog) } else if msg.Type == "video" && msg.Video != nil { text = msg.Video.Caption - mediaURL, err = resolveMediaURL(msg.Video.ID, token, clog) + mediaURL, err = h.resolveMediaURL(msg.Video.ID, token, clog) } else if msg.Type == "location" && msg.Location != nil { mediaURL = fmt.Sprintf("geo:%f,%f", msg.Location.Latitude, msg.Location.Longitude) } else if msg.Type == "interactive" && msg.Interactive.Type == "button_reply" { @@ -721,7 +721,7 @@ func (h *handler) sendFacebookInstagramMsg(ctx context.Context, msg courier.MsgO req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - _, respBody, _ := handlers.RequestHTTP(req, clog) + _, respBody, _ := h.RequestHTTP(req, clog) respPayload := &messenger.SendResponse{} err = json.Unmarshal(respBody, respPayload) if err != nil { @@ -997,7 +997,7 @@ func (h *handler) sendWhatsAppMsg(ctx context.Context, msg courier.MsgOut, clog zeroIndex = true } payloadAudio = whatsapp.SendRequest{MessagingProduct: "whatsapp", RecipientType: "individual", To: msg.URN().Path(), Type: "audio", Audio: &whatsapp.Media{Link: attURL}} - err := requestWAC(payloadAudio, accessToken, status, wacPhoneURL, zeroIndex, clog) + err := h.requestWAC(payloadAudio, accessToken, status, wacPhoneURL, zeroIndex, clog) if err != nil { return status, nil } @@ -1066,7 +1066,7 @@ func (h *handler) sendWhatsAppMsg(ctx context.Context, msg courier.MsgOut, clog zeroIndex = true } - err := requestWAC(payload, accessToken, status, wacPhoneURL, zeroIndex, clog) + err := h.requestWAC(payload, accessToken, status, wacPhoneURL, zeroIndex, clog) if err != nil { return status, err } @@ -1078,7 +1078,7 @@ func (h *handler) sendWhatsAppMsg(ctx context.Context, msg courier.MsgOut, clog return status, nil } -func requestWAC(payload whatsapp.SendRequest, accessToken string, status courier.StatusUpdate, wacPhoneURL *url.URL, zeroIndex bool, clog *courier.ChannelLog) error { +func (h *handler) requestWAC(payload whatsapp.SendRequest, accessToken string, status courier.StatusUpdate, wacPhoneURL *url.URL, zeroIndex bool, clog *courier.ChannelLog) error { jsonBody := jsonx.MustMarshal(payload) req, err := http.NewRequest(http.MethodPost, wacPhoneURL.String(), bytes.NewReader(jsonBody)) @@ -1090,7 +1090,7 @@ func requestWAC(payload whatsapp.SendRequest, accessToken string, status courier req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - _, respBody, _ := handlers.RequestHTTP(req, clog) + _, respBody, _ := h.RequestHTTP(req, clog) respPayload := &whatsapp.SendResponse{} err = json.Unmarshal(respBody, respPayload) if err != nil { @@ -1143,7 +1143,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn u.RawQuery = query.Encode() req, _ := http.NewRequest(http.MethodGet, u.String(), nil) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to look up contact data") } diff --git a/handlers/meta/instagram_test.go b/handlers/meta/instagram_test.go index 078e32483..9fadd3853 100644 --- a/handlers/meta/instagram_test.go +++ b/handlers/meta/instagram_test.go @@ -394,7 +394,7 @@ func TestInstagramDescribeURN(t *testing.T) { channel := instgramTestChannels[0] handler := newHandler("IG", "Instagram") - handler.Initialize(courier.NewServer(courier.NewConfig(), nil)) + handler.Initialize(test.NewMockServer(courier.NewConfig(), test.NewMockBackend())) clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, channel, handler.RedactValues(channel)) tcs := []struct { diff --git a/handlers/mtarget/handler.go b/handlers/mtarget/handler.go index a1453ffbb..9f79ea345 100644 --- a/handlers/mtarget/handler.go +++ b/handlers/mtarget/handler.go @@ -179,7 +179,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch return nil, err } - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/mtn/handler.go b/handlers/mtn/handler.go index 8ee9a1b68..560712425 100644 --- a/handlers/mtn/handler.go +++ b/handlers/mtn/handler.go @@ -154,7 +154,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken)) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -225,7 +225,7 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel, req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return "", 0, err } diff --git a/handlers/nexmo/handler.go b/handlers/nexmo/handler.go index 1e7dc00dd..585f9a3ec 100644 --- a/handlers/nexmo/handler.go +++ b/handlers/nexmo/handler.go @@ -216,7 +216,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, requestErr = handlers.RequestHTTP(req, clog) + resp, respBody, requestErr = h.RequestHTTP(req, clog) matched := throttledRE.FindAllStringSubmatch(string(respBody), -1) if len(matched) > 0 && len(matched[0]) > 0 { sleepTime, _ := strconv.Atoi(matched[0][1]) diff --git a/handlers/novo/handler.go b/handlers/novo/handler.go index 7f07ea51c..6d10b5bc7 100644 --- a/handlers/novo/handler.go +++ b/handlers/novo/handler.go @@ -110,7 +110,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch return nil, err } - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/playmobile/handler.go b/handlers/playmobile/handler.go index ecce2fff0..91bf0d10d 100644 --- a/handlers/playmobile/handler.go +++ b/handlers/playmobile/handler.go @@ -193,7 +193,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, _, err := handlers.RequestHTTP(req, clog) + resp, _, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/plivo/handler.go b/handlers/plivo/handler.go index 9ed6e092c..48f0dce8f 100644 --- a/handlers/plivo/handler.go +++ b/handlers/plivo/handler.go @@ -170,7 +170,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.SetBasicAuth(authID, authToken) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/redrabbit/handler.go b/handlers/redrabbit/handler.go index 7d34d242b..6543ae342 100644 --- a/handlers/redrabbit/handler.go +++ b/handlers/redrabbit/handler.go @@ -72,7 +72,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch return nil, err } - resp, _, err := handlers.RequestHTTP(req, clog) + resp, _, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/rocketchat/handler.go b/handlers/rocketchat/handler.go index 2937bdd41..a36eecd3c 100644 --- a/handlers/rocketchat/handler.go +++ b/handlers/rocketchat/handler.go @@ -132,7 +132,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Token %s", secret)) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/shaqodoon/handler.go b/handlers/shaqodoon/handler.go index d6fe3a0df..6b77f3ef8 100644 --- a/handlers/shaqodoon/handler.go +++ b/handlers/shaqodoon/handler.go @@ -115,7 +115,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) - resp, _, err := handlers.RequestHTTPInsecure(req, clog) + resp, _, err := h.RequestHTTPInsecure(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/slack/handler.go b/handlers/slack/handler.go index 41020f85e..d1152c166 100644 --- a/handlers/slack/handler.go +++ b/handlers/slack/handler.go @@ -116,7 +116,7 @@ func (h *handler) resolveFile(ctx context.Context, channel courier.Channel, file req.Header.Add("Content-Type", "application/json; charset=utf-8") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", userToken)) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return "", errors.New("unable to resolve file") } @@ -154,14 +154,14 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) for _, attachment := range msg.Attachments() { - fileAttachment, err := parseAttachmentToFileParams(msg, attachment, clog) + fileAttachment, err := h.parseAttachmentToFileParams(msg, attachment, clog) if err != nil { clog.RawError(err) return status, nil } if fileAttachment != nil { - err = sendFilePart(msg, botToken, fileAttachment, clog) + err = h.sendFilePart(msg, botToken, fileAttachment, clog) if err != nil { clog.RawError(err) return status, nil @@ -170,7 +170,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch } if msg.Text() != "" { - err := sendTextMsgPart(msg, botToken, clog) + err := h.sendTextMsgPart(msg, botToken, clog) if err != nil { clog.RawError(err) return status, nil @@ -181,7 +181,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch return status, nil } -func sendTextMsgPart(msg courier.MsgOut, token string, clog *courier.ChannelLog) error { +func (h *handler) sendTextMsgPart(msg courier.MsgOut, token string, clog *courier.ChannelLog) error { sendURL := apiURL + "/chat.postMessage" msgPayload := &mtPayload{ @@ -201,7 +201,7 @@ func sendTextMsgPart(msg courier.MsgOut, token string, clog *courier.ChannelLog) req.Header.Set("Content-Type", "application/json; charset=utf-8") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return errors.New("error sending message") } @@ -221,7 +221,7 @@ func sendTextMsgPart(msg courier.MsgOut, token string, clog *courier.ChannelLog) return nil } -func parseAttachmentToFileParams(msg courier.MsgOut, attachment string, clog *courier.ChannelLog) (*FileParams, error) { +func (h *handler) parseAttachmentToFileParams(msg courier.MsgOut, attachment string, clog *courier.ChannelLog) (*FileParams, error) { _, attURL := handlers.SplitAttachment(attachment) req, err := http.NewRequest(http.MethodGet, attURL, nil) @@ -229,7 +229,7 @@ func parseAttachmentToFileParams(msg courier.MsgOut, attachment string, clog *co return nil, errors.Wrapf(err, "error building file request") } - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("error fetching attachment") } @@ -241,7 +241,7 @@ func parseAttachmentToFileParams(msg courier.MsgOut, attachment string, clog *co return &FileParams{File: respBody, FileName: filename, Channels: msg.URN().Path()}, nil } -func sendFilePart(msg courier.MsgOut, token string, fileParams *FileParams, clog *courier.ChannelLog) error { +func (h *handler) sendFilePart(msg courier.MsgOut, token string, fileParams *FileParams, clog *courier.ChannelLog) error { uploadURL := apiURL + "/files.upload" body := &bytes.Buffer{} @@ -273,7 +273,7 @@ func sendFilePart(msg courier.MsgOut, token string, fileParams *FileParams, clog req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) req.Header.Add("Content-Type", writer.FormDataContentType()) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return errors.New("error uploading file to slack") } @@ -304,7 +304,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn q.Add("user", urn.Path()) req.URL.RawQuery = q.Encode() - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to look up user info") } diff --git a/handlers/slack/handler_test.go b/handlers/slack/handler_test.go index 246b02aed..1f24fde97 100644 --- a/handlers/slack/handler_test.go +++ b/handlers/slack/handler_test.go @@ -360,6 +360,7 @@ func TestDescribeURN(t *testing.T) { defer server.Close() handler := newHandler() + handler.Initialize(test.NewMockServer(courier.NewConfig(), test.NewMockBackend())) clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], handler.RedactValues(testChannels[0])) urn, _ := urns.NewURNFromParts(urns.SlackScheme, "U012345", "", "") diff --git a/handlers/smscentral/handler.go b/handlers/smscentral/handler.go index 250265104..51750406c 100644 --- a/handlers/smscentral/handler.go +++ b/handlers/smscentral/handler.go @@ -90,7 +90,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, _, err := handlers.RequestHTTP(req, clog) + resp, _, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/start/handler.go b/handlers/start/handler.go index b349c1996..67336b83f 100644 --- a/handlers/start/handler.go +++ b/handlers/start/handler.go @@ -164,7 +164,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/xml; charset=utf8") req.SetBasicAuth(username, password) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/telegram/handler.go b/handlers/telegram/handler.go index 4ab58a2c8..a824a29cf 100644 --- a/handlers/telegram/handler.go +++ b/handlers/telegram/handler.go @@ -157,7 +157,7 @@ func (h *handler) sendMsgPart(msg courier.MsgOut, token string, path string, for } req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, _ := handlers.RequestHTTP(req, clog) + resp, respBody, _ := h.RequestHTTP(req, clog) response := &mtResponse{} err = json.Unmarshal(respBody, response) @@ -346,7 +346,7 @@ func (h *handler) resolveFileID(ctx context.Context, channel courier.Channel, fi courier.LogRequestError(req, channel, err) } - resp, respBody, _ := handlers.RequestHTTP(req, clog) + resp, respBody, _ := h.RequestHTTP(req, clog) respPayload := &fileResponse{} err = json.Unmarshal(respBody, respPayload) diff --git a/handlers/telesom/handler.go b/handlers/telesom/handler.go index 9c306bc13..7f9e86e1e 100644 --- a/handlers/telesom/handler.go +++ b/handlers/telesom/handler.go @@ -114,7 +114,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/thinq/handler.go b/handlers/thinq/handler.go index 6bfca6309..3cac20b1d 100644 --- a/handlers/thinq/handler.go +++ b/handlers/thinq/handler.go @@ -172,7 +172,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.SetBasicAuth(tokenUser, token) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -205,7 +205,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.SetBasicAuth(tokenUser, token) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/twiml/handlers.go b/handlers/twiml/handlers.go index 24298b361..7d54e40bf 100644 --- a/handlers/twiml/handlers.go +++ b/handlers/twiml/handlers.go @@ -286,7 +286,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil { return status, nil } diff --git a/handlers/twitter/handler.go b/handlers/twitter/handler.go index a5ee3d19f..29b4fcaa0 100644 --- a/handlers/twitter/handler.go +++ b/handlers/twitter/handler.go @@ -19,7 +19,6 @@ import ( "github.com/dghubble/oauth1" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/jsonx" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" @@ -288,7 +287,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch mimeType, s3url := handlers.SplitAttachment(attachment) mediaID := "" if strings.HasPrefix(mimeType, "image") || strings.HasPrefix(mimeType, "video") { - mediaID, err = uploadMediaToTwitter(msg, mediaURL, mimeType, s3url, client, clog) + mediaID, err = h.uploadMediaToTwitter(msg, mediaURL, mimeType, s3url, client, clog) if err != nil { clog.RawError(errors.Wrap(err, "unable to upload media to Twitter server")) } @@ -328,7 +327,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTPWithClient(client, req, clog) + resp, respBody, err := h.RequestHTTPWithClient(client, req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -360,11 +359,11 @@ func generateSignature(secret string, content string) string { return base64.StdEncoding.EncodeToString(h.Sum(nil)) } -func uploadMediaToTwitter(msg courier.MsgOut, mediaUrl string, attachmentMimeType string, attachmentURL string, client *http.Client, clog *courier.ChannelLog) (string, error) { +func (h *handler) uploadMediaToTwitter(msg courier.MsgOut, mediaUrl string, attachmentMimeType string, attachmentURL string, client *http.Client, clog *courier.ChannelLog) (string, error) { // retrieve the media to be sent from S3 req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) - s3Resp, s3RespBody, err := handlers.RequestHTTP(req, clog) + s3Resp, s3RespBody, err := h.RequestHTTP(req, clog) if err != nil || s3Resp.StatusCode/100 != 2 { return "", err } @@ -392,9 +391,8 @@ func uploadMediaToTwitter(msg courier.MsgOut, mediaUrl string, attachmentMimeTyp twReq, _ := http.NewRequest(http.MethodPost, mediaUrl, strings.NewReader(form.Encode())) twReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") twReq.Header.Set("Accept", "application/json") - twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twResp, twRespBody, err := handlers.RequestHTTPWithClient(client, twReq, clog) + twResp, twRespBody, err := h.RequestHTTPWithClient(client, twReq, clog) if err != nil || twResp.StatusCode/100 != 2 { return "", err } @@ -435,9 +433,8 @@ func uploadMediaToTwitter(msg courier.MsgOut, mediaUrl string, attachmentMimeTyp twReq, _ = http.NewRequest(http.MethodPost, mediaUrl, bytes.NewReader(body.Bytes())) twReq.Header.Set("Content-Type", contentType) twReq.Header.Set("Accept", "application/json") - twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twResp, twRespBody, err = handlers.RequestHTTPWithClient(client, twReq, clog) + twResp, twRespBody, err = h.RequestHTTPWithClient(client, twReq, clog) if err != nil || twResp.StatusCode/100 != 2 { return "", err } @@ -454,9 +451,8 @@ func uploadMediaToTwitter(msg courier.MsgOut, mediaUrl string, attachmentMimeTyp twReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") twReq.Header.Set("Accept", "application/json") - twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twResp, twRespBody, err = handlers.RequestHTTPWithClient(client, twReq, clog) + twResp, twRespBody, err = h.RequestHTTPWithClient(client, twReq, clog) if err != nil || twResp.StatusCode/100 != 2 { return "", err } @@ -485,9 +481,8 @@ func uploadMediaToTwitter(msg courier.MsgOut, mediaUrl string, attachmentMimeTyp twReq, _ = http.NewRequest(http.MethodGet, statusURL.String(), nil) twReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") twReq.Header.Set("Accept", "application/json") - twReq.Header.Set("User-Agent", utils.HTTPUserAgent) - twResp, twRespBody, err = handlers.RequestHTTPWithClient(client, twReq, clog) + twResp, twRespBody, err = h.RequestHTTPWithClient(client, twReq, clog) if err != nil || twResp.StatusCode/100 != 2 { return "", err } diff --git a/handlers/viber/handler.go b/handlers/viber/handler.go index 86d04414b..38f7ab4f4 100644 --- a/handlers/viber/handler.go +++ b/handlers/viber/handler.go @@ -385,7 +385,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch case "video": msgType = "video" attURL = mediaURL - attSize, err = getAttachmentSize(mediaURL, clog) + attSize, err = h.getAttachmentSize(mediaURL, clog) if err != nil { return nil, err } @@ -394,7 +394,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch case "audio": msgType = "file" attURL = mediaURL - attSize, err = getAttachmentSize(mediaURL, clog) + attSize, err = h.getAttachmentSize(mediaURL, clog) if err != nil { return nil, err } @@ -438,7 +438,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { clog.Error(courier.ErrorResponseStatusCode()) return status, nil @@ -466,13 +466,13 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch return status, nil } -func getAttachmentSize(u string, clog *courier.ChannelLog) (int, error) { +func (h *handler) getAttachmentSize(u string, clog *courier.ChannelLog) (int, error) { req, err := http.NewRequest(http.MethodHead, u, nil) if err != nil { return 0, err } - resp, _, err := handlers.RequestHTTP(req, clog) + resp, _, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return 0, errors.New("unable to get attachment size") } diff --git a/handlers/vk/handler.go b/handlers/vk/handler.go index 19d8e0022..dc7e191b1 100644 --- a/handlers/vk/handler.go +++ b/handlers/vk/handler.go @@ -16,7 +16,6 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" - "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/jsonx" "github.com/nyaruka/gocommon/urns" "github.com/pkg/errors" @@ -273,7 +272,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn req.URL.RawQuery = params.Encode() - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to look up user info") } @@ -381,7 +380,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch params.Set(paramUserId, msg.URN().Path()) params.Set(paramRandomId, msg.ID().String()) - text, attachments := buildTextAndAttachmentParams(msg, clog) + text, attachments := h.buildTextAndAttachmentParams(msg, clog) params.Set(paramMessage, text) params.Set(paramAttachments, attachments) @@ -399,7 +398,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.URL.RawQuery = params.Encode() - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -415,8 +414,8 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch return status, nil } -// buildTextAndAttachmentParams builds msg text with attachment links (if needed) and attachments list param, also returns the errors that occurred -func buildTextAndAttachmentParams(msg courier.MsgOut, clog *courier.ChannelLog) (string, string) { +// builds msg text with attachment links (if needed) and attachments list param, also returns the errors that occurred +func (h *handler) buildTextAndAttachmentParams(msg courier.MsgOut, clog *courier.ChannelLog) (string, string) { var msgAttachments []string textBuf := bytes.Buffer{} @@ -434,7 +433,7 @@ func buildTextAndAttachmentParams(msg courier.MsgOut, clog *courier.ChannelLog) switch mediaType { case mediaTypeImage: - if attachment, err := handleMediaUploadAndGetAttachment(msg.Channel(), mediaTypeImage, mediaExt, mediaURL, clog); err == nil { + if attachment, err := h.handleMediaUploadAndGetAttachment(msg.Channel(), mediaTypeImage, mediaExt, mediaURL, clog); err == nil { msgAttachments = append(msgAttachments, attachment) } else { clog.RawError(err) @@ -448,24 +447,24 @@ func buildTextAndAttachmentParams(msg courier.MsgOut, clog *courier.ChannelLog) return textBuf.String(), strings.Join(msgAttachments, ",") } -// handleMediaUploadAndGetAttachment handles media downloading, uploading, saving information and returns the attachment string -func handleMediaUploadAndGetAttachment(channel courier.Channel, mediaType, mediaExt, mediaURL string, clog *courier.ChannelLog) (string, error) { +// handles media downloading, uploading, saving information and returns the attachment string +func (h *handler) handleMediaUploadAndGetAttachment(channel courier.Channel, mediaType, mediaExt, mediaURL string, clog *courier.ChannelLog) (string, error) { switch mediaType { case mediaTypeImage: uploadKey := "photo" // initialize server URL to upload photos if URLPhotoUploadServer == "" { - if serverURL, err := getUploadServerURL(channel, apiBaseURL+actionGetPhotoUploadServer, clog); err == nil { + if serverURL, err := h.getUploadServerURL(channel, apiBaseURL+actionGetPhotoUploadServer, clog); err == nil { URLPhotoUploadServer = serverURL } } - download, err := downloadMedia(mediaURL) + download, err := h.downloadMedia(mediaURL) if err != nil { return "", err } - uploadResponse, err := uploadMedia(URLPhotoUploadServer, uploadKey, mediaExt, download, clog) + uploadResponse, err := h.uploadMedia(URLPhotoUploadServer, uploadKey, mediaExt, download, clog) if err != nil { return "", err @@ -476,7 +475,7 @@ func handleMediaUploadAndGetAttachment(channel courier.Channel, mediaType, media return "", err } serverId := strconv.FormatInt(payload.ServerId, 10) - info, err := saveUploadedMediaInfo(channel, apiBaseURL+actionSaveUploadedPhotoInfo, serverId, payload.Hash, uploadKey, payload.Photo, clog) + info, err := h.saveUploadedMediaInfo(channel, apiBaseURL+actionSaveUploadedPhotoInfo, serverId, payload.Hash, uploadKey, payload.Photo, clog) if err != nil { return "", err @@ -491,7 +490,7 @@ func handleMediaUploadAndGetAttachment(channel courier.Channel, mediaType, media } // getUploadServerURL gets VK's media upload server -func getUploadServerURL(channel courier.Channel, sendURL string, clog *courier.ChannelLog) (string, error) { +func (h *handler) getUploadServerURL(channel courier.Channel, sendURL string, clog *courier.ChannelLog) (string, error) { req, err := http.NewRequest(http.MethodPost, sendURL, nil) if err != nil { @@ -500,7 +499,7 @@ func getUploadServerURL(channel courier.Channel, sendURL string, clog *courier.C params := buildApiBaseParams(channel) req.URL.RawQuery = params.Encode() - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return "", errors.New("unable to get upload server URL") } @@ -514,13 +513,13 @@ func getUploadServerURL(channel courier.Channel, sendURL string, clog *courier.C } // downloadMedia GET request to given media URL -func downloadMedia(mediaURL string) (io.Reader, error) { +func (h *handler) downloadMedia(mediaURL string) (io.Reader, error) { req, err := http.NewRequest(http.MethodGet, mediaURL, nil) if err != nil { return nil, err } - if res, err := utils.GetHTTPClient().Do(req); err == nil { + if res, err := h.Backend().HttpClient(true).Do(req); err == nil { return res.Body, nil } else { return nil, err @@ -528,7 +527,7 @@ func downloadMedia(mediaURL string) (io.Reader, error) { } // uploadMedia multiform request that passes file key as uploadKey and file value as media to upload server -func uploadMedia(serverURL, uploadKey, mediaExt string, media io.Reader, clog *courier.ChannelLog) ([]byte, error) { +func (h *handler) uploadMedia(serverURL, uploadKey, mediaExt string, media io.Reader, clog *courier.ChannelLog) ([]byte, error) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) fileName := fmt.Sprintf("%s.%s", uploadKey, mediaExt) @@ -555,7 +554,7 @@ func uploadMedia(serverURL, uploadKey, mediaExt string, media io.Reader, clog *c req.Header.Set("Content-Type", writer.FormDataContentType()) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to upload media") } @@ -563,7 +562,7 @@ func uploadMedia(serverURL, uploadKey, mediaExt string, media io.Reader, clog *c } // saveUploadedMediaInfo saves uploaded media info and returns an object containing media/owner id -func saveUploadedMediaInfo(channel courier.Channel, sendURL, serverId, hash, mediaKey, mediaValue string, clog *courier.ChannelLog) (*mediaUploadInfoPayload, error) { +func (h *handler) saveUploadedMediaInfo(channel courier.Channel, sendURL, serverId, hash, mediaKey, mediaValue string, clog *courier.ChannelLog) (*mediaUploadInfoPayload, error) { params := buildApiBaseParams(channel) params.Set(paramServerId, serverId) params.Set(paramHash, hash) @@ -576,7 +575,7 @@ func saveUploadedMediaInfo(channel courier.Channel, sendURL, serverId, hash, med req.URL.RawQuery = params.Encode() - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to save uploaded media info") } diff --git a/handlers/vk/handler_test.go b/handlers/vk/handler_test.go index e208a9694..d1c9af0b6 100644 --- a/handlers/vk/handler_test.go +++ b/handlers/vk/handler_test.go @@ -369,6 +369,7 @@ func TestDescribeURN(t *testing.T) { defer server.Close() handler := newHandler() + handler.Initialize(test.NewMockServer(courier.NewConfig(), test.NewMockBackend())) clog := courier.NewChannelLog(courier.ChannelLogTypeUnknown, testChannels[0], handler.RedactValues(testChannels[0])) urn, _ := urns.NewURNFromParts(urns.VKScheme, "123456789", "", "") data := map[string]string{"name": "John Doe"} diff --git a/handlers/wavy/handler.go b/handlers/wavy/handler.go index 073315425..e4531ff37 100644 --- a/handlers/wavy/handler.go +++ b/handlers/wavy/handler.go @@ -148,7 +148,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("username", username) req.Header.Set("authenticationtoken", token) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/wechat/handler.go b/handlers/wechat/handler.go index d745b209c..d104d6d4e 100644 --- a/handlers/wechat/handler.go +++ b/handlers/wechat/handler.go @@ -209,7 +209,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - resp, _, err := handlers.RequestHTTP(req, clog) + resp, _, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } @@ -239,7 +239,7 @@ func (h *handler) DescribeURN(ctx context.Context, channel courier.Channel, urn req, _ := http.NewRequest(http.MethodGet, reqURL.String(), nil) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("unable to look up contact data") } @@ -326,7 +326,7 @@ func (h *handler) fetchAccessToken(ctx context.Context, channel courier.Channel, req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return "", 0, err } diff --git a/handlers/whatsapp_legacy/handler.go b/handlers/whatsapp_legacy/handler.go index d03e70250..de11ebcd9 100644 --- a/handlers/whatsapp_legacy/handler.go +++ b/handlers/whatsapp_legacy/handler.go @@ -313,7 +313,6 @@ func (h *handler) BuildAttachmentRequest(ctx context.Context, b courier.Backend, // set the access token as the authorization header req, _ := http.NewRequest(http.MethodGet, attachmentURL, nil) - req.Header.Set("User-Agent", utils.HTTPUserAgent) setWhatsAppAuthHeader(&req.Header, channel) return req, nil } @@ -524,7 +523,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch for i, payload := range payloads { externalID := "" - wppID, externalID, err = sendWhatsAppMsg(conn, msg, sendPath, payload, clog) + wppID, externalID, err = h.sendWhatsAppMsg(conn, msg, sendPath, payload, clog) if err != nil { break } @@ -866,7 +865,7 @@ func (h *handler) fetchMediaID(msg courier.MsgOut, mimeType, mediaURL string, cl return "", errors.Wrapf(err, "error building media request") } - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { failedMediaCache.Set(failKey, true, cache.DefaultExpiration) return "", nil @@ -888,7 +887,7 @@ func (h *handler) fetchMediaID(msg courier.MsgOut, mimeType, mediaURL string, cl mediaType, _ := httpx.DetectContentType(respBody) req.Header.Add("Content-Type", mediaType) - resp, respBody, err = handlers.RequestHTTP(req, clog) + resp, respBody, err = h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { failedMediaCache.Set(failKey, true, cache.DefaultExpiration) return "", errors.Wrapf(err, "error uploading media to whatsapp") @@ -909,13 +908,13 @@ func (h *handler) fetchMediaID(msg courier.MsgOut, mimeType, mediaURL string, cl return mediaID, nil } -func sendWhatsAppMsg(rc redis.Conn, msg courier.MsgOut, sendPath *url.URL, payload any, clog *courier.ChannelLog) (string, string, error) { +func (h *handler) sendWhatsAppMsg(rc redis.Conn, msg courier.MsgOut, sendPath *url.URL, payload any, clog *courier.ChannelLog) (string, string, error) { jsonBody := jsonx.MustMarshal(payload) req, _ := http.NewRequest(http.MethodPost, sendPath.String(), bytes.NewReader(jsonBody)) req.Header = buildWhatsAppHeaders(msg.Channel()) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil { return "", "", err } @@ -955,7 +954,7 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.MsgOut, sendPath *url.URL, paylo } // check contact baseURL := fmt.Sprintf("%s://%s", sendPath.Scheme, sendPath.Host) - checkResp, err := checkWhatsAppContact(msg.Channel(), baseURL, msg.URN(), clog) + checkResp, err := h.checkWhatsAppContact(msg.Channel(), baseURL, msg.URN(), clog) if checkResp == nil { return "", "", err } @@ -1009,7 +1008,7 @@ func sendWhatsAppMsg(rc redis.Conn, msg courier.MsgOut, sendPath *url.URL, paylo reqRetry.URL.RawQuery = fmt.Sprintf("%s=1", retryParam) } - retryResp, retryRespBody, err := handlers.RequestHTTP(reqRetry, clog) + retryResp, retryRespBody, err := h.RequestHTTP(reqRetry, clog) if err != nil || retryResp.StatusCode/100 != 2 { return "", "", errors.New("error making retry request") } @@ -1041,7 +1040,6 @@ func buildWhatsAppHeaders(channel courier.Channel) http.Header { header := http.Header{ "Content-Type": []string{"application/json"}, "Accept": []string{"application/json"}, - "User-Agent": []string{utils.HTTPUserAgent}, } setWhatsAppAuthHeader(&header, channel) return header @@ -1079,7 +1077,7 @@ type mtContactCheckPayload struct { ForceCheck bool `json:"force_check"` } -func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN, clog *courier.ChannelLog) ([]byte, error) { +func (h *handler) checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN, clog *courier.ChannelLog) ([]byte, error) { payload := mtContactCheckPayload{ Blocking: "wait", Contacts: []string{fmt.Sprintf("+%s", urn.Path())}, @@ -1090,7 +1088,7 @@ func checkWhatsAppContact(channel courier.Channel, baseURL string, urn urns.URN, req, _ := http.NewRequest(http.MethodPost, sendURL, bytes.NewReader(reqBody)) req.Header = buildWhatsAppHeaders(channel) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return nil, errors.New("error checking contact") } diff --git a/handlers/yo/handler.go b/handlers/yo/handler.go index 49160ddd1..d225b08c0 100644 --- a/handlers/yo/handler.go +++ b/handlers/yo/handler.go @@ -130,7 +130,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/handlers/zenvia/handlers.go b/handlers/zenvia/handlers.go index 392e8d300..173beb857 100644 --- a/handlers/zenvia/handlers.go +++ b/handlers/zenvia/handlers.go @@ -238,7 +238,7 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, clog *courier.Ch req.Header.Set("Accept", "application/json") req.Header.Set("X-API-TOKEN", token) - resp, respBody, err := handlers.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) if err != nil || resp.StatusCode/100 != 2 { return status, nil } diff --git a/server.go b/server.go index 6210e3c3e..f080a1c73 100644 --- a/server.go +++ b/server.go @@ -91,9 +91,6 @@ func NewServerWithLogger(config *Config, backend Backend, logger *slog.Logger) S // if it encounters any unrecoverable (or ignorable) error, though its bias is to move forward despite // connection errors func (s *server) Start() error { - // set our user agent, needs to happen before we do anything so we don't change have threading issues - utils.HTTPUserAgent = fmt.Sprintf("Courier/%s", s.config.Version) - // configure librato if we have configuration options for it host, _ := os.Hostname() if s.config.LibratoUsername != "" { diff --git a/test/backend.go b/test/backend.go index 94d9d6e67..b4ba905c9 100644 --- a/test/backend.go +++ b/test/backend.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "net/http" "sync" "time" @@ -11,6 +12,7 @@ import ( _ "github.com/lib/pq" "github.com/nyaruka/courier" "github.com/nyaruka/courier/utils" + "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/gocommon/uuids" "github.com/pkg/errors" @@ -352,11 +354,19 @@ func (mb *MockBackend) ResolveMedia(ctx context.Context, mediaUrl string) (couri return media, nil } -// Health gives a string representing our health, empty for our mock func (mb *MockBackend) Health() string { return "" } +// Health gives a string representing our health, empty for our mock +func (mb *MockBackend) HttpClient(bool) *http.Client { + return http.DefaultClient +} + +func (mb *MockBackend) HttpAccess() *httpx.AccessConfig { + return nil +} + // Status returns a string describing the status of the service, queue size etc.. func (mb *MockBackend) Status() string { return "ALL GOOD" diff --git a/test/server.go b/test/server.go new file mode 100644 index 000000000..9f31b92d8 --- /dev/null +++ b/test/server.go @@ -0,0 +1,59 @@ +package test + +import ( + "sync" + + "github.com/go-chi/chi" + "github.com/nyaruka/courier" +) + +type MockServer struct { + backend courier.Backend + config *courier.Config + + stopChan chan bool + stopped bool +} + +func NewMockServer(config *courier.Config, backend courier.Backend) courier.Server { + return &MockServer{ + backend: backend, + config: config, + stopChan: make(chan bool), + } +} + +func (ms *MockServer) Config() *courier.Config { + return ms.config +} + +func (ms *MockServer) AddHandlerRoute(handler courier.ChannelHandler, method string, action string, logType courier.ChannelLogType, handlerFunc courier.ChannelHandleFunc) { + +} +func (ms *MockServer) GetHandler(courier.Channel) courier.ChannelHandler { + return nil +} + +func (ms *MockServer) Backend() courier.Backend { + return ms.backend +} + +func (ms *MockServer) WaitGroup() *sync.WaitGroup { + return nil +} +func (ms *MockServer) StopChan() chan bool { + return ms.stopChan +} +func (ms *MockServer) Stopped() bool { + return ms.stopped +} + +func (ms *MockServer) Router() chi.Router { + return nil +} + +func (ms *MockServer) Start() error { return nil } +func (ms *MockServer) Stop() error { + ms.stopped = true + return nil +} diff --git a/utils/http.go b/utils/http.go deleted file mode 100644 index db49c0ad1..000000000 --- a/utils/http.go +++ /dev/null @@ -1,51 +0,0 @@ -package utils - -import ( - "crypto/tls" - "net/http" - "sync" - "time" -) - -// GetHTTPClient returns the shared HTTP client used by all Courier threads -func GetHTTPClient() *http.Client { - once.Do(func() { - transport := http.DefaultTransport.(*http.Transport).Clone() - transport.MaxIdleConns = 64 - transport.MaxIdleConnsPerHost = 8 - transport.IdleConnTimeout = 15 * time.Second - client = &http.Client{ - Transport: transport, - Timeout: 30 * time.Second, - } - }) - - return client -} - -// GetInsecureHTTPClient returns the shared HTTP client used by all Courier threads -func GetInsecureHTTPClient() *http.Client { - insecureOnce.Do(func() { - insecureTransport := http.DefaultTransport.(*http.Transport).Clone() - insecureTransport.MaxIdleConns = 64 - insecureTransport.MaxIdleConnsPerHost = 8 - insecureTransport.IdleConnTimeout = 15 * time.Second - insecureTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - insecureClient = &http.Client{ - Transport: insecureTransport, - Timeout: 30 * time.Second, - } - }) - - return insecureClient -} - -var ( - client *http.Client - once sync.Once - - insecureClient *http.Client - insecureOnce sync.Once - - HTTPUserAgent = "Courier/vDev" -) diff --git a/utils/http_test.go b/utils/http_test.go deleted file mode 100644 index 160ef0480..000000000 --- a/utils/http_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package utils - -import "testing" - -func TestClient(t *testing.T) { - client := GetHTTPClient() - if client == nil { - t.Error("Client should not be nil") - } - - insecureClient := GetInsecureHTTPClient() - if insecureClient == nil { - t.Error("Insecure client should not be nil") - } - - if client == insecureClient || client.Transport == insecureClient.Transport { - t.Error("Client and insecure client should not be the same") - } - - client2 := GetHTTPClient() - if client != client2 { - t.Error("GetHTTPClient should always return same client") - } -}