From 0288eb9d38bc1e53dd4850ba851e264f0c0f8ab8 Mon Sep 17 00:00:00 2001
From: Viktor <viktor@farcic.com>
Date: Fri, 3 Mar 2017 00:12:43 +0100
Subject: [PATCH] Moved "X-Forwarded-Proto https" behind the "xForwardedProto"
 conditional.

---
 actions/reconfigure.go      |  2 +-
 actions/reconfigure_test.go | 49 +++++++++++++++++++++++--------------
 docs/usage.md               |  1 +
 proxy/types.go              |  2 ++
 server.go                   |  1 +
 server_test.go              | 23 +++++++++++++++++
 6 files changed, 58 insertions(+), 20 deletions(-)

diff --git a/actions/reconfigure.go b/actions/reconfigure.go
index 782fae16..388e0b3f 100644
--- a/actions/reconfigure.go
+++ b/actions/reconfigure.go
@@ -354,7 +354,7 @@ backend %s{{$.ServiceName}}-be{{.Port}}
     mode %s`,
 		prefix, rmode,
 	)
-	if strings.EqualFold(rmode, "http") {
+	if sr.XForwardedProto {
 		tmpl += `
     http-request add-header X-Forwarded-Proto https if { ssl_fc }`
 	}
diff --git a/actions/reconfigure_test.go b/actions/reconfigure_test.go
index a2fc5f72..ef1367a6 100644
--- a/actions/reconfigure_test.go
+++ b/actions/reconfigure_test.go
@@ -48,7 +48,6 @@ func (s *ReconfigureTestSuite) SetupTest() {
 	s.ConsulTemplateBe = `
 backend myService-be
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     {{range $i, $e := service "myService" "any"}}
     server {{$e.Node}}_{{$i}}_{{$e.Port}} {{$e.Address}}:{{$e.Port}} check
     {{end}}`
@@ -159,7 +158,6 @@ func (s ReconfigureTestSuite) Test_GetTemplates_AddsHttpAuth_WhenUsersEnvIsPrese
 	expected := `
 backend myService-be
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     {{range $i, $e := service "myService" "any"}}
     server {{$e.Node}}_{{$i}}_{{$e.Port}} {{$e.Address}}:{{$e.Port}} check
     {{end}}
@@ -184,7 +182,6 @@ func (s ReconfigureTestSuite) Test_GetTemplates_AddsHttpAuth_WhenUsersIsPresent(
 
 backend myService-be
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     {{range $i, $e := service "myService" "any"}}
     server {{$e.Node}}_{{$i}}_{{$e.Port}} {{$e.Address}}:{{$e.Port}} check
     {{end}}
@@ -209,7 +206,6 @@ func (s ReconfigureTestSuite) Test_GetTemplates_AddsHttpAuth_WhenUsersIsPresentA
 
 backend myService-be
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     {{range $i, $e := service "myService" "any"}}
     server {{$e.Node}}_{{$i}}_{{$e.Port}} {{$e.Address}}:{{$e.Port}} check
     {{end}}
@@ -230,7 +226,6 @@ func (s ReconfigureTestSuite) Test_GetTemplates_ReturnsFormattedContent_WhenMode
 		expected := `
 backend myService-be1234
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     server myService myService:1234`
 
 		_, actual, _ := s.reconfigure.GetTemplates(&s.reconfigure.Service)
@@ -248,7 +243,6 @@ func (s ReconfigureTestSuite) Test_GetTemplates_AddSllVerifyNone_WhenSslVerifyNo
 		expected := `
 backend myService-be1234
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     server myService myService:1234 ssl verify none`
 
 		_, actual, _ := s.reconfigure.GetTemplates(&s.reconfigure.Service)
@@ -280,7 +274,6 @@ func (s ReconfigureTestSuite) Test_GetTemplates_AddsHttpAuth_WhenModeIsSwarmAndU
 	expected := `
 backend myService-be1234
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     server myService myService:1234
     acl defaultUsersAcl http_auth(defaultUsers)
     http-request auth realm defaultRealm if !defaultUsersAcl
@@ -305,7 +298,6 @@ func (s ReconfigureTestSuite) Test_GetTemplates_AddsHttpAuth_WhenModeIsSwarmAndU
 
 backend myService-be1234
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     server myService myService:1234
     acl myServiceUsersAcl http_auth(myServiceUsers)
     http-request auth realm myServiceRealm if !myServiceUsersAcl
@@ -320,12 +312,10 @@ func (s ReconfigureTestSuite) Test_GetTemplates_AddsHttpsPort_WhenPresent() {
 	expectedBack := `
 backend myService-be1234
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     server myService myService:1234
 
 backend https-myService-be1234
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     server myService myService:4321`
 	s.reconfigure.ServiceDest[0].Port = "1234"
 	s.reconfigure.Mode = "service"
@@ -340,7 +330,6 @@ func (s ReconfigureTestSuite) Test_GetTemplates_AddsTimeoutServer_WhenPresent()
 	expectedBack := `
 backend myService-be1234
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     timeout server 9999s
     server myService myService:1234`
 	s.reconfigure.ServiceDest[0].Port = "1234"
@@ -356,7 +345,6 @@ func (s ReconfigureTestSuite) Test_GetTemplates_AddsTimeoutTunnel_WhenPresent()
 	expectedBack := `
 backend myService-be1234
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     timeout tunnel 9999s
     server myService myService:1234`
 	s.reconfigure.ServiceDest[0].Port = "1234"
@@ -377,15 +365,12 @@ func (s ReconfigureTestSuite) Test_GetTemplates_AddsMultipleDestinations() {
 	expectedBack := `
 backend myService-be1111
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     server myService myService:1111
 backend myService-be3333
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     server myService myService:3333
 backend myService-be5555
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     server myService myService:5555`
 	s.reconfigure.ServiceDest = sd
 	s.reconfigure.Mode = "service"
@@ -402,7 +387,6 @@ func (s ReconfigureTestSuite) Test_GetTemplates_AddsReqRep_WhenReqRepSearchAndRe
 	expected := fmt.Sprintf(`
 backend myService-be
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     reqrep %s     %s
     {{range $i, $e := service "%s" "any"}}
     server {{$e.Node}}_{{$i}}_{{$e.Port}} {{$e.Address}}:{{$e.Port}} check
@@ -423,7 +407,6 @@ func (s ReconfigureTestSuite) Test_GetTemplates_AddsHttpRequestSetPath_WhenReqPa
 	expected := fmt.Sprintf(`
 backend myService-be
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     http-request set-path %%[path,regsub(%s,%s)]
     {{range $i, $e := service "%s" "any"}}
     server {{$e.Node}}_{{$i}}_{{$e.Port}} {{$e.Address}}:{{$e.Port}} check
@@ -576,7 +559,6 @@ func (s ReconfigureTestSuite) Test_Execute_WritesBeTemplate_WhenModeIsService()
 		`
 backend %s-be%s
     mode http
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
     server %s %s:%s`,
 		s.ServiceName,
 		s.reconfigure.ServiceDest[0].Port,
@@ -600,7 +582,36 @@ backend %s-be%s
 
 func (s ReconfigureTestSuite) Test_Execute_WritesBeTemplate_WhenModeIsSwarm() {
 	s.reconfigure.Mode = "sWArm"
-	s.reconfigure.ServiceDest[0].Port = "1234"
+	var actualFilename, actualData string
+	expectedFilename := fmt.Sprintf("%s/%s-be.cfg", s.TemplatesPath, s.ServiceName)
+	expectedData := fmt.Sprintf(
+		`
+backend %s-be%s
+    mode http
+    server %s %s:%s`,
+		s.ServiceName,
+		s.reconfigure.ServiceDest[0].Port,
+		s.ServiceName,
+		s.ServiceName,
+		s.reconfigure.ServiceDest[0].Port,
+	)
+	writeBeTemplateOrig := writeBeTemplate
+	defer func() { writeBeTemplate = writeBeTemplateOrig }()
+	writeBeTemplate = func(filename string, data []byte, perm os.FileMode) error {
+		actualFilename = filename
+		actualData = string(data)
+		return nil
+	}
+
+	s.reconfigure.Execute([]string{})
+
+	s.Equal(expectedFilename, actualFilename)
+	s.Equal(expectedData, actualData)
+}
+
+func (s ReconfigureTestSuite) Test_Execute_AddsXForwardedProto_WhenTrue() {
+	s.reconfigure.Mode = "swarm"
+	s.reconfigure.XForwardedProto = true
 	var actualFilename, actualData string
 	expectedFilename := fmt.Sprintf("%s/%s-be.cfg", s.TemplatesPath, s.ServiceName)
 	expectedData := fmt.Sprintf(
diff --git a/docs/usage.md b/docs/usage.md
index 8e2b1390..7eaa41ca 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -20,6 +20,7 @@ The following query parameters can be used to send as a *reconfigure* request to
 |serviceName  |The name of the service. It must match the name of the Swarm service or the one stored in Consul.|Yes| |go-demo |
 |timeoutServer|The server timeout in seconds.                                                  |No      |       |60           |
 |timeoutTunnel|The tunnel timeout in seconds.                                                  |No      |       |1800         |
+|xForwardedProto|Whether to add "X-Forwarded-Proto https" header.                              |No      |false  |true         |
 
 The following query parameters can be used when `reqMode` is set to `http` or is empty.
 
diff --git a/proxy/types.go b/proxy/types.go
index d7e0bf90..90f23c90 100644
--- a/proxy/types.go
+++ b/proxy/types.go
@@ -90,6 +90,8 @@ type Service struct {
 	TimeoutTunnel string
 	// A comma-separated list of credentials(<user>:<pass>) for HTTP basic auth, which applies only to the service that will be reconfigured.
 	Users               []User
+	// Whether to add "X-Forwarded-Proto https" header.
+	XForwardedProto     bool
 	ServiceColor        string
 	ServicePort         string
 	AclCondition        string
diff --git a/server.go b/server.go
index 69162524..47dae6b1 100644
--- a/server.go
+++ b/server.go
@@ -326,6 +326,7 @@ func (m *Serve) getService(sd []proxy.ServiceDest, req *http.Request) proxy.Serv
 		sr.ReqMode = "http"
 	}
 	sr.HttpsOnly = m.getBoolParam(req, "httpsOnly")
+	sr.XForwardedProto = m.getBoolParam(req, "xForwardedProto")
 	sr.RedirectWhenHttpProto = m.getBoolParam(req, "redirectWhenHttpProto")
 	if len(req.URL.Query().Get("httpsPort")) > 0 {
 		sr.HttpsPort, _ = strconv.Atoi(req.URL.Query().Get("httpsPort"))
diff --git a/server_test.go b/server_test.go
index 00c7236d..e7a0689f 100644
--- a/server_test.go
+++ b/server_test.go
@@ -831,6 +831,29 @@ func (s *ServerTestSuite) Test_ServeHTTP_ReturnsJsonWithPorts_WhenPresent() {
 	s.ResponseWriter.AssertCalled(s.T(), "Write", []byte(expected))
 }
 
+func (s *ServerTestSuite) Test_ServeHTTP_ReturnsJsonWithXForwardedProto_WhenPresent() {
+	req, _ := http.NewRequest("GET", s.ReconfigureUrl+"&xForwardedProto=true", nil)
+	expected, _ := json.Marshal(server.Response{
+		Status:      "OK",
+		ServiceName: s.ServiceName,
+		Service: proxy.Service{
+			ServiceName:      s.ServiceName,
+			ReqMode:          "http",
+			ServiceColor:     s.ServiceColor,
+			ServiceDomain:    s.ServiceDomain,
+			OutboundHostname: s.OutboundHostname,
+			PathType:         s.PathType,
+			XForwardedProto:  true,
+			ServiceDest:      []proxy.ServiceDest{s.sd},
+		},
+	})
+
+	srv := Serve{}
+	srv.ServeHTTP(s.ResponseWriter, req)
+
+	s.ResponseWriter.AssertCalled(s.T(), "Write", []byte(expected))
+}
+
 func (s *ServerTestSuite) Test_ServeHTTP_ReturnsJsonWithSkipCheck_WhenPresent() {
 	req, _ := http.NewRequest("GET", s.ReconfigureUrl+"&skipCheck=true", nil)
 	expected, _ := json.Marshal(server.Response{