/* Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments Copyright (C) ITsysCOM GmbH This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ package engine import ( "bytes" "fmt" "io" "net/http" "net/url" "strings" "time" "github.com/cgrates/cgrates/utils" ) type HTTPPosterRequest struct { Header http.Header Body interface{} } // HTTPPostJSON posts without automatic failover func HTTPPostJSON(url string, content []byte) (respBody []byte, err error) { client := &http.Client{Transport: httpPstrTransport} var resp *http.Response if resp, err = client.Post(url, "application/json", bytes.NewBuffer(content)); err != nil { return } respBody, err = io.ReadAll(resp.Body) resp.Body.Close() if err != nil { return } if resp.StatusCode > 299 { err = fmt.Errorf("Unexpected status code received: %d", resp.StatusCode) } return } // NewHTTPPoster return a new HTTP poster func NewHTTPPoster(replyTimeout time.Duration, addr, contentType string, attempts int) (httposter *HTTPPoster) { return &HTTPPoster{ httpClient: &http.Client{Transport: httpPstrTransport, Timeout: replyTimeout}, addr: addr, contentType: contentType, attempts: attempts, } } // HTTPPoster used to post cdrs type HTTPPoster struct { httpClient *http.Client addr string contentType string attempts int } // PostValues will post the event func (pstr *HTTPPoster) PostValues(content interface{}, hdr http.Header) (err error) { _, err = pstr.GetResponse(content, hdr) return } // GetResponse will post the event and return the response func (pstr *HTTPPoster) GetResponse(content interface{}, hdr http.Header) (respBody []byte, err error) { fib := utils.Fib() for i := 0; i < pstr.attempts; i++ { var req *http.Request if req, err = pstr.getRequest(content, hdr); err != nil { utils.Logger.Warning(fmt.Sprintf(" Posting to : <%s>, error creating request: <%s>", pstr.addr, err.Error())) return } if respBody, err = pstr.do(req); err != nil { if i+1 < pstr.attempts { time.Sleep(time.Duration(fib()) * time.Second) } continue } return } return } func (pstr *HTTPPoster) do(req *http.Request) (respBody []byte, err error) { var resp *http.Response if resp, err = pstr.httpClient.Do(req); err != nil { utils.Logger.Warning(fmt.Sprintf(" Posting to : <%s>, error: <%s>", pstr.addr, err.Error())) return } respBody, err = io.ReadAll(resp.Body) resp.Body.Close() if err != nil { utils.Logger.Warning(fmt.Sprintf(" Posting to : <%s>, error: <%s>", pstr.addr, err.Error())) return } if resp.StatusCode > 299 { err = fmt.Errorf("unexpected status code received: <%d>", resp.StatusCode) utils.Logger.Warning(fmt.Sprintf(" Posting to : <%s>, unexpected status code received: <%d>", pstr.addr, resp.StatusCode)) return } return } func (pstr *HTTPPoster) getRequest(content interface{}, hdr http.Header) (req *http.Request, err error) { var body io.Reader if pstr.contentType == utils.ContentForm { body = strings.NewReader(content.(url.Values).Encode()) } else { body = bytes.NewBuffer(content.([]byte)) } contentType := "application/x-www-form-urlencoded" if pstr.contentType == utils.ContentJSON { contentType = "application/json" } hdr.Set("Content-Type", contentType) if req, err = http.NewRequest(http.MethodPost, pstr.addr, body); err != nil { return } req.Header = hdr return }