func Example() { // create registry registry := builtin.MakeRegistry() // create and register the filter specification spec := &customSpec{name: "customFilter"} registry.Register(spec) // create simple data client, with route entries referencing 'customFilter', // and clipping part of the request path: dataClient, err := testdataclient.NewDoc(` ui: Path("/ui/*page") -> customFilter("ui request") -> modPath("^/[^/]*", "") -> "https://ui.example.org"; api: Path("/api/*resource") -> customFilter("api request") -> modPath("^/[^/]*", "") -> "https://api.example.org"`) if err != nil { log.Fatal(err) } // create http.Handler: proxy.New( routing.New(routing.Options{ FilterRegistry: registry, DataClients: []routing.DataClient{dataClient}}), proxy.OptionsNone) }
func Example() { // create etcd data client: dataClient := etcd.New([]string{"https://etcd.example.org"}, "/skipper") // create http.Handler: proxy.New( routing.New(routing.Options{ FilterRegistry: builtin.MakeRegistry(), DataClients: []routing.DataClient{dataClient}}), proxy.OptionsNone) }
// Run skipper. func Run(o Options) error { // create authentication for Innkeeper auth := createInnkeeperAuthentication(o) // create data client dataClients, err := createDataClients(o, auth) if err != nil { return err } if len(dataClients) == 0 { log.Println("warning: no route source specified") } // create a filter registry with the available filter specs registered, // and register the custom filters registry := builtin.MakeRegistry() for _, f := range o.CustomFilters { registry.Register(f) } // create routing // create the proxy instance var mo routing.MatchingOptions if o.IgnoreTrailingSlash { mo = routing.IgnoreTrailingSlash } // ensure a non-zero poll timeout if o.SourcePollTimeout <= 0 { o.SourcePollTimeout = defaultSourcePollTimeout } // check for dev mode, and set update buffer of the routes updateBuffer := defaultRoutingUpdateBuffer if o.DevMode { updateBuffer = 0 } // create a routing engine routing := routing.New(routing.Options{ registry, mo, o.SourcePollTimeout, dataClients, updateBuffer}) // create the proxy proxy := proxy.New(routing, o.ProxyOptions, o.PriorityRoutes...) // start the http server log.Printf("listening on %v\n", o.Address) return http.ListenAndServe(o.Address, proxy) }
func Example() { // create etcd data client: dataClient, err := etcd.New(etcd.Options{[]string{"https://etcd.example.org"}, "/skipper", 0}) if err != nil { log.Fatal(err) } // create http.Handler: proxy.New( routing.New(routing.Options{ FilterRegistry: builtin.MakeRegistry(), DataClients: []routing.DataClient{dataClient}}), proxy.OptionsNone) }
func DisabledExample() { // create a target backend server. It will return the value of the 'X-Echo' request header // as the response body: targetServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(r.Header.Get("X-Echo"))) })) defer targetServer.Close() // create a filter registry, and register the custom filter: filterRegistry := builtin.MakeRegistry() filterRegistry.Register(&setEchoHeader{}) // create a data client with a predefined route, referencing the filter and a path condition // containing a wildcard called 'echo': routeDoc := fmt.Sprintf(`Path("/return/:echo") -> setEchoHeader() -> "%s"`, targetServer.URL) dataClient, err := testdataclient.NewDoc(routeDoc) if err != nil { log.Fatal(err) } // create routing object: rt := routing.New(routing.Options{ FilterRegistry: filterRegistry, DataClients: []routing.DataClient{dataClient}}) defer rt.Close() // create a proxy instance, and start an http server: proxy := proxy.New(rt, proxy.OptionsNone) defer proxy.Close() router := httptest.NewServer(proxy) defer router.Close() // make a request to the proxy: rsp, err := http.Get(fmt.Sprintf("%s/return/Hello,+world!", router.URL)) if err != nil { log.Fatal(err) } defer rsp.Body.Close() // print out the response: if _, err := io.Copy(os.Stdout, rsp.Body); err != nil { log.Fatal(err) } // Output: // Hello, world! }
func Example() { // open file with a routing table: dataClient, err := eskipfile.Open("/some/path/to/routing-table.eskip") if err != nil { // log.Fatal(err) return } // create http.Handler: proxy.New( routing.New(routing.Options{ DataClients: []routing.DataClient{dataClient}}), proxy.OptionsNone) }
func Example() { // create etcd data client: dataClient, err := etcd.New(etcd.Options{[]string{"https://etcd.example.org"}, "/skipper", 0, false}) if err != nil { log.Fatal(err) } // create routing object: rt := routing.New(routing.Options{ FilterRegistry: builtin.MakeRegistry(), DataClients: []routing.DataClient{dataClient}}) defer rt.Close() // create http.Handler: p := proxy.New(rt, proxy.OptionsNone) defer p.Close() }
func ExampleFilter() { // create a test filter and add to the registry: fr := builtin.MakeRegistry() fr.Register(&filtertest.Filter{FilterName: "testFilter"}) // create a data client, with a predefined route referencing the filter: dc, err := testdataclient.NewDoc(`Path("/some/path/:param") -> testFilter(3.14, "Hello, world!") -> "https://www.example.org"`) if err != nil { log.Fatal(err) } // create an http.Handler: proxy.New( routing.New(routing.Options{ DataClients: []routing.DataClient{dc}, FilterRegistry: fr}), proxy.OptionsNone) }
func ExamplePriorityRoute() { // create a routing doc forwarding all requests, // and load it in a data client: routeDoc := `* -> "https://www.example.org"` dataClient, err := testdataclient.NewDoc(routeDoc) if err != nil { log.Fatal(err) } // create a priority route making exceptions: pr := &priorityRoute{} // create an http.Handler: proxy.New( routing.New(routing.Options{ FilterRegistry: builtin.MakeRegistry(), DataClients: []routing.DataClient{dataClient}}), proxy.OptionsNone, pr) }
// to run this test, set `-args listener` for the test command func TestHTTPSServer(t *testing.T) { // TODO: figure why sometimes cannot connect if !testListener() { t.Skip() } a, err := findAddress() if err != nil { t.Fatal(err) } o := Options{ Address: a, CertPathTLS: "fixtures/test.crt", KeyPathTLS: "fixtures/test.key", } rt := routing.New(routing.Options{ FilterRegistry: builtin.MakeRegistry(), DataClients: []routing.DataClient{}}) defer rt.Close() proxy := proxy.New(rt, proxy.OptionsNone) defer proxy.Close() go listenAndServe(proxy, &o) r, err := waitConnGet("https://" + o.Address) if r != nil { defer r.Body.Close() } if err != nil { t.Fatalf("Cannot connect to the local server for testing: %s ", err.Error()) } if r.StatusCode != 404 { t.Fatalf("Status code should be 404, instead got: %d\n", r.StatusCode) } _, err = ioutil.ReadAll(r.Body) if err != nil { t.Fatalf("Failed to stream response body: %v", err) } }
func TestWithWrongKeyPathFails(t *testing.T) { a, err := findAddress() if err != nil { t.Fatal(err) } o := Options{Address: a, CertPathTLS: "fixtures/test.crt", KeyPathTLS: "fixtures/notFound.key", } rt := routing.New(routing.Options{ FilterRegistry: builtin.MakeRegistry(), DataClients: []routing.DataClient{}}) defer rt.Close() proxy := proxy.New(rt, proxy.OptionsNone) defer proxy.Close() err = listenAndServe(proxy, &o) if err == nil { t.Fatal(err) } }
// Run skipper. func Run(o Options) error { // init log err := initLog(o) if err != nil { return err } // init metrics metrics.Init(metrics.Options{ Listener: o.MetricsListener, Prefix: o.MetricsPrefix, EnableDebugGcMetrics: o.EnableDebugGcMetrics, EnableRuntimeMetrics: o.EnableRuntimeMetrics, }) // create authentication for Innkeeper auth := innkeeper.CreateInnkeeperAuthentication(innkeeper.AuthOptions{ InnkeeperAuthToken: o.InnkeeperAuthToken, OAuthCredentialsDir: o.OAuthCredentialsDir, OAuthUrl: o.OAuthUrl, OAuthScope: o.OAuthScope}) // create data client dataClients, err := createDataClients(o, auth) if err != nil { return err } if len(dataClients) == 0 { log.Warning("no route source specified") } // create a filter registry with the available filter specs registered, // and register the custom filters registry := builtin.MakeRegistry() for _, f := range o.CustomFilters { registry.Register(f) } // create routing // create the proxy instance var mo routing.MatchingOptions if o.IgnoreTrailingSlash { mo = routing.IgnoreTrailingSlash } // ensure a non-zero poll timeout if o.SourcePollTimeout <= 0 { o.SourcePollTimeout = defaultSourcePollTimeout } // check for dev mode, and set update buffer of the routes updateBuffer := defaultRoutingUpdateBuffer if o.DevMode { updateBuffer = 0 } // create a routing engine routing := routing.New(routing.Options{ registry, mo, o.SourcePollTimeout, dataClients, o.CustomPredicates, updateBuffer}) // create the proxy proxy := proxy.New(routing, o.ProxyOptions, o.PriorityRoutes...) // create the access log handler loggingHandler := logging.NewHandler(proxy) // start the http server log.Infof("proxy listener on %v", o.Address) return http.ListenAndServe(o.Address, loggingHandler) }
func TestRedirect(t *testing.T) { for _, ti := range []struct { msg string code int filterLocation string checkLocation string }{{ "schema only", http.StatusFound, "http:", "http://incoming.example.org/some/path?foo=1&bar=2", }, { "schema and host", http.StatusFound, "http://redirect.example.org", "http://redirect.example.org/some/path?foo=1&bar=2", }, { "schema, host and path", http.StatusFound, "http://redirect.example.org/some/other/path", "http://redirect.example.org/some/other/path?foo=1&bar=2", }, { "schema, host, path and query", http.StatusFound, "http://redirect.example.org/some/other/path?newquery=3", "http://redirect.example.org/some/other/path?newquery=3", }, { "host only", http.StatusFound, "//redirect.example.org", "https://redirect.example.org/some/path?foo=1&bar=2", }, { "host and path", http.StatusFound, "//redirect.example.org/some/other/path", "https://redirect.example.org/some/other/path?foo=1&bar=2", }, { "host, path and query", http.StatusFound, "//redirect.example.org/some/other/path?newquery=3", "https://redirect.example.org/some/other/path?newquery=3", }, { "path only", http.StatusFound, "/some/other/path", "https://incoming.example.org/some/other/path?foo=1&bar=2", }, { "path and query", http.StatusFound, "/some/other/path?newquery=3", "https://incoming.example.org/some/other/path?newquery=3", }, { "query only", http.StatusFound, "?newquery=3", "https://incoming.example.org/some/path?newquery=3", }, { "schema and path", http.StatusFound, "http:///some/other/path", "http://incoming.example.org/some/other/path?foo=1&bar=2", }, { "schema, path and query", http.StatusFound, "http:///some/other/path?newquery=3", "http://incoming.example.org/some/other/path?newquery=3", }, { "schema and query", http.StatusFound, "http://?newquery=3", "http://incoming.example.org/some/path?newquery=3", }, { "different code", http.StatusMovedPermanently, "/some/path", "https://incoming.example.org/some/path?foo=1&bar=2", }} { for _, tii := range []struct { msg string name string }{{ "deprecated", RedirectName, }, { "not deprecated", RedirectToName, }} { dc := testdataclient.New([]*eskip.Route{{ Shunt: true, Filters: []*eskip.Filter{{ Name: tii.name, Args: []interface{}{float64(ti.code), ti.filterLocation}}}}}) tl := loggingtest.New() rt := routing.New(routing.Options{ FilterRegistry: MakeRegistry(), DataClients: []routing.DataClient{dc}, Log: tl}) p := proxy.New(rt, proxy.OptionsNone) closeAll := func() { p.Close() rt.Close() tl.Close() } // pick up routing if err := tl.WaitFor("route settings applied", time.Second); err != nil { t.Error(err) closeAll() continue } req := &http.Request{ URL: &url.URL{Path: "/some/path", RawQuery: "foo=1&bar=2"}, Host: "incoming.example.org"} w := httptest.NewRecorder() p.ServeHTTP(w, req) if w.Code != ti.code { t.Error(ti.msg, tii.msg, "invalid status code", w.Code) } if w.Header().Get("Location") != ti.checkLocation { t.Error(ti.msg, tii.msg, "invalid location", w.Header().Get("Location")) } closeAll() } } }