Merge branch 'mattbaird-feature/ssl-support-for-websockets' into develop

This commit is contained in:
Jeevanandam M
2016-05-23 22:55:04 -07:00

View File

@@ -13,7 +13,6 @@ package harness
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"github.com/revel/revel"
"go/build" "go/build"
"io" "io"
"net" "net"
@@ -22,10 +21,11 @@ import (
"net/url" "net/url"
"os" "os"
"os/signal" "os/signal"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
"sync/atomic" "sync/atomic"
"github.com/revel/revel"
) )
var ( var (
@@ -52,7 +52,7 @@ func renderError(w http.ResponseWriter, r *http.Request, err error) {
// ServeHTTP handles all requests. // ServeHTTP handles all requests.
// It checks for changes to app, rebuilds if necessary, and forwards the request. // It checks for changes to app, rebuilds if necessary, and forwards the request.
func (hp *Harness) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (h *Harness) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Don't rebuild the app for favicon requests. // Don't rebuild the app for favicon requests.
if lastRequestHadError > 0 && r.URL.Path == "/favicon.ico" { if lastRequestHadError > 0 && r.URL.Path == "/favicon.ico" {
return return
@@ -71,18 +71,19 @@ func (hp *Harness) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Reverse proxy the request. // Reverse proxy the request.
// (Need special code for websockets, courtesy of bradfitz) // (Need special code for websockets, courtesy of bradfitz)
if strings.EqualFold(r.Header.Get("Upgrade"), "websocket") { if strings.EqualFold(r.Header.Get("Upgrade"), "websocket") {
proxyWebsocket(w, r, hp.serverHost) proxyWebsocket(w, r, h.serverHost)
} else { } else {
hp.proxy.ServeHTTP(w, r) h.proxy.ServeHTTP(w, r)
} }
} }
// Return a reverse proxy that forwards requests to the given port. // NewHarness method returns a reverse proxy that forwards requests
// to the given port.
func NewHarness() *Harness { func NewHarness() *Harness {
// Get a template loader to render errors. // Get a template loader to render errors.
// Prefer the app's views/errors directory, and fall back to the stock error pages. // Prefer the app's views/errors directory, and fall back to the stock error pages.
revel.MainTemplateLoader = revel.NewTemplateLoader( revel.MainTemplateLoader = revel.NewTemplateLoader(
[]string{path.Join(revel.RevelPath, "templates")}) []string{filepath.Join(revel.RevelPath, "templates")})
revel.MainTemplateLoader.Refresh() revel.MainTemplateLoader.Refresh()
addr := revel.HttpAddr addr := revel.HttpAddr
@@ -101,12 +102,12 @@ func NewHarness() *Harness {
port = getFreePort() port = getFreePort()
} }
serverUrl, _ := url.ParseRequestURI(fmt.Sprintf(scheme+"://%s:%d", addr, port)) serverURL, _ := url.ParseRequestURI(fmt.Sprintf(scheme+"://%s:%d", addr, port))
harness := &Harness{ harness := &Harness{
port: port, port: port,
serverHost: serverUrl.String()[len(scheme+"://"):], serverHost: serverURL.String()[len(scheme+"://"):],
proxy: httputil.NewSingleHostReverseProxy(serverUrl), proxy: httputil.NewSingleHostReverseProxy(serverURL),
} }
if revel.HttpSsl { if revel.HttpSsl {
@@ -117,7 +118,7 @@ func NewHarness() *Harness {
return harness return harness
} }
// Rebuild the Revel application and run it on the given port. // Refresh method rebuilds the Revel application and run it on the given port.
func (h *Harness) Refresh() (err *revel.Error) { func (h *Harness) Refresh() (err *revel.Error) {
if h.app != nil { if h.app != nil {
h.app.Kill() h.app.Kill()
@@ -140,10 +141,14 @@ func (h *Harness) Refresh() (err *revel.Error) {
return return
} }
// WatchDir method returns false to file matches with doNotWatch
// otheriwse true
func (h *Harness) WatchDir(info os.FileInfo) bool { func (h *Harness) WatchDir(info os.FileInfo) bool {
return !revel.ContainsString(doNotWatch, info.Name()) return !revel.ContainsString(doNotWatch, info.Name())
} }
// WatchFile method returns true given filename HasSuffix of ".go"
// otheriwse false
func (h *Harness) WatchFile(filename string) bool { func (h *Harness) WatchFile(filename string) bool {
return strings.HasSuffix(filename, ".go") return strings.HasSuffix(filename, ".go")
} }
@@ -204,7 +209,18 @@ func getFreePort() (port int) {
// proxyWebsocket copies data between websocket client and server until one side // proxyWebsocket copies data between websocket client and server until one side
// closes the connection. (ReverseProxy doesn't work with websocket requests.) // closes the connection. (ReverseProxy doesn't work with websocket requests.)
func proxyWebsocket(w http.ResponseWriter, r *http.Request, host string) { func proxyWebsocket(w http.ResponseWriter, r *http.Request, host string) {
d, err := net.Dial("tcp", host) var (
d net.Conn
err error
)
if revel.HttpSsl {
// since this proxy isn't used in production,
// it's OK to set InsecureSkipVerify to true
// no need to add another configuration option.
d, err = tls.Dial("tcp", host, &tls.Config{InsecureSkipVerify: true})
} else {
d, err = net.Dial("tcp", host)
}
if err != nil { if err != nil {
http.Error(w, "Error contacting backend server.", 500) http.Error(w, "Error contacting backend server.", 500)
revel.ERROR.Printf("Error dialing websocket backend %s: %v", host, err) revel.ERROR.Printf("Error dialing websocket backend %s: %v", host, err)