@@ -0,0 +1,158 @@
1+package middleware
2+
3+import (
4+ "crypto/tls"
5+ "fmt"
6+ "net/http/httptest"
7+
8+ . "github.com/onsi/ginkgo"
9+ . "github.com/onsi/ginkgo/extensions/table"
10+ . "github.com/onsi/gomega"
11+)
12+
13+var _ = Describe("RedirectToHTTPS suite", func() {
14+ const httpsPort = "8443"
15+
16+ var permanentRedirectBody = func(address string) string {
17+ return fmt.Sprintf("<a href=\"%s\">Permanent Redirect</a>.\n\n", address)
18+ }
19+
20+ type requestTableInput struct {
21+ requestString string
22+ useTLS bool
23+ headers map[string]string
24+ expectedStatus int
25+ expectedBody string
26+ expectedLocation string
27+ }
28+
29+ DescribeTable("when serving a request",
30+ func(in *requestTableInput) {
31+ req := httptest.NewRequest("", in.requestString, nil)
32+ for k, v := range in.headers {
33+ req.Header.Add(k, v)
34+ }
35+ if in.useTLS {
36+ req.TLS = &tls.ConnectionState{}
37+ }
38+
39+ rw := httptest.NewRecorder()
40+
41+ handler := NewRedirectToHTTPS(httpsPort)(testHandler())
42+ handler.ServeHTTP(rw, req)
43+
44+ Expect(rw.Code).To(Equal(in.expectedStatus))
45+ Expect(rw.Body.String()).To(Equal(in.expectedBody))
46+
47+ if in.expectedLocation != "" {
48+ Expect(rw.Header().Values("Location")).To(ConsistOf(in.expectedLocation))
49+ }
50+ },
51+ Entry("without TLS", &requestTableInput{
52+ requestString: "http://example.com",
53+ useTLS: false,
54+ headers: map[string]string{},
55+ expectedStatus: 308,
56+ expectedBody: permanentRedirectBody("https://example.com"),
57+ expectedLocation: "https://example.com",
58+ }),
59+ Entry("with TLS", &requestTableInput{
60+ requestString: "https://example.com",
61+ useTLS: true,
62+ headers: map[string]string{},
63+ expectedStatus: 200,
64+ expectedBody: "test",
65+ }),
66+ Entry("without TLS and X-Forwarded-Proto=HTTPS", &requestTableInput{
67+ requestString: "http://example.com",
68+ useTLS: false,
69+ headers: map[string]string{
70+ "X-Forwarded-Proto": "HTTPS",
71+ },
72+ expectedStatus: 200,
73+ expectedBody: "test",
74+ }),
75+ Entry("with TLS and X-Forwarded-Proto=HTTPS", &requestTableInput{
76+ requestString: "https://example.com",
77+ useTLS: true,
78+ headers: map[string]string{
79+ "X-Forwarded-Proto": "HTTPS",
80+ },
81+ expectedStatus: 200,
82+ expectedBody: "test",
83+ }),
84+ Entry("without TLS and X-Forwarded-Proto=https", &requestTableInput{
85+ requestString: "http://example.com",
86+ useTLS: false,
87+ headers: map[string]string{
88+ "X-Forwarded-Proto": "https",
89+ },
90+ expectedStatus: 200,
91+ expectedBody: "test",
92+ }),
93+ Entry("with TLS and X-Forwarded-Proto=https", &requestTableInput{
94+ requestString: "https://example.com",
95+ useTLS: true,
96+ headers: map[string]string{
97+ "X-Forwarded-Proto": "https",
98+ },
99+ expectedStatus: 200,
100+ expectedBody: "test",
101+ }),
102+ Entry("without TLS and X-Forwarded-Proto=HTTP", &requestTableInput{
103+ requestString: "http://example.com",
104+ useTLS: false,
105+ headers: map[string]string{
106+ "X-Forwarded-Proto": "HTTP",
107+ },
108+ expectedStatus: 308,
109+ expectedBody: permanentRedirectBody("https://example.com"),
110+ expectedLocation: "https://example.com",
111+ }),
112+ Entry("with TLS and X-Forwarded-Proto=HTTP", &requestTableInput{
113+ requestString: "https://example.com",
114+ useTLS: true,
115+ headers: map[string]string{
116+ "X-Forwarded-Proto": "HTTP",
117+ },
118+ expectedStatus: 308,
119+ expectedBody: permanentRedirectBody("https://example.com"),
120+ expectedLocation: "https://example.com",
121+ }),
122+ Entry("without TLS and X-Forwarded-Proto=http", &requestTableInput{
123+ requestString: "https://example.com",
124+ useTLS: false,
125+ headers: map[string]string{
126+ "X-Forwarded-Proto": "http",
127+ },
128+ expectedStatus: 308,
129+ expectedBody: permanentRedirectBody("https://example.com"),
130+ expectedLocation: "https://example.com",
131+ }),
132+ Entry("with TLS and X-Forwarded-Proto=http", &requestTableInput{
133+ requestString: "https://example.com",
134+ useTLS: true,
135+ headers: map[string]string{
136+ "X-Forwarded-Proto": "http",
137+ },
138+ expectedStatus: 308,
139+ expectedBody: permanentRedirectBody("https://example.com"),
140+ expectedLocation: "https://example.com",
141+ }),
142+ Entry("without TLS on a non-standard port", &requestTableInput{
143+ requestString: "http://example.com:8080",
144+ useTLS: false,
145+ headers: map[string]string{},
146+ expectedStatus: 308,
147+ expectedBody: permanentRedirectBody("https://example.com:8443"),
148+ expectedLocation: "https://example.com:8443",
149+ }),
150+ Entry("with TLS on a non-standard port", &requestTableInput{
151+ requestString: "https://example.com:8443",
152+ useTLS: true,
153+ headers: map[string]string{},
154+ expectedStatus: 200,
155+ expectedBody: "test",
156+ }),
157+ )
158+})