diff --git a/.travis.yml b/.travis.yml index a04503639..efd2ae5ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ language: go go: - - "1.12.x" - "1.13.x" - "1.14.x" + - "1.15.x" - "tip" os: diff --git a/README.md b/README.md index c9244d1f4..5b6a1caf9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A high productivity, full-stack web framework for the [Go language](http://www.golang.org). -Current Version: 1.0.0 (2020-07-11) +Current Version: 1.1.0-dev (2020-07-11) **Supports go.mod package management** @@ -14,7 +14,8 @@ Current Version: 1.0.0 (2020-07-11) Install Revel: - go get -u github.com/revel/cmd/revel + go install github.com/revel/cmd/revel@latest + Create & Run your app: diff --git a/before_after_filter.go b/before_after_filter.go index bc9974a61..8c4644d82 100644 --- a/before_after_filter.go +++ b/before_after_filter.go @@ -5,7 +5,7 @@ import ( ) // Autocalls any defined before and after methods on the target controller -// If either calls returns a value then the result is returned +// If either calls returns a value then the result is returned. func BeforeAfterFilter(c *Controller, fc []Filter) { defer func() { if resultValue := beforeAfterFilterInvoke(FINALLY, c); resultValue != nil && !resultValue.IsNil() { @@ -31,7 +31,6 @@ func BeforeAfterFilter(c *Controller, fc []Filter) { } func beforeAfterFilterInvoke(method When, c *Controller) (r *reflect.Value) { - if c.Type == nil { return } diff --git a/binder.go b/binder.go index 784e01475..65dccf1c7 100644 --- a/binder.go +++ b/binder.go @@ -57,16 +57,16 @@ func ValueBinder(f func(value string, typ reflect.Type) reflect.Value) func(*Par } } -// Revel's default date and time constants +// Revel's default date and time constants. const ( DefaultDateFormat = "2006-01-02" DefaultDateTimeFormat = "2006-01-02 15:04" ) -// Binders type and kind definition +// Binders type and kind definition. var ( // These are the lookups to find a Binder for any type of data. - // The most specific binder found will be used (Type before Kind) + // The most specific binder found will be used (Type before Kind). TypeBinders = make(map[reflect.Type]Binder) KindBinders = make(map[reflect.Kind]Binder) @@ -284,7 +284,7 @@ func bindSlice(params *Params, name string, typ reflect.Type) reflect.Value { } // Break on dots and brackets. -// e.g. bar => "bar", bar.baz => "bar", bar[0] => "bar" +// e.g. bar => "bar", bar.baz => "bar", bar[0] => "bar". func nextKey(key string) string { fieldLen := strings.IndexAny(key, ".[") if fieldLen == -1 { diff --git a/binder_test.go b/binder_test.go index 23749ddcf..7f593a20c 100644 --- a/binder_test.go +++ b/binder_test.go @@ -7,7 +7,6 @@ package revel import ( "encoding/json" "fmt" - "github.com/revel/config" "io" "io/ioutil" "os" @@ -16,12 +15,15 @@ import ( "strings" "testing" "time" + + "github.com/revel/config" ) type A struct { - ID int - Name string - B B + ID int + Name string + B B + //nolint:unused private int } @@ -209,7 +211,6 @@ func TestJsonBinder(t *testing.T) { if actualb["a"]["b"] != 45 { t.Errorf("Failed to fetch map value %#v", actual["a"]) } - } } @@ -250,7 +251,6 @@ func TestBinder(t *testing.T) { } for k, fhs := range expectedBoundFiles { - if len(fhs) == 1 { // Test binding single files to: *os.File, []byte, io.Reader, io.ReadSeeker for _, binding := range fileBindings { @@ -263,7 +263,6 @@ func TestBinder(t *testing.T) { returns := reflect.ValueOf(binding.f).Call([]reflect.Value{actual}) valEq(t, k, returns[0], reflect.ValueOf(fhs[0].content)) } - } else { // Test binding multi to: // []*os.File, [][]byte, []io.Reader, []io.ReadSeeker diff --git a/cache/cache.go b/cache/cache.go index 7406004ca..056fdbf83 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -137,9 +137,11 @@ func Flush() error { return Insta func Set(key string, value interface{}, expires time.Duration) error { return Instance.Set(key, value, expires) } + func Add(key string, value interface{}, expires time.Duration) error { return Instance.Add(key, value, expires) } + func Replace(key string, value interface{}, expires time.Duration) error { return Instance.Replace(key, value, expires) } diff --git a/cache/cache_test.go b/cache/cache_test.go index bc5461708..070ee8d6e 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -14,7 +14,7 @@ import ( // They should pass for all implementations. type cacheFactory func(*testing.T, time.Duration) Cache -// Test typical cache interactions +// Test typical cache interactions. func typicalGetSet(t *testing.T, newCache cacheFactory) { var err error cache := newCache(t, time.Hour) @@ -34,7 +34,7 @@ func typicalGetSet(t *testing.T, newCache cacheFactory) { } } -// Test the increment-decrement cases +// Test the increment-decrement cases. func incrDecr(t *testing.T, newCache cacheFactory) { var err error cache := newCache(t, time.Hour) diff --git a/cache/inmemory.go b/cache/inmemory.go index 8257f97ac..1d0eb4562 100644 --- a/cache/inmemory.go +++ b/cache/inmemory.go @@ -7,10 +7,10 @@ package cache import ( "fmt" "reflect" + "sync" "time" "github.com/patrickmn/go-cache" - "sync" ) type InMemoryCache struct { @@ -122,7 +122,7 @@ func (c InMemoryCache) Flush() error { return nil } -// Fetches and returns the converted type to a uint64 +// Fetches and returns the converted type to a uint64. func (c InMemoryCache) convertTypeToUint64(key string) (newValue uint64, err error) { v, found := c.cache.Get(key) if !found { @@ -151,7 +151,7 @@ func (c InMemoryCache) convertTypeToUint64(key string) (newValue uint64, err err case uint32: newValue = uint64(v.(uint32)) case uint64: - newValue = uint64(v.(uint64)) + newValue = v.(uint64) case float32: newValue = uint64(v.(float32)) case float64: diff --git a/cache/inmemory_test.go b/cache/inmemory_test.go index 1f9cf1f24..60e2fc6e2 100644 --- a/cache/inmemory_test.go +++ b/cache/inmemory_test.go @@ -13,12 +13,12 @@ var newInMemoryCache = func(_ *testing.T, defaultExpiration time.Duration) Cache return NewInMemoryCache(defaultExpiration) } -// Test typical cache interactions +// Test typical cache interactions. func TestInMemoryCache_TypicalGetSet(t *testing.T) { typicalGetSet(t, newInMemoryCache) } -// Test the increment-decrement cases +// Test the increment-decrement cases. func TestInMemoryCache_IncrDecr(t *testing.T) { incrDecr(t, newInMemoryCache) } diff --git a/cache/memcached.go b/cache/memcached.go index fbc7ece35..f082c158c 100644 --- a/cache/memcached.go +++ b/cache/memcached.go @@ -72,7 +72,6 @@ func (c MemcachedCache) Flush() error { func (c MemcachedCache) invoke(f func(*memcache.Client, *memcache.Item) error, key string, value interface{}, expires time.Duration) error { - switch expires { case DefaultExpiryTime: expires = c.defaultExpiration diff --git a/cache/memcached_test.go b/cache/memcached_test.go index 75376e0c1..660dfe747 100644 --- a/cache/memcached_test.go +++ b/cache/memcached_test.go @@ -10,7 +10,7 @@ import ( "time" ) -// These tests require memcached running on localhost:11211 (the default) +// These tests require memcached running on localhost:11211 (the default). const testServer = "localhost:11211" var newMemcachedCache = func(t *testing.T, defaultExpiration time.Duration) Cache { diff --git a/cache/redis.go b/cache/redis.go index 62aafc402..6452fe7a8 100644 --- a/cache/redis.go +++ b/cache/redis.go @@ -7,7 +7,7 @@ package cache import ( "time" - "github.com/garyburd/redigo/redis" + "github.com/gomodule/redigo/redis" "github.com/revel/revel" ) @@ -18,9 +18,9 @@ type RedisCache struct { } // NewRedisCache returns a new RedisCache with given parameters -// until redigo supports sharding/clustering, only one host will be in hostList +// until redigo supports sharding/clustering, only one host will be in hostList. func NewRedisCache(host string, password string, defaultExpiration time.Duration) RedisCache { - var pool = &redis.Pool{ + pool := &redis.Pool{ MaxIdle: revel.Config.IntDefault("cache.redis.maxidle", 5), MaxActive: revel.Config.IntDefault("cache.redis.maxactive", 0), IdleTimeout: time.Duration(revel.Config.IntDefault("cache.redis.idletimeout", 240)) * time.Second, @@ -237,7 +237,6 @@ func (c RedisCache) Flush() error { func (c RedisCache) invoke(f func(string, ...interface{}) (interface{}, error), key string, value interface{}, expires time.Duration) error { - switch expires { case DefaultExpiryTime: expires = c.defaultExpiration diff --git a/cache/redis_test.go b/cache/redis_test.go index ad0b00630..5bf9f47e1 100644 --- a/cache/redis_test.go +++ b/cache/redis_test.go @@ -13,7 +13,7 @@ import ( "github.com/revel/revel" ) -// These tests require redis server running on localhost:6379 (the default) +// These tests require redis server running on localhost:6379 (the default). const redisTestServer = "localhost:6379" var newRedisCache = func(t *testing.T, defaultExpiration time.Duration) Cache { diff --git a/cache/serialization_test.go b/cache/serialization_test.go index a2bb6e969..f5005cc71 100644 --- a/cache/serialization_test.go +++ b/cache/serialization_test.go @@ -77,11 +77,3 @@ func TestRoundTrip(t *testing.T) { } } } - -func zeroMap(arg map[string]interface{}) map[string]interface{} { - result := map[string]interface{}{} - for key, value := range arg { - result[key] = reflect.Zero(reflect.TypeOf(value)).Interface() - } - return result -} diff --git a/compress.go b/compress.go index a44053dd8..565dfbf76 100644 --- a/compress.go +++ b/compress.go @@ -20,6 +20,7 @@ var compressionTypes = [...]string{ var compressableMimes = [...]string{ "text/plain", + "text/csv", "text/html", "text/xml", "text/css", @@ -31,31 +32,31 @@ var compressableMimes = [...]string{ "application/x-javascript", } -// Local log instance for this class +// Local log instance for this class. var compressLog = RevelLog.New("section", "compress") -// WriteFlusher interface for compress writer +// WriteFlusher interface for compress writer. type WriteFlusher interface { - io.Writer // An IO Writer - io.Closer // A closure + io.Writer // An IO Writer + io.Closer // A closure Flush() error /// A flush function } -// The compressed writer +// The compressed writer. type CompressResponseWriter struct { Header *BufferedServerHeader // The header - ControllerResponse *Response // The response - OriginalWriter io.Writer // The writer - compressWriter WriteFlusher // The flushed writer - compressionType string // The compression type - headersWritten bool // True if written - closeNotify chan bool // The notify channel to close - parentNotify <-chan bool // The parent chanel to receive the closed event - closed bool // True if closed + ControllerResponse *Response // The response + OriginalWriter io.Writer // The writer + compressWriter WriteFlusher // The flushed writer + compressionType string // The compression type + headersWritten bool // True if written + closeNotify chan bool // The notify channel to close + parentNotify <-chan bool // The parent chanel to receive the closed event + closed bool // True if closed } // CompressFilter does compression of response body in gzip/deflate if -// `results.compressed=true` in the app.conf +// `results.compressed=true` in the app.conf. func CompressFilter(c *Controller, fc []Filter) { if c.Response.Out.internalHeader.Server != nil && Config.BoolDefault("results.compressed", false) { if c.Response.Status != http.StatusNoContent && c.Response.Status != http.StatusNotModified { @@ -84,7 +85,7 @@ func CompressFilter(c *Controller, fc []Filter) { fc[0](c, fc[1:]) } -// Called to notify the writer is closing +// Called to notify the writer is closing. func (c CompressResponseWriter) CloseNotify() <-chan bool { if c.parentNotify != nil { return c.parentNotify @@ -92,12 +93,7 @@ func (c CompressResponseWriter) CloseNotify() <-chan bool { return c.closeNotify } -// Cancel the writer -func (c *CompressResponseWriter) cancel() { - c.closed = true -} - -// Prepare the headers +// Prepare the headers. func (c *CompressResponseWriter) prepareHeaders() { if c.compressionType != "" { responseMime := "" @@ -126,7 +122,7 @@ func (c *CompressResponseWriter) prepareHeaders() { c.Header.Release() } -// Write the headers +// Write the headers. func (c *CompressResponseWriter) WriteHeader(status int) { if c.closed { return @@ -136,7 +132,7 @@ func (c *CompressResponseWriter) WriteHeader(status int) { c.Header.SetStatus(status) } -// Close the writer +// Close the writer. func (c *CompressResponseWriter) Close() error { if c.closed { return nil @@ -150,7 +146,6 @@ func (c *CompressResponseWriter) Close() error { // TODO When writing directly to stream, an error will be generated compressLog.Error("Close: Error closing compress writer", "type", c.compressionType, "error", err) } - } // Non-blocking write to the closenotifier, if we for some reason should // get called multiple times @@ -162,7 +157,7 @@ func (c *CompressResponseWriter) Close() error { return nil } -// Write to the underling buffer +// Write to the underling buffer. func (c *CompressResponseWriter) Write(b []byte) (int, error) { if c.closed { return 0, io.ErrClosedPipe @@ -191,7 +186,7 @@ func (c *CompressResponseWriter) Write(b []byte) (int, error) { } // DetectCompressionType method detects the compression type -// from header "Accept-Encoding" +// from header "Accept-Encoding". func detectCompressionType(req *Request, resp *Response) (found bool, compressionType string, compressionKind WriteFlusher) { if Config.BoolDefault("results.compressed", false) { acceptedEncodings := strings.Split(req.GetHttpHeader("Accept-Encoding"), ",") @@ -274,21 +269,21 @@ func detectCompressionType(req *Request, resp *Response) (found bool, compressio } // BufferedServerHeader will not send content out until the Released is called, from that point on it will act normally -// It implements all the ServerHeader +// It implements all the ServerHeader. type BufferedServerHeader struct { - cookieList []string // The cookie list + cookieList []string // The cookie list headerMap map[string][]string // The header map - status int // The status - released bool // True if released - original ServerHeader // The original header + status int // The status + released bool // True if released + original ServerHeader // The original header } -// Creates a new instance based on the ServerHeader +// Creates a new instance based on the ServerHeader. func NewBufferedServerHeader(o ServerHeader) *BufferedServerHeader { return &BufferedServerHeader{original: o, headerMap: map[string][]string{}} } -// Sets the cookie +// Sets the cookie. func (bsh *BufferedServerHeader) SetCookie(cookie string) { if bsh.released { bsh.original.SetCookie(cookie) @@ -297,12 +292,12 @@ func (bsh *BufferedServerHeader) SetCookie(cookie string) { } } -// Returns a cookie +// Returns a cookie. func (bsh *BufferedServerHeader) GetCookie(key string) (ServerCookie, error) { return bsh.original.GetCookie(key) } -// Sets (replace) the header key +// Sets (replace) the header key. func (bsh *BufferedServerHeader) Set(key string, value string) { if bsh.released { bsh.original.Set(key, value) @@ -311,7 +306,7 @@ func (bsh *BufferedServerHeader) Set(key string, value string) { } } -// Add (append) to a key this value +// Add (append) to a key this value. func (bsh *BufferedServerHeader) Add(key string, value string) { if bsh.released { bsh.original.Set(key, value) @@ -324,7 +319,7 @@ func (bsh *BufferedServerHeader) Add(key string, value string) { } } -// Delete this key +// Delete this key. func (bsh *BufferedServerHeader) Del(key string) { if bsh.released { bsh.original.Del(key) @@ -333,7 +328,7 @@ func (bsh *BufferedServerHeader) Del(key string) { } } -// Get this key +// Get this key. func (bsh *BufferedServerHeader) Get(key string) (value []string) { if bsh.released { value = bsh.original.Get(key) @@ -347,7 +342,7 @@ func (bsh *BufferedServerHeader) Get(key string) (value []string) { return } -// Get all header keys +// Get all header keys. func (bsh *BufferedServerHeader) GetKeys() (value []string) { if bsh.released { value = bsh.original.GetKeys() @@ -355,21 +350,21 @@ func (bsh *BufferedServerHeader) GetKeys() (value []string) { value = bsh.original.GetKeys() for key := range bsh.headerMap { found := false - for _,v := range value { - if v==key { + for _, v := range value { + if v == key { found = true break } } if !found { - value = append(value,key) + value = append(value, key) } } } return } -// Set the status +// Set the status. func (bsh *BufferedServerHeader) SetStatus(statusCode int) { if bsh.released { bsh.original.SetStatus(statusCode) @@ -378,7 +373,7 @@ func (bsh *BufferedServerHeader) SetStatus(statusCode int) { } } -// Release the header and push the results to the original +// Release the header and push the results to the original. func (bsh *BufferedServerHeader) Release() { bsh.released = true for k, v := range bsh.headerMap { diff --git a/controller.go b/controller.go index 5e122fb71..2f4235c71 100644 --- a/controller.go +++ b/controller.go @@ -22,48 +22,49 @@ import ( ) // Controller Revel's controller structure that gets embedded in user defined -// controllers +// controllers. type Controller struct { - Name string // The controller name, e.g. "Application" - Type *ControllerType // A description of the controller type. - MethodName string // The method name, e.g. "Index" - MethodType *MethodType // A description of the invoked action type. - AppController interface{} // The controller that was instantiated. embeds revel.Controller - Action string // The fully qualified action name, e.g. "App.Index" - ClientIP string // holds IP address of request came from - - Request *Request - Response *Response - Result Result - - Flash Flash // User cookie, cleared after 1 request. - Session session.Session // Session, stored using the session engine specified - Params *Params // Parameters from URL and form (including multipart). - Args map[string]interface{} // Per-request scratch space. - ViewArgs map[string]interface{} // Variables passed to the template. - Validation *Validation // Data validation helpers - Log logger.MultiLogger // Context Logger -} - -// The map of controllers, controllers are mapped by using the namespace|controller_name as the key -var controllers = make(map[string]*ControllerType) -var controllerLog = RevelLog.New("section", "controller") - -// NewController returns new controller instance for Request and Response + Name string // The controller name, e.g. "Application" + Type *ControllerType // A description of the controller type. + MethodName string // The method name, e.g. "Index" + MethodType *MethodType // A description of the invoked action type. + AppController interface{} // The controller that was instantiated. embeds revel.Controller + Action string // The fully qualified action name, e.g. "App.Index" + ClientIP string // holds IP address of request came from + + Request *Request + Response *Response + Result Result + + Flash Flash // User cookie, cleared after 1 request. + Session session.Session // Session, stored using the session engine specified + Params *Params // Parameters from URL and form (including multipart). + Args map[string]interface{} // Per-request scratch space. + ViewArgs map[string]interface{} // Variables passed to the template. + Validation *Validation // Data validation helpers + Log logger.MultiLogger // Context Logger +} + +// The map of controllers, controllers are mapped by using the namespace|controller_name as the key. +var ( + controllers = make(map[string]*ControllerType) + controllerLog = RevelLog.New("section", "controller") +) + +// NewController returns new controller instance for Request and Response. func NewControllerEmpty() *Controller { return &Controller{Request: NewRequest(nil), Response: NewResponse(nil)} } -// New controller, creates a new instance wrapping the request and response in it +// New controller, creates a new instance wrapping the request and response in it. func NewController(context ServerContext) *Controller { c := NewControllerEmpty() c.SetController(context) return c } -// Sets the request and the response for the controller +// Sets the request and the response for the controller. func (c *Controller) SetController(context ServerContext) { - c.Request.SetRequest(context.GetRequest()) c.Response.SetResponse(context.GetResponse()) c.Request.controller = c @@ -73,8 +74,8 @@ func (c *Controller) SetController(context ServerContext) { "RunMode": RunMode, "DevMode": DevMode, } - } + func (c *Controller) Destroy() { // When the instantiated controller gets injected // It inherits this method, so we need to @@ -165,7 +166,7 @@ func (c *Controller) setStatusIfNil(status int) { // c.RenderTemplate(c.Name + "/" + c.MethodType.Name + "." + c.Request.Format) // // If you want your code to run faster it is recommended you add the template values directly -// to the c.ViewArgs and call c.RenderTemplate directly +// to the c.ViewArgs and call c.RenderTemplate directly. func (c *Controller) Render(extraViewArgs ...interface{}) Result { c.setStatusIfNil(http.StatusOK) @@ -223,7 +224,7 @@ func (c *Controller) RenderJSON(o interface{}) Result { return RenderJSONResult{o, ""} } -// RenderJSONP renders JSONP result using encoding/json.Marshal +// RenderJSONP renders JSONP result using encoding/json.Marshal. func (c *Controller) RenderJSONP(callback string, o interface{}) Result { c.setStatusIfNil(http.StatusOK) @@ -248,7 +249,7 @@ func (c *Controller) RenderText(text string, objs ...interface{}) Result { return &RenderTextResult{finalText} } -// RenderHTML renders html in response +// RenderHTML renders html in response. func (c *Controller) RenderHTML(html string) Result { c.setStatusIfNil(http.StatusOK) @@ -312,7 +313,7 @@ func (c *Controller) RenderFile(file *os.File, delivery ContentDisposition) Resu c.setStatusIfNil(http.StatusOK) var ( - modtime = time.Now() + modtime = time.Now() fileInfo, err = file.Stat() ) if err != nil { @@ -358,13 +359,13 @@ func (c *Controller) Redirect(val interface{}, args ...interface{}) Result { } // This stats returns some interesting stats based on what is cached in memory -// and what is available directly +// and what is available directly. func (c *Controller) Stats() map[string]interface{} { result := CurrentEngine.Stats() if RevelConfig.Controller.Reuse { result["revel-controllers"] = RevelConfig.Controller.Stack.String() for key, appStack := range RevelConfig.Controller.CachedMap { - result["app-" + key] = appStack.String() + result["app-"+key] = appStack.String() } } return result @@ -379,15 +380,13 @@ func (c *Controller) Message(message string, args ...interface{}) string { } // SetAction sets the action that is being invoked in the current request. -// It sets the following properties: Name, Action, Type, MethodType +// It sets the following properties: Name, Action, Type, MethodType. func (c *Controller) SetAction(controllerName, methodName string) error { - return c.SetTypeAction(controllerName, methodName, nil) } -// SetAction sets the assigns the Controller type, sets the action and initializes the controller +// SetAction sets the assigns the Controller type, sets the action and initializes the controller. func (c *Controller) SetTypeAction(controllerName, methodName string, typeOfController *ControllerType) error { - // Look up the controller and method types. if typeOfController == nil { if c.Type = ControllerTypeByName(controllerName, anyModule); c.Type == nil { @@ -443,7 +442,6 @@ func ControllerTypeByName(controllerName string, moduleSource *Module) (c *Contr if testControllerName == strings.ToLower(controllerName) && (cType.ModuleSource == moduleSource || moduleSource == anyModule) { controllerLog.Warn("ControllerTypeByName: Matched empty namespace controller ", "controller", controllerName, "namespace", cType.ModuleSource.Name) c = cType - found = true break } } @@ -452,7 +450,7 @@ func ControllerTypeByName(controllerName string, moduleSource *Module) (c *Contr return } -// Injects this instance (c) into the AppController instance +// Injects this instance (c) into the AppController instance. func (c *Controller) setAppControllerFields() { appController := reflect.ValueOf(c.AppController).Elem() cValue := reflect.ValueOf(c) @@ -461,7 +459,7 @@ func (c *Controller) setAppControllerFields() { } } -// Removes this instance (c) from the AppController instance +// Removes this instance (c) from the AppController instance. func (c *Controller) resetAppControllerFields() { appController := reflect.ValueOf(c.AppController).Elem() // Zero out controller @@ -482,8 +480,8 @@ func findControllers(appControllerType reflect.Type) (indexes [][]int) { for len(queue) > 0 { // Get the next value and de-reference it if necessary. var ( - node = queue[0] - elem = node.val + node = queue[0] + elem = node.val elemType = elem.Type() ) if elemType.Kind() == reflect.Ptr { diff --git a/controller_type.go b/controller_type.go index 4ba2f33f9..aeecc7f0b 100644 --- a/controller_type.go +++ b/controller_type.go @@ -14,12 +14,13 @@ type ControllerType struct { ControllerIndexes [][]int // FieldByIndex to all embedded *Controllers ControllerEvents *ControllerTypeEvents } + type ControllerTypeEvents struct { Before, After, Finally, Panic []*ControllerFieldPath } // The controller field path provides the caller the ability to invoke the call -// directly +// directly. type ControllerFieldPath struct { IsPointer bool FieldIndexPath []int @@ -67,7 +68,7 @@ func AddControllerType(moduleSource *Module, controllerType reflect.Type, method return } -// Method searches for a given exported method (case insensitive) +// Method searches for a given exported method (case insensitive). func (ct *ControllerType) Method(name string) *MethodType { lowerName := strings.ToLower(name) for _, method := range ct.Methods { @@ -78,12 +79,12 @@ func (ct *ControllerType) Method(name string) *MethodType { return nil } -// The controller name with the namespace +// The controller name with the namespace. func (ct *ControllerType) Name() string { return ct.Namespace + ct.ShortName() } -// The controller name without the namespace +// The controller name without the namespace. func (ct *ControllerType) ShortName() string { return strings.ToLower(ct.Type.Name()) } @@ -97,7 +98,7 @@ func NewControllerTypeEvents(c *ControllerType) (ce *ControllerTypeEvents) { } // Add in before after panic and finally, recursive call -// Befores are ordered in revers, everything else is in order of first encountered +// Befores are ordered in revers, everything else is in order of first encountered. func (cte *ControllerTypeEvents) check(theType reflect.Type, fieldPath []int) { typeChecker := func(checkType reflect.Type) { for index := 0; index < checkType.NumMethod(); index++ { @@ -141,6 +142,7 @@ func (cte *ControllerTypeEvents) check(theType reflect.Type, fieldPath []int) { } } } + func newFieldPath(isPointer bool, value reflect.Value, fieldPath []int) *ControllerFieldPath { return &ControllerFieldPath{IsPointer: isPointer, FunctionCall: value, FieldIndexPath: fieldPath} } diff --git a/errors.go b/errors.go index dc3807a06..77fb012b7 100644 --- a/errors.go +++ b/errors.go @@ -34,7 +34,6 @@ type SourceLine struct { // provide a code listing of that, on the line that eventually triggered // the panic. Returns nil if no relevant stack frame can be found. func NewErrorFromPanic(err interface{}) *Error { - // Parse the filename and line from the originating line of app code. // /Users/robfig/code/gocode/src/revel/examples/booking/app/controllers/hotels.go:191 (0x44735) stack := string(debug.Stack()) @@ -71,7 +70,7 @@ func NewErrorFromPanic(err interface{}) *Error { // Error method constructs a plaintext version of the error, taking // account that fields are optionally set. Returns e.g. Compilation Error -// (in views/header.html:51): expected right delim in end; got "}" +// (in views/header.html:51): expected right delim in end; got "}". func (e *Error) Error() string { loc := "" if e.Path != "" { @@ -115,7 +114,7 @@ func (e *Error) ContextSource() []SourceLine { return lines } -// SetLink method prepares a link and assign to Error.Link attribute +// SetLink method prepares a link and assign to Error.Link attribute. func (e *Error) SetLink(errorLink string) { errorLink = strings.Replace(errorLink, "{{Path}}", e.Path, -1) errorLink = strings.Replace(errorLink, "{{Line}}", strconv.Itoa(e.Line), -1) diff --git a/event.go b/event.go index 9c66fb025..826249095 100644 --- a/event.go +++ b/event.go @@ -1,47 +1,47 @@ package revel type ( - // The event type + // The event type. Event int - // The event response + // The event response. EventResponse int - // The handler signature + // The handler signature. EventHandler func(typeOf Event, value interface{}) (responseOf EventResponse) ) const ( - // Event type when templates are going to be refreshed (receivers are registered template engines added to the template.engine conf option) + // Event type when templates are going to be refreshed (receivers are registered template engines added to the template.engine conf option). TEMPLATE_REFRESH_REQUESTED Event = iota - // Event type when templates are refreshed (receivers are registered template engines added to the template.engine conf option) + // Event type when templates are refreshed (receivers are registered template engines added to the template.engine conf option). TEMPLATE_REFRESH_COMPLETED - // Event type before all module loads, events thrown to handlers added to AddInitEventHandler + // Event type before all module loads, events thrown to handlers added to AddInitEventHandler. - // Event type before all module loads, events thrown to handlers added to AddInitEventHandler + // Event type before all module loads, events thrown to handlers added to AddInitEventHandler. REVEL_BEFORE_MODULES_LOADED - // Event type after all module loads, events thrown to handlers added to AddInitEventHandler + // Event type after all module loads, events thrown to handlers added to AddInitEventHandler. REVEL_AFTER_MODULES_LOADED - // Event type before server engine is initialized, receivers are active server engine and handlers added to AddInitEventHandler + // Event type before server engine is initialized, receivers are active server engine and handlers added to AddInitEventHandler. ENGINE_BEFORE_INITIALIZED - // Event type before server engine is started, receivers are active server engine and handlers added to AddInitEventHandler + // Event type before server engine is started, receivers are active server engine and handlers added to AddInitEventHandler. ENGINE_STARTED - // Event raised when the engine is told to shutdown + // Event raised when the engine is told to shutdown. ENGINE_SHUTDOWN_REQUEST - // Event type after server engine is stopped, receivers are active server engine and handlers added to AddInitEventHandler + // Event type after server engine is stopped, receivers are active server engine and handlers added to AddInitEventHandler. ENGINE_SHUTDOWN - // Called before routes are refreshed + // Called before routes are refreshed. ROUTE_REFRESH_REQUESTED - // Called after routes have been refreshed + // Called after routes have been refreshed. ROUTE_REFRESH_COMPLETED - // Fired when a panic is caught during the startup process + // Fired when a panic is caught during the startup process. REVEL_FAILURE ) -// Fires system events from revel +// Fires system events from revel. func RaiseEvent(key Event, value interface{}) (response EventResponse) { utilLog.Info("Raising event", "len", len(initEventList)) for _, handler := range initEventList { @@ -50,7 +50,7 @@ func RaiseEvent(key Event, value interface{}) (response EventResponse) { return } -// Add event handler to listen for all system events +// Add event handler to listen for all system events. func AddInitEventHandler(handler EventHandler) { initEventList = append(initEventList, handler) return diff --git a/event_test.go b/event_test.go index 0baadc058..15196f8f5 100644 --- a/event_test.go +++ b/event_test.go @@ -1,12 +1,13 @@ package revel_test import ( + "testing" + "github.com/revel/revel" "github.com/stretchr/testify/assert" - "testing" ) -// Test that the event handler can be attached and it dispatches the event received +// Test that the event handler can be attached and it dispatches the event received. func TestEventHandler(t *testing.T) { counter := 0 newListener := func(typeOf revel.Event, value interface{}) (responseOf revel.EventResponse) { diff --git a/fakeapp_test.go b/fakeapp_test.go index a2bcabd4c..8ecdd16cd 100644 --- a/fakeapp_test.go +++ b/fakeapp_test.go @@ -68,7 +68,7 @@ func (c Static) Serve(prefix, path string) Result { return c.RenderFile(file, "") } -// Register controllers is in its own function so the route test can use it as well +// Register controllers is in its own function so the route test can use it as well. func registerControllers() { controllers = make(map[string]*ControllerType) RaiseEvent(ROUTE_REFRESH_REQUESTED, nil) @@ -134,12 +134,13 @@ func registerControllers() { }, }) } + func startFakeBookingApp() { Init("prod", "github.com/revel/revel/testdata", "") MainTemplateLoader = NewTemplateLoader([]string{ViewsPath, filepath.Join(RevelPath, "templates")}) if err := MainTemplateLoader.Refresh(); err != nil { - RevelLog.Fatal("Template error","error",err) + RevelLog.Fatal("Template error", "error", err) } registerControllers() diff --git a/field.go b/field.go index 93f2b1c5f..f08f04e27 100644 --- a/field.go +++ b/field.go @@ -90,7 +90,7 @@ func (f *Field) ErrorClass() string { return "" } -// Get the short name and translate it +// Get the short name and translate it. func (f *Field) ShortName() string { name := f.Name if i := strings.LastIndex(name, "."); i > 0 { @@ -99,7 +99,7 @@ func (f *Field) ShortName() string { return f.Translate(name) } -// Translate the text +// Translate the text. func (f *Field) Translate(text string, args ...interface{}) string { if f.controller != nil { text = f.controller.Message(text, args...) diff --git a/filter.go b/filter.go index 2226dff86..aa4b02a59 100644 --- a/filter.go +++ b/filter.go @@ -4,7 +4,7 @@ package revel -// Filter type definition for Revel's filter +// Filter type definition for Revel's filter. type Filter func(c *Controller, filterChain []Filter) // Filters is the default set of global filters. diff --git a/filterconfig.go b/filterconfig.go index 010d7ea92..6ec4c83be 100644 --- a/filterconfig.go +++ b/filterconfig.go @@ -9,7 +9,7 @@ import ( "strings" ) -// Map from "Controller" or "Controller.Method" to the Filter chain +// Map from "Controller" or "Controller.Method" to the Filter chain. var filterOverrides = make(map[string][]Filter) // FilterConfigurator allows the developer configure the filter chain on a @@ -102,7 +102,7 @@ func FilterAction(methodRef interface{}) FilterConfigurator { } // Add the given filter in the second-to-last position in the filter chain. -// (Second-to-last so that it is before ActionInvoker) +// (Second-to-last so that it is before ActionInvoker). func (conf FilterConfigurator) Add(f Filter) FilterConfigurator { conf.apply(func(fc []Filter) []Filter { return conf.addFilter(f, fc) @@ -211,7 +211,7 @@ func FilterConfiguringFilter(c *Controller, fc []Filter) { fc[0](c, fc[1:]) } -// getOverrideChain retrieves the overrides for the action that is set +// getOverrideChain retrieves the overrides for the action that is set. func getOverrideChain(controllerName, action string) []Filter { if newChain, ok := filterOverrides[action]; ok { return newChain diff --git a/http.go b/http.go index dbdd58d6a..2a9ea09fc 100644 --- a/http.go +++ b/http.go @@ -6,21 +6,20 @@ package revel import ( "bytes" + "context" "errors" "fmt" "io" + "mime/multipart" "net/http" "net/url" + "path/filepath" "sort" "strconv" "strings" - - "context" - "mime/multipart" - "path/filepath" ) -// Request is Revel's HTTP request object structure +// Request is Revel's HTTP request object structure. type Request struct { In ServerRequest // The server request Header *RevelHeader // The revel header @@ -41,10 +40,12 @@ type Request struct { controller *Controller // The controller, so some of this data can be fetched } -var FORM_NOT_FOUND = errors.New("Form Not Found") -var httpLog = RevelLog.New("section", "http") +var ( + FORM_NOT_FOUND = errors.New("Form Not Found") + httpLog = RevelLog.New("section", "http") +) -// Response is Revel's HTTP response object structure +// Response is Revel's HTTP response object structure. type Response struct { Status int ContentType string @@ -52,7 +53,7 @@ type Response struct { writer io.Writer } -// The output response +// The output response. type OutResponse struct { // internalHeader.Server Set by ServerResponse.Get(HTTP_SERVER_HEADER), saves calling the get every time the header needs to be written to internalHeader *RevelHeader // The internal header @@ -60,19 +61,19 @@ type OutResponse struct { response *Response // The response } -// The header defined in Revel +// The header defined in Revel. type RevelHeader struct { Server ServerHeader // The server } -// NewResponse wraps ServerResponse inside a Revel's Response and returns it +// NewResponse wraps ServerResponse inside a Revel's Response and returns it. func NewResponse(w ServerResponse) (r *Response) { r = &Response{Out: OutResponse{Server: w, internalHeader: &RevelHeader{}}} r.Out.response = r return r } -// NewRequest returns a Revel's HTTP request instance with given HTTP instance +// NewRequest returns a Revel's HTTP request instance with given HTTP instance. func NewRequest(r ServerRequest) *Request { req := &Request{Header: &RevelHeader{}} if r != nil { @@ -80,6 +81,7 @@ func NewRequest(r ServerRequest) *Request { } return req } + func (req *Request) SetRequest(r ServerRequest) { req.In = r if h, e := req.In.Get(HTTP_SERVER_HEADER); e == nil { @@ -93,10 +95,9 @@ func (req *Request) SetRequest(r ServerRequest) { req.Method, _ = req.GetValue(HTTP_METHOD).(string) req.RemoteAddr, _ = req.GetValue(HTTP_REMOTE_ADDR).(string) req.Host, _ = req.GetValue(HTTP_HOST).(string) - } -// Returns a cookie +// Returns a cookie. func (req *Request) Cookie(key string) (ServerCookie, error) { if req.Header.Server != nil { return req.Header.Server.GetCookie(key) @@ -104,42 +105,42 @@ func (req *Request) Cookie(key string) (ServerCookie, error) { return nil, http.ErrNoCookie } -// Fetch the requested URI +// Fetch the requested URI. func (req *Request) GetRequestURI() string { uri, _ := req.GetValue(HTTP_REQUEST_URI).(string) return uri } -// Fetch the query +// Fetch the query. func (req *Request) GetQuery() (v url.Values) { v, _ = req.GetValue(ENGINE_PARAMETERS).(url.Values) return } -// Fetch the path +// Fetch the path. func (req *Request) GetPath() (path string) { path, _ = req.GetValue(ENGINE_PATH).(string) return } -// Fetch the body +// Fetch the body. func (req *Request) GetBody() (body io.Reader) { body, _ = req.GetValue(HTTP_BODY).(io.Reader) return } -// Fetch the context +// Fetch the context. func (req *Request) Context() (c context.Context) { c, _ = req.GetValue(HTTP_REQUEST_CONTEXT).(context.Context) return } -// Deprecated use controller.Params.Get() +// Deprecated use controller.Params.Get(). func (req *Request) FormValue(key string) (value string) { return req.controller.Params.Get(key) } -// Deprecated use controller.Params.Form[Key] +// Deprecated use controller.Params.Form[Key]. func (req *Request) PostFormValue(key string) (value string) { valueList := req.controller.Params.Form[key] if len(valueList) > 0 { @@ -148,7 +149,7 @@ func (req *Request) PostFormValue(key string) (value string) { return } -// Deprecated use GetForm() instead +// Deprecated use GetForm() instead. func (req *Request) ParseForm() (e error) { if req.Form == nil { req.Form, e = req.GetForm() @@ -166,7 +167,7 @@ func (req *Request) GetForm() (url.Values, error) { return nil, FORM_NOT_FOUND } -// Deprecated for backwards compatibility only +// Deprecated for backwards compatibility only. type MultipartForm struct { File map[string][]*multipart.FileHeader Value url.Values @@ -174,16 +175,15 @@ type MultipartForm struct { } func (req *Request) MultipartReader() (*multipart.Reader, error) { - return nil, errors.New("MultipartReader not supported, use controller.Param") } -// Deprecated for backwards compatibility only +// Deprecated for backwards compatibility only. func newMultipareForm(s ServerMultipartForm) (f *MultipartForm) { return &MultipartForm{File: s.GetFiles(), Value: s.GetValues(), origin: s} } -// Deprecated use GetMultipartForm() instead +// Deprecated use GetMultipartForm() instead. func (req *Request) ParseMultipartForm(_ int64) (e error) { var s ServerMultipartForm if s, e = req.GetMultipartForm(); e == nil { @@ -192,12 +192,12 @@ func (req *Request) ParseMultipartForm(_ int64) (e error) { return } -// Return the args for the controller +// Return the args for the controller. func (req *Request) Args() map[string]interface{} { return req.controller.Args } -// Return a multipart form +// Return a multipart form. func (req *Request) GetMultipartForm() (ServerMultipartForm, error) { if form, err := req.In.Get(HTTP_MULTIPART_FORM); err != nil { return nil, err @@ -207,7 +207,7 @@ func (req *Request) GetMultipartForm() (ServerMultipartForm, error) { return nil, FORM_NOT_FOUND } -// Destroy the request +// Destroy the request. func (req *Request) Destroy() { req.In = nil req.ContentType = "" @@ -222,7 +222,7 @@ func (req *Request) Destroy() { req.MultipartForm = nil } -// Set the server response +// Set the server response. func (resp *Response) SetResponse(r ServerResponse) { resp.Out.Server = r if h, e := r.Get(HTTP_SERVER_HEADER); e == nil { @@ -230,18 +230,18 @@ func (resp *Response) SetResponse(r ServerResponse) { } } -// Destroy the output response +// Destroy the output response. func (o *OutResponse) Destroy() { o.response = nil o.internalHeader.Destroy() } -// Destroy the RevelHeader +// Destroy the RevelHeader. func (h *RevelHeader) Destroy() { h.Server = nil } -// Destroy the Response +// Destroy the Response. func (resp *Response) Destroy() { resp.Out.Destroy() resp.Status = 0 @@ -259,12 +259,12 @@ func (req *Request) Referer() string { return req.Header.Get("Referer") } -// Return the httpheader for the key +// Return the httpheader for the key. func (req *Request) GetHttpHeader(key string) string { return req.Header.Get(key) } -// Return the value from the server +// Return the value from the server. func (r *Request) GetValue(key int) (value interface{}) { value, _ = r.In.Get(key) return @@ -283,16 +283,16 @@ func (resp *Response) WriteHeader(defaultStatusCode int, defaultContentType stri } resp.SetStatus(resp.Status) } + func (resp *Response) SetStatus(statusCode int) { if resp.Out.internalHeader.Server != nil { resp.Out.internalHeader.Server.SetStatus(statusCode) } else { resp.Out.Server.Set(ENGINE_RESPONSE_STATUS, statusCode) } - } -// Return the writer +// Return the writer. func (resp *Response) GetWriter() (writer io.Writer) { writer = resp.writer if writer == nil { @@ -304,14 +304,14 @@ func (resp *Response) GetWriter() (writer io.Writer) { return } -// Replace the writer +// Replace the writer. func (resp *Response) SetWriter(writer io.Writer) bool { resp.writer = writer // Leave it up to the engine to flush and close the writer return resp.Out.Server.Set(ENGINE_WRITER, writer) } -// Passes full control to the response to the caller - terminates any initial writes +// Passes full control to the response to the caller - terminates any initial writes. func (resp *Response) GetStreamWriter() (writer StreamWriter) { if w, e := resp.Out.Server.Get(HTTP_STREAM_WRITER); e == nil { writer = w.(StreamWriter) @@ -319,45 +319,45 @@ func (resp *Response) GetStreamWriter() (writer StreamWriter) { return } -// Return the header +// Return the header. func (o *OutResponse) Header() *RevelHeader { return o.internalHeader } -// Write the header out +// Write the header out. func (o *OutResponse) Write(data []byte) (int, error) { return o.response.GetWriter().Write(data) } -// Set a value in the header +// Set a value in the header. func (h *RevelHeader) Set(key, value string) { if h.Server != nil { h.Server.Set(key, value) } } -// Add a key to the header +// Add a key to the header. func (h *RevelHeader) Add(key, value string) { if h.Server != nil { h.Server.Add(key, value) } } -// Set a cookie in the header +// Set a cookie in the header. func (h *RevelHeader) SetCookie(cookie string) { if h.Server != nil { h.Server.SetCookie(cookie) } } -// Set the status for the header +// Set the status for the header. func (h *RevelHeader) SetStatus(status int) { if h.Server != nil { h.Server.SetStatus(status) } } -// Get a key from the header +// Get a key from the header. func (h *RevelHeader) Get(key string) (value string) { values := h.GetAll(key) if len(values) > 0 { @@ -366,7 +366,7 @@ func (h *RevelHeader) Get(key string) (value string) { return } -// GetAll returns []string of items (the header split by a comma) +// GetAll returns []string of items (the header split by a comma). func (h *RevelHeader) GetAll(key string) (values []string) { if h.Server != nil { values = h.Server.Get(key) @@ -378,7 +378,6 @@ func (h *RevelHeader) GetAll(key string) (values []string) { // e.g. From "multipart/form-data; boundary=--" to "multipart/form-data" // If none is specified, returns "text/html" by default. func ResolveContentType(req *Request) string { - contentType := req.Header.Get("Content-Type") if contentType == "" { return "text/html" diff --git a/i18n.go b/i18n.go index 13fe810da..7c2219044 100644 --- a/i18n.go +++ b/i18n.go @@ -16,7 +16,7 @@ import ( ) const ( - // CurrentLocaleViewArg the key for the current locale view arg value + // CurrentLocaleViewArg the key for the current locale view arg value. CurrentLocaleViewArg = "currentLocale" messageFilesDirectory = "messages" @@ -138,7 +138,7 @@ func loadMessages(path string) { } } -// Load a single message file +// Load a single message file. func loadMessageFile(path string, info os.FileInfo, osError error) error { if osError != nil { return osError diff --git a/i18n_test.go b/i18n_test.go index ce2f67555..1b6b0a8dc 100644 --- a/i18n_test.go +++ b/i18n_test.go @@ -189,7 +189,6 @@ func BenchmarkI18nMessageWithArguments(b *testing.B) { })) }) - for i := 0; i < b.N; i++ { Message("en", "arguments.string", "Vincent Hanna") } @@ -202,7 +201,6 @@ func BenchmarkI18nMessageWithFoldingAndArguments(b *testing.B) { })) }) - for i := 0; i < b.N; i++ { Message("en", "folded.arguments", 12345) } diff --git a/intercept.go b/intercept.go index 2ee867735..7c10a1830 100644 --- a/intercept.go +++ b/intercept.go @@ -40,7 +40,9 @@ import ( // func (c *AppController) example() revel.Result // type InterceptorFunc func(*Controller) Result + type InterceptorMethod interface{} + type When int const ( @@ -207,7 +209,7 @@ func getInterceptors(when When, val reflect.Value) interceptorItemList { // Find the value of the target, starting from val and including embedded types. // Also, convert between any difference in indirection. -// If the target couldn't be found, the returned Value will have IsValid() == false +// If the target couldn't be found, the returned Value will have IsValid() == false. func findTarget(val reflect.Value, target reflect.Type) (int, reflect.Value) { // Look through the embedded types (until we reach the *revel.Controller at the top). valueQueue := []reflect.Value{val} diff --git a/intercept_test.go b/intercept_test.go index ee2138dec..c4bb8186e 100644 --- a/intercept_test.go +++ b/intercept_test.go @@ -9,17 +9,21 @@ import ( "testing" ) -var funcP = func(c *Controller) Result { return nil } -var funcP2 = func(c *Controller) Result { return nil } +var ( + funcP = func(c *Controller) Result { return nil } + funcP2 = func(c *Controller) Result { return nil } +) -type InterceptController struct{ *Controller } -type InterceptControllerN struct{ InterceptController } -type InterceptControllerP struct{ *InterceptController } -type InterceptControllerNP struct { - *Controller - InterceptControllerN - InterceptControllerP -} +type ( + InterceptController struct{ *Controller } + InterceptControllerN struct{ InterceptController } + InterceptControllerP struct{ *InterceptController } + InterceptControllerNP struct { + *Controller + InterceptControllerN + InterceptControllerP + } +) func (c InterceptController) methN() Result { return nil } func (c *InterceptController) methP() Result { return nil } @@ -29,7 +33,7 @@ func (c *InterceptControllerN) methNP() Result { return nil } func (c InterceptControllerP) methPN() Result { return nil } func (c *InterceptControllerP) methPP() Result { return nil } -// Methods accessible from InterceptControllerN +// Methods accessible from InterceptControllerN. var MethodN = []interface{}{ InterceptController.methN, (*InterceptController).methP, @@ -37,7 +41,7 @@ var MethodN = []interface{}{ (*InterceptControllerN).methNP, } -// Methods accessible from InterceptControllerP +// Methods accessible from InterceptControllerP. var MethodP = []interface{}{ InterceptController.methN, (*InterceptController).methP, diff --git a/invoker_test.go b/invoker_test.go index dff94ccf4..cf58f5eee 100644 --- a/invoker_test.go +++ b/invoker_test.go @@ -19,8 +19,9 @@ type PN struct{ P } type PNN struct{ PN } -// Embedded via two paths +// Embedded via two paths. type P2 struct{ *Controller } + type PP2 struct { *Controller // Need to embed this explicitly to avoid duplicate selector. P @@ -81,17 +82,21 @@ func TestSetAction(t *testing.T) { } func BenchmarkSetAction(b *testing.B) { + //nolint:unused type Mixin1 struct { *Controller x, y int foo string } + + //nolint:unused type Mixin2 struct { *Controller a, b float64 bar string } + //nolint:unused type Benchmark struct { *Controller Mixin1 diff --git a/libs.go b/libs.go index fb171786f..3599c58a9 100644 --- a/libs.go +++ b/libs.go @@ -29,7 +29,7 @@ func Sign(message string) string { } // Verify returns true if the given signature is correct for the given message. -// e.g. it matches what we generate with Sign() +// e.g. it matches what we generate with Sign(). func Verify(message, sig string) bool { return hmac.Equal([]byte(sig), []byte(Sign(message))) } @@ -42,7 +42,7 @@ func Verify(message, sig string) bool { // - For string value, please refer `revel.Atob` method // - An array, map, slice with zero elements // - Boolean value returned as-is -// - "nil" value +// - "nil" value. func ToBool(val interface{}) bool { if val == nil { return false @@ -74,7 +74,7 @@ func ToBool(val interface{}) bool { // - The "false" string // - The "f" string // - The "off" string, -// - The string "0" & "0.0" +// - The string "0" & "0.0". func Atob(v string) bool { switch strings.TrimSpace(strings.ToLower(v)) { case "", "false", "off", "f", "0", "0.0": diff --git a/logger.go b/logger.go index 8d1ac36df..647d96ebf 100644 --- a/logger.go +++ b/logger.go @@ -4,40 +4,36 @@ import ( "github.com/revel/revel/logger" ) -//Logger +// Logger. var ( // The root log is what all other logs are branched from, meaning if you set the handler for the root - // it will adjust all children + // it will adjust all children. RootLog = logger.New() // This logger is the application logger, use this for your application log messages - ie jobs and startup, // Use Controller.Log for Controller logging - // The requests are logged to this logger with the context of `section:requestlog` + // The requests are logged to this logger with the context of `section:requestlog`. AppLog = RootLog.New("module", "app") // This is the logger revel writes to, added log messages will have a context of module:revel in them - // It is based off of `RootLog` + // It is based off of `RootLog`. RevelLog = RootLog.New("module", "revel") // This is the handler for the AppLog, it is stored so that if the AppLog is changed it can be assigned to the - // new AppLog + // new AppLog. appLogHandler *logger.CompositeMultiHandler - // This oldLog is the revel logger, historical for revel, The application should use the AppLog or the Controller.oldLog - // DEPRECATED - oldLog = AppLog.New("section", "deprecated") - // System logger + // System logger. SysLog = AppLog.New("section", "system") ) -// Initialize the loggers first +// Initialize the loggers first. func init() { - - //RootLog.SetHandler( + // RootLog.SetHandler( // logger.LevelHandler(logger.LogLevel(log15.LvlDebug), // logger.StreamHandler(os.Stdout, logger.TerminalFormatHandler(false, true)))) initLoggers() OnAppStart(initLoggers, -5) - } + func initLoggers() { appHandle := logger.InitializeFromConfig(BasePath, Config) @@ -46,7 +42,7 @@ func initLoggers() { } // Set the application log and handler, if handler is nil it will -// use the same handler used to configure the application log before +// use the same handler used to configure the application log before. func setAppLog(appLog logger.MultiLogger, appHandler *logger.CompositeMultiHandler) { if appLog != nil { AppLog = appLog diff --git a/logger/composite_multihandler.go b/logger/composite_multihandler.go index fb15e8a3e..79f00197f 100644 --- a/logger/composite_multihandler.go +++ b/logger/composite_multihandler.go @@ -1,10 +1,11 @@ package logger import ( - "github.com/mattn/go-colorable" - "gopkg.in/natefinch/lumberjack.v2" "io" "os" + + "github.com/mattn/go-colorable" + "gopkg.in/natefinch/lumberjack.v2" ) type CompositeMultiHandler struct { @@ -19,8 +20,8 @@ func NewCompositeMultiHandler() (*CompositeMultiHandler, LogHandler) { cw := &CompositeMultiHandler{} return cw, cw } -func (h *CompositeMultiHandler) Log(r *Record) (err error) { +func (h *CompositeMultiHandler) Log(r *Record) (err error) { var handler LogHandler switch r.Level { @@ -78,7 +79,7 @@ func (h *CompositeMultiHandler) SetHandler(handler LogHandler, replace bool, lev } } -// For the multi handler set the handler, using the LogOptions defined +// For the multi handler set the handler, using the LogOptions defined. func (h *CompositeMultiHandler) SetHandlers(handler LogHandler, options *LogOptions) { if len(options.Levels) == 0 { options.Levels = LvlAllList @@ -88,8 +89,8 @@ func (h *CompositeMultiHandler) SetHandlers(handler LogHandler, options *LogOpti for _, lvl := range options.Levels { h.SetHandler(handler, options.ReplaceExistingHandler, lvl) } - } + func (h *CompositeMultiHandler) SetJson(writer io.Writer, options *LogOptions) { handler := CallerFileHandler(StreamHandler(writer, JsonFormatEx( options.GetBoolDefault("pretty", false), @@ -101,12 +102,12 @@ func (h *CompositeMultiHandler) SetJson(writer io.Writer, options *LogOptions) { h.SetHandlers(handler, options) } -// Use built in rolling function +// Use built in rolling function. func (h *CompositeMultiHandler) SetJsonFile(filePath string, options *LogOptions) { writer := &lumberjack.Logger{ Filename: filePath, MaxSize: options.GetIntDefault("maxSizeMB", 1024), // megabytes - MaxAge: options.GetIntDefault("maxAgeDays", 7), //days + MaxAge: options.GetIntDefault("maxAgeDays", 7), // days MaxBackups: options.GetIntDefault("maxBackups", 7), Compress: options.GetBoolDefault("compress", true), } @@ -141,12 +142,12 @@ func (h *CompositeMultiHandler) SetTerminal(writer io.Writer, options *LogOption h.SetHandlers(handler, options) } -// Use built in rolling function +// Use built in rolling function. func (h *CompositeMultiHandler) SetTerminalFile(filePath string, options *LogOptions) { writer := &lumberjack.Logger{ Filename: filePath, MaxSize: options.GetIntDefault("maxSizeMB", 1024), // megabytes - MaxAge: options.GetIntDefault("maxAgeDays", 7), //days + MaxAge: options.GetIntDefault("maxAgeDays", 7), // days MaxBackups: options.GetIntDefault("maxBackups", 7), Compress: options.GetBoolDefault("compress", true), } diff --git a/logger/handlers.go b/logger/handlers.go index dee850ec4..571e303c5 100644 --- a/logger/handlers.go +++ b/logger/handlers.go @@ -11,12 +11,12 @@ type LevelFilterHandler struct { } // Filters out records which do not match the level -// Uses the `log15.FilterHandler` to perform this task +// Uses the `log15.FilterHandler` to perform this task. func LevelHandler(lvl LogLevel, h LogHandler) LogHandler { return &LevelFilterHandler{lvl, h} } -// The implementation of the Log +// The implementation of the Log. func (h LevelFilterHandler) Log(r *Record) error { if r.Level == h.Level { return h.h.Log(r) @@ -25,7 +25,7 @@ func (h LevelFilterHandler) Log(r *Record) error { } // Filters out records which do not match the level -// Uses the `log15.FilterHandler` to perform this task +// Uses the `log15.FilterHandler` to perform this task. func MinLevelHandler(lvl LogLevel, h LogHandler) LogHandler { return FilterHandler(func(r *Record) (pass bool) { return r.Level <= lvl @@ -33,7 +33,7 @@ func MinLevelHandler(lvl LogLevel, h LogHandler) LogHandler { } // Filters out records which match the level -// Uses the `log15.FilterHandler` to perform this task +// Uses the `log15.FilterHandler` to perform this task. func NotLevelHandler(lvl LogLevel, h LogHandler) LogHandler { return FilterHandler(func(r *Record) (pass bool) { return r.Level != lvl @@ -48,13 +48,13 @@ func CallerFileHandler(h LogHandler) LogHandler { } // Adds in a context called `caller` to the record (contains file name and line number like `foo.go:12`) -// Uses the `log15.CallerFuncHandler` to perform this task +// Uses the `log15.CallerFuncHandler` to perform this task. func CallerFuncHandler(h LogHandler) LogHandler { return CallerFuncHandler(h) } // Filters out records which match the key value pair -// Uses the `log15.MatchFilterHandler` to perform this task +// Uses the `log15.MatchFilterHandler` to perform this task. func MatchHandler(key string, value interface{}, h LogHandler) LogHandler { return MatchFilterHandler(key, value, h) } @@ -72,7 +72,7 @@ func MatchFilterHandler(key string, value interface{}, h LogHandler) LogHandler }, h) } -// If match then A handler is called otherwise B handler is called +// If match then A handler is called otherwise B handler is called. func MatchAbHandler(key string, value interface{}, a, b LogHandler) LogHandler { return FuncHandler(func(r *Record) error { if r.Context[key] == value { @@ -85,24 +85,24 @@ func MatchAbHandler(key string, value interface{}, a, b LogHandler) LogHandler { }) } -// The nil handler is used if logging for a specific request needs to be turned off +// The nil handler is used if logging for a specific request needs to be turned off. func NilHandler() LogHandler { return FuncHandler(func(r *Record) error { return nil }) } -// Match all values in map to log +// Match all values in map to log. func MatchMapHandler(matchMap map[string]interface{}, a LogHandler) LogHandler { return matchMapHandler(matchMap, false, a) } -// Match !(Match all values in map to log) The inverse of MatchMapHandler +// Match !(Match all values in map to log) The inverse of MatchMapHandler. func NotMatchMapHandler(matchMap map[string]interface{}, a LogHandler) LogHandler { return matchMapHandler(matchMap, true, a) } -// Rather then chaining multiple filter handlers, process all here +// Rather then chaining multiple filter handlers, process all here. func matchMapHandler(matchMap map[string]interface{}, inverse bool, a LogHandler) LogHandler { return FuncHandler(func(r *Record) error { matchCount := 0 @@ -126,7 +126,7 @@ func matchMapHandler(matchMap map[string]interface{}, inverse bool, a LogHandler } // Filters out records which do not match the key value pair -// Uses the `log15.FilterHandler` to perform this task +// Uses the `log15.FilterHandler` to perform this task. func NotMatchHandler(key string, value interface{}, h LogHandler) LogHandler { return FilterHandler(func(r *Record) (pass bool) { return r.Context[key] != value @@ -158,7 +158,7 @@ func StreamHandler(wr io.Writer, fmtr LogFormat) LogHandler { return LazyHandler(SyncHandler(h)) } -// Filter handler +// Filter handler. func FilterHandler(fn func(r *Record) bool, h LogHandler) LogHandler { return FuncHandler(func(r *Record) error { if fn(r) { @@ -168,18 +168,18 @@ func FilterHandler(fn func(r *Record) bool, h LogHandler) LogHandler { }) } -// List log handler handles a list of LogHandlers +// List log handler handles a list of LogHandlers. type ListLogHandler struct { handlers []LogHandler } -// Create a new list of log handlers +// Create a new list of log handlers. func NewListLogHandler(h1, h2 LogHandler) *ListLogHandler { ll := &ListLogHandler{handlers: []LogHandler{h1, h2}} return ll } -// Log the record +// Log the record. func (ll *ListLogHandler) Log(r *Record) (err error) { for _, handler := range ll.handlers { if err == nil { @@ -191,14 +191,14 @@ func (ll *ListLogHandler) Log(r *Record) (err error) { return } -// Add another log handler +// Add another log handler. func (ll *ListLogHandler) Add(h LogHandler) { if h != nil { ll.handlers = append(ll.handlers, h) } } -// Remove a log handler +// Remove a log handler. func (ll *ListLogHandler) Del(h LogHandler) { if h != nil { for i, handler := range ll.handlers { diff --git a/logger/init.go b/logger/init.go index e654ab46f..702a9a9b1 100644 --- a/logger/init.go +++ b/logger/init.go @@ -1,22 +1,23 @@ package logger -// Get all handlers based on the Config (if available) +// Get all handlers based on the Config (if available). import ( "fmt" - "github.com/revel/config" "log" "os" "path/filepath" "strings" + + "github.com/revel/config" ) func InitializeFromConfig(basePath string, config *config.Context) (c *CompositeMultiHandler) { // If running in test mode suppress anything that is not an error if config != nil && config.BoolDefault(TEST_MODE_FLAG, false) { // Preconfigure all the options - config.SetOption("log.info.output", "none") - config.SetOption("log.debug.output", "none") - config.SetOption("log.warn.output", "none") + config.SetOption("log.info.output", "off") + config.SetOption("log.debug.output", "off") + config.SetOption("log.warn.output", "off") config.SetOption("log.error.output", "stderr") config.SetOption("log.crit.output", "stderr") } @@ -43,7 +44,7 @@ func InitializeFromConfig(basePath string, config *config.Context) (c *Composite return c } -// Init the log.all configuration options +// Init the log.all configuration options. func initAllLog(c *CompositeMultiHandler, basePath string, config *config.Context) { if config != nil { extraLogFlag := config.BoolDefault(SPECIAL_USE_FLAG, false) @@ -61,13 +62,13 @@ func initAllLog(c *CompositeMultiHandler, basePath string, config *config.Contex // log.all.filter .... // log.error.filter .... func initFilterLog(c *CompositeMultiHandler, basePath string, config *config.Context) { - if config != nil { extraLogFlag := config.BoolDefault(SPECIAL_USE_FLAG, false) for _, logFilter := range logFilterList { // Init for all filters - for _, name := range []string{"all", "debug", "info", "warn", "error", "crit", + for _, name := range []string{ + "all", "debug", "info", "warn", "error", "crit", "trace", // TODO trace is deprecated } { optionList := config.Options(logFilter.LogPrefix + name + logFilter.LogSuffix) @@ -94,9 +95,10 @@ func initFilterLog(c *CompositeMultiHandler, basePath string, config *config.Con } } -// Init the log.error, log.warn etc configuration options +// Init the log.error, log.warn etc configuration options. func initLogLevels(c *CompositeMultiHandler, basePath string, config *config.Context) { - for _, name := range []string{"debug", "info", "warn", "error", "crit", + for _, name := range []string{ + "debug", "info", "warn", "error", "crit", "trace", // TODO trace is deprecated } { if config != nil { @@ -115,7 +117,7 @@ func initLogLevels(c *CompositeMultiHandler, basePath string, config *config.Con } } -// Init the request log options +// Init the request log options. func initRequestLog(c *CompositeMultiHandler, basePath string, config *config.Context) { // Request logging to a separate output handler // This takes the InfoHandlers and adds a MatchAbHandler handler to it to direct @@ -143,7 +145,7 @@ func initRequestLog(c *CompositeMultiHandler, basePath string, config *config.Co // Returns a handler for the level using the output string // Accept formats for output string are // LogFunctionMap[value] callback function -// `stdout` `stderr` `full/file/path/to/location/app.log` `full/file/path/to/location/app.json` +// `stdout` `stderr` `full/file/path/to/location/app.log` `full/file/path/to/location/app.json`. func initHandlerFor(c *CompositeMultiHandler, output, basePath string, options *LogOptions) { if options.Ctx != nil { options.SetExtendedOptions( diff --git a/logger/init_test.go b/logger/init_test.go index 50fcd61ce..138a55ab1 100644 --- a/logger/init_test.go +++ b/logger/init_test.go @@ -5,46 +5,57 @@ package logger_test import ( - "github.com/revel/config" - "github.com/revel/revel/logger" - "github.com/stretchr/testify/assert" "os" "strings" "testing" + + "github.com/revel/config" + "github.com/revel/revel/logger" + "github.com/stretchr/testify/assert" ) type ( - // A counter for the tester + // A counter for the tester. testCounter struct { debug, info, warn, error, critical int } - // The data to tes + // The data to tes. testData struct { config []string result testResult tc *testCounter } - // The test result + // The test result. testResult struct { debug, info, warn, error, critical int } ) -// Single test cases +// Single test cases. var singleCases = []testData{ - {config: []string{"log.crit.output"}, - result: testResult{0, 0, 0, 0, 1}}, - {config: []string{"log.error.output"}, - result: testResult{0, 0, 0, 1, 1}}, - {config: []string{"log.warn.output"}, - result: testResult{0, 0, 1, 0, 0}}, - {config: []string{"log.info.output"}, - result: testResult{0, 1, 0, 0, 0}}, - {config: []string{"log.debug.output"}, - result: testResult{1, 0, 0, 0, 0}}, + { + config: []string{"log.crit.output"}, + result: testResult{0, 0, 0, 0, 1}, + }, + { + config: []string{"log.error.output"}, + result: testResult{0, 0, 0, 1, 1}, + }, + { + config: []string{"log.warn.output"}, + result: testResult{0, 0, 1, 0, 0}, + }, + { + config: []string{"log.info.output"}, + result: testResult{0, 1, 0, 0, 0}, + }, + { + config: []string{"log.debug.output"}, + result: testResult{1, 0, 0, 0, 0}, + }, } -// Test singles +// Test singles. func TestSingleCases(t *testing.T) { rootLog := logger.New() for _, testCase := range singleCases { @@ -53,31 +64,51 @@ func TestSingleCases(t *testing.T) { } } -// Filter test cases +// Filter test cases. var filterCases = []testData{ - {config: []string{"log.crit.filter.module.app"}, - result: testResult{0, 0, 0, 0, 1}}, - {config: []string{"log.crit.filter.module.appa"}, - result: testResult{0, 0, 0, 0, 0}}, - {config: []string{"log.error.filter.module.app"}, - result: testResult{0, 0, 0, 1, 1}}, - {config: []string{"log.error.filter.module.appa"}, - result: testResult{0, 0, 0, 0, 0}}, - {config: []string{"log.warn.filter.module.app"}, - result: testResult{0, 0, 1, 0, 0}}, - {config: []string{"log.warn.filter.module.appa"}, - result: testResult{0, 0, 0, 0, 0}}, - {config: []string{"log.info.filter.module.app"}, - result: testResult{0, 1, 0, 0, 0}}, - {config: []string{"log.info.filter.module.appa"}, - result: testResult{0, 0, 0, 0, 0}}, - {config: []string{"log.debug.filter.module.app"}, - result: testResult{1, 0, 0, 0, 0}}, - {config: []string{"log.debug.filter.module.appa"}, - result: testResult{0, 0, 0, 0, 0}}, + { + config: []string{"log.crit.filter.module.app"}, + result: testResult{0, 0, 0, 0, 1}, + }, + { + config: []string{"log.crit.filter.module.appa"}, + result: testResult{0, 0, 0, 0, 0}, + }, + { + config: []string{"log.error.filter.module.app"}, + result: testResult{0, 0, 0, 1, 1}, + }, + { + config: []string{"log.error.filter.module.appa"}, + result: testResult{0, 0, 0, 0, 0}, + }, + { + config: []string{"log.warn.filter.module.app"}, + result: testResult{0, 0, 1, 0, 0}, + }, + { + config: []string{"log.warn.filter.module.appa"}, + result: testResult{0, 0, 0, 0, 0}, + }, + { + config: []string{"log.info.filter.module.app"}, + result: testResult{0, 1, 0, 0, 0}, + }, + { + config: []string{"log.info.filter.module.appa"}, + result: testResult{0, 0, 0, 0, 0}, + }, + { + config: []string{"log.debug.filter.module.app"}, + result: testResult{1, 0, 0, 0, 0}, + }, + { + config: []string{"log.debug.filter.module.appa"}, + result: testResult{0, 0, 0, 0, 0}, + }, } -// Filter test +// Filter test. func TestFilterCases(t *testing.T) { rootLog := logger.New("module", "app") for _, testCase := range filterCases { @@ -86,33 +117,55 @@ func TestFilterCases(t *testing.T) { } } -// Inverse test cases +// Inverse test cases. var nfilterCases = []testData{ - {config: []string{"log.crit.nfilter.module.appa"}, - result: testResult{0, 0, 0, 0, 1}}, - {config: []string{"log.crit.nfilter.modules.appa"}, - result: testResult{0, 0, 0, 0, 0}}, - {config: []string{"log.crit.nfilter.module.app"}, - result: testResult{0, 0, 0, 0, 0}}, - {config: []string{"log.error.nfilter.module.appa"}, // Special case, when error is not nill critical inherits from error - result: testResult{0, 0, 0, 1, 1}}, - {config: []string{"log.error.nfilter.module.app"}, - result: testResult{0, 0, 0, 0, 0}}, - {config: []string{"log.warn.nfilter.module.appa"}, - result: testResult{0, 0, 1, 0, 0}}, - {config: []string{"log.warn.nfilter.module.app"}, - result: testResult{0, 0, 0, 0, 0}}, - {config: []string{"log.info.nfilter.module.appa"}, - result: testResult{0, 1, 0, 0, 0}}, - {config: []string{"log.info.nfilter.module.app"}, - result: testResult{0, 0, 0, 0, 0}}, - {config: []string{"log.debug.nfilter.module.appa"}, - result: testResult{1, 0, 0, 0, 0}}, - {config: []string{"log.debug.nfilter.module.app"}, - result: testResult{0, 0, 0, 0, 0}}, + { + config: []string{"log.crit.nfilter.module.appa"}, + result: testResult{0, 0, 0, 0, 1}, + }, + { + config: []string{"log.crit.nfilter.modules.appa"}, + result: testResult{0, 0, 0, 0, 0}, + }, + { + config: []string{"log.crit.nfilter.module.app"}, + result: testResult{0, 0, 0, 0, 0}, + }, + { + config: []string{"log.error.nfilter.module.appa"}, // Special case, when error is not nill critical inherits from error + result: testResult{0, 0, 0, 1, 1}, + }, + { + config: []string{"log.error.nfilter.module.app"}, + result: testResult{0, 0, 0, 0, 0}, + }, + { + config: []string{"log.warn.nfilter.module.appa"}, + result: testResult{0, 0, 1, 0, 0}, + }, + { + config: []string{"log.warn.nfilter.module.app"}, + result: testResult{0, 0, 0, 0, 0}, + }, + { + config: []string{"log.info.nfilter.module.appa"}, + result: testResult{0, 1, 0, 0, 0}, + }, + { + config: []string{"log.info.nfilter.module.app"}, + result: testResult{0, 0, 0, 0, 0}, + }, + { + config: []string{"log.debug.nfilter.module.appa"}, + result: testResult{1, 0, 0, 0, 0}, + }, + { + config: []string{"log.debug.nfilter.module.app"}, + result: testResult{0, 0, 0, 0, 0}, + }, } -// Inverse test +// Inverse test. func TestNotFilterCases(t *testing.T) { rootLog := logger.New("module", "app") for _, testCase := range nfilterCases { @@ -121,13 +174,15 @@ func TestNotFilterCases(t *testing.T) { } } -// off test cases +// off test cases. var offCases = []testData{ - {config: []string{"log.all.output", "log.error.output=off"}, - result: testResult{1, 1, 1, 0, 1}}, + { + config: []string{"log.all.output", "log.error.output=off"}, + result: testResult{1, 1, 1, 0, 1}, + }, } -// Off test +// Off test. func TestOffCases(t *testing.T) { rootLog := logger.New("module", "app") for _, testCase := range offCases { @@ -136,13 +191,15 @@ func TestOffCases(t *testing.T) { } } -// Duplicate test cases +// Duplicate test cases. var duplicateCases = []testData{ - {config: []string{"log.all.output", "log.error.output", "log.error.filter.module.app"}, - result: testResult{1, 1, 1, 2, 1}}, + { + config: []string{"log.all.output", "log.error.output", "log.error.filter.module.app"}, + result: testResult{1, 1, 1, 2, 1}, + }, } -// test duplicate cases +// test duplicate cases. func TestDuplicateCases(t *testing.T) { rootLog := logger.New("module", "app") for _, testCase := range duplicateCases { @@ -151,19 +208,27 @@ func TestDuplicateCases(t *testing.T) { } } -// Contradicting cases +// Contradicting cases. var contradictCases = []testData{ - {config: []string{"log.all.output", "log.error.output=off", "log.all.output"}, - result: testResult{1, 1, 1, 0, 1}}, - {config: []string{"log.all.output", "log.error.output=off", "log.debug.filter.module.app"}, - result: testResult{2, 1, 1, 0, 1}}, - {config: []string{"log.all.filter.module.app", "log.info.output=off", "log.info.filter.module.app"}, - result: testResult{1, 2, 1, 1, 1}}, - {config: []string{"log.all.output", "log.info.output=off", "log.info.filter.module.app"}, - result: testResult{1, 1, 1, 1, 1}}, + { + config: []string{"log.all.output", "log.error.output=off", "log.all.output"}, + result: testResult{1, 1, 1, 0, 1}, + }, + { + config: []string{"log.all.output", "log.error.output=off", "log.debug.filter.module.app"}, + result: testResult{2, 1, 1, 0, 1}, + }, + { + config: []string{"log.all.filter.module.app", "log.info.output=off", "log.info.filter.module.app"}, + result: testResult{1, 2, 1, 1, 1}, + }, + { + config: []string{"log.all.output", "log.info.output=off", "log.info.filter.module.app"}, + result: testResult{1, 1, 1, 1, 1}, + }, } -// Contradiction test +// Contradiction test. func TestContradictCases(t *testing.T) { rootLog := logger.New("module", "app") for _, testCase := range contradictCases { @@ -172,15 +237,19 @@ func TestContradictCases(t *testing.T) { } } -// All test cases +// All test cases. var allCases = []testData{ - {config: []string{"log.all.filter.module.app"}, - result: testResult{1, 1, 1, 1, 1}}, - {config: []string{"log.all.output"}, - result: testResult{2, 2, 2, 2, 2}}, + { + config: []string{"log.all.filter.module.app"}, + result: testResult{1, 1, 1, 1, 1}, + }, + { + config: []string{"log.all.output"}, + result: testResult{2, 2, 2, 2, 2}, + }, } -// All tests +// All tests. func TestAllCases(t *testing.T) { rootLog := logger.New("module", "app") for i, testCase := range allCases { @@ -195,7 +264,6 @@ func TestAllCases(t *testing.T) { for _, testCase := range allCases { testCase.validate(t) } - } func (c *testCounter) Log(r *logger.Record) error { @@ -215,7 +283,9 @@ func (c *testCounter) Log(r *logger.Record) error { } return nil } + func (td *testData) logTest(rootLog logger.MultiLogger, t *testing.T) { + t.Helper() if td.tc == nil { td.tc = &testCounter{} counterInit(td.tc) @@ -256,7 +326,7 @@ func (td *testData) validate(t *testing.T) { assert.Equal(t, td.result.critical, td.tc.critical, "Critical failed "+strings.Join(td.config, " ")) } -// Add test to the function map +// Add test to the function map. func counterInit(tc *testCounter) { logger.LogFunctionMap["test"] = func(c *logger.CompositeMultiHandler, logOptions *logger.LogOptions) { // Output to the test log and the stdout diff --git a/logger/log_function_map.go b/logger/log_function_map.go index ebbc76dfe..2ab2379fd 100644 --- a/logger/log_function_map.go +++ b/logger/log_function_map.go @@ -5,7 +5,7 @@ import ( ) // The log function map can be added to, so that you can specify your own logging mechanism -// it has defaults for off, stdout, stderr +// it has defaults for off, stdout, stderr. var LogFunctionMap = map[string]func(*CompositeMultiHandler, *LogOptions){ // Do nothing - set the logger off "off": func(c *CompositeMultiHandler, logOptions *LogOptions) { diff --git a/logger/logger.go b/logger/logger.go index b9abdaff9..ef46a7944 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -2,14 +2,15 @@ package logger import ( "fmt" - "github.com/revel/config" "time" + + "github.com/revel/config" ) -// The LogHandler defines the interface to handle the log records +// The LogHandler defines the interface to handle the log records. type ( // The Multilogger reduces the number of exposed defined logging variables, - // and allows the output to be easily refined + // and allows the output to be easily refined. MultiLogger interface { // New returns a new Logger that has this logger's context plus the given context New(ctx ...interface{}) MultiLogger @@ -63,32 +64,32 @@ type ( Panicf(msg string, params ...interface{}) } - // The log handler interface + // The log handler interface. LogHandler interface { Log(*Record) error - //log15.Handler + // log15.Handler } - // The log stack handler interface + // The log stack handler interface. LogStackHandler interface { LogHandler GetStack() int } - // The log handler interface which has child logs + // The log handler interface which has child logs. ParentLogHandler interface { SetChild(handler LogHandler) LogHandler } - // The log format interface + // The log format interface. LogFormat interface { Format(r *Record) []byte } - // The log level type + // The log level type. LogLevel int - // Used for the callback to LogFunctionMap + // Used for the callback to LogFunctionMap. LogOptions struct { Ctx *config.Context ReplaceExistingHandler bool @@ -97,22 +98,22 @@ type ( ExtendedOptions map[string]interface{} } - // The log record + // The log record. Record struct { Message string // The message Time time.Time // The time - Level LogLevel //The level + Level LogLevel // The level Call CallStack // The call stack if built Context ContextMap // The context } - // The lazy structure to implement a function to be invoked only if needed + // The lazy structure to implement a function to be invoked only if needed. Lazy struct { Fn interface{} // the function } // Currently the only requirement for the callstack is to support the Formatter method - // which stack.Call does so we use that + // which stack.Call does so we use that. CallStack interface { fmt.Formatter // Requirement } @@ -129,6 +130,7 @@ type formatFunc func(*Record) []byte func (f formatFunc) Format(r *Record) []byte { return f(r) } + func NewRecord(message string, level LogLevel) *Record { return &Record{Message: message, Context: ContextMap{}, Level: level} } @@ -141,28 +143,28 @@ const ( LvlDebug // Debug ) -// A list of all the log levels +// A list of all the log levels. var LvlAllList = []LogLevel{LvlDebug, LvlInfo, LvlWarn, LvlError, LvlCrit} -// Implements the ParentLogHandler +// Implements the ParentLogHandler. type parentLogHandler struct { setChild func(handler LogHandler) LogHandler } -// Create a new parent log handler +// Create a new parent log handler. func NewParentLogHandler(callBack func(child LogHandler) LogHandler) ParentLogHandler { return &parentLogHandler{callBack} } -// Sets the child of the log handler +// Sets the child of the log handler. func (p *parentLogHandler) SetChild(child LogHandler) LogHandler { return p.setChild(child) } -// Create a new log options +// Create a new log options. func NewLogOptions(cfg *config.Context, replaceHandler bool, phandler ParentLogHandler, lvl ...LogLevel) (logOptions *LogOptions) { logOptions = &LogOptions{ - Ctx: cfg, + Ctx: cfg, ReplaceExistingHandler: replaceHandler, HandlerWrap: phandler, Levels: lvl, @@ -171,14 +173,14 @@ func NewLogOptions(cfg *config.Context, replaceHandler bool, phandler ParentLogH return } -// Assumes options will be an even number and have a string, value syntax +// Assumes options will be an even number and have a string, value syntax. func (l *LogOptions) SetExtendedOptions(options ...interface{}) { for x := 0; x < len(options); x += 2 { l.ExtendedOptions[options[x].(string)] = options[x+1] } } -// Gets a string option with default +// Gets a string option with default. func (l *LogOptions) GetStringDefault(option, value string) string { if v, found := l.ExtendedOptions[option]; found { return v.(string) @@ -186,7 +188,7 @@ func (l *LogOptions) GetStringDefault(option, value string) string { return value } -// Gets an int option with default +// Gets an int option with default. func (l *LogOptions) GetIntDefault(option string, value int) int { if v, found := l.ExtendedOptions[option]; found { return v.(int) @@ -194,7 +196,7 @@ func (l *LogOptions) GetIntDefault(option string, value int) int { return value } -// Gets a boolean option with default +// Gets a boolean option with default. func (l *LogOptions) GetBoolDefault(option string, value bool) bool { if v, found := l.ExtendedOptions[option]; found { return v.(bool) diff --git a/logger/revel_logger.go b/logger/revel_logger.go index dcd9026c3..38bac26b9 100644 --- a/logger/revel_logger.go +++ b/logger/revel_logger.go @@ -2,18 +2,19 @@ package logger import ( "fmt" - "github.com/revel/log15" "log" "os" + + "github.com/revel/log15" ) -// This type implements the MultiLogger +// This type implements the MultiLogger. type RevelLogger struct { log15.Logger } // Set the systems default logger -// Default logs will be captured and handled by revel at level info +// Default logs will be captured and handled by revel at level info. func SetDefaultLog(fromLog MultiLogger) { log.SetOutput(loggerRewrite{Logger: fromLog, Level: log15.LvlInfo, hideDeprecated: true}) // No need to show date and time, that will be logged with revel @@ -24,73 +25,73 @@ func (rl *RevelLogger) Debugf(msg string, param ...interface{}) { rl.Debug(fmt.Sprintf(msg, param...)) } -// Print a formatted info message +// Print a formatted info message. func (rl *RevelLogger) Infof(msg string, param ...interface{}) { rl.Info(fmt.Sprintf(msg, param...)) } -// Print a formatted warn message +// Print a formatted warn message. func (rl *RevelLogger) Warnf(msg string, param ...interface{}) { rl.Warn(fmt.Sprintf(msg, param...)) } -// Print a formatted error message +// Print a formatted error message. func (rl *RevelLogger) Errorf(msg string, param ...interface{}) { rl.Error(fmt.Sprintf(msg, param...)) } -// Print a formatted critical message +// Print a formatted critical message. func (rl *RevelLogger) Critf(msg string, param ...interface{}) { rl.Crit(fmt.Sprintf(msg, param...)) } -// Print a formatted fatal message +// Print a formatted fatal message. func (rl *RevelLogger) Fatalf(msg string, param ...interface{}) { rl.Fatal(fmt.Sprintf(msg, param...)) } -// Print a formatted panic message +// Print a formatted panic message. func (rl *RevelLogger) Panicf(msg string, param ...interface{}) { rl.Panic(fmt.Sprintf(msg, param...)) } -// Print a critical message and call os.Exit(1) +// Print a critical message and call os.Exit(1). func (rl *RevelLogger) Fatal(msg string, ctx ...interface{}) { rl.Crit(msg, ctx...) os.Exit(1) } -// Print a critical message and panic +// Print a critical message and panic. func (rl *RevelLogger) Panic(msg string, ctx ...interface{}) { rl.Crit(msg, ctx...) panic(msg) } -// Override log15 method +// Override log15 method. func (rl *RevelLogger) New(ctx ...interface{}) MultiLogger { old := &RevelLogger{Logger: rl.Logger.New(ctx...)} return old } -// Set the stack level to check for the caller +// Set the stack level to check for the caller. func (rl *RevelLogger) SetStackDepth(amount int) MultiLogger { rl.Logger.SetStackDepth(amount) // Ignore the logger returned return rl } -// Create a new logger +// Create a new logger. func New(ctx ...interface{}) MultiLogger { r := &RevelLogger{Logger: log15.New(ctx...)} - //r.SetStackDepth(2) + // r.SetStackDepth(2) return r } -// Set the handler in the Logger +// Set the handler in the Logger. func (rl *RevelLogger) SetHandler(h LogHandler) { rl.Logger.SetHandler(callHandler(h.Log)) } -// The function wrapper to implement the callback +// The function wrapper to implement the callback. type callHandler func(r *Record) error // Log implementation, reads the record and extracts the details from the log record @@ -122,10 +123,10 @@ func (c callHandler) Log(log *log15.Record) error { return c(r) } -// Internally used contextMap, allows conversion of map to map[string]string +// Internally used contextMap, allows conversion of map to map[string]string. type ContextMap map[string]interface{} -// Convert the context map to be string only values, any non string values are ignored +// Convert the context map to be string only values, any non string values are ignored. func (m ContextMap) StringMap() (newMap map[string]string) { if m != nil { newMap = map[string]string{} @@ -137,6 +138,7 @@ func (m ContextMap) StringMap() (newMap map[string]string) { } return } + func (m ContextMap) Add(key string, value interface{}) { m[key] = value } diff --git a/logger/terminal_format.go b/logger/terminal_format.go index ca2cd1511..98cf16710 100644 --- a/logger/terminal_format.go +++ b/logger/terminal_format.go @@ -18,13 +18,13 @@ const ( errorKey = "REVEL_ERROR" ) -var ( - levelString = map[LogLevel]string{LvlDebug: "DEBUG", - LvlInfo: "INFO", LvlWarn: "WARN", LvlError: "ERROR", LvlCrit: "CRIT"} -) +var levelString = map[LogLevel]string{ + LvlDebug: "DEBUG", + LvlInfo: "INFO", LvlWarn: "WARN", LvlError: "ERROR", LvlCrit: "CRIT", +} // Outputs to the terminal in a format like below -// INFO 09:11:32 server-engine.go:169: Request Stats +// INFO 09:11:32 server-engine.go:169: Request Stats. func TerminalFormatHandler(noColor bool, smallDate bool) LogFormat { dateFormat := termTimeFormat if smallDate { @@ -32,7 +32,7 @@ func TerminalFormatHandler(noColor bool, smallDate bool) LogFormat { } return FormatFunc(func(r *Record) []byte { // Bash coloring http://misc.flogisoft.com/bash/tip_colors_and_formatting - var color = 0 + color := 0 switch r.Level { case LvlCrit: // Magenta @@ -92,7 +92,7 @@ func TerminalFormatHandler(noColor bool, smallDate bool) LogFormat { }) } -// formatValue formats a value for serialization +// formatValue formats a value for serialization. func formatLogfmtValue(value interface{}) string { if value == nil { return "nil" @@ -121,7 +121,7 @@ func formatLogfmtValue(value interface{}) string { } } -// Format the value in json format +// Format the value in json format. func formatShared(value interface{}) (result interface{}) { defer func() { if err := recover(); err != nil { @@ -148,12 +148,12 @@ func formatShared(value interface{}) (result interface{}) { } } -// A reusuable buffer for outputting data +// A reusuable buffer for outputting data. var stringBufPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) }, } -// Escape the string when needed +// Escape the string when needed. func escapeString(s string) string { needsQuotes := false needsEscape := false diff --git a/logger/utils.go b/logger/utils.go index 3918cc1d9..e8c138d11 100644 --- a/logger/utils.go +++ b/logger/utils.go @@ -1,29 +1,31 @@ package logger import ( + "log" + "github.com/revel/log15" "gopkg.in/stack.v0" - "log" ) -// Utility package to make existing logging backwards compatible +// Utility package to make existing logging backwards compatible. var ( - // Convert the string to LogLevel - toLevel = map[string]LogLevel{"debug": LogLevel(log15.LvlDebug), - "info": LogLevel(log15.LvlInfo), "request": LogLevel(log15.LvlInfo), "warn": LogLevel(log15.LvlWarn), + // Convert the string to LogLevel. + toLevel = map[string]LogLevel{ + "debug": LogLevel(log15.LvlDebug), + "info": LogLevel(log15.LvlInfo), "request": LogLevel(log15.LvlInfo), "warn": LogLevel(log15.LvlWarn), "error": LogLevel(log15.LvlError), "crit": LogLevel(log15.LvlCrit), "trace": LogLevel(log15.LvlDebug), // TODO trace is deprecated, replaced by debug } ) const ( - // The test mode flag overrides the default log level and shows only errors + // The test mode flag overrides the default log level and shows only errors. TEST_MODE_FLAG = "testModeFlag" - // The special use flag enables showing messages when the logger is setup + // The special use flag enables showing messages when the logger is setup. SPECIAL_USE_FLAG = "specialUseFlag" ) -// Returns the logger for the name +// Returns the logger for the name. func GetLogger(name string, logger MultiLogger) (l *log.Logger) { switch name { case "trace": // TODO trace is deprecated, replaced by debug @@ -41,10 +43,9 @@ func GetLogger(name string, logger MultiLogger) (l *log.Logger) { } return l - } -// Used by the initFilterLog to handle the filters +// Used by the initFilterLog to handle the filters. var logFilterList = []struct { LogPrefix, LogSuffix string parentHandler func(map[string]interface{}) ParentLogHandler @@ -54,7 +55,6 @@ var logFilterList = []struct { return NewParentLogHandler(func(child LogHandler) LogHandler { return MatchMapHandler(keyMap, child) }) - }, }, { "log.", ".nfilter", @@ -65,17 +65,17 @@ var logFilterList = []struct { }, }} -// This structure and method will handle the old output format and log it to the new format +// This structure and method will handle the old output format and log it to the new format. type loggerRewrite struct { Logger MultiLogger Level log15.Lvl hideDeprecated bool } -// The message indicating that a logger is using a deprecated log mechanism +// The message indicating that a logger is using a deprecated log mechanism. var log_deprecated = []byte("* LOG DEPRECATED * ") -// Implements the Write of the logger +// Implements the Write of the logger. func (lr loggerRewrite) Write(p []byte) (n int, err error) { if !lr.hideDeprecated { p = append(log_deprecated, p...) @@ -104,7 +104,7 @@ func (lr loggerRewrite) Write(p []byte) (n int, err error) { // For logging purposes the call stack can be used to record the stack trace of a bad error // simply pass it as a context field in your log statement like -// `controller.Log.Crit("This should not occur","stack",revel.NewCallStack())` +// `controller.Log.Crit("This should not occur","stack",revel.NewCallStack())`. func NewCallStack() interface{} { return stack.Trace() } diff --git a/logger/wrap_handlers.go b/logger/wrap_handlers.go index 3d68e750a..8e836f8e5 100644 --- a/logger/wrap_handlers.go +++ b/logger/wrap_handlers.go @@ -9,29 +9,29 @@ import ( "time" ) -// Function handler wraps the declared function and returns the handler for it +// Function handler wraps the declared function and returns the handler for it. func FuncHandler(fn func(r *Record) error) LogHandler { return funcHandler(fn) } -// The type decleration for the function +// The type declaration for the function. type funcHandler func(r *Record) error -// The implementation of the Log +// The implementation of the Log. func (h funcHandler) Log(r *Record) error { return h(r) } // This function allows you to do a full declaration for the log, -// it is recommended you use FuncHandler instead +// it is recommended you use FuncHandler instead. func HandlerFunc(log func(message string, time time.Time, level LogLevel, call CallStack, context ContextMap) error) LogHandler { return remoteHandler(log) } -// The type used for the HandlerFunc +// The type used for the HandlerFunc. type remoteHandler func(message string, time time.Time, level LogLevel, call CallStack, context ContextMap) error -// The Log implementation +// The Log implementation. func (c remoteHandler) Log(record *Record) error { return c(record.Message, record.Time, record.Level, record.Call, record.Context) } @@ -56,11 +56,9 @@ func LazyHandler(h LogHandler) LogHandler { return FuncHandler(func(r *Record) error { for k, v := range r.Context { if lz, ok := v.(Lazy); ok { - value, err := evaluateLazy(lz) + _, err := evaluateLazy(lz) if err != nil { r.Context[errorKey] = "bad lazy " + k - } else { - v = value } } } diff --git a/model/revel_container.go b/model/revel_container.go index 70465e260..a0c1e3b80 100644 --- a/model/revel_container.go +++ b/model/revel_container.go @@ -1,10 +1,9 @@ package model - -// The single instance object that has the config populated to it +// The single instance object that has the config populated to it. type ( RevelContainer struct { Controller RevelController - Paths RevelPaths -} -) \ No newline at end of file + Paths RevelPaths + } +) diff --git a/model/revel_controller.go b/model/revel_controller.go index 8cba10108..e3dcc4354 100644 --- a/model/revel_controller.go +++ b/model/revel_controller.go @@ -2,11 +2,10 @@ package model import "github.com/revel/revel/utils" -type RevelController struct { +type RevelController struct { Reuse bool // True if the controllers are reused Set via revel.controller.reuse Stack *utils.SimpleLockStack // size set by revel.controller.stack, revel.controller.maxstack CachedMap map[string]*utils.SimpleLockStack // The map of reusable controllers CachedStackSize int // The default size of each stack in CachedMap Set via revel.cache.controller.stack CachedStackMaxSize int // The max size of each stack in CachedMap Set via revel.cache.controller.maxstack } - diff --git a/model/revel_paths.go b/model/revel_paths.go index f2bd0518e..aea94c9fa 100644 --- a/model/revel_paths.go +++ b/model/revel_paths.go @@ -1,6 +1,6 @@ package model -type RevelPaths struct { +type RevelPaths struct { Import string Source string Base string diff --git a/model/revel_unit.go b/model/revel_unit.go index 5df0c65d0..5c7e22abb 100644 --- a/model/revel_unit.go +++ b/model/revel_unit.go @@ -18,5 +18,4 @@ type ( } RevelUnitList []*RevelUnit RevelUnitType int - ) diff --git a/module.go b/module.go index df320debd..8ed9d30b7 100644 --- a/module.go +++ b/module.go @@ -10,7 +10,7 @@ import ( "github.com/revel/revel/logger" ) -// Module specific functions +// Module specific functions. type Module struct { Name, ImportPath, Path string ControllerTypeList []*ControllerType @@ -21,7 +21,7 @@ type Module struct { // Modules can be called back after they are loaded in revel by using this interface. type ModuleCallbackInterface func(*Module) -// The namespace separator constant +// The namespace separator constant. const namespaceSeperator = `\` // (note cannot be . or : as this is already used for routes) var ( @@ -32,7 +32,7 @@ var ( ) // Called by a module init() function, caller will receive the *Module object created for that module -// This would be useful for assigning a logger for logging information in the module (since the module context would be correct) +// This would be useful for assigning a logger for logging information in the module (since the module context would be correct). func RegisterModuleInit(callback ModuleCallbackInterface) { // Store the module that called this so we can do a callback when the app is initialized // The format %+k is from go-stack/Call.Format and returns the package path @@ -44,7 +44,7 @@ func RegisterModuleInit(callback ModuleCallbackInterface) { } } -// Called on startup to make a callback so that modules can be initialized through the `RegisterModuleInit` function +// Called on startup to make a callback so that modules can be initialized through the `RegisterModuleInit` function. func init() { AddInitEventHandler(func(typeOf Event, value interface{}) (responseOf EventResponse) { if typeOf == REVEL_BEFORE_MODULES_LOADED { @@ -57,13 +57,13 @@ func init() { }) } -// Returns the namespace for the module in the format `module_name|` +// Returns the namespace for the module in the format `module_name|`. func (m *Module) Namespace() (namespace string) { namespace = m.Name + namespaceSeperator return } -// Returns the named controller and action that is in this module +// Returns the named controller and action that is in this module. func (m *Module) ControllerByName(name, action string) (ctype *ControllerType) { comparison := name if strings.Index(name, namespaceSeperator) < 0 { @@ -78,13 +78,13 @@ func (m *Module) ControllerByName(name, action string) (ctype *ControllerType) { return } -// Adds the controller type to this module +// Adds the controller type to this module. func (m *Module) AddController(ct *ControllerType) { m.ControllerTypeList = append(m.ControllerTypeList, ct) } // Based on the full path given return the relevant module -// Only to be used on initialization +// Only to be used on initialization. func ModuleFromPath(packagePath string, addGopathToPath bool) (module *Module) { packagePath = filepath.ToSlash(packagePath) // The module paths will match the configuration module paths, so we will use those to determine them @@ -92,7 +92,7 @@ func ModuleFromPath(packagePath string, addGopathToPath bool) (module *Module) { // See if the path exists in the module based for i := range Modules { - if strings.Index(packagePath, Modules[i].ImportPath)==0 { + if strings.Index(packagePath, Modules[i].ImportPath) == 0 { // This is a prefix, so the module is this module module = Modules[i] break @@ -126,7 +126,7 @@ func ModuleByName(name string) (*Module, bool) { return nil, false } -// Loads the modules specified in the config +// Loads the modules specified in the config. func loadModules() { keys := []string{} for _, key := range Config.Options("module.") { @@ -137,7 +137,6 @@ func loadModules() { sort.Strings(keys) for _, key := range keys { moduleLog.Debug("Sorted keys", "keys", key) - } for _, key := range keys { moduleImportPath := Config.StringDefault(key, "") @@ -168,15 +167,17 @@ func loadModules() { } } -// called by `loadModules`, creates a new `Module` instance and appends it to the `Modules` list +// called by `loadModules`, creates a new `Module` instance and appends it to the `Modules` list. func addModule(name, importPath, modulePath string) { if _, found := ModuleByName(name); found { moduleLog.Panic("Attempt to import duplicate module %s path %s aborting startup", "name", name, "path", modulePath) } - Modules = append(Modules, &Module{Name: name, + Modules = append(Modules, &Module{ + Name: name, ImportPath: filepath.ToSlash(importPath), Path: filepath.ToSlash(modulePath), - Log: RootLog.New("module", name)}) + Log: RootLog.New("module", name), + }) if codePath := filepath.Join(modulePath, "app"); DirExists(codePath) { CodePaths = append(CodePaths, codePath) if viewsPath := filepath.Join(modulePath, "app", "views"); DirExists(viewsPath) { diff --git a/namespace.go b/namespace.go index 9f66cf4c9..638aa3ccb 100644 --- a/namespace.go +++ b/namespace.go @@ -7,11 +7,11 @@ import ( // Module matching template syntax allows for modules to replace this text with the name of the module declared on import // this allows the reverse router to use correct syntax -// Match _LOCAL_.static or _LOCAL_| +// Match _LOCAL_.static or _LOCAL_|. var namespaceReplacement = regexp.MustCompile(`(_LOCAL_)(\.(.*?))?\\`) // Function to replace the bytes data that may match the _LOCAL_ namespace specifier, -// the replacement will be the current module.Name +// the replacement will be the current module.Name. func namespaceReplace(fileBytes []byte, module *Module) []byte { newBytes, lastIndex := &bytes.Buffer{}, 0 matches := namespaceReplacement.FindAllSubmatchIndex(fileBytes, -1) diff --git a/none b/none deleted file mode 100644 index f8275e8a9..000000000 --- a/none +++ /dev/null @@ -1 +0,0 @@ -INFO 2020/07/11 22:52:29 revel revel.go:124: Paths app=/tmp/release/v1.0.0/go/src/github.com/revel/revel/testdata/app views=/tmp/release/v1.0.0/go/src/github.com/revel/revel/testdata/app/views revel=/tmp/release/v1.0.0/go/src/github.com/revel/revel base=/tmp/release/v1.0.0/go/src/github.com/revel/revel/testdata diff --git a/params.go b/params.go index 3df3dde55..ef90db5f0 100644 --- a/params.go +++ b/params.go @@ -39,7 +39,7 @@ type Params struct { var paramsLogger = RevelLog.New("section", "params") -// ParseParams parses the `http.Request` params into `revel.Controller.Params` +// ParseParams parses the `http.Request` params into `revel.Controller.Params`. func ParseParams(params *Params, req *Request) { params.Query = req.GetQuery() diff --git a/results.go b/results.go index 24ddfaf96..4deb19801 100644 --- a/results.go +++ b/results.go @@ -116,7 +116,6 @@ func (r ErrorResult) Apply(req *Request, resp *Response) { resultsLog.Error("Apply: Response WriteTo failed:", "error", err) } } - } type PlaintextErrorResult struct { @@ -151,7 +150,7 @@ func (r *RenderTemplateResult) Apply(req *Request, resp *Response) { chunked := Config.BoolDefault("results.chunked", false) // If it's a HEAD request, throw away the bytes. - out := io.Writer(resp.GetWriter()) + out := resp.GetWriter() if req.Method == "HEAD" { out = ioutil.Discard } @@ -186,7 +185,7 @@ func (r *RenderTemplateResult) Apply(req *Request, resp *Response) { } } -// Return a byte array and or an error object if the template failed to render +// Return a byte array and or an error object if the template failed to render. func (r *RenderTemplateResult) ToBytes() (b *bytes.Buffer, err error) { defer func() { if rerr := recover(); rerr != nil { @@ -203,7 +202,7 @@ func (r *RenderTemplateResult) ToBytes() (b *bytes.Buffer, err error) { return } -// Output the template to the writer, catch any panics and return as an error +// Output the template to the writer, catch any panics and return as an error. func (r *RenderTemplateResult) renderOutput(wr io.Writer) (err error) { defer func() { if rerr := recover(); rerr != nil { @@ -223,7 +222,6 @@ func (r *RenderTemplateResult) renderOutput(wr io.Writer) (err error) { // This is safe unless white-space: pre; is used in css for formatting. // Since there is no way to detect that, you will have to keep trimming off in these cases. func (r *RenderTemplateResult) compressHtml(b *bytes.Buffer) (b2 *bytes.Buffer) { - // Allocate length of original buffer, so we can write everything without allocating again b2.Grow(b.Len()) insidePre := false @@ -263,7 +261,7 @@ func (r *RenderTemplateResult) compressHtml(b *bytes.Buffer) (b2 *bytes.Buffer) return } -// Render the error in the response +// Render the error in the response. func (r *RenderTemplateResult) renderError(err error, req *Request, resp *Response) { compileError, found := err.(*Error) if !found { @@ -273,13 +271,12 @@ func (r *RenderTemplateResult) renderError(err error, req *Request, resp *Respon templateLog.Info("Cannot determine template name to render error", "error", err) templateName = r.Template.Name() templateContent = r.Template.Content() - } else { lang, _ := r.ViewArgs[CurrentLocaleViewArg].(string) if tmpl, err := MainTemplateLoader.TemplateLang(templateName, lang); err == nil { templateContent = tmpl.Content() } else { - templateLog.Info("Unable to retreive template ", "error", err) + templateLog.Info("Unable to retrieve template ", "error", err) } } compileError = &Error{ @@ -413,7 +410,7 @@ func (r *BinaryResult) Apply(req *Request, resp *Response) { if content, ok := r.Reader.(io.ReadSeeker); ok && r.Length < 0 { // get the size from the stream // go1.6 compatibility change, go1.6 does not define constants io.SeekStart - //if size, err := content.Seek(0, io.SeekEnd); err == nil { + // if size, err := content.Seek(0, io.SeekEnd); err == nil { // if _, err = content.Seek(0, io.SeekStart); err == nil { if size, err := content.Seek(0, 2); err == nil { if _, err = content.Seek(0, 0); err == nil { diff --git a/results_test.go b/results_test.go index ce375d1cd..ba7f0bd7a 100644 --- a/results_test.go +++ b/results_test.go @@ -11,7 +11,7 @@ import ( "testing" ) -// Added test case for redirection testing for strings +// Added test case for redirection testing for strings. func TestRedirect(t *testing.T) { startFakeBookingApp() redirect := RedirectToURLResult{fmt.Sprintf("/hotels/index/foo")} diff --git a/revel.go b/revel.go index b72df7c26..d328fec99 100644 --- a/revel.go +++ b/revel.go @@ -5,20 +5,20 @@ package revel import ( + "encoding/json" + "fmt" "go/build" "net/http" "path/filepath" "strings" - "encoding/json" - "fmt" "github.com/revel/config" "github.com/revel/revel/logger" "github.com/revel/revel/model" ) const ( - // RevelImportPath Revel framework import path + // RevelImportPath Revel framework import path. RevelImportPath = "github.com/revel/revel" ) @@ -27,22 +27,22 @@ const ( SPECIAL_USE_FLAG = "specialUseFlag" ) -// App details +// App details. var ( RevelConfig *model.RevelContainer - AppName string // e.g. "sample" - AppRoot string // e.g. "/app1" - BasePath string // e.g. "$GOPATH/src/corp/sample" - AppPath string // e.g. "$GOPATH/src/corp/sample/app" - ViewsPath string // e.g. "$GOPATH/src/corp/sample/app/views" - ImportPath string // e.g. "corp/sample" - SourcePath string // e.g. "$GOPATH/src" + AppName string // e.g. "sample" + AppRoot string // e.g. "/app1" + BasePath string // e.g. "$GOPATH/src/corp/sample" + AppPath string // e.g. "$GOPATH/src/corp/sample/app" + ViewsPath string // e.g. "$GOPATH/src/corp/sample/app/views" + ImportPath string // e.g. "corp/sample" + SourcePath string // e.g. "$GOPATH/src" Config *config.Context RunMode string // Application-defined (by default, "dev" or "prod") DevMode bool // if true, RunMode is a development mode. - // Revel installation details + // Revel installation details. RevelPath string // e.g. "$GOPATH/src/github.com/revel/revel" // Where to look for templates @@ -54,7 +54,7 @@ var ( // Config load order // 1. framework (revel/conf/*) // 2. application (conf/*) - // 3. user supplied configs (...) - User configs can override/add any from above + // 3. user supplied configs (...) - User configs can override/add any from above. ConfPaths []string // Server config. @@ -71,22 +71,22 @@ var ( // All cookies dropped by the framework begin with this prefix. CookiePrefix string - // Cookie domain + // Cookie domain. CookieDomain string - // Cookie flags + // Cookie flags. CookieSecure bool CookieSameSite http.SameSite // Revel request access log, not exposed from package. - // However output settings can be controlled from app.conf + // However output settings can be controlled from app.conf. - // True when revel engine has been initialized (Init has returned) + // True when revel engine has been initialized (Init has returned). Initialized bool - // Private - secretKey []byte // Key used to sign cookies. An empty key disables signing. - packaged bool // If true, this is running from a pre-built package. - initEventList = []EventHandler{} // Event handler list for receiving events + // Private. + secretKey []byte // Key used to sign cookies. An empty key disables signing. + packaged bool // If true, this is running from a pre-built package. + initEventList = []EventHandler{} // Event handler list for receiving events packagePathMap = map[string]string{} // The map of the directories needed ) @@ -109,19 +109,19 @@ func Init(inputmode, importPath, srcPath string) { var revelSourcePath string // may be different from the app source path if SourcePath == "" { revelSourcePath, SourcePath = findSrcPaths(importPath) - BasePath = SourcePath + BasePath = SourcePath } else { // If the SourcePath was specified, assume both Revel and the app are within it. SourcePath = filepath.Clean(SourcePath) revelSourcePath = filepath.Join(SourcePath, filepath.FromSlash(RevelImportPath)) - BasePath = filepath.Join(SourcePath, filepath.FromSlash(importPath)) + BasePath = filepath.Join(SourcePath, filepath.FromSlash(importPath)) packaged = true } - RevelPath = revelSourcePath //filepath.Join(revelSourcePath, filepath.FromSlash(RevelImportPath)) + RevelPath = revelSourcePath // filepath.Join(revelSourcePath, filepath.FromSlash(RevelImportPath)) AppPath = filepath.Join(BasePath, "app") ViewsPath = filepath.Join(AppPath, "views") - RevelLog.Info("Paths","revel", RevelPath,"base", BasePath,"app", AppPath,"views", ViewsPath) + RevelLog.Debug("Paths", "revel", RevelPath, "base", BasePath, "app", AppPath, "views", ViewsPath) CodePaths = []string{AppPath} @@ -203,7 +203,7 @@ func Init(inputmode, importPath, srcPath string) { // The input mode can be as simple as "prod" or it can be a JSON string like // {"mode":"%s","testModeFlag":true} // When this function is called it returns the true "inputmode" extracted from the parameter -// and it sets the log context appropriately +// and it sets the log context appropriately. func updateLog(inputmode string) (returnMode string) { if inputmode == "" { returnMode = config.DefaultSection @@ -225,10 +225,10 @@ func updateLog(inputmode string) (returnMode string) { specialUseFlag, _ = specialUse.(bool) } if packagePathMapI, found := modemap["packagePathMap"]; found { - for k,v := range packagePathMapI.(map[string]interface{}) { - packagePathMap[k]=v.(string) - } - } + for k, v := range packagePathMapI.(map[string]interface{}) { + packagePathMap[k] = v.(string) + } + } } var newContext *config.Context @@ -240,7 +240,7 @@ func updateLog(inputmode string) (returnMode string) { // Ensure that the selected runmode appears in app.conf. // If empty string is passed as the mode, treat it as "DEFAULT" if !Config.HasSection(returnMode) { - RevelLog.Fatal("app.conf: Run mode not found:","runmode", returnMode) + RevelLog.Fatal("app.conf: Run mode not found:", "runmode", returnMode) } Config.SetSection(returnMode) newContext = Config @@ -262,7 +262,7 @@ func updateLog(inputmode string) (returnMode string) { return } -// Set the secret key +// Set the secret key. func SetSecretKey(newKey []byte) error { secretKey = newKey return nil @@ -274,9 +274,9 @@ func ResolveImportPath(importPath string) (string, error) { if packaged { return filepath.Join(SourcePath, importPath), nil } - if path,found := packagePathMap[importPath];found { - return path, nil - } + if path, found := packagePathMap[importPath]; found { + return path, nil + } modPkg, err := build.Import(importPath, RevelPath, build.FindOnly) if err != nil { @@ -285,7 +285,7 @@ func ResolveImportPath(importPath string) (string, error) { return modPkg.Dir, nil } -// CheckInit method checks `revel.Initialized` if not initialized it panics +// CheckInit method checks `revel.Initialized` if not initialized it panics. func CheckInit() { if !Initialized { RevelLog.Panic("CheckInit: Revel has not been initialized!") @@ -295,9 +295,9 @@ func CheckInit() { // findSrcPaths uses the "go/build" package to find the source root for Revel // and the app. func findSrcPaths(importPath string) (revelSourcePath, appSourcePath string) { - if importFsPath,found := packagePathMap[importPath];found { - return packagePathMap[RevelImportPath],importFsPath - } + if importFsPath, found := packagePathMap[importPath]; found { + return packagePathMap[RevelImportPath], importFsPath + } var ( gopaths = filepath.SplitList(build.Default.GOPATH) goroot = build.Default.GOROOT diff --git a/revel_hooks.go b/revel_hooks.go index 9378166d4..8faff3e35 100644 --- a/revel_hooks.go +++ b/revel_hooks.go @@ -4,9 +4,9 @@ import ( "sort" ) -// The list of startup hooks +// The list of startup hooks. type ( - // The startup hooks structure + // The startup hooks structure. RevelHook struct { order int // The order f func() // The function to call @@ -16,14 +16,14 @@ type ( ) var ( - // The local instance of the list + // The local instance of the list. startupHooks RevelHooks - // The instance of the list + // The instance of the list. shutdownHooks RevelHooks ) -// Called to run the hooks +// Called to run the hooks. func (r RevelHooks) Run() { serverLogger.Infof("There is %d hooks need to run ...", len(r)) sort.Sort(r) @@ -33,7 +33,7 @@ func (r RevelHooks) Run() { } } -// Adds a new function hook, using the order +// Adds a new function hook, using the order. func (r RevelHooks) Add(fn func(), order ...int) RevelHooks { o := 1 if len(order) > 0 { @@ -42,17 +42,17 @@ func (r RevelHooks) Add(fn func(), order ...int) RevelHooks { return append(r, RevelHook{order: o, f: fn}) } -// Sorting function +// Sorting function. func (slice RevelHooks) Len() int { return len(slice) } -// Sorting function +// Sorting function. func (slice RevelHooks) Less(i, j int) bool { return slice[i].order < slice[j].order } -// Sorting function +// Sorting function. func (slice RevelHooks) Swap(i, j int) { slice[i], slice[j] = slice[j], slice[i] } @@ -97,7 +97,7 @@ func OnAppStart(f func(), order ...int) { startupHooks = startupHooks.Add(f, order...) } -// Called to add a new stop hook +// Called to add a new stop hook. func OnAppStop(f func(), order ...int) { shutdownHooks = shutdownHooks.Add(f, order...) } diff --git a/router.go b/router.go index 8028e25eb..13137836d 100644 --- a/router.go +++ b/router.go @@ -6,20 +6,19 @@ package revel import ( "encoding/csv" + "errors" "fmt" "io" "io/ioutil" "net/url" + "os" "path/filepath" "regexp" "strings" - - "os" "sync" "github.com/revel/pathtree" "github.com/revel/revel/logger" - "errors" ) const ( @@ -65,11 +64,11 @@ type ActionPathData struct { } var ( - // Used to store decoded action path mappings + // Used to store decoded action path mappings. actionPathCacheMap = map[string]*ActionPathData{} - // Used to prevent concurrent writes to map + // Used to prevent concurrent writes to map. actionPathCacheLock = sync.Mutex{} - // The path returned if not found + // The path returned if not found. notFound = &RouteMatch{Action: "404"} ) @@ -194,7 +193,7 @@ func (router *Router) Route(req *Request) (routeMatch *RouteMatch) { routeList := leaf.Value.([]*Route) var typeOfController *ControllerType - //INFO.Printf("Found route for path %s %#v", req.URL.Path, len(routeList)) + // INFO.Printf("Found route for path %s %#v", req.URL.Path, len(routeList)) for index := range routeList { route = routeList[index] methodName = route.MethodName @@ -231,7 +230,6 @@ func (router *Router) Route(req *Request) (routeMatch *RouteMatch) { if route == nil { routeMatch = notFound } else { - routeMatch = &RouteMatch{ ControllerName: route.ControllerNamespace + controllerName, MethodName: methodName, @@ -291,7 +289,7 @@ func (router *Router) updateTree() *Error { return nil } -// Returns the controller namespace and name, action and module if found from the actionPath specified +// Returns the controller namespace and name, action and module if found from the actionPath specified. func splitActionPath(actionPathData *ActionPathData, actionPath string, useCache bool) (pathData *ActionPathData, found bool) { actionPath = strings.ToLower(actionPath) if pathData, found = actionPathCacheMap[actionPath]; found && useCache { @@ -319,17 +317,17 @@ func splitActionPath(actionPathData *ActionPathData, actionPath string, useCache if moduleSource, found := ModuleByName(controllerNamespace[:len(controllerNamespace)-1]); found { foundModuleSource = moduleSource controllerNamespace = moduleSource.Namespace() - log = log.New("namespace",controllerNamespace) + log = log.New("namespace", controllerNamespace) log.Debug("Found module namespace") } else { log.Warnf("splitActionPath: Unable to find module %s for action: %s", controllerNamespace[:len(controllerNamespace)-1], actionPath) } controllerName = controllerName[i+1:] - log = log.New("controllerShortName",controllerName) + log = log.New("controllerShortName", controllerName) // Check for the type of controller typeOfController = foundModuleSource.ControllerByName(controllerName, methodName) found = typeOfController != nil - log.Debug("Found controller","found",found,"type",typeOfController) + log.Debug("Found controller", "found", found, "type", typeOfController) } else if controllerName[0] != ':' { // First attempt to find the controller in the module source if foundModuleSource != nil { @@ -620,15 +618,16 @@ func (a *ActionDefinition) String() string { } func (router *Router) Reverse(action string, argValues map[string]string) (ad *ActionDefinition) { - ad, err := router.ReverseError(action,argValues,nil) - if err!=nil { + ad, err := router.ReverseError(action, argValues, nil) + if err != nil { routerLog.Error("splitActionPath: Failed to find reverse route", "action", action, "arguments", argValues) } return ad } + func (router *Router) ReverseError(action string, argValues map[string]string, req *Request) (ad *ActionDefinition, err error) { var log logger.MultiLogger - if req!=nil { + if req != nil { log = req.controller.Log.New("action", action) } else { log = routerLog.New("action", action) @@ -724,9 +723,8 @@ func (router *Router) ReverseError(action string, argValues map[string]string, r if !ok { val = "" log.Error("Reverse: reverse route missing route argument ", "argument", el[1:]) + err = errors.New("Missing route argument") panic("Check stack") - err = errors.New("Missing route arguement") - return } pathElements[i] = val delete(argValues, el[1:]) @@ -751,7 +749,7 @@ func (router *Router) ReverseError(action string, argValues map[string]string, r star = true } - log.Infof("Reversing action %s to %s Using Route %#v",action,urlPath,pathData.Route) + log.Debugf("Reversing action %s to %s Using Route %#v", action, urlPath, pathData.Route) ad = &ActionDefinition{ URL: urlPath, @@ -815,7 +813,7 @@ func RouterFilter(c *Controller, fc []Filter) { fc[0](c, fc[1:]) } -// HTTPMethodOverride overrides allowed http methods via form or browser param +// HTTPMethodOverride overrides allowed http methods via form or browser param. func HTTPMethodOverride(c *Controller, fc []Filter) { // An array of HTTP verbs allowed. verbs := []string{"POST", "PUT", "PATCH", "DELETE"} @@ -848,7 +846,6 @@ func HTTPMethodOverride(c *Controller, fc []Filter) { }) return } - } } diff --git a/router_test.go b/router_test.go index fe669700e..3d2256140 100644 --- a/router_test.go +++ b/router_test.go @@ -543,13 +543,10 @@ var reverseRoutingTestCases = map[*ReverseRouteArgs]*ActionDefinition{ }, } -type testController struct { - *Controller -} - func initControllers() { registerControllers() } + func TestReverseRouting(t *testing.T) { initControllers() router := NewRouter("") @@ -584,7 +581,7 @@ func BenchmarkRouter(b *testing.B) { } } -// The benchmark from github.com/ant0ine/go-urlrouter +// The benchmark from github.com/ant0ine/go-urlrouter. func BenchmarkLargeRouter(b *testing.B) { router := NewRouter("") diff --git a/server-engine.go b/server-engine.go index 0ac4b8a34..6303d28ee 100644 --- a/server-engine.go +++ b/server-engine.go @@ -14,7 +14,7 @@ import ( ) const ( - /* Minimum Engine Type Values */ + /* Minimum Engine Type Values. */ _ = iota ENGINE_RESPONSE_STATUS ENGINE_WRITER @@ -23,8 +23,9 @@ const ( ENGINE_REQUEST ENGINE_RESPONSE ) + const ( - /* HTTP Engine Type Values Starts at 1000 */ + /* HTTP Engine Type Values Starts at 1000. */ HTTP_QUERY = ENGINE_PARAMETERS HTTP_PATH = ENGINE_PATH HTTP_BODY = iota + 1000 @@ -47,17 +48,17 @@ type ( GetResponse() ServerResponse } - // Callback ServerRequest type + // Callback ServerRequest type. ServerRequest interface { GetRaw() interface{} Get(theType int) (interface{}, error) Set(theType int, theValue interface{}) bool } - // Callback ServerResponse type + // Callback ServerResponse type. ServerResponse interface { ServerRequest } - // Callback WebSocket type + // Callback WebSocket type. ServerWebSocket interface { ServerResponse MessageSendJSON(v interface{}) error @@ -66,9 +67,9 @@ type ( MessageReceive(v interface{}) error } - // Expected response for HTTP_SERVER_HEADER type (if implemented) + // Expected response for HTTP_SERVER_HEADER type (if implemented). ServerHeader interface { - SetCookie(cookie string) // Sets the cookie + SetCookie(cookie string) // Sets the cookie GetCookie(key string) (value ServerCookie, err error) // Gets the cookie Set(key string, value string) Add(key string, value string) @@ -78,12 +79,12 @@ type ( SetStatus(statusCode int) } - // Expected response for FROM_HTTP_COOKIE type (if implemented) + // Expected response for FROM_HTTP_COOKIE type (if implemented). ServerCookie interface { GetValue() string } - // Expected response for HTTP_MULTIPART_FORM + // Expected response for HTTP_MULTIPART_FORM. ServerMultipartForm interface { GetFiles() map[string][]*multipart.FileHeader GetValues() url.Values @@ -108,7 +109,7 @@ type ( Stats() map[string]interface{} } - // The initialization structure passed into the engine + // The initialization structure passed into the engine. EngineInit struct { Address, // The address Network string // The network @@ -117,36 +118,36 @@ type ( Callback func(ServerContext) // The ServerContext callback endpoint } - // An empty server engine + // An empty server engine. ServerEngineEmpty struct { } - // The route handler structure + // The route handler structure. ServerMux struct { PathPrefix string // The path prefix Callback interface{} // The callback interface as appropriate to the server } - // A list of handlers used for adding special route functions + // A list of handlers used for adding special route functions. ServerMuxList []ServerMux ) -// Sorting function +// Sorting function. func (r ServerMuxList) Len() int { return len(r) } -// Sorting function +// Sorting function. func (r ServerMuxList) Less(i, j int) bool { return len(r[i].PathPrefix) > len(r[j].PathPrefix) } -// Sorting function +// Sorting function. func (r ServerMuxList) Swap(i, j int) { r[i], r[j] = r[j], r[i] } -// Search function, returns the largest path matching this +// Search function, returns the largest path matching this. func (r ServerMuxList) Find(path string) (interface{}, bool) { for _, p := range r { if p.PathPrefix == path || strings.HasPrefix(path, p.PathPrefix) { @@ -157,17 +158,17 @@ func (r ServerMuxList) Find(path string) (interface{}, bool) { } // Adds this routehandler to the route table. It will be called (if the path prefix matches) -// before the Revel mux, this can only be called after the ENGINE_BEFORE_INITIALIZED event +// before the Revel mux, this can only be called after the ENGINE_BEFORE_INITIALIZED event. func AddHTTPMux(path string, callback interface{}) { ServerEngineInit.HTTPMuxList = append(ServerEngineInit.HTTPMuxList, ServerMux{PathPrefix: path, Callback: callback}) } -// Callback point for the server to handle the +// Callback point for the server to handle the. func handleInternal(ctx ServerContext) { start := time.Now() var c *Controller if RevelConfig.Controller.Reuse { - c = RevelConfig.Controller.Stack.Pop().(*Controller) + c = RevelConfig.Controller.Stack.Pop().(*Controller) defer func() { RevelConfig.Controller.Stack.Push(c) }() @@ -176,8 +177,8 @@ func handleInternal(ctx ServerContext) { } var ( - - req, resp = c.Request, c.Response + req = c.Request + resp = c.Response ) c.SetController(ctx) req.WebSocket, _ = ctx.GetResponse().(ServerWebSocket) @@ -217,13 +218,12 @@ func handleInternal(ctx ServerContext) { ) } -var ( - ENGINE_UNKNOWN_GET = errors.New("Server Engine Invalid Get") -) +var ENGINE_UNKNOWN_GET = errors.New("Server Engine Invalid Get") func (e *ServerEngineEmpty) Get(_ string) interface{} { return nil } + func (e *ServerEngineEmpty) Set(_ string, _ interface{}) bool { return false } diff --git a/server.go b/server.go index 0f5c7869a..b9eb2d8cf 100644 --- a/server.go +++ b/server.go @@ -6,14 +6,15 @@ package revel import ( "fmt" - "github.com/revel/revel/session" "os" "strconv" "strings" + + "github.com/revel/revel/session" "github.com/revel/revel/utils" ) -// Revel's variables server, router, etc +// Revel's variables server, router, etc. var ( MainRouter *Router MainTemplateLoader *TemplateLoader @@ -56,7 +57,6 @@ func InitServer() { if MainWatcher != nil && Config.BoolDefault("watch.templates", true) { MainWatcher.Listen(MainTemplateLoader, MainTemplateLoader.paths...) } - } // Run the server. @@ -92,7 +92,7 @@ func Run(port int) { println("\nRevel exited normally\n") } -// Build an engine initialization object and start the engine +// Build an engine initialization object and start the engine. func InitServerEngine(port int, serverEngine string) { address := HTTPAddr if address == "" { @@ -102,8 +102,10 @@ func InitServerEngine(port int, serverEngine string) { port = HTTPPort } - var network = "tcp" - var localAddress string + var ( + network = "tcp" + localAddress string + ) // If the port is zero, treat the address as a fully qualified local address. // This address must be prefixed with the network type followed by a colon, @@ -131,9 +133,9 @@ func InitServerEngine(port int, serverEngine string) { AddInitEventHandler(CurrentEngine.Event) } -// Initialize the controller stack for the application +// Initialize the controller stack for the application. func initControllerStack() { - RevelConfig.Controller.Reuse = Config.BoolDefault("revel.controller.reuse",true) + RevelConfig.Controller.Reuse = Config.BoolDefault("revel.controller.reuse", true) if RevelConfig.Controller.Reuse { RevelConfig.Controller.Stack = utils.NewStackLock( @@ -147,7 +149,7 @@ func initControllerStack() { } } -// Called to stop the server +// Called to stop the server. func StopServer(value interface{}) EventResponse { - return RaiseEvent(ENGINE_SHUTDOWN_REQUEST,value) -} \ No newline at end of file + return RaiseEvent(ENGINE_SHUTDOWN_REQUEST, value) +} diff --git a/server_adapter_go.go b/server_adapter_go.go index 148430a85..fdf5d70dd 100644 --- a/server_adapter_go.go +++ b/server_adapter_go.go @@ -20,7 +20,7 @@ import ( "golang.org/x/net/websocket" ) -// Register the GoHttpServer engine +// Register the GoHttpServer engine. func init() { AddInitEventHandler(func(typeOf Event, value interface{}) (responseOf EventResponse) { if typeOf == REVEL_BEFORE_MODULES_LOADED { @@ -30,7 +30,7 @@ func init() { }) } -// The Go HTTP server +// The Go HTTP server. type GoHttpServer struct { Server *http.Server // The server instance ServerInit *EngineInit // The server engine initialization @@ -42,7 +42,7 @@ type GoHttpServer struct { signalChan chan os.Signal } -// Called to initialize the server with this EngineInit +// Called to initialize the server with this EngineInit. func (g *GoHttpServer) Init(init *EngineInit) { g.MaxMultipartSize = int64(Config.IntDefault("server.request.max.multipart.filesize", 32)) << 20 /* 32 MB */ g.goContextStack = utils.NewStackLock(Config.IntDefault("server.context.stack", 100), @@ -71,10 +71,9 @@ func (g *GoHttpServer) Init(init *EngineInit) { ReadTimeout: time.Duration(Config.IntDefault("http.timeout.read", 0)) * time.Second, WriteTimeout: time.Duration(Config.IntDefault("http.timeout.write", 0)) * time.Second, } - } -// Handler is assigned in the Init +// Handler is assigned in the Init. func (g *GoHttpServer) Start() { go func() { time.Sleep(100 * time.Millisecond) @@ -97,7 +96,7 @@ func (g *GoHttpServer) Start() { } } -// Handle the request and response for the server +// Handle the request and response for the server. func (g *GoHttpServer) Handle(w http.ResponseWriter, r *http.Request) { // This section is called if the developer has added custom mux to the app if g.HasAppMux && g.handleAppMux(w, r) { @@ -106,7 +105,7 @@ func (g *GoHttpServer) Handle(w http.ResponseWriter, r *http.Request) { g.handleMux(w, r) } -// Handle the request and response for the servers mux +// Handle the request and response for the servers mux. func (g *GoHttpServer) handleAppMux(w http.ResponseWriter, r *http.Request) bool { // Check the prefix and split them requestPath := path.Clean(r.URL.Path) @@ -131,7 +130,7 @@ func (g *GoHttpServer) handleAppMux(w http.ResponseWriter, r *http.Request) bool return false } -// Passes the server request to Revel +// Passes the server request to Revel. func (g *GoHttpServer) handleMux(w http.ResponseWriter, r *http.Request) { if maxRequestSize := int64(Config.IntDefault("http.maxrequestsize", 0)); maxRequestSize > 0 { r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) @@ -147,7 +146,7 @@ func (g *GoHttpServer) handleMux(w http.ResponseWriter, r *http.Request) { if upgrade == "websocket" || upgrade == "Websocket" { websocket.Handler(func(ws *websocket.Conn) { - //Override default Read/Write timeout with sane value for a web socket request + // Override default Read/Write timeout with sane value for a web socket request if err := ws.SetDeadline(time.Now().Add(time.Hour * 24)); err != nil { serverLogger.Error("SetDeadLine failed:", err) } @@ -168,7 +167,7 @@ func (g *GoHttpServer) handleMux(w http.ResponseWriter, r *http.Request) { // you may get inaccurate Client IP address. Revel parses the // IP address in the order of X-Forwarded-For, X-Real-IP. // -// By default revel will get http.Request's RemoteAddr +// By default revel will get http.Request's RemoteAddr. func HttpClientIP(r *http.Request) string { if Config.BoolDefault("app.behind.proxy", false) { // Header X-Forwarded-For @@ -193,15 +192,15 @@ func HttpClientIP(r *http.Request) string { return "" } -// The server key name +// The server key name. const GO_NATIVE_SERVER_ENGINE = "go" -// Returns the name of this engine +// Returns the name of this engine. func (g *GoHttpServer) Name() string { return GO_NATIVE_SERVER_ENGINE } -// Returns stats for this engine +// Returns stats for this engine. func (g *GoHttpServer) Stats() map[string]interface{} { return map[string]interface{}{ "Go Engine Context": g.goContextStack.String(), @@ -209,12 +208,12 @@ func (g *GoHttpServer) Stats() map[string]interface{} { } } -// Return the engine instance +// Return the engine instance. func (g *GoHttpServer) Engine() interface{} { return g.Server } -// Handles an event from Revel +// Handles an event from Revel. func (g *GoHttpServer) Event(event Event, args interface{}) (r EventResponse) { switch event { case ENGINE_STARTED: @@ -229,21 +228,20 @@ func (g *GoHttpServer) Event(event Event, args interface{}) (r EventResponse) { defer cancel() g.Server.Shutdown(ctx) default: - } return } type ( - // The go context + // The go context. GoContext struct { Request *GoRequest // The request Response *GoResponse // The response WebSocket *GoWebSocket // The websocket } - // The go request + // The go request. GoRequest struct { Original *http.Request // The original FormParsed bool // True if form parsed @@ -254,7 +252,7 @@ type ( Engine *GoHttpServer // THe server } - // The response + // The response. GoResponse struct { Original http.ResponseWriter // The original writer Goheader *GoHeader // The header @@ -263,28 +261,28 @@ type ( Engine *GoHttpServer // The engine } - // The multipart form + // The multipart form. GoMultipartForm struct { Form *multipart.Form // The form } - // The go header + // The go header. GoHeader struct { Source interface{} // The source isResponse bool // True if response header } - // The websocket + // The websocket. GoWebSocket struct { Conn *websocket.Conn // The connection GoResponse // The response } - // The cookie + // The cookie. GoCookie http.Cookie ) -// Create a new go context +// Create a new go context. func NewGoContext(instance *GoHttpServer) *GoContext { // This bit in here is for the test cases, which pass in a nil value if instance == nil { @@ -301,12 +299,12 @@ func NewGoContext(instance *GoHttpServer) *GoContext { return c } -// get the request +// get the request. func (c *GoContext) GetRequest() ServerRequest { return c.Request } -// Get the response +// Get the response. func (c *GoContext) GetResponse() ServerResponse { if c.WebSocket != nil { return c.WebSocket @@ -314,7 +312,7 @@ func (c *GoContext) GetResponse() ServerResponse { return c.Response } -// Destroy the context +// Destroy the context. func (c *GoContext) Destroy() { c.Response.Destroy() c.Request.Destroy() @@ -324,7 +322,7 @@ func (c *GoContext) Destroy() { } } -// Communicate with the server engine to exchange data +// Communicate with the server engine to exchange data. func (r *GoRequest) Get(key int) (value interface{}, err error) { switch key { case HTTP_SERVER_HEADER: @@ -358,12 +356,12 @@ func (r *GoRequest) Get(key int) (value interface{}, err error) { return } -// Sets the request key with value +// Sets the request key with value. func (r *GoRequest) Set(key int, value interface{}) bool { return false } -// Returns the form +// Returns the form. func (r *GoRequest) GetForm() (url.Values, error) { if !r.FormParsed { if e := r.Original.ParseForm(); e != nil { @@ -375,7 +373,7 @@ func (r *GoRequest) GetForm() (url.Values, error) { return r.Original.Form, nil } -// Returns the form +// Returns the form. func (r *GoRequest) GetMultipartForm() (ServerMultipartForm, error) { if !r.MultiFormParsed { if e := r.Original.ParseMultipartForm(r.Engine.MaxMultipartSize); e != nil { @@ -388,25 +386,24 @@ func (r *GoRequest) GetMultipartForm() (ServerMultipartForm, error) { return r.ParsedForm, nil } -// Returns the header +// Returns the header. func (r *GoRequest) GetHeader() ServerHeader { return r.Goheader } -// Returns the raw value +// Returns the raw value. func (r *GoRequest) GetRaw() interface{} { return r.Original } -// Sets the request +// Sets the request. func (r *GoRequest) SetRequest(req *http.Request) { r.Original = req r.Goheader.Source = r r.Goheader.isResponse = false - } -// Destroy the request +// Destroy the request. func (r *GoRequest) Destroy() { r.Goheader.Source = nil r.Original = nil @@ -415,7 +412,7 @@ func (r *GoRequest) Destroy() { r.ParsedForm = nil } -// Gets the key from the response +// Gets the key from the response. func (r *GoResponse) Get(key int) (value interface{}, err error) { switch key { case HTTP_SERVER_HEADER: @@ -430,7 +427,7 @@ func (r *GoResponse) Get(key int) (value interface{}, err error) { return } -// Sets the key with the value +// Sets the key with the value. func (r *GoResponse) Set(key int, value interface{}) (set bool) { switch key { case ENGINE_RESPONSE_STATUS: @@ -443,22 +440,22 @@ func (r *GoResponse) Set(key int, value interface{}) (set bool) { return } -// Sets the header +// Sets the header. func (r *GoResponse) Header() ServerHeader { return r.Goheader } -// Gets the original response +// Gets the original response. func (r *GoResponse) GetRaw() interface{} { return r.Original } -// Sets the writer +// Sets the writer. func (r *GoResponse) SetWriter(writer io.Writer) { r.Writer = writer } -// Write output to stream +// Write output to stream. func (r *GoResponse) WriteStream(name string, contentlen int64, modtime time.Time, reader io.Reader) error { // Check to see if the output stream is modified, if not send it using the // Native writer @@ -502,7 +499,7 @@ func (r *GoResponse) WriteStream(name string, contentlen int64, modtime time.Tim return nil } -// Frees response +// Frees response. func (r *GoResponse) Destroy() { if c, ok := r.Writer.(io.Closer); ok { c.Close() @@ -512,57 +509,54 @@ func (r *GoResponse) Destroy() { r.Writer = nil } -// Sets the response +// Sets the response. func (r *GoResponse) SetResponse(w http.ResponseWriter) { r.Original = w r.Writer = w r.Goheader.Source = r r.Goheader.isResponse = true - } -// Sets the cookie +// Sets the cookie. func (r *GoHeader) SetCookie(cookie string) { if r.isResponse { r.Source.(*GoResponse).Original.Header().Add("Set-Cookie", cookie) } } -// Gets the cookie +// Gets the cookie. func (r *GoHeader) GetCookie(key string) (value ServerCookie, err error) { if !r.isResponse { var cookie *http.Cookie if cookie, err = r.Source.(*GoRequest).Original.Cookie(key); err == nil { value = GoCookie(*cookie) - } - } return } -// Sets (replaces) header key +// Sets (replaces) header key. func (r *GoHeader) Set(key string, value string) { if r.isResponse { r.Source.(*GoResponse).Original.Header().Set(key, value) } } -// Adds the header key +// Adds the header key. func (r *GoHeader) Add(key string, value string) { if r.isResponse { r.Source.(*GoResponse).Original.Header().Add(key, value) } } -// Deletes the header key +// Deletes the header key. func (r *GoHeader) Del(key string) { if r.isResponse { r.Source.(*GoResponse).Original.Header().Del(key) } } -// Gets the header key +// Gets the header key. func (r *GoHeader) Get(key string) (value []string) { if !r.isResponse { value = r.Source.(*GoRequest).Original.Header[key] @@ -577,7 +571,7 @@ func (r *GoHeader) Get(key string) (value []string) { return } -// Returns list of header keys +// Returns list of header keys. func (r *GoHeader) GetKeys() (value []string) { if !r.isResponse { for key := range r.Source.(*GoRequest).Original.Header { @@ -591,56 +585,56 @@ func (r *GoHeader) GetKeys() (value []string) { return } -// Sets the status of the header +// Sets the status of the header. func (r *GoHeader) SetStatus(statusCode int) { if r.isResponse { r.Source.(*GoResponse).Original.WriteHeader(statusCode) } } -// Return cookies value +// Return cookies value. func (r GoCookie) GetValue() string { return r.Value } -// Return files from the form +// Return files from the form. func (f *GoMultipartForm) GetFiles() map[string][]*multipart.FileHeader { return f.Form.File } -// Return values from the form +// Return values from the form. func (f *GoMultipartForm) GetValues() url.Values { return url.Values(f.Form.Value) } -// Remove all values from the form freeing memory +// Remove all values from the form freeing memory. func (f *GoMultipartForm) RemoveAll() error { return f.Form.RemoveAll() } /** - * Message send JSON + * Message send JSON. */ func (g *GoWebSocket) MessageSendJSON(v interface{}) error { return websocket.JSON.Send(g.Conn, v) } /** - * Message receive JSON + * Message receive JSON. */ func (g *GoWebSocket) MessageReceiveJSON(v interface{}) error { return websocket.JSON.Receive(g.Conn, v) } /** - * Message Send + * Message Send. */ func (g *GoWebSocket) MessageSend(v interface{}) error { return websocket.Message.Send(g.Conn, v) } /** - * Message receive + * Message receive. */ func (g *GoWebSocket) MessageReceive(v interface{}) error { return websocket.Message.Receive(g.Conn, v) diff --git a/server_test.go b/server_test.go index e37fa2457..472e94eaa 100644 --- a/server_test.go +++ b/server_test.go @@ -5,7 +5,6 @@ package revel import ( - "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "os" @@ -13,6 +12,8 @@ import ( "strings" "testing" "time" + + "github.com/stretchr/testify/assert" ) // This tries to benchmark the usual request-serving pipeline to get an overall @@ -26,7 +27,7 @@ import ( // - Parameter binding // - Session, flash, i18n cookies // - Render() call magic -// - Template rendering +// - Template rendering. func BenchmarkServeAction(b *testing.B) { benchmarkRequest(b, showRequest) } @@ -101,7 +102,7 @@ func getFileSize(t *testing.T, name string) int64 { return fi.Size() } -// Ensure on app start runs in order +// Ensure on app start runs in order. func TestOnAppStart(t *testing.T) { str := "" a := assert.New(t) @@ -118,7 +119,7 @@ func TestOnAppStart(t *testing.T) { a.Equal("Hello World", str, "Failed to order OnAppStart") } -// Ensure on app stop runs in order +// Ensure on app stop runs in order. func TestOnAppStop(t *testing.T) { a := assert.New(t) startFakeBookingApp() @@ -137,7 +138,6 @@ func TestOnAppStop(t *testing.T) { }() Run(0) a.Equal("goodbye cruel world", i, "Did not get shutdown events") - } var ( diff --git a/session/init.go b/session/init.go index 56069e58a..ecdf33ee9 100644 --- a/session/init.go +++ b/session/init.go @@ -1,6 +1,6 @@ package session -// The logger for the session +// The logger for the session. import "github.com/revel/revel/logger" var sessionLog logger.MultiLogger diff --git a/session/session.go b/session/session.go index bae34b44e..b76df918c 100644 --- a/session/session.go +++ b/session/session.go @@ -8,7 +8,7 @@ import ( "encoding/hex" "encoding/json" "errors" - "github.com/twinj/uuid" + "github.com/google/uuid" "reflect" "strconv" "strings" @@ -16,19 +16,19 @@ import ( ) const ( - // The key for the identity of the session + // The key for the identity of the session. SessionIDKey = "_ID" - // The expiration date of the session + // The expiration date of the session. TimestampKey = "_TS" // The value name indicating how long the session should persist - ie should it persist after the browser closes - // this is set under the TimestampKey if the session data should expire immediately + // this is set under the TimestampKey if the session data should expire immediately. SessionValueName = "session" // The key container for the json objects of the data, any non strings found in the map will be placed in here - // serialized by key using JSON + // serialized by key using JSON. SessionObjectKeyName = "_object_" - // The mapped session object + // The mapped session object. SessionMapKeyName = "_map_" - // The suffix of the session cookie + // The suffix of the session cookie. SessionCookieSuffix = "_SESSION" ) @@ -49,15 +49,15 @@ func (s Session) ID() string { return sessionIDStr.(string) } - buffer := uuid.NewV4() + suuid := uuid.New() - s[SessionIDKey] = hex.EncodeToString(buffer.Bytes()) + s[SessionIDKey] = hex.EncodeToString(suuid[0:]) return s[SessionIDKey].(string) } // getExpiration return a time.Time with the session's expiration date. // It uses the passed in expireAfterDuration to add with the current time if the timeout is not -// browser dependent (ie session). If previous session has set to "session", the time returned is time.IsZero() +// browser dependent (ie session). If previous session has set to "session", the time returned is time.IsZero(). func (s Session) GetExpiration(expireAfterDuration time.Duration) time.Time { if expireAfterDuration == 0 || s[TimestampKey] == SessionValueName { // Expire after closing browser @@ -66,12 +66,12 @@ func (s Session) GetExpiration(expireAfterDuration time.Duration) time.Time { return time.Now().Add(expireAfterDuration) } -// SetNoExpiration sets session to expire when browser session ends +// SetNoExpiration sets session to expire when browser session ends. func (s Session) SetNoExpiration() { s[TimestampKey] = SessionValueName } -// SetDefaultExpiration sets session to expire after default duration +// SetDefaultExpiration sets session to expire after default duration. func (s Session) SetDefaultExpiration() { delete(s, TimestampKey) } @@ -90,7 +90,7 @@ func (s Session) SessionTimeoutExpiredOrMissing() bool { return false } -// Constant error if session value is not found +// Constant error if session value is not found. var SESSION_VALUE_NOT_FOUND = errors.New("Session value not found") // Get an object or property from the session @@ -104,7 +104,7 @@ func (s Session) Get(key string) (newValue interface{}, err error) { } // Get into the specified value. -// If value exists in the session it will just return the value +// If value exists in the session it will just return the value. func (s Session) GetInto(key string, target interface{}, force bool) (result interface{}, err error) { if v, found := s[key]; found && !force { return v, nil @@ -142,7 +142,7 @@ func (s Session) GetInto(key string, target interface{}, force bool) (result int return s.getNestedProperty(splitKey, v) } -// Returns the default value if the key is not found +// Returns the default value if the key is not found. func (s Session) GetDefault(key string, value interface{}, defaultValue interface{}) interface{} { v, e := s.GetInto(key, value, false) if e != nil { @@ -151,7 +151,7 @@ func (s Session) GetDefault(key string, value interface{}, defaultValue interfac return v } -// Extract the values from the session +// Extract the values from the session. func (s Session) GetProperty(key string, value interface{}) (interface{}, error) { // Capitalize the first letter key = strings.Title(key) @@ -165,7 +165,7 @@ func (s Session) GetProperty(key string, value interface{}) (interface{}, error) if valueOf == reflect.Zero(reflect.ValueOf(value).Type()) { return nil, nil } - //idx := val.MapIndex(reflect.ValueOf(key)) + // idx := val.MapIndex(reflect.ValueOf(key)) if !valueOf.IsValid() { return nil, nil } @@ -183,7 +183,7 @@ func (s Session) GetProperty(key string, value interface{}) (interface{}, error) } // Places the object into the session, a nil value will cause remove the key from the session -// (or you can use the Session.Del(key) function +// (or you can use the Session.Del(key) function. func (s Session) Set(key string, value interface{}) error { if value == nil { s.Del(key) @@ -194,14 +194,14 @@ func (s Session) Set(key string, value interface{}) error { return nil } -// Delete the key from the sessionObjects and Session +// Delete the key from the sessionObjects and Session. func (s Session) Del(key string) { sessionJsonMap := s.getSessionJsonMap() delete(sessionJsonMap, key) delete(s, key) } -// Extracts the session as a map of [string keys] and json values +// Extracts the session as a map of [string keys] and json values. func (s Session) getSessionJsonMap() map[string]string { if sessionJson, found := s[SessionObjectKeyName]; found { if _, valid := sessionJson.(map[string]string); !valid { @@ -218,7 +218,7 @@ func (s Session) getSessionJsonMap() map[string]string { // Convert the map to a simple map[string]string map // this will marshal any non string objects encountered and store them the the jsonMap -// The expiration time will also be assigned +// The expiration time will also be assigned. func (s Session) Serialize() map[string]string { sessionJsonMap := s.getSessionJsonMap() newMap := map[string]string{} @@ -244,7 +244,6 @@ func (s Session) Serialize() map[string]string { if len(newObjectMap) > 0 { if data, err := json.Marshal(newObjectMap); err != nil { sessionLog.Error("Unable to marshal session ", "key", SessionObjectKeyName, "error", err) - } else { newMap[SessionObjectKeyName] = string(data) } @@ -253,7 +252,7 @@ func (s Session) Serialize() map[string]string { return newMap } -// Set the session object from the loaded data +// Set the session object from the loaded data. func (s Session) Load(data map[string]string) { for key, value := range data { if key == SessionObjectKeyName { @@ -266,11 +265,10 @@ func (s Session) Load(data map[string]string) { } else { s[key] = value } - } } -// Checks to see if the session is empty +// Checks to see if the session is empty. func (s Session) Empty() bool { i := 0 for k := range s { @@ -294,7 +292,7 @@ func (s *Session) reflectValue(obj interface{}) reflect.Value { return val } -// Starting at position 1 drill into the object +// Starting at position 1 drill into the object. func (s Session) getNestedProperty(keys []string, newValue interface{}) (result interface{}, err error) { for x := 1; x < len(keys); x++ { newValue, err = s.GetProperty(keys[x], newValue) @@ -306,7 +304,7 @@ func (s Session) getNestedProperty(keys []string, newValue interface{}) (result } // Always converts the data from the session mapped objects into the target, -// it will store the results under the session key name SessionMapKeyName +// it will store the results under the session key name SessionMapKeyName. func (s Session) sessionDataFromMap(key string) (result interface{}, err error) { var mapValue map[string]interface{} uncastMapValue, found := s[SessionMapKeyName] @@ -331,7 +329,7 @@ func (s Session) sessionDataFromMap(key string) (result interface{}, err error) return } -// Unpack the object from the session map and store it in the session when done, if no error occurs +// Unpack the object from the session map and store it in the session when done, if no error occurs. func (s Session) sessionDataFromObject(key string, newValue interface{}) (result interface{}, err error) { result, err = s.convertSessionData(key, newValue) if err != nil { @@ -341,7 +339,7 @@ func (s Session) sessionDataFromObject(key string, newValue interface{}) (result return } -// Converts from the session json map into the target, +// Converts from the session json map into the target,. func (s Session) convertSessionData(key string, target interface{}) (result interface{}, err error) { sessionJsonMap := s.getSessionJsonMap() v, found := sessionJsonMap[key] diff --git a/session/session_cookie_test.go b/session/session_cookie_test.go index ca6c82952..292a7aa31 100644 --- a/session/session_cookie_test.go +++ b/session/session_cookie_test.go @@ -5,13 +5,13 @@ package session_test import ( + "net/http" "testing" + "time" "github.com/revel/revel" "github.com/revel/revel/session" "github.com/stretchr/testify/assert" - "net/http" - "time" ) func TestCookieRestore(t *testing.T) { @@ -30,8 +30,8 @@ func TestCookieRestore(t *testing.T) { restoredSession := session.NewSession() cse.DecodeCookie(revel.GoCookie(*cookie), restoredSession) - a.Equal("foo",restoredSession["foo"]) - a.Equal("bar",restoredSession["bar"]) + a.Equal("foo", restoredSession["foo"]) + a.Equal("bar", restoredSession["bar"]) testSharedData(originSession, restoredSession, t, a) } diff --git a/session/session_test.go b/session/session_test.go index 6be1ce568..bdb756ef2 100644 --- a/session/session_test.go +++ b/session/session_test.go @@ -6,20 +6,20 @@ package session_test import ( "fmt" + "testing" + "github.com/revel/revel" "github.com/revel/revel/session" "github.com/stretchr/testify/assert" - "testing" ) -// test the commands +// test the commands. func TestSessionString(t *testing.T) { session.InitSession(revel.RevelLog) a := assert.New(t) s := session.NewSession() s.Set("happy", "day") a.Equal("day", s.GetDefault("happy", nil, ""), fmt.Sprintf("Session Data %#v\n", s)) - } func TestSessionStruct(t *testing.T) { @@ -33,7 +33,6 @@ func TestSessionStruct(t *testing.T) { s1 := session.NewSession() s1.Load(stringMap) testSharedData(s, s1, t, a) - } func setSharedDataTest(s session.Session) { @@ -44,21 +43,23 @@ func setSharedDataTest(s session.Session) { B int C string D float32 - }{A: struct { - Aa string - }{Aa: "test"}, + }{ + A: struct { + Aa string + }{Aa: "test"}, B: 5, C: "test", - D: -325.25} + D: -325.25, + } s.Set("happy", data) } + func testSharedData(s, s1 session.Session, t *testing.T, a *assert.Assertions) { // Compress the session to a string t.Logf("Original session %#v\n", s) t.Logf("New built session %#v\n", s1) - data,err := s1.Get("happy.a.aa") - a.Nil(err,"Expected nil") + data, err := s1.Get("happy.a.aa") + a.Nil(err, "Expected nil") a.Equal("test", data, fmt.Sprintf("Session Data %#v\n", s)) t.Logf("After test session %#v\n", s1) - } diff --git a/session_adapter_cookie.go b/session_adapter_cookie.go index 92f6b9620..c3f70e7c0 100644 --- a/session_adapter_cookie.go +++ b/session_adapter_cookie.go @@ -2,37 +2,37 @@ package revel import ( "fmt" - "github.com/revel/revel/session" "net/http" "net/url" "strconv" "strings" "time" -) + "github.com/revel/revel/session" +) type ( - // The session cookie engine + // The session cookie engine. SessionCookieEngine struct { ExpireAfterDuration time.Duration } ) -// A logger for the session engine +// A logger for the session engine. var sessionEngineLog = RevelLog.New("section", "session-engine") -// Create a new instance to test +// Create a new instance to test. func init() { RegisterSessionEngine(initCookieEngine, "revel-cookie") } -// For testing purposes this engine is used +// For testing purposes this engine is used. func NewSessionCookieEngine() *SessionCookieEngine { ce := &SessionCookieEngine{} return ce } -// Called when the the application starts, retrieves data from the app config so cannot be run until then +// Called when the the application starts, retrieves data from the app config so cannot be run until then. func initCookieEngine() SessionEngine { ce := &SessionCookieEngine{} @@ -48,7 +48,7 @@ func initCookieEngine() SessionEngine { return ce } -// Decode the session information from the cookie retrieved from the controller request +// Decode the session information from the cookie retrieved from the controller request. func (cse *SessionCookieEngine) Decode(c *Controller) { // Decode the session from a cookie. c.Session = map[string]interface{}{} @@ -61,13 +61,12 @@ func (cse *SessionCookieEngine) Decode(c *Controller) { } } -// Encode the session information to the cookie, set the cookie on the controller +// Encode the session information to the cookie, set the cookie on the controller. func (cse *SessionCookieEngine) Encode(c *Controller) { - c.SetCookie(cse.GetCookie(c.Session)) } -// Exposed only for testing purposes +// Exposed only for testing purposes. func (cse *SessionCookieEngine) DecodeCookie(cookie ServerCookie, s session.Session) { // Decode the session from a cookie. // Separate the data from the signature. @@ -101,7 +100,7 @@ func (cse *SessionCookieEngine) DecodeCookie(cookie ServerCookie, s session.Sess } } -// Convert session to cookie +// Convert session to cookie. func (cse *SessionCookieEngine) GetCookie(s session.Session) *http.Cookie { var sessionValue string ts := s.GetExpiration(cse.ExpireAfterDuration) @@ -141,5 +140,4 @@ func (cse *SessionCookieEngine) GetCookie(s session.Session) *http.Cookie { MaxAge: int(cse.ExpireAfterDuration.Seconds()), } return sessionCookie - } diff --git a/session_engine.go b/session_engine.go index 1f95d7b3a..96a8b1403 100644 --- a/session_engine.go +++ b/session_engine.go @@ -1,6 +1,6 @@ package revel -// The session engine provides an interface to allow for storage of session data +// The session engine provides an interface to allow for storage of session data. type ( SessionEngine interface { Decode(c *Controller) // Called to decode the session information on the controller @@ -13,7 +13,7 @@ var ( CurrentSessionEngine SessionEngine ) -// Initialize session engine on startup +// Initialize session engine on startup. func init() { OnAppStart(initSessionEngine, 5) } @@ -22,7 +22,7 @@ func RegisterSessionEngine(f func() SessionEngine, name string) { sessionEngineMap[name] = f } -// Called when application is starting up +// Called when application is starting up. func initSessionEngine() { // Check for session engine to use and assign it sename := Config.StringDefault("session.engine", "revel-cookie") diff --git a/session_filter.go b/session_filter.go index f10470a96..e75d9abe4 100644 --- a/session_filter.go +++ b/session_filter.go @@ -3,7 +3,6 @@ package revel // SessionFilter is a Revel Filter that retrieves and sets the session cookie. // Within Revel, it is available as a Session attribute on Controller instances. // The name of the Session cookie is set as CookiePrefix + "_SESSION". -import () var sessionLog = RevelLog.New("section", "session") diff --git a/template.go b/template.go index c5bd91e84..8f492cf96 100644 --- a/template.go +++ b/template.go @@ -19,7 +19,7 @@ import ( "sync/atomic" ) -// ErrorCSSClass httml CSS error class name +// ErrorCSSClass httml CSS error class name. var ErrorCSSClass = "hasError" // TemplateLoader object handles loading and parsing of templates. @@ -46,9 +46,11 @@ type Template interface { Location() string // Disk location } -var invalidSlugPattern = regexp.MustCompile(`[^a-z0-9 _-]`) -var whiteSpacePattern = regexp.MustCompile(`\s+`) -var templateLog = RevelLog.New("section", "template") +var ( + invalidSlugPattern = regexp.MustCompile(`[^a-z0-9 _-]`) + whiteSpacePattern = regexp.MustCompile(`\s+`) + templateLog = RevelLog.New("section", "template") +) // TemplateOutputArgs returns the result of the template rendered using the passed in arguments. func TemplateOutputArgs(templatePath string, args map[string]interface{}) (data []byte, err error) { @@ -77,20 +79,20 @@ func NewTemplateLoader(paths []string) *TemplateLoader { } // WatchDir returns true of directory doesn't start with . (dot) -// otherwise false +// otherwise false. func (loader *TemplateLoader) WatchDir(info os.FileInfo) bool { // Watch all directories, except the ones starting with a dot. return !strings.HasPrefix(info.Name(), ".") } // WatchFile returns true of file doesn't start with . (dot) -// otherwise false +// otherwise false. func (loader *TemplateLoader) WatchFile(basename string) bool { // Watch all files, except the ones starting with a dot. return !strings.HasPrefix(basename, ".") } -// DEPRECATED Use TemplateLang, will be removed in future release +// DEPRECATED Use TemplateLang, will be removed in future release. func (loader *TemplateLoader) Template(name string) (tmpl Template, err error) { runtimeLoader := loader.runtimeLoader.Load().(*templateRuntime) return runtimeLoader.TemplateLang(name, "") @@ -103,15 +105,17 @@ func (loader *TemplateLoader) TemplateLang(name, lang string) (tmpl Template, er // Refresh method scans the views directory and parses all templates as Go Templates. // If a template fails to parse, the error is set on the loader. -// (It's awkward to refresh a single Go Template) +// (It's awkward to refresh a single Go Template). func (loader *TemplateLoader) Refresh() (err *Error) { loader.templateMutex.Lock() defer loader.templateMutex.Unlock() loader.loadVersionSeed++ - runtimeLoader := &templateRuntime{loader: loader, + runtimeLoader := &templateRuntime{ + loader: loader, version: loader.loadVersionSeed, - templateMap: map[string]Template{}} + templateMap: map[string]Template{}, + } templateLog.Debug("Refresh: Refreshing templates from ", "path", loader.paths) if err = loader.initializeEngines(runtimeLoader, Config.StringDefault("template.engines", GO_TEMPLATE)); err != nil { @@ -183,6 +187,7 @@ func (loader *TemplateLoader) Refresh() (err *Error) { return nil } + //nolint:scopelint fileBytes, err := runtimeLoader.findAndAddTemplate(path, fullSrcDir, basePath) if err != nil { // Add in this template name to the list of templates unable to be compiled @@ -206,7 +211,6 @@ func (loader *TemplateLoader) Refresh() (err *Error) { templateLog.Errorf("Refresh: Template compilation error (In %s around line %d):\n\t%s", path, runtimeLoader.compileError.Line, err.Error()) } else if nil != err { //&& strings.HasPrefix(templateName, "errors/") { - if compileError, ok := err.(*Error); ok { templateLog.Errorf("Template compilation error (In %s around line %d):\n\t%s", path, compileError.Line, err.Error()) @@ -254,7 +258,7 @@ type templateRuntime struct { } // Checks to see if template exists in templatePaths, if so it is skipped (templates are imported in order -// reads the template file into memory, replaces namespace keys with module (if found +// reads the template file into memory, replaces namespace keys with module (if found. func (runtimeLoader *templateRuntime) findAndAddTemplate(path, fullSrcDir, basePath string) (fileBytes []byte, err error) { templateName := filepath.ToSlash(path[len(fullSrcDir)+1:]) // Convert template names to use forward slashes, even on Windows. @@ -344,7 +348,7 @@ func (runtimeLoader *templateRuntime) loadIntoEngine(engine TemplateEngine, base } // Parse the line, and description from an error message like: -// html/template:Application/Register.html:36: no such template "footer.html" +// html/template:Application/Register.html:36: no such template "footer.html". func ParseTemplateError(err error) (templateName string, line int, description string) { if e, ok := err.(*Error); ok { return "", e.Line, e.Description @@ -390,7 +394,7 @@ func (runtimeLoader *templateRuntime) TemplateLang(name, lang string) (tmpl Temp return } -// Load and also updates map if name is not found (to speed up next lookup) +// Load and also updates map if name is not found (to speed up next lookup). func (runtimeLoader *templateRuntime) templateLoad(name, lang string) (tmpl Template) { langName := name found := false diff --git a/template_adapter_go.go b/template_adapter_go.go index 411130797..50634c9bf 100644 --- a/template_adapter_go.go +++ b/template_adapter_go.go @@ -9,7 +9,7 @@ import ( const GO_TEMPLATE = "go" -// Called on startup, initialized when the REVEL_BEFORE_MODULES_LOADED is called +// Called on startup, initialized when the REVEL_BEFORE_MODULES_LOADED is called. func init() { AddInitEventHandler(func(typeOf Event, value interface{}) (responseOf EventResponse) { if typeOf == REVEL_BEFORE_MODULES_LOADED { @@ -50,7 +50,7 @@ func (gotmpl GoTemplate) Render(wr io.Writer, arg interface{}) error { return gotmpl.Execute(wr, arg) } -// The main template engine for Go +// The main template engine for Go. type GoEngine struct { // The template loader loader *TemplateLoader @@ -64,7 +64,7 @@ type GoEngine struct { CaseInsensitive bool } -// Convert the path to lower case if needed +// Convert the path to lower case if needed. func (i *GoEngine) ConvertPath(path string) string { if i.CaseInsensitive { return strings.ToLower(path) @@ -72,12 +72,12 @@ func (i *GoEngine) ConvertPath(path string) string { return path } -// Returns true if this engine can handle the response +// Returns true if this engine can handle the response. func (i *GoEngine) Handles(templateView *TemplateView) bool { return EngineHandles(i, templateView) } -// Parses the template vide and adds it to the template set +// Parses the template vide and adds it to the template set. func (engine *GoEngine) ParseAndAdd(baseTemplate *TemplateView) error { // If alternate delimiters set for the project, change them for this set if engine.splitDelims != nil && strings.Index(baseTemplate.Location(), ViewsPath) > -1 { @@ -103,7 +103,7 @@ func (engine *GoEngine) ParseAndAdd(baseTemplate *TemplateView) error { return nil } -// Lookups the template name, to see if it is contained in this engine +// Lookups the template name, to see if it is contained in this engine. func (engine *GoEngine) Lookup(templateName string) Template { // Case-insensitive matching of template file name if tpl, found := engine.templatesByName[engine.ConvertPath(templateName)]; found { @@ -112,12 +112,12 @@ func (engine *GoEngine) Lookup(templateName string) Template { return nil } -// Return the engine name +// Return the engine name. func (engine *GoEngine) Name() string { return GO_TEMPLATE } -// An event listener to listen for Revel INIT events +// An event listener to listen for Revel INIT events. func (engine *GoEngine) Event(action Event, i interface{}) { if action == TEMPLATE_REFRESH_REQUESTED { // At this point all the templates have been passed into the diff --git a/template_engine.go b/template_engine.go index a62f5f212..30772dc94 100644 --- a/template_engine.go +++ b/template_engine.go @@ -26,7 +26,7 @@ type TemplateEngine interface { Name() string } -// The template view information +// The template view information. type TemplateView struct { TemplateName string // The name of the view FilePath string // The file path (view relative) @@ -37,7 +37,7 @@ type TemplateView struct { var templateLoaderMap = map[string]func(loader *TemplateLoader) (TemplateEngine, error){} -// Allow for templates to be registered during init but not initialized until application has been started +// Allow for templates to be registered during init but not initialized until application has been started. func RegisterTemplateLoader(key string, loader func(loader *TemplateLoader) (TemplateEngine, error)) (err error) { if _, found := templateLoaderMap[key]; found { err = fmt.Errorf("Template loader %s already exists", key) @@ -48,18 +48,18 @@ func RegisterTemplateLoader(key string, loader func(loader *TemplateLoader) (Tem } // Sets the template name from Config -// Sets the template API methods for parsing and storing templates before rendering +// Sets the template API methods for parsing and storing templates before rendering. func (loader *TemplateLoader) CreateTemplateEngine(templateEngineName string) (TemplateEngine, error) { - if "" == templateEngineName { + if templateEngineName == "" { templateEngineName = GO_TEMPLATE } factory := templateLoaderMap[templateEngineName] - if nil == factory { + if factory == nil { fmt.Printf("registered factories %#v\n %s \n", templateLoaderMap, templateEngineName) return nil, errors.New("Unknown template engine name - " + templateEngineName + ".") } templateEngine, err := factory(loader) - if nil != err { + if err != nil { return nil, errors.New("Failed to init template engine (" + templateEngineName + "), " + err.Error()) } @@ -67,12 +67,11 @@ func (loader *TemplateLoader) CreateTemplateEngine(templateEngineName string) (T return templateEngine, nil } -// Passing in a comma delimited list of engine names to be used with this loader to parse the template files +// Passing in a comma delimited list of engine names to be used with this loader to parse the template files. func (loader *TemplateLoader) initializeEngines(runtimeLoader *templateRuntime, templateEngineNameList string) (err *Error) { // Walk through the template loader's paths and build up a template set. if templateEngineNameList == "" { templateEngineNameList = GO_TEMPLATE - } runtimeLoader.templatesAndEngineList = []TemplateEngine{} for _, engine := range strings.Split(templateEngineNameList, ",") { diff --git a/template_functions.go b/template_functions.go index 98bb988de..bb0a5b963 100644 --- a/template_functions.go +++ b/template_functions.go @@ -4,215 +4,214 @@ import ( "bytes" "errors" "fmt" - "github.com/xeonx/timeago" "html" "html/template" "reflect" "strings" "time" + + "github.com/xeonx/timeago" ) -var ( - // The functions available for use in the templates. - TemplateFuncs = map[string]interface{}{ - "url": ReverseURL, - "set": func(viewArgs map[string]interface{}, key string, value interface{}) template.JS { - viewArgs[key] = value - return template.JS("") - }, - "append": func(viewArgs map[string]interface{}, key string, value interface{}) template.JS { - if viewArgs[key] == nil { - viewArgs[key] = []interface{}{value} - } else { - viewArgs[key] = append(viewArgs[key].([]interface{}), value) - } - return template.JS("") - }, - "field": NewField, - "firstof": func(args ...interface{}) interface{} { - for _, val := range args { - switch val.(type) { - case nil: +// The functions available for use in the templates. +var TemplateFuncs = map[string]interface{}{ + "url": ReverseURL, + "set": func(viewArgs map[string]interface{}, key string, value interface{}) template.JS { + viewArgs[key] = value + return template.JS("") + }, + "append": func(viewArgs map[string]interface{}, key string, value interface{}) template.JS { + if viewArgs[key] == nil { + viewArgs[key] = []interface{}{value} + } else { + viewArgs[key] = append(viewArgs[key].([]interface{}), value) + } + return template.JS("") + }, + "field": NewField, + "firstof": func(args ...interface{}) interface{} { + for _, val := range args { + switch val.(type) { + case nil: + continue + case string: + if val == "" { continue - case string: - if val == "" { - continue - } - return val - default: - return val } + return val + default: + return val } - return nil - }, - "option": func(f *Field, val interface{}, label string) template.HTML { - selected := "" - if f.Flash() == val || (f.Flash() == "" && f.Value() == val) { - selected = " selected" - } + } + return nil + }, + "option": func(f *Field, val interface{}, label string) template.HTML { + selected := "" + if f.Flash() == val || (f.Flash() == "" && f.Value() == val) { + selected = " selected" + } - return template.HTML(fmt.Sprintf(``, - html.EscapeString(fmt.Sprintf("%v", val)), selected, html.EscapeString(label))) - }, - "radio": func(f *Field, val string) template.HTML { - checked := "" - if f.Flash() == val { - checked = " checked" - } - return template.HTML(fmt.Sprintf(``, - html.EscapeString(f.Name), html.EscapeString(val), checked)) - }, - "checkbox": func(f *Field, val string) template.HTML { - checked := "" - if f.Flash() == val { - checked = " checked" - } - return template.HTML(fmt.Sprintf(``, - html.EscapeString(f.Name), html.EscapeString(val), checked)) - }, - // Pads the given string with  's up to the given width. - "pad": func(str string, width int) template.HTML { - if len(str) >= width { - return template.HTML(html.EscapeString(str)) - } - return template.HTML(html.EscapeString(str) + strings.Repeat(" ", width-len(str))) - }, - - "errorClass": func(name string, viewArgs map[string]interface{}) template.HTML { - errorMap, ok := viewArgs["errors"].(map[string]*ValidationError) - if !ok || errorMap == nil { - templateLog.Warn("errorClass: Called 'errorClass' without 'errors' in the view args.") - return template.HTML("") - } - valError, ok := errorMap[name] - if !ok || valError == nil { - return template.HTML("") + return template.HTML(fmt.Sprintf(``, + html.EscapeString(fmt.Sprintf("%v", val)), selected, html.EscapeString(label))) + }, + "radio": func(f *Field, val string) template.HTML { + checked := "" + if f.Flash() == val { + checked = " checked" + } + return template.HTML(fmt.Sprintf(``, + html.EscapeString(f.Name), html.EscapeString(val), checked)) + }, + "checkbox": func(f *Field, val string) template.HTML { + checked := "" + if f.Flash() == val { + checked = " checked" + } + return template.HTML(fmt.Sprintf(``, + html.EscapeString(f.Name), html.EscapeString(val), checked)) + }, + // Pads the given string with  's up to the given width. + "pad": func(str string, width int) template.HTML { + if len(str) >= width { + return template.HTML(html.EscapeString(str)) + } + return template.HTML(html.EscapeString(str) + strings.Repeat(" ", width-len(str))) + }, + + "errorClass": func(name string, viewArgs map[string]interface{}) template.HTML { + errorMap, ok := viewArgs["errors"].(map[string]*ValidationError) + if !ok || errorMap == nil { + templateLog.Warn("errorClass: Called 'errorClass' without 'errors' in the view args.") + return template.HTML("") + } + valError, ok := errorMap[name] + if !ok || valError == nil { + return template.HTML("") + } + return template.HTML(ErrorCSSClass) + }, + + "msg": func(viewArgs map[string]interface{}, message string, args ...interface{}) template.HTML { + str, ok := viewArgs[CurrentLocaleViewArg].(string) + if !ok { + return "" + } + return template.HTML(MessageFunc(str, message, args...)) + }, + + // Replaces newlines with
+ "nl2br": func(text string) template.HTML { + return template.HTML(strings.Replace(template.HTMLEscapeString(text), "\n", "
", -1)) + }, + + // Skips sanitation on the parameter. Do not use with dynamic data. + "raw": func(text string) template.HTML { + return template.HTML(text) + }, + + // Pluralize, a helper for pluralizing words to correspond to data of dynamic length. + // items - a slice of items, or an integer indicating how many items there are. + // pluralOverrides - optional arguments specifying the output in the + // singular and plural cases. by default "" and "s" + "pluralize": func(items interface{}, pluralOverrides ...string) string { + singular, plural := "", "s" + if len(pluralOverrides) >= 1 { + singular = pluralOverrides[0] + if len(pluralOverrides) == 2 { + plural = pluralOverrides[1] } - return template.HTML(ErrorCSSClass) - }, + } - "msg": func(viewArgs map[string]interface{}, message string, args ...interface{}) template.HTML { - str, ok := viewArgs[CurrentLocaleViewArg].(string) - if !ok { - return "" + switch v := reflect.ValueOf(items); v.Kind() { + case reflect.Int: + if items.(int) != 1 { + return plural } - return template.HTML(MessageFunc(str, message, args...)) - }, - - // Replaces newlines with
- "nl2br": func(text string) template.HTML { - return template.HTML(strings.Replace(template.HTMLEscapeString(text), "\n", "
", -1)) - }, - - // Skips sanitation on the parameter. Do not use with dynamic data. - "raw": func(text string) template.HTML { - return template.HTML(text) - }, - - // Pluralize, a helper for pluralizing words to correspond to data of dynamic length. - // items - a slice of items, or an integer indicating how many items there are. - // pluralOverrides - optional arguments specifying the output in the - // singular and plural cases. by default "" and "s" - "pluralize": func(items interface{}, pluralOverrides ...string) string { - singular, plural := "", "s" - if len(pluralOverrides) >= 1 { - singular = pluralOverrides[0] - if len(pluralOverrides) == 2 { - plural = pluralOverrides[1] - } + case reflect.Slice: + if v.Len() != 1 { + return plural } + default: + templateLog.Error("pluralize: unexpected type: ", "value", v) + } + return singular + }, - switch v := reflect.ValueOf(items); v.Kind() { - case reflect.Int: - if items.(int) != 1 { - return plural - } - case reflect.Slice: - if v.Len() != 1 { - return plural - } - default: - templateLog.Error("pluralize: unexpected type: ", "value", v) - } - return singular - }, - - // Format a date according to the application's default date(time) format. - "date": func(date time.Time) string { - return date.Format(DateFormat) - }, - "datetime": func(date time.Time) string { - return date.Format(DateTimeFormat) - }, - // Fetch an object from the session. - "session": func(key string, viewArgs map[string]interface{}) interface{} { - if viewArgs != nil { - if c, found := viewArgs["_controller"]; found { - if v, err := c.(*Controller).Session.Get(key); err == nil { - return v - } else { - templateLog.Errorf("template.session, key %s error %v", key, err) - } + // Format a date according to the application's default date(time) format. + "date": func(date time.Time) string { + return date.Format(DateFormat) + }, + "datetime": func(date time.Time) string { + return date.Format(DateTimeFormat) + }, + // Fetch an object from the session. + "session": func(key string, viewArgs map[string]interface{}) interface{} { + if viewArgs != nil { + if c, found := viewArgs["_controller"]; found { + if v, err := c.(*Controller).Session.Get(key); err == nil { + return v } else { - templateLog.Warnf("template.session, key %s requested without controller", key) + templateLog.Errorf("template.session, key %s error %v", key, err) } } else { - templateLog.Warnf("template.session, key %s requested passing in view args", key) - } - return "" - }, - - "slug": Slug, - "even": func(a int) bool { return (a % 2) == 0 }, - - // Using https://github.com/xeonx/timeago - "timeago": TimeAgo, - "i18ntemplate": func(args ...interface{}) (template.HTML, error) { - templateName, lang := "", "" - var viewArgs interface{} - switch len(args) { - case 0: - templateLog.Error("i18ntemplate: No arguments passed to template call") - case 1: - // Assume only the template name is passed in - templateName = args[0].(string) - case 2: - // Assume template name and viewArgs is passed in - templateName = args[0].(string) - viewArgs = args[1] - // Try to extract language from the view args - if viewargsmap, ok := viewArgs.(map[string]interface{}); ok { - lang, _ = viewargsmap[CurrentLocaleViewArg].(string) - } - default: - // Assume third argument is the region - templateName = args[0].(string) - viewArgs = args[1] - lang, _ = args[2].(string) - if len(args) > 3 { - templateLog.Error("i18ntemplate: Received more parameters then needed for", "template", templateName) - } + templateLog.Warnf("template.session, key %s requested without controller", key) } + } else { + templateLog.Warnf("template.session, key %s requested passing in view args", key) + } + return "" + }, - var buf bytes.Buffer - // Get template - tmpl, err := MainTemplateLoader.TemplateLang(templateName, lang) - if err == nil { - err = tmpl.Render(&buf, viewArgs) - } else { - templateLog.Error("i18ntemplate: Failed to render i18ntemplate ", "name", templateName, "error", err) + "slug": Slug, + "even": func(a int) bool { return (a % 2) == 0 }, + + // Using https://github.com/xeonx/timeago + "timeago": TimeAgo, + "i18ntemplate": func(args ...interface{}) (template.HTML, error) { + templateName, lang := "", "" + var viewArgs interface{} + switch len(args) { + case 0: + templateLog.Error("i18ntemplate: No arguments passed to template call") + case 1: + // Assume only the template name is passed in + templateName = args[0].(string) + case 2: + // Assume template name and viewArgs is passed in + templateName = args[0].(string) + viewArgs = args[1] + // Try to extract language from the view args + if viewargsmap, ok := viewArgs.(map[string]interface{}); ok { + lang, _ = viewargsmap[CurrentLocaleViewArg].(string) } - return template.HTML(buf.String()), err - }, - } -) + default: + // Assume third argument is the region + templateName = args[0].(string) + viewArgs = args[1] + lang, _ = args[2].(string) + if len(args) > 3 { + templateLog.Error("i18ntemplate: Received more parameters then needed for", "template", templateName) + } + } + + var buf bytes.Buffer + // Get template + tmpl, err := MainTemplateLoader.TemplateLang(templateName, lang) + if err == nil { + err = tmpl.Render(&buf, viewArgs) + } else { + templateLog.Error("i18ntemplate: Failed to render i18ntemplate ", "name", templateName, "error", err) + } + return template.HTML(buf.String()), err + }, +} ///////////////////// // Template functions ///////////////////// // ReverseURL returns a url capable of invoking a given controller method: -// "Application.ShowApp 123" => "/app/123" +// "Application.ShowApp 123" => "/app/123". func ReverseURL(args ...interface{}) (template.URL, error) { if len(args) == 0 { return "", errors.New("no arguments provided to reverse route") @@ -269,7 +268,6 @@ func Slug(text string) string { var timeAgoLangs = map[string]timeago.Config{} func TimeAgo(args ...interface{}) string { - datetime := time.Now() lang := "" var viewArgs interface{} @@ -298,24 +296,28 @@ func TimeAgo(args ...interface{}) string { default: // Assume third argument is the region datetime = args[0].(time.Time) + if reflect.ValueOf(args[1]).Kind() != reflect.Map { templateLog.Error("TimeAgo: unexpected type", "value", args[1]) } + if reflect.ValueOf(args[2]).Kind() != reflect.String { templateLog.Error("TimeAgo: unexpected type: ", "value", args[2]) } - viewArgs = args[1] + lang, _ = args[2].(string) if len(args) > 3 { templateLog.Error("TimeAgo: Received more parameters then needed for timeago") } } + if lang == "" { lang, _ = Config.String(defaultLanguageOption) if lang == "en" { timeAgoLangs[lang] = timeago.English } } + _, ok := timeAgoLangs[lang] if !ok { timeAgoLangs[lang] = timeago.Config{ @@ -335,7 +337,6 @@ func TimeAgo(args ...interface{}) string { Max: 73 * time.Hour, DefaultLayout: "2006-01-02", } - } return timeAgoLangs[lang].Format(datetime) } diff --git a/testing/testsuite.go b/testing/testsuite.go index ff02472e0..8dc0cd803 100644 --- a/testing/testsuite.go +++ b/testing/testsuite.go @@ -13,6 +13,7 @@ import ( "mime/multipart" "net/http" "net/http/cookiejar" + "net/http/httptest" "net/textproto" "net/url" "os" @@ -21,10 +22,8 @@ import ( "strings" "github.com/revel/revel" - "github.com/revel/revel/session" "golang.org/x/net/websocket" - "net/http/httptest" ) type TestSuite struct { @@ -40,7 +39,7 @@ type TestRequest struct { testSuite *TestSuite } -// This is populated by the generated code in the run/run/go file +// This is populated by the generated code in the run/run/go file. var TestSuites []interface{} // Array of structs that embed TestSuite // NewTestSuite returns an initialized TestSuite ready for use. It is invoked @@ -49,7 +48,7 @@ func NewTestSuite() TestSuite { return NewTestSuiteEngine(revel.NewSessionCookieEngine()) } -// Define a new test suite with a custom session engine +// Define a new test suite with a custom session engine. func NewTestSuiteEngine(engine revel.SessionEngine) TestSuite { jar, _ := cookiejar.New(nil) ts := TestSuite{ @@ -62,7 +61,7 @@ func NewTestSuiteEngine(engine revel.SessionEngine) TestSuite { } // NewTestRequest returns an initialized *TestRequest. It is used for extending -// testsuite package making it possibe to define own methods. Example: +// testsuite package making it possible to define own methods. Example: // type MyTestSuite struct { // testing.TestSuite // } @@ -80,7 +79,7 @@ func (t *TestSuite) NewTestRequest(req *http.Request) *TestRequest { return request } -// Host returns the address and port of the server, e.g. "127.0.0.1:8557" +// Host returns the address and port of the server, e.g. "127.0.0.1:8557". func (t *TestSuite) Host() string { if revel.ServerEngineInit.Address[0] == ':' { return "127.0.0.1" + revel.ServerEngineInit.Address @@ -261,7 +260,7 @@ func (r *TestRequest) Send() { // MakeRequest issues any request and read the response. If successful, the // caller may examine the Response and ResponseBody properties. You will need to -// manage session / cookie data manually +// manage session / cookie data manually. func (r *TestRequest) MakeRequest() { var err error if r.testSuite.Response, err = r.testSuite.Client.Do(r.Request); err != nil { @@ -287,7 +286,7 @@ func (r *TestRequest) MakeRequest() { r.testSuite.Session = controller.Session } -// WebSocket creates a websocket connection to the given path and returns it +// WebSocket creates a websocket connection to the given path and returns it. func (t *TestSuite) WebSocket(path string) *websocket.Conn { origin := t.BaseUrl() + "/" urlPath := t.WebSocketUrl() + path diff --git a/testing/testsuite_test.go b/testing/testsuite_test.go index e82066c01..a11545482 100644 --- a/testing/testsuite_test.go +++ b/testing/testsuite_test.go @@ -71,7 +71,7 @@ func TestGetNotFound(t *testing.T) { // testSuite.AssertNotContains("not exists") } -// This test is known to fail +// This test is known to fail. func TestGetCustom(t *testing.T) { testSuite := createNewTestSuite(t) for x := 0; x < 5; x++ { @@ -192,7 +192,6 @@ func TestPostFileUpload(t *testing.T) { testSuite.AssertContains("File: server.go") testSuite.AssertNotContains("File: not_exists.go") testSuite.AssertEqual("text/plain; charset=utf-8", testSuite.Response.Header.Get("Content-Type")) - } func createNewTestSuite(t *testing.T) *TestSuite { diff --git a/util.go b/util.go index 340c5995b..21d111f19 100644 --- a/util.go +++ b/util.go @@ -6,7 +6,6 @@ package revel import ( "bytes" - "fmt" "io" "io/ioutil" "net" @@ -22,7 +21,7 @@ import ( ) const ( - // DefaultFileContentType Revel's default response content type + // DefaultFileContentType Revel's default response content type. DefaultFileContentType = "application/octet-stream" ) @@ -191,7 +190,7 @@ func Equal(a, b interface{}) bool { // you may get inaccurate Client IP address. Revel parses the // IP address in the order of X-Forwarded-For, X-Real-IP. // -// By default revel will get http.Request's RemoteAddr +// By default revel will get http.Request's RemoteAddr. func ClientIP(r *Request) string { if Config.BoolDefault("app.behind.proxy", false) { // Header X-Forwarded-For @@ -222,20 +221,6 @@ func Walk(root string, walkFn filepath.WalkFunc) error { return fsWalk(root, root, walkFn) } -// createDir method creates nested directories if not exists -func createDir(path string) error { - if _, err := os.Stat(path); err != nil { - if os.IsNotExist(err) { - if err = os.MkdirAll(path, 0755); err != nil { - return fmt.Errorf("Failed to create directory '%v': %v", path, err) - } - } else { - return fmt.Errorf("Failed to create directory '%v': %v", path, err) - } - } - return nil -} - func fsWalk(fname string, linkName string, walkFn filepath.WalkFunc) error { fsWalkFunc := func(path string, info os.FileInfo, err error) error { if err != nil { diff --git a/util_test.go b/util_test.go index ef8745ad2..a23b654c9 100644 --- a/util_test.go +++ b/util_test.go @@ -19,9 +19,10 @@ func TestContentTypeByFilename(t *testing.T) { "hello.world.c": "text/x-c; charset=utf-8", } srcPath, _ := findSrcPaths(RevelImportPath) - ConfPaths = []string{filepath.Join( - srcPath, - "conf"), + ConfPaths = []string{ + filepath.Join( + srcPath, + "conf"), } LoadMimeConfig() for filename, expected := range testCases { @@ -35,7 +36,10 @@ func TestContentTypeByFilename(t *testing.T) { func TestEqual(t *testing.T) { type testStruct struct{} type testStruct2 struct{} - i, i2 := 8, 9 + const ( + i = 8 + i2 = 9 + ) s, s2 := "@朕µ\n\tüöäß", "@朕µ\n\tüöäss" slice, slice2 := []int{1, 2, 3, 4, 5}, []int{1, 2, 3, 4, 5} slice3, slice4 := []int{5, 4, 3, 2, 1}, []int{5, 4, 3, 2, 1} diff --git a/utils/simplestack.go b/utils/simplestack.go index bb22430b0..b78cebf00 100644 --- a/utils/simplestack.go +++ b/utils/simplestack.go @@ -45,6 +45,7 @@ func NewStackLock(startsize, maxsize int, creator func() interface{}) *SimpleLoc } return ss } + func (s *SimpleLockStack) Pop() (value interface{}) { s.lock.Lock() defer s.lock.Unlock() @@ -64,6 +65,7 @@ func (s *SimpleLockStack) Pop() (value interface{}) { s.active++ return } + func (s *SimpleLockStack) Push(value interface{}) { if d, ok := value.(ObjectDestroy); ok { d.Destroy() @@ -86,18 +88,22 @@ func (s *SimpleLockStack) Push(value interface{}) { } s.len++ s.active-- - //println("Push ",value, s.len, s.active, s.capacity) + // println("Push ",value, s.len, s.active, s.capacity) return } + func (s *SimpleLockStack) Len() int { return s.len } + func (s *SimpleLockStack) Capacity() int { return s.capacity } + func (s *SimpleLockStack) Active() int { return s.active } + func (s *SimpleLockStack) String() string { return fmt.Sprintf("SS: Capacity:%d Active:%d Stored:%d", s.capacity, s.active, s.len) } diff --git a/utils/simplestack_test.go b/utils/simplestack_test.go index 3a9374058..999f14e66 100644 --- a/utils/simplestack_test.go +++ b/utils/simplestack_test.go @@ -59,8 +59,8 @@ func TestUnique(b *testing.T) { if !isDifferent(value1, value2, value3) { b.Errorf("Failed to get unique values") } - } + func TestLimits(b *testing.T) { stack := NewStackLock(10, 20, func() interface{} { newone := &SimpleStackTest{} @@ -79,8 +79,8 @@ func TestLimits(b *testing.T) { if stack.Capacity() != 20 { b.Errorf("Failed to match 20 capcity %v ", stack.Capacity()) } - } + func isDifferent(values ...*SimpleStackTest) bool { if len(values) == 2 { return values[0] != values[1] @@ -99,15 +99,18 @@ func BenchmarkCreateWrite(b *testing.B) { stack.Push(x) } } + func BenchmarkAllocWrite(b *testing.B) { stack := NewStackLock(b.N, b.N+100, func() interface{} { return &SimpleStackTest{} }) for x := 0; x < b.N; x++ { stack.Push(x) } } + func BenchmarkCreate(b *testing.B) { NewStackLock(b.N, b.N+100, func() interface{} { return &SimpleStackTest{} }) } + func BenchmarkParrallel(b *testing.B) { stack := NewStackLock(b.N, b.N+100, func() interface{} { return &SimpleStackTest{} }) b.RunParallel(func(pb *testing.PB) { diff --git a/validation.go b/validation.go index 7027ab71b..ea8a5609d 100644 --- a/validation.go +++ b/validation.go @@ -12,7 +12,7 @@ import ( "runtime" ) -// ValidationError simple struct to store the Message & Key of a validation error +// ValidationError simple struct to store the Message & Key of a validation error. type ValidationError struct { Message, Key string } @@ -43,7 +43,7 @@ func (v *Validation) Keep() { v.keep = true } -// Clear *all* ValidationErrors +// Clear *all* ValidationErrors. func (v *Validation) Clear() { v.Errors = []*ValidationError{} } @@ -98,7 +98,7 @@ type ValidationResult struct { Translator func(locale, message string, args ...interface{}) string } -// Key sets the ValidationResult's Error "key" and returns itself for chaining +// Key sets the ValidationResult's Error "key" and returns itself for chaining. func (r *ValidationResult) Key(key string) *ValidationResult { if r.Error != nil { r.Error.Key = key @@ -107,7 +107,7 @@ func (r *ValidationResult) Key(key string) *ValidationResult { } // Message sets the error message for a ValidationResult. Returns itself to -// allow chaining. Allows Sprintf() type calling with multiple parameters +// allow chaining. Allows Sprintf() type calling with multiple parameters. func (r *ValidationResult) Message(message string, args ...interface{}) *ValidationResult { if r.Error != nil { if len(args) == 0 { @@ -120,7 +120,7 @@ func (r *ValidationResult) Message(message string, args ...interface{}) *Validat } // Allow a message key to be passed into the validation result. The Validation has already -// setup the translator to translate the message key +// setup the translator to translate the message key. func (r *ValidationResult) MessageKey(message string, args ...interface{}) *ValidationResult { if r.Error == nil { return r @@ -136,7 +136,7 @@ func (r *ValidationResult) MessageKey(message string, args ...interface{}) *Vali return r } -// Required tests that the argument is non-nil and non-empty (if string or list) +// Required tests that the argument is non-nil and non-empty (if string or list). func (v *Validation) Required(obj interface{}) *ValidationResult { return v.apply(Required{}, obj) } diff --git a/validation_test.go b/validation_test.go index a3a7ac7b9..8c318ac5b 100644 --- a/validation_test.go +++ b/validation_test.go @@ -22,7 +22,7 @@ func getRecordedCookie(recorder *httptest.ResponseRecorder, name string) (*http. return nil, http.ErrNoCookie } -// r.Original.URL.String() +// r.Original.URL.String(). func validationTester(req *Request, fn func(c *Controller)) *httptest.ResponseRecorder { recorder := httptest.NewRecorder() c := NewTestController(recorder, req.In.GetRaw().(*http.Request)) @@ -102,5 +102,4 @@ func TestValidateMessageKey(t *testing.T) { t.Fatal("errors should not be present") } }) - } diff --git a/validators.go b/validators.go index 78685b825..3b73eef4a 100644 --- a/validators.go +++ b/validators.go @@ -265,11 +265,9 @@ type IPAddr struct { Vaildtypes []int } -// Requires an IP Address string to be exactly a given validation type (IPv4, IPv6, IPv4MappedIPv6, IPv4CIDR, IPv6CIDR, IPv4MappedIPv6CIDR OR IPAny) +// Requires an IP Address string to be exactly a given validation type (IPv4, IPv6, IPv4MappedIPv6, IPv4CIDR, IPv6CIDR, IPv4MappedIPv6CIDR OR IPAny). func ValidIPAddr(cktypes ...int) IPAddr { - for _, cktype := range cktypes { - if cktype != IPAny && cktype != IPv4 && cktype != IPv6 && cktype != IPv4MappedIPv6 && cktype != IPv4CIDR && cktype != IPv6CIDR && cktype != IPv4MappedIPv6CIDR { return IPAddr{Vaildtypes: []int{None}} } @@ -279,13 +277,11 @@ func ValidIPAddr(cktypes ...int) IPAddr { } func isWithCIDR(str string, l int) bool { - if str[l-3] == '/' || str[l-2] == '/' { - cidr_bit := strings.Split(str, "/") if 2 == len(cidr_bit) { bit, err := strconv.Atoi(cidr_bit[1]) - //IPv4 : 0~32, IPv6 : 0 ~ 128 + // IPv4 : 0~32, IPv6 : 0 ~ 128 if err == nil && bit >= 0 && bit <= 128 { return true } @@ -296,8 +292,7 @@ func isWithCIDR(str string, l int) bool { } func getIPType(str string, l int) int { - - if l < 3 { //least 3 chars (::F) + if l < 3 { // least 3 chars (::F) return None } @@ -330,16 +325,12 @@ func getIPType(str string, l int) int { } func (i IPAddr) IsSatisfied(obj interface{}) bool { - if str, ok := obj.(string); ok { - l := len(str) ret := getIPType(str, l) for _, ck := range i.Vaildtypes { - if ret != None && (ck == ret || ck == IPAny) { - switch ret { case IPv4, IPv6, IPv4MappedIPv6: ip := net.ParseIP(str) @@ -362,19 +353,17 @@ func (i IPAddr) IsSatisfied(obj interface{}) bool { } func (i IPAddr) DefaultMessage() string { - return fmt.Sprintln("Must be a vaild IP address") + return fmt.Sprintln("Must be a valid IP address") } -// Requires a MAC Address string to be exactly +// Requires a MAC Address string to be exactly. type MacAddr struct{} func ValidMacAddr() MacAddr { - return MacAddr{} } func (m MacAddr) IsSatisfied(obj interface{}) bool { - if str, ok := obj.(string); ok { if _, err := net.ParseMAC(str); err == nil { return true @@ -385,12 +374,12 @@ func (m MacAddr) IsSatisfied(obj interface{}) bool { } func (m MacAddr) DefaultMessage() string { - return fmt.Sprintln("Must be a vaild MAC address") + return fmt.Sprintln("Must be a valid MAC address") } var domainPattern = regexp.MustCompile(`^(([a-zA-Z0-9-\p{L}]{1,63}\.)?(xn--)?[a-zA-Z0-9\p{L}]+(-[a-zA-Z0-9\p{L}]+)*\.)+[a-zA-Z\p{L}]{2,63}$`) -// Requires a Domain string to be exactly +// Requires a Domain string to be exactly. type Domain struct { Regexp *regexp.Regexp } @@ -400,16 +389,14 @@ func ValidDomain() Domain { } func (d Domain) IsSatisfied(obj interface{}) bool { - if str, ok := obj.(string); ok { - l := len(str) - //can't exceed 253 chars. + // can't exceed 253 chars. if l > 253 { return false } - //first and last char must be alphanumeric + // first and last char must be alphanumeric if str[l-1] == 46 || str[0] == 46 { return false } @@ -421,7 +408,7 @@ func (d Domain) IsSatisfied(obj interface{}) bool { } func (d Domain) DefaultMessage() string { - return fmt.Sprintln("Must be a vaild domain address") + return fmt.Sprintln("Must be a valid domain address") } var urlPattern = regexp.MustCompile(`^((((https?|ftps?|gopher|telnet|nntp)://)|(mailto:|news:))(%[0-9A-Fa-f]{2}|[-()_.!~*';/?:@#&=+$,A-Za-z0-9\p{L}])+)([).!';/?:,][[:blank:]])?$`) @@ -435,9 +422,7 @@ func ValidURL() URL { } func (u URL) IsSatisfied(obj interface{}) bool { - if str, ok := obj.(string); ok { - // TODO : Required lot of testing return urlPattern.MatchString(str) } @@ -446,19 +431,19 @@ func (u URL) IsSatisfied(obj interface{}) bool { } func (u URL) DefaultMessage() string { - return fmt.Sprintln("Must be a vaild URL address") + return fmt.Sprintln("Must be a valid URL address") } /* NORMAL BenchmarkRegex-8 2000000000 0.24 ns/op -STRICT BenchmarkLoop-8 2000000000 0.01 ns/op +STRICT BenchmarkLoop-8 2000000000 0.01 ns/op. */ const ( NORMAL = 0 STRICT = 4 ) -// Requires a string to be without invisible characters +// Requires a string to be without invisible characters. type PureText struct { Mode int } @@ -471,11 +456,9 @@ func ValidPureText(m int) PureText { } func isPureTextStrict(str string) (bool, error) { - l := len(str) for i := 0; i < l; i++ { - c := str[i] // deny : control char (00-31 without 9(TAB) and Single 10(LF),13(CR) @@ -488,9 +471,8 @@ func isPureTextStrict(str string) (bool, error) { return false, errors.New("detect control character (DEL)") } - //deny : short tag (<~> <~ />) + // deny : short tag (<~> <~ />) if c == 60 { - for n := i + 2; n < l; n++ { // 62 (>) if str[n] == 62 { @@ -499,15 +481,14 @@ func isPureTextStrict(str string) (bool, error) { } } - //deny : html tag (< ~ >) + // deny : html tag (< ~ >) if c == 60 { ds := 0 for n := i; n < l; n++ { - // 60 (<) , 47(/) | 33(!) | 63(?) if str[n] == 60 && n+1 <= l && (str[n+1] == 47 || str[n+1] == 33 || str[n+1] == 63) { ds = 1 - n += 3 //jump to next char + n += 3 // jump to next char } // 62 (>) @@ -517,10 +498,9 @@ func isPureTextStrict(str string) (bool, error) { } } - //deny : html encoded(hex) tag (&xxx;) + // deny : html encoded(hex) tag (&xxx;) // 38(&) , 35(#), 59(;) if c == 38 && i+1 <= l { - max := i + 64 if max > l { max = l @@ -540,14 +520,13 @@ func isPureTextStrict(str string) (bool, error) { // referrer : http://www.w3schools.com/Tags/ var elementPattern = regexp.MustCompile(`(?im)<(?P(/*\s*|\?*|\!*)(figcaption|expression|blockquote|plaintext|textarea|progress|optgroup|noscript|noframes|menuitem|frameset|fieldset|!DOCTYPE|datalist|colgroup|behavior|basefont|summary|section|isindex|details|caption|bgsound|article|address|acronym|strong|strike|source|select|script|output|option|object|legend|keygen|ilayer|iframe|header|footer|figure|dialog|center|canvas|button|applet|video|track|title|thead|tfoot|tbody|table|style|small|param|meter|layer|label|input|frame|embed|blink|audio|aside|alert|time|span|samp|ruby|meta|menu|mark|main|link|html|head|form|font|code|cite|body|base|area|abbr|xss|xml|wbr|var|svg|sup|sub|pre|nav|map|kbd|ins|img|div|dir|dfn|del|col|big|bdo|bdi|!--|ul|tt|tr|th|td|rt|rp|ol|li|hr|em|dt|dl|dd|br|u|s|q|p|i|b|a|(h[0-9]+)))([^><]*)([><]*)`) -// Requires a string to match a given urlencoded regex pattern +// Requires a string to match a given urlencoded regex pattern. var urlencodedPattern = regexp.MustCompile(`(?im)(\%[0-9a-fA-F]{1,})`) -// Requires a string to match a given control characters regex pattern (ASCII : 00-08, 11, 12, 14, 15-31) +// Requires a string to match a given control characters regex pattern (ASCII : 00-08, 11, 12, 14, 15-31). var controlcharPattern = regexp.MustCompile(`(?im)([\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+)`) func isPureTextNormal(str string) (bool, error) { - decoded_str := html.UnescapeString(str) matched_urlencoded := urlencodedPattern.MatchString(decoded_str) @@ -572,9 +551,7 @@ func isPureTextNormal(str string) (bool, error) { } func (p PureText) IsSatisfied(obj interface{}) bool { - if str, ok := obj.(string); ok { - var ret bool switch p.Mode { case STRICT: @@ -589,7 +566,7 @@ func (p PureText) IsSatisfied(obj interface{}) bool { } func (p PureText) DefaultMessage() string { - return fmt.Sprintln("Must be a vaild Text") + return fmt.Sprintln("Must be a valid Text") } const ( @@ -597,19 +574,22 @@ const ( ALLOW_RELATIVE_PATH = 1 ) -const regexDenyFileNameCharList = `[\x00-\x1f|\x21-\x2c|\x3b-\x40|\x5b-\x5e|\x60|\x7b-\x7f]+` -const regexDenyFileName = `|\x2e\x2e\x2f+` +const ( + regexDenyFileNameCharList = `[\x00-\x1f|\x21-\x2c|\x3b-\x40|\x5b-\x5e|\x60|\x7b-\x7f]+` + regexDenyFileName = `|\x2e\x2e\x2f+` +) -var checkAllowRelativePath = regexp.MustCompile(`(?m)(` + regexDenyFileNameCharList + `)`) -var checkDenyRelativePath = regexp.MustCompile(`(?m)(` + regexDenyFileNameCharList + regexDenyFileName + `)`) +var ( + checkAllowRelativePath = regexp.MustCompile(`(?m)(` + regexDenyFileNameCharList + `)`) + checkDenyRelativePath = regexp.MustCompile(`(?m)(` + regexDenyFileNameCharList + regexDenyFileName + `)`) +) -// Requires an string to be sanitary file path +// Requires an string to be sanitary file path. type FilePath struct { Mode int } func ValidFilePath(m int) FilePath { - if m != ONLY_FILENAME && m != ALLOW_RELATIVE_PATH { m = ONLY_FILENAME } @@ -617,18 +597,15 @@ func ValidFilePath(m int) FilePath { } func (f FilePath) IsSatisfied(obj interface{}) bool { - if str, ok := obj.(string); ok { - var ret bool switch f.Mode { - case ALLOW_RELATIVE_PATH: ret = checkAllowRelativePath.MatchString(str) if ret == false { return true } - default: //ONLY_FILENAME + default: // ONLY_FILENAME ret = checkDenyRelativePath.MatchString(str) if ret == false { return true diff --git a/validators_test.go b/validators_test.go index f20737702..c4eb76992 100644 --- a/validators_test.go +++ b/validators_test.go @@ -291,7 +291,6 @@ func TestEmail(t *testing.T) { } func runIPAddrTestfunc(t *testing.T, test_type int, ipaddr_list map[string]bool, msg_fmt string) { - // generate dataset for test test_ipaddr_list := []Expect{} for ipaddr, expected := range ipaddr_list { @@ -304,8 +303,7 @@ func runIPAddrTestfunc(t *testing.T, test_type int, ipaddr_list map[string]bool, } func TestIPAddr(t *testing.T) { - - //IPv4 + // IPv4 test_ipv4_ipaddrs := map[string]bool{ "192.168.1.1": true, "127.0.0.1": true, @@ -317,7 +315,7 @@ func TestIPAddr(t *testing.T) { "192.192.19.999": false, } - //IPv4 with CIDR + // IPv4 with CIDR test_ipv4_with_cidr_ipaddrs := map[string]bool{ "192.168.1.1/24": true, "127.0.0.1/32": true, @@ -331,11 +329,11 @@ func TestIPAddr(t *testing.T) { "4.4.4.4/256": false, } - //IPv6 + // IPv6 test_ipv6_ipaddrs := map[string]bool{ "2607:f0d0:1002:51::4": true, "2607:f0d0:1002:0051:0000:0000:0000:0004": true, - "ff05::1:3": true, + "ff05::1:3": true, "FE80:0000:0000:0000:0202:B3FF:FE1E:8329": true, "FE80::0202:B3FF:FE1E:8329": true, "fe80::202:b3ff:fe1e:8329": true, @@ -351,7 +349,7 @@ func TestIPAddr(t *testing.T) { "234:23:23:23:23:23:23": false, } - //IPv6 with CIDR + // IPv6 with CIDR test_ipv6_with_cidr_ipaddrs := map[string]bool{ "2000::/5": true, "2000::/15": true, @@ -360,7 +358,7 @@ func TestIPAddr(t *testing.T) { "fc00::/7": true, } - //IPv4-Mapped Embedded IPv6 Address + // IPv4-Mapped Embedded IPv6 Address test_ipv4_mapped_ipv6_ipaddrs := map[string]bool{ "2001:470:1f09:495::3:217.126.185.215": true, "2001:470:1f1d:275::1:213.0.69.132": true, @@ -384,7 +382,6 @@ func TestIPAddr(t *testing.T) { } func TestMacAddr(t *testing.T) { - macaddr_list := map[string]bool{ "02:f3:71:eb:9e:4b": true, "02-f3-71-eb-9e-4b": true, @@ -411,7 +408,6 @@ func TestMacAddr(t *testing.T) { } func TestDomain(t *testing.T) { - test_domains := map[string]bool{ "대한민국.xn-korea.co.kr": true, "google.com": true, @@ -477,12 +473,11 @@ func TestDomain(t *testing.T) { } func TestURL(t *testing.T) { - test_urls := map[string]bool{ - "https://www.google.co.kr/url?sa=t&rct=j&q=&esrc=s&source=web": true, - "http://stackoverflow.com/questions/27812164/can-i-import-3rd-party-package-into-golang-playground": true, - "https://tour.golang.org/welcome/4": true, - "https://revel.github.io/": true, + "https://www.google.co.kr/url?sa=t&rct=j&q=&esrc=s&source=web": true, + "http://stackoverflow.com/questions/27812164/can-i-import-3rd-party-package-into-golang-playground": true, + "https://tour.golang.org/welcome/4": true, + "https://revel.github.io/": true, "https://github.com/revel/revel/commit/bd1d083ee4345e919b3bca1e4c42ca682525e395#diff-972a2b2141d27e9d7a8a4149a7e28eef": true, "https://github.com/ndevilla/iniparser/pull/82#issuecomment-261817064": true, "http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=golang": true, @@ -498,11 +493,9 @@ func TestURL(t *testing.T) { for _, url := range []revel.URL{{}, revel.ValidURL()} { performTests(url, tests, t) } - } func TestPureTextNormal(t *testing.T) { - test_txts := map[string]bool{ `qd08j123lneqw\t\nqwedojiqwd\rqwdoihjqwd1d[08jaedl;jkqwd\r\nqdolijqdwqwd`: false, `a\r\nbqd08j123lneqw\t\nqwedojiqwd\rqwdoihjqwd1d[08jaedl;jkqwd\r\nqdolijqdwqwd`: false, @@ -519,17 +512,17 @@ func TestPureTextNormal(t *testing.T) { `I like Golang\r\na`: true, "I like Golang\t\n": true, "I & like Golang\t\n": true, - `ハイレゾ対応ウォークマン®、ヘッドホン、スピーカー「Winter Gift Collection ~Presented by JUJU~」をソニーストアにて販売開始`: true, - `VAIOパーソナルコンピューター type T TZシリーズ 無償点検・修理のお知らせとお詫び(2009年10月15日更新)`: true, - `把百度设为主页关于百度About Baidu百度推广`: true, + `ハイレゾ対応ウォークマン®、ヘッドホン、スピーカー「Winter Gift Collection ~Presented by JUJU~」をソニーストアにて販売開始`: true, + `VAIOパーソナルコンピューター type T TZシリーズ 無償点検・修理のお知らせとお詫び(2009年10月15日更新)`: true, + `把百度设为主页关于百度About Baidu百度推广`: true, `%E6%8A%8A%E7%99%BE%E5%BA%A6%E8%AE%BE%E4%B8%BA%E4%B8%BB%E9%A1%B5%E5%85%B3%E4%BA%8E%E7%99%BE%E5%BA%A6About++Baidu%E7%99%BE%E5%BA%A6%E6%8E%A8%E5%B9%BF`: true, `%E6%8A%8A%E7%99%BE%E5%BA%A6%E8%AE%BE%E4%B8%BA%E4%B8%BB%E9%A1%B5%E5%85%B3%E4%BA%8E%E7%99%BE%E5%BA%A6About%20%20Baidu%E7%99%BE%E5%BA%A6%E6%8E%A8%E5%B9%BF`: true, - `abcd/>qwdqwdoijhwer/>qwdojiqwdqwdqwdoijqwdoiqjd`: true, - `abcd/>qwdqwdoijhwer/>qwdojiqwdqwdqwdoijqwdoiqjd`: false, - ``: false, - ``: false, - `<img src="javascript:alert('abc')">`: false, - `<a href="javascript:alert('hello');">AAA</a>`: false, + `abcd/>qwdqwdoijhwer/>qwdojiqwdqwdqwdoijqwdoiqjd`: true, + `abcd/>qwdqwdoijhwer/>qwdojiqwdqwdqwdoijqwdoiqjd`: false, + ``: false, + ``: false, + `<img src="javascript:alert('abc')">`: false, + `<a href="javascript:alert('hello');">AAA</a>`: false, } tests := []Expect{} @@ -545,7 +538,6 @@ func TestPureTextNormal(t *testing.T) { } func TestPureTextStrict(t *testing.T) { - test_txts := map[string]bool{ `qd08j123lneqw\t\nqwedojiqwd\rqwdoihjqwd1d[08jaedl;jkqwd\r\nqdolijqdwqwd`: false, `a\r\nbqd08j123lneqw\t\nqwedojiqwd\rqwdoihjqwd1d[08jaedl;jkqwd\r\nqdolijqdwqwd`: false, @@ -562,17 +554,17 @@ func TestPureTextStrict(t *testing.T) { `I like Golang\r\na`: true, "I like Golang\t\n": false, "I & like Golang\t\n": false, - `ハイレゾ対応ウォークマン®、ヘッドホン、スピーカー「Winter Gift Collection ~Presented by JUJU~」をソニーストアにて販売開始`: true, - `VAIOパーソナルコンピューター type T TZシリーズ 無償点検・修理のお知らせとお詫び(2009年10月15日更新)`: true, - `把百度设为主页关于百度About Baidu百度推广`: true, + `ハイレゾ対応ウォークマン®、ヘッドホン、スピーカー「Winter Gift Collection ~Presented by JUJU~」をソニーストアにて販売開始`: true, + `VAIOパーソナルコンピューター type T TZシリーズ 無償点検・修理のお知らせとお詫び(2009年10月15日更新)`: true, + `把百度设为主页关于百度About Baidu百度推广`: true, `%E6%8A%8A%E7%99%BE%E5%BA%A6%E8%AE%BE%E4%B8%BA%E4%B8%BB%E9%A1%B5%E5%85%B3%E4%BA%8E%E7%99%BE%E5%BA%A6About++Baidu%E7%99%BE%E5%BA%A6%E6%8E%A8%E5%B9%BF`: true, `%E6%8A%8A%E7%99%BE%E5%BA%A6%E8%AE%BE%E4%B8%BA%E4%B8%BB%E9%A1%B5%E5%85%B3%E4%BA%8E%E7%99%BE%E5%BA%A6About%20%20Baidu%E7%99%BE%E5%BA%A6%E6%8E%A8%E5%B9%BF`: true, - `abcd/>qwdqwdoijhwer/>qwdojiqwdqwdqwdoijqwdoiqjd`: false, - `abcd/>qwdqwdoijhwer/>qwdojiqwdqwdqwdoijqwdoiqjd`: false, - ``: false, - ``: false, - `<img src="javascript:alert('abc')">`: false, - `<a href="javascript:alert('hello');">AAA</a>`: false, + `abcd/>qwdqwdoijhwer/>qwdojiqwdqwdqwdoijqwdoiqjd`: false, + `abcd/>qwdqwdoijhwer/>qwdojiqwdqwdqwdoijqwdoiqjd`: false, + ``: false, + ``: false, + `<img src="javascript:alert('abc')">`: false, + `<a href="javascript:alert('hello');">AAA</a>`: false, } tests := []Expect{} @@ -588,7 +580,6 @@ func TestPureTextStrict(t *testing.T) { } func TestFilePathOnlyFilePath(t *testing.T) { - test_filepaths := map[string]bool{ "../../qwdqwdqwd/../qwdqwdqwd.txt": false, `../../qwdqwdqwd/.. @@ -596,12 +587,12 @@ func TestFilePathOnlyFilePath(t *testing.T) { "\t../../qwdqwdqwd/../qwdqwdqwd.txt": false, `../../qwdqwdqwd/../qwdqwdqwd.txt`: false, `../../qwdqwdqwd/../qwdqwdqwd.txt`: false, - "../../etc/passwd": false, - "a.txt;rm -rf /": false, - "sudo rm -rf ../": false, - "a-1-s-d-v-we-wd_+qwd-qwd-qwd.txt": false, - "a-qwdqwd_qwdqwdqwd-123.txt": true, - "a.txt": true, + "../../etc/passwd": false, + "a.txt;rm -rf /": false, + "sudo rm -rf ../": false, + "a-1-s-d-v-we-wd_+qwd-qwd-qwd.txt": false, + "a-qwdqwd_qwdqwdqwd-123.txt": true, + "a.txt": true, "a-1-e-r-t-_1_21234_d_1234_qwed_1423_.txt": true, } @@ -618,7 +609,6 @@ func TestFilePathOnlyFilePath(t *testing.T) { } func TestFilePathAllowRelativePath(t *testing.T) { - test_filepaths := map[string]bool{ "../../qwdqwdqwd/../qwdqwdqwd.txt": true, `../../qwdqwdqwd/.. @@ -626,13 +616,13 @@ func TestFilePathAllowRelativePath(t *testing.T) { "\t../../qwdqwdqwd/../qwdqwdqwd.txt": false, `../../qwdqwdqwd/../qwdqwdqwd.txt`: false, `../../qwdqwdqwd/../qwdqwdqwd.txt`: false, - "../../etc/passwd": true, - "a.txt;rm -rf /": false, - "sudo rm -rf ../": true, - "a-1-s-d-v-we-wd_+qwd-qwd-qwd.txt": false, - "a-qwdqwd_qwdqwdqwd-123.txt": true, - "a.txt": true, - "a-1-e-r-t-_1_21234_d_1234_qwed_1423_.txt": true, + "../../etc/passwd": true, + "a.txt;rm -rf /": false, + "sudo rm -rf ../": true, + "a-1-s-d-v-we-wd_+qwd-qwd-qwd.txt": false, + "a-qwdqwd_qwdqwdqwd-123.txt": true, + "a.txt": true, + "a-1-e-r-t-_1_21234_d_1234_qwed_1423_.txt": true, "/asdasd/asdasdasd/qwdqwd_qwdqwd/12-12/a-1-e-r-t-_1_21234_d_1234_qwed_1423_.txt": true, } diff --git a/version.go b/version.go index 38cf9989e..22f1b4da0 100644 --- a/version.go +++ b/version.go @@ -5,12 +5,12 @@ package revel const ( - // Version current Revel version - Version = "1.0.0" + // Version current Revel version. + Version = "1.1.0-dev" - // BuildDate latest commit/release date + // BuildDate latest commit/release date. BuildDate = "2020-07-11" - // MinimumGoVersion minimum required Go version for Revel + // MinimumGoVersion minimum required Go version for Revel. MinimumGoVersion = ">= go1.12" ) diff --git a/watcher.go b/watcher.go index cbeba6b53..0f5af886a 100644 --- a/watcher.go +++ b/watcher.go @@ -9,9 +9,9 @@ import ( "path/filepath" "strings" "sync" + "time" "github.com/fsnotify/fsnotify" - "time" ) // Listener is an interface for receivers of filesystem events. @@ -139,7 +139,6 @@ func (w *Watcher) Listen(listener Listener, roots ...string) { // NotifyWhenUpdated notifies the watcher when a file event is received. func (w *Watcher) NotifyWhenUpdated(listener Listener, watcher *fsnotify.Watcher) { - for { select { case ev := <-watcher.Events: @@ -214,7 +213,7 @@ func (w *Watcher) Notify() *Error { } // Build a queue for refresh notifications -// this will not return until one of the queue completes +// this will not return until one of the queue completes. func (w *Watcher) notifyInProcess(listener Listener) (err *Error) { shouldReturn := false // This code block ensures that either a timer is created