Forward Proxy support made Inline.
diff --git a/README.md b/README.md index 6bf9a09..551ba2f 100644 --- a/README.md +++ b/README.md
@@ -65,3 +65,8 @@ This service provides the primitives to perform SQL operations on the database. It also provides the provision to alter DB connection pool settings via ConfigDBMaxConns, ConfigDBIdleConns and configDBConnsTimeout configuration parameters. They currently are defaulted to 1000 connections, 1000 connections and 120 seconds respectively. More details on this can be found at https://golang.org/pkg/database/sql + + +## Making http.Client calls through Forward proxy server +If forward proxy server related parameters are set, util.Transport() will provide the Transport roundtripper with the forward proxy parameters set. +
diff --git a/apid.go b/apid.go index fd325d5..3613765 100644 --- a/apid.go +++ b/apid.go
@@ -24,6 +24,12 @@ SystemEventsSelector EventSelector = "system event" ShutdownEventSelector EventSelector = "shutdown event" ShutdownTimeout time.Duration = 10 * time.Second + configfwdProxyURL = "configfwdproxy_url" + configfwdProxyProt = "configfwdproxy_prot" + configfwdProxyUser = "configfwdproxy_user" + configfwdProxyPasswd = "configfwdproxy_passwd" + configfwdProxyPort = "configfwdproxy_port" + configfwdProxyPortURL = "configcompletefwdp" ) var ( @@ -43,6 +49,23 @@ Log() LogService } +func setFwdProxyConfig(config ConfigService) { + var pURL string + + config.SetDefault(configfwdProxyProt, "https") + fwdPrxy := config.GetString(configfwdProxyURL) + fwdprxyProt := config.GetString(configfwdProxyProt) + fwdPrxyUser := config.GetString(configfwdProxyUser) + fwdPrxyPass := config.GetString(configfwdProxyPasswd) + fwdPrxyPort := config.GetString(configfwdProxyPort) + if fwdPrxy != "" && fwdPrxyUser != "" && fwdPrxyPort != "" { + pURL = fwdprxyProt + "://" + fwdPrxyUser + ":" + fwdPrxyPass + "@" + fwdPrxy + ":" + fwdPrxyPort + } else if fwdPrxy != "" && fwdPrxyPort != "" { + pURL = fwdprxyProt + "://" + fwdPrxy + ":" + fwdPrxyPort + } + config.Set(configfwdProxyPortURL, pURL) +} + type PluginInitFunc func(Services) (PluginData, error) // passed Services can be a factory - makes copies and maintains returned references @@ -60,7 +83,7 @@ if err := os.MkdirAll(lsp, 0700); err != nil { ss.log.Panicf("can't create local storage path %s: %v", lsp, err) } - + setFwdProxyConfig(ss.config) ss.events = s.Events() ss.api = s.API() ss.data = s.Data()
diff --git a/util/util.go b/util/util.go index ad936ff..da35113 100644 --- a/util/util.go +++ b/util/util.go
@@ -14,12 +14,23 @@ package util + import ( "github.com/google/uuid" "net/http" + "net/url" "time" ) +const ( + configfwdProxyURL = "configfwdProxyURL" + configfwdProxyUser = "configfwdProxyUser" + configfwdProxyPasswd = "configfwdProxyPasswd" + configfwdProxyProtocol = "configfwdProxyProtocol" + configfwdProxyPort = "configfwdProxyPort" +) + + func IsValidUUID(id string) bool { _, err := uuid.Parse(id) return err == nil @@ -29,6 +40,24 @@ return uuid.New().String() } + +func Transport(pURL string) *http.Transport { + var tr http.Transport + if pURL != "" { + paURL, err := url.Parse(pURL) + if err != nil { + panic("Error parsing proxy URL") + } + tr = http.Transport{ + Proxy: http.ProxyURL(paURL), + } + } else { + tr = http.Transport{ + } + } + return &tr +} + // distributeEvents() receives elements from deliverChan, and send them to subscribers // Sending a `chan interface{}` to addSubscriber adds a new subscriber. // It closes the subscriber channel after sending the element.
diff --git a/util/util_test.go b/util/util_test.go index 54fd997..8ca741b 100644 --- a/util/util_test.go +++ b/util/util_test.go
@@ -18,6 +18,8 @@ . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + + "net/http/httptest" "github.com/apid/apid-core/util" "math/rand" "net/http" @@ -61,6 +63,50 @@ }) }) + Context("Forward Proxy Protocol", func() { + It("Verify Forward proxying to server works", func() { + var maxIdleConnsPerHost = 10 + var tr *http.Transport + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Fail("Cant come here, as we have not forwarded request from fwdPrxyServer") + })) + fwdPrxyServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Expect(r.Header.Get("foo")).Should(Equal("bar")) + })) + tr = util.Transport(fwdPrxyServer.URL) + tr.MaxIdleConnsPerHost = maxIdleConnsPerHost + var rspcnt int = 0 + ch := make(chan *http.Response) + client := &http.Client{Transport: tr} + for i := 0; i < 2*maxIdleConnsPerHost; i++ { + go func(client *http.Client) { + defer GinkgoRecover() + req, err := http.NewRequest("GET", server.URL, nil) + req.Header.Set("foo", "bar") + resp, err := client.Do(req) + if err != nil { + Fail("Unable to process Client request") + } + ch <- resp + resp.Body.Close() + + }(client) + } + for { + select { + case resp := <-ch: + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + if rspcnt >= 2*maxIdleConnsPerHost-1 { + return + } + rspcnt++ + default: + } + } + + }, 3) + }) + Context("Long polling utils", func() { It("DistributeEvents", func() { // make test data