From cf79155990d6fadb7eb4393e7dca402eead241da Mon Sep 17 00:00:00 2001 From: Andrew Querol Date: Mon, 17 May 2021 17:43:54 -0500 Subject: [PATCH] Switch away from using http.Header.Write() due to it stripping \n This is needed for some header strings that need to be sent to FreeSWITCH. For example the `extra-headers` header used in `sendevent NOTIFY` when providing a contact URI or the to/from URIs. This change makes the following header possible: extra-headers: Messages-Waiting: yes\r\nMessage-Account: example@1.1.1.1\r\nVoice-Message: 1/0\r\n The main tradeoff here may be an increase of time building the header string. However when testing this out the difference was within microseconds and within error margins. --- README.md | 2 +- command/command.go | 34 ++++++++++++++++++++++++++++++++++ command/event.go | 9 +-------- command/sendmsg.go | 10 +--------- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index d7bd456..20f4e1b 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ eslgo was written from the ground up in idiomatic Go for use in our production p go get github.com/percipia/eslgo ``` ``` -github.com/percipia/eslgo v1.4.0 +github.com/percipia/eslgo v1.4.1 ``` ## Overview diff --git a/command/command.go b/command/command.go index a5e9b95..7b5e062 100644 --- a/command/command.go +++ b/command/command.go @@ -10,7 +10,41 @@ */ package command +import ( + "net/textproto" + "sort" + "strings" +) + // Command - A basic interface for FreeSWITCH ESL commands. Implement this if you want to send your own raw data to FreeSIWTCH over the ESL connection. Do not add the eslgo.EndOfMessage(\r\n\r\n) marker, eslgo does that for you. type Command interface { BuildMessage() string } + +var crlfToLF = strings.NewReplacer("\r\n", "\n") + +// FormatHeaderString - Writes headers in a FreeSWITCH ESL friendly format. Converts headers containing \r\n to \n +func FormatHeaderString(headers textproto.MIMEHeader) string { + var ws strings.Builder + + keys := make([]string, len(headers)) + i := 0 + for key := range headers { + keys[i] = key + i++ + } + sort.Strings(keys) + + for _, key := range keys { + for _, value := range headers[key] { + value = crlfToLF.Replace(value) + value = textproto.TrimString(value) + ws.WriteString(key) + ws.WriteString(": ") + ws.WriteString(value) + ws.WriteString("\r\n") + } + } + // Remove the extra \r\n + return ws.String()[:ws.Len()-2] +} diff --git a/command/event.go b/command/event.go index 2a46950..002b7c5 100644 --- a/command/event.go +++ b/command/event.go @@ -12,7 +12,6 @@ package command import ( "fmt" - "net/http" "net/textproto" "strconv" "strings" @@ -78,13 +77,7 @@ func (s *SendEvent) BuildMessage() string { } // Format the headers - var headers strings.Builder - err := http.Header(s.Headers).Write(&headers) - if err != nil || headers.Len() < 3 { - return "" - } - // -2 to remove the trailing \r\n added by http.Header.Write - headerString := headers.String()[:headers.Len()-2] + headerString := FormatHeaderString(s.Headers) if _, ok := s.Headers["Content-Length"]; ok { return fmt.Sprintf("sendevent %s\r\n%s\r\n\r\n%s", s.Name, headerString, s.Body) } diff --git a/command/sendmsg.go b/command/sendmsg.go index 7aacd12..5e69db3 100644 --- a/command/sendmsg.go +++ b/command/sendmsg.go @@ -12,10 +12,8 @@ package command import ( "fmt" - "net/http" "net/textproto" "strconv" - "strings" ) type SendMessage struct { @@ -47,13 +45,7 @@ func (s *SendMessage) BuildMessage() string { } // Format the headers - var headers strings.Builder - err := http.Header(s.Headers).Write(&headers) - if err != nil || headers.Len() < 3 { - return "" - } - // -2 to remove the trailing \r\n added by http.Header.Write - headerString := headers.String()[:headers.Len()-2] + headerString := FormatHeaderString(s.Headers) if _, ok := s.Headers["Content-Length"]; ok { return fmt.Sprintf("sendmsg %s\r\n%s\r\n\r\n%s", s.UUID, headerString, s.Body) }