1
0
mirror of https://github.com/labstack/echo.git synced 2025-06-08 23:56:20 +02:00

Added Context#IsWebSocket(), proxy fix header

Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2017-06-04 10:39:08 -07:00
parent 353a2f8b78
commit c3887ebb13
3 changed files with 65 additions and 38 deletions

View File

@ -31,6 +31,9 @@ type (
// IsTLS returns true if HTTP connection is TLS otherwise false. // IsTLS returns true if HTTP connection is TLS otherwise false.
IsTLS() bool IsTLS() bool
// IsWebSocket returns true if HTTP connection is WebSocket otherwise false.
IsWebSocket() bool
// Scheme returns the HTTP protocol scheme, `http` or `https`. // Scheme returns the HTTP protocol scheme, `http` or `https`.
Scheme() string Scheme() string
@ -219,6 +222,11 @@ func (c *context) IsTLS() bool {
return c.request.TLS != nil return c.request.TLS != nil
} }
func (c *context) IsWebSocket() bool {
upgrade := c.request.Header.Get(HeaderUpgrade)
return upgrade == "websocket" || upgrade == "Websocket"
}
func (c *context) Scheme() string { func (c *context) Scheme() string {
// Can't use `r.Request.URL.Scheme` // Can't use `r.Request.URL.Scheme`
// See: https://groups.google.com/forum/#!topic/golang-nuts/pMUkBlQBDF0 // See: https://groups.google.com/forum/#!topic/golang-nuts/pMUkBlQBDF0
@ -228,9 +236,15 @@ func (c *context) Scheme() string {
if scheme := c.request.Header.Get(HeaderXForwardedProto); scheme != "" { if scheme := c.request.Header.Get(HeaderXForwardedProto); scheme != "" {
return scheme return scheme
} }
if scheme := c.request.Header.Get(HeaderXForwardedProtocol); scheme != "" {
return scheme
}
if ssl := c.request.Header.Get(HeaderXForwardedSsl); ssl == "on" { if ssl := c.request.Header.Get(HeaderXForwardedSsl); ssl == "on" {
return "https" return "https"
} }
if scheme := c.request.Header.Get(HeaderXUrlScheme); scheme != "" {
return scheme
}
return "http" return "http"
} }

View File

@ -181,14 +181,18 @@ const (
HeaderUpgrade = "Upgrade" HeaderUpgrade = "Upgrade"
HeaderVary = "Vary" HeaderVary = "Vary"
HeaderWWWAuthenticate = "WWW-Authenticate" HeaderWWWAuthenticate = "WWW-Authenticate"
HeaderXForwardedProto = "X-Forwarded-Proto"
HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
HeaderXForwardedFor = "X-Forwarded-For" HeaderXForwardedFor = "X-Forwarded-For"
HeaderXForwardedProto = "X-Forwarded-Proto"
HeaderXForwardedProtocol = "X-Forwarded-Protocol"
HeaderXForwardedSsl = "X-Forwarded-Ssl" HeaderXForwardedSsl = "X-Forwarded-Ssl"
HeaderXUrlScheme = "X-Url-Scheme"
HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
HeaderXRealIP = "X-Real-IP" HeaderXRealIP = "X-Real-IP"
HeaderXRequestID = "X-Request-ID" HeaderXRequestID = "X-Request-ID"
HeaderServer = "Server" HeaderServer = "Server"
HeaderOrigin = "Origin" HeaderOrigin = "Origin"
// Access control
HeaderAccessControlRequestMethod = "Access-Control-Request-Method" HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers" HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers"
HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin" HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin"

View File

@ -15,6 +15,8 @@ import (
"github.com/labstack/echo" "github.com/labstack/echo"
) )
// TODO: Handle TLS proxy
type ( type (
// ProxyConfig defines the config for Proxy middleware. // ProxyConfig defines the config for Proxy middleware.
ProxyConfig struct { ProxyConfig struct {
@ -63,17 +65,16 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
c.Error(errors.New("proxy raw, not a hijacker")) c.Error(errors.New("proxy raw, not a hijacker"))
return return
} }
in, _, err := h.Hijack() in, _, err := h.Hijack()
if err != nil { if err != nil {
c.Error(fmt.Errorf("proxy raw hijack error=%v, url=%s", r.URL, err)) c.Error(fmt.Errorf("proxy raw, hijack error=%v, url=%s", r.URL, err))
return return
} }
defer in.Close() defer in.Close()
out, err := net.Dial("tcp", t.URL.Host) out, err := net.Dial("tcp", t.URL.Host)
if err != nil { if err != nil {
he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw dial error=%v, url=%s", r.URL, err)) he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", r.URL, err))
c.Error(he) c.Error(he)
return return
} }
@ -81,7 +82,7 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
err = r.Write(out) err = r.Write(out)
if err != nil { if err != nil {
he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw request copy error=%v, url=%s", r.URL, err)) he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request copy error=%v, url=%s", r.URL, err))
c.Error(he) c.Error(he)
return return
} }
@ -96,7 +97,7 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
go cp(in, out) go cp(in, out)
err = <-errc err = <-errc
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
c.Logger().Errorf("proxy raw error=%v, url=%s", r.URL, err) c.Logger().Errorf("proxy raw, error=%v, url=%s", r.URL, err)
} }
}) })
} }
@ -131,18 +132,26 @@ func Proxy(config ProxyConfig) echo.MiddlewareFunc {
return func(c echo.Context) (err error) { return func(c echo.Context) (err error) {
req := c.Request() req := c.Request()
res := c.Response() res := c.Response()
t := config.Balancer.Next() tgt := config.Balancer.Next()
// Fix header
if req.Header.Get(echo.HeaderXRealIP) == "" {
req.Header.Set(echo.HeaderXRealIP, c.RealIP())
}
if req.Header.Get(echo.HeaderXForwardedProto) == "" {
req.Header.Set(echo.HeaderXForwardedProto, c.Scheme())
}
if c.IsWebSocket() && req.Header.Get(echo.HeaderXForwardedFor) == "" { // For HTTP, it is automatically set by Go HTTP reverse proxy.
req.Header.Set(echo.HeaderXForwardedFor, c.RealIP())
}
// Proxy // Proxy
upgrade := req.Header.Get(echo.HeaderUpgrade)
accept := req.Header.Get(echo.HeaderAccept)
switch { switch {
case upgrade == "websocket" || upgrade == "Websocket": case c.IsWebSocket():
proxyRaw(t, c).ServeHTTP(res, req) proxyRaw(tgt, c).ServeHTTP(res, req)
case accept == "text/event-stream": case req.Header.Get(echo.HeaderAccept) == "text/event-stream":
default: default:
proxyHTTP(t).ServeHTTP(res, req) proxyHTTP(tgt).ServeHTTP(res, req)
} }
return return