@@ -5,6 +5,7 @@ import (
@@ -17,16 +18,17 @@ import (
17const hello = "Hello World!"
18const hello = "Hello World!"
19var _ = Describe("Server", func() {
20var _ = Describe("Server", func() {
20 handler := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
22 handler := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
21 rw.Write([]byte(hello))
23 rw.Write([]byte(hello))
24 Context("NewServer", func() {
25 Context("NewServer", func() {
25 type newServerTableInput struct {
26 type newServerTableInput struct {
27 expectedErr error
28 expectedErr error
28 expectHTTPListener bool
29 expectHTTPListener bool
29 expectTLSListener bool
30 expectTLSListener bool
@@ -34,6 +36,15 @@ var _ = Describe("Server", func() {
34 if in.ipv6 {
36 if in.ipv6 {
35 skipDevContainer()
37 skipDevContainer()
41+ l, err := net.Listen("tcp", in.fdAddr)
42+ Expect(err).ToNot(HaveOccurred())
43+ f, err := l.(*net.TCPListener).File()
44+ Expect(err).ToNot(HaveOccurred())
45+ in.opts.fdFiles = []*os.File{f}
37 srv, err := NewServer(in.opts)
48 srv, err := NewServer(in.opts)
38 if in.expectedErr != nil {
49 if in.expectedErr != nil {
39 Expect(err).To(MatchError(ContainSubstring(in.expectedErr.Error())))
50 Expect(err).To(MatchError(ContainSubstring(in.expectedErr.Error())))
@@ -55,6 +66,46 @@ var _ = Describe("Server", func() {
55 Expect(s.tlsListener.Close()).To(Succeed())
66 Expect(s.tlsListener.Close()).To(Succeed())
69+ Entry("with a valid non-lowercase fd IPv4 bind address", &newServerTableInput{
75+ expectHTTPListener: true,
76+ expectTLSListener: false,
77+ fdAddr: "127.0.0.1:0",
79+ Entry("with a valid fd IPv4 bind address", &newServerTableInput{
85+ expectHTTPListener: true,
86+ expectTLSListener: false,
87+ fdAddr: "127.0.0.1:0",
89+ Entry("with a invalid fd named bind address", &newServerTableInput{
92+ BindAddress: "fd:hello",
94+ expectedErr: fmt.Errorf("error setting up listener: listen (file, %s) failed: listen failed: fd with name is not implemented yet", "hello"),
95+ expectHTTPListener: true,
96+ expectTLSListener: false,
97+ fdAddr: "127.0.0.1:0",
99+ Entry("with a invalid fd IPv4 bind address", &newServerTableInput{
102+ BindAddress: "fd:4",
104+ expectedErr: fmt.Errorf("error setting up listener: listen (file, %d) failed: listen failed: fd outside of range of available file descriptors", 4),
105+ expectHTTPListener: true,
106+ expectTLSListener: false,
107+ fdAddr: "127.0.0.1:0",
58 Entry("with an ipv4 valid http bind address", &newServerTableInput{
109 Entry("with an ipv4 valid http bind address", &newServerTableInput{
59 opts: Opts{
110 opts: Opts{
60 Handler: handler,
111 Handler: handler,
@@ -86,6 +137,21 @@ var _ = Describe("Server", func() {
86 expectHTTPListener: false,
137 expectHTTPListener: false,
87 expectTLSListener: true,
138 expectTLSListener: true,
140+ Entry("with a both a fd valid http and ipv4 valid https bind address, and valid TLS config", &newServerTableInput{
143+ BindAddress: "fd:3",
144+ SecureBindAddress: "127.0.0.1:0",
146+ Key: &ipv4KeyDataSource,
147+ Cert: &ipv4CertDataSource,
151+ expectHTTPListener: true,
152+ expectTLSListener: true,
153+ fdAddr: "127.0.0.1:0",
89 Entry("with a both a ipv4 valid http and ipv4 valid https bind address, and valid TLS config", &newServerTableInput{
155 Entry("with a both a ipv4 valid http and ipv4 valid https bind address, and valid TLS config", &newServerTableInput{
90 opts: Opts{
156 opts: Opts{
91 Handler: handler,
157 Handler: handler,
@@ -300,6 +366,27 @@ var _ = Describe("Server", func() {
300 expectHTTPListener: false,
366 expectHTTPListener: false,
301 expectTLSListener: true,
367 expectTLSListener: true,
369+ Entry("with valid fd IPv6 bind address", &newServerTableInput{
372+ BindAddress: "fd:3",
375+ expectHTTPListener: true,
376+ expectTLSListener: false,
380+ Entry("with a invalid fd IPv6 bind address", &newServerTableInput{
383+ BindAddress: "fd:4",
385+ expectedErr: fmt.Errorf("error setting up listener: listen (file, %d) failed: listen failed: fd outside of range of available file descriptors", 4),
386+ expectHTTPListener: true,
387+ expectTLSListener: false,
303 Entry("with an ipv6 valid http bind address", &newServerTableInput{
390 Entry("with an ipv6 valid http bind address", &newServerTableInput{
304 opts: Opts{
391 opts: Opts{
305 Handler: handler,
392 Handler: handler,
@@ -334,6 +421,22 @@ var _ = Describe("Server", func() {
334 expectTLSListener: true,
421 expectTLSListener: true,
335 ipv6: true,
422 ipv6: true,
424+ Entry("with a both a fd valid http and ipv6 valid https bind address, and valid TLS config", &newServerTableInput{
427+ BindAddress: "fd:3",
428+ SecureBindAddress: "[::1]:0",
430+ Key: &ipv6KeyDataSource,
431+ Cert: &ipv6CertDataSource,
435+ expectHTTPListener: true,
436+ expectTLSListener: true,
337 Entry("with a both a ipv6 valid http and ipv6 valid https bind address, and valid TLS config", &newServerTableInput{
440 Entry("with a both a ipv6 valid http and ipv6 valid https bind address, and valid TLS config", &newServerTableInput{
338 opts: Opts{
441 opts: Opts{
339 Handler: handler,
442 Handler: handler,
@@ -563,6 +666,58 @@ var _ = Describe("Server", func() {
669+ Context("with an fd ipv4 http server", func() {
670+ var listenAddr string
673+ l, err := net.Listen("tcp", "127.0.0.1:0")
674+ Expect(err).ToNot(HaveOccurred())
675+ f, err := l.(*net.TCPListener).File()
676+ Expect(err).ToNot(HaveOccurred())
678+ srv, err = NewServer(Opts{
680+ BindAddress: "fd:3",
681+ fdFiles: []*os.File{f},
683+ Expect(err).ToNot(HaveOccurred())
685+ listenAddr = fmt.Sprintf("http://%s/", l.Addr().String())
688+ It("Starts the server and serves the handler", func() {
690+ defer GinkgoRecover()
691+ Expect(srv.Start(ctx)).To(Succeed())
694+ resp, err := httpGet(ctx, listenAddr)
695+ Expect(err).ToNot(HaveOccurred())
696+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
698+ body, err := io.ReadAll(resp.Body)
699+ Expect(err).ToNot(HaveOccurred())
700+ Expect(string(body)).To(Equal(hello))
703+ It("Stops the server when the context is cancelled", func() {
705+ defer GinkgoRecover()
706+ Expect(srv.Start(ctx)).To(Succeed())
709+ _, err := httpGet(ctx, listenAddr)
710+ Expect(err).ToNot(HaveOccurred())
714+ Eventually(func() error {
715+ _, err := httpGet(ctx, listenAddr)
717+ }).Should(HaveOccurred())
566 Context("with an ipv4 http server", func() {
721 Context("with an ipv4 http server", func() {
567 var listenAddr string
722 var listenAddr string
@@ -682,6 +837,88 @@ var _ = Describe("Server", func() {
840+ Context("with a fd ipv4 http and an ipv4 https server", func() {
841+ var listenAddr, secureListenAddr string
844+ l, err := net.Listen("tcp", "127.0.0.1:0")
845+ Expect(err).ToNot(HaveOccurred())
846+ f, err := l.(*net.TCPListener).File()
847+ Expect(err).ToNot(HaveOccurred())
849+ srv, err = NewServer(Opts{
851+ BindAddress: "fd:3",
852+ fdFiles: []*os.File{f},
853+ SecureBindAddress: "127.0.0.1:0",
855+ Key: &ipv4KeyDataSource,
856+ Cert: &ipv4CertDataSource,
859+ Expect(err).ToNot(HaveOccurred())
861+ s, ok := srv.(*server)
862+ Expect(ok).To(BeTrue())
864+ listenAddr = fmt.Sprintf("http://%s/", l.Addr().String())
865+ secureListenAddr = fmt.Sprintf("https://%s/", s.tlsListener.Addr().String())
868+ It("Starts the server and serves the handler on http", func() {
870+ defer GinkgoRecover()
871+ Expect(srv.Start(ctx)).To(Succeed())
874+ resp, err := httpGet(ctx, listenAddr)
875+ Expect(err).ToNot(HaveOccurred())
876+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
878+ body, err := io.ReadAll(resp.Body)
879+ Expect(err).ToNot(HaveOccurred())
880+ Expect(string(body)).To(Equal(hello))
883+ It("Starts the server and serves the handler on https", func() {
885+ defer GinkgoRecover()
886+ Expect(srv.Start(ctx)).To(Succeed())
889+ resp, err := httpGet(ctx, secureListenAddr)
890+ Expect(err).ToNot(HaveOccurred())
891+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
893+ body, err := io.ReadAll(resp.Body)
894+ Expect(err).ToNot(HaveOccurred())
895+ Expect(string(body)).To(Equal(hello))
898+ It("Stops both servers when the context is cancelled", func() {
900+ defer GinkgoRecover()
901+ Expect(srv.Start(ctx)).To(Succeed())
904+ _, err := httpGet(ctx, listenAddr)
905+ Expect(err).ToNot(HaveOccurred())
906+ _, err = httpGet(ctx, secureListenAddr)
907+ Expect(err).ToNot(HaveOccurred())
911+ Eventually(func() error {
912+ _, err := httpGet(ctx, listenAddr)
914+ }).Should(HaveOccurred())
915+ Eventually(func() error {
916+ _, err := httpGet(ctx, secureListenAddr)
918+ }).Should(HaveOccurred())
685 Context("with both an ipv4 http and an ipv4 https server", func() {
922 Context("with both an ipv4 http and an ipv4 https server", func() {
686 var listenAddr, secureListenAddr string
923 var listenAddr, secureListenAddr string
@@ -880,6 +1117,89 @@ var _ = Describe("Server", func() {
1120+ Context("with an fd ipv6 http and an ipv6 https server", func() {
1121+ var listenAddr, secureListenAddr string
1123+ BeforeEach(func() {
1125+ l, err := net.Listen("tcp", "[::1]:0")
1126+ Expect(err).ToNot(HaveOccurred())
1127+ f, err := l.(*net.TCPListener).File()
1128+ Expect(err).ToNot(HaveOccurred())
1130+ srv, err = NewServer(Opts{
1132+ BindAddress: "fd:3",
1133+ fdFiles: []*os.File{f},
1134+ SecureBindAddress: "[::1]:0",
1136+ Key: &ipv6KeyDataSource,
1137+ Cert: &ipv6CertDataSource,
1140+ Expect(err).ToNot(HaveOccurred())
1142+ s, ok := srv.(*server)
1143+ Expect(ok).To(BeTrue())
1145+ listenAddr = fmt.Sprintf("http://%s/", l.Addr().String())
1146+ secureListenAddr = fmt.Sprintf("https://%s/", s.tlsListener.Addr().String())
1149+ It("Starts the server and serves the handler on http", func() {
1151+ defer GinkgoRecover()
1152+ Expect(srv.Start(ctx)).To(Succeed())
1155+ resp, err := httpGet(ctx, listenAddr)
1156+ Expect(err).ToNot(HaveOccurred())
1157+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
1159+ body, err := io.ReadAll(resp.Body)
1160+ Expect(err).ToNot(HaveOccurred())
1161+ Expect(string(body)).To(Equal(hello))
1164+ It("Starts the server and serves the handler on https", func() {
1166+ defer GinkgoRecover()
1167+ Expect(srv.Start(ctx)).To(Succeed())
1170+ resp, err := httpGet(ctx, secureListenAddr)
1171+ Expect(err).ToNot(HaveOccurred())
1172+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
1174+ body, err := io.ReadAll(resp.Body)
1175+ Expect(err).ToNot(HaveOccurred())
1176+ Expect(string(body)).To(Equal(hello))
1179+ It("Stops both servers when the context is cancelled", func() {
1181+ defer GinkgoRecover()
1182+ Expect(srv.Start(ctx)).To(Succeed())
1185+ _, err := httpGet(ctx, listenAddr)
1186+ Expect(err).ToNot(HaveOccurred())
1187+ _, err = httpGet(ctx, secureListenAddr)
1188+ Expect(err).ToNot(HaveOccurred())
1192+ Eventually(func() error {
1193+ _, err := httpGet(ctx, listenAddr)
1195+ }).Should(HaveOccurred())
1196+ Eventually(func() error {
1197+ _, err := httpGet(ctx, secureListenAddr)
1199+ }).Should(HaveOccurred())
883 Context("with both an ipv6 http and an ipv6 https server", func() {
1203 Context("with both an ipv6 http and an ipv6 https server", func() {
884 var listenAddr, secureListenAddr string
1204 var listenAddr, secureListenAddr string