mirror of
https://github.com/kataras/iris.git
synced 2026-01-10 13:35:59 +00:00
This commit is contained in:
@@ -71,6 +71,10 @@ type (
|
|||||||
//
|
//
|
||||||
// Default 2 hours
|
// Default 2 hours
|
||||||
GcDuration time.Duration
|
GcDuration time.Duration
|
||||||
|
|
||||||
|
// DisableSubdomainPersistance set it to dissallow your iris subdomains to have access to the session cookie
|
||||||
|
// defaults to false
|
||||||
|
DisableSubdomainPersistance bool
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -81,6 +85,7 @@ func DefaultSessions() Sessions {
|
|||||||
Cookie: DefaultCookieName,
|
Cookie: DefaultCookieName,
|
||||||
Expires: CookieExpireNever,
|
Expires: CookieExpireNever,
|
||||||
GcDuration: DefaultSessionGcDuration,
|
GcDuration: DefaultSessionGcDuration,
|
||||||
|
DisableSubdomainPersistance: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
context.go
22
context.go
@@ -215,12 +215,21 @@ func (ctx *Context) HostString() string {
|
|||||||
// VirtualHostname returns the hostname that user registers, host path maybe differs from the real which is HostString, which taken from a net.listener
|
// VirtualHostname returns the hostname that user registers, host path maybe differs from the real which is HostString, which taken from a net.listener
|
||||||
func (ctx *Context) VirtualHostname() string {
|
func (ctx *Context) VirtualHostname() string {
|
||||||
realhost := ctx.HostString()
|
realhost := ctx.HostString()
|
||||||
|
hostname := realhost
|
||||||
virtualhost := ctx.framework.HTTPServer.VirtualHostname()
|
virtualhost := ctx.framework.HTTPServer.VirtualHostname()
|
||||||
hostname := strings.Replace(realhost, "127.0.0.1", virtualhost, 1)
|
|
||||||
hostname = strings.Replace(realhost, "localhost", virtualhost, 1)
|
|
||||||
if portIdx := strings.IndexByte(hostname, ':'); portIdx > 0 {
|
if portIdx := strings.IndexByte(hostname, ':'); portIdx > 0 {
|
||||||
hostname = hostname[0:portIdx]
|
hostname = hostname[0:portIdx]
|
||||||
}
|
}
|
||||||
|
if idxDotAnd := strings.LastIndexByte(hostname, '.'); idxDotAnd > 0 {
|
||||||
|
s := hostname[idxDotAnd:]
|
||||||
|
if s == ".1" {
|
||||||
|
hostname = strings.Replace(hostname, "127.0.0.1", virtualhost, 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hostname = strings.Replace(hostname, "localhost", virtualhost, 1)
|
||||||
|
}
|
||||||
|
|
||||||
return hostname
|
return hostname
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,6 +297,15 @@ func (ctx *Context) PostFormMulti(name string) []string {
|
|||||||
return arrStr
|
return arrStr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Domain same as VirtualHostname but without the :port part (if any)
|
||||||
|
func (ctx *Context) Domain() string {
|
||||||
|
domain := ctx.VirtualHostname()
|
||||||
|
if idx := strings.IndexByte(domain, ':'); idx > 0 {
|
||||||
|
domain = domain[0 : idx-1]
|
||||||
|
}
|
||||||
|
return domain
|
||||||
|
}
|
||||||
|
|
||||||
// Subdomain returns the subdomain (string) of this request, if any
|
// Subdomain returns the subdomain (string) of this request, if any
|
||||||
func (ctx *Context) Subdomain() (subdomain string) {
|
func (ctx *Context) Subdomain() (subdomain string) {
|
||||||
host := ctx.HostString()
|
host := ctx.HostString()
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type (
|
|||||||
URLParams() map[string]string
|
URLParams() map[string]string
|
||||||
MethodString() string
|
MethodString() string
|
||||||
HostString() string
|
HostString() string
|
||||||
|
Domain() string
|
||||||
Subdomain() string
|
Subdomain() string
|
||||||
PathString() string
|
PathString() string
|
||||||
RequestPath(bool) string
|
RequestPath(bool) string
|
||||||
|
|||||||
88
iris.go
88
iris.go
@@ -89,8 +89,8 @@ type (
|
|||||||
ListenTLS(string, string, string)
|
ListenTLS(string, string, string)
|
||||||
ListenUNIXWithErr(string, os.FileMode) error
|
ListenUNIXWithErr(string, os.FileMode) error
|
||||||
ListenUNIX(string, os.FileMode)
|
ListenUNIX(string, os.FileMode)
|
||||||
NoListen() *Server
|
|
||||||
SecondaryListen(config.Server) *Server
|
SecondaryListen(config.Server) *Server
|
||||||
|
NoListen() *Server
|
||||||
Close()
|
Close()
|
||||||
// global middleware prepending, registers to all subdomains, to all parties, you can call it at the last also
|
// global middleware prepending, registers to all subdomains, to all parties, you can call it at the last also
|
||||||
MustUse(...Handler)
|
MustUse(...Handler)
|
||||||
@@ -292,6 +292,49 @@ func (s *Framework) ListenUNIX(addr string, mode os.FileMode) {
|
|||||||
s.Must(s.ListenUNIXWithErr(addr, mode))
|
s.Must(s.ListenUNIXWithErr(addr, mode))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SecondaryListen starts a server which listens to this station
|
||||||
|
// Note that the view engine's functions {{ url }} and {{ urlpath }} will return the first's registered server's scheme (http/https)
|
||||||
|
//
|
||||||
|
// this is useful only when you want to have two or more listening ports ( two or more servers ) for the same station
|
||||||
|
//
|
||||||
|
// receives one parameter which is the config.Server for the new server
|
||||||
|
// returns the new standalone server( you can close this server by the returning reference)
|
||||||
|
//
|
||||||
|
// If you need only one server this function is not for you, instead you must use the normal .Listen/ListenTLS functions.
|
||||||
|
//
|
||||||
|
// this is a NOT A BLOCKING version, the main iris.Listen should be always executed LAST, so this function goes before the main .Listen.
|
||||||
|
func SecondaryListen(cfg config.Server) *Server {
|
||||||
|
return Default.SecondaryListen(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecondaryListen starts a server which listens to this station
|
||||||
|
// Note that the view engine's functions {{ url }} and {{ urlpath }} will return the first's registered server's scheme (http/https)
|
||||||
|
//
|
||||||
|
// this is useful only when you want to have two or more listening ports ( two or more servers ) for the same station
|
||||||
|
//
|
||||||
|
// receives one parameter which is the config.Server for the new server
|
||||||
|
// returns the new standalone server( you can close this server by the returning reference)
|
||||||
|
//
|
||||||
|
// If you need only one server this function is not for you, instead you must use the normal .Listen/ListenTLS functions.
|
||||||
|
//
|
||||||
|
// this is a NOT A BLOCKING version, the main iris.Listen should be always executed LAST, so this function goes before the main .Listen.
|
||||||
|
func (s *Framework) SecondaryListen(cfg config.Server) *Server {
|
||||||
|
srv := newServer(&cfg)
|
||||||
|
// add a post listen event to start this server after the previous started
|
||||||
|
s.Plugins.Add(PostListenFunc(func(*Framework) {
|
||||||
|
go func() { // goroutine in order to not block any runtime post listeners
|
||||||
|
srv.Handler = s.HTTPServer.Handler
|
||||||
|
if err := srv.Open(); err == nil {
|
||||||
|
ch := make(chan os.Signal)
|
||||||
|
<-ch
|
||||||
|
srv.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}))
|
||||||
|
|
||||||
|
return srv
|
||||||
|
}
|
||||||
|
|
||||||
// NoListen is useful only when you want to test Iris, it doesn't starts the server but it configures and returns it
|
// NoListen is useful only when you want to test Iris, it doesn't starts the server but it configures and returns it
|
||||||
func NoListen() *Server {
|
func NoListen() *Server {
|
||||||
return Default.NoListen()
|
return Default.NoListen()
|
||||||
@@ -558,49 +601,6 @@ func (s *Framework) TemplateString(templateFile string, pageContext interface{},
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecondaryListen starts a server which listens to this station
|
|
||||||
// Note that the view engine's functions {{ url }} and {{ urlpath }} will return the first's registered server's scheme (http/https)
|
|
||||||
//
|
|
||||||
// this is useful only when you want to have two or more listening ports ( two or more servers ) for the same station
|
|
||||||
//
|
|
||||||
// receives one parameter which is the config.Server for the new server
|
|
||||||
// returns the new standalone server( you can close this server by the returning reference)
|
|
||||||
//
|
|
||||||
// If you need only one server this function is not for you, instead you must use the normal .Listen/ListenTLS functions.
|
|
||||||
//
|
|
||||||
// this is a NOT A BLOCKING version, the main iris.Listen should be always executed LAST, so this function goes before the main .Listen.
|
|
||||||
func SecondaryListen(cfg config.Server) *Server {
|
|
||||||
return Default.SecondaryListen(cfg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SecondaryListen starts a server which listens to this station
|
|
||||||
// Note that the view engine's functions {{ url }} and {{ urlpath }} will return the first's registered server's scheme (http/https)
|
|
||||||
//
|
|
||||||
// this is useful only when you want to have two or more listening ports ( two or more servers ) for the same station
|
|
||||||
//
|
|
||||||
// receives one parameter which is the config.Server for the new server
|
|
||||||
// returns the new standalone server( you can close this server by the returning reference)
|
|
||||||
//
|
|
||||||
// If you need only one server this function is not for you, instead you must use the normal .Listen/ListenTLS functions.
|
|
||||||
//
|
|
||||||
// this is a NOT A BLOCKING version, the main iris.Listen should be always executed LAST, so this function goes before the main .Listen.
|
|
||||||
func (s *Framework) SecondaryListen(cfg config.Server) *Server {
|
|
||||||
srv := newServer(&cfg)
|
|
||||||
// add a post listen event to start this server after the previous started
|
|
||||||
s.Plugins.Add(PostListenFunc(func(*Framework) {
|
|
||||||
go func() { // goroutine in order to not block any runtime post listeners
|
|
||||||
srv.Handler = s.HTTPServer.Handler
|
|
||||||
if err := srv.Open(); err == nil {
|
|
||||||
ch := make(chan os.Signal)
|
|
||||||
<-ch
|
|
||||||
srv.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}))
|
|
||||||
|
|
||||||
return srv
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
// ----------------------------------MuxAPI implementation------------------------------
|
// ----------------------------------MuxAPI implementation------------------------------
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package sessions
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"net/url"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -26,6 +26,7 @@ type (
|
|||||||
config *config.Sessions
|
config *config.Sessions
|
||||||
provider IProvider
|
provider IProvider
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
compiledCookie string
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ func newManager(c config.Sessions) (*Manager, error) {
|
|||||||
manager := &Manager{}
|
manager := &Manager{}
|
||||||
manager.config = &c
|
manager.config = &c
|
||||||
manager.provider = provider
|
manager.provider = provider
|
||||||
|
manager.compiledCookie = base64.URLEncoding.EncodeToString([]byte(c.Cookie))
|
||||||
return manager, nil
|
return manager, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,29 +75,57 @@ func (m *Manager) generateSessionID() string {
|
|||||||
return base64.URLEncoding.EncodeToString(utils.Random(32))
|
return base64.URLEncoding.EncodeToString(utils.Random(32))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dotB = byte('.')
|
||||||
|
|
||||||
// Start starts the session
|
// Start starts the session
|
||||||
func (m *Manager) Start(ctx context.IContext) store.IStore {
|
func (m *Manager) Start(ctx context.IContext) store.IStore {
|
||||||
|
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
var store store.IStore
|
var store store.IStore
|
||||||
requestCtx := ctx.GetRequestCtx()
|
requestCtx := ctx.GetRequestCtx()
|
||||||
cookieValue := string(requestCtx.Request.Header.Cookie(m.config.Cookie))
|
cookieValue := string(requestCtx.Request.Header.Cookie(m.compiledCookie))
|
||||||
|
|
||||||
if cookieValue == "" { // cookie doesn't exists, let's generate a session and add set a cookie
|
if cookieValue == "" { // cookie doesn't exists, let's generate a session and add set a cookie
|
||||||
sid := m.generateSessionID()
|
sid := m.generateSessionID()
|
||||||
store, _ = m.provider.Init(sid)
|
store, _ = m.provider.Init(sid)
|
||||||
cookie := fasthttp.AcquireCookie()
|
cookie := fasthttp.AcquireCookie()
|
||||||
cookie.SetKey(m.config.Cookie)
|
// The RFC makes no mention of encoding url value, so here I think to encode both sessionid key and the value using the safe(to put and to use as cookie) url-encoding
|
||||||
cookie.SetValue(url.QueryEscape(sid))
|
cookie.SetKey(m.compiledCookie)
|
||||||
|
cookie.SetValue(base64.URLEncoding.EncodeToString([]byte(sid)))
|
||||||
cookie.SetPath("/")
|
cookie.SetPath("/")
|
||||||
|
if !m.config.DisableSubdomainPersistance {
|
||||||
|
requestDomain := ctx.HostString() // we don't use the ctx.Domain because it gives the virtual domain, which is correct on some cases but not here.
|
||||||
|
|
||||||
|
if portIdx := strings.IndexByte(requestDomain, ':'); portIdx > 0 {
|
||||||
|
requestDomain = requestDomain[0:portIdx]
|
||||||
|
}
|
||||||
|
// RFC2109, we allow level 1 subdomains, but no further
|
||||||
|
// if we have localhost.com , we want the localhost.com.
|
||||||
|
// so if we have something like: mysubdomain.localhost.com we want the localhost here
|
||||||
|
// if we have mysubsubdomain.mysubdomain.localhost.com we want the .mysubdomain.localhost.com here
|
||||||
|
// slow things here, especially the 'replace' but this is a good and understable( I hope) way to get the be able to set cookies from subdomains & domain with 1-level limit
|
||||||
|
if dotIdx := strings.LastIndexByte(requestDomain, dotB); dotIdx > 0 {
|
||||||
|
// is mysubdomain.localhost.com || mysubsubdomain.mysubdomain.localhost.com
|
||||||
|
s := requestDomain[0:dotIdx] // set mysubdomain.localhost || mysubsubdomain.mysubdomain.localhost
|
||||||
|
if secondDotIdx := strings.LastIndexByte(s, dotB); secondDotIdx > 0 {
|
||||||
|
//is mysubdomain.localhost || mysubsubdomain.mysubdomain.localhost
|
||||||
|
s = s[secondDotIdx+1:] // set to localhost || mysubdomain.localhost
|
||||||
|
}
|
||||||
|
// replace the s with the requestDomain before the domain's siffux
|
||||||
|
subdomainSuff := strings.LastIndexByte(requestDomain, dotB)
|
||||||
|
if subdomainSuff > len(s) { // if it is actual exists as subdomain suffix
|
||||||
|
requestDomain = strings.Replace(requestDomain, requestDomain[0:subdomainSuff], s, 1) // set to localhost.com || mysubdomain.localhost.com
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cookie.SetDomain("." + requestDomain) // . to allow persistance
|
||||||
|
}
|
||||||
cookie.SetHTTPOnly(true)
|
cookie.SetHTTPOnly(true)
|
||||||
cookie.SetExpire(m.config.Expires)
|
cookie.SetExpire(m.config.Expires)
|
||||||
requestCtx.Response.Header.SetCookie(cookie)
|
requestCtx.Response.Header.SetCookie(cookie)
|
||||||
fasthttp.ReleaseCookie(cookie)
|
fasthttp.ReleaseCookie(cookie)
|
||||||
//println("manager.go:156-> Setting cookie with lifetime: ", m.lifeDuration.Seconds())
|
|
||||||
} else {
|
} else {
|
||||||
sid, _ := url.QueryUnescape(cookieValue)
|
sid, _ := base64.URLEncoding.DecodeString(cookieValue)
|
||||||
store, _ = m.provider.Read(sid)
|
store, _ = m.provider.Read(string(sid))
|
||||||
}
|
}
|
||||||
|
|
||||||
m.mu.Unlock()
|
m.mu.Unlock()
|
||||||
|
|||||||
Reference in New Issue
Block a user