From 88ec7f6f18d44c9e0f1e78f47116a4a9fa4fc9ac Mon Sep 17 00:00:00 2001 From: Benji Hooper Date: Thu, 23 Aug 2018 18:26:33 +0100 Subject: [PATCH] Added --pac-file flag to hoverctl start --- functional-tests/hoverctl/start_test.go | 23 ++++++ functional-tests/hoverctl/testdata/test.pac | 18 +++++ hoverctl/cmd/start.go | 8 ++ hoverctl/configuration/target.go | 1 + hoverctl/wrapper/hoverfly.go | 5 ++ hoverctl/wrapper/pac.go | 21 +++++ hoverctl/wrapper/pac_test.go | 85 +++++++++++++++++++++ 7 files changed, 161 insertions(+) create mode 100644 functional-tests/hoverctl/testdata/test.pac create mode 100644 hoverctl/wrapper/pac.go create mode 100644 hoverctl/wrapper/pac_test.go diff --git a/functional-tests/hoverctl/start_test.go b/functional-tests/hoverctl/start_test.go index 0534b112d..c047da1f8 100644 --- a/functional-tests/hoverctl/start_test.go +++ b/functional-tests/hoverctl/start_test.go @@ -295,4 +295,27 @@ var _ = Describe("hoverctl `start`", func() { Expect(output).To(ContainSubstring("Port 8500 was not free")) }) }) + + Context("with pac-file", func() { + BeforeEach(func() { + }) + + It("starts with pac file when defined", func() { + output := functional_tests.Run(hoverctlBinary, "start", "--pac-file", "testdata/test.pac") + + Expect(output).To(ContainSubstring("Hoverfly is now running")) + + response := functional_tests.DoRequest(sling.New().Get("http://localhost:8888/api/v2/hoverfly/pac")) + Expect(response.StatusCode).To(Equal(200)) + responseBody, err := ioutil.ReadAll(response.Body) + Expect(err).To(BeNil()) + Expect(string(responseBody)).To(ContainSubstring(`function FindProxyForURL(url, host) {`)) + }) + + It("errors when pac file not found", func() { + output := functional_tests.Run(hoverctlBinary, "start", "--pac-file", "unknown.pac") + + Expect(output).To(ContainSubstring("File not found: unknown.pac")) + }) + }) }) diff --git a/functional-tests/hoverctl/testdata/test.pac b/functional-tests/hoverctl/testdata/test.pac new file mode 100644 index 000000000..cfa607d25 --- /dev/null +++ b/functional-tests/hoverctl/testdata/test.pac @@ -0,0 +1,18 @@ +function FindProxyForURL(url, host) { + // our local URLs from the domains below example.com don't need a proxy: + if (shExpMatch(host, "*.example.com")) + { + return "DIRECT"; + } + + // URLs within this network are accessed through + // port 8080 on fastproxy.example.com: + if (isInNet(host, "10.0.0.0", "255.255.248.0")) + { + return "PROXY fastproxy.example.com:8080"; + } + + // All other requests go through port 8080 of proxy.example.com. + // should that fail to respond, go directly to the WWW: + return "PROXY proxy.example.com:8080; DIRECT"; +} \ No newline at end of file diff --git a/hoverctl/cmd/start.go b/hoverctl/cmd/start.go index 8d8acd907..1653e6e82 100644 --- a/hoverctl/cmd/start.go +++ b/hoverctl/cmd/start.go @@ -71,6 +71,13 @@ hoverctl configuration file. target.UpstreamProxyUrl, _ = cmd.Flags().GetString("upstream-proxy") target.HttpsOnly, _ = cmd.Flags().GetBool("https-only") + if pacFileLocation, _ := cmd.Flags().GetString("pac-file"); pacFileLocation != "" { + + pacFileData, err := configuration.ReadFile(pacFileLocation) + handleIfError(err) + target.PACFile = string(pacFileData) + } + if enableAuth, _ := cmd.Flags().GetBool("auth"); enableAuth { username, _ := cmd.Flags().GetString("username") password, _ := cmd.Flags().GetString("password") @@ -124,6 +131,7 @@ func init() { startCmd.Flags().String("key", "", "A path to a key file. Overrides the default Hoverfly TLS key") startCmd.Flags().Bool("disable-tls", false, "Disables TLS verification") startCmd.Flags().String("upstream-proxy", "", "A host for which Hoverfly will proxy its requests to") + startCmd.Flags().String("pac-file", "", "Configure upstream proxy by PAC file") startCmd.Flags().Bool("https-only", false, "Disables insecure HTTP traffic in Hoverfly") startCmd.Flags().String("listen-on-host", "", "Binds hoverfly listener to a host") diff --git a/hoverctl/configuration/target.go b/hoverctl/configuration/target.go index 79227c946..d14c15304 100644 --- a/hoverctl/configuration/target.go +++ b/hoverctl/configuration/target.go @@ -24,6 +24,7 @@ type Target struct { DisableTls bool `yaml:",omitempty"` UpstreamProxyUrl string `yaml:",omitempty"` + PACFile string `yaml:",omitempty"` HttpsOnly bool `yaml:",omitempty"` AuthEnabled bool diff --git a/hoverctl/wrapper/hoverfly.go b/hoverctl/wrapper/hoverfly.go index f211ff5c4..5580a3227 100644 --- a/hoverctl/wrapper/hoverfly.go +++ b/hoverctl/wrapper/hoverfly.go @@ -27,6 +27,7 @@ const ( v2ApiDestination = "/api/v2/hoverfly/destination" v2ApiState = "/api/v2/state" v2ApiMiddleware = "/api/v2/hoverfly/middleware" + v2ApiPac = "/api/v2/hoverfly/pac" v2ApiCache = "/api/v2/cache" v2ApiLogs = "/api/v2/logs" v2ApiHoverfly = "/api/v2/hoverfly" @@ -240,6 +241,10 @@ func Start(target *configuration.Target) error { } } + if target.PACFile != "" { + SetPACFile(*target) + } + return nil } diff --git a/hoverctl/wrapper/pac.go b/hoverctl/wrapper/pac.go new file mode 100644 index 000000000..0073b3ce8 --- /dev/null +++ b/hoverctl/wrapper/pac.go @@ -0,0 +1,21 @@ +package wrapper + +import ( + "github.com/SpectoLabs/hoverfly/hoverctl/configuration" +) + +func SetPACFile(target configuration.Target) error { + response, err := doRequest(target, "PUT", v2ApiPac, target.PACFile, nil) + if err != nil { + return err + } + + defer response.Body.Close() + + err = handleResponseError(response, "Could not set PAC file") + if err != nil { + return err + } + + return nil +} diff --git a/hoverctl/wrapper/pac_test.go b/hoverctl/wrapper/pac_test.go new file mode 100644 index 000000000..8e6440a60 --- /dev/null +++ b/hoverctl/wrapper/pac_test.go @@ -0,0 +1,85 @@ +package wrapper + +import ( + "testing" + + "github.com/SpectoLabs/hoverfly/core/handlers/v2" + "github.com/SpectoLabs/hoverfly/core/matching/matchers" + . "github.com/onsi/gomega" +) + +func Test_SetPACFile_CanSetPACFile(t *testing.T) { + RegisterTestingT(t) + + hoverfly.DeleteSimulation() + hoverfly.PutSimulation(v2.SimulationViewV5{ + v2.DataViewV5{ + RequestResponsePairs: []v2.RequestMatcherResponsePairViewV5{ + v2.RequestMatcherResponsePairViewV5{ + RequestMatcher: v2.RequestMatcherViewV5{ + Method: []v2.MatcherViewV5{ + { + Matcher: matchers.Exact, + Value: "PUT", + }, + }, + Path: []v2.MatcherViewV5{ + { + Matcher: matchers.Exact, + Value: "/api/v2/hoverfly/pac", + }, + }, + }, + Response: v2.ResponseDetailsViewV5{ + Status: 200, + Body: `PACFILE`, + }, + }, + }, + }, + v2.MetaView{ + SchemaVersion: "v2", + }, + }) + + err := SetPACFile(target) + Expect(err).To(BeNil()) +} + +func Test_SetPACFile_ServerError(t *testing.T) { + RegisterTestingT(t) + + hoverfly.DeleteSimulation() + hoverfly.PutSimulation(v2.SimulationViewV5{ + v2.DataViewV5{ + RequestResponsePairs: []v2.RequestMatcherResponsePairViewV5{ + v2.RequestMatcherResponsePairViewV5{ + RequestMatcher: v2.RequestMatcherViewV5{ + Method: []v2.MatcherViewV5{ + { + Matcher: matchers.Exact, + Value: "PUT", + }, + }, + Path: []v2.MatcherViewV5{ + { + Matcher: matchers.Exact, + Value: "/api/v2/hoverfly/pac", + }, + }, + }, + Response: v2.ResponseDetailsViewV5{ + Status: 400, + Body: `PACFILE`, + }, + }, + }, + }, + v2.MetaView{ + SchemaVersion: "v2", + }, + }) + + err := SetPACFile(target) + Expect(err).To(Not(BeNil())) +}