From d304086c32cb4d0211e6844bfac0404aef1edbd9 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Thu, 11 Jun 2020 16:08:35 +0300 Subject: [PATCH] add 'Context.IsSSL() bool' Former-commit-id: 494394ecb3a44dc69d95893eae024efff0ff3612 --- HISTORY.md | 1 + configuration.go | 26 +++++++++++++++++++++++++- context/configuration.go | 2 ++ context/context.go | 26 +++++++++++++++++++++++++- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 68e80cbe..8a74be39 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -417,6 +417,7 @@ New Package-level Variables: New Context Methods: +- `Context.IsSSL() bool` reports whether the request is under HTTPS SSL (New `Configuration.SSLProxyHeaders` field too). - `Context.GzipReader(enable bool)` method and `iris.GzipReader` middleware to enable future request read body calls to decompress data using gzip, [example](_examples/request-body/read-gzip). - `Context.RegisterDependency(v interface{})` and `Context.RemoveDependency(typ reflect.Type)` to register/remove struct dependencies on serve-time through a middleware. - `Context.SetID(id interface{})` and `Context.GetID() interface{}` added to register a custom unique indetifier to the Context, if necessary. diff --git a/configuration.go b/configuration.go index 2d18e3e5..9a7983de 100644 --- a/configuration.go +++ b/configuration.go @@ -395,6 +395,18 @@ func WithRemoteAddrPrivateSubnet(startIP, endIP string) Configurator { } } +// WithSSLProxyHeader sets a SSLProxyHeaders key value pair. +// Example: WithSSLProxyHeader("X-Forwarded-Proto", "https"). +func WithSSLProxyHeader(headerKey, headerValue string) Configurator { + return func(app *Application) { + if app.config.SSLProxyHeaders == nil { + app.config.SSLProxyHeaders = make(map[string]string) + } + + app.config.SSLProxyHeaders[headerKey] = headerValue + } +} + // WithOtherValue adds a value based on a key to the Other setting. // // See `Configuration.Other`. @@ -976,10 +988,16 @@ type Configuration struct { // // Look `context.RemoteAddr()` for more. RemoteAddrPrivateSubnets []netutil.IPRange `json:"remoteAddrPrivateSubnets" yaml:"RemoteAddrPrivateSubnets" toml:"RemoteAddrPrivateSubnets"` + // SSLProxyHeaders defines the set of header key values + // that would indicate a valid https Request (look `context.IsSSL()`). + // Example: `map[string]string{"X-Forwarded-Proto": "https"}`. + // + // Defaults to empty map. + SSLProxyHeaders map[string]string `json:"sslProxyHeaders" yaml:"SSLProxyHeaders" toml:"SSLProxyHeaders"` // Other are the custom, dynamic options, can be empty. // This field used only by you to set any app's options you want. // - // Defaults to a non-nil empty map. + // Defaults to empty map. Other map[string]interface{} `json:"other,omitempty" yaml:"Other" toml:"Other"` } @@ -1158,6 +1176,11 @@ func (c Configuration) GetRemoteAddrHeaders() map[string]bool { return c.RemoteAddrHeaders } +// GetSSLProxyHeaders returns the SSLProxyHeaders field. +func (c Configuration) GetSSLProxyHeaders() map[string]string { + return c.SSLProxyHeaders +} + // GetRemoteAddrPrivateSubnets returns the configuration's private sub-networks. // They are used to be compared against // IP Addresses fetched through `RemoteAddrHeaders` or `Request.RemoteAddr`. @@ -1384,6 +1407,7 @@ func DefaultConfiguration() Configuration { End: net.ParseIP("198.19.255.255"), }, }, + SSLProxyHeaders: make(map[string]string), EnableOptimizations: false, Other: make(map[string]interface{}), } diff --git a/context/configuration.go b/context/configuration.go index b9604713..c00f202f 100644 --- a/context/configuration.go +++ b/context/configuration.go @@ -123,6 +123,8 @@ type ConfigurationReadOnly interface { // // Look `context.RemoteAddr()` for more. GetRemoteAddrPrivateSubnets() []netutil.IPRange + // GetSSLProxyHeaders returns the SSLProxyHeaders field. + GetSSLProxyHeaders() map[string]string // GetOther returns the configuration.Other map. GetOther() map[string]interface{} } diff --git a/context/context.go b/context/context.go index 695956a5..2dc0da91 100644 --- a/context/context.go +++ b/context/context.go @@ -400,8 +400,14 @@ type Context interface { IsMobile() bool // IsScript reports whether a client is a script. IsScript() bool + // IsSSL reports whether the client is running under HTTPS SSL. + // + // See `IsHTTP2` too. + IsSSL() bool // IsHTTP2 reports whether the protocol version for incoming request was HTTP/2. // The client code always uses either HTTP/1.1 or HTTP/2. + // + // See `IsSSL` too. IsHTTP2() bool // IsGRPC reports whether the request came from a gRPC client. IsGRPC() bool @@ -1978,10 +1984,28 @@ func (ctx *context) IsScript() bool { return isScriptRegex.MatchString(s) } +// IsSSL reports whether the client is running under HTTPS SSL. +// +// See `IsHTTP2` too. +func (ctx *context) IsSSL() bool { + ssl := strings.EqualFold(ctx.request.URL.Scheme, "https") || ctx.request.TLS != nil + if !ssl { + for k, v := range ctx.app.ConfigurationReadOnly().GetSSLProxyHeaders() { + if ctx.GetHeader(k) == v { + ssl = true + break + } + } + } + return ssl +} + // IsHTTP2 reports whether the protocol version for incoming request was HTTP/2. // The client code always uses either HTTP/1.1 or HTTP/2. +// +// See `IsSSL` too. func (ctx *context) IsHTTP2() bool { - return ctx.Request().ProtoMajor == 2 + return ctx.request.ProtoMajor == 2 } // IsGRPC reports whether the request came from a gRPC client.